From aa0f4269e62c3d2257936291e44f5721d3f3f1d1 Mon Sep 17 00:00:00 2001 From: trav90 Date: Fri, 10 Aug 2018 14:44:03 -0500 Subject: js::atomics_wait: Remove unnecessary parentheses in declaration of 'addr' Silences a warning with GCC 8. --- js/src/builtin/AtomicsObject.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'js/src') diff --git a/js/src/builtin/AtomicsObject.cpp b/js/src/builtin/AtomicsObject.cpp index 08777fd51..2551f3b7d 100644 --- a/js/src/builtin/AtomicsObject.cpp +++ b/js/src/builtin/AtomicsObject.cpp @@ -789,7 +789,7 @@ js::atomics_wait(JSContext* cx, unsigned argc, Value* vp) // and it provides the necessary memory fence. AutoLockFutexAPI lock; - SharedMem(addr) = view->viewDataShared().cast() + offset; + SharedMem addr = view->viewDataShared().cast() + offset; if (jit::AtomicOperations::loadSafeWhenRacy(addr) != value) { r.setString(cx->names().futexNotEqual); return true; -- cgit v1.2.3 From 9d1bfd4dc7338a39642f07eeea316f76bec43b8c Mon Sep 17 00:00:00 2001 From: trav90 Date: Sun, 12 Aug 2018 07:51:14 -0500 Subject: Avoid using memcpy on HeapSlot that is not trivially copyable. --- js/src/vm/NativeObject.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'js/src') diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h index d2c06eabc..f4199b4cf 100644 --- a/js/src/vm/NativeObject.h +++ b/js/src/vm/NativeObject.h @@ -1085,7 +1085,8 @@ class NativeObject : public ShapedObject for (uint32_t i = 0; i < count; ++i) elements_[dstStart + i].set(this, HeapSlot::Element, dstStart + i, src[i]); } else { - memcpy(&elements_[dstStart], src, count * sizeof(HeapSlot)); + memcpy(reinterpret_cast(&elements_[dstStart]), src, + count * sizeof(Value)); elementsRangeWriteBarrierPost(dstStart, count); } } @@ -1094,7 +1095,7 @@ class NativeObject : public ShapedObject MOZ_ASSERT(dstStart + count <= getDenseCapacity()); MOZ_ASSERT(!denseElementsAreCopyOnWrite()); MOZ_ASSERT(!denseElementsAreFrozen()); - memcpy(&elements_[dstStart], src, count * sizeof(HeapSlot)); + memcpy(reinterpret_cast(&elements_[dstStart]), src, count * sizeof(Value)); elementsRangeWriteBarrierPost(dstStart, count); } @@ -1129,7 +1130,8 @@ class NativeObject : public ShapedObject dst->set(this, HeapSlot::Element, dst - elements_, *src); } } else { - memmove(elements_ + dstStart, elements_ + srcStart, count * sizeof(HeapSlot)); + memmove(reinterpret_cast(elements_ + dstStart), elements_ + srcStart, + count * sizeof(Value)); elementsRangeWriteBarrierPost(dstStart, count); } } @@ -1142,7 +1144,8 @@ class NativeObject : public ShapedObject MOZ_ASSERT(!denseElementsAreCopyOnWrite()); MOZ_ASSERT(!denseElementsAreFrozen()); - memmove(elements_ + dstStart, elements_ + srcStart, count * sizeof(Value)); + memmove(reinterpret_cast(elements_ + dstStart), elements_ + srcStart, + count * sizeof(Value)); elementsRangeWriteBarrierPost(dstStart, count); } -- cgit v1.2.3 From 9ac48ef8319087fcb68d9021db0af9d5cb1080af Mon Sep 17 00:00:00 2001 From: trav90 Date: Sun, 12 Aug 2018 07:57:10 -0500 Subject: Simplify HeapSlot to make it trivially copyable This removes the constructors, which were never called since we allocate arrays of HeapSlot with pod_malloc. The destructor is only ever called explicitly since we free this memory with js_free so it has been renamed to destroy(). Also removed is an unused manual barrier. --- js/src/gc/Barrier.h | 27 ++++----------------------- js/src/vm/NativeObject.h | 10 ++++------ 2 files changed, 8 insertions(+), 29 deletions(-) (limited to 'js/src') diff --git a/js/src/gc/Barrier.h b/js/src/gc/Barrier.h index effc9233e..dce3b2a20 100644 --- a/js/src/gc/Barrier.h +++ b/js/src/gc/Barrier.h @@ -667,29 +667,15 @@ class HeapSlot : public WriteBarrieredBase Element = 1 }; - explicit HeapSlot() = delete; - - explicit HeapSlot(NativeObject* obj, Kind kind, uint32_t slot, const Value& v) - : WriteBarrieredBase(v) - { - post(obj, kind, slot, v); - } - - explicit HeapSlot(NativeObject* obj, Kind kind, uint32_t slot, const HeapSlot& s) - : WriteBarrieredBase(s.value) - { - post(obj, kind, slot, s); - } - - ~HeapSlot() { - pre(); - } - void init(NativeObject* owner, Kind kind, uint32_t slot, const Value& v) { value = v; post(owner, kind, slot, v); } + void destroy() { + pre(); + } + #ifdef DEBUG bool preconditionForSet(NativeObject* owner, Kind kind, uint32_t slot) const; bool preconditionForWriteBarrierPost(NativeObject* obj, Kind kind, uint32_t slot, @@ -703,11 +689,6 @@ class HeapSlot : public WriteBarrieredBase post(owner, kind, slot, v); } - /* For users who need to manually barrier the raw types. */ - static void writeBarrierPost(NativeObject* owner, Kind kind, uint32_t slot, const Value& target) { - reinterpret_cast(const_cast(&target))->post(owner, kind, slot, target); - } - private: void post(NativeObject* owner, Kind kind, uint32_t slot, const Value& target) { MOZ_ASSERT(preconditionForWriteBarrierPost(owner, kind, slot, target)); diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h index f4199b4cf..4dbc167ab 100644 --- a/js/src/vm/NativeObject.h +++ b/js/src/vm/NativeObject.h @@ -876,7 +876,7 @@ class NativeObject : public ShapedObject MOZ_ASSERT(end <= getDenseInitializedLength()); MOZ_ASSERT(!denseElementsAreCopyOnWrite()); for (size_t i = start; i < end; i++) - elements_[i].HeapSlot::~HeapSlot(); + elements_[i].destroy(); } /* @@ -885,7 +885,7 @@ class NativeObject : public ShapedObject */ void prepareSlotRangeForOverwrite(size_t start, size_t end) { for (size_t i = start; i < end; i++) - getSlotAddressUnchecked(i)->HeapSlot::~HeapSlot(); + getSlotAddressUnchecked(i)->destroy(); } public: @@ -1130,8 +1130,7 @@ class NativeObject : public ShapedObject dst->set(this, HeapSlot::Element, dst - elements_, *src); } } else { - memmove(reinterpret_cast(elements_ + dstStart), elements_ + srcStart, - count * sizeof(Value)); + memmove(elements_ + dstStart, elements_ + srcStart, count * sizeof(HeapSlot)); elementsRangeWriteBarrierPost(dstStart, count); } } @@ -1144,8 +1143,7 @@ class NativeObject : public ShapedObject MOZ_ASSERT(!denseElementsAreCopyOnWrite()); MOZ_ASSERT(!denseElementsAreFrozen()); - memmove(reinterpret_cast(elements_ + dstStart), elements_ + srcStart, - count * sizeof(Value)); + memmove(elements_ + dstStart, elements_ + srcStart, count * sizeof(HeapSlot)); elementsRangeWriteBarrierPost(dstStart, count); } -- cgit v1.2.3 From f214aa5dbe2c4aa3e543aecc2b6ad96d7786862e Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 30 Aug 2018 12:26:26 +0200 Subject: Revert "Bug 1444668 - Avoid allocating large AssemblerBuffers. r=luke, r=bbouvier, a=RyanVM" This reverts commit 9472136272f01b858412f2d9d7854d2daa82496f. --- js/src/jit/MacroAssembler.cpp | 6 ---- js/src/jit/ProcessExecutableMemory.cpp | 8 ++++++ js/src/jit/ProcessExecutableMemory.h | 8 ------ js/src/jit/shared/IonAssemblerBuffer.h | 4 --- js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h | 32 +--------------------- 5 files changed, 9 insertions(+), 49 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp index 9dbbe7624..f633b9b7b 100644 --- a/js/src/jit/MacroAssembler.cpp +++ b/js/src/jit/MacroAssembler.cpp @@ -2214,12 +2214,6 @@ MacroAssembler::finish() } MacroAssemblerSpecific::finish(); - - MOZ_RELEASE_ASSERT(size() <= MaxCodeBytesPerProcess, - "AssemblerBuffer should ensure we don't exceed MaxCodeBytesPerProcess"); - - if (bytesNeeded() > MaxCodeBytesPerProcess) - setOOM(); } void diff --git a/js/src/jit/ProcessExecutableMemory.cpp b/js/src/jit/ProcessExecutableMemory.cpp index 301541541..71c2ab0dc 100644 --- a/js/src/jit/ProcessExecutableMemory.cpp +++ b/js/src/jit/ProcessExecutableMemory.cpp @@ -385,6 +385,14 @@ class PageBitSet #endif }; +// Limit on the number of bytes of executable memory to prevent JIT spraying +// attacks. +#if JS_BITS_PER_WORD == 32 +static const size_t MaxCodeBytesPerProcess = 128 * 1024 * 1024; +#else +static const size_t MaxCodeBytesPerProcess = 1 * 1024 * 1024 * 1024; +#endif + // Per-process executable memory allocator. It reserves a block of memory of // MaxCodeBytesPerProcess bytes, then allocates/deallocates pages from that. // diff --git a/js/src/jit/ProcessExecutableMemory.h b/js/src/jit/ProcessExecutableMemory.h index a0e2fab98..078ce7cb7 100644 --- a/js/src/jit/ProcessExecutableMemory.h +++ b/js/src/jit/ProcessExecutableMemory.h @@ -17,14 +17,6 @@ namespace jit { // alignment though. static const size_t ExecutableCodePageSize = 64 * 1024; -// Limit on the number of bytes of executable memory to prevent JIT spraying -// attacks. -#if JS_BITS_PER_WORD == 32 -static const size_t MaxCodeBytesPerProcess = 128 * 1024 * 1024; -#else -static const size_t MaxCodeBytesPerProcess = 1 * 1024 * 1024 * 1024; -#endif - enum class ProtectionSetting { Protected, // Not readable, writable, or executable. Writable, diff --git a/js/src/jit/shared/IonAssemblerBuffer.h b/js/src/jit/shared/IonAssemblerBuffer.h index 3a6552696..cc20e26d2 100644 --- a/js/src/jit/shared/IonAssemblerBuffer.h +++ b/js/src/jit/shared/IonAssemblerBuffer.h @@ -181,10 +181,6 @@ class AssemblerBuffer protected: virtual Slice* newSlice(LifoAlloc& a) { - if (size() > MaxCodeBytesPerProcess - sizeof(Slice)) { - fail_oom(); - return nullptr; - } Slice* tmp = static_cast(a.alloc(sizeof(Slice))); if (!tmp) { fail_oom(); diff --git a/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h b/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h index fe678fc7d..8cb557784 100644 --- a/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h +++ b/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h @@ -68,33 +68,6 @@ namespace js { namespace jit { - // AllocPolicy for AssemblerBuffer. OOMs when trying to allocate more than - // MaxCodeBytesPerProcess bytes. Use private inheritance to make sure we - // explicitly have to expose SystemAllocPolicy methods. - class AssemblerBufferAllocPolicy : private SystemAllocPolicy - { - public: - using SystemAllocPolicy::checkSimulatedOOM; - using SystemAllocPolicy::reportAllocOverflow; - using SystemAllocPolicy::free_; - - template T* pod_realloc(T* p, size_t oldSize, size_t newSize) { - static_assert(sizeof(T) == 1, - "AssemblerBufferAllocPolicy should only be used with byte vectors"); - MOZ_ASSERT(oldSize <= MaxCodeBytesPerProcess); - if (MOZ_UNLIKELY(newSize > MaxCodeBytesPerProcess)) - return nullptr; - return SystemAllocPolicy::pod_realloc(p, oldSize, newSize); - } - template T* pod_malloc(size_t numElems) { - static_assert(sizeof(T) == 1, - "AssemblerBufferAllocPolicy should only be used with byte vectors"); - if (MOZ_UNLIKELY(numElems > MaxCodeBytesPerProcess)) - return nullptr; - return SystemAllocPolicy::pod_malloc(numElems); - } - }; - class AssemblerBuffer { template @@ -120,9 +93,6 @@ namespace jit { void ensureSpace(size_t space) { - // This should only be called with small |space| values to ensure - // we don't overflow below. - MOZ_ASSERT(space <= 16); if (MOZ_UNLIKELY(!m_buffer.reserve(m_buffer.length() + space))) oomDetected(); } @@ -198,7 +168,7 @@ namespace jit { m_buffer.clear(); } - PageProtectingVector m_buffer; + PageProtectingVector m_buffer; bool m_oom; }; -- cgit v1.2.3 From b4aed63f5758b955e84840c5871b1301ccb6968f Mon Sep 17 00:00:00 2001 From: trav90 Date: Sun, 2 Sep 2018 18:45:56 -0500 Subject: Convert the trailing array of BindingNames at the end of the various kinds of scope data into raw unsigned chars into which those BindingNames are placement-new'd, rather than memcpy-ing non-trivial classes around and failing to comply with the C++ object model --- js/src/frontend/BytecodeEmitter.cpp | 5 ++- js/src/frontend/ParseNode.cpp | 2 +- js/src/frontend/Parser.cpp | 76 +++++++++++++++++++++---------------- js/src/gc/Marking.cpp | 30 +++++++-------- js/src/vm/Scope.cpp | 14 +++---- js/src/vm/Scope.h | 45 +++++++++++++++++++--- 6 files changed, 108 insertions(+), 64 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index c7c615ccf..4eb7bf880 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -319,7 +319,7 @@ ScopeKindIsInBody(ScopeKind kind) static inline void MarkAllBindingsClosedOver(LexicalScope::Data& data) { - BindingName* names = data.names; + TrailingNamesArray& names = data.trailingNames; for (uint32_t i = 0; i < data.length; i++) names[i] = BindingName(names[i].name(), true); } @@ -8978,7 +8978,8 @@ BytecodeEmitter::isRestParameter(ParseNode* pn, bool* result) if (bindings->nonPositionalFormalStart > 0) { // |paramName| can be nullptr when the rest destructuring syntax is // used: `function f(...[]) {}`. - JSAtom* paramName = bindings->names[bindings->nonPositionalFormalStart - 1].name(); + JSAtom* paramName = + bindings->trailingNames[bindings->nonPositionalFormalStart - 1].name(); *result = paramName && name == paramName; return true; } diff --git a/js/src/frontend/ParseNode.cpp b/js/src/frontend/ParseNode.cpp index ece3a45df..91f17625c 100644 --- a/js/src/frontend/ParseNode.cpp +++ b/js/src/frontend/ParseNode.cpp @@ -838,7 +838,7 @@ LexicalScopeNode::dump(int indent) if (!isEmptyScope()) { LexicalScope::Data* bindings = scopeBindings(); for (uint32_t i = 0; i < bindings->length; i++) { - JSAtom* name = bindings->names[i].name(); + JSAtom* name = bindings->trailingNames[i].name(); JS::AutoCheckCannotGC nogc; if (name->hasLatin1Chars()) DumpName(name->latin1Chars(nogc), name->length()); diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 623379f61..343621194 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -19,6 +19,8 @@ #include "frontend/Parser.h" +#include + #include "jsapi.h" #include "jsatom.h" #include "jscntxt.h" @@ -1452,7 +1454,7 @@ static typename Scope::Data* NewEmptyBindingData(ExclusiveContext* cx, LifoAlloc& alloc, uint32_t numBindings) { size_t allocSize = Scope::sizeOfData(numBindings); - typename Scope::Data* bindings = static_cast(alloc.alloc(allocSize)); + auto* bindings = static_cast(alloc.alloc(allocSize)); if (!bindings) { ReportOutOfMemory(cx); return nullptr; @@ -1461,6 +1463,18 @@ NewEmptyBindingData(ExclusiveContext* cx, LifoAlloc& alloc, uint32_t numBindings return bindings; } +/** + * Copy-construct |BindingName|s from |bindings| into |cursor|, then return + * the location one past the newly-constructed |BindingName|s. + */ +static MOZ_MUST_USE BindingName* +FreshlyInitializeBindings(BindingName* cursor, const Vector& bindings) +{ + for (const BindingName& binding : bindings) + new (cursor++) BindingName(binding); + return cursor; +} + template <> Maybe Parser::newGlobalScopeData(ParseContext::Scope& scope) @@ -1505,22 +1519,20 @@ Parser::newGlobalScopeData(ParseContext::Scope& scope) return Nothing(); // The ordering here is important. See comments in GlobalScope. - BindingName* start = bindings->names; + BindingName* start = bindings->trailingNames.start(); BindingName* cursor = start; - PodCopy(cursor, funs.begin(), funs.length()); - cursor += funs.length(); + cursor = FreshlyInitializeBindings(cursor, funs); bindings->varStart = cursor - start; - PodCopy(cursor, vars.begin(), vars.length()); - cursor += vars.length(); + cursor = FreshlyInitializeBindings(cursor, vars); bindings->letStart = cursor - start; - PodCopy(cursor, lets.begin(), lets.length()); - cursor += lets.length(); + cursor = FreshlyInitializeBindings(cursor, lets); bindings->constStart = cursor - start; - PodCopy(cursor, consts.begin(), consts.length()); + cursor = FreshlyInitializeBindings(cursor, consts); + bindings->length = numBindings; } @@ -1572,22 +1584,20 @@ Parser::newModuleScopeData(ParseContext::Scope& scope) return Nothing(); // The ordering here is important. See comments in ModuleScope. - BindingName* start = bindings->names; + BindingName* start = bindings->trailingNames.start(); BindingName* cursor = start; - PodCopy(cursor, imports.begin(), imports.length()); - cursor += imports.length(); + cursor = FreshlyInitializeBindings(cursor, imports); bindings->varStart = cursor - start; - PodCopy(cursor, vars.begin(), vars.length()); - cursor += vars.length(); + cursor = FreshlyInitializeBindings(cursor, vars); bindings->letStart = cursor - start; - PodCopy(cursor, lets.begin(), lets.length()); - cursor += lets.length(); + cursor = FreshlyInitializeBindings(cursor, lets); bindings->constStart = cursor - start; - PodCopy(cursor, consts.begin(), consts.length()); + cursor = FreshlyInitializeBindings(cursor, consts); + bindings->length = numBindings; } @@ -1623,16 +1633,16 @@ Parser::newEvalScopeData(ParseContext::Scope& scope) if (!bindings) return Nothing(); - BindingName* start = bindings->names; + BindingName* start = bindings->trailingNames.start(); BindingName* cursor = start; // Keep track of what vars are functions. This is only used in BCE to omit // superfluous DEFVARs. - PodCopy(cursor, funs.begin(), funs.length()); - cursor += funs.length(); + cursor = FreshlyInitializeBindings(cursor, funs); bindings->varStart = cursor - start; - PodCopy(cursor, vars.begin(), vars.length()); + cursor = FreshlyInitializeBindings(cursor, vars); + bindings->length = numBindings; } @@ -1719,18 +1729,17 @@ Parser::newFunctionScopeData(ParseContext::Scope& scope, bool return Nothing(); // The ordering here is important. See comments in FunctionScope. - BindingName* start = bindings->names; + BindingName* start = bindings->trailingNames.start(); BindingName* cursor = start; - PodCopy(cursor, positionalFormals.begin(), positionalFormals.length()); - cursor += positionalFormals.length(); + cursor = FreshlyInitializeBindings(cursor, positionalFormals); bindings->nonPositionalFormalStart = cursor - start; - PodCopy(cursor, formals.begin(), formals.length()); - cursor += formals.length(); + cursor = FreshlyInitializeBindings(cursor, formals); bindings->varStart = cursor - start; - PodCopy(cursor, vars.begin(), vars.length()); + cursor = FreshlyInitializeBindings(cursor, vars); + bindings->length = numBindings; } @@ -1760,10 +1769,11 @@ Parser::newVarScopeData(ParseContext::Scope& scope) return Nothing(); // The ordering here is important. See comments in FunctionScope. - BindingName* start = bindings->names; + BindingName* start = bindings->trailingNames.start(); BindingName* cursor = start; - PodCopy(cursor, vars.begin(), vars.length()); + cursor = FreshlyInitializeBindings(cursor, vars); + bindings->length = numBindings; } @@ -1808,14 +1818,14 @@ Parser::newLexicalScopeData(ParseContext::Scope& scope) return Nothing(); // The ordering here is important. See comments in LexicalScope. - BindingName* cursor = bindings->names; + BindingName* cursor = bindings->trailingNames.start(); BindingName* start = cursor; - PodCopy(cursor, lets.begin(), lets.length()); - cursor += lets.length(); + cursor = FreshlyInitializeBindings(cursor, lets); bindings->constStart = cursor - start; - PodCopy(cursor, consts.begin(), consts.length()); + cursor = FreshlyInitializeBindings(cursor, consts); + bindings->length = numBindings; } diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index b2c105999..3ea4c9d29 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -1231,34 +1231,34 @@ BindingIter::trace(JSTracer* trc) void LexicalScope::Data::trace(JSTracer* trc) { - TraceBindingNames(trc, names, length); + TraceBindingNames(trc, trailingNames.start(), length); } void FunctionScope::Data::trace(JSTracer* trc) { TraceNullableEdge(trc, &canonicalFunction, "scope canonical function"); - TraceNullableBindingNames(trc, names, length); + TraceNullableBindingNames(trc, trailingNames.start(), length); } void VarScope::Data::trace(JSTracer* trc) { - TraceBindingNames(trc, names, length); + TraceBindingNames(trc, trailingNames.start(), length); } void GlobalScope::Data::trace(JSTracer* trc) { - TraceBindingNames(trc, names, length); + TraceBindingNames(trc, trailingNames.start(), length); } void EvalScope::Data::trace(JSTracer* trc) { - TraceBindingNames(trc, names, length); + TraceBindingNames(trc, trailingNames.start(), length); } void ModuleScope::Data::trace(JSTracer* trc) { TraceNullableEdge(trc, &module, "scope module"); - TraceBindingNames(trc, names, length); + TraceBindingNames(trc, trailingNames.start(), length); } void Scope::traceChildren(JSTracer* trc) @@ -1302,13 +1302,13 @@ js::GCMarker::eagerlyMarkChildren(Scope* scope) traverseEdge(scope, static_cast(scope->enclosing_)); if (scope->environmentShape_) traverseEdge(scope, static_cast(scope->environmentShape_)); - BindingName* names = nullptr; + TrailingNamesArray* names = nullptr; uint32_t length = 0; switch (scope->kind_) { case ScopeKind::Function: { FunctionScope::Data* data = reinterpret_cast(scope->data_); traverseEdge(scope, static_cast(data->canonicalFunction)); - names = data->names; + names = &data->trailingNames; length = data->length; break; } @@ -1316,7 +1316,7 @@ js::GCMarker::eagerlyMarkChildren(Scope* scope) case ScopeKind::FunctionBodyVar: case ScopeKind::ParameterExpressionVar: { VarScope::Data* data = reinterpret_cast(scope->data_); - names = data->names; + names = &data->trailingNames; length = data->length; break; } @@ -1327,7 +1327,7 @@ js::GCMarker::eagerlyMarkChildren(Scope* scope) case ScopeKind::NamedLambda: case ScopeKind::StrictNamedLambda: { LexicalScope::Data* data = reinterpret_cast(scope->data_); - names = data->names; + names = &data->trailingNames; length = data->length; break; } @@ -1335,7 +1335,7 @@ js::GCMarker::eagerlyMarkChildren(Scope* scope) case ScopeKind::Global: case ScopeKind::NonSyntactic: { GlobalScope::Data* data = reinterpret_cast(scope->data_); - names = data->names; + names = &data->trailingNames; length = data->length; break; } @@ -1343,7 +1343,7 @@ js::GCMarker::eagerlyMarkChildren(Scope* scope) case ScopeKind::Eval: case ScopeKind::StrictEval: { EvalScope::Data* data = reinterpret_cast(scope->data_); - names = data->names; + names = &data->trailingNames; length = data->length; break; } @@ -1351,7 +1351,7 @@ js::GCMarker::eagerlyMarkChildren(Scope* scope) case ScopeKind::Module: { ModuleScope::Data* data = reinterpret_cast(scope->data_); traverseEdge(scope, static_cast(data->module)); - names = data->names; + names = &data->trailingNames; length = data->length; break; } @@ -1361,12 +1361,12 @@ js::GCMarker::eagerlyMarkChildren(Scope* scope) } if (scope->kind_ == ScopeKind::Function) { for (uint32_t i = 0; i < length; i++) { - if (JSAtom* name = names[i].name()) + if (JSAtom* name = names->operator[](i).name()) traverseEdge(scope, static_cast(name)); } } else { for (uint32_t i = 0; i < length; i++) - traverseEdge(scope, static_cast(names[i].name())); + traverseEdge(scope, static_cast(names->operator[](i).name())); } } diff --git a/js/src/vm/Scope.cpp b/js/src/vm/Scope.cpp index 112b34586..25e389d8a 100644 --- a/js/src/vm/Scope.cpp +++ b/js/src/vm/Scope.cpp @@ -273,7 +273,7 @@ Scope::XDRSizedBindingNames(XDRState* xdr, Handle scope, } for (uint32_t i = 0; i < length; i++) { - if (!XDRBindingName(xdr, &data->names[i])) { + if (!XDRBindingName(xdr, &data->trailingNames[i])) { if (mode == XDR_DECODE) { DeleteScopeData(data.get()); data.set(nullptr); @@ -1250,7 +1250,7 @@ BindingIter::init(LexicalScope::Data& data, uint32_t firstFrameSlot, uint8_t fla init(0, 0, 0, 0, 0, 0, CanHaveEnvironmentSlots | flags, firstFrameSlot, JSSLOT_FREE(&LexicalEnvironmentObject::class_), - data.names, data.length); + data.trailingNames.start(), data.length); } else { // imports - [0, 0) // positional formals - [0, 0) @@ -1262,7 +1262,7 @@ BindingIter::init(LexicalScope::Data& data, uint32_t firstFrameSlot, uint8_t fla init(0, 0, 0, 0, 0, data.constStart, CanHaveFrameSlots | CanHaveEnvironmentSlots | flags, firstFrameSlot, JSSLOT_FREE(&LexicalEnvironmentObject::class_), - data.names, data.length); + data.trailingNames.start(), data.length); } } @@ -1283,7 +1283,7 @@ BindingIter::init(FunctionScope::Data& data, uint8_t flags) init(0, data.nonPositionalFormalStart, data.varStart, data.varStart, data.length, data.length, flags, 0, JSSLOT_FREE(&CallObject::class_), - data.names, data.length); + data.trailingNames.start(), data.length); } void @@ -1299,7 +1299,7 @@ BindingIter::init(VarScope::Data& data, uint32_t firstFrameSlot) init(0, 0, 0, 0, data.length, data.length, CanHaveFrameSlots | CanHaveEnvironmentSlots, firstFrameSlot, JSSLOT_FREE(&VarEnvironmentObject::class_), - data.names, data.length); + data.trailingNames.start(), data.length); } void @@ -1343,7 +1343,7 @@ BindingIter::init(EvalScope::Data& data, bool strict) // consts - [data.length, data.length) init(0, 0, 0, data.varStart, data.length, data.length, flags, firstFrameSlot, firstEnvironmentSlot, - data.names, data.length); + data.trailingNames.start(), data.length); } void @@ -1359,7 +1359,7 @@ BindingIter::init(ModuleScope::Data& data) init(data.varStart, data.varStart, data.varStart, data.varStart, data.letStart, data.constStart, CanHaveFrameSlots | CanHaveEnvironmentSlots, 0, JSSLOT_FREE(&ModuleEnvironmentObject::class_), - data.names, data.length); + data.trailingNames.start(), data.length); } PositionalFormalParameterIter::PositionalFormalParameterIter(JSScript* script) diff --git a/js/src/vm/Scope.h b/js/src/vm/Scope.h index 5304d6713..387eb30eb 100644 --- a/js/src/vm/Scope.h +++ b/js/src/vm/Scope.h @@ -111,6 +111,39 @@ class BindingName void trace(JSTracer* trc); }; +/** + * The various {Global,Module,...}Scope::Data classes consist of always-present + * bits, then a trailing array of BindingNames. The various Data classes all + * end in a TrailingNamesArray that contains sized/aligned space for *one* + * BindingName. Data instances that contain N BindingNames, are then allocated + * in sizeof(Data) + (space for (N - 1) BindingNames). Because this class's + * |data_| field is properly sized/aligned, the N-BindingName array can start + * at |data_|. + * + * This is concededly a very low-level representation, but we want to only + * allocate once for data+bindings both, and this does so approximately as + * elegantly as C++ allows. + */ +class TrailingNamesArray +{ + private: + alignas(BindingName) unsigned char data_[sizeof(BindingName)]; + + private: + // Some versions of GCC treat it as a -Wstrict-aliasing violation (ergo a + // -Werror compile error) to reinterpret_cast<> |data_| to |T*|, even + // through |void*|. Placing the latter cast in these separate functions + // breaks the chain such that affected GCC versions no longer warn/error. + void* ptr() { + return data_; + } + + public: + BindingName* start() { return reinterpret_cast(ptr()); } + + BindingName& operator[](size_t i) { return start()[i]; } +}; + class BindingLocation { public: @@ -346,7 +379,7 @@ class LexicalScope : public Scope // The array of tagged JSAtom* names, allocated beyond the end of the // struct. - BindingName names[1]; + TrailingNamesArray trailingNames; void trace(JSTracer* trc); }; @@ -462,7 +495,7 @@ class FunctionScope : public Scope // The array of tagged JSAtom* names, allocated beyond the end of the // struct. - BindingName names[1]; + TrailingNamesArray trailingNames; void trace(JSTracer* trc); }; @@ -556,7 +589,7 @@ class VarScope : public Scope // The array of tagged JSAtom* names, allocated beyond the end of the // struct. - BindingName names[1]; + TrailingNamesArray trailingNames; void trace(JSTracer* trc); }; @@ -645,7 +678,7 @@ class GlobalScope : public Scope // The array of tagged JSAtom* names, allocated beyond the end of the // struct. - BindingName names[1]; + TrailingNamesArray trailingNames; void trace(JSTracer* trc); }; @@ -745,7 +778,7 @@ class EvalScope : public Scope // The array of tagged JSAtom* names, allocated beyond the end of the // struct. - BindingName names[1]; + TrailingNamesArray trailingNames; void trace(JSTracer* trc); }; @@ -846,7 +879,7 @@ class ModuleScope : public Scope // The array of tagged JSAtom* names, allocated beyond the end of the // struct. - BindingName names[1]; + TrailingNamesArray trailingNames; void trace(JSTracer* trc); }; -- cgit v1.2.3 From 36cb80d1cac66a1511bec4ad97947a2deeab2e08 Mon Sep 17 00:00:00 2001 From: trav90 Date: Sun, 2 Sep 2018 18:59:51 -0500 Subject: Call the relevant scope-data constructor when allocating it, and poison/mark as undefined the memory for the trailing array of BindingNames, ratther than impermissibly PodZero-ing non-trivial classes. --- js/src/ds/LifoAlloc.h | 16 ++++++++++ js/src/frontend/Parser.cpp | 8 ++--- js/src/vm/Scope.cpp | 4 +-- js/src/vm/Scope.h | 75 +++++++++++++++++++++++++++++++--------------- 4 files changed, 72 insertions(+), 31 deletions(-) (limited to 'js/src') diff --git a/js/src/ds/LifoAlloc.h b/js/src/ds/LifoAlloc.h index f349cd476..b4e9c3418 100644 --- a/js/src/ds/LifoAlloc.h +++ b/js/src/ds/LifoAlloc.h @@ -15,6 +15,8 @@ #include "mozilla/TemplateLib.h" #include "mozilla/TypeTraits.h" +#include + // This data structure supports stacky LIFO allocation (mark/release and // LifoAllocScope). It does not maintain one contiguous segment; instead, it // maintains a bunch of linked memory segments. In order to prevent malloc/free @@ -285,6 +287,20 @@ class LifoAlloc return allocImpl(n); } + template + MOZ_ALWAYS_INLINE T* + allocInSize(size_t n, Args&&... args) + { + MOZ_ASSERT(n >= sizeof(T), "must request enough space to store a T"); + static_assert(alignof(T) <= detail::LIFO_ALLOC_ALIGN, + "LifoAlloc must provide enough alignment to store T"); + void* ptr = alloc(n); + if (!ptr) + return nullptr; + + return new (ptr) T(mozilla::Forward(args)...); + } + MOZ_ALWAYS_INLINE void* allocInfallible(size_t n) { AutoEnterOOMUnsafeRegion oomUnsafe; diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 343621194..7bfab87a3 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -1453,13 +1453,11 @@ template static typename Scope::Data* NewEmptyBindingData(ExclusiveContext* cx, LifoAlloc& alloc, uint32_t numBindings) { + using Data = typename Scope::Data; size_t allocSize = Scope::sizeOfData(numBindings); - auto* bindings = static_cast(alloc.alloc(allocSize)); - if (!bindings) { + auto* bindings = alloc.allocInSize(allocSize, numBindings); + if (!bindings) ReportOutOfMemory(cx); - return nullptr; - } - PodZero(bindings); return bindings; } diff --git a/js/src/vm/Scope.cpp b/js/src/vm/Scope.cpp index 25e389d8a..8bb1702ea 100644 --- a/js/src/vm/Scope.cpp +++ b/js/src/vm/Scope.cpp @@ -191,12 +191,12 @@ template static UniquePtr NewEmptyScopeData(ExclusiveContext* cx, uint32_t length = 0) { - uint8_t* bytes = cx->zone()->pod_calloc(ConcreteScope::sizeOfData(length)); + uint8_t* bytes = cx->zone()->pod_malloc(ConcreteScope::sizeOfData(length)); if (!bytes) ReportOutOfMemory(cx); auto data = reinterpret_cast(bytes); if (data) - new (data) typename ConcreteScope::Data(); + new (data) typename ConcreteScope::Data(length); return UniquePtr(data); } diff --git a/js/src/vm/Scope.h b/js/src/vm/Scope.h index 387eb30eb..1d04fd9f6 100644 --- a/js/src/vm/Scope.h +++ b/js/src/vm/Scope.h @@ -12,6 +12,7 @@ #include "jsobj.h" #include "jsopcode.h" +#include "jsutil.h" #include "gc/Heap.h" #include "gc/Policy.h" @@ -139,6 +140,14 @@ class TrailingNamesArray } public: + // Explicitly ensure no one accidentally allocates scope data without + // poisoning its trailing names. + TrailingNamesArray() = delete; + + explicit TrailingNamesArray(size_t nameCount) { + if (nameCount) + JS_POISON(&data_, 0xCC, sizeof(BindingName) * nameCount); + } BindingName* start() { return reinterpret_cast(ptr()); } BindingName& operator[](size_t i) { return start()[i]; } @@ -370,17 +379,20 @@ class LexicalScope : public Scope // // lets - [0, constStart) // consts - [constStart, length) - uint32_t constStart; - uint32_t length; + uint32_t constStart = 0; + uint32_t length = 0; // Frame slots [0, nextFrameSlot) are live when this is the innermost // scope. - uint32_t nextFrameSlot; + uint32_t nextFrameSlot = 0; // The array of tagged JSAtom* names, allocated beyond the end of the // struct. TrailingNamesArray trailingNames; + explicit Data(size_t nameCount) : trailingNames(nameCount) {} + Data() = delete; + void trace(JSTracer* trc); }; @@ -466,11 +478,11 @@ class FunctionScope : public Scope // The canonical function of the scope, as during a scope walk we // often query properties of the JSFunction (e.g., is the function an // arrow). - GCPtrFunction canonicalFunction; + GCPtrFunction canonicalFunction = {}; // If parameter expressions are present, parameters act like lexical // bindings. - bool hasParameterExprs; + bool hasParameterExprs = false; // Bindings are sorted by kind in both frames and environments. // @@ -485,18 +497,21 @@ class FunctionScope : public Scope // positional formals - [0, nonPositionalFormalStart) // other formals - [nonPositionalParamStart, varStart) // vars - [varStart, length) - uint16_t nonPositionalFormalStart; - uint16_t varStart; - uint32_t length; + uint16_t nonPositionalFormalStart = 0; + uint16_t varStart = 0; + uint32_t length = 0; // Frame slots [0, nextFrameSlot) are live when this is the innermost // scope. - uint32_t nextFrameSlot; + uint32_t nextFrameSlot = 0; // The array of tagged JSAtom* names, allocated beyond the end of the // struct. TrailingNamesArray trailingNames; + explicit Data(size_t nameCount) : trailingNames(nameCount) {} + Data() = delete; + void trace(JSTracer* trc); }; @@ -581,16 +596,19 @@ class VarScope : public Scope struct Data { // All bindings are vars. - uint32_t length; + uint32_t length = 0; // Frame slots [firstFrameSlot(), nextFrameSlot) are live when this is // the innermost scope. - uint32_t nextFrameSlot; + uint32_t nextFrameSlot = 0; // The array of tagged JSAtom* names, allocated beyond the end of the // struct. TrailingNamesArray trailingNames; + explicit Data(size_t nameCount) : trailingNames(nameCount) {} + Data() = delete; + void trace(JSTracer* trc); }; @@ -671,15 +689,18 @@ class GlobalScope : public Scope // vars - [varStart, letStart) // lets - [letStart, constStart) // consts - [constStart, length) - uint32_t varStart; - uint32_t letStart; - uint32_t constStart; - uint32_t length; + uint32_t varStart = 0; + uint32_t letStart = 0; + uint32_t constStart = 0; + uint32_t length = 0; // The array of tagged JSAtom* names, allocated beyond the end of the // struct. TrailingNamesArray trailingNames; + explicit Data(size_t nameCount) : trailingNames(nameCount) {} + Data() = delete; + void trace(JSTracer* trc); }; @@ -769,17 +790,20 @@ class EvalScope : public Scope // // top-level funcs - [0, varStart) // vars - [varStart, length) - uint32_t varStart; - uint32_t length; + uint32_t varStart = 0; + uint32_t length = 0; // Frame slots [0, nextFrameSlot) are live when this is the innermost // scope. - uint32_t nextFrameSlot; + uint32_t nextFrameSlot = 0; // The array of tagged JSAtom* names, allocated beyond the end of the // struct. TrailingNamesArray trailingNames; + explicit Data(size_t nameCount) : trailingNames(nameCount) {} + Data() = delete; + void trace(JSTracer* trc); }; @@ -860,7 +884,7 @@ class ModuleScope : public Scope struct Data { // The module of the scope. - GCPtr module; + GCPtr module = {}; // Bindings are sorted by kind. // @@ -868,19 +892,22 @@ class ModuleScope : public Scope // vars - [varStart, letStart) // lets - [letStart, constStart) // consts - [constStart, length) - uint32_t varStart; - uint32_t letStart; - uint32_t constStart; - uint32_t length; + uint32_t varStart = 0; + uint32_t letStart = 0; + uint32_t constStart = 0; + uint32_t length = 0; // Frame slots [0, nextFrameSlot) are live when this is the innermost // scope. - uint32_t nextFrameSlot; + uint32_t nextFrameSlot = 0; // The array of tagged JSAtom* names, allocated beyond the end of the // struct. TrailingNamesArray trailingNames; + explicit Data(size_t nameCount) : trailingNames(nameCount) {} + Data() = delete; + void trace(JSTracer* trc); }; -- cgit v1.2.3 From 47c5bba17a1049ca69e01981aebe858fb50c8d69 Mon Sep 17 00:00:00 2001 From: trav90 Date: Sun, 2 Sep 2018 21:01:45 -0500 Subject: Fix build bustage --- js/src/vm/Scope.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'js/src') diff --git a/js/src/vm/Scope.cpp b/js/src/vm/Scope.cpp index 8bb1702ea..a71c03695 100644 --- a/js/src/vm/Scope.cpp +++ b/js/src/vm/Scope.cpp @@ -1315,7 +1315,7 @@ BindingIter::init(GlobalScope::Data& data) init(0, 0, 0, data.varStart, data.letStart, data.constStart, CannotHaveSlots, UINT32_MAX, UINT32_MAX, - data.names, data.length); + data.trailingNames.start(), data.length); } void -- cgit v1.2.3 From 7d73b3fbfe1cd4f3a45b569f98f19041f95a50b9 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Tue, 4 Sep 2018 07:40:42 +0200 Subject: Add extra check for assembler buffer space. --- js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'js/src') diff --git a/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h b/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h index 8cb557784..8343579c8 100644 --- a/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h +++ b/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h @@ -93,7 +93,8 @@ namespace jit { void ensureSpace(size_t space) { - if (MOZ_UNLIKELY(!m_buffer.reserve(m_buffer.length() + space))) + if (MOZ_UNLIKELY(m_buffer.length() > (SIZE_MAX - space) || + !m_buffer.reserve(m_buffer.length() + space))) oomDetected(); } -- cgit v1.2.3 From 847f12e88faf1b9a34d0b6fa9b262dfed209aedb Mon Sep 17 00:00:00 2001 From: trav90 Date: Wed, 12 Sep 2018 05:41:41 -0500 Subject: Stop using PodZero in several places to initialize values of non-trivial type --- js/src/gc/GCInternals.h | 5 ++--- js/src/gc/Statistics.h | 18 +++++++----------- js/src/jit/IonCode.h | 11 ++++------- js/src/jit/shared/Assembler-shared.h | 10 +++------- js/src/vm/Caches.h | 16 ++++++++++++---- js/src/vm/Runtime.h | 15 ++++++++------- js/src/vm/String.h | 11 ++++------- js/src/vm/TypeInference.h | 20 +++++++++----------- 8 files changed, 49 insertions(+), 57 deletions(-) (limited to 'js/src') diff --git a/js/src/gc/GCInternals.h b/js/src/gc/GCInternals.h index 4919b87a5..e8df0bb70 100644 --- a/js/src/gc/GCInternals.h +++ b/js/src/gc/GCInternals.h @@ -9,7 +9,6 @@ #include "mozilla/ArrayUtils.h" #include "mozilla/Maybe.h" -#include "mozilla/PodOperations.h" #include "jscntxt.h" @@ -102,9 +101,9 @@ struct TenureCountCache static const size_t EntryShift = 4; static const size_t EntryCount = 1 << EntryShift; - TenureCount entries[EntryCount]; + TenureCount entries[EntryCount] = {}; // zeroes - TenureCountCache() { mozilla::PodZero(this); } + TenureCountCache() = default; HashNumber hash(ObjectGroup* group) { #if JS_BITS_PER_WORD == 32 diff --git a/js/src/gc/Statistics.h b/js/src/gc/Statistics.h index ca1969b2c..08a2810cf 100644 --- a/js/src/gc/Statistics.h +++ b/js/src/gc/Statistics.h @@ -10,7 +10,6 @@ #include "mozilla/EnumeratedArray.h" #include "mozilla/IntegerRange.h" #include "mozilla/Maybe.h" -#include "mozilla/PodOperations.h" #include "jsalloc.h" #include "jsgc.h" @@ -112,29 +111,26 @@ enum Stat { struct ZoneGCStats { /* Number of zones collected in this GC. */ - int collectedZoneCount; + int collectedZoneCount = 0; /* Total number of zones in the Runtime at the start of this GC. */ - int zoneCount; + int zoneCount = 0; /* Number of zones swept in this GC. */ - int sweptZoneCount; + int sweptZoneCount = 0; /* Total number of compartments in all zones collected. */ - int collectedCompartmentCount; + int collectedCompartmentCount = 0; /* Total number of compartments in the Runtime at the start of this GC. */ - int compartmentCount; + int compartmentCount = 0; /* Total number of compartments swept by this GC. */ - int sweptCompartmentCount; + int sweptCompartmentCount = 0; bool isCollectingAllZones() const { return collectedZoneCount == zoneCount; } - ZoneGCStats() - : collectedZoneCount(0), zoneCount(0), sweptZoneCount(0), - collectedCompartmentCount(0), compartmentCount(0), sweptCompartmentCount(0) - {} + ZoneGCStats() = default; }; #define FOR_EACH_GC_PROFILE_TIME(_) \ diff --git a/js/src/jit/IonCode.h b/js/src/jit/IonCode.h index c581aa62e..55c3d4dad 100644 --- a/js/src/jit/IonCode.h +++ b/js/src/jit/IonCode.h @@ -9,7 +9,6 @@ #include "mozilla/Atomics.h" #include "mozilla/MemoryReporting.h" -#include "mozilla/PodOperations.h" #include "jstypes.h" @@ -692,17 +691,15 @@ struct IonScriptCounts { private: // Any previous invalidated compilation(s) for the script. - IonScriptCounts* previous_; + IonScriptCounts* previous_ = nullptr; // Information about basic blocks in this script. - size_t numBlocks_; - IonBlockCounts* blocks_; + size_t numBlocks_ = 0; + IonBlockCounts* blocks_ = nullptr; public: - IonScriptCounts() { - mozilla::PodZero(this); - } + IonScriptCounts() = default; ~IonScriptCounts() { for (size_t i = 0; i < numBlocks_; i++) diff --git a/js/src/jit/shared/Assembler-shared.h b/js/src/jit/shared/Assembler-shared.h index aac9687b8..8044e75cb 100644 --- a/js/src/jit/shared/Assembler-shared.h +++ b/js/src/jit/shared/Assembler-shared.h @@ -7,8 +7,6 @@ #ifndef jit_shared_Assembler_shared_h #define jit_shared_Assembler_shared_h -#include "mozilla/PodOperations.h" - #include #include "jit/AtomicOp.h" @@ -491,10 +489,10 @@ class CodeLabel class CodeOffsetJump { - size_t offset_; + size_t offset_ = 0; #ifdef JS_SMALL_BRANCH - size_t jumpTableIndex_; + size_t jumpTableIndex_ = 0; #endif public: @@ -510,9 +508,7 @@ class CodeOffsetJump explicit CodeOffsetJump(size_t offset) : offset_(offset) {} #endif - CodeOffsetJump() { - mozilla::PodZero(this); - } + CodeOffsetJump() = default; size_t offset() const { return offset_; diff --git a/js/src/vm/Caches.h b/js/src/vm/Caches.h index 91a78bdc8..b11dd9dcb 100644 --- a/js/src/vm/Caches.h +++ b/js/src/vm/Caches.h @@ -7,6 +7,8 @@ #ifndef vm_Caches_h #define vm_Caches_h +#include + #include "jsatom.h" #include "jsbytecode.h" #include "jsobj.h" @@ -191,14 +193,20 @@ class NewObjectCache char templateObject[MAX_OBJ_SIZE]; }; - Entry entries[41]; // TODO: reconsider size + using EntryArray = Entry[41]; // TODO: reconsider size; + EntryArray entries; public: - typedef int EntryIndex; + using EntryIndex = int; + + NewObjectCache() + : entries{} // zeroes out the array + {} - NewObjectCache() { mozilla::PodZero(this); } - void purge() { mozilla::PodZero(this); } + void purge() { + new (&entries) EntryArray{}; // zeroes out the array + } /* Remove any cached items keyed on moved objects. */ void clearNurseryObjects(JSRuntime* rt); diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 735adadf2..f354d2069 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -11,11 +11,11 @@ #include "mozilla/Attributes.h" #include "mozilla/LinkedList.h" #include "mozilla/MemoryReporting.h" -#include "mozilla/PodOperations.h" #include "mozilla/Scoped.h" #include "mozilla/ThreadLocal.h" #include "mozilla/Vector.h" +#include #include #include "jsatom.h" @@ -1504,20 +1504,21 @@ PerThreadData::exclusiveThreadsPresent() static MOZ_ALWAYS_INLINE void MakeRangeGCSafe(Value* vec, size_t len) { - mozilla::PodZero(vec, len); + // Don't PodZero here because JS::Value is non-trivial. + for (size_t i = 0; i < len; i++) + vec[i].setDouble(+0.0); } static MOZ_ALWAYS_INLINE void MakeRangeGCSafe(Value* beg, Value* end) { - mozilla::PodZero(beg, end - beg); + MakeRangeGCSafe(beg, end - beg); } static MOZ_ALWAYS_INLINE void MakeRangeGCSafe(jsid* beg, jsid* end) { - for (jsid* id = beg; id != end; ++id) - *id = INT_TO_JSID(0); + std::fill(beg, end, INT_TO_JSID(0)); } static MOZ_ALWAYS_INLINE void @@ -1529,13 +1530,13 @@ MakeRangeGCSafe(jsid* vec, size_t len) static MOZ_ALWAYS_INLINE void MakeRangeGCSafe(Shape** beg, Shape** end) { - mozilla::PodZero(beg, end - beg); + std::fill(beg, end, nullptr); } static MOZ_ALWAYS_INLINE void MakeRangeGCSafe(Shape** vec, size_t len) { - mozilla::PodZero(vec, len); + MakeRangeGCSafe(vec, vec + len); } static MOZ_ALWAYS_INLINE void diff --git a/js/src/vm/String.h b/js/src/vm/String.h index 1a0c58575..514e2c205 100644 --- a/js/src/vm/String.h +++ b/js/src/vm/String.h @@ -8,7 +8,6 @@ #define vm_String_h #include "mozilla/MemoryReporting.h" -#include "mozilla/PodOperations.h" #include "mozilla/Range.h" #include "jsapi.h" @@ -1087,19 +1086,17 @@ class StaticStrings static const size_t SMALL_CHAR_LIMIT = 128U; static const size_t NUM_SMALL_CHARS = 64U; - JSAtom* length2StaticTable[NUM_SMALL_CHARS * NUM_SMALL_CHARS]; + JSAtom* length2StaticTable[NUM_SMALL_CHARS * NUM_SMALL_CHARS] = {}; // zeroes public: /* We keep these public for the JITs. */ static const size_t UNIT_STATIC_LIMIT = 256U; - JSAtom* unitStaticTable[UNIT_STATIC_LIMIT]; + JSAtom* unitStaticTable[UNIT_STATIC_LIMIT] = {}; // zeroes static const size_t INT_STATIC_LIMIT = 256U; - JSAtom* intStaticTable[INT_STATIC_LIMIT]; + JSAtom* intStaticTable[INT_STATIC_LIMIT] = {}; // zeroes - StaticStrings() { - mozilla::PodZero(this); - } + StaticStrings() = default; bool init(JSContext* cx); void trace(JSTracer* trc); diff --git a/js/src/vm/TypeInference.h b/js/src/vm/TypeInference.h index 9ba1c3cc8..0e737bad7 100644 --- a/js/src/vm/TypeInference.h +++ b/js/src/vm/TypeInference.h @@ -807,12 +807,10 @@ class PreliminaryObjectArray private: // All objects with the type which have been allocated. The pointers in // this array are weak. - JSObject* objects[COUNT]; + JSObject* objects[COUNT] = {}; // zeroes public: - PreliminaryObjectArray() { - mozilla::PodZero(this); - } + PreliminaryObjectArray() = default; void registerNewObject(JSObject* res); void unregisterObject(JSObject* obj); @@ -906,11 +904,11 @@ class TypeNewScript private: // Scripted function which this information was computed for. - HeapPtr function_; + HeapPtr function_ = {}; // Any preliminary objects with the type. The analyses are not performed // until this array is cleared. - PreliminaryObjectArray* preliminaryObjects; + PreliminaryObjectArray* preliminaryObjects = nullptr; // After the new script properties analyses have been performed, a template // object to use for newly constructed objects. The shape of this object @@ -918,7 +916,7 @@ class TypeNewScript // allocation kind to use. This is null if the new objects have an unboxed // layout, in which case the UnboxedLayout provides the initial structure // of the object. - HeapPtr templateObject_; + HeapPtr templateObject_ = {}; // Order in which definite properties become initialized. We need this in // case the definite properties are invalidated (such as by adding a setter @@ -928,21 +926,21 @@ class TypeNewScript // shape. Property assignments in inner frames are preceded by a series of // SETPROP_FRAME entries specifying the stack down to the frame containing // the write. - Initializer* initializerList; + Initializer* initializerList = nullptr; // If there are additional properties found by the acquired properties // analysis which were not found by the definite properties analysis, this // shape contains all such additional properties (plus the definite // properties). When an object of this group acquires this shape, it is // fully initialized and its group can be changed to initializedGroup. - HeapPtr initializedShape_; + HeapPtr initializedShape_ = {}; // Group with definite properties set for all properties found by // both the definite and acquired properties analyses. - HeapPtr initializedGroup_; + HeapPtr initializedGroup_ = {}; public: - TypeNewScript() { mozilla::PodZero(this); } + TypeNewScript() = default; ~TypeNewScript() { js_delete(preliminaryObjects); js_free(initializerList); -- cgit v1.2.3 From 8bac8c27fa3455bc0b65c5210bf9cd6bc11a33fc Mon Sep 17 00:00:00 2001 From: trav90 Date: Wed, 12 Sep 2018 19:07:57 -0500 Subject: Initialize some asm.js structures using in-class initializers instead of PodZero --- js/src/wasm/AsmJS.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'js/src') diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp index 7fade24fb..2237d1d7f 100644 --- a/js/src/wasm/AsmJS.cpp +++ b/js/src/wasm/AsmJS.cpp @@ -249,14 +249,14 @@ typedef Vector AsmJSImportVector; // case the function is toString()ed. class AsmJSExport { - uint32_t funcIndex_; + uint32_t funcIndex_ = 0; // All fields are treated as cacheable POD: - uint32_t startOffsetInModule_; // Store module-start-relative offsets - uint32_t endOffsetInModule_; // so preserved by serialization. + uint32_t startOffsetInModule_ = 0; // Store module-start-relative offsets + uint32_t endOffsetInModule_ = 0; // so preserved by serialization. public: - AsmJSExport() { PodZero(this); } + AsmJSExport() = default; AsmJSExport(uint32_t funcIndex, uint32_t startOffsetInModule, uint32_t endOffsetInModule) : funcIndex_(funcIndex), startOffsetInModule_(startOffsetInModule), @@ -288,12 +288,12 @@ enum class CacheResult struct AsmJSMetadataCacheablePod { - uint32_t numFFIs; - uint32_t srcLength; - uint32_t srcLengthWithRightBrace; - bool usesSimd; + uint32_t numFFIs = 0; + uint32_t srcLength = 0; + uint32_t srcLengthWithRightBrace = 0; + bool usesSimd = false; - AsmJSMetadataCacheablePod() { PodZero(this); } + AsmJSMetadataCacheablePod() = default; }; struct js::AsmJSMetadata : Metadata, AsmJSMetadataCacheablePod -- cgit v1.2.3 From 0712ac7f81a455b21e0065b6a212b64385835e5e Mon Sep 17 00:00:00 2001 From: trav90 Date: Wed, 12 Sep 2018 19:19:12 -0500 Subject: Don't memset-zero the BacktrackingAllocator::vregs array of non-trivial VirtualRegister instances --- js/src/jit/BacktrackingAllocator.cpp | 11 +++++------ js/src/jit/BacktrackingAllocator.h | 15 ++++++--------- 2 files changed, 11 insertions(+), 15 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/BacktrackingAllocator.cpp b/js/src/jit/BacktrackingAllocator.cpp index 94ef25785..73aceeccb 100644 --- a/js/src/jit/BacktrackingAllocator.cpp +++ b/js/src/jit/BacktrackingAllocator.cpp @@ -378,7 +378,6 @@ BacktrackingAllocator::init() size_t numVregs = graph.numVirtualRegisters(); if (!vregs.init(mir->alloc(), numVregs)) return false; - memset(&vregs[0], 0, sizeof(VirtualRegister) * numVregs); for (uint32_t i = 0; i < numVregs; i++) new(&vregs[i]) VirtualRegister(); @@ -1101,9 +1100,9 @@ BacktrackingAllocator::mergeAndQueueRegisters() if (iter->isParameter()) { for (size_t i = 0; i < iter->numDefs(); i++) { DebugOnly found = false; - VirtualRegister ¶mVreg = vreg(iter->getDef(i)); + VirtualRegister& paramVreg = vreg(iter->getDef(i)); for (; original < paramVreg.vreg(); original++) { - VirtualRegister &originalVreg = vregs[original]; + VirtualRegister& originalVreg = vregs[original]; if (*originalVreg.def()->output() == *iter->getDef(i)->output()) { MOZ_ASSERT(originalVreg.ins()->isParameter()); if (!tryMergeBundles(originalVreg.firstBundle(), paramVreg.firstBundle())) @@ -1136,7 +1135,7 @@ BacktrackingAllocator::mergeAndQueueRegisters() LBlock* block = graph.getBlock(i); for (size_t j = 0; j < block->numPhis(); j++) { LPhi* phi = block->getPhi(j); - VirtualRegister &outputVreg = vreg(phi->getDef(0)); + VirtualRegister& outputVreg = vreg(phi->getDef(0)); for (size_t k = 0, kend = phi->numOperands(); k < kend; k++) { VirtualRegister& inputVreg = vreg(phi->getOperand(k)->toUse()); if (!tryMergeBundles(inputVreg.firstBundle(), outputVreg.firstBundle())) @@ -1334,7 +1333,7 @@ BacktrackingAllocator::computeRequirement(LiveBundle* bundle, for (LiveRange::BundleLinkIterator iter = bundle->rangesBegin(); iter; iter++) { LiveRange* range = LiveRange::get(*iter); - VirtualRegister ® = vregs[range->vreg()]; + VirtualRegister& reg = vregs[range->vreg()]; if (range->hasDefinition()) { // Deal with any definition constraints/hints. @@ -1396,7 +1395,7 @@ BacktrackingAllocator::tryAllocateRegister(PhysicalRegister& r, LiveBundle* bund for (LiveRange::BundleLinkIterator iter = bundle->rangesBegin(); iter; iter++) { LiveRange* range = LiveRange::get(*iter); - VirtualRegister ® = vregs[range->vreg()]; + VirtualRegister& reg = vregs[range->vreg()]; if (!reg.isCompatible(r.reg)) return true; diff --git a/js/src/jit/BacktrackingAllocator.h b/js/src/jit/BacktrackingAllocator.h index 6d14ffacd..9910498fb 100644 --- a/js/src/jit/BacktrackingAllocator.h +++ b/js/src/jit/BacktrackingAllocator.h @@ -478,34 +478,31 @@ class LiveBundle : public TempObject class VirtualRegister { // Instruction which defines this register. - LNode* ins_; + LNode* ins_ = nullptr; // Definition in the instruction for this register. - LDefinition* def_; + LDefinition* def_ = nullptr; // All live ranges for this register. These may overlap each other, and are // ordered by their start position. InlineForwardList ranges_; // Whether def_ is a temp or an output. - bool isTemp_; + bool isTemp_ = false; // Whether this vreg is an input for some phi. This use is not reflected in // any range on the vreg. - bool usedByPhi_; + bool usedByPhi_ = false; // If this register's definition is MUST_REUSE_INPUT, whether a copy must // be introduced before the definition that relaxes the policy. - bool mustCopyInput_; + bool mustCopyInput_ = false; void operator=(const VirtualRegister&) = delete; VirtualRegister(const VirtualRegister&) = delete; public: - explicit VirtualRegister() - { - // Note: This class is zeroed before it is constructed. - } + VirtualRegister() = default; void init(LNode* ins, LDefinition* def, bool isTemp) { MOZ_ASSERT(!ins_); -- cgit v1.2.3 From 33cd07bcee1268be688a9080cbc96007f06a91f5 Mon Sep 17 00:00:00 2001 From: trav90 Date: Wed, 19 Sep 2018 18:59:49 -0500 Subject: Give uint8_clamped a defaulted (and also trivial) default constructor, copy constructor, and copy-assignment operator. This also allows uint8_clamped to be permissibly memmove'd and memcpy'd. --- js/src/vm/ArrayBufferObject.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'js/src') diff --git a/js/src/vm/ArrayBufferObject.h b/js/src/vm/ArrayBufferObject.h index 6614f5220..e9c9bc0e0 100644 --- a/js/src/vm/ArrayBufferObject.h +++ b/js/src/vm/ArrayBufferObject.h @@ -457,8 +457,8 @@ ClampDoubleToUint8(const double x); struct uint8_clamped { uint8_t val; - uint8_clamped() { } - uint8_clamped(const uint8_clamped& other) : val(other.val) { } + uint8_clamped() = default; + uint8_clamped(const uint8_clamped& other) = default; // invoke our assignment helpers for constructor conversion explicit uint8_clamped(uint8_t x) { *this = x; } @@ -469,10 +469,7 @@ struct uint8_clamped { explicit uint8_clamped(int32_t x) { *this = x; } explicit uint8_clamped(double x) { *this = x; } - uint8_clamped& operator=(const uint8_clamped& x) { - val = x.val; - return *this; - } + uint8_clamped& operator=(const uint8_clamped& x) = default; uint8_clamped& operator=(uint8_t x) { val = x; -- cgit v1.2.3 From a0737572d41efaf6faaac5e0d92f623b3292aa8e Mon Sep 17 00:00:00 2001 From: trav90 Date: Wed, 19 Sep 2018 19:05:22 -0500 Subject: Don't use PodCopy/PodMove to implement typed-array element-to-element copying Standard std::copy and std::copy_n are readily optimized to the same thing, and they don't have a non-obvious requirement that the type being copied be trivial. --- js/src/vm/TypedArrayCommon.h | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'js/src') diff --git a/js/src/vm/TypedArrayCommon.h b/js/src/vm/TypedArrayCommon.h index d29c93a65..f59419b28 100644 --- a/js/src/vm/TypedArrayCommon.h +++ b/js/src/vm/TypedArrayCommon.h @@ -11,7 +11,8 @@ #include "mozilla/Assertions.h" #include "mozilla/FloatingPoint.h" -#include "mozilla/PodOperations.h" + +#include #include "jsarray.h" #include "jscntxt.h" @@ -245,12 +246,24 @@ class UnsharedOps template static void podCopy(SharedMem dest, SharedMem src, size_t nelem) { - mozilla::PodCopy(dest.unwrapUnshared(), src.unwrapUnshared(), nelem); + // std::copy_n better matches the argument values/types of this + // function, but as noted below it allows the input/output ranges to + // overlap. std::copy does not, so use it so the compiler has extra + // ability to optimize. + const auto* first = src.unwrapUnshared(); + const auto* last = first + nelem; + auto* result = dest.unwrapUnshared(); + std::copy(first, last, result); } template - static void podMove(SharedMem dest, SharedMem src, size_t nelem) { - mozilla::PodMove(dest.unwrapUnshared(), src.unwrapUnshared(), nelem); + static void podMove(SharedMem dest, SharedMem src, size_t n) { + // std::copy_n copies from |src| to |dest| starting from |src|, so + // input/output ranges *may* permissibly overlap, as this function + // allows. + const auto* start = src.unwrapUnshared(); + auto* result = dest.unwrapUnshared(); + std::copy_n(start, n, result); } static SharedMem extract(TypedArrayObject* obj) { -- cgit v1.2.3 From 3b362e9ded0e79c86db239bed536465745c2278a Mon Sep 17 00:00:00 2001 From: trav90 Date: Wed, 19 Sep 2018 20:31:28 -0500 Subject: Rename TypeSet::clone to TypeSet::cloneIntoUninitialized to indicate that it freshly initializes the TemporaryTypeSet* provided to it. Also removes existing code that, quite unnecessarily, partly initialized that argument. --- js/src/vm/TypeInference.cpp | 15 +++++++-------- js/src/vm/TypeInference.h | 5 ++++- 2 files changed, 11 insertions(+), 9 deletions(-) (limited to 'js/src') diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index 3d09c7464..c86345d9c 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -12,6 +12,8 @@ #include "mozilla/SizePrintfMacros.h" #include "mozilla/Sprintf.h" +#include + #include "jsapi.h" #include "jscntxt.h" #include "jsgc.h" @@ -859,10 +861,8 @@ TypeSet::IsTypeAboutToBeFinalized(TypeSet::Type* v) } bool -TypeSet::clone(LifoAlloc* alloc, TemporaryTypeSet* result) const +TypeSet::cloneIntoUninitialized(LifoAlloc* alloc, TemporaryTypeSet* result) const { - MOZ_ASSERT(result->empty()); - unsigned objectCount = baseObjectCount(); unsigned capacity = (objectCount >= 2) ? TypeHashSet::Capacity(objectCount) : 0; @@ -874,15 +874,15 @@ TypeSet::clone(LifoAlloc* alloc, TemporaryTypeSet* result) const PodCopy(newSet, objectSet, capacity); } - new(result) TemporaryTypeSet(flags, capacity ? newSet : objectSet); + new (result) TemporaryTypeSet(flags, capacity ? newSet : objectSet); return true; } TemporaryTypeSet* TypeSet::clone(LifoAlloc* alloc) const { - TemporaryTypeSet* res = alloc->new_(); - if (!res || !clone(alloc, res)) + TemporaryTypeSet* res = alloc->pod_malloc(); + if (!res || !cloneIntoUninitialized(alloc, res)) return nullptr; return res; } @@ -1150,10 +1150,9 @@ TypeScript::FreezeTypeSets(CompilerConstraintList* constraints, JSScript* script TemporaryTypeSet* types = alloc->newArrayUninitialized(count); if (!types) return false; - PodZero(types, count); for (size_t i = 0; i < count; i++) { - if (!existing[i].clone(alloc, &types[i])) + if (!existing[i].cloneIntoUninitialized(alloc, &types[i])) return false; } diff --git a/js/src/vm/TypeInference.h b/js/src/vm/TypeInference.h index 0e737bad7..0f1cd4936 100644 --- a/js/src/vm/TypeInference.h +++ b/js/src/vm/TypeInference.h @@ -498,7 +498,10 @@ class TypeSet // Clone a type set into an arbitrary allocator. TemporaryTypeSet* clone(LifoAlloc* alloc) const; - bool clone(LifoAlloc* alloc, TemporaryTypeSet* result) const; + + // |*result| is not even partly initialized when this function is called: + // this function placement-new's its contents into existence. + bool cloneIntoUninitialized(LifoAlloc* alloc, TemporaryTypeSet* result) const; // Create a new TemporaryTypeSet where undefined and/or null has been filtered out. TemporaryTypeSet* filter(LifoAlloc* alloc, bool filterUndefined, bool filterNull) const; -- cgit v1.2.3 From ca7ecd37c94e268972697a37eec4e46771c6e6f2 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 4 Oct 2018 22:04:26 +0200 Subject: Bug 1493900. DiD fix. --- js/src/jit/BacktrackingAllocator.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/BacktrackingAllocator.cpp b/js/src/jit/BacktrackingAllocator.cpp index 73aceeccb..741ed1592 100644 --- a/js/src/jit/BacktrackingAllocator.cpp +++ b/js/src/jit/BacktrackingAllocator.cpp @@ -1843,10 +1843,19 @@ BacktrackingAllocator::resolveControlFlow() LiveRange* from = vreg(input).rangeFor(exitOf(predecessor), /* preferRegister = */ true); MOZ_ASSERT(from); - if (!alloc().ensureBallast()) - return false; - if (!moveAtExit(predecessor, from, to, def->type())) + if (!alloc().ensureBallast()) { return false; + } + if (mSuccessor->numPredecessors() > 1) { + MOZ_ASSERT(predecessor->mir()->numSuccessors() == 1); + if (!moveAtExit(predecessor, from, to, def->type())) { + return false; + } + } else { + if (!moveAtEntry(successor, from, to, def->type())) { + return false; + } + } } } } -- cgit v1.2.3 From 980b7e4da5d80f09cf805674b8822b260870b8d3 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Tue, 23 Oct 2018 09:44:24 +0200 Subject: Improve graph edge resolution code. This is a follow-up to ca7ecd37c94e268972697a37eec4e46771c6e6f2 further improving the DiD resolution for CVE-2018-12386. --- js/src/jit-test/tests/ion/bug1493900-1.js | 17 ++++++++++++++ js/src/jit-test/tests/ion/bug1493900-2.js | 7 ++++++ js/src/jit/BacktrackingAllocator.cpp | 38 +++++++++++++++++-------------- js/src/jit/BacktrackingAllocator.h | 3 +++ 4 files changed, 48 insertions(+), 17 deletions(-) create mode 100644 js/src/jit-test/tests/ion/bug1493900-1.js create mode 100644 js/src/jit-test/tests/ion/bug1493900-2.js (limited to 'js/src') diff --git a/js/src/jit-test/tests/ion/bug1493900-1.js b/js/src/jit-test/tests/ion/bug1493900-1.js new file mode 100644 index 000000000..643c1943d --- /dev/null +++ b/js/src/jit-test/tests/ion/bug1493900-1.js @@ -0,0 +1,17 @@ +function f() { + var objs = []; + for (var i = 0; i < 100; i++) { + objs[i] = {}; + } + var o = objs[0]; + var a = new Float64Array(1024); + function g(a, b) { + let p = b; + for (; p.x < 0; p = p.x) { + while (p === p) {} + } + for (var i = 0; i < 10000; ++i) {} + } + g(a, o); +} +f(); diff --git a/js/src/jit-test/tests/ion/bug1493900-2.js b/js/src/jit-test/tests/ion/bug1493900-2.js new file mode 100644 index 000000000..7e7f5fdec --- /dev/null +++ b/js/src/jit-test/tests/ion/bug1493900-2.js @@ -0,0 +1,7 @@ +function f(a, b) { + for (; b.x < 0; b = b.x) { + while (b === b) {}; + } + for (var i = 0; i < 99999; ++i) {} +} +f(0, 0); diff --git a/js/src/jit/BacktrackingAllocator.cpp b/js/src/jit/BacktrackingAllocator.cpp index 741ed1592..645aefc4f 100644 --- a/js/src/jit/BacktrackingAllocator.cpp +++ b/js/src/jit/BacktrackingAllocator.cpp @@ -1735,6 +1735,18 @@ BacktrackingAllocator::deadRange(LiveRange* range) return true; } +bool +BacktrackingAllocator::moveAtEdge(LBlock* predecessor, LBlock* successor, LiveRange* from, + LiveRange* to, LDefinition::Type type) +{ + if (successor->mir()->numPredecessors() > 1) { + MOZ_ASSERT(predecessor->mir()->numSuccessors() == 1); + return moveAtExit(predecessor, from, to, type); + } + + return moveAtEntry(successor, from, to, type); +} + bool BacktrackingAllocator::resolveControlFlow() { @@ -1846,15 +1858,11 @@ BacktrackingAllocator::resolveControlFlow() if (!alloc().ensureBallast()) { return false; } - if (mSuccessor->numPredecessors() > 1) { - MOZ_ASSERT(predecessor->mir()->numSuccessors() == 1); - if (!moveAtExit(predecessor, from, to, def->type())) { - return false; - } - } else { - if (!moveAtEntry(successor, from, to, def->type())) { - return false; - } + + // Note: we have to use moveAtEdge both here and below (for edge + // resolution) to avoid conflicting moves. See bug 1493900. + if (!moveAtEdge(predecessor, successor, from, to, def->type())) { + return false; } } } @@ -1884,16 +1892,12 @@ BacktrackingAllocator::resolveControlFlow() if (targetRange->covers(exitOf(predecessor))) continue; - if (!alloc().ensureBallast()) + if (!alloc().ensureBallast()) { return false; + } LiveRange* from = reg.rangeFor(exitOf(predecessor), true); - if (successor->mir()->numPredecessors() > 1) { - MOZ_ASSERT(predecessor->mir()->numSuccessors() == 1); - if (!moveAtExit(predecessor, from, targetRange, reg.type())) - return false; - } else { - if (!moveAtEntry(successor, from, targetRange, reg.type())) - return false; + if (!moveAtEdge(predecessor, successor, from, targetRange, reg.type())) { + return false; } } } diff --git a/js/src/jit/BacktrackingAllocator.h b/js/src/jit/BacktrackingAllocator.h index 9910498fb..ef3c2a572 100644 --- a/js/src/jit/BacktrackingAllocator.h +++ b/js/src/jit/BacktrackingAllocator.h @@ -774,6 +774,9 @@ class BacktrackingAllocator : protected RegisterAllocator return addMove(moves, from, to, type); } + MOZ_MUST_USE bool moveAtEdge(LBlock* predecessor, LBlock* successor, LiveRange* from, + LiveRange* to, LDefinition::Type type); + // Debugging methods. void dumpAllocations(); -- cgit v1.2.3 From b4e78255c0df5ec542a6cc0c0a644e248d4d0c5c Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Tue, 23 Oct 2018 09:44:51 +0200 Subject: Code style improvements (no bug). --- js/src/jit/BacktrackingAllocator.h | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/BacktrackingAllocator.h b/js/src/jit/BacktrackingAllocator.h index ef3c2a572..c6cf26695 100644 --- a/js/src/jit/BacktrackingAllocator.h +++ b/js/src/jit/BacktrackingAllocator.h @@ -108,8 +108,9 @@ class Requirement } MOZ_ASSERT(newRequirement.kind() == Requirement::REGISTER); - if (kind() == Requirement::FIXED) + if (kind() == Requirement::FIXED) { return allocation().isRegister(); + } *this = newRequirement; return true; @@ -353,10 +354,12 @@ class LiveRange : public TempObject // Comparator for use in range splay trees. static int compare(LiveRange* v0, LiveRange* v1) { // LiveRange includes 'from' but excludes 'to'. - if (v0->to() <= v1->from()) + if (v0->to() <= v1->from()) { return -1; - if (v0->from() >= v1->to()) + } + if (v0->from() >= v1->to()) { return 1; + } return 0; } }; @@ -642,10 +645,12 @@ class BacktrackingAllocator : protected RegisterAllocator // Comparator for use in splay tree. static int compare(CallRange* v0, CallRange* v1) { - if (v0->range.to <= v1->range.from) + if (v0->range.to <= v1->range.from) { return -1; - if (v0->range.from >= v1->range.to) + } + if (v0->range.from >= v1->range.to) { return 1; + } return 0; } }; @@ -744,32 +749,36 @@ class BacktrackingAllocator : protected RegisterAllocator MOZ_MUST_USE bool moveInput(LInstruction* ins, LiveRange* from, LiveRange* to, LDefinition::Type type) { - if (from->bundle()->allocation() == to->bundle()->allocation()) + if (from->bundle()->allocation() == to->bundle()->allocation()) { return true; + } LMoveGroup* moves = getInputMoveGroup(ins); return addMove(moves, from, to, type); } MOZ_MUST_USE bool moveAfter(LInstruction* ins, LiveRange* from, LiveRange* to, LDefinition::Type type) { - if (from->bundle()->allocation() == to->bundle()->allocation()) + if (from->bundle()->allocation() == to->bundle()->allocation()) { return true; + } LMoveGroup* moves = getMoveGroupAfter(ins); return addMove(moves, from, to, type); } MOZ_MUST_USE bool moveAtExit(LBlock* block, LiveRange* from, LiveRange* to, LDefinition::Type type) { - if (from->bundle()->allocation() == to->bundle()->allocation()) + if (from->bundle()->allocation() == to->bundle()->allocation()) { return true; + } LMoveGroup* moves = block->getExitMoveGroup(alloc()); return addMove(moves, from, to, type); } MOZ_MUST_USE bool moveAtEntry(LBlock* block, LiveRange* from, LiveRange* to, LDefinition::Type type) { - if (from->bundle()->allocation() == to->bundle()->allocation()) + if (from->bundle()->allocation() == to->bundle()->allocation()) { return true; + } LMoveGroup* moves = block->getEntryMoveGroup(alloc()); return addMove(moves, from, to, type); } -- cgit v1.2.3 From 1cfcf17a10898f8c429021c4f78bd9ae61935c52 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Wed, 31 Oct 2018 17:30:52 +0100 Subject: Don't mark MGetFirstDollarIndex as movable. --- js/src/jit/MIR.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'js/src') diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 6ec05af76..b2e84322f 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -8272,7 +8272,10 @@ class MGetFirstDollarIndex : MUnaryInstruction(str) { setResultType(MIRType::Int32); - setMovable(); + + // Codegen assumes string length > 0 but that's not guaranteed in RegExp. + // Don't allow LICM to move this. + MOZ_ASSERT(!isMovable()); } public: -- cgit v1.2.3 From 24a83a813641a6500e91f9fcf1ea3ca0aecc047a Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 1 Nov 2018 10:33:07 +0100 Subject: Simplify SIMD conversion from Uint64 to Double. --- js/src/jit/x86/Assembler-x86.h | 13 ++----------- js/src/jit/x86/BaseAssembler-x86.h | 8 -------- js/src/jit/x86/MacroAssembler-x86.cpp | 31 +++++++++++++++++++------------ 3 files changed, 21 insertions(+), 31 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/x86/Assembler-x86.h b/js/src/jit/x86/Assembler-x86.h index 3fb5efaff..5939583d9 100644 --- a/js/src/jit/x86/Assembler-x86.h +++ b/js/src/jit/x86/Assembler-x86.h @@ -421,20 +421,11 @@ class Assembler : public AssemblerX86Shared MOZ_ASSERT(dest.size() == 16); masm.vhaddpd_rr(src.encoding(), dest.encoding()); } - void vsubpd(const Operand& src1, FloatRegister src0, FloatRegister dest) { + void vsubpd(FloatRegister src1, FloatRegister src0, FloatRegister dest) { MOZ_ASSERT(HasSSE2()); MOZ_ASSERT(src0.size() == 16); MOZ_ASSERT(dest.size() == 16); - switch (src1.kind()) { - case Operand::MEM_REG_DISP: - masm.vsubpd_mr(src1.disp(), src1.base(), src0.encoding(), dest.encoding()); - break; - case Operand::MEM_ADDRESS32: - masm.vsubpd_mr(src1.address(), src0.encoding(), dest.encoding()); - break; - default: - MOZ_CRASH("unexpected operand kind"); - } + masm.vsubpd_rr(src1.encoding(), src0.encoding(), dest.encoding()); } void vpunpckldq(FloatRegister src1, FloatRegister src0, FloatRegister dest) { diff --git a/js/src/jit/x86/BaseAssembler-x86.h b/js/src/jit/x86/BaseAssembler-x86.h index 5b16311d0..caaef3f82 100644 --- a/js/src/jit/x86/BaseAssembler-x86.h +++ b/js/src/jit/x86/BaseAssembler-x86.h @@ -152,14 +152,6 @@ class BaseAssemblerX86 : public BaseAssembler { twoByteOpSimd("vsubpd", VEX_PD, OP2_SUBPS_VpsWps, src1, src0, dst); } - void vsubpd_mr(int32_t offset, RegisterID base, XMMRegisterID src0, XMMRegisterID dst) - { - twoByteOpSimd("vsubpd", VEX_PD, OP2_SUBPS_VpsWps, offset, base, src0, dst); - } - void vsubpd_mr(const void* address, XMMRegisterID src0, XMMRegisterID dst) - { - twoByteOpSimd("vsubpd", VEX_PD, OP2_SUBPS_VpsWps, address, src0, dst); - } void vpunpckldq_rr(XMMRegisterID src1, XMMRegisterID src0, XMMRegisterID dst) { twoByteOpSimd("vpunpckldq", VEX_PD, OP2_PUNPCKLDQ, src1, src0, dst); diff --git a/js/src/jit/x86/MacroAssembler-x86.cpp b/js/src/jit/x86/MacroAssembler-x86.cpp index dc97b5b5b..429a71fa9 100644 --- a/js/src/jit/x86/MacroAssembler-x86.cpp +++ b/js/src/jit/x86/MacroAssembler-x86.cpp @@ -21,15 +21,6 @@ using namespace js; using namespace js::jit; -// vpunpckldq requires 16-byte boundary for memory operand. -// See convertUInt64ToDouble for the details. -MOZ_ALIGNED_DECL(static const uint64_t, 16) TO_DOUBLE[4] = { - 0x4530000043300000LL, - 0x0LL, - 0x4330000000000000LL, - 0x4530000000000000LL -}; - static const double TO_DOUBLE_HIGH_SCALE = 0x100000000; bool @@ -90,8 +81,16 @@ MacroAssemblerX86::convertUInt64ToDouble(Register64 src, FloatRegister dest, Reg // here, each 64-bit part of dest represents following double: // HI(dest) = 0x 1.00000HHHHHHHH * 2**84 == 2**84 + 0x HHHHHHHH 00000000 // LO(dest) = 0x 1.00000LLLLLLLL * 2**52 == 2**52 + 0x 00000000 LLLLLLLL - movePtr(ImmWord((uintptr_t)TO_DOUBLE), temp); - vpunpckldq(Operand(temp, 0), dest128, dest128); + // See convertUInt64ToDouble for the details. + static const int32_t CST1[4] = { + 0x43300000, + 0x45300000, + 0x0, + 0x0, + }; + + loadConstantSimd128Int(SimdConstant::CreateX4(CST1), ScratchSimd128Reg); + vpunpckldq(ScratchSimd128Reg, dest128, dest128); // Subtract a constant C2 from dest, for each 64-bit part: // C2 = 0x 45300000 00000000 43300000 00000000 @@ -101,7 +100,15 @@ MacroAssemblerX86::convertUInt64ToDouble(Register64 src, FloatRegister dest, Reg // after the operation each 64-bit part of dest represents following: // HI(dest) = double(0x HHHHHHHH 00000000) // LO(dest) = double(0x 00000000 LLLLLLLL) - vsubpd(Operand(temp, sizeof(uint64_t) * 2), dest128, dest128); + static const int32_t CST2[4] = { + 0x0, + 0x43300000, + 0x0, + 0x45300000, + }; + + loadConstantSimd128Int(SimdConstant::CreateX4(CST2), ScratchSimd128Reg); + vsubpd(ScratchSimd128Reg, dest128, dest128); // Add HI(dest) and LO(dest) in double and store it into LO(dest), // LO(dest) = double(0x HHHHHHHH 00000000) + double(0x 00000000 LLLLLLLL) -- cgit v1.2.3 From deba73b3bc9168838034c2b5bab4b7d2945bfaaf Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 2 Nov 2018 10:32:53 +0100 Subject: Fix a longstanding IndexedDB correctness issue. Standards Compliance fix, port of Bug 1492737 --- js/src/jsapi.cpp | 18 +++++++++++++++--- js/src/jsapi.h | 6 +++++- 2 files changed, 20 insertions(+), 4 deletions(-) (limited to 'js/src') diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 85a38bba4..37d023bd4 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -2003,10 +2003,10 @@ JS_GetOwnPropertyDescriptor(JSContext* cx, HandleObject obj, const char* name, } JS_PUBLIC_API(bool) -JS_GetOwnUCPropertyDescriptor(JSContext* cx, HandleObject obj, const char16_t* name, +JS_GetOwnUCPropertyDescriptor(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, MutableHandle desc) { - JSAtom* atom = AtomizeChars(cx, name, js_strlen(name)); + JSAtom* atom = AtomizeChars(cx, name, namelen); if (!atom) return false; RootedId id(cx, AtomToId(atom)); @@ -2028,7 +2028,19 @@ JS_GetPropertyDescriptor(JSContext* cx, HandleObject obj, const char* name, if (!atom) return false; RootedId id(cx, AtomToId(atom)); - return atom && JS_GetPropertyDescriptorById(cx, obj, id, desc); + return JS_GetPropertyDescriptorById(cx, obj, id, desc); +} + +JS_PUBLIC_API(bool) +JS_GetUCPropertyDescriptor(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, + MutableHandle desc) +{ + JSAtom* atom = AtomizeChars(cx, name, namelen); + if (!atom) { + return false; + } + RootedId id(cx, AtomToId(atom)); + return JS_GetPropertyDescriptorById(cx, obj, id, desc); } static bool diff --git a/js/src/jsapi.h b/js/src/jsapi.h index c1195cc00..30c4a835a 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -2917,7 +2917,7 @@ JS_GetOwnPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char* nam JS::MutableHandle desc); extern JS_PUBLIC_API(bool) -JS_GetOwnUCPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char16_t* name, +JS_GetOwnUCPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, JS::MutableHandle desc); /** @@ -2934,6 +2934,10 @@ extern JS_PUBLIC_API(bool) JS_GetPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char* name, JS::MutableHandle desc); +extern JS_PUBLIC_API(bool) +JS_GetUCPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, + JS::MutableHandle desc); + /** * Define a property on obj. * -- cgit v1.2.3 From f2d4bd1e395f903355cc157a1de7207e5b22b7fb Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Wed, 12 Dec 2018 00:49:58 +0100 Subject: Fix mistakingly flagged instructions. This enables optimizations which were wrongly inhibited before by this typo. --- js/src/jit/IonAnalysis.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'js/src') diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index 2c9ffb607..b163d5818 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -2306,7 +2306,7 @@ jit::RemoveUnmarkedBlocks(MIRGenerator* mir, MIRGraph& graph, uint32_t numMarked // bailout. for (PostorderIterator it(graph.poBegin()); it != graph.poEnd();) { MBasicBlock* block = *it++; - if (!block->isMarked()) + if (block->isMarked()) continue; FlagAllOperandsAsHavingRemovedUses(mir, block); -- cgit v1.2.3 From 42766ad06f7d37b507a500c8d78002d25fd804f8 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 13 Dec 2018 11:34:00 +0100 Subject: Use canonical function in TypeNewScript::rollbackPartiallyInitializedObjects. --- js/src/jsfun.h | 13 +++++++++++++ js/src/vm/ObjectGroup.cpp | 7 +------ js/src/vm/TypeInference.cpp | 13 ++++++++++++- 3 files changed, 26 insertions(+), 7 deletions(-) (limited to 'js/src') diff --git a/js/src/jsfun.h b/js/src/jsfun.h index 7da831aa2..1c7da57ec 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -460,6 +460,19 @@ class JSFunction : public js::NativeObject return nonLazyScript(); } + // If this is a scripted function, returns its canonical function (the + // original function allocated by the frontend). Note that lazy self-hosted + // builtins don't have a lazy script so in that case we also return nullptr. + JSFunction* maybeCanonicalFunction() const { + if (hasScript()) { + return nonLazyScript()->functionNonDelazifying(); + } + if (isInterpretedLazy() && !isSelfHostedBuiltin()) { + return lazyScript()->functionNonDelazifying(); + } + return nullptr; + } + // The state of a JSFunction whose script errored out during bytecode // compilation. Such JSFunctions are only reachable via GC iteration and // not from script. diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp index d6a8fcaa4..1fbf8976b 100644 --- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -496,12 +496,7 @@ ObjectGroup::defaultNewGroup(ExclusiveContext* cx, const Class* clasp, // Canonicalize new functions to use the original one associated with its script. JSFunction* fun = &associated->as(); - if (fun->hasScript()) - associated = fun->nonLazyScript()->functionNonDelazifying(); - else if (fun->isInterpretedLazy() && !fun->isSelfHostedBuiltin()) - associated = fun->lazyScript()->functionNonDelazifying(); - else - associated = nullptr; + associated = associated->as().maybeCanonicalFunction(); // If we have previously cleared the 'new' script information for this // function, don't try to construct another one. diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index c86345d9c..4775a2dea 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -3603,6 +3603,10 @@ TypeNewScript::make(JSContext* cx, ObjectGroup* group, JSFunction* fun) MOZ_ASSERT(!group->newScript()); MOZ_ASSERT(!group->maybeUnboxedLayout()); + // rollbackPartiallyInitializedObjects expects function_ to be + // canonicalized. + MOZ_ASSERT(fun->maybeCanonicalFunction() == fun); + if (group->unknownProperties()) return true; @@ -3958,8 +3962,15 @@ TypeNewScript::rollbackPartiallyInitializedObjects(JSContext* cx, ObjectGroup* g oomUnsafe.crash("rollbackPartiallyInitializedObjects"); } - if (!iter.isConstructing() || !iter.matchCallee(cx, function)) + if (!iter.isConstructing()) { + continue; + } + + MOZ_ASSERT(iter.calleeTemplate()->maybeCanonicalFunction()); + + if (iter.calleeTemplate()->maybeCanonicalFunction() != function) { continue; + } // Derived class constructors initialize their this-binding later and // we shouldn't run the definite properties analysis on them. -- cgit v1.2.3 From 99b534f23d9db2a6ef6a030aeb95e297cb887dd8 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 13 Dec 2018 12:24:17 +0100 Subject: Restrict ExtractLinearSum to find non-wrapping results. --- js/src/jit/RangeAnalysis.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'js/src') diff --git a/js/src/jit/RangeAnalysis.cpp b/js/src/jit/RangeAnalysis.cpp index 95484c249..d64f9b8ca 100644 --- a/js/src/jit/RangeAnalysis.cpp +++ b/js/src/jit/RangeAnalysis.cpp @@ -2167,7 +2167,7 @@ RangeAnalysis::analyzeLoopPhi(MBasicBlock* header, LoopIterationBound* loopBound if (initial->block()->isMarked()) return; - SimpleLinearSum modified = ExtractLinearSum(phi->getLoopBackedgeOperand()); + SimpleLinearSum modified = ExtractLinearSum(phi->getLoopBackedgeOperand(), MathSpace::Infinite); if (modified.term != phi || modified.constant == 0) return; -- cgit v1.2.3 From 5335681cd2ab05ad47e81be7722c9eee19d54065 Mon Sep 17 00:00:00 2001 From: adeshkp Date: Sat, 12 Jan 2019 06:20:31 -0500 Subject: Telemetry: Remove stubs and related code --- js/src/jsapi.h | 4 ---- js/src/jsfriendapi.cpp | 11 ----------- js/src/jsfriendapi.h | 3 --- js/src/vm/Stopwatch.cpp | 7 ------- 4 files changed, 25 deletions(-) (limited to 'js/src') diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 30c4a835a..0983f034f 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -6605,10 +6605,6 @@ SetStopwatchIsMonitoringJank(JSContext*, bool); extern JS_PUBLIC_API(bool) GetStopwatchIsMonitoringJank(JSContext*); -// Extract the CPU rescheduling data. -extern JS_PUBLIC_API(void) -GetPerfMonitoringTestCpuRescheduling(JSContext*, uint64_t* stayed, uint64_t* moved); - /** * Add a number of microseconds to the time spent waiting on CPOWs diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index 595a21410..f5cd56a9b 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -543,11 +543,6 @@ js::SetPreserveWrapperCallback(JSContext* cx, PreserveWrapperCallback callback) cx->preserveWrapperCallback = callback; } -/* - * The below code is for temporary telemetry use. It can be removed when - * sufficient data has been harvested. - */ - namespace js { // Defined in vm/GlobalObject.cpp. extern size_t sSetProtoCalled; @@ -643,12 +638,6 @@ js::StringToLinearStringSlow(JSContext* cx, JSString* str) return str->ensureLinear(cx); } -JS_FRIEND_API(void) -JS_SetAccumulateTelemetryCallback(JSContext* cx, JSAccumulateTelemetryDataCallback callback) -{ - cx->setTelemetryCallback(cx, callback); -} - JS_FRIEND_API(JSObject*) JS_CloneObject(JSContext* cx, HandleObject obj, HandleObject protoArg) { diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index 722085549..a3ae23b10 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -142,9 +142,6 @@ enum { typedef void (*JSAccumulateTelemetryDataCallback)(int id, uint32_t sample, const char* key); -extern JS_FRIEND_API(void) -JS_SetAccumulateTelemetryCallback(JSContext* cx, JSAccumulateTelemetryDataCallback callback); - extern JS_FRIEND_API(bool) JS_GetIsSecureContext(JSCompartment* compartment); diff --git a/js/src/vm/Stopwatch.cpp b/js/src/vm/Stopwatch.cpp index 28632c2a1..7a6acb970 100644 --- a/js/src/vm/Stopwatch.cpp +++ b/js/src/vm/Stopwatch.cpp @@ -637,13 +637,6 @@ GetStopwatchIsMonitoringCPOW(JSContext* cx) return cx->performanceMonitoring.isMonitoringCPOW(); } -JS_PUBLIC_API(void) -GetPerfMonitoringTestCpuRescheduling(JSContext* cx, uint64_t* stayed, uint64_t* moved) -{ - *stayed = cx->performanceMonitoring.testCpuRescheduling.stayed; - *moved = cx->performanceMonitoring.testCpuRescheduling.moved; -} - JS_PUBLIC_API(void) AddCPOWPerformanceDelta(JSContext* cx, uint64_t delta) { -- cgit v1.2.3 From 3476c1d60ec29c5497123194acd7a9310b1023d2 Mon Sep 17 00:00:00 2001 From: David Teller Date: Mon, 28 Jan 2019 23:41:20 +0100 Subject: Reduce number of allocations in AutoStopwatch This patch fixes two related issues. 1. The AutoStopwatch uses a stack-allocated `mozilla::Vector` to communicate with its callback during each compartment switch. This vector was designed to allow its contents to be stack-allocated but they turned out to be accidentally heap-allocated. 2. During each tick, the stopwatch fills a vector `recentGroups_`. This vector always started with minimal capacity and had to grow repeatedly as groups were added, causing repeated reallocations. This patch preallocates `recentGroups_` to have the same capacity as the previous tick. We expect that this should eventually reach a stable size that closely matches the actual needs of the process. --- js/src/jsapi.h | 2 +- js/src/vm/Stopwatch.cpp | 24 +++++++++++++++++------- 2 files changed, 18 insertions(+), 8 deletions(-) (limited to 'js/src') diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 0983f034f..799396a0a 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -6566,7 +6566,7 @@ struct JS_PUBLIC_API(PerformanceGroup) { uint64_t refCount_; }; -using PerformanceGroupVector = mozilla::Vector, 0, SystemAllocPolicy>; +using PerformanceGroupVector = mozilla::Vector, 8, SystemAllocPolicy>; /** * Commit any Performance Monitoring data. diff --git a/js/src/vm/Stopwatch.cpp b/js/src/vm/Stopwatch.cpp index 7a6acb970..49b70c478 100644 --- a/js/src/vm/Stopwatch.cpp +++ b/js/src/vm/Stopwatch.cpp @@ -136,6 +136,9 @@ PerformanceMonitoring::start() bool PerformanceMonitoring::commit() { + // Maximum initialization size, in elements for the vector of groups. + static const size_t MAX_GROUPS_INIT_CAPACITY = 1024; + #if !defined(MOZ_HAVE_RDTSC) // The AutoStopwatch is only executed if `MOZ_HAVE_RDTSC`. return false; @@ -152,12 +155,19 @@ PerformanceMonitoring::commit() return true; } - PerformanceGroupVector recentGroups; - recentGroups_.swap(recentGroups); + // The move operation is generally constant time, unless `recentGroups_.length()` is very small, in which case it's + // fast anyway because it's small. + PerformanceGroupVector recentGroups(Move(recentGroups_)); + recentGroups_ = PerformanceGroupVector(); // Reconstruct after `Move`. bool success = true; - if (stopwatchCommitCallback) - success = stopwatchCommitCallback(iteration_, recentGroups, stopwatchCommitClosure); + if (stopwatchCommitCallback) { + success = stopwatchCommitCallback(iteration_, recentGroups, stopwatchCommitClosure); + } + + // Heuristic use: we expect to have roughly the same number of groups as in the previous iteration. + const size_t capacity = std::min(recentGroups.capacity(), MAX_GROUPS_INIT_CAPACITY); + success = recentGroups_.reserve(capacity) && success; // Reset immediately, to make sure that we're not hit by the end // of a nested event loop (which would cause `commit` to be called @@ -227,7 +237,7 @@ AutoStopwatch::AutoStopwatch(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IM MOZ_GUARD_OBJECT_NOTIFIER_INIT; JSCompartment* compartment = cx_->compartment(); - if (compartment->scheduledForDestruction) + if (MOZ_UNLIKELY(compartment->scheduledForDestruction)) return; JSRuntime* runtime = cx_->runtime(); @@ -266,11 +276,11 @@ AutoStopwatch::~AutoStopwatch() } JSCompartment* compartment = cx_->compartment(); - if (compartment->scheduledForDestruction) + if (MOZ_UNLIKELY(compartment->scheduledForDestruction)) return; JSRuntime* runtime = cx_->runtime(); - if (iteration_ != runtime->performanceMonitoring.iteration()) { + if (MOZ_UNLIKELY(iteration_ != runtime->performanceMonitoring.iteration())) { // We have entered a nested event loop at some point. // Any information we may have is obsolete. return; -- cgit v1.2.3 From abcaa560fcaf2f814fc40eef46557033c910eb96 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Tue, 29 Jan 2019 00:40:24 +0100 Subject: Revert "Reduce number of allocations in AutoStopwatch" This reverts commit 3476c1d60ec29c5497123194acd7a9310b1023d2. --- js/src/jsapi.h | 2 +- js/src/vm/Stopwatch.cpp | 24 +++++++----------------- 2 files changed, 8 insertions(+), 18 deletions(-) (limited to 'js/src') diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 799396a0a..0983f034f 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -6566,7 +6566,7 @@ struct JS_PUBLIC_API(PerformanceGroup) { uint64_t refCount_; }; -using PerformanceGroupVector = mozilla::Vector, 8, SystemAllocPolicy>; +using PerformanceGroupVector = mozilla::Vector, 0, SystemAllocPolicy>; /** * Commit any Performance Monitoring data. diff --git a/js/src/vm/Stopwatch.cpp b/js/src/vm/Stopwatch.cpp index 49b70c478..7a6acb970 100644 --- a/js/src/vm/Stopwatch.cpp +++ b/js/src/vm/Stopwatch.cpp @@ -136,9 +136,6 @@ PerformanceMonitoring::start() bool PerformanceMonitoring::commit() { - // Maximum initialization size, in elements for the vector of groups. - static const size_t MAX_GROUPS_INIT_CAPACITY = 1024; - #if !defined(MOZ_HAVE_RDTSC) // The AutoStopwatch is only executed if `MOZ_HAVE_RDTSC`. return false; @@ -155,19 +152,12 @@ PerformanceMonitoring::commit() return true; } - // The move operation is generally constant time, unless `recentGroups_.length()` is very small, in which case it's - // fast anyway because it's small. - PerformanceGroupVector recentGroups(Move(recentGroups_)); - recentGroups_ = PerformanceGroupVector(); // Reconstruct after `Move`. + PerformanceGroupVector recentGroups; + recentGroups_.swap(recentGroups); bool success = true; - if (stopwatchCommitCallback) { - success = stopwatchCommitCallback(iteration_, recentGroups, stopwatchCommitClosure); - } - - // Heuristic use: we expect to have roughly the same number of groups as in the previous iteration. - const size_t capacity = std::min(recentGroups.capacity(), MAX_GROUPS_INIT_CAPACITY); - success = recentGroups_.reserve(capacity) && success; + if (stopwatchCommitCallback) + success = stopwatchCommitCallback(iteration_, recentGroups, stopwatchCommitClosure); // Reset immediately, to make sure that we're not hit by the end // of a nested event loop (which would cause `commit` to be called @@ -237,7 +227,7 @@ AutoStopwatch::AutoStopwatch(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IM MOZ_GUARD_OBJECT_NOTIFIER_INIT; JSCompartment* compartment = cx_->compartment(); - if (MOZ_UNLIKELY(compartment->scheduledForDestruction)) + if (compartment->scheduledForDestruction) return; JSRuntime* runtime = cx_->runtime(); @@ -276,11 +266,11 @@ AutoStopwatch::~AutoStopwatch() } JSCompartment* compartment = cx_->compartment(); - if (MOZ_UNLIKELY(compartment->scheduledForDestruction)) + if (compartment->scheduledForDestruction) return; JSRuntime* runtime = cx_->runtime(); - if (MOZ_UNLIKELY(iteration_ != runtime->performanceMonitoring.iteration())) { + if (iteration_ != runtime->performanceMonitoring.iteration()) { // We have entered a nested event loop at some point. // Any information we may have is obsolete. return; -- cgit v1.2.3 From b55d41c240df13812760a2a77f086a477f450fd0 Mon Sep 17 00:00:00 2001 From: David Teller Date: Tue, 29 Jan 2019 03:11:39 +0100 Subject: Reduce number of allocations in AutoStopwatch This patch fixes two related issues. 1. The AutoStopwatch uses a stack-allocated `mozilla::Vector` to communicate with its callback during each compartment switch. This vector was designed to allow its contents to be stack-allocated but they turned out to be accidentally heap-allocated. 2. During each tick, the stopwatch fills a vector `recentGroups_`. This vector always started with minimal capacity and had to grow repeatedly as groups were added, causing repeated reallocations. This patch preallocates `recentGroups_` to have the same capacity as the previous tick. We expect that this should eventually reach a stable size that closely matches the actual needs of the process. --- js/src/jsapi.h | 2 +- js/src/vm/Stopwatch.cpp | 25 ++++++++++++++++++++----- 2 files changed, 21 insertions(+), 6 deletions(-) (limited to 'js/src') diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 0983f034f..799396a0a 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -6566,7 +6566,7 @@ struct JS_PUBLIC_API(PerformanceGroup) { uint64_t refCount_; }; -using PerformanceGroupVector = mozilla::Vector, 0, SystemAllocPolicy>; +using PerformanceGroupVector = mozilla::Vector, 8, SystemAllocPolicy>; /** * Commit any Performance Monitoring data. diff --git a/js/src/vm/Stopwatch.cpp b/js/src/vm/Stopwatch.cpp index 7a6acb970..5b5ec6196 100644 --- a/js/src/vm/Stopwatch.cpp +++ b/js/src/vm/Stopwatch.cpp @@ -20,6 +20,7 @@ #include "gc/Zone.h" #include "vm/Runtime.h" + namespace js { bool @@ -136,6 +137,9 @@ PerformanceMonitoring::start() bool PerformanceMonitoring::commit() { + // Maximal initialization size, in elements for the vector of groups. + static const size_t MAX_GROUPS_INIT_CAPACITY = 1024; + #if !defined(MOZ_HAVE_RDTSC) // The AutoStopwatch is only executed if `MOZ_HAVE_RDTSC`. return false; @@ -152,13 +156,24 @@ PerformanceMonitoring::commit() return true; } - PerformanceGroupVector recentGroups; - recentGroups_.swap(recentGroups); + // The move operation is generally constant time, unless + // `recentGroups_.length()` is very small, in which case + // it's fast just because it's small. + PerformanceGroupVector recentGroups(Move(recentGroups_)); + recentGroups_ = PerformanceGroupVector(); // Reconstruct after `Move`. bool success = true; if (stopwatchCommitCallback) success = stopwatchCommitCallback(iteration_, recentGroups, stopwatchCommitClosure); + // Heuristic: we expect to have roughly the same number of groups as in + // the previous iteration. + const size_t capacity = recentGroups.capacity() < MAX_GROUPS_INIT_CAPACITY ? + recentGroups.capacity() : + MAX_GROUPS_INIT_CAPACITY; + success = recentGroups_.reserve(capacity) + && success; + // Reset immediately, to make sure that we're not hit by the end // of a nested event loop (which would cause `commit` to be called // twice in succession). @@ -227,7 +242,7 @@ AutoStopwatch::AutoStopwatch(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IM MOZ_GUARD_OBJECT_NOTIFIER_INIT; JSCompartment* compartment = cx_->compartment(); - if (compartment->scheduledForDestruction) + if (MOZ_UNLIKELY(compartment->scheduledForDestruction)) return; JSRuntime* runtime = cx_->runtime(); @@ -266,11 +281,11 @@ AutoStopwatch::~AutoStopwatch() } JSCompartment* compartment = cx_->compartment(); - if (compartment->scheduledForDestruction) + if (MOZ_UNLIKELY(compartment->scheduledForDestruction)) return; JSRuntime* runtime = cx_->runtime(); - if (iteration_ != runtime->performanceMonitoring.iteration()) { + if (MOZ_UNLIKELY(iteration_ != runtime->performanceMonitoring.iteration())) { // We have entered a nested event loop at some point. // Any information we may have is obsolete. return; -- cgit v1.2.3 From 493c956d8de0fdb763851d9c12cfd248776b80b8 Mon Sep 17 00:00:00 2001 From: adeshkp Date: Wed, 30 Jan 2019 13:56:07 -0500 Subject: Remove telemetry leftovers from JS engine. --- js/src/frontend/Parser.cpp | 13 --- js/src/frontend/Parser.h | 2 - js/src/gc/Nursery.cpp | 8 -- js/src/gc/Statistics.cpp | 219 +++++++++++--------------------------- js/src/jscompartment.cpp | 37 ------- js/src/jscompartment.h | 31 ------ js/src/jsexn.cpp | 65 ----------- js/src/jsfriendapi.h | 40 ------- js/src/tests/user.js | 1 - js/src/vm/Runtime.cpp | 14 --- js/src/vm/Runtime.h | 10 -- js/src/vm/SelfHosting.cpp | 18 ---- js/src/vm/Stopwatch.cpp | 16 --- js/src/vm/Stopwatch.h | 30 ------ js/src/wasm/WasmBinaryConstants.h | 9 -- js/src/wasm/WasmModule.cpp | 3 - 16 files changed, 63 insertions(+), 453 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 7bfab87a3..209265a58 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -3463,7 +3463,6 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if (kind != Arrow) { #if JS_HAS_EXPR_CLOSURES - addTelemetry(JSCompartment::DeprecatedExpressionClosure); if (!warnOnceAboutExprClosure()) return false; #else @@ -5545,7 +5544,6 @@ Parser::forStatement(YieldHandling yieldHandling) if (matched) { iflags = JSITER_FOREACH; isForEach = true; - addTelemetry(JSCompartment::DeprecatedForEach); if (!warnOnceAboutForEach()) return null(); } @@ -6077,7 +6075,6 @@ Parser::yieldExpression(InHandling inHandling) } pc->functionBox()->setGeneratorKind(LegacyGenerator); - addTelemetry(JSCompartment::DeprecatedLegacyGenerator); MOZ_FALLTHROUGH; @@ -9588,16 +9585,6 @@ Parser::exprInParens(InHandling inHandling, YieldHandling yieldHan return expr(inHandling, yieldHandling, tripledotHandling, possibleError, PredictInvoked); } -template -void -Parser::addTelemetry(JSCompartment::DeprecatedLanguageExtension e) -{ - JSContext* cx = context->maybeJSContext(); - if (!cx) - return; - cx->compartment()->addTelemetry(getFilename(), e); -} - template bool Parser::warnOnceAboutExprClosure() diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index b58b021cd..12642fad8 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1420,8 +1420,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool asmJS(Node list); - void addTelemetry(JSCompartment::DeprecatedLanguageExtension e); - bool warnOnceAboutExprClosure(); bool warnOnceAboutForEach(); }; diff --git a/js/src/gc/Nursery.cpp b/js/src/gc/Nursery.cpp index 55ca5a059..ea4350fb8 100644 --- a/js/src/gc/Nursery.cpp +++ b/js/src/gc/Nursery.cpp @@ -530,7 +530,6 @@ js::Nursery::collect(JSRuntime* rt, JS::gcreason::Reason reason) // the nursery is full, look for object groups that are getting promoted // excessively and try to pretenure them. maybeStartProfile(ProfileKey::Pretenure); - uint32_t pretenureCount = 0; if (promotionRate > 0.8 || reason == JS::gcreason::FULL_STORE_BUFFER) { JSContext* cx = rt->contextFromMainThread(); for (auto& entry : tenureCounts.entries) { @@ -539,7 +538,6 @@ js::Nursery::collect(JSRuntime* rt, JS::gcreason::Reason reason) if (group->canPreTenure()) { AutoCompartment ac(cx, group->compartment()); group->setShouldPreTenure(cx); - pretenureCount++; } } } @@ -556,12 +554,6 @@ js::Nursery::collect(JSRuntime* rt, JS::gcreason::Reason reason) minorGcCount_++; int64_t totalTime = profileTimes_[ProfileKey::Total]; - rt->addTelemetry(JS_TELEMETRY_GC_MINOR_US, totalTime); - rt->addTelemetry(JS_TELEMETRY_GC_MINOR_REASON, reason); - if (totalTime > 1000) - rt->addTelemetry(JS_TELEMETRY_GC_MINOR_REASON_LONG, reason); - rt->addTelemetry(JS_TELEMETRY_GC_NURSERY_BYTES, sizeOfHeapCommitted()); - rt->addTelemetry(JS_TELEMETRY_GC_PRETENURE_COUNT, pretenureCount); rt->gc.stats.endNurseryCollection(reason); TraceMinorGCEnd(); diff --git a/js/src/gc/Statistics.cpp b/js/src/gc/Statistics.cpp index 19f9986dd..8a9f4e135 100644 --- a/js/src/gc/Statistics.cpp +++ b/js/src/gc/Statistics.cpp @@ -34,13 +34,6 @@ using mozilla::MakeRange; using mozilla::PodArrayZero; using mozilla::PodZero; -/* - * If this fails, then you can either delete this assertion and allow all - * larger-numbered reasons to pile up in the last telemetry bucket, or switch - * to GC_REASON_3 and bump the max value. - */ -JS_STATIC_ASSERT(JS::gcreason::NUM_TELEMETRY_REASONS >= JS::gcreason::NUM_REASONS); - const char* js::gcstats::ExplainInvocationKind(JSGCInvocationKind gckind) { @@ -92,7 +85,6 @@ struct PhaseInfo Phase index; const char* name; Phase parent; - const uint8_t telemetryBucket; }; // The zeroth entry in the timing arrays is used for phases that have a @@ -134,78 +126,74 @@ struct DagChildEdge { */ static const PhaseInfo phases[] = { - { PHASE_MUTATOR, "Mutator Running", PHASE_NO_PARENT, 0 }, - { PHASE_GC_BEGIN, "Begin Callback", PHASE_NO_PARENT, 1 }, - { PHASE_WAIT_BACKGROUND_THREAD, "Wait Background Thread", PHASE_NO_PARENT, 2 }, - { PHASE_MARK_DISCARD_CODE, "Mark Discard Code", PHASE_NO_PARENT, 3 }, - { PHASE_RELAZIFY_FUNCTIONS, "Relazify Functions", PHASE_NO_PARENT, 4 }, - { PHASE_PURGE, "Purge", PHASE_NO_PARENT, 5 }, - { PHASE_MARK, "Mark", PHASE_NO_PARENT, 6 }, - { PHASE_UNMARK, "Unmark", PHASE_MARK, 7 }, + { PHASE_MUTATOR, "Mutator Running", PHASE_NO_PARENT }, + { PHASE_GC_BEGIN, "Begin Callback", PHASE_NO_PARENT }, + { PHASE_WAIT_BACKGROUND_THREAD, "Wait Background Thread", PHASE_NO_PARENT }, + { PHASE_MARK_DISCARD_CODE, "Mark Discard Code", PHASE_NO_PARENT }, + { PHASE_RELAZIFY_FUNCTIONS, "Relazify Functions", PHASE_NO_PARENT }, + { PHASE_PURGE, "Purge", PHASE_NO_PARENT }, + { PHASE_MARK, "Mark", PHASE_NO_PARENT }, + { PHASE_UNMARK, "Unmark", PHASE_MARK }, /* PHASE_MARK_ROOTS */ - { PHASE_MARK_DELAYED, "Mark Delayed", PHASE_MARK, 8 }, - { PHASE_SWEEP, "Sweep", PHASE_NO_PARENT, 9 }, - { PHASE_SWEEP_MARK, "Mark During Sweeping", PHASE_SWEEP, 10 }, - { PHASE_SWEEP_MARK_TYPES, "Mark Types During Sweeping", PHASE_SWEEP_MARK, 11 }, - { PHASE_SWEEP_MARK_INCOMING_BLACK, "Mark Incoming Black Pointers", PHASE_SWEEP_MARK, 12 }, - { PHASE_SWEEP_MARK_WEAK, "Mark Weak", PHASE_SWEEP_MARK, 13 }, - { PHASE_SWEEP_MARK_INCOMING_GRAY, "Mark Incoming Gray Pointers", PHASE_SWEEP_MARK, 14 }, - { PHASE_SWEEP_MARK_GRAY, "Mark Gray", PHASE_SWEEP_MARK, 15 }, - { PHASE_SWEEP_MARK_GRAY_WEAK, "Mark Gray and Weak", PHASE_SWEEP_MARK, 16 }, - { PHASE_FINALIZE_START, "Finalize Start Callbacks", PHASE_SWEEP, 17 }, - { PHASE_WEAK_ZONEGROUP_CALLBACK, "Per-Slice Weak Callback", PHASE_FINALIZE_START, 57 }, - { PHASE_WEAK_COMPARTMENT_CALLBACK, "Per-Compartment Weak Callback", PHASE_FINALIZE_START, 58 }, - { PHASE_SWEEP_ATOMS, "Sweep Atoms", PHASE_SWEEP, 18 }, - { PHASE_SWEEP_SYMBOL_REGISTRY, "Sweep Symbol Registry", PHASE_SWEEP, 19 }, - { PHASE_SWEEP_COMPARTMENTS, "Sweep Compartments", PHASE_SWEEP, 20 }, - { PHASE_SWEEP_DISCARD_CODE, "Sweep Discard Code", PHASE_SWEEP_COMPARTMENTS, 21 }, - { PHASE_SWEEP_INNER_VIEWS, "Sweep Inner Views", PHASE_SWEEP_COMPARTMENTS, 22 }, - { PHASE_SWEEP_CC_WRAPPER, "Sweep Cross Compartment Wrappers", PHASE_SWEEP_COMPARTMENTS, 23 }, - { PHASE_SWEEP_BASE_SHAPE, "Sweep Base Shapes", PHASE_SWEEP_COMPARTMENTS, 24 }, - { PHASE_SWEEP_INITIAL_SHAPE, "Sweep Initial Shapes", PHASE_SWEEP_COMPARTMENTS, 25 }, - { PHASE_SWEEP_TYPE_OBJECT, "Sweep Type Objects", PHASE_SWEEP_COMPARTMENTS, 26 }, - { PHASE_SWEEP_BREAKPOINT, "Sweep Breakpoints", PHASE_SWEEP_COMPARTMENTS, 27 }, - { PHASE_SWEEP_REGEXP, "Sweep Regexps", PHASE_SWEEP_COMPARTMENTS, 28 }, - { PHASE_SWEEP_MISC, "Sweep Miscellaneous", PHASE_SWEEP_COMPARTMENTS, 29 }, - { PHASE_SWEEP_TYPES, "Sweep type information", PHASE_SWEEP_COMPARTMENTS, 30 }, - { PHASE_SWEEP_TYPES_BEGIN, "Sweep type tables and compilations", PHASE_SWEEP_TYPES, 31 }, - { PHASE_SWEEP_TYPES_END, "Free type arena", PHASE_SWEEP_TYPES, 32 }, - { PHASE_SWEEP_OBJECT, "Sweep Object", PHASE_SWEEP, 33 }, - { PHASE_SWEEP_STRING, "Sweep String", PHASE_SWEEP, 34 }, - { PHASE_SWEEP_SCRIPT, "Sweep Script", PHASE_SWEEP, 35 }, - { PHASE_SWEEP_SCOPE, "Sweep Scope", PHASE_SWEEP, 59 }, - { PHASE_SWEEP_SHAPE, "Sweep Shape", PHASE_SWEEP, 36 }, - { PHASE_SWEEP_JITCODE, "Sweep JIT code", PHASE_SWEEP, 37 }, - { PHASE_FINALIZE_END, "Finalize End Callback", PHASE_SWEEP, 38 }, - { PHASE_DESTROY, "Deallocate", PHASE_SWEEP, 39 }, - { PHASE_COMPACT, "Compact", PHASE_NO_PARENT, 40 }, - { PHASE_COMPACT_MOVE, "Compact Move", PHASE_COMPACT, 41 }, - { PHASE_COMPACT_UPDATE, "Compact Update", PHASE_COMPACT, 42 }, + { PHASE_MARK_DELAYED, "Mark Delayed", PHASE_MARK }, + { PHASE_SWEEP, "Sweep", PHASE_NO_PARENT }, + { PHASE_SWEEP_MARK, "Mark During Sweeping", PHASE_SWEEP }, + { PHASE_SWEEP_MARK_TYPES, "Mark Types During Sweeping", PHASE_SWEEP_MARK }, + { PHASE_SWEEP_MARK_INCOMING_BLACK, "Mark Incoming Black Pointers", PHASE_SWEEP_MARK }, + { PHASE_SWEEP_MARK_WEAK, "Mark Weak", PHASE_SWEEP_MARK }, + { PHASE_SWEEP_MARK_INCOMING_GRAY, "Mark Incoming Gray Pointers", PHASE_SWEEP_MARK }, + { PHASE_SWEEP_MARK_GRAY, "Mark Gray", PHASE_SWEEP_MARK }, + { PHASE_SWEEP_MARK_GRAY_WEAK, "Mark Gray and Weak", PHASE_SWEEP_MARK }, + { PHASE_FINALIZE_START, "Finalize Start Callbacks", PHASE_SWEEP }, + { PHASE_WEAK_ZONEGROUP_CALLBACK, "Per-Slice Weak Callback", PHASE_FINALIZE_START }, + { PHASE_WEAK_COMPARTMENT_CALLBACK, "Per-Compartment Weak Callback", PHASE_FINALIZE_START }, + { PHASE_SWEEP_ATOMS, "Sweep Atoms", PHASE_SWEEP }, + { PHASE_SWEEP_SYMBOL_REGISTRY, "Sweep Symbol Registry", PHASE_SWEEP }, + { PHASE_SWEEP_COMPARTMENTS, "Sweep Compartments", PHASE_SWEEP }, + { PHASE_SWEEP_DISCARD_CODE, "Sweep Discard Code", PHASE_SWEEP_COMPARTMENTS }, + { PHASE_SWEEP_INNER_VIEWS, "Sweep Inner Views", PHASE_SWEEP_COMPARTMENTS }, + { PHASE_SWEEP_CC_WRAPPER, "Sweep Cross Compartment Wrappers", PHASE_SWEEP_COMPARTMENTS }, + { PHASE_SWEEP_BASE_SHAPE, "Sweep Base Shapes", PHASE_SWEEP_COMPARTMENTS }, + { PHASE_SWEEP_INITIAL_SHAPE, "Sweep Initial Shapes", PHASE_SWEEP_COMPARTMENTS }, + { PHASE_SWEEP_TYPE_OBJECT, "Sweep Type Objects", PHASE_SWEEP_COMPARTMENTS }, + { PHASE_SWEEP_BREAKPOINT, "Sweep Breakpoints", PHASE_SWEEP_COMPARTMENTS }, + { PHASE_SWEEP_REGEXP, "Sweep Regexps", PHASE_SWEEP_COMPARTMENTS }, + { PHASE_SWEEP_MISC, "Sweep Miscellaneous", PHASE_SWEEP_COMPARTMENTS }, + { PHASE_SWEEP_TYPES, "Sweep type information", PHASE_SWEEP_COMPARTMENTS }, + { PHASE_SWEEP_TYPES_BEGIN, "Sweep type tables and compilations", PHASE_SWEEP_TYPES }, + { PHASE_SWEEP_TYPES_END, "Free type arena", PHASE_SWEEP_TYPES }, + { PHASE_SWEEP_OBJECT, "Sweep Object", PHASE_SWEEP }, + { PHASE_SWEEP_STRING, "Sweep String", PHASE_SWEEP }, + { PHASE_SWEEP_SCRIPT, "Sweep Script", PHASE_SWEEP }, + { PHASE_SWEEP_SCOPE, "Sweep Scope", PHASE_SWEEP }, + { PHASE_SWEEP_SHAPE, "Sweep Shape", PHASE_SWEEP }, + { PHASE_SWEEP_JITCODE, "Sweep JIT code", PHASE_SWEEP }, + { PHASE_FINALIZE_END, "Finalize End Callback", PHASE_SWEEP }, + { PHASE_DESTROY, "Deallocate", PHASE_SWEEP }, + { PHASE_COMPACT, "Compact", PHASE_NO_PARENT }, + { PHASE_COMPACT_MOVE, "Compact Move", PHASE_COMPACT }, + { PHASE_COMPACT_UPDATE, "Compact Update", PHASE_COMPACT }, /* PHASE_MARK_ROOTS */ - { PHASE_COMPACT_UPDATE_CELLS, "Compact Update Cells", PHASE_COMPACT_UPDATE, 43 }, - { PHASE_GC_END, "End Callback", PHASE_NO_PARENT, 44 }, - { PHASE_MINOR_GC, "All Minor GCs", PHASE_NO_PARENT, 45 }, + { PHASE_COMPACT_UPDATE_CELLS, "Compact Update Cells", PHASE_COMPACT_UPDATE }, + { PHASE_GC_END, "End Callback", PHASE_NO_PARENT }, + { PHASE_MINOR_GC, "All Minor GCs", PHASE_NO_PARENT }, /* PHASE_MARK_ROOTS */ - { PHASE_EVICT_NURSERY, "Minor GCs to Evict Nursery", PHASE_NO_PARENT, 46 }, + { PHASE_EVICT_NURSERY, "Minor GCs to Evict Nursery", PHASE_NO_PARENT }, /* PHASE_MARK_ROOTS */ - { PHASE_TRACE_HEAP, "Trace Heap", PHASE_NO_PARENT, 47 }, + { PHASE_TRACE_HEAP, "Trace Heap", PHASE_NO_PARENT }, /* PHASE_MARK_ROOTS */ - { PHASE_BARRIER, "Barriers", PHASE_NO_PARENT, 55 }, - { PHASE_UNMARK_GRAY, "Unmark gray", PHASE_BARRIER, 56 }, - { PHASE_MARK_ROOTS, "Mark Roots", PHASE_MULTI_PARENTS, 48 }, - { PHASE_BUFFER_GRAY_ROOTS, "Buffer Gray Roots", PHASE_MARK_ROOTS, 49 }, - { PHASE_MARK_CCWS, "Mark Cross Compartment Wrappers", PHASE_MARK_ROOTS, 50 }, - { PHASE_MARK_STACK, "Mark C and JS stacks", PHASE_MARK_ROOTS, 51 }, - { PHASE_MARK_RUNTIME_DATA, "Mark Runtime-wide Data", PHASE_MARK_ROOTS, 52 }, - { PHASE_MARK_EMBEDDING, "Mark Embedding", PHASE_MARK_ROOTS, 53 }, - { PHASE_MARK_COMPARTMENTS, "Mark Compartments", PHASE_MARK_ROOTS, 54 }, - { PHASE_PURGE_SHAPE_TABLES, "Purge ShapeTables", PHASE_NO_PARENT, 60 }, - - { PHASE_LIMIT, nullptr, PHASE_NO_PARENT, 60 } - - // Current number of telemetryBuckets is 60. If you insert new phases - // somewhere, start at that number and count up. Do not change any existing - // numbers. + { PHASE_BARRIER, "Barriers", PHASE_NO_PARENT }, + { PHASE_UNMARK_GRAY, "Unmark gray", PHASE_BARRIER }, + { PHASE_MARK_ROOTS, "Mark Roots", PHASE_MULTI_PARENTS }, + { PHASE_BUFFER_GRAY_ROOTS, "Buffer Gray Roots", PHASE_MARK_ROOTS }, + { PHASE_MARK_CCWS, "Mark Cross Compartment Wrappers", PHASE_MARK_ROOTS }, + { PHASE_MARK_STACK, "Mark C and JS stacks", PHASE_MARK_ROOTS }, + { PHASE_MARK_RUNTIME_DATA, "Mark Runtime-wide Data", PHASE_MARK_ROOTS }, + { PHASE_MARK_EMBEDDING, "Mark Embedding", PHASE_MARK_ROOTS }, + { PHASE_MARK_COMPARTMENTS, "Mark Compartments", PHASE_MARK_ROOTS }, + { PHASE_PURGE_SHAPE_TABLES, "Purge ShapeTables", PHASE_NO_PARENT }, + + { PHASE_LIMIT, nullptr, PHASE_NO_PARENT } }; static ExtraPhaseInfo phaseExtra[PHASE_LIMIT] = { { 0, 0 } }; @@ -845,12 +833,6 @@ Statistics::~Statistics() /* static */ bool Statistics::initialize() { - for (size_t i = 0; i < PHASE_LIMIT; i++) { - MOZ_ASSERT(phases[i].index == i); - for (size_t j = 0; j < PHASE_LIMIT; j++) - MOZ_ASSERT_IF(i != j, phases[i].telemetryBucket != phases[j].telemetryBucket); - } - // Create a static table of descendants for every phase with multiple // children. This assumes that all descendants come linearly in the // list, which is reasonable since full dags are not supported; any @@ -925,32 +907,6 @@ Statistics::getMaxGCPauseSinceClear() return maxPauseInInterval; } -// Sum up the time for a phase, including instances of the phase with different -// parents. -static int64_t -SumPhase(Phase phase, const Statistics::PhaseTimeTable times) -{ - int64_t sum = 0; - for (auto i : MakeRange(Statistics::NumTimingArrays)) - sum += times[i][phase]; - return sum; -} - -static Phase -LongestPhase(const Statistics::PhaseTimeTable times) -{ - int64_t longestTime = 0; - Phase longestPhase = PHASE_NONE; - for (size_t i = 0; i < PHASE_LIMIT; ++i) { - int64_t phaseTime = SumPhase(Phase(i), times); - if (phaseTime > longestTime) { - longestTime = phaseTime; - longestPhase = Phase(i); - } - } - return longestPhase; -} - void Statistics::printStats() { @@ -985,34 +941,6 @@ Statistics::endGC() int64_t total, longest; gcDuration(&total, &longest); - int64_t sccTotal, sccLongest; - sccDurations(&sccTotal, &sccLongest); - - runtime->addTelemetry(JS_TELEMETRY_GC_IS_ZONE_GC, !zoneStats.isCollectingAllZones()); - runtime->addTelemetry(JS_TELEMETRY_GC_MS, t(total)); - runtime->addTelemetry(JS_TELEMETRY_GC_MAX_PAUSE_MS, t(longest)); - int64_t markTotal = SumPhase(PHASE_MARK, phaseTimes); - int64_t markRootsTotal = SumPhase(PHASE_MARK_ROOTS, phaseTimes); - runtime->addTelemetry(JS_TELEMETRY_GC_MARK_MS, t(markTotal)); - runtime->addTelemetry(JS_TELEMETRY_GC_SWEEP_MS, t(phaseTimes[PHASE_DAG_NONE][PHASE_SWEEP])); - if (runtime->gc.isCompactingGc()) { - runtime->addTelemetry(JS_TELEMETRY_GC_COMPACT_MS, - t(phaseTimes[PHASE_DAG_NONE][PHASE_COMPACT])); - } - runtime->addTelemetry(JS_TELEMETRY_GC_MARK_ROOTS_MS, t(markRootsTotal)); - runtime->addTelemetry(JS_TELEMETRY_GC_MARK_GRAY_MS, t(phaseTimes[PHASE_DAG_NONE][PHASE_SWEEP_MARK_GRAY])); - runtime->addTelemetry(JS_TELEMETRY_GC_NON_INCREMENTAL, nonincremental()); - if (nonincremental()) - runtime->addTelemetry(JS_TELEMETRY_GC_NON_INCREMENTAL_REASON, uint32_t(nonincrementalReason_)); - runtime->addTelemetry(JS_TELEMETRY_GC_INCREMENTAL_DISABLED, !runtime->gc.isIncrementalGCAllowed()); - runtime->addTelemetry(JS_TELEMETRY_GC_SCC_SWEEP_TOTAL_MS, t(sccTotal)); - runtime->addTelemetry(JS_TELEMETRY_GC_SCC_SWEEP_MAX_PAUSE_MS, t(sccLongest)); - - if (!aborted) { - double mmu50 = computeMMU(50 * PRMJ_USEC_PER_MSEC); - runtime->addTelemetry(JS_TELEMETRY_GC_MMU_50, mmu50 * 100); - } - if (fp) printStats(); @@ -1061,8 +989,6 @@ Statistics::beginSlice(const ZoneGCStats& zoneStats, JSGCInvocationKind gckind, return; } - runtime->addTelemetry(JS_TELEMETRY_GC_REASON, reason); - // Slice callbacks should only fire for the outermost level. if (gcDepth == 1) { bool wasFullGC = zoneStats.isCollectingAllZones(); @@ -1082,25 +1008,6 @@ Statistics::endSlice() slices.back().endFaults = GetPageFaultCount(); slices.back().finalState = runtime->gc.state(); - int64_t sliceTime = slices.back().end - slices.back().start; - runtime->addTelemetry(JS_TELEMETRY_GC_SLICE_MS, t(sliceTime)); - runtime->addTelemetry(JS_TELEMETRY_GC_RESET, slices.back().wasReset()); - if (slices.back().wasReset()) - runtime->addTelemetry(JS_TELEMETRY_GC_RESET_REASON, uint32_t(slices.back().resetReason)); - - if (slices.back().budget.isTimeBudget()) { - int64_t budget_ms = slices.back().budget.timeBudget.budget; - runtime->addTelemetry(JS_TELEMETRY_GC_BUDGET_MS, budget_ms); - if (budget_ms == runtime->gc.defaultSliceBudget()) - runtime->addTelemetry(JS_TELEMETRY_GC_ANIMATION_MS, t(sliceTime)); - - // Record any phase that goes more than 2x over its budget. - if (sliceTime > 2 * budget_ms * 1000) { - Phase longest = LongestPhase(slices.back().phaseTimes); - runtime->addTelemetry(JS_TELEMETRY_GC_SLOW_PHASE, phases[longest].telemetryBucket); - } - } - sliceCount_++; } diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index 4e4ccdf2a..a48bb0ffe 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -41,7 +41,6 @@ using namespace js::gc; using namespace js::jit; using mozilla::DebugOnly; -using mozilla::PodArrayZero; JSCompartment::JSCompartment(Zone* zone, const JS::CompartmentOptions& options = JS::CompartmentOptions()) : creationOptions_(options.creationOptions()), @@ -91,7 +90,6 @@ JSCompartment::JSCompartment(Zone* zone, const JS::CompartmentOptions& options = unmappedArgumentsTemplate_(nullptr), lcovOutput() { - PodArrayZero(sawDeprecatedLanguageExtension); runtime_->numCompartments++; MOZ_ASSERT_IF(creationOptions_.mergeable(), creationOptions_.invisibleToDebugger()); @@ -99,8 +97,6 @@ JSCompartment::JSCompartment(Zone* zone, const JS::CompartmentOptions& options = JSCompartment::~JSCompartment() { - reportTelemetry(); - // Write the code coverage information in a file. JSRuntime* rt = runtimeFromMainThread(); if (rt->lcovOutput.isEnabled()) @@ -1268,39 +1264,6 @@ JSCompartment::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, *privateData += callback(mallocSizeOf, this); } -void -JSCompartment::reportTelemetry() -{ - // Only report telemetry for web content and add-ons, not chrome JS. - if (isSystem_) - return; - - // Hazard analysis can't tell that the telemetry callbacks don't GC. - JS::AutoSuppressGCAnalysis nogc; - - int id = creationOptions_.addonIdOrNull() - ? JS_TELEMETRY_DEPRECATED_LANGUAGE_EXTENSIONS_IN_ADDONS - : JS_TELEMETRY_DEPRECATED_LANGUAGE_EXTENSIONS_IN_CONTENT; - - // Call back into Firefox's Telemetry reporter. - for (size_t i = 0; i < DeprecatedLanguageExtensionCount; i++) { - if (sawDeprecatedLanguageExtension[i]) - runtime_->addTelemetry(id, i); - } -} - -void -JSCompartment::addTelemetry(const char* filename, DeprecatedLanguageExtension e) -{ - // Only report telemetry for web content and add-ons, not chrome JS. - if (isSystem_) - return; - if (!creationOptions_.addonIdOrNull() && (!filename || strncmp(filename, "http", 4) != 0)) - return; - - sawDeprecatedLanguageExtension[e] = true; -} - HashNumber JSCompartment::randomHashCode() { diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index 7bfeee1f6..98c8fe200 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -344,13 +344,6 @@ struct JSCompartment isAtomsCompartment_ = true; } - // Used to approximate non-content code when reporting telemetry. - inline bool isProbablySystemOrAddonCode() const { - if (creationOptions_.addonIdOrNull()) - return true; - - return isSystem_; - } private: JSPrincipals* principals_; bool isSystem_; @@ -879,34 +872,10 @@ struct JSCompartment return jitCompartment_; } - enum DeprecatedLanguageExtension { - DeprecatedForEach = 0, // JS 1.6+ - // NO LONGER USING 1 - DeprecatedLegacyGenerator = 2, // JS 1.7+ - DeprecatedExpressionClosure = 3, // Added in JS 1.8 - // NO LONGER USING 4 - // NO LONGER USING 5 - // NO LONGER USING 6 - // NO LONGER USING 7 - // NO LONGER USING 8 - // NO LONGER USING 9 - DeprecatedBlockScopeFunRedecl = 10, - DeprecatedLanguageExtensionCount - }; - js::ArgumentsObject* getOrCreateArgumentsTemplateObject(JSContext* cx, bool mapped); js::ArgumentsObject* maybeArgumentsTemplateObject(bool mapped) const; - private: - // Used for collecting telemetry on SpiderMonkey's deprecated language extensions. - bool sawDeprecatedLanguageExtension[DeprecatedLanguageExtensionCount]; - - void reportTelemetry(); - - public: - void addTelemetry(const char* filename, DeprecatedLanguageExtension e); - public: // Aggregated output used to collect JSScript hit counts when code coverage // is enabled. diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index 9a8e364ed..1e70a3890 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -707,67 +707,6 @@ ErrorReport::~ErrorReport() { } -void -ErrorReport::ReportAddonExceptionToTelementry(JSContext* cx) -{ - MOZ_ASSERT(exnObject); - RootedObject unwrapped(cx, UncheckedUnwrap(exnObject)); - MOZ_ASSERT(unwrapped, "UncheckedUnwrap failed?"); - - // There is not much we can report if the exception is not an ErrorObject, let's ignore those. - if (!unwrapped->is()) - return; - - Rooted errObj(cx, &unwrapped->as()); - RootedObject stack(cx, errObj->stack()); - - // Let's ignore TOP level exceptions. For regular add-ons those will not be reported anyway, - // for SDK based once it should not be a valid case either. - // At this point the frame stack is unwound but the exception object stored the stack so let's - // use that for getting the function name. - if (!stack) - return; - - JSCompartment* comp = stack->compartment(); - JSAddonId* addonId = comp->creationOptions().addonIdOrNull(); - - // We only want to send the report if the scope that just have thrown belongs to an add-on. - // Let's check the compartment of the youngest function on the stack, to determine that. - if (!addonId) - return; - - RootedString funnameString(cx); - JS::SavedFrameResult result = GetSavedFrameFunctionDisplayName(cx, stack, &funnameString); - // AccessDenied should never be the case here for add-ons but let's not risk it. - JSAutoByteString bytes; - const char* funname = nullptr; - bool denied = result == JS::SavedFrameResult::AccessDenied; - funname = denied ? "unknown" - : funnameString ? AtomToPrintableString(cx, - &funnameString->asAtom(), - &bytes) - : "anonymous"; - - UniqueChars addonIdChars(JS_EncodeString(cx, addonId)); - - const char* filename = nullptr; - if (reportp && reportp->filename) { - filename = strrchr(reportp->filename, '/'); - if (filename) - filename++; - } - if (!filename) { - filename = "FILE_NOT_FOUND"; - } - char histogramKey[64]; - SprintfLiteral(histogramKey, "%s %s %s %u", - addonIdChars.get(), - funname, - filename, - (reportp ? reportp->lineno : 0) ); - cx->runtime()->addTelemetry(JS_TELEMETRY_ADDON_EXCEPTIONS, 1, histogramKey); -} - bool ErrorReport::init(JSContext* cx, HandleValue exn, SniffingBehavior sniffingBehavior) @@ -786,10 +725,6 @@ ErrorReport::init(JSContext* cx, HandleValue exn, JSMSG_ERR_DURING_THROW); return false; } - - // Let's see if the exception is from add-on code, if so, it should be reported - // to telementry. - ReportAddonExceptionToTelementry(cx); } diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index a3ae23b10..d29285483 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -105,43 +105,6 @@ JS_TraceShapeCycleCollectorChildren(JS::CallbackTracer* trc, JS::GCCellPtr shape extern JS_FRIEND_API(void) JS_TraceObjectGroupCycleCollectorChildren(JS::CallbackTracer* trc, JS::GCCellPtr group); -enum { - JS_TELEMETRY_GC_REASON, - JS_TELEMETRY_GC_IS_ZONE_GC, - JS_TELEMETRY_GC_MS, - JS_TELEMETRY_GC_BUDGET_MS, - JS_TELEMETRY_GC_ANIMATION_MS, - JS_TELEMETRY_GC_MAX_PAUSE_MS, - JS_TELEMETRY_GC_MARK_MS, - JS_TELEMETRY_GC_SWEEP_MS, - JS_TELEMETRY_GC_COMPACT_MS, - JS_TELEMETRY_GC_MARK_ROOTS_MS, - JS_TELEMETRY_GC_MARK_GRAY_MS, - JS_TELEMETRY_GC_SLICE_MS, - JS_TELEMETRY_GC_SLOW_PHASE, - JS_TELEMETRY_GC_MMU_50, - JS_TELEMETRY_GC_RESET, - JS_TELEMETRY_GC_RESET_REASON, - JS_TELEMETRY_GC_INCREMENTAL_DISABLED, - JS_TELEMETRY_GC_NON_INCREMENTAL, - JS_TELEMETRY_GC_NON_INCREMENTAL_REASON, - JS_TELEMETRY_GC_SCC_SWEEP_TOTAL_MS, - JS_TELEMETRY_GC_SCC_SWEEP_MAX_PAUSE_MS, - JS_TELEMETRY_GC_MINOR_REASON, - JS_TELEMETRY_GC_MINOR_REASON_LONG, - JS_TELEMETRY_GC_MINOR_US, - JS_TELEMETRY_GC_NURSERY_BYTES, - JS_TELEMETRY_GC_PRETENURE_COUNT, - JS_TELEMETRY_DEPRECATED_LANGUAGE_EXTENSIONS_IN_CONTENT, - JS_TELEMETRY_DEPRECATED_LANGUAGE_EXTENSIONS_IN_ADDONS, - JS_TELEMETRY_ADDON_EXCEPTIONS, - JS_TELEMETRY_AOT_USAGE, - JS_TELEMETRY_END -}; - -typedef void -(*JSAccumulateTelemetryDataCallback)(int id, uint32_t sample, const char* key); - extern JS_FRIEND_API(bool) JS_GetIsSecureContext(JSCompartment* compartment); @@ -1453,9 +1416,6 @@ struct MOZ_STACK_CLASS JS_FRIEND_API(ErrorReport) bool populateUncaughtExceptionReportUTF8(JSContext* cx, ...); bool populateUncaughtExceptionReportUTF8VA(JSContext* cx, va_list ap); - // Reports exceptions from add-on scopes to telementry. - void ReportAddonExceptionToTelementry(JSContext* cx); - // We may have a provided JSErrorReport, so need a way to represent that. JSErrorReport* reportp; diff --git a/js/src/tests/user.js b/js/src/tests/user.js index 732bbbd1a..e75593ab1 100755 --- a/js/src/tests/user.js +++ b/js/src/tests/user.js @@ -22,7 +22,6 @@ user_pref("javascript.options.strict", false); user_pref("javascript.options.werror", false); user_pref("toolkit.startup.max_resumed_crashes", -1); user_pref("security.turn_off_all_security_so_that_viruses_can_take_over_this_computer", true); -user_pref("toolkit.telemetry.enabled", false); user_pref("browser.safebrowsing.phishing.enabled", false); user_pref("browser.safebrowsing.malware.enabled", false); user_pref("browser.safebrowsing.forbiddenURIs.enabled", false); diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index 174e23594..8eb997c71 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -147,7 +147,6 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime) updateChildRuntimeCount(parentRuntime), #endif interrupt_(false), - telemetryCallback(nullptr), handlingSegFault(false), handlingJitInterrupt_(false), interruptCallbackDisabled(false), @@ -451,19 +450,6 @@ JSRuntime::destroyRuntime() #endif } -void -JSRuntime::addTelemetry(int id, uint32_t sample, const char* key) -{ - if (telemetryCallback) - (*telemetryCallback)(id, sample, key); -} - -void -JSRuntime::setTelemetryCallback(JSRuntime* rt, JSAccumulateTelemetryDataCallback callback) -{ - rt->telemetryCallback = callback; -} - void JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes* rtSizes) { diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index f354d2069..e60371e38 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -577,17 +577,7 @@ struct JSRuntime : public JS::shadow::Runtime, #endif mozilla::Atomic interrupt_; - - /* Call this to accumulate telemetry data. */ - JSAccumulateTelemetryDataCallback telemetryCallback; public: - // Accumulates data for Firefox telemetry. |id| is the ID of a JS_TELEMETRY_* - // histogram. |key| provides an additional key to identify the histogram. - // |sample| is the data to add to the histogram. - void addTelemetry(int id, uint32_t sample, const char* key = nullptr); - - void setTelemetryCallback(JSRuntime* rt, JSAccumulateTelemetryDataCallback callback); - enum InterruptMode { RequestInterruptUrgent, RequestInterruptCanWait diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index 08670c833..328a960b6 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -1903,23 +1903,6 @@ intrinsic_RuntimeDefaultLocale(JSContext* cx, unsigned argc, Value* vp) return true; } -static bool -intrinsic_AddContentTelemetry(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - MOZ_ASSERT(args.length() == 2); - - int id = args[0].toInt32(); - MOZ_ASSERT(id < JS_TELEMETRY_END); - MOZ_ASSERT(id >= 0); - - if (!cx->compartment()->isProbablySystemOrAddonCode()) - cx->runtime()->addTelemetry(id, args[1].toInt32()); - - args.rval().setUndefined(); - return true; -} - static bool intrinsic_ConstructFunction(JSContext* cx, unsigned argc, Value* vp) { @@ -2273,7 +2256,6 @@ static const JSFunctionSpec intrinsic_functions[] = { JS_FN("DecompileArg", intrinsic_DecompileArg, 2,0), JS_FN("_FinishBoundFunctionInit", intrinsic_FinishBoundFunctionInit, 3,0), JS_FN("RuntimeDefaultLocale", intrinsic_RuntimeDefaultLocale, 0,0), - JS_FN("AddContentTelemetry", intrinsic_AddContentTelemetry, 2,0), JS_INLINABLE_FN("_IsConstructing", intrinsic_IsConstructing, 0,0, IntrinsicIsConstructing), diff --git a/js/src/vm/Stopwatch.cpp b/js/src/vm/Stopwatch.cpp index 5b5ec6196..684846f00 100644 --- a/js/src/vm/Stopwatch.cpp +++ b/js/src/vm/Stopwatch.cpp @@ -334,11 +334,6 @@ AutoStopwatch::exit() const uint64_t cyclesEnd = getCycles(runtime); cyclesDelta = cyclesEnd - cyclesStart_; // Always >= 0 by definition of `getCycles`. } -#if WINVER >= 0x600 - updateTelemetry(cpuStart_, cpuEnd); -#elif defined(__linux__) - updateTelemetry(cpuStart_, cpuEnd); -#endif // WINVER >= 0x600 || _linux__ } uint64_t CPOWTimeDelta = 0; @@ -350,17 +345,6 @@ AutoStopwatch::exit() return addToGroups(cyclesDelta, CPOWTimeDelta); } -void -AutoStopwatch::updateTelemetry(const cpuid_t& cpuStart_, const cpuid_t& cpuEnd) -{ - JSRuntime* runtime = cx_->runtime(); - - if (isSameCPU(cpuStart_, cpuEnd)) - runtime->performanceMonitoring.testCpuRescheduling.stayed += 1; - else - runtime->performanceMonitoring.testCpuRescheduling.moved += 1; -} - PerformanceGroup* AutoStopwatch::acquireGroup(PerformanceGroup* group) { diff --git a/js/src/vm/Stopwatch.h b/js/src/vm/Stopwatch.h index 38a3eb801..d7f299594 100644 --- a/js/src/vm/Stopwatch.h +++ b/js/src/vm/Stopwatch.h @@ -217,33 +217,6 @@ struct PerformanceMonitoring { */ uint64_t monotonicReadTimestampCounter(); - /** - * Data extracted by the AutoStopwatch to determine how often - * we reschedule the process to a different CPU during the - * execution of JS. - * - * Warning: These values are incremented *only* on platforms - * that offer a syscall/libcall to check on which CPU a - * process is currently executed. - */ - struct TestCpuRescheduling - { - // Incremented once we have finished executing code - // in a group, if the CPU on which we started - // execution is the same as the CPU on which - // we finished. - uint64_t stayed; - // Incremented once we have finished executing code - // in a group, if the CPU on which we started - // execution is different from the CPU on which - // we finished. - uint64_t moved; - TestCpuRescheduling() - : stayed(0), - moved(0) - { } - }; - TestCpuRescheduling testCpuRescheduling; private: PerformanceMonitoring(const PerformanceMonitoring&) = delete; PerformanceMonitoring& operator=(const PerformanceMonitoring&) = delete; @@ -375,9 +348,6 @@ class AutoStopwatch final { // Add recent changes to a single group. Mark the group as changed recently. bool addToGroup(JSRuntime* runtime, uint64_t cyclesDelta, uint64_t CPOWTimeDelta, PerformanceGroup* group); - // Update telemetry statistics. - void updateTelemetry(const cpuid_t& a, const cpuid_t& b); - // Perform a subtraction for a quantity that should be monotonic // but is not guaranteed to be so. // diff --git a/js/src/wasm/WasmBinaryConstants.h b/js/src/wasm/WasmBinaryConstants.h index fd3bd1264..9aa5091f6 100644 --- a/js/src/wasm/WasmBinaryConstants.h +++ b/js/src/wasm/WasmBinaryConstants.h @@ -434,15 +434,6 @@ enum class Op Limit }; -// Telemetry sample values for the JS_AOT_USAGE key, indicating whether asm.js -// or WebAssembly is used. - -enum class Telemetry -{ - ASMJS = 0, - WASM = 1 -}; - } // namespace wasm } // namespace js diff --git a/js/src/wasm/WasmModule.cpp b/js/src/wasm/WasmModule.cpp index b24e01a40..f1ecd8620 100644 --- a/js/src/wasm/WasmModule.cpp +++ b/js/src/wasm/WasmModule.cpp @@ -1066,8 +1066,5 @@ Module::instantiate(JSContext* cx, return false; } - uint32_t mode = uint32_t(metadata().isAsmJS() ? Telemetry::ASMJS : Telemetry::WASM); - cx->runtime()->addTelemetry(JS_TELEMETRY_AOT_USAGE, mode); - return true; } -- cgit v1.2.3 From e547de64c80b98d661999c0788c09210d9d4a37e Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 2 Feb 2019 12:47:28 +0100 Subject: Stage 1-1: Implement Function.prototype.toString revision proposal. Tag #960 --- js/src/frontend/BytecodeCompiler.cpp | 12 +-- js/src/frontend/BytecodeCompiler.h | 2 + js/src/frontend/BytecodeEmitter.cpp | 3 +- js/src/frontend/Parser.cpp | 167 +++++++++++++++++++++++------------ js/src/frontend/Parser.h | 28 +++--- js/src/frontend/SharedContext.h | 5 +- js/src/frontend/TokenStream.cpp | 6 ++ js/src/frontend/TokenStream.h | 7 ++ js/src/jsapi.cpp | 46 +++++++--- js/src/jsfun.cpp | 90 ++++++++++++------- js/src/jsscript.cpp | 47 +++++++--- js/src/jsscript.h | 49 +++++++--- js/src/wasm/AsmJS.cpp | 22 ++--- 13 files changed, 330 insertions(+), 154 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index 76afe80b1..b5be5f5ac 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -77,7 +77,7 @@ class MOZ_STACK_CLASS BytecodeCompiler bool canLazilyParse(); bool createParser(); bool createSourceAndParser(Maybe parameterListEnd = Nothing()); - bool createScript(); + bool createScript(uint32_t preludeStart = 0); bool emplaceEmitter(Maybe& emitter, SharedContext* sharedContext); bool handleParseFailure(const Directives& newDirectives); bool deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObject environment); @@ -242,10 +242,11 @@ BytecodeCompiler::createSourceAndParser(Maybe parameterListEnd /* = No } bool -BytecodeCompiler::createScript() +BytecodeCompiler::createScript(uint32_t preludeStart /* = 0 */) { script = JSScript::Create(cx, options, - sourceObject, /* sourceStart = */ 0, sourceBuffer.length()); + sourceObject, /* sourceStart = */ 0, sourceBuffer.length(), + preludeStart); return script != nullptr; } @@ -456,7 +457,7 @@ BytecodeCompiler::compileStandaloneFunction(MutableHandleFunction fun, if (fn->pn_funbox->function()->isInterpreted()) { MOZ_ASSERT(fun == fn->pn_funbox->function()); - if (!createScript()) + if (!createScript(fn->pn_funbox->preludeStart)) return false; Maybe emitter; @@ -650,7 +651,8 @@ frontend::CompileLazyFunction(JSContext* cx, Handle lazy, const cha MOZ_ASSERT(sourceObject); Rooted script(cx, JSScript::Create(cx, options, sourceObject, - lazy->begin(), lazy->end())); + lazy->begin(), lazy->end(), + lazy->preludeStart())); if (!script) return false; diff --git a/js/src/frontend/BytecodeCompiler.h b/js/src/frontend/BytecodeCompiler.h index 72e967639..0bc1ab2ab 100644 --- a/js/src/frontend/BytecodeCompiler.h +++ b/js/src/frontend/BytecodeCompiler.h @@ -109,6 +109,8 @@ IsIdentifier(JSLinearString* str); * As above, but taking chars + length. */ bool +IsIdentifier(const char* chars, size_t length); +bool IsIdentifier(const char16_t* chars, size_t length); /* True if str is a keyword. Defined in TokenStream.cpp. */ diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 4eb7bf880..c5e62ae34 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -7834,7 +7834,8 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto) Rooted sourceObject(cx, script->sourceObject()); Rooted script(cx, JSScript::Create(cx, options, sourceObject, - funbox->bufStart, funbox->bufEnd)); + funbox->bufStart, funbox->bufEnd, + funbox->preludeStart)); if (!script) return false; diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 209265a58..1ba725a82 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -441,7 +441,8 @@ UsedNameTracker::rewind(RewindToken token) } FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead, - JSFunction* fun, Directives directives, bool extraWarnings, + JSFunction* fun, uint32_t preludeStart, + Directives directives, bool extraWarnings, GeneratorKind generatorKind, FunctionAsyncKind asyncKind) : ObjectBox(fun, traceListHead), SharedContext(cx, Kind::ObjectBox, directives, extraWarnings), @@ -454,6 +455,7 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* trac bufEnd(0), startLine(1), startColumn(0), + preludeStart(preludeStart), length(0), generatorKindBits_(GeneratorKindAsBits(generatorKind)), asyncKindBits_(AsyncKindAsBits(asyncKind)), @@ -738,7 +740,8 @@ Parser::newObjectBox(JSObject* obj) template FunctionBox* -Parser::newFunctionBox(Node fn, JSFunction* fun, Directives inheritedDirectives, +Parser::newFunctionBox(Node fn, JSFunction* fun, uint32_t preludeStart, + Directives inheritedDirectives, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB) { @@ -753,8 +756,9 @@ Parser::newFunctionBox(Node fn, JSFunction* fun, Directives inheri * function. */ FunctionBox* funbox = - alloc.new_(context, alloc, traceListHead, fun, inheritedDirectives, - options().extraWarningsOption, generatorKind, asyncKind); + alloc.new_(context, alloc, traceListHead, fun, preludeStart, + inheritedDirectives, options().extraWarningsOption, + generatorKind, asyncKind); if (!funbox) { ReportOutOfMemory(context); return nullptr; @@ -2214,6 +2218,7 @@ Parser::finishFunction() LazyScript* lazy = LazyScript::Create(context, fun, pc->closedOverBindingsForLazy(), pc->innerFunctionsForLazy, versionNumber(), funbox->bufStart, funbox->bufEnd, + funbox->preludeStart, funbox->startLine, funbox->startColumn); if (!lazy) return false; @@ -2267,6 +2272,33 @@ Parser::standaloneFunction(HandleFunction fun, { MOZ_ASSERT(checkOptionsCalled); + // Skip prelude. + TokenKind tt; + if (!tokenStream.getToken(&tt)) + return null(); + if (asyncKind == AsyncFunction) { + MOZ_ASSERT(tt == TOK_ASYNC); + if (!tokenStream.getToken(&tt)) + return null(); + } + MOZ_ASSERT(tt == TOK_FUNCTION); + + if (!tokenStream.getToken(&tt)) + return null(); + if (generatorKind == StarGenerator && asyncKind == SyncFunction) { + MOZ_ASSERT(tt == TOK_MUL); + if (!tokenStream.getToken(&tt)) + return null(); + } + + // Skip function name, if present. + if (tt == TOK_NAME || tt == TOK_YIELD) { + MOZ_ASSERT(tokenStream.currentName() == fun->explicitName()); + } else { + MOZ_ASSERT(fun->explicitName() == nullptr); + tokenStream.ungetToken(); + } + Node fn = handler.newFunctionDefinition(); if (!fn) return null(); @@ -2276,8 +2308,8 @@ Parser::standaloneFunction(HandleFunction fun, return null(); fn->pn_body = argsbody; - FunctionBox* funbox = newFunctionBox(fn, fun, inheritedDirectives, generatorKind, - asyncKind, /* tryAnnexB = */ false); + FunctionBox* funbox = newFunctionBox(fn, fun, /* preludeStart = */ 0, inheritedDirectives, + generatorKind, asyncKind, /* tryAnnexB = */ false); if (!funbox) return null(); funbox->initStandaloneFunction(enclosingScope); @@ -2295,7 +2327,6 @@ Parser::standaloneFunction(HandleFunction fun, return null(); } - TokenKind tt; if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); if (tt != TOK_EOF) { @@ -2991,8 +3022,8 @@ Parser::checkFunctionDefinition(HandleAtom funAtom, Node pn, Funct template <> bool -Parser::skipLazyInnerFunction(ParseNode* pn, FunctionSyntaxKind kind, - bool tryAnnexB) +Parser::skipLazyInnerFunction(ParseNode* pn, uint32_t preludeStart, + FunctionSyntaxKind kind, bool tryAnnexB) { // When a lazily-parsed function is called, we only fully parse (and emit) // that function, not any of its nested children. The initial syntax-only @@ -3001,7 +3032,7 @@ Parser::skipLazyInnerFunction(ParseNode* pn, FunctionSyntaxKin RootedFunction fun(context, handler.nextLazyInnerFunction()); MOZ_ASSERT(!fun->isLegacyGenerator()); - FunctionBox* funbox = newFunctionBox(pn, fun, Directives(/* strict = */ false), + FunctionBox* funbox = newFunctionBox(pn, fun, preludeStart, Directives(/* strict = */ false), fun->generatorKind(), fun->asyncKind(), tryAnnexB); if (!funbox) return false; @@ -3031,8 +3062,8 @@ Parser::skipLazyInnerFunction(ParseNode* pn, FunctionSyntaxKin template <> bool -Parser::skipLazyInnerFunction(Node pn, FunctionSyntaxKind kind, - bool tryAnnexB) +Parser::skipLazyInnerFunction(Node pn, uint32_t preludeStart, + FunctionSyntaxKind kind, bool tryAnnexB) { MOZ_CRASH("Cannot skip lazy inner functions when syntax parsing"); } @@ -3108,7 +3139,8 @@ Parser::templateLiteral(YieldHandling yieldHandling) template typename ParseHandler::Node -Parser::functionDefinition(InHandling inHandling, YieldHandling yieldHandling, +Parser::functionDefinition(uint32_t preludeStart, InHandling inHandling, + YieldHandling yieldHandling, HandleAtom funName, FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, InvokedPrediction invoked) @@ -3132,7 +3164,7 @@ Parser::functionDefinition(InHandling inHandling, YieldHandling yi // functions, which are also lazy. Instead, their free variables and // source extents are recorded and may be skipped. if (handler.canSkipLazyInnerFunctions()) { - if (!skipLazyInnerFunction(pn, kind, tryAnnexB)) + if (!skipLazyInnerFunction(pn, preludeStart, kind, tryAnnexB)) return null(); return pn; } @@ -3165,8 +3197,9 @@ Parser::functionDefinition(InHandling inHandling, YieldHandling yi // reparse a function due to failed syntax parsing and encountering new // "use foo" directives. while (true) { - if (trySyntaxParseInnerFunction(pn, fun, inHandling, yieldHandling, kind, generatorKind, - asyncKind, tryAnnexB, directives, &newDirectives)) + if (trySyntaxParseInnerFunction(pn, fun, preludeStart, inHandling, yieldHandling, kind, + generatorKind, asyncKind, tryAnnexB, directives, + &newDirectives)) { break; } @@ -3193,6 +3226,7 @@ Parser::functionDefinition(InHandling inHandling, YieldHandling yi template <> bool Parser::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunction fun, + uint32_t preludeStart, InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind, @@ -3226,14 +3260,15 @@ Parser::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunct // Make a FunctionBox before we enter the syntax parser, because |pn| // still expects a FunctionBox to be attached to it during BCE, and // the syntax parser cannot attach one to it. - FunctionBox* funbox = newFunctionBox(pn, fun, inheritedDirectives, generatorKind, - asyncKind, tryAnnexB); + FunctionBox* funbox = newFunctionBox(pn, fun, preludeStart, inheritedDirectives, + generatorKind, asyncKind, tryAnnexB); if (!funbox) return false; funbox->initWithEnclosingParseContext(pc, kind); - if (!parser->innerFunction(SyntaxParseHandler::NodeGeneric, pc, funbox, inHandling, - yieldHandling, kind, inheritedDirectives, newDirectives)) + if (!parser->innerFunction(SyntaxParseHandler::NodeGeneric, pc, funbox, preludeStart, + inHandling, yieldHandling, kind, + inheritedDirectives, newDirectives)) { if (parser->hadAbortedSyntaxParse()) { // Try again with a full parse. UsedNameTracker needs to be @@ -3259,13 +3294,14 @@ Parser::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunct } while (false); // We failed to do a syntax parse above, so do the full parse. - return innerFunction(pn, pc, fun, inHandling, yieldHandling, kind, generatorKind, asyncKind, - tryAnnexB, inheritedDirectives, newDirectives); + return innerFunction(pn, pc, fun, preludeStart, inHandling, yieldHandling, kind, + generatorKind, asyncKind, tryAnnexB, inheritedDirectives, newDirectives); } template <> bool Parser::trySyntaxParseInnerFunction(Node pn, HandleFunction fun, + uint32_t preludeStart, InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind, @@ -3276,13 +3312,14 @@ Parser::trySyntaxParseInnerFunction(Node pn, HandleFunction Directives* newDirectives) { // This is already a syntax parser, so just parse the inner function. - return innerFunction(pn, pc, fun, inHandling, yieldHandling, kind, generatorKind, asyncKind, - tryAnnexB, inheritedDirectives, newDirectives); + return innerFunction(pn, pc, fun, preludeStart, inHandling, yieldHandling, kind, + generatorKind, asyncKind, tryAnnexB, inheritedDirectives, newDirectives); } template bool Parser::innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox, + uint32_t preludeStart, InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind, Directives inheritedDirectives, Directives* newDirectives) @@ -3306,6 +3343,7 @@ Parser::innerFunction(Node pn, ParseContext* outerpc, FunctionBox* template bool Parser::innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun, + uint32_t preludeStart, InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, @@ -3317,14 +3355,14 @@ Parser::innerFunction(Node pn, ParseContext* outerpc, HandleFuncti // parser. In that case, outerpc is a ParseContext from the full parser // instead of the current top of the stack of the syntax parser. - FunctionBox* funbox = newFunctionBox(pn, fun, inheritedDirectives, generatorKind, - asyncKind, tryAnnexB); + FunctionBox* funbox = newFunctionBox(pn, fun, preludeStart, inheritedDirectives, + generatorKind, asyncKind, tryAnnexB); if (!funbox) return false; funbox->initWithEnclosingParseContext(outerpc, kind); - return innerFunction(pn, outerpc, funbox, inHandling, yieldHandling, kind, inheritedDirectives, - newDirectives); + return innerFunction(pn, outerpc, funbox, preludeStart, inHandling, yieldHandling, kind, + inheritedDirectives, newDirectives); } template @@ -3359,8 +3397,8 @@ Parser::standaloneLazyFunction(HandleFunction fun, bool strict return null(); Directives directives(strict); - FunctionBox* funbox = newFunctionBox(pn, fun, directives, generatorKind, asyncKind, - /* tryAnnexB = */ false); + FunctionBox* funbox = newFunctionBox(pn, fun, /* preludeStart = */ 0, directives, + generatorKind, asyncKind, /* tryAnnexB = */ false); if (!funbox) return null(); funbox->initFromLazyFunction(); @@ -3529,8 +3567,8 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, template typename ParseHandler::Node -Parser::functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling, - FunctionAsyncKind asyncKind) +Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHandling, + DefaultHandling defaultHandling, FunctionAsyncKind asyncKind) { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION)); @@ -3579,8 +3617,8 @@ Parser::functionStmt(YieldHandling yieldHandling, DefaultHandling } YieldHandling newYieldHandling = GetYieldHandling(generatorKind, asyncKind); - Node fun = functionDefinition(InAllowed, newYieldHandling, name, Statement, generatorKind, - asyncKind, PredictUninvoked); + Node fun = functionDefinition(preludeStart, InAllowed, newYieldHandling, name, Statement, + generatorKind, asyncKind, PredictUninvoked); if (!fun) return null(); @@ -3597,7 +3635,8 @@ Parser::functionStmt(YieldHandling yieldHandling, DefaultHandling template typename ParseHandler::Node -Parser::functionExpr(InvokedPrediction invoked, FunctionAsyncKind asyncKind) +Parser::functionExpr(uint32_t preludeStart, InvokedPrediction invoked, + FunctionAsyncKind asyncKind) { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION)); @@ -3628,8 +3667,8 @@ Parser::functionExpr(InvokedPrediction invoked, FunctionAsyncKind tokenStream.ungetToken(); } - return functionDefinition(InAllowed, yieldHandling, name, Expression, generatorKind, - asyncKind, invoked); + return functionDefinition(preludeStart, InAllowed, yieldHandling, name, Expression, + generatorKind, asyncKind, invoked); } /* @@ -5074,7 +5113,7 @@ Parser::exportDeclaration() } case TOK_FUNCTION: - kid = functionStmt(YieldIsKeyword, NameRequired); + kid = functionStmt(pos().begin, YieldIsKeyword, NameRequired); if (!kid) return null(); @@ -5114,7 +5153,7 @@ Parser::exportDeclaration() ParseNode* nameNode = nullptr; switch (tt) { case TOK_FUNCTION: - kid = functionStmt(YieldIsKeyword, AllowDefaultName); + kid = functionStmt(pos().begin, YieldIsKeyword, AllowDefaultName); if (!kid) return null(); break; @@ -5131,7 +5170,7 @@ Parser::exportDeclaration() if (nextSameLine == TOK_FUNCTION) { tokenStream.consumeKnownToken(nextSameLine); - kid = functionStmt(YieldIsName, AllowDefaultName, AsyncFunction); + kid = functionStmt(pos().begin, YieldIsName, AllowDefaultName, AsyncFunction); if (!kid) return null(); break; @@ -5232,7 +5271,7 @@ Parser::consequentOrAlternative(YieldHandling yieldHandling) // will report the strict mode error. if (!pc->sc()->strict()) { tokenStream.consumeKnownToken(next, TokenStream::Operand); - return functionStmt(yieldHandling, NameRequired); + return functionStmt(pos().begin, yieldHandling, NameRequired); } } @@ -6182,7 +6221,7 @@ Parser::labeledItem(YieldHandling yieldHandling) return null(); } - return functionStmt(yieldHandling, NameRequired); + return functionStmt(pos().begin, yieldHandling, NameRequired); } tokenStream.ungetToken(); @@ -6649,6 +6688,10 @@ Parser::classDefinition(YieldHandling yieldHandling, tokenStream.ungetToken(); } + uint32_t nameOffset; + if (!tokenStream.peekOffset(&nameOffset)) + return null(); + PropertyType propType; Node propName = propertyName(yieldHandling, classMethods, &propType, &propAtom); if (!propName) @@ -6701,7 +6744,7 @@ Parser::classDefinition(YieldHandling yieldHandling, if (!tokenStream.isCurrentTokenType(TOK_RB)) funName = propAtom; } - Node fn = methodDefinition(propType, funName); + Node fn = methodDefinition(nameOffset, propType, funName); if (!fn) return null(); @@ -7094,8 +7137,9 @@ Parser::statementListItem(YieldHandling yieldHandling, if (!tokenStream.peekTokenSameLine(&nextSameLine)) return null(); if (nextSameLine == TOK_FUNCTION) { + uint32_t preludeStart = pos().begin; tokenStream.consumeKnownToken(TOK_FUNCTION); - return functionStmt(yieldHandling, NameRequired, AsyncFunction); + return functionStmt(preludeStart, yieldHandling, NameRequired, AsyncFunction); } } @@ -7174,7 +7218,7 @@ Parser::statementListItem(YieldHandling yieldHandling, // HoistableDeclaration[?Yield, ~Default] case TOK_FUNCTION: - return functionStmt(yieldHandling, NameRequired); + return functionStmt(pos().begin, yieldHandling, NameRequired); // ClassDeclaration[?Yield, ~Default] case TOK_CLASS: @@ -7677,8 +7721,10 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl tokenStream.seek(start); - if (!tokenStream.peekToken(&next, TokenStream::Operand)) + if (!tokenStream.getToken(&next, TokenStream::Operand)) return null(); + uint32_t preludeStart = pos().begin; + tokenStream.ungetToken(); GeneratorKind generatorKind = NotGenerator; FunctionAsyncKind asyncKind = SyncFunction; @@ -7702,7 +7748,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl } } - Node arrowFunc = functionDefinition(inHandling, yieldHandling, nullptr, + Node arrowFunc = functionDefinition(preludeStart, inHandling, yieldHandling, nullptr, Arrow, generatorKind, asyncKind); if (!arrowFunc) return null(); @@ -8054,8 +8100,8 @@ Parser::generatorComprehensionLambda(unsigned begin) // Create box for fun->object early to root it. Directives directives(/* strict = */ outerpc->sc()->strict()); - FunctionBox* genFunbox = newFunctionBox(genfn, fun, directives, StarGenerator, SyncFunction, - /* tryAnnexB = */ false); + FunctionBox* genFunbox = newFunctionBox(genfn, fun, /* preludeStart = */ 0, directives, + StarGenerator, SyncFunction, /* tryAnnexB = */ false); if (!genFunbox) return null(); genFunbox->isGenexpLambda = true; @@ -8087,12 +8133,14 @@ Parser::generatorComprehensionLambda(unsigned begin) MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN); + uint32_t end = pos().end; handler.setBeginPosition(comp, begin); - handler.setEndPosition(comp, pos().end); + handler.setEndPosition(comp, end); + genFunbox->bufEnd = end; handler.addStatementToList(body, comp); - handler.setEndPosition(body, pos().end); + handler.setEndPosition(body, end); handler.setBeginPosition(genfn, begin); - handler.setEndPosition(genfn, pos().end); + handler.setEndPosition(genfn, end); Node generator = newDotGeneratorName(); if (!generator) @@ -9158,6 +9206,8 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* if (tt == TOK_RC) break; + TokenPos namePos = pos(); + tokenStream.ungetToken(); PropertyType propType; @@ -9309,7 +9359,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* } } - Node fn = methodDefinition(propType, funName); + Node fn = methodDefinition(namePos.begin, propType, funName); if (!fn) return null(); @@ -9336,13 +9386,15 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* template typename ParseHandler::Node -Parser::methodDefinition(PropertyType propType, HandleAtom funName) +Parser::methodDefinition(uint32_t preludeStart, PropertyType propType, + HandleAtom funName) { FunctionSyntaxKind kind = FunctionSyntaxKindFromPropertyType(propType); GeneratorKind generatorKind = GeneratorKindFromPropertyType(propType); FunctionAsyncKind asyncKind = AsyncKindFromPropertyType(propType); YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind); - return functionDefinition(InAllowed, yieldHandling, funName, kind, generatorKind, asyncKind); + return functionDefinition(preludeStart, InAllowed, yieldHandling, funName, kind, + generatorKind, asyncKind); } template @@ -9404,7 +9456,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling switch (tt) { case TOK_FUNCTION: - return functionExpr(invoked); + return functionExpr(pos().begin, invoked); case TOK_CLASS: return classDefinition(yieldHandling, ClassExpression, NameRequired); @@ -9471,8 +9523,9 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling return null(); if (nextSameLine == TOK_FUNCTION) { + uint32_t preludeStart = pos().begin; tokenStream.consumeKnownToken(TOK_FUNCTION); - return functionExpr(PredictUninvoked, AsyncFunction); + return functionExpr(preludeStart, PredictUninvoked, AsyncFunction); } } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 12642fad8..090931f5b 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -954,7 +954,8 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter * cx->tempLifoAlloc. */ ObjectBox* newObjectBox(JSObject* obj); - FunctionBox* newFunctionBox(Node fn, JSFunction* fun, Directives directives, + FunctionBox* newFunctionBox(Node fn, JSFunction* fun, uint32_t preludeStart, + Directives directives, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB); @@ -1034,8 +1035,9 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter // Parse an inner function given an enclosing ParseContext and a // FunctionBox for the inner function. - bool innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox, InHandling inHandling, - YieldHandling yieldHandling, FunctionSyntaxKind kind, + bool innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox, uint32_t preludeStart, + InHandling inHandling, YieldHandling yieldHandling, + FunctionSyntaxKind kind, Directives inheritedDirectives, Directives* newDirectives); // Parse a function's formal parameters and its body assuming its function @@ -1088,9 +1090,10 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter * Some parsers have two versions: an always-inlined version (with an 'i' * suffix) and a never-inlined version (with an 'n' suffix). */ - Node functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling, + Node functionStmt(uint32_t preludeStart, + YieldHandling yieldHandling, DefaultHandling defaultHandling, FunctionAsyncKind asyncKind = SyncFunction); - Node functionExpr(InvokedPrediction invoked = PredictUninvoked, + Node functionExpr(uint32_t preludeStart, InvokedPrediction invoked = PredictUninvoked, FunctionAsyncKind asyncKind = SyncFunction); Node statementList(YieldHandling yieldHandling); @@ -1222,7 +1225,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool tryNewTarget(Node& newTarget); bool checkAndMarkSuperScope(); - Node methodDefinition(PropertyType propType, HandleAtom funName); + Node methodDefinition(uint32_t preludeStart, PropertyType propType, HandleAtom funName); /* * Additional JS parsers. @@ -1230,7 +1233,8 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind, Node funcpn); - Node functionDefinition(InHandling inHandling, YieldHandling yieldHandling, HandleAtom name, + Node functionDefinition(uint32_t preludeStart, + InHandling inHandling, YieldHandling yieldHandling, HandleAtom name, FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, InvokedPrediction invoked = PredictUninvoked); @@ -1321,14 +1325,16 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool checkFunctionDefinition(HandleAtom funAtom, Node pn, FunctionSyntaxKind kind, GeneratorKind generatorKind, bool* tryAnnexB); - bool skipLazyInnerFunction(Node pn, FunctionSyntaxKind kind, bool tryAnnexB); - bool innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun, + bool skipLazyInnerFunction(Node pn, uint32_t preludeStart, FunctionSyntaxKind kind, + bool tryAnnexB); + bool innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun, uint32_t preludeStart, InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB, Directives inheritedDirectives, Directives* newDirectives); - bool trySyntaxParseInnerFunction(Node pn, HandleFunction fun, InHandling inHandling, - YieldHandling yieldHandling, FunctionSyntaxKind kind, + bool trySyntaxParseInnerFunction(Node pn, HandleFunction fun, uint32_t preludeStart, + InHandling inHandling, YieldHandling yieldHandling, + FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB, Directives inheritedDirectives, Directives* newDirectives); diff --git a/js/src/frontend/SharedContext.h b/js/src/frontend/SharedContext.h index a6ac542f6..b20417d5d 100644 --- a/js/src/frontend/SharedContext.h +++ b/js/src/frontend/SharedContext.h @@ -450,6 +450,7 @@ class FunctionBox : public ObjectBox, public SharedContext uint32_t bufEnd; uint32_t startLine; uint32_t startColumn; + uint32_t preludeStart; uint16_t length; uint8_t generatorKindBits_; /* The GeneratorKind of this function. */ @@ -476,8 +477,8 @@ class FunctionBox : public ObjectBox, public SharedContext FunctionContextFlags funCxFlags; FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead, JSFunction* fun, - Directives directives, bool extraWarnings, GeneratorKind generatorKind, - FunctionAsyncKind asyncKind); + uint32_t preludeStart, Directives directives, bool extraWarnings, + GeneratorKind generatorKind, FunctionAsyncKind asyncKind); MutableHandle namedLambdaBindings() { MOZ_ASSERT(context->compartment()->runtimeFromAnyThread()->keepAtoms()); diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index 179a7c244..b040d2998 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -171,6 +171,12 @@ frontend::IsIdentifier(JSLinearString* str) : ::IsIdentifierMaybeNonBMP(str->twoByteChars(nogc), str->length()); } +bool +frontend::IsIdentifier(const char* chars, size_t length) +{ + return ::IsIdentifier(chars, length); +} + bool frontend::IsIdentifier(const char16_t* chars, size_t length) { diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index 5d6b4b795..77eea3d81 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -570,6 +570,13 @@ class MOZ_STACK_CLASS TokenStream return true; } + MOZ_MUST_USE bool peekOffset(uint32_t* offset, Modifier modifier = None) { + TokenPos pos; + if (!peekTokenPos(&pos, modifier)) + return false; + *offset = pos.begin; + return true; + } // This is like peekToken(), with one exception: if there is an EOL // between the end of the current token and the start of the next token, it // return true and store TOK_EOL in |*ttp|. In that case, no token with diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 37d023bd4..9ee29ffe4 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -4250,7 +4250,7 @@ JS_GetFunctionScript(JSContext* cx, HandleFunction fun) */ static bool CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg, - const char* name, + HandleAtom name, bool isInvalidName, SourceBufferHolder& srcBuf, uint32_t parameterListEnd, HandleObject enclosingEnv, HandleScope enclosingScope, MutableHandleFunction fun) @@ -4261,13 +4261,8 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg, assertSameCompartment(cx, enclosingEnv); RootedAtom funAtom(cx); - if (name) { - funAtom = Atomize(cx, name, strlen(name)); - if (!funAtom) - return false; - } - - fun.set(NewScriptedFunction(cx, 0, JSFunction::INTERPRETED_NORMAL, funAtom, + fun.set(NewScriptedFunction(cx, 0, JSFunction::INTERPRETED_NORMAL, + isInvalidName ? nullptr : name, /* proto = */ nullptr, gc::AllocKind::FUNCTION, TenuredObject, enclosingEnv)); @@ -4285,11 +4280,17 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg, return false; } + // When function name is not a valid identifier, the generated function + // source in srcBuf doesn't have a function name. Set it here. + if (isInvalidName) + fun->setAtom(name); + return true; } static MOZ_MUST_USE bool -BuildFunctionString(unsigned nargs, const char* const* argnames, +BuildFunctionString(const char* name, size_t nameLen, + unsigned nargs, const char* const* argnames, const SourceBufferHolder& srcBuf, StringBuffer* out, uint32_t* parameterListEnd) { @@ -4298,6 +4299,12 @@ BuildFunctionString(unsigned nargs, const char* const* argnames, if (!out->ensureTwoByteChars()) return false; + if (!out->append("function ")) + return false; + if (name) { + if (!out->append(name, nameLen)) + return false; + } if (!out->append("(")) return false; for (unsigned i = 0; i < nargs; i++) { @@ -4334,15 +4341,32 @@ JS::CompileFunction(JSContext* cx, AutoObjectVector& envChain, if (!CreateNonSyntacticEnvironmentChain(cx, envChain, &env, &scope)) return false; + size_t nameLen = 0; + bool isInvalidName = false; + RootedAtom nameAtom(cx); + if (name) { + nameLen = strlen(name); + nameAtom = Atomize(cx, name, nameLen); + if (!nameAtom) + return false; + + // If name is not valid identifier + if (!js::frontend::IsIdentifier(name, nameLen)) + isInvalidName = true; + } + uint32_t parameterListEnd; StringBuffer funStr(cx); - if (!BuildFunctionString(nargs, argnames, srcBuf, &funStr, ¶meterListEnd)) + if (!BuildFunctionString(isInvalidName ? nullptr : name, nameLen, nargs, argnames, srcBuf, + &funStr, ¶meterListEnd)) { return false; + } size_t newLen = funStr.length(); SourceBufferHolder newSrcBuf(funStr.stealChars(), newLen, SourceBufferHolder::GiveOwnership); - return CompileFunction(cx, options, name, newSrcBuf, parameterListEnd, env, scope, fun); + return CompileFunction(cx, options, nameAtom, isInvalidName, newSrcBuf, parameterListEnd, env, + scope, fun); } JS_PUBLIC_API(bool) diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index bcb0da80b..4412362c2 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -815,8 +815,10 @@ CreateFunctionPrototype(JSContext* cx, JSProtoKey key) RootedFunction functionProto(cx, &functionProto_->as()); - const char* rawSource = "() {\n}"; + const char* rawSource = "function () {\n}"; size_t sourceLen = strlen(rawSource); + size_t begin = 9; + MOZ_ASSERT(rawSource[begin] == '('); mozilla::UniquePtr source(InflateString(cx, rawSource, &sourceLen)); if (!source) return nullptr; @@ -838,8 +840,9 @@ CreateFunctionPrototype(JSContext* cx, JSProtoKey key) RootedScript script(cx, JSScript::Create(cx, options, sourceObject, - 0, - ss->length())); + begin, + ss->length(), + 0)); if (!script || !JSScript::initFunctionPrototype(cx, script, functionProto)) return nullptr; @@ -1019,53 +1022,62 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint) } } - if (fun->isAsync()) { - if (!out.append("async ")) - return nullptr; - } - - bool funIsMethodOrNonArrowLambda = (fun->isLambda() && !fun->isArrow()) || fun->isMethod() || - fun->isGetter() || fun->isSetter(); + bool funIsNonArrowLambda = fun->isLambda() && !fun->isArrow(); bool haveSource = fun->isInterpreted() && !fun->isSelfHostedBuiltin(); - // If we're not in pretty mode, put parentheses around lambda functions and methods. - if (haveSource && !prettyPrint && funIsMethodOrNonArrowLambda) { + // If we're not in pretty mode, put parentheses around lambda functions + // so that eval returns lambda, not function statement. + if (haveSource && !prettyPrint && funIsNonArrowLambda) { if (!out.append("(")) return nullptr; } - if (!fun->isArrow()) { - bool ok; - if (fun->isStarGenerator() && !fun->isAsync()) - ok = out.append("function* "); - else - ok = out.append("function "); - if (!ok) - return nullptr; - } - if (fun->explicitName()) { - if (!out.append(fun->explicitName())) - return nullptr; - } if (haveSource && !script->scriptSource()->hasSourceData() && !JSScript::loadSource(cx, script->scriptSource(), &haveSource)) { return nullptr; } + + auto AppendPrelude = [&out, &fun]() { + if (fun->isAsync()) { + if (!out.append("async ")) + return false; + } + + if (!fun->isArrow()) { + if (!out.append("function")) + return false; + + if (fun->isStarGenerator()) { + if (!out.append('*')) + return false; + } + } + + if (fun->explicitName()) { + if (!out.append(' ')) + return false; + if (!out.append(fun->explicitName())) + return false; + } + return true; + }; + if (haveSource) { - Rooted src(cx, script->sourceData(cx)); + Rooted src(cx, script->sourceDataWithPrelude(cx)); if (!src) return nullptr; if (!out.append(src)) return nullptr; - if (!prettyPrint && funIsMethodOrNonArrowLambda) { + if (!prettyPrint && funIsNonArrowLambda) { if (!out.append(")")) return nullptr; } } else if (fun->isInterpreted() && !fun->isSelfHostedBuiltin()) { - if (!out.append("() {\n ") || + if (!AppendPrelude() || + !out.append("() {\n ") || !out.append("[sourceless code]") || !out.append("\n}")) { @@ -1076,13 +1088,15 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint) bool derived = fun->infallibleIsDefaultClassConstructor(cx); if (derived && fun->isDerivedClassConstructor()) { - if (!out.append("(...args) {\n ") || + if (!AppendPrelude() || + !out.append("(...args) {\n ") || !out.append("super(...args);\n}")) { return nullptr; } } else { - if (!out.append("() {\n ")) + if (!AppendPrelude() || + !out.append("() {\n ")) return nullptr; if (!derived) { @@ -1669,7 +1683,18 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator StringBuffer sb(cx); - if (!sb.append('(')) + if (isAsync) { + if (!sb.append("async ")) + return false; + } + if (!sb.append("function")) + return false; + if (isStarGenerator && !isAsync) { + if (!sb.append('*')) + return false; + } + + if (!sb.append(" anonymous(")) return false; if (args.length() > 1) { @@ -1696,6 +1721,9 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator } } + if (!sb.append('\n')) + return false; + // Remember the position of ")". Maybe parameterListEnd = Some(uint32_t(sb.length())); MOZ_ASSERT(FunctionConstructorMedialSigils[0] == ')'); diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 9f914943e..33ae56d6f 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -235,6 +235,7 @@ XDRRelazificationInfo(XDRState* xdr, HandleFunction fun, HandleScript scri { uint32_t begin = script->sourceStart(); uint32_t end = script->sourceEnd(); + uint32_t preludeStart = script->preludeStart(); uint32_t lineno = script->lineno(); uint32_t column = script->column(); @@ -242,6 +243,7 @@ XDRRelazificationInfo(XDRState* xdr, HandleFunction fun, HandleScript scri packedFields = lazy->packedFields(); MOZ_ASSERT(begin == lazy->begin()); MOZ_ASSERT(end == lazy->end()); + MOZ_ASSERT(preludeStart == lazy->preludeStart()); MOZ_ASSERT(lineno == lazy->lineno()); MOZ_ASSERT(column == lazy->column()); // We can assert we have no inner functions because we don't @@ -255,7 +257,7 @@ XDRRelazificationInfo(XDRState* xdr, HandleFunction fun, HandleScript scri if (mode == XDR_DECODE) { lazy.set(LazyScript::Create(cx, fun, script, enclosingScope, script, - packedFields, begin, end, lineno, column)); + packedFields, begin, end, preludeStart, lineno, column)); // As opposed to XDRLazyScript, we need to restore the runtime bits // of the script, as we are trying to match the fact this function @@ -517,7 +519,7 @@ js::XDRScript(XDRState* xdr, HandleScope scriptEnclosingScope, HandleScrip sourceObject = &enclosingScript->sourceObject()->as(); } - script = JSScript::Create(cx, options, sourceObject, 0, 0); + script = JSScript::Create(cx, options, sourceObject, 0, 0, 0); if (!script) return false; @@ -600,6 +602,8 @@ js::XDRScript(XDRState* xdr, HandleScope scriptEnclosingScope, HandleScrip return false; if (!xdr->codeUint32(&script->sourceEnd_)) return false; + if (!xdr->codeUint32(&script->preludeStart_)) + return false; if (!xdr->codeUint32(&lineno) || !xdr->codeUint32(&column) || @@ -930,6 +934,7 @@ js::XDRLazyScript(XDRState* xdr, HandleScope enclosingScope, HandleScript { uint32_t begin; uint32_t end; + uint32_t preludeStart; uint32_t lineno; uint32_t column; uint64_t packedFields; @@ -943,12 +948,14 @@ js::XDRLazyScript(XDRState* xdr, HandleScope enclosingScope, HandleScript begin = lazy->begin(); end = lazy->end(); + preludeStart = lazy->preludeStart(); lineno = lazy->lineno(); column = lazy->column(); packedFields = lazy->packedFields(); } if (!xdr->codeUint32(&begin) || !xdr->codeUint32(&end) || + !xdr->codeUint32(&preludeStart) || !xdr->codeUint32(&lineno) || !xdr->codeUint32(&column) || !xdr->codeUint64(&packedFields)) { @@ -957,7 +964,7 @@ js::XDRLazyScript(XDRState* xdr, HandleScope enclosingScope, HandleScript if (mode == XDR_DECODE) { lazy.set(LazyScript::Create(cx, fun, nullptr, enclosingScope, enclosingScript, - packedFields, begin, end, lineno, column)); + packedFields, begin, end, preludeStart, lineno, column)); if (!lazy) return false; fun->initLazyScript(lazy); @@ -1430,6 +1437,13 @@ JSScript::sourceData(JSContext* cx) return scriptSource()->substring(cx, sourceStart(), sourceEnd()); } +JSFlatString* +JSScript::sourceDataWithPrelude(JSContext* cx) +{ + MOZ_ASSERT(scriptSource()->hasSourceData()); + return scriptSource()->substring(cx, preludeStart(), sourceEnd()); +} + UncompressedSourceCache::AutoHoldEntry::AutoHoldEntry() : cache_(nullptr), sourceChunk_() { @@ -2428,7 +2442,8 @@ JSScript::initCompartment(ExclusiveContext* cx) /* static */ JSScript* JSScript::Create(ExclusiveContext* cx, const ReadOnlyCompileOptions& options, - HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd) + HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd, + uint32_t preludeStart) { MOZ_ASSERT(bufStart <= bufEnd); @@ -2450,6 +2465,7 @@ JSScript::Create(ExclusiveContext* cx, const ReadOnlyCompileOptions& options, script->setSourceObject(sourceObject); script->sourceStart_ = bufStart; script->sourceEnd_ = bufEnd; + script->preludeStart_ = preludeStart; return script; } @@ -3382,7 +3398,8 @@ CreateEmptyScriptForClone(JSContext* cx, HandleScript src) .setNoScriptRval(src->noScriptRval()) .setVersion(src->getVersion()); - return JSScript::Create(cx, options, sourceObject, src->sourceStart(), src->sourceEnd()); + return JSScript::Create(cx, options, sourceObject, src->sourceStart(), src->sourceEnd(), + src->preludeStart()); } JSScript* @@ -3932,7 +3949,8 @@ JSScript::formalLivesInArgumentsObject(unsigned argSlot) } LazyScript::LazyScript(JSFunction* fun, void* table, uint64_t packedFields, - uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column) + uint32_t begin, uint32_t end, + uint32_t preludeStart, uint32_t lineno, uint32_t column) : script_(nullptr), function_(fun), enclosingScope_(nullptr), @@ -3941,6 +3959,7 @@ LazyScript::LazyScript(JSFunction* fun, void* table, uint64_t packedFields, packedFields_(packedFields), begin_(begin), end_(end), + preludeStart_(preludeStart), lineno_(lineno), column_(column) { @@ -3990,7 +4009,7 @@ LazyScript::maybeForwardedScriptSource() const /* static */ LazyScript* LazyScript::CreateRaw(ExclusiveContext* cx, HandleFunction fun, uint64_t packedFields, uint32_t begin, uint32_t end, - uint32_t lineno, uint32_t column) + uint32_t preludeStart, uint32_t lineno, uint32_t column) { union { PackedView p; @@ -4018,7 +4037,8 @@ LazyScript::CreateRaw(ExclusiveContext* cx, HandleFunction fun, cx->compartment()->scheduleDelazificationForDebugger(); - return new (res) LazyScript(fun, table.forget(), packed, begin, end, lineno, column); + return new (res) LazyScript(fun, table.forget(), packed, begin, end, + preludeStart, lineno, column); } /* static */ LazyScript* @@ -4026,7 +4046,8 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun, const frontend::AtomVector& closedOverBindings, Handle> innerFunctions, JSVersion version, - uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column) + uint32_t begin, uint32_t end, + uint32_t preludeStart, uint32_t lineno, uint32_t column) { union { PackedView p; @@ -4049,7 +4070,8 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun, p.isDerivedClassConstructor = false; p.needsHomeObject = false; - LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, lineno, column); + LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, preludeStart, + lineno, column); if (!res) return nullptr; @@ -4070,7 +4092,7 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun, HandleScript script, HandleScope enclosingScope, HandleScript enclosingScript, uint64_t packedFields, uint32_t begin, uint32_t end, - uint32_t lineno, uint32_t column) + uint32_t preludeStart, uint32_t lineno, uint32_t column) { // Dummy atom which is not a valid property name. RootedAtom dummyAtom(cx, cx->names().comma); @@ -4079,7 +4101,8 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun, // holding this lazy script. HandleFunction dummyFun = fun; - LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, lineno, column); + LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, preludeStart, + lineno, column); if (!res) return nullptr; diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 87da79901..bb8635581 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -575,10 +575,6 @@ class ScriptSource introductionOffset_ = offset; hasIntroductionOffset_ = true; } - - uint32_t parameterListEnd() const { - return parameterListEnd_; - } }; class ScriptSourceHolder @@ -857,9 +853,19 @@ class JSScript : public js::gc::TenuredCell uint32_t bodyScopeIndex_; /* index into the scopes array of the body scope */ - /* Range of characters in scriptSource which contains this script's source. */ + // Range of characters in scriptSource which contains this script's source. + // each field points the following location. + // + // function * f(a, b) { return a + b; } + // ^ ^ ^ + // | | | + // | sourceStart_ sourceEnd_ + // | + // preludeStart_ + // uint32_t sourceStart_; uint32_t sourceEnd_; + uint32_t preludeStart_; // Number of times the script has been called or has had backedges taken. // When running in ion, also increased for any inlined scripts. Reset if @@ -1020,7 +1026,7 @@ class JSScript : public js::gc::TenuredCell // instead of private to suppress -Wunused-private-field compiler warnings. protected: #if JS_BITS_PER_WORD == 32 - // Currently no padding is needed. + uint32_t padding; #endif // @@ -1031,7 +1037,7 @@ class JSScript : public js::gc::TenuredCell static JSScript* Create(js::ExclusiveContext* cx, const JS::ReadOnlyCompileOptions& options, js::HandleObject sourceObject, uint32_t sourceStart, - uint32_t sourceEnd); + uint32_t sourceEnd, uint32_t preludeStart); void initCompartment(js::ExclusiveContext* cx); @@ -1178,6 +1184,10 @@ class JSScript : public js::gc::TenuredCell return sourceEnd_; } + size_t preludeStart() const { + return preludeStart_; + } + bool noScriptRval() const { return noScriptRval_; } @@ -1501,7 +1511,8 @@ class JSScript : public js::gc::TenuredCell bool mayReadFrameArgsDirectly(); JSFlatString* sourceData(JSContext* cx); - + JSFlatString* sourceDataWithPrelude(JSContext* cx); + static bool loadSource(JSContext* cx, js::ScriptSource* ss, bool* worked); void setSourceObject(JSObject* object); @@ -1920,7 +1931,8 @@ class LazyScript : public gc::TenuredCell // instead of private to suppress -Wunused-private-field compiler warnings. protected: #if JS_BITS_PER_WORD == 32 - uint32_t padding; + // uint32_t padding; + // Currently no padding is needed. #endif private: @@ -1960,20 +1972,25 @@ class LazyScript : public gc::TenuredCell }; // Source location for the script. + // See the comment in JSScript for the details. uint32_t begin_; uint32_t end_; + uint32_t preludeStart_; + // Line and column of |begin_| position, that is the position where we + // start parsing. uint32_t lineno_; uint32_t column_; LazyScript(JSFunction* fun, void* table, uint64_t packedFields, - uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column); + uint32_t begin, uint32_t end, uint32_t preludeStart, + uint32_t lineno, uint32_t column); // Create a LazyScript without initializing the closedOverBindings and the // innerFunctions. To be GC-safe, the caller must initialize both vectors // with valid atoms and functions. static LazyScript* CreateRaw(ExclusiveContext* cx, HandleFunction fun, uint64_t packedData, uint32_t begin, uint32_t end, - uint32_t lineno, uint32_t column); + uint32_t preludeStart, uint32_t lineno, uint32_t column); public: static const uint32_t NumClosedOverBindingsLimit = 1 << NumClosedOverBindingsBits; @@ -1985,7 +2002,7 @@ class LazyScript : public gc::TenuredCell const frontend::AtomVector& closedOverBindings, Handle> innerFunctions, JSVersion version, uint32_t begin, uint32_t end, - uint32_t lineno, uint32_t column); + uint32_t preludeStart, uint32_t lineno, uint32_t column); // Create a LazyScript and initialize the closedOverBindings and the // innerFunctions with dummy values to be replaced in a later initialization @@ -2000,7 +2017,7 @@ class LazyScript : public gc::TenuredCell HandleScript script, HandleScope enclosingScope, HandleScript enclosingScript, uint64_t packedData, uint32_t begin, uint32_t end, - uint32_t lineno, uint32_t column); + uint32_t preludeStart, uint32_t lineno, uint32_t column); void initRuntimeFields(uint64_t packedFields); @@ -2173,6 +2190,9 @@ class LazyScript : public gc::TenuredCell uint32_t end() const { return end_; } + uint32_t preludeStart() const { + return preludeStart_; + } uint32_t lineno() const { return lineno_; } @@ -2199,7 +2219,8 @@ class LazyScript : public gc::TenuredCell }; /* If this fails, add/remove padding within LazyScript. */ -JS_STATIC_ASSERT(sizeof(LazyScript) % js::gc::CellSize == 0); +static_assert(sizeof(LazyScript) % js::gc::CellSize == 0, + "Size of LazyScript must be an integral multiple of js::gc::CellSize"); struct ScriptAndCounts { diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp index 2237d1d7f..2b6690363 100644 --- a/js/src/wasm/AsmJS.cpp +++ b/js/src/wasm/AsmJS.cpp @@ -318,6 +318,7 @@ struct js::AsmJSMetadata : Metadata, AsmJSMetadataCacheablePod // Function constructor, this will be the first character in the function // source. Otherwise, it will be the opening parenthesis of the arguments // list. + uint32_t preludeStart; uint32_t srcStart; uint32_t srcBodyStart; bool strict; @@ -1758,6 +1759,7 @@ class MOZ_STACK_CLASS ModuleValidator if (!asmJSMetadata_) return false; + asmJSMetadata_->preludeStart = moduleFunctionNode_->pn_funbox->preludeStart; asmJSMetadata_->srcStart = moduleFunctionNode_->pn_body->pn_pos.begin; asmJSMetadata_->srcBodyStart = parser_.tokenStream.currentToken().pos.end; asmJSMetadata_->strict = parser_.pc->sc()->strict() && @@ -7049,6 +7051,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line) TokenStream& tokenStream = m.tokenStream(); tokenStream.consumeKnownToken(TOK_FUNCTION, TokenStream::Operand); + uint32_t preludeStart = tokenStream.currentToken().pos.begin; *line = tokenStream.srcCoords.lineNum(tokenStream.currentToken().pos.end); TokenKind tk; @@ -7071,7 +7074,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line) ParseContext* outerpc = m.parser().pc; Directives directives(outerpc); - FunctionBox* funbox = m.parser().newFunctionBox(fn, fun, directives, NotGenerator, + FunctionBox* funbox = m.parser().newFunctionBox(fn, fun, preludeStart, directives, NotGenerator, SyncFunction, /* tryAnnexB = */ false); if (!funbox) return false; @@ -8054,7 +8057,7 @@ HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& me return false; } - uint32_t begin = metadata.srcStart; + uint32_t begin = metadata.preludeStart; uint32_t end = metadata.srcEndAfterCurly(); Rooted src(cx, source->substringDontDeflate(cx, begin, end)); if (!src) @@ -8085,7 +8088,7 @@ HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& me SourceBufferHolder::Ownership ownership = stableChars.maybeGiveOwnershipToCaller() ? SourceBufferHolder::GiveOwnership : SourceBufferHolder::NoOwnership; - SourceBufferHolder srcBuf(chars, stableChars.twoByteRange().length(), ownership); + SourceBufferHolder srcBuf(chars, end - begin, ownership); if (!frontend::CompileStandaloneFunction(cx, &fun, options, srcBuf, Nothing())) return false; @@ -8537,6 +8540,7 @@ LookupAsmJSModuleInCache(ExclusiveContext* cx, AsmJSParser& parser, bool* loaded return true; // See AsmJSMetadata comment as well as ModuleValidator::init(). + asmJSMetadata->preludeStart = parser.pc->functionBox()->preludeStart; asmJSMetadata->srcStart = parser.pc->functionBox()->functionNode->pn_body->pn_pos.begin; asmJSMetadata->srcBodyStart = parser.tokenStream.currentToken().pos.end; asmJSMetadata->strict = parser.pc->sc()->strict() && !parser.pc->sc()->hasExplicitUseStrict(); @@ -8834,7 +8838,7 @@ js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool addParenToLambda MOZ_ASSERT(IsAsmJSModule(fun)); const AsmJSMetadata& metadata = AsmJSModuleFunctionToModule(fun).metadata().asAsmJS(); - uint32_t begin = metadata.srcStart; + uint32_t begin = metadata.preludeStart; uint32_t end = metadata.srcEndAfterCurly(); ScriptSource* source = metadata.scriptSource.get(); @@ -8843,17 +8847,15 @@ js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool addParenToLambda if (addParenToLambda && fun->isLambda() && !out.append("(")) return nullptr; - if (!out.append("function ")) - return nullptr; - - if (fun->explicitName() && !out.append(fun->explicitName())) - return nullptr; - bool haveSource = source->hasSourceData(); if (!haveSource && !JSScript::loadSource(cx, source, &haveSource)) return nullptr; if (!haveSource) { + if (!out.append("function ")) + return nullptr; + if (fun->explicitName() && !out.append(fun->explicitName())) + return nullptr; if (!out.append("() {\n [sourceless code]\n}")) return nullptr; } else { -- cgit v1.2.3 From 4ee0411274b7ded730da8cb87f016d53dab56533 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 2 Feb 2019 13:51:57 +0100 Subject: Stage 1-2: Remove a space after comma in parameter list for generated function source. --- js/src/jsfun.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'js/src') diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 4412362c2..be11bf436 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -1715,7 +1715,7 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator if (i < args.length() - 2) { // Step 9.d.iii. - if (!sb.append(", ")) + if (!sb.append(",")) return false; } } -- cgit v1.2.3 From 90f6b2704658a554a12ed3c37545cb6474fbcf51 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 2 Feb 2019 14:29:54 +0100 Subject: Stage 1-3: Generate better source in Object.prototype.toSource. Tag #960. --- js/src/builtin/Object.cpp | 280 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 193 insertions(+), 87 deletions(-) (limited to 'js/src') diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp index cd4ac122c..389bb57db 100644 --- a/js/src/builtin/Object.cpp +++ b/js/src/builtin/Object.cpp @@ -9,11 +9,13 @@ #include "mozilla/ArrayUtils.h" #include "jscntxt.h" +#include "jsstr.h" #include "builtin/Eval.h" #include "frontend/BytecodeCompiler.h" #include "jit/InlinableNatives.h" #include "js/UniquePtr.h" +#include "vm/AsyncFunction.h" #include "vm/StringBuffer.h" #include "jsobjinlines.h" @@ -124,6 +126,27 @@ obj_toSource(JSContext* cx, unsigned argc, Value* vp) return true; } +template +static bool +Consume(const CharT*& s, const CharT* e, const char *chars) +{ + size_t len = strlen(chars); + if (s + len >= e) + return false; + if (!EqualChars(s, chars, len)) + return false; + s += len; + return true; +} + +template +static void +ConsumeSpaces(const CharT*& s, const CharT* e) +{ + while (*s == ' ' && s < e) + s++; +} + /* * Given a function source string, return the offset and length of the part * between '(function $name' and ')'. @@ -133,37 +156,53 @@ static bool ArgsAndBodySubstring(mozilla::Range chars, size_t* outOffset, size_t* outLen) { const CharT* const start = chars.begin().get(); - const CharT* const end = chars.end().get(); const CharT* s = start; + const CharT* e = chars.end().get(); - uint8_t parenChomp = 0; - if (s[0] == '(') { - s++; - parenChomp = 1; - } - - /* Try to jump "function" keyword. */ - s = js_strchr_limit(s, ' ', end); - if (!s) + if (s == e) return false; - /* - * Jump over the function's name: it can't be encoded as part - * of an ECMA getter or setter. - */ - s = js_strchr_limit(s, '(', end); - if (!s) - return false; + // Remove enclosing parentheses. + if (*s == '(' && *(e - 1) == ')') { + s++; + e--; + } - if (*s == ' ') + (void) Consume(s, e, "async"); + ConsumeSpaces(s, e); + (void) (Consume(s, e, "function") || Consume(s, e, "get") || Consume(s, e, "set")); + ConsumeSpaces(s, e); + (void) Consume(s, e, "*"); + ConsumeSpaces(s, e); + + // Jump over the function's name. + if (Consume(s, e, "[")) { + s = js_strchr_limit(s, ']', e); + if (!s) + return false; s++; + ConsumeSpaces(s, e); + if (*s != '(') + return false; + } else { + s = js_strchr_limit(s, '(', e); + if (!s) + return false; + } *outOffset = s - start; - *outLen = end - s - parenChomp; + *outLen = e - s; MOZ_ASSERT(*outOffset + *outLen <= chars.length()); return true; } +enum class PropertyKind { + Getter, + Setter, + Method, + Normal +}; + JSString* js::ObjectToSource(JSContext* cx, HandleObject obj) { @@ -182,59 +221,28 @@ js::ObjectToSource(JSContext* cx, HandleObject obj) if (!buf.append('{')) return nullptr; - RootedValue v0(cx), v1(cx); - MutableHandleValue val[2] = {&v0, &v1}; - - RootedString str0(cx), str1(cx); - MutableHandleString gsop[2] = {&str0, &str1}; - AutoIdVector idv(cx); if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY | JSITER_SYMBOLS, &idv)) return nullptr; bool comma = false; - for (size_t i = 0; i < idv.length(); ++i) { - RootedId id(cx, idv[i]); - Rooted desc(cx); - if (!GetOwnPropertyDescriptor(cx, obj, id, &desc)) - return nullptr; - - int valcnt = 0; - if (desc.object()) { - if (desc.isAccessorDescriptor()) { - if (desc.hasGetterObject() && desc.getterObject()) { - val[valcnt].setObject(*desc.getterObject()); - gsop[valcnt].set(cx->names().get); - valcnt++; - } - if (desc.hasSetterObject() && desc.setterObject()) { - val[valcnt].setObject(*desc.setterObject()); - gsop[valcnt].set(cx->names().set); - valcnt++; - } - } else { - valcnt = 1; - val[0].set(desc.value()); - gsop[0].set(nullptr); - } - } - + auto AddProperty = [cx, &comma, &buf](HandleId id, HandleValue val, PropertyKind kind) -> bool { /* Convert id to a string. */ RootedString idstr(cx); if (JSID_IS_SYMBOL(id)) { RootedValue v(cx, SymbolValue(JSID_TO_SYMBOL(id))); idstr = ValueToSource(cx, v); if (!idstr) - return nullptr; + return false; } else { RootedValue idv(cx, IdToValue(id)); idstr = ToString(cx, idv); if (!idstr) - return nullptr; + return false; /* - * If id is a string that's not an identifier, or if it's a negative - * integer, then it must be quoted. + * If id is a string that's not an identifier, or if it's a + * negative integer, then it must be quoted. */ if (JSID_IS_ATOM(id) ? !IsIdentifier(JSID_TO_ATOM(id)) @@ -242,28 +250,65 @@ js::ObjectToSource(JSContext* cx, HandleObject obj) { idstr = QuoteString(cx, idstr, char16_t('\'')); if (!idstr) - return nullptr; + return false; } } - for (int j = 0; j < valcnt; j++) { - /* Convert val[j] to its canonical source form. */ - JSString* valsource = ValueToSource(cx, val[j]); - if (!valsource) - return nullptr; + RootedString valsource(cx, ValueToSource(cx, val)); + if (!valsource) + return false; - RootedLinearString valstr(cx, valsource->ensureLinear(cx)); - if (!valstr) - return nullptr; + RootedLinearString valstr(cx, valsource->ensureLinear(cx)); + if (!valstr) + return false; + + if (comma && !buf.append(", ")) + return false; + comma = true; + + size_t voffset, vlength; + + // Methods and accessors can return exact syntax of source, that fits + // into property without adding property name or "get"/"set" prefix. + // Use the exact syntax when the following conditions are met: + // + // * It's a function object + // (exclude proxies) + // * Function's kind and property's kind are same + // (this can be false for dynamically defined properties) + // * Function has explicit name + // (this can be false for computed property and dynamically defined + // properties) + // * Function's name and property's name are same + // (this can be false for dynamically defined properties) + if (kind == PropertyKind::Getter || kind == PropertyKind::Setter || + kind == PropertyKind::Method) + { + RootedFunction fun(cx); + if (val.toObject().is()) { + fun = &val.toObject().as(); + // Method's case should be checked on caller. + if (((fun->isGetter() && kind == PropertyKind::Getter) || + (fun->isSetter() && kind == PropertyKind::Setter) || + kind == PropertyKind::Method) && + fun->explicitName()) + { + bool result; + if (!EqualStrings(cx, fun->explicitName(), idstr, &result)) + return false; - size_t voffset = 0; - size_t vlength = valstr->length(); + if (result) { + if (!buf.append(valstr)) + return false; + return true; + } + } + } - /* - * Remove '(function ' from the beginning of valstr and ')' from the - * end so that we can put "get" in front of the function definition. - */ - if (gsop[j] && IsFunctionObject(val[j])) { + { + // When falling back try to generate a better string + // representation by skipping the prelude, and also removing + // the enclosing parentheses. bool success; JS::AutoCheckCannotGC nogc; if (valstr->hasLatin1Chars()) @@ -271,29 +316,90 @@ js::ObjectToSource(JSContext* cx, HandleObject obj) else success = ArgsAndBodySubstring(valstr->twoByteRange(nogc), &voffset, &vlength); if (!success) - gsop[j].set(nullptr); + kind = PropertyKind::Normal; } - if (comma && !buf.append(", ")) - return nullptr; - comma = true; + if (kind == PropertyKind::Getter) { + if (!buf.append("get ")) + return false; + } else if (kind == PropertyKind::Setter) { + if (!buf.append("set ")) + return false; + } else if (kind == PropertyKind::Method && fun) { + if (IsWrappedAsyncFunction(fun)) { + if (!buf.append("async ")) + return false; + } - if (gsop[j]) { - if (!buf.append(gsop[j]) || !buf.append(' ')) - return nullptr; + if (fun->isStarGenerator()) { + if (!buf.append('*')) + return false; + } } - if (JSID_IS_SYMBOL(id) && !buf.append('[')) - return nullptr; - if (!buf.append(idstr)) - return nullptr; - if (JSID_IS_SYMBOL(id) && !buf.append(']')) - return nullptr; - if (!buf.append(gsop[j] ? ' ' : ':')) - return nullptr; + } + bool needsBracket = JSID_IS_SYMBOL(id); + if (needsBracket && !buf.append('[')) + return false; + if (!buf.append(idstr)) + return false; + if (needsBracket && !buf.append(']')) + return false; + + if (kind == PropertyKind::Getter || kind == PropertyKind::Setter || + kind == PropertyKind::Method) + { if (!buf.appendSubstring(valstr, voffset, vlength)) - return nullptr; + return false; + } else { + if (!buf.append(':')) + return false; + if (!buf.append(valstr)) + return false; + } + return true; + }; + + RootedId id(cx); + Rooted desc(cx); + RootedValue val(cx); + RootedFunction fun(cx); + for (size_t i = 0; i < idv.length(); ++i) { + id = idv[i]; + if (!GetOwnPropertyDescriptor(cx, obj, id, &desc)) + return nullptr; + + if (!desc.object()) + continue; + + if (desc.isAccessorDescriptor()) { + if (desc.hasGetterObject() && desc.getterObject()) { + val.setObject(*desc.getterObject()); + if (!AddProperty(id, val, PropertyKind::Getter)) + return nullptr; + } + if (desc.hasSetterObject() && desc.setterObject()) { + val.setObject(*desc.setterObject()); + if (!AddProperty(id, val, PropertyKind::Setter)) + return nullptr; + } + continue; } + + val.set(desc.value()); + if (IsFunctionObject(val, fun.address())) { + if (IsWrappedAsyncFunction(fun)) + fun = GetUnwrappedAsyncFunction(fun); + + if (fun->isMethod()) { + if (!AddProperty(id, val, PropertyKind::Method)) + return nullptr; + continue; + } + } + + if (!AddProperty(id, val, PropertyKind::Normal)) + return nullptr; } if (!buf.append('}')) -- cgit v1.2.3 From f8f3dc70b6208d94991e52e9e034ac05e8bdac03 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 2 Feb 2019 16:43:45 +0100 Subject: Fix build error with JS_HAS_TOSOURCE undefined. --- js/src/jsstr.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'js/src') diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 4151d012b..e3b5708ca 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -3070,8 +3070,11 @@ js::ValueToSource(JSContext* cx, HandleValue v) return ToString(cx, v); } - +#if JS_HAS_TOSOURCE return ObjectToSource(cx, obj); +#else + return ToString(cx, v); +#endif } JSString* -- cgit v1.2.3 From ae4af7b7e598b4fec037254a1fd03ac3495695a4 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Sun, 3 Feb 2019 08:21:19 +0100 Subject: Stage 1-4: Update tests --- js/src/jit-test/tests/asm.js/testSource.js | 48 +-- .../tests/basic/function-tosource-bug779694.js | 2 +- .../tests/basic/function-tosource-constructor.js | 16 +- .../tests/basic/function-tosource-getset.js | 10 +- js/src/jit-test/tests/basic/testLet.js | 2 +- js/src/jit-test/tests/debug/Script-gc-02.js | 2 +- js/src/jit-test/tests/debug/Script-gc-03.js | 2 +- .../jit-test/tests/debug/Script-sourceStart-04.js | 4 +- js/src/jit-test/tests/debug/Source-text-02.js | 1 + js/src/jit-test/tests/latin1/assorted.js | 6 +- js/src/jit-test/tests/latin1/function.js | 4 +- js/src/tests/ecma_2017/Function/Object-toSource.js | 370 +++++++++++++++++++++ js/src/tests/ecma_2017/Function/browser.js | 0 js/src/tests/ecma_2017/Function/shell.js | 0 js/src/tests/ecma_6/Generators/runtime.js | 2 +- js/src/tests/js1_5/Scope/regress-185485.js | 2 +- js/src/tests/js1_7/extensions/regress-354945-01.js | 2 +- js/src/tests/js1_7/extensions/regress-354945-02.js | 2 +- js/src/tests/js1_8_5/regress/regress-584355.js | 2 +- 19 files changed, 424 insertions(+), 53 deletions(-) create mode 100644 js/src/tests/ecma_2017/Function/Object-toSource.js create mode 100644 js/src/tests/ecma_2017/Function/browser.js create mode 100644 js/src/tests/ecma_2017/Function/shell.js (limited to 'js/src') diff --git a/js/src/jit-test/tests/asm.js/testSource.js b/js/src/jit-test/tests/asm.js/testSource.js index b44c52a6b..d7ad42864 100644 --- a/js/src/jit-test/tests/asm.js/testSource.js +++ b/js/src/jit-test/tests/asm.js/testSource.js @@ -32,7 +32,7 @@ var f0 = function() { } -funcBody1 = funcBody.replace('function f0','function '); +funcBody1 = funcBody.replace('function f0','function'); assertEq(f0.toString(), funcBody1); assertEq(f0.toSource(), '(' + funcBody1 + ')'); @@ -48,14 +48,14 @@ assertEq(g.toString(), funcBody2); assertEq(g.toSource(), '(' + funcBody2 + ')'); f0 = new Function(bodyOnly); -assertEq(f0.toString(), "function anonymous() {\n" + bodyOnly + "\n}"); -assertEq(f0.toSource(), "(function anonymous() {\n" + bodyOnly + "\n})"); +assertEq(f0.toString(), "function anonymous(\n) {\n" + bodyOnly + "\n}"); +assertEq(f0.toSource(), "(function anonymous(\n) {\n" + bodyOnly + "\n})"); if (isAsmJSCompilationAvailable() && isCachingEnabled()) { var m = new Function(bodyOnly); assertEq(isAsmJSModuleLoadedFromCache(m), true); - assertEq(m.toString(), "function anonymous() {\n" + bodyOnly + "\n}"); - assertEq(m.toSource(), "(function anonymous() {\n" + bodyOnly + "\n})"); + assertEq(m.toString(), "function anonymous(\n) {\n" + bodyOnly + "\n}"); + assertEq(m.toSource(), "(function anonymous(\n) {\n" + bodyOnly + "\n})"); } })(); @@ -91,7 +91,7 @@ f1 = function(glob) { } -funcBody1 = funcBody.replace('function f1', 'function '); +funcBody1 = funcBody.replace('function f1', 'function'); assertEq(f1.toString(), funcBody1); assertEq(f1.toSource(), '(' + funcBody1 + ')'); @@ -107,14 +107,14 @@ assertEq(g.toString(), funcBody2); assertEq(g.toSource(), '(' + funcBody2 + ')'); f1 = new Function('glob', bodyOnly); -assertEq(f1.toString(), "function anonymous(glob) {\n" + bodyOnly + "\n}"); -assertEq(f1.toSource(), "(function anonymous(glob) {\n" + bodyOnly + "\n})"); +assertEq(f1.toString(), "function anonymous(glob\n) {\n" + bodyOnly + "\n}"); +assertEq(f1.toSource(), "(function anonymous(glob\n) {\n" + bodyOnly + "\n})"); if (isAsmJSCompilationAvailable() && isCachingEnabled()) { var m = new Function('glob', bodyOnly); assertEq(isAsmJSModuleLoadedFromCache(m), true); - assertEq(m.toString(), "function anonymous(glob) {\n" + bodyOnly + "\n}"); - assertEq(m.toSource(), "(function anonymous(glob) {\n" + bodyOnly + "\n})"); + assertEq(m.toString(), "function anonymous(glob\n) {\n" + bodyOnly + "\n}"); + assertEq(m.toSource(), "(function anonymous(glob\n) {\n" + bodyOnly + "\n})"); } })(); @@ -144,14 +144,14 @@ var funcBody = 'function f2(glob, ffi) {\n\ assertEq(f2.toString(), funcBody); assertEq(f2.toSource(), funcBody); -f2 = function (glob, ffi) { +f2 = function(glob, ffi) { "use asm"; function g() {} return g; } -funcBody1 = funcBody.replace('function f2', 'function '); +funcBody1 = funcBody.replace('function f2', 'function'); assertEq(f2.toString(), funcBody1); assertEq(f2.toSource(), '(' + funcBody1 + ')'); @@ -167,14 +167,14 @@ assertEq(g.toString(), funcBody2); assertEq(g.toSource(), '(' + funcBody2 + ')'); f2 = new Function('glob', 'ffi', bodyOnly); -assertEq(f2.toString(), "function anonymous(glob, ffi) {\n" + bodyOnly + "\n}"); -assertEq(f2.toSource(), "(function anonymous(glob, ffi) {\n" + bodyOnly + "\n})"); +assertEq(f2.toString(), "function anonymous(glob,ffi\n) {\n" + bodyOnly + "\n}"); +assertEq(f2.toSource(), "(function anonymous(glob,ffi\n) {\n" + bodyOnly + "\n})"); if (isAsmJSCompilationAvailable() && isCachingEnabled()) { var m = new Function('glob', 'ffi', bodyOnly); assertEq(isAsmJSModuleLoadedFromCache(m), true); - assertEq(m.toString(), "function anonymous(glob, ffi) {\n" + bodyOnly + "\n}"); - assertEq(m.toSource(), "(function anonymous(glob, ffi) {\n" + bodyOnly + "\n})"); + assertEq(m.toString(), "function anonymous(glob,ffi\n) {\n" + bodyOnly + "\n}"); + assertEq(m.toSource(), "(function anonymous(glob,ffi\n) {\n" + bodyOnly + "\n})"); } })(); @@ -204,14 +204,14 @@ var funcBody = 'function f3(glob, ffi, heap) {\n\ assertEq(f3.toString(), funcBody); assertEq(f3.toSource(), funcBody); -f3 = function (glob, ffi, heap) { +f3 = function(glob, ffi, heap) { "use asm"; function g() {} return g; } -funcBody1 = funcBody.replace('function f3', 'function '); +funcBody1 = funcBody.replace('function f3', 'function'); assertEq(f3.toString(), funcBody1); assertEq(f3.toSource(), '(' + funcBody1 + ')'); @@ -227,14 +227,14 @@ assertEq(g.toString(), funcBody2); assertEq(g.toSource(), '(' + funcBody2 + ')'); f3 = new Function('glob', 'ffi', 'heap', bodyOnly); -assertEq(f3.toString(), "function anonymous(glob, ffi, heap) {\n" + bodyOnly + "\n}"); -assertEq(f3.toSource(), "(function anonymous(glob, ffi, heap) {\n" + bodyOnly + "\n})"); +assertEq(f3.toString(), "function anonymous(glob,ffi,heap\n) {\n" + bodyOnly + "\n}"); +assertEq(f3.toSource(), "(function anonymous(glob,ffi,heap\n) {\n" + bodyOnly + "\n})"); if (isAsmJSCompilationAvailable() && isCachingEnabled()) { var m = new Function('glob', 'ffi', 'heap', bodyOnly); assertEq(isAsmJSModuleLoadedFromCache(m), true); - assertEq(m.toString(), "function anonymous(glob, ffi, heap) {\n" + bodyOnly + "\n}"); - assertEq(m.toSource(), "(function anonymous(glob, ffi, heap) {\n" + bodyOnly + "\n})"); + assertEq(m.toString(), "function anonymous(glob,ffi,heap\n) {\n" + bodyOnly + "\n}"); + assertEq(m.toSource(), "(function anonymous(glob,ffi,heap\n) {\n" + bodyOnly + "\n})"); } })(); @@ -243,7 +243,7 @@ if (isAsmJSCompilationAvailable() && isCachingEnabled()) { (function() { var funcSource = - `function (glob, ffi, heap) { + `function(glob, ffi, heap) { "use asm"; function g() {} return g; @@ -252,7 +252,7 @@ var funcSource = var f4 = eval("\"use strict\";\n(" + funcSource + ")"); var expectedToString = funcSource; -var expectedToSource = '(' + expectedToString + ')' +var expectedToSource = '(' + expectedToString + ')'; assertEq(f4.toString(), expectedToString); assertEq(f4.toSource(), expectedToSource); diff --git a/js/src/jit-test/tests/basic/function-tosource-bug779694.js b/js/src/jit-test/tests/basic/function-tosource-bug779694.js index 3893d3ff2..782b2594b 100644 --- a/js/src/jit-test/tests/basic/function-tosource-bug779694.js +++ b/js/src/jit-test/tests/basic/function-tosource-bug779694.js @@ -5,4 +5,4 @@ for (var i=0; i<400; ++i) { x += String.fromCharCode(i * 289); } var s = "'" + x + "'"; -assertEq(Function("evt", s).toString(), "function anonymous(evt) {\n" + s + "\n}"); +assertEq(Function("evt", s).toString(), "function anonymous(evt\n) {\n" + s + "\n}"); diff --git a/js/src/jit-test/tests/basic/function-tosource-constructor.js b/js/src/jit-test/tests/basic/function-tosource-constructor.js index e1d144364..9a8961fe2 100644 --- a/js/src/jit-test/tests/basic/function-tosource-constructor.js +++ b/js/src/jit-test/tests/basic/function-tosource-constructor.js @@ -1,14 +1,14 @@ var f = Function("a", "b", "return a + b;"); -assertEq(f.toString(), "function anonymous(a, b) {\nreturn a + b;\n}"); -assertEq(f.toSource(), "(function anonymous(a, b) {\nreturn a + b;\n})"); +assertEq(f.toString(), "function anonymous(a,b\n) {\nreturn a + b;\n}"); +assertEq(f.toSource(), "(function anonymous(a,b\n) {\nreturn a + b;\n})"); assertEq(decompileFunction(f), f.toString()); f = Function("a", "...rest", "return rest[42] + b;"); -assertEq(f.toString(), "function anonymous(a, ...rest) {\nreturn rest[42] + b;\n}"); -assertEq(f.toSource(), "(function anonymous(a, ...rest) {\nreturn rest[42] + b;\n})") +assertEq(f.toString(), "function anonymous(a,...rest\n) {\nreturn rest[42] + b;\n}"); +assertEq(f.toSource(), "(function anonymous(a,...rest\n) {\nreturn rest[42] + b;\n})") assertEq(decompileFunction(f), f.toString()); f = Function(""); -assertEq(f.toString(), "function anonymous() {\n\n}"); +assertEq(f.toString(), "function anonymous(\n) {\n\n}"); f = Function("", "(abc)"); -assertEq(f.toString(), "function anonymous() {\n(abc)\n}"); -f = Function("", "return function (a, b) a + b;")(); -assertEq(f.toString(), "function (a, b) a + b"); +assertEq(f.toString(), "function anonymous(\n) {\n(abc)\n}"); +f = Function("", "return function (a,b) a + b;")(); +assertEq(f.toString(), "function (a,b) a + b"); diff --git a/js/src/jit-test/tests/basic/function-tosource-getset.js b/js/src/jit-test/tests/basic/function-tosource-getset.js index 36c6d010e..1804d38f2 100644 --- a/js/src/jit-test/tests/basic/function-tosource-getset.js +++ b/js/src/jit-test/tests/basic/function-tosource-getset.js @@ -1,7 +1,7 @@ var o = {get prop() a + b, set prop(x) a + b}; var prop = Object.getOwnPropertyDescriptor(o, "prop"); -assertEq(prop.get.toString(), "function get prop() a + b"); -assertEq(prop.get.toSource(), "(function get prop() a + b)"); -assertEq(prop.set.toString(), "function set prop(x) a + b"); -assertEq(prop.set.toSource(), "(function set prop(x) a + b)"); -assertEq(o.toSource(), "({get prop () a + b, set prop (x) a + b})"); +assertEq(prop.get.toString(), "get prop() { a + b; }"); +assertEq(prop.get.toSource(), "get prop() { a + b; }"); +assertEq(prop.set.toString(), "set prop(x) { a + b; }"); +assertEq(prop.set.toSource(), "set prop(x) { a + b; }"); +assertEq(o.toSource(), "({get prop() { a + b; }, set prop(x) { a + b; }})"); diff --git a/js/src/jit-test/tests/basic/testLet.js b/js/src/jit-test/tests/basic/testLet.js index 263c3eb8a..9a2f39197 100644 --- a/js/src/jit-test/tests/basic/testLet.js +++ b/js/src/jit-test/tests/basic/testLet.js @@ -9,7 +9,7 @@ function test(str, arg, result) var fun = new Function('x', str); var got = fun.toSource(); - var expect = '(function anonymous(x) {\n' + str + '\n})'; + var expect = '(function anonymous(x\n) {\n' + str + '\n})'; if (got !== expect) { print("GOT: " + got); print("EXPECT: " + expect); diff --git a/js/src/jit-test/tests/debug/Script-gc-02.js b/js/src/jit-test/tests/debug/Script-gc-02.js index 04dd4b220..9689a6ebe 100644 --- a/js/src/jit-test/tests/debug/Script-gc-02.js +++ b/js/src/jit-test/tests/debug/Script-gc-02.js @@ -10,5 +10,5 @@ assertEq(arr.length, 10); gc(); for (var i = 0; i < arr.length; i++) - assertEq(arr[i].lineCount, 3); + assertEq(arr[i].lineCount, 4); diff --git a/js/src/jit-test/tests/debug/Script-gc-03.js b/js/src/jit-test/tests/debug/Script-gc-03.js index 30c3e8dbc..5ecb4556f 100644 --- a/js/src/jit-test/tests/debug/Script-gc-03.js +++ b/js/src/jit-test/tests/debug/Script-gc-03.js @@ -10,6 +10,6 @@ assertEq(arr.length, 100); gc(g); for (var i = 0; i < arr.length; i++) - assertEq(arr[i].lineCount, 3); + assertEq(arr[i].lineCount, 4); gc(); diff --git a/js/src/jit-test/tests/debug/Script-sourceStart-04.js b/js/src/jit-test/tests/debug/Script-sourceStart-04.js index 2aa382b7b..4546818e4 100644 --- a/js/src/jit-test/tests/debug/Script-sourceStart-04.js +++ b/js/src/jit-test/tests/debug/Script-sourceStart-04.js @@ -20,6 +20,6 @@ function test(string, range) { } test("eval('2 * 3')", [0, 5]); -test("new Function('2 * 3')", [0, 12]); -test("new Function('x', 'x * x')", [0, 13]); +test("new Function('2 * 3')", [0, 31]); +test("new Function('x', 'x * x')", [0, 32]); assertEq(count, 6); diff --git a/js/src/jit-test/tests/debug/Source-text-02.js b/js/src/jit-test/tests/debug/Source-text-02.js index 64cfce92a..46e76015e 100644 --- a/js/src/jit-test/tests/debug/Source-text-02.js +++ b/js/src/jit-test/tests/debug/Source-text-02.js @@ -3,6 +3,7 @@ let g = newGlobal(); let dbg = new Debugger(g); +var text; var count = 0; dbg.onNewScript = function (script) { ++count; diff --git a/js/src/jit-test/tests/latin1/assorted.js b/js/src/jit-test/tests/latin1/assorted.js index cef79cb96..1389a1ada 100644 --- a/js/src/jit-test/tests/latin1/assorted.js +++ b/js/src/jit-test/tests/latin1/assorted.js @@ -12,18 +12,18 @@ var o = {}; Object.defineProperty(o, "prop", {get: function() { return 1; }, set: function() { return 2; }, enumerable: true, configurable: true}); -assertEq(o.toSource(), "({get prop () { return 1; }, set prop () { return 2; }})"); +assertEq(o.toSource(), "({get prop() { return 1; }, set prop() { return 2; }})"); // obj.toSource TwoByte Object.defineProperty(o, "prop", {get: function() { return "\u1200"; }, set: function() { return "\u1200"; }, enumerable: true}); -assertEq(o.toSource(), '({get prop () { return "\\u1200"; }, set prop () { return "\\u1200"; }})'); +assertEq(o.toSource(), '({get prop() { return "\\u1200"; }, set prop() { return "\\u1200"; }})'); var ff = function() { return 10; }; ff.toSource = function() { return "((11))"; } Object.defineProperty(o, "prop", {get: ff, set: ff, enumerable: true}); -assertEq(o.toSource(), "({prop:((11)), prop:((11))})"); +assertEq(o.toSource(), "({get prop(11), set prop(11)})"); // XDR load(libdir + 'bytecode-cache.js'); diff --git a/js/src/jit-test/tests/latin1/function.js b/js/src/jit-test/tests/latin1/function.js index a0dedf251..07a76733a 100644 --- a/js/src/jit-test/tests/latin1/function.js +++ b/js/src/jit-test/tests/latin1/function.js @@ -6,11 +6,11 @@ function test() { var f = Function(arg1TwoByte, arg2Latin1, bodyLatin1); assertEq(f(10, 20), 60); - assertEq(f.toSource().includes("arg1\u1200, arg2"), true); + assertEq(f.toSource().includes("arg1\u1200,arg2"), true); var bodyTwoByte = "return arg1\u1200 + arg2;"; f = Function(arg1TwoByte, arg2Latin1, bodyTwoByte); assertEq(f(30, 40), 70); - assertEq(f.toSource().includes("arg1\u1200, arg2"), true); + assertEq(f.toSource().includes("arg1\u1200,arg2"), true); } test(); diff --git a/js/src/tests/ecma_2017/Function/Object-toSource.js b/js/src/tests/ecma_2017/Function/Object-toSource.js new file mode 100644 index 000000000..33b9e588e --- /dev/null +++ b/js/src/tests/ecma_2017/Function/Object-toSource.js @@ -0,0 +1,370 @@ +var BUGNUMBER = 1317400; +var summary = "Function string representation in Object.prototype.toSource"; + +print(BUGNUMBER + ": " + summary); + +// Methods. + +assertEq(({ foo(){} }).toSource(), + "({foo(){}})"); +assertEq(({ *foo(){} }).toSource(), + "({*foo(){}})"); +assertEq(({ async foo(){} }).toSource(), + "({async foo(){}})"); + +assertEq(({ 1(){} }).toSource(), + "({1(){}})"); + +// Methods with more spacing. +// Spacing is kept. + +assertEq(({ foo (){} }).toSource(), + "({foo (){}})"); +assertEq(({ foo () {} }).toSource(), + "({foo () {}})"); + +// Methods with computed name. +// Method syntax is composed. + +let name = "foo"; +assertEq(({ [name](){} }).toSource(), + "({foo(){}})"); +assertEq(({ *[name](){} }).toSource(), + "({*foo(){}})"); +assertEq(({ async [name](){} }).toSource(), + "({async foo(){}})"); + +assertEq(({ [ Symbol.iterator ](){} }).toSource(), + "({[Symbol.iterator](){}})"); + +// Accessors. + +assertEq(({ get foo(){} }).toSource(), + "({get foo(){}})"); +assertEq(({ set foo(v){} }).toSource(), + "({set foo(v){}})"); + +// Accessors with computed name. +// Method syntax is composed. + +assertEq(({ get [name](){} }).toSource(), + "({get foo(){}})"); +assertEq(({ set [name](v){} }).toSource(), + "({set foo(v){}})"); + +assertEq(({ get [ Symbol.iterator ](){} }).toSource(), + "({get [Symbol.iterator](){}})"); +assertEq(({ set [ Symbol.iterator ](v){} }).toSource(), + "({set [Symbol.iterator](v){}})"); + +// Getter and setter with same name. +// Getter always comes before setter. + +assertEq(({ get foo(){}, set foo(v){} }).toSource(), + "({get foo(){}, set foo(v){}})"); +assertEq(({ set foo(v){}, get foo(){} }).toSource(), + "({get foo(){}, set foo(v){}})"); + +// Normal properties. + +assertEq(({ foo: function(){} }).toSource(), + "({foo:(function(){})})"); +assertEq(({ foo: function bar(){} }).toSource(), + "({foo:(function bar(){})})"); +assertEq(({ foo: function*(){} }).toSource(), + "({foo:(function*(){})})"); +assertEq(({ foo: async function(){} }).toSource(), + "({foo:(async function(){})})"); + +// Normal properties with computed name. + +assertEq(({ [ Symbol.iterator ]: function(){} }).toSource(), + "({[Symbol.iterator]:(function(){})})"); + +// Dynamically defined properties with function expression. +// Never become a method syntax. + +let obj = {}; +obj.foo = function() {}; +assertEq(obj.toSource(), + "({foo:(function() {})})"); + +obj = {}; +Object.defineProperty(obj, "foo", {value: function() {}}); +assertEq(obj.toSource(), + "({})"); + +obj = {}; +Object.defineProperty(obj, "foo", {value: function() {}, enumerable: true}); +assertEq(obj.toSource(), + "({foo:(function() {})})"); + +obj = {}; +Object.defineProperty(obj, "foo", {value: function bar() {}, enumerable: true}); +assertEq(obj.toSource(), + "({foo:(function bar() {})})"); + +obj = {}; +Object.defineProperty(obj, Symbol.iterator, {value: function() {}, enumerable: true}); +assertEq(obj.toSource(), + "({[Symbol.iterator]:(function() {})})"); + +// Dynamically defined property with other object's method. +// Method syntax is composed. + +let method = ({foo() {}}).foo; + +obj = {}; +Object.defineProperty(obj, "foo", {value: method, enumerable: true}); +assertEq(obj.toSource(), + "({foo() {}})"); + +obj = {}; +Object.defineProperty(obj, "bar", {value: method, enumerable: true}); +assertEq(obj.toSource(), + "({bar() {}})"); + +method = ({*foo() {}}).foo; + +obj = {}; +Object.defineProperty(obj, "bar", {value: method, enumerable: true}); +assertEq(obj.toSource(), + "({*bar() {}})"); + +method = ({async foo() {}}).foo; + +obj = {}; +Object.defineProperty(obj, "bar", {value: method, enumerable: true}); +assertEq(obj.toSource(), + "({async bar() {}})"); + +// Dynamically defined accessors. +// Accessor syntax is composed. + +obj = {}; +Object.defineProperty(obj, "foo", {get: function() {}, enumerable: true}); +assertEq(obj.toSource(), + "({get foo() {}})"); + +obj = {}; +Object.defineProperty(obj, "foo", {set: function() {}, enumerable: true}); +assertEq(obj.toSource(), + "({set foo() {}})"); + +obj = {}; +Object.defineProperty(obj, Symbol.iterator, {get: function() {}, enumerable: true}); +assertEq(obj.toSource(), + "({get [Symbol.iterator]() {}})"); + +obj = {}; +Object.defineProperty(obj, Symbol.iterator, {set: function() {}, enumerable: true}); +assertEq(obj.toSource(), + "({set [Symbol.iterator]() {}})"); + +// Dynamically defined accessors with other object's accessors. +// Accessor syntax is composed. + +let accessor = Object.getOwnPropertyDescriptor({ get foo() {} }, "foo").get; +obj = {}; +Object.defineProperty(obj, "foo", {get: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({get foo() {}})"); + +accessor = Object.getOwnPropertyDescriptor({ get bar() {} }, "bar").get; +obj = {}; +Object.defineProperty(obj, "foo", {get: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({get foo() {}})"); + +accessor = Object.getOwnPropertyDescriptor({ set foo(v) {} }, "foo").set; +obj = {}; +Object.defineProperty(obj, "foo", {get: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({get foo(v) {}})"); + +accessor = Object.getOwnPropertyDescriptor({ set bar(v) {} }, "bar").set; +obj = {}; +Object.defineProperty(obj, "foo", {get: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({get foo(v) {}})"); + +accessor = Object.getOwnPropertyDescriptor({ get foo() {} }, "foo").get; +obj = {}; +Object.defineProperty(obj, "foo", {set: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({set foo() {}})"); + +accessor = Object.getOwnPropertyDescriptor({ get bar() {} }, "bar").get; +obj = {}; +Object.defineProperty(obj, "foo", {set: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({set foo() {}})"); + +accessor = Object.getOwnPropertyDescriptor({ set foo(v) {} }, "foo").set; +obj = {}; +Object.defineProperty(obj, "foo", {set: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({set foo(v) {}})"); + +accessor = Object.getOwnPropertyDescriptor({ set bar(v) {} }, "bar").set; +obj = {}; +Object.defineProperty(obj, "foo", {set: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({set foo(v) {}})"); + +// Methods with proxy. +// Treated as normal property. + +method = ({foo() {}}).foo; +let handler = { + get(that, name) { + if (name == "toSource") { + return function() { + return that.toSource(); + }; + } + return that[name]; + } +}; +let proxy = new Proxy(method, handler); + +obj = {}; +Object.defineProperty(obj, "foo", {value: proxy, enumerable: true}); +assertEq(obj.toSource(), + "({foo:foo() {}})"); + +// Accessors with proxy. +// Accessor syntax is composed. + +accessor = Object.getOwnPropertyDescriptor({ get foo() {} }, "foo").get; +proxy = new Proxy(accessor, handler); + +obj = {}; +Object.defineProperty(obj, "foo", {get: proxy, enumerable: true}); +assertEq(obj.toSource(), + "({get foo() {}})"); + +obj = {}; +Object.defineProperty(obj, "foo", {set: proxy, enumerable: true}); +assertEq(obj.toSource(), + "({set foo() {}})"); + +// Methods from other global. +// Treated as normal property. + +let g = newGlobal(); + +method = g.eval("({ foo() {} }).foo"); + +obj = {}; +Object.defineProperty(obj, "foo", {value: method, enumerable: true}); +assertEq(obj.toSource(), + "({foo:foo() {}})"); + +// Accessors from other global. +// Accessor syntax is composed. + +accessor = g.eval("Object.getOwnPropertyDescriptor({ get foo() {} }, 'foo').get"); + +obj = {}; +Object.defineProperty(obj, "foo", {get: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({get foo() {}})"); + +accessor = g.eval("Object.getOwnPropertyDescriptor({ get bar() {} }, 'bar').get"); + +obj = {}; +Object.defineProperty(obj, "foo", {get: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({get foo() {}})"); + +accessor = g.eval("Object.getOwnPropertyDescriptor({ set foo(v) {} }, 'foo').set"); + +obj = {}; +Object.defineProperty(obj, "foo", {get: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({get foo(v) {}})"); + +accessor = g.eval("Object.getOwnPropertyDescriptor({ set bar(v) {} }, 'bar').set"); + +obj = {}; +Object.defineProperty(obj, "foo", {get: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({get foo(v) {}})"); + +accessor = g.eval("Object.getOwnPropertyDescriptor({ get foo() {} }, 'foo').get"); + +obj = {}; +Object.defineProperty(obj, "foo", {set: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({set foo() {}})"); + +accessor = g.eval("Object.getOwnPropertyDescriptor({ get bar() {} }, 'bar').get"); + +obj = {}; +Object.defineProperty(obj, "foo", {set: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({set foo() {}})"); + +accessor = g.eval("Object.getOwnPropertyDescriptor({ set foo(v) {} }, 'foo').set"); + +obj = {}; +Object.defineProperty(obj, "foo", {set: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({set foo(v) {}})"); + +accessor = g.eval("Object.getOwnPropertyDescriptor({ set bar(v) {} }, 'bar').set"); + +obj = {}; +Object.defineProperty(obj, "foo", {set: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({set foo(v) {}})"); + +// **** Some weird cases **** + +// Accessors with generator or async. + +obj = {}; +Object.defineProperty(obj, "foo", {get: function*() {}, enumerable: true}); +assertEq(obj.toSource(), + "({get foo() {}})"); + +obj = {}; +Object.defineProperty(obj, "foo", {set: async function() {}, enumerable: true}); +assertEq(obj.toSource(), + "({set foo() {}})"); + +// Modified toSource. + +obj = { foo() {} }; +obj.foo.toSource = () => "hello"; +assertEq(obj.toSource(), + "({hello})"); + +obj = { foo() {} }; +obj.foo.toSource = () => "bar() {}"; +assertEq(obj.toSource(), + "({bar() {}})"); + +// Modified toSource with different method name. + +obj = {}; +Object.defineProperty(obj, "foo", {value: function bar() {}, enumerable: true}); +obj.foo.toSource = () => "hello"; +assertEq(obj.toSource(), + "({foo:hello})"); + +obj = {}; +Object.defineProperty(obj, "foo", {value: function* bar() {}, enumerable: true}); +obj.foo.toSource = () => "hello"; +assertEq(obj.toSource(), + "({foo:hello})"); + +obj = {}; +Object.defineProperty(obj, "foo", {value: async function bar() {}, enumerable: true}); +obj.foo.toSource = () => "hello"; +assertEq(obj.toSource(), + "({foo:hello})"); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_2017/Function/browser.js b/js/src/tests/ecma_2017/Function/browser.js new file mode 100644 index 000000000..e69de29bb diff --git a/js/src/tests/ecma_2017/Function/shell.js b/js/src/tests/ecma_2017/Function/shell.js new file mode 100644 index 000000000..e69de29bb diff --git a/js/src/tests/ecma_6/Generators/runtime.js b/js/src/tests/ecma_6/Generators/runtime.js index c4d3bb6a6..7146eef9f 100644 --- a/js/src/tests/ecma_6/Generators/runtime.js +++ b/js/src/tests/ecma_6/Generators/runtime.js @@ -109,7 +109,7 @@ function TestGeneratorFunction() { // Doesn't matter particularly what string gets serialized, as long // as it contains "function*" and "yield 10". assertEq(GeneratorFunction('yield 10').toString(), - "function* anonymous() {\nyield 10\n}"); + "function* anonymous(\n) {\nyield 10\n}"); } TestGeneratorFunction(); diff --git a/js/src/tests/js1_5/Scope/regress-185485.js b/js/src/tests/js1_5/Scope/regress-185485.js index 19d190eea..a75bf885a 100644 --- a/js/src/tests/js1_5/Scope/regress-185485.js +++ b/js/src/tests/js1_5/Scope/regress-185485.js @@ -94,7 +94,7 @@ with (x) } status = inSection(5); actual = x.g.toString(); -expect = (function () {}).toString(); +expect = (function() {}).toString(); addThis(); diff --git a/js/src/tests/js1_7/extensions/regress-354945-01.js b/js/src/tests/js1_7/extensions/regress-354945-01.js index 76f1a3c82..1c57db0f7 100644 --- a/js/src/tests/js1_7/extensions/regress-354945-01.js +++ b/js/src/tests/js1_7/extensions/regress-354945-01.js @@ -6,7 +6,7 @@ //----------------------------------------------------------------------------- var BUGNUMBER = 354945; var summary = 'Do not crash with new Iterator'; -var expect = 'TypeError: trap __iterator__ for ({__iterator__:(function (){ })}) returned a primitive value'; +var expect = 'TypeError: trap __iterator__ for ({__iterator__:(function(){ })}) returned a primitive value'; var actual; diff --git a/js/src/tests/js1_7/extensions/regress-354945-02.js b/js/src/tests/js1_7/extensions/regress-354945-02.js index 261bf7de1..abef90f77 100644 --- a/js/src/tests/js1_7/extensions/regress-354945-02.js +++ b/js/src/tests/js1_7/extensions/regress-354945-02.js @@ -20,7 +20,7 @@ function test() printBugNumber(BUGNUMBER); printStatus (summary); - expect = 'TypeError: trap __iterator__ for ({__iterator__:(function (){ })}) returned a primitive value'; + expect = 'TypeError: trap __iterator__ for ({__iterator__:(function(){ })}) returned a primitive value'; var obj = {}; obj.__iterator__ = function(){ }; try diff --git a/js/src/tests/js1_8_5/regress/regress-584355.js b/js/src/tests/js1_8_5/regress/regress-584355.js index 4ddfe65d3..7d1b81a2e 100644 --- a/js/src/tests/js1_8_5/regress/regress-584355.js +++ b/js/src/tests/js1_8_5/regress/regress-584355.js @@ -1,5 +1,5 @@ var actual; -var expect = "function f() { ff (); }"; +var expect = "function f () { ff (); }"; function fun() { (new Function ("function ff () { actual = '' + ff. caller; } function f () { ff (); } f ();")) (); } -- cgit v1.2.3 From 88db0108b14d58cf5d82ed7346f48f010feaaf0d Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 7 Feb 2019 10:39:40 +0100 Subject: Align `instanceof` with the final ES6 spec. --- js/src/jsapi.h | 7 +++++++ js/src/jsfun.cpp | 10 +++++----- js/src/jswrapper.h | 2 ++ js/src/proxy/OpaqueCrossCompartmentWrapper.cpp | 8 ++++++++ js/src/proxy/ScriptedProxyHandler.cpp | 4 +--- js/src/vm/Interpreter.cpp | 14 +++++++------- js/src/vm/Interpreter.h | 3 --- 7 files changed, 30 insertions(+), 18 deletions(-) (limited to 'js/src') diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 799396a0a..005d2278e 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -2154,6 +2154,13 @@ namespace JS { extern JS_PUBLIC_API(bool) OrdinaryHasInstance(JSContext* cx, HandleObject objArg, HandleValue v, bool* bp); +// Implementation of +// https://www.ecma-international.org/ecma-262/6.0/#sec-instanceofoperator +// This is almost identical to JS_HasInstance, except the latter may call a +// custom hasInstance class op instead of InstanceofOperator. +extern JS_PUBLIC_API(bool) +InstanceofOperator(JSContext* cx, HandleObject obj, HandleValue v, bool* bp); + } // namespace JS extern JS_PUBLIC_API(void*) diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index bcb0da80b..863871df9 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -690,7 +690,7 @@ js::fun_symbolHasInstance(JSContext* cx, unsigned argc, Value* vp) } /* - * ES6 (4-25-16) 7.3.19 OrdinaryHasInstance + * ES6 7.3.19 OrdinaryHasInstance */ bool JS::OrdinaryHasInstance(JSContext* cx, HandleObject objArg, HandleValue v, bool* bp) @@ -707,7 +707,7 @@ JS::OrdinaryHasInstance(JSContext* cx, HandleObject objArg, HandleValue v, bool* if (obj->is() && obj->isBoundFunction()) { /* Steps 2a-b. */ obj = obj->as().getBoundFunctionTarget(); - return InstanceOfOperator(cx, obj, v, bp); + return InstanceofOperator(cx, obj, v, bp); } /* Step 3. */ @@ -716,12 +716,12 @@ JS::OrdinaryHasInstance(JSContext* cx, HandleObject objArg, HandleValue v, bool* return true; } - /* Step 4. */ + /* Step 4-5. */ RootedValue pval(cx); if (!GetProperty(cx, obj, obj, cx->names().prototype, &pval)) return false; - /* Step 5. */ + /* Step 6. */ if (pval.isPrimitive()) { /* * Throw a runtime error if instanceof is called on a function that @@ -732,7 +732,7 @@ JS::OrdinaryHasInstance(JSContext* cx, HandleObject objArg, HandleValue v, bool* return false; } - /* Step 6. */ + /* Step 7. */ RootedObject pobj(cx, &pval.toObject()); bool isDelegate; if (!IsDelegate(cx, pobj, v, &isDelegate)) diff --git a/js/src/jswrapper.h b/js/src/jswrapper.h index 3c73979f8..84ebe2732 100644 --- a/js/src/jswrapper.h +++ b/js/src/jswrapper.h @@ -270,6 +270,8 @@ class JS_FRIEND_API(OpaqueCrossCompartmentWrapper) : public CrossCompartmentWrap virtual bool getBuiltinClass(JSContext* cx, HandleObject wrapper, ESClass* cls) const override; virtual bool isArray(JSContext* cx, HandleObject obj, JS::IsArrayAnswer* answer) const override; + virtual bool hasInstance(JSContext* cx, HandleObject wrapper, + MutableHandleValue v, bool* bp) const override; virtual const char* className(JSContext* cx, HandleObject wrapper) const override; virtual JSString* fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const override; diff --git a/js/src/proxy/OpaqueCrossCompartmentWrapper.cpp b/js/src/proxy/OpaqueCrossCompartmentWrapper.cpp index ff3f4145c..02bf237ff 100644 --- a/js/src/proxy/OpaqueCrossCompartmentWrapper.cpp +++ b/js/src/proxy/OpaqueCrossCompartmentWrapper.cpp @@ -175,6 +175,14 @@ OpaqueCrossCompartmentWrapper::isArray(JSContext* cx, HandleObject obj, return true; } +bool OpaqueCrossCompartmentWrapper::hasInstance(JSContext* cx, + HandleObject wrapper, + MutableHandleValue v, + bool* bp) const { + *bp = false; + return true; +} + const char* OpaqueCrossCompartmentWrapper::className(JSContext* cx, HandleObject proxy) const diff --git a/js/src/proxy/ScriptedProxyHandler.cpp b/js/src/proxy/ScriptedProxyHandler.cpp index 776547337..0e25f470c 100644 --- a/js/src/proxy/ScriptedProxyHandler.cpp +++ b/js/src/proxy/ScriptedProxyHandler.cpp @@ -8,8 +8,6 @@ #include "jsapi.h" -#include "vm/Interpreter.h" // For InstanceOfOperator - #include "jsobjinlines.h" #include "vm/NativeObject-inl.h" @@ -1230,7 +1228,7 @@ bool ScriptedProxyHandler::hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v, bool* bp) const { - return InstanceOfOperator(cx, proxy, v, bp); + return InstanceofOperator(cx, proxy, v, bp); } bool diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index b747e4d7a..e6d6630c4 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -718,14 +718,14 @@ js::Execute(JSContext* cx, HandleScript script, JSObject& envChainArg, Value* rv } /* - * ES6 (4-25-16) 12.10.4 InstanceofOperator + * ES6 12.9.4 InstanceofOperator */ extern bool -js::InstanceOfOperator(JSContext* cx, HandleObject obj, HandleValue v, bool* bp) +JS::InstanceofOperator(JSContext* cx, HandleObject obj, HandleValue v, bool* bp) { /* Step 1. is handled by caller. */ - /* Step 2. */ + /* Step 2-3. */ RootedValue hasInstance(cx); RootedId id(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().hasInstance)); if (!GetProperty(cx, obj, obj, id, &hasInstance)) @@ -735,7 +735,7 @@ js::InstanceOfOperator(JSContext* cx, HandleObject obj, HandleValue v, bool* bp) if (!IsCallable(hasInstance)) return ReportIsNotFunction(cx, hasInstance); - /* Step 3. */ + /* Step 4. */ RootedValue rval(cx); if (!Call(cx, hasInstance, obj, v, &rval)) return false; @@ -743,13 +743,13 @@ js::InstanceOfOperator(JSContext* cx, HandleObject obj, HandleValue v, bool* bp) return true; } - /* Step 4. */ + /* Step 5. */ if (!obj->isCallable()) { RootedValue val(cx, ObjectValue(*obj)); return ReportIsNotFunction(cx, val); } - /* Step 5. */ + /* Step 6. */ return OrdinaryHasInstance(cx, obj, v, bp); } @@ -760,7 +760,7 @@ js::HasInstance(JSContext* cx, HandleObject obj, HandleValue v, bool* bp) RootedValue local(cx, v); if (JSHasInstanceOp hasInstance = clasp->getHasInstance()) return hasInstance(cx, obj, &local, bp); - return js::InstanceOfOperator(cx, obj, local, bp); + return JS::InstanceofOperator(cx, obj, local, bp); } static inline bool diff --git a/js/src/vm/Interpreter.h b/js/src/vm/Interpreter.h index 330dbef5f..9fefd75cc 100644 --- a/js/src/vm/Interpreter.h +++ b/js/src/vm/Interpreter.h @@ -322,9 +322,6 @@ TypeOfObject(JSObject* obj); extern JSType TypeOfValue(const Value& v); -extern bool -InstanceOfOperator(JSContext* cx, HandleObject obj, HandleValue v, bool* bp); - extern bool HasInstance(JSContext* cx, HandleObject obj, HandleValue v, bool* bp); -- cgit v1.2.3 From f8db3a89b664ce5a53a4b663daf17c70bdaf398d Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 7 Feb 2019 12:31:57 +0100 Subject: Fix possible data race while updating scope object during compacting GC. --- js/src/jsgc.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'js/src') diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 3d4dae9bb..8cee9ec09 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -2310,22 +2310,27 @@ GCRuntime::updateCellPointers(MovingTracer* trc, Zone* zone, AllocKinds kinds, s // 2) typed object type descriptor objects // 3) all other objects // +// Also, there can be data races calling IsForwarded() on the new location of a +// cell that is being updated in parallel on another thread. This can be avoided +// by updating some kinds of cells in different phases. This is done for JSScripts +// and LazyScripts, and JSScripts and Scopes. +// // Since we want to minimize the number of phases, we put everything else into // the first phase and label it the 'misc' phase. static const AllocKinds UpdatePhaseMisc { AllocKind::SCRIPT, - AllocKind::LAZY_SCRIPT, AllocKind::BASE_SHAPE, AllocKind::SHAPE, AllocKind::ACCESSOR_SHAPE, AllocKind::OBJECT_GROUP, AllocKind::STRING, - AllocKind::JITCODE, - AllocKind::SCOPE + AllocKind::JITCODE }; static const AllocKinds UpdatePhaseObjects { + AllocKind::LAZY_SCRIPT, + AllocKind::SCOPE, AllocKind::FUNCTION, AllocKind::FUNCTION_EXTENDED, AllocKind::OBJECT0, -- cgit v1.2.3 From 71d32272eb2e800ea6cda5480fd67ef793712735 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 14 Feb 2019 12:00:47 +0100 Subject: Use C++11 thread-safe statics with MSVC. (js) --- js/src/old-configure.in | 4 ---- 1 file changed, 4 deletions(-) (limited to 'js/src') diff --git a/js/src/old-configure.in b/js/src/old-configure.in index 8abea5956..45108ee59 100644 --- a/js/src/old-configure.in +++ b/js/src/old-configure.in @@ -206,10 +206,6 @@ case "$target" in # -Zc:sizedDealloc- disables C++14 global sized deallocation (see bug 1160146) CXXFLAGS="$CXXFLAGS -Zc:sizedDealloc-" - - # Disable C++11 thread-safe statics due to crashes on XP (bug 1204752) - # See https://connect.microsoft.com/VisualStudio/feedback/details/1789709/visual-c-2015-runtime-broken-on-windows-server-2003-c-11-magic-statics - CXXFLAGS="$CXXFLAGS -Zc:threadSafeInit-" ;; esac AC_SUBST(MSVS_VERSION) -- cgit v1.2.3 From 90d1ee25b1de235847605fbc95a9ddebcf5c061d Mon Sep 17 00:00:00 2001 From: adeshkp Date: Thu, 14 Mar 2019 09:53:02 -0400 Subject: Remove a couple of unused variables --- js/src/jit/StupidAllocator.cpp | 1 - js/src/vm/ObjectGroup.cpp | 1 - 2 files changed, 2 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/StupidAllocator.cpp b/js/src/jit/StupidAllocator.cpp index 8e3ea6286..55431e8e0 100644 --- a/js/src/jit/StupidAllocator.cpp +++ b/js/src/jit/StupidAllocator.cpp @@ -407,7 +407,6 @@ StupidAllocator::allocateForDefinition(LInstruction* ins, LDefinition* def) { uint32_t vreg = def->virtualRegister(); - CodePosition from; if ((def->output()->isRegister() && def->policy() == LDefinition::FIXED) || def->policy() == LDefinition::MUST_REUSE_INPUT) { diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp index 1fbf8976b..46159a972 100644 --- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -495,7 +495,6 @@ ObjectGroup::defaultNewGroup(ExclusiveContext* cx, const Class* clasp, if (associated->is()) { // Canonicalize new functions to use the original one associated with its script. - JSFunction* fun = &associated->as(); associated = associated->as().maybeCanonicalFunction(); // If we have previously cleared the 'new' script information for this -- cgit v1.2.3 From 890bb438b000821586c076ed8f880e95ea03f075 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 21 Mar 2019 09:53:24 +0100 Subject: Pref the use of unboxed plain objects in JS and disable by default. This should be all that's needed for #1017, but verification of impact is definitely desired. --- js/src/jit/JitOptions.cpp | 2 +- js/src/jsapi.cpp | 3 +++ js/src/jsapi.h | 25 +++++++++++++------------ 3 files changed, 17 insertions(+), 13 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/JitOptions.cpp b/js/src/jit/JitOptions.cpp index eb5a6c1c2..b9a7c7b27 100644 --- a/js/src/jit/JitOptions.cpp +++ b/js/src/jit/JitOptions.cpp @@ -222,7 +222,7 @@ DefaultJitOptions::DefaultJitOptions() } // Toggles whether unboxed plain objects can be created by the VM. - SET_DEFAULT(disableUnboxedObjects, false); + SET_DEFAULT(disableUnboxedObjects, true); // Test whether Atomics are allowed in asm.js code. SET_DEFAULT(asmJSAtomicsEnable, false); diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 37d023bd4..6114b8157 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -6410,6 +6410,9 @@ JS_SetGlobalJitCompilerOption(JSContext* cx, JSJitCompilerOption opt, uint32_t v } jit::JitOptions.jumpThreshold = value; break; + case JSJITCOMPILER_UNBOXED_OBJECTS: + jit::JitOptions.disableUnboxedObjects = !value; + break; case JSJITCOMPILER_ASMJS_ATOMICS_ENABLE: jit::JitOptions.asmJSAtomicsEnable = !!value; break; diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 005d2278e..1f726f2e5 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -5783,19 +5783,20 @@ JS_SetParallelParsingEnabled(JSContext* cx, bool enabled); extern JS_PUBLIC_API(void) JS_SetOffthreadIonCompilationEnabled(JSContext* cx, bool enabled); -#define JIT_COMPILER_OPTIONS(Register) \ - Register(BASELINE_WARMUP_TRIGGER, "baseline.warmup.trigger") \ - Register(ION_WARMUP_TRIGGER, "ion.warmup.trigger") \ - Register(ION_GVN_ENABLE, "ion.gvn.enable") \ - Register(ION_FORCE_IC, "ion.forceinlineCaches") \ - Register(ION_ENABLE, "ion.enable") \ +#define JIT_COMPILER_OPTIONS(Register) \ + Register(BASELINE_WARMUP_TRIGGER, "baseline.warmup.trigger") \ + Register(ION_WARMUP_TRIGGER, "ion.warmup.trigger") \ + Register(ION_GVN_ENABLE, "ion.gvn.enable") \ + Register(ION_FORCE_IC, "ion.forceinlineCaches") \ + Register(ION_ENABLE, "ion.enable") \ Register(ION_INTERRUPT_WITHOUT_SIGNAL, "ion.interrupt-without-signals") \ - Register(ION_CHECK_RANGE_ANALYSIS, "ion.check-range-analysis") \ - Register(BASELINE_ENABLE, "baseline.enable") \ - Register(OFFTHREAD_COMPILATION_ENABLE, "offthread-compilation.enable") \ - Register(JUMP_THRESHOLD, "jump-threshold") \ - Register(ASMJS_ATOMICS_ENABLE, "asmjs.atomics.enable") \ - Register(WASM_TEST_MODE, "wasm.test-mode") \ + Register(ION_CHECK_RANGE_ANALYSIS, "ion.check-range-analysis") \ + Register(BASELINE_ENABLE, "baseline.enable") \ + Register(OFFTHREAD_COMPILATION_ENABLE, "offthread-compilation.enable") \ + Register(JUMP_THRESHOLD, "jump-threshold") \ + Register(UNBOXED_OBJECTS, "unboxed_objects") \ + Register(ASMJS_ATOMICS_ENABLE, "asmjs.atomics.enable") \ + Register(WASM_TEST_MODE, "wasm.test-mode") \ Register(WASM_FOLD_OFFSETS, "wasm.fold-offsets") typedef enum JSJitCompilerOption { -- cgit v1.2.3 From a7013083d3620b683457d96c302c50a56f30e070 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 22 Mar 2019 12:06:40 +0100 Subject: Check for dead wrappers in CallerGetterImpl/CallerSetterImpl. This also removes code duplication by making CallerSetterImpl call CallerGetterImpl. --- js/src/jsfun.cpp | 58 ++++++++++++-------------------------------------------- 1 file changed, 12 insertions(+), 46 deletions(-) (limited to 'js/src') diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 863871df9..98311be2f 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -288,6 +288,12 @@ CallerGetterImpl(JSContext* cx, const CallArgs& args) return true; } + if (JS_IsDeadWrapper(callerObj)) { + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, + JSMSG_DEAD_OBJECT); + return false; + } + JSFunction* callerFun = &callerObj->as(); MOZ_ASSERT(!callerFun->isBuiltin(), "non-builtin iterator returned a builtin?"); @@ -314,54 +320,14 @@ CallerSetterImpl(JSContext* cx, const CallArgs& args) { MOZ_ASSERT(IsFunction(args.thisv())); - // Beware! This function can be invoked on *any* function! It can't - // assume it'll never be invoked on natives, strict mode functions, bound - // functions, or anything else that ordinarily has immutable .caller - // defined with [[ThrowTypeError]]. - RootedFunction fun(cx, &args.thisv().toObject().as()); - if (!CallerRestrictions(cx, fun)) - return false; - - // Return |undefined| unless an error must be thrown. - args.rval().setUndefined(); - - // We can almost just return |undefined| here -- but if the caller function - // was strict mode code, we still have to throw a TypeError. This requires - // computing the caller, checking that no security boundaries are crossed, - // and throwing a TypeError if the resulting caller is strict. - - NonBuiltinScriptFrameIter iter(cx); - if (!AdvanceToActiveCallLinear(cx, iter, fun)) - return true; - - ++iter; - while (!iter.done() && iter.isEvalFrame()) - ++iter; - - if (iter.done() || !iter.isFunctionFrame()) - return true; - - RootedObject caller(cx, iter.callee(cx)); - if (!cx->compartment()->wrap(cx, &caller)) { - cx->clearPendingException(); - return true; - } - - // If we don't have full access to the caller, or the caller is not strict, - // return undefined. Otherwise throw a TypeError. - JSObject* callerObj = CheckedUnwrap(caller); - if (!callerObj) - return true; - - JSFunction* callerFun = &callerObj->as(); - MOZ_ASSERT(!callerFun->isBuiltin(), "non-builtin iterator returned a builtin?"); - - if (callerFun->strict()) { - JS_ReportErrorFlagsAndNumberASCII(cx, JSREPORT_ERROR, GetErrorMessage, nullptr, - JSMSG_CALLER_IS_STRICT); - return false; + // We just have to return |undefined|, but first we call CallerGetterImpl + // because we need the same strict-mode and security checks. + + if (!CallerGetterImpl(cx, args)) { + return false; } + args.rval().setUndefined(); return true; } -- cgit v1.2.3 From c53602c802cfaeaede20cb0bb2180194389eeb05 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Fri, 22 Mar 2019 13:17:31 +0100 Subject: Reset nursery position when it's disabled. --- js/src/gc/Nursery.cpp | 1 + js/src/gc/Nursery.h | 1 + 2 files changed, 2 insertions(+) (limited to 'js/src') diff --git a/js/src/gc/Nursery.cpp b/js/src/gc/Nursery.cpp index ea4350fb8..93a0eb6a8 100644 --- a/js/src/gc/Nursery.cpp +++ b/js/src/gc/Nursery.cpp @@ -210,6 +210,7 @@ js::Nursery::disable() return; updateNumChunks(0); currentEnd_ = 0; + position_ = 0; runtime()->gc.storeBuffer.disable(); } diff --git a/js/src/gc/Nursery.h b/js/src/gc/Nursery.h index 0d215d997..a839a4979 100644 --- a/js/src/gc/Nursery.h +++ b/js/src/gc/Nursery.h @@ -245,6 +245,7 @@ class Nursery // Free space remaining, not counting chunk trailers. MOZ_ALWAYS_INLINE size_t freeSpace() const { + MOZ_ASSERT(isEnabled()); MOZ_ASSERT(currentEnd_ - position_ <= NurseryChunkUsableSize); return (currentEnd_ - position_) + (numChunks() - currentChunk_ - 1) * NurseryChunkUsableSize; -- cgit v1.2.3 From 054794f8c5c93f502318a99517cfacfd757510d6 Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Sat, 23 Mar 2019 09:36:15 +0100 Subject: Restrict ExtractLinearSum to monotonous operation in infinite math space. Thanks to Bruno Keith & Niklas Baumstark from the phoenhex team for finding this issue and reporting it with a proper analysis. --- js/src/jit/IonAnalysis.cpp | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index b163d5818..d255c32a8 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -3127,6 +3127,15 @@ ExtractMathSpace(MDefinition* ins) MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unknown TruncateKind"); } +static bool MonotoneAdd(int32_t lhs, int32_t rhs) { + return (lhs >= 0 && rhs >= 0) || (lhs <= 0 && rhs <= 0); +} + +static bool MonotoneSub(int32_t lhs, int32_t rhs) { + return (lhs >= 0 && rhs <= 0) || (lhs <= 0 && rhs >= 0); +} + + // Extract a linear sum from ins, if possible (otherwise giving the sum 'ins + 0'). SimpleLinearSum jit::ExtractLinearSum(MDefinition* ins, MathSpace space) @@ -3168,10 +3177,12 @@ jit::ExtractLinearSum(MDefinition* ins, MathSpace space) // Check if this is of the form + n or n + . if (ins->isAdd()) { int32_t constant; - if (space == MathSpace::Modulo) + if (space == MathSpace::Modulo) { constant = lsum.constant + rsum.constant; - else if (!SafeAdd(lsum.constant, rsum.constant, &constant)) + } else if (!SafeAdd(lsum.constant, rsum.constant, &constant) || + !MonotoneAdd(lsum.constant, rsum.constant)) { return SimpleLinearSum(ins, 0); + } return SimpleLinearSum(lsum.term ? lsum.term : rsum.term, constant); } @@ -3179,10 +3190,12 @@ jit::ExtractLinearSum(MDefinition* ins, MathSpace space) // Check if this is of the form - n. if (lsum.term) { int32_t constant; - if (space == MathSpace::Modulo) + if (space == MathSpace::Modulo) { constant = lsum.constant - rsum.constant; - else if (!SafeSub(lsum.constant, rsum.constant, &constant)) + } else if (!SafeSub(lsum.constant, rsum.constant, &constant) || + !MonotoneSub(lsum.constant, rsum.constant)) { return SimpleLinearSum(ins, 0); + } return SimpleLinearSum(lsum.term, constant); } -- cgit v1.2.3 From 0b999100f6c0b7b90d1167237621826e0e6a808a Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Tue, 26 Mar 2019 18:30:57 +0100 Subject: Simplify some alias sets in IonMonkey. --- js/src/jit/AliasAnalysisShared.cpp | 3 ++- js/src/jit/MIR.h | 7 ++----- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/AliasAnalysisShared.cpp b/js/src/jit/AliasAnalysisShared.cpp index ae28327ca..81c0fd067 100644 --- a/js/src/jit/AliasAnalysisShared.cpp +++ b/js/src/jit/AliasAnalysisShared.cpp @@ -102,7 +102,6 @@ GetObject(const MDefinition* ins) case MDefinition::Op_SetDisjointTypedElements: case MDefinition::Op_ArrayPopShift: case MDefinition::Op_ArrayPush: - case MDefinition::Op_ArraySlice: case MDefinition::Op_LoadTypedArrayElementHole: case MDefinition::Op_StoreTypedArrayElementHole: case MDefinition::Op_LoadFixedSlot: @@ -126,6 +125,7 @@ GetObject(const MDefinition* ins) object = ins->getOperand(0); break; case MDefinition::Op_GetPropertyCache: + case MDefinition::Op_CallGetProperty: case MDefinition::Op_LoadTypedArrayElementStatic: case MDefinition::Op_StoreTypedArrayElementStatic: case MDefinition::Op_GetDOMProperty: @@ -148,6 +148,7 @@ GetObject(const MDefinition* ins) case MDefinition::Op_WasmLoadGlobalVar: case MDefinition::Op_WasmStoreGlobalVar: case MDefinition::Op_ArrayJoin: + case MDefinition::Op_ArraySlice: return nullptr; default: #ifdef DEBUG diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index b2e84322f..fb0f22fc3 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -9910,10 +9910,6 @@ class MArraySlice return unboxedType_; } - AliasSet getAliasSet() const override { - return AliasSet::Store(AliasSet::BoxedOrUnboxedElements(unboxedType()) | - AliasSet::ObjectFields); - } bool possiblyCalls() const override { return true; } @@ -11837,7 +11833,8 @@ class MCallGetProperty AliasSet getAliasSet() const override { if (!idempotent_) return AliasSet::Store(AliasSet::Any); - return AliasSet::None(); + return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot | + AliasSet::DynamicSlot); } bool possiblyCalls() const override { return true; -- cgit v1.2.3 From 25779d371c571e4f51792af3e3c5588b3186e934 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 30 Mar 2019 19:10:17 +0100 Subject: Issue #187: Remove solaris conditional code. --- js/src/builtin/TestingFunctions.cpp | 4 -- js/src/ctypes/CTypes.cpp | 4 -- js/src/gc/Memory.cpp | 85 ---------------------------------- js/src/jsapi-tests/testGCAllocator.cpp | 12 +---- js/src/jsnativestack.cpp | 14 ------ js/src/vm/Time.cpp | 11 ----- js/src/wasm/WasmSignalHandlers.cpp | 2 +- 7 files changed, 2 insertions(+), 130 deletions(-) (limited to 'js/src') diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 373b6c9ed..c896ce5d1 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -240,11 +240,7 @@ GetBuildConfiguration(JSContext* cx, unsigned argc, Value* vp) if (!JS_SetProperty(cx, info, "intl-api", value)) return false; -#if defined(SOLARIS) - value = BooleanValue(false); -#else value = BooleanValue(true); -#endif if (!JS_SetProperty(cx, info, "mapped-array-buffer", value)) return false; diff --git a/js/src/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp index 0facd0009..d6adfac2c 100644 --- a/js/src/ctypes/CTypes.cpp +++ b/js/src/ctypes/CTypes.cpp @@ -20,10 +20,6 @@ #include #endif -#if defined(SOLARIS) -#include -#endif - #ifdef HAVE_SSIZE_T #include #endif diff --git a/js/src/gc/Memory.cpp b/js/src/gc/Memory.cpp index 26da75469..268e1e489 100644 --- a/js/src/gc/Memory.cpp +++ b/js/src/gc/Memory.cpp @@ -17,11 +17,6 @@ #include "jswin.h" #include -#elif defined(SOLARIS) - -#include -#include - #elif defined(XP_UNIX) #include @@ -408,86 +403,6 @@ DeallocateMappedContent(void* p, size_t length) # endif -#elif defined(SOLARIS) - -#ifndef MAP_NOSYNC -# define MAP_NOSYNC 0 -#endif - -void -InitMemorySubsystem() -{ - if (pageSize == 0) - pageSize = allocGranularity = size_t(sysconf(_SC_PAGESIZE)); -} - -void* -MapAlignedPages(size_t size, size_t alignment) -{ - MOZ_ASSERT(size >= alignment); - MOZ_ASSERT(size >= allocGranularity); - MOZ_ASSERT(size % alignment == 0); - MOZ_ASSERT(size % pageSize == 0); - MOZ_ASSERT_IF(alignment < allocGranularity, allocGranularity % alignment == 0); - MOZ_ASSERT_IF(alignment > allocGranularity, alignment % allocGranularity == 0); - - int prot = PROT_READ | PROT_WRITE; - int flags = MAP_PRIVATE | MAP_ANON | MAP_ALIGN | MAP_NOSYNC; - - void* p = mmap((caddr_t)alignment, size, prot, flags, -1, 0); - if (p == MAP_FAILED) - return nullptr; - return p; -} - -static void* -MapAlignedPagesLastDitch(size_t size, size_t alignment) -{ - return nullptr; -} - -void -UnmapPages(void* p, size_t size) -{ - MOZ_ALWAYS_TRUE(0 == munmap((caddr_t)p, size)); -} - -bool -MarkPagesUnused(void* p, size_t size) -{ - MOZ_ASSERT(OffsetFromAligned(p, pageSize) == 0); - return true; -} - -bool -MarkPagesInUse(void* p, size_t size) -{ - if (!DecommitEnabled()) - return; - - MOZ_ASSERT(OffsetFromAligned(p, pageSize) == 0); -} - -size_t -GetPageFaultCount() -{ - return 0; -} - -void* -AllocateMappedContent(int fd, size_t offset, size_t length, size_t alignment) -{ - // Not implemented. - return nullptr; -} - -// Deallocate mapped memory for object. -void -DeallocateMappedContent(void* p, size_t length) -{ - // Not implemented. -} - #elif defined(XP_UNIX) void diff --git a/js/src/jsapi-tests/testGCAllocator.cpp b/js/src/jsapi-tests/testGCAllocator.cpp index 2c5c58a29..d203019ec 100644 --- a/js/src/jsapi-tests/testGCAllocator.cpp +++ b/js/src/jsapi-tests/testGCAllocator.cpp @@ -14,8 +14,6 @@ #if defined(XP_WIN) #include "jswin.h" #include -#elif defined(SOLARIS) -// This test doesn't apply to Solaris. #elif defined(XP_UNIX) #include #include @@ -39,8 +37,6 @@ BEGIN_TEST(testGCAllocator) # else // Various APIs are unavailable. This test is disabled. return true; # endif -#elif defined(SOLARIS) - return true; #elif defined(XP_UNIX) PageSize = size_t(sysconf(_SC_PAGESIZE)); #else @@ -301,12 +297,6 @@ void* mapMemory(size_t length) { return nullptr; } void unmapPages(void* p, size_t size) { } # endif -#elif defined(SOLARIS) // This test doesn't apply to Solaris. - -void* mapMemoryAt(void* desired, size_t length) { return nullptr; } -void* mapMemory(size_t length) { return nullptr; } -void unmapPages(void* p, size_t size) { } - #elif defined(XP_UNIX) void* @@ -377,7 +367,7 @@ unmapPages(void* p, size_t size) MOZ_RELEASE_ASSERT(errno == ENOMEM); } -#else // !defined(XP_WIN) && !defined(SOLARIS) && !defined(XP_UNIX) +#else // !defined(XP_WIN) && !defined(XP_UNIX) #error "Memory mapping functions are not defined for your OS." #endif END_TEST(testGCAllocator) diff --git a/js/src/jsnativestack.cpp b/js/src/jsnativestack.cpp index 166a5a4f7..95e0f8da7 100644 --- a/js/src/jsnativestack.cpp +++ b/js/src/jsnativestack.cpp @@ -71,20 +71,6 @@ js::GetNativeStackBaseImpl() # endif } -#elif defined(SOLARIS) - -#include - -JS_STATIC_ASSERT(JS_STACK_GROWTH_DIRECTION < 0); - -void* -js::GetNativeStackBaseImpl() -{ - stack_t st; - stack_getbounds(&st); - return static_cast(st.ss_sp) + st.ss_size; -} - #elif defined(AIX) #include diff --git a/js/src/vm/Time.cpp b/js/src/vm/Time.cpp index 69e2cc41d..87531c148 100644 --- a/js/src/vm/Time.cpp +++ b/js/src/vm/Time.cpp @@ -11,9 +11,6 @@ #include "mozilla/DebugOnly.h" #include "mozilla/MathAlgorithms.h" -#ifdef SOLARIS -#define _REENTRANT 1 -#endif #include #include @@ -33,10 +30,6 @@ #ifdef XP_UNIX -#ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris */ -extern int gettimeofday(struct timeval* tv); -#endif - #include #endif /* XP_UNIX */ @@ -49,11 +42,7 @@ PRMJ_Now() { struct timeval tv; -#ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris */ - gettimeofday(&tv); -#else gettimeofday(&tv, 0); -#endif /* _SVID_GETTOD */ return int64_t(tv.tv_sec) * PRMJ_USEC_PER_SEC + int64_t(tv.tv_usec); } diff --git a/js/src/wasm/WasmSignalHandlers.cpp b/js/src/wasm/WasmSignalHandlers.cpp index 78d21369d..c4733cc96 100644 --- a/js/src/wasm/WasmSignalHandlers.cpp +++ b/js/src/wasm/WasmSignalHandlers.cpp @@ -130,7 +130,7 @@ class AutoSetHandlingSegFault # define EPC_sig(p) ((p)->sc_pc) # define RFP_sig(p) ((p)->sc_regs[30]) # endif -#elif defined(__linux__) || defined(SOLARIS) +#elif defined(__linux__) # if defined(__linux__) # define XMM_sig(p,i) ((p)->uc_mcontext.fpregs->_xmm[i]) # define EIP_sig(p) ((p)->uc_mcontext.gregs[REG_EIP]) -- cgit v1.2.3 From 6b968b13d9cab02d8634facc87ae39e51dee4020 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 30 Mar 2019 20:03:33 +0100 Subject: Issue #187: Remove solaris 1st party code OS checks. --- js/src/Makefile.in | 10 ---------- js/src/ctypes/libffi/testsuite/libffi.call/float2.c | 10 ---------- js/src/moz.build | 8 -------- 3 files changed, 28 deletions(-) (limited to 'js/src') diff --git a/js/src/Makefile.in b/js/src/Makefile.in index b007954b1..7f49a3718 100644 --- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -146,16 +146,6 @@ ifeq ($(OS_ARCH),AIX) # 1540-1608: anonymous unions using static data members CFLAGS += -qsuppress=1540-1281 -qsuppress=1540-1608 CXXFLAGS += -qsuppress=1540-1281 -qsuppress=1540-1608 -endif -endif -ifeq ($(OS_ARCH),SunOS) -ifeq ($(TARGET_CPU),sparc) - -ifdef GNU_CC -CFLAGS += -mcpu=v9 -CXXFLAGS += -mcpu=v9 -endif # GNU_CC - endif endif diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/float2.c b/js/src/ctypes/libffi/testsuite/libffi.call/float2.c index a0b296cf4..dfdef0598 100644 --- a/js/src/ctypes/libffi/testsuite/libffi.call/float2.c +++ b/js/src/ctypes/libffi/testsuite/libffi.call/float2.c @@ -32,21 +32,11 @@ int main (void) f = 3.14159; -#if 1 - /* This is ifdef'd out for now. long double support under SunOS/gcc - is pretty much non-existent. You'll get the odd bus error in library - routines like printf(). */ printf ("%Lf\n", ldblit(f)); -#endif ld = 666; ffi_call(&cif, FFI_FN(ldblit), &ld, values); -#if 1 - /* This is ifdef'd out for now. long double support under SunOS/gcc - is pretty much non-existent. You'll get the odd bus error in library - routines like printf(). */ printf ("%Lf, %Lf, %Lf, %Lf\n", ld, ldblit(f), ld - ldblit(f), LDBL_EPSILON); -#endif /* These are not always the same!! Check for a reasonable delta */ if (ld - ldblit(f) < LDBL_EPSILON) diff --git a/js/src/moz.build b/js/src/moz.build index a3283b5d6..888741138 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -722,14 +722,6 @@ if CONFIG['OS_ARCH'] == 'Linux': 'dl', ] -if CONFIG['OS_ARCH'] == 'SunOS': - OS_LIBS += [ - 'posix4', - 'dl', - 'nsl', - 'socket', - ] - OS_LIBS += CONFIG['REALTIME_LIBS'] CFLAGS += CONFIG['MOZ_ICU_CFLAGS'] -- cgit v1.2.3 From 5d409fdca92e085dad2f9c80b42f33afe4f10800 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sun, 31 Mar 2019 18:43:10 +0200 Subject: Remove AIX 1st party code OS checks, part 1 Issue #186 --- js/src/Makefile.in | 11 ----------- js/src/jsnativestack.cpp | 15 --------------- 2 files changed, 26 deletions(-) (limited to 'js/src') diff --git a/js/src/Makefile.in b/js/src/Makefile.in index 7f49a3718..20678c68c 100644 --- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -138,17 +138,6 @@ distclean:: CFLAGS += $(MOZ_ZLIB_CFLAGS) -# Silence warnings on AIX/HP-UX from non-GNU compilers -ifndef GNU_CC -ifeq ($(OS_ARCH),AIX) -# Suppress warnings from xlC -# 1540-1281: offsetof() on null non-POD types -# 1540-1608: anonymous unions using static data members -CFLAGS += -qsuppress=1540-1281 -qsuppress=1540-1608 -CXXFLAGS += -qsuppress=1540-1281 -qsuppress=1540-1608 -endif -endif - $(LIBRARY_NAME).pc: js.pc cp $^ $@ diff --git a/js/src/jsnativestack.cpp b/js/src/jsnativestack.cpp index 95e0f8da7..98f8fc741 100644 --- a/js/src/jsnativestack.cpp +++ b/js/src/jsnativestack.cpp @@ -71,21 +71,6 @@ js::GetNativeStackBaseImpl() # endif } -#elif defined(AIX) - -#include - -JS_STATIC_ASSERT(JS_STACK_GROWTH_DIRECTION < 0); - -void* -js::GetNativeStackBaseImpl() -{ - ucontext_t context; - getcontext(&context); - return static_cast(context.uc_stack.ss_sp) + - context.uc_stack.ss_size; -} - #elif defined(XP_LINUX) && !defined(ANDROID) && defined(__GLIBC__) void* js::GetNativeStackBaseImpl() -- cgit v1.2.3 From a2786c051173286c9d7ccee2c3c6a19c15966322 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Mon, 1 Apr 2019 00:11:06 +0200 Subject: Remove AIX 1st party code OS checks, part 2 Issue #186 --- js/src/jstypes.h | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'js/src') diff --git a/js/src/jstypes.h b/js/src/jstypes.h index 75774e5b8..6cfb3d4ad 100644 --- a/js/src/jstypes.h +++ b/js/src/jstypes.h @@ -147,13 +147,7 @@ # define JS_64BIT # endif #elif defined(__GNUC__) -/* Additional GCC defines are when running on Solaris, AIX, and HPUX */ -# if defined(__x86_64__) || defined(__sparcv9) || \ - defined(__64BIT__) || defined(__LP64__) -# define JS_64BIT -# endif -#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) /* Sun Studio C/C++ */ -# if defined(__x86_64) || defined(__sparcv9) +# if defined(__x86_64__) || defined(__64BIT__) # define JS_64BIT # endif #elif defined(__xlc__) || defined(__xlC__) /* IBM XL C/C++ */ -- cgit v1.2.3 From 8bbd0d556c0bf583b16076844b9e263a5f996495 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 5 Apr 2019 20:54:29 +0200 Subject: Split Parser::report into Parser::zeport (a temporary name) that uses the current offset, and Parser::reportWithNode that derives it from a Node. --- js/src/frontend/BytecodeEmitter.cpp | 6 +- js/src/frontend/Parser.cpp | 387 +++++++++++++++++------------------- js/src/frontend/Parser.h | 13 +- js/src/frontend/TokenStream.h | 1 + 4 files changed, 198 insertions(+), 209 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index c5e62ae34..71289e84a 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -3559,9 +3559,11 @@ BytecodeEmitter::maybeSetSourceMap() if (parser->options().sourceMapURL()) { // Warn about the replacement, but use the new one. if (parser->ss->hasSourceMapURL()) { - if(!parser->report(ParseWarning, false, nullptr, JSMSG_ALREADY_HAS_PRAGMA, - parser->ss->filename(), "//# sourceMappingURL")) + if (!parser->reportNoOffset(ParseWarning, false, JSMSG_ALREADY_HAS_PRAGMA, + parser->ss->filename(), "//# sourceMappingURL")) + { return false; + } } if (!parser->ss->setSourceMapURL(cx, parser->options().sourceMapURL())) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 1ba725a82..26b3c2c25 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -69,7 +69,7 @@ using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr; if (!tokenStream.getToken(&token, modifier)) \ return null(); \ if (token != tt) { \ - report(ParseError, false, null(), errno); \ + zeport(ParseError, false, errno); \ return null(); \ } \ JS_END_MACRO @@ -596,7 +596,18 @@ Parser::reportHelper(ParseReportKind kind, bool strict, uint32_t o template bool -Parser::report(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...) +Parser::zeport(ParseReportKind kind, bool strict, unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); + bool result = reportHelper(kind, strict, pos().begin, errorNumber, args); + va_end(args); + return result; +} + +template +bool +Parser::reportWithNode(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...) { uint32_t offset = (pn ? handler.getPosition(pn) : pos()).begin; @@ -826,8 +837,7 @@ Parser::parse() if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); if (tt != TOK_EOF) { - report(ParseError, false, null(), JSMSG_GARBAGE_AFTER_INPUT, - "script", TokenKindToDesc(tt)); + zeport(ParseError, false, JSMSG_GARBAGE_AFTER_INPUT, "script", TokenKindToDesc(tt)); return null(); } if (foldConstants) { @@ -850,7 +860,7 @@ Parser::reportBadReturn(Node pn, ParseReportKind kind, } else { errnum = anonerrnum; } - return report(kind, pc->sc()->strict(), pn, errnum, name.ptr()); + return reportWithNode(kind, pc->sc()->strict(), pn, errnum, name.ptr()); } /* @@ -941,7 +951,7 @@ Parser::notePositionalFormalParameter(Node fn, HandlePropertyName { if (AddDeclaredNamePtr p = pc->functionScope().lookupDeclaredNameForAdd(name)) { if (disallowDuplicateParams) { - report(ParseError, false, null(), JSMSG_BAD_DUP_ARGS); + zeport(ParseError, false, JSMSG_BAD_DUP_ARGS); return false; } @@ -953,11 +963,8 @@ Parser::notePositionalFormalParameter(Node fn, HandlePropertyName JSAutoByteString bytes; if (!AtomToPrintableString(context, name, &bytes)) return false; - if (!report(ParseStrictError, pc->sc()->strict(), null(), - JSMSG_DUPLICATE_FORMAL, bytes.ptr())) - { + if (!zeport(ParseStrictError, pc->sc()->strict(), JSMSG_DUPLICATE_FORMAL, bytes.ptr())) return false; - } } *duplicatedParam = true; @@ -1239,7 +1246,7 @@ Parser::noteDeclaredName(HandlePropertyName name, DeclarationKind AddDeclaredNamePtr p = pc->functionScope().lookupDeclaredNameForAdd(name); if (p) { - report(ParseError, false, null(), JSMSG_BAD_DUP_ARGS); + zeport(ParseError, false, JSMSG_BAD_DUP_ARGS); return false; } @@ -1446,8 +1453,7 @@ Parser::checkStatementsEOF() if (!tokenStream.peekToken(&tt, TokenStream::Operand)) return false; if (tt != TOK_EOF) { - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, - "expression", TokenKindToDesc(tt)); + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); return false; } return true; @@ -1912,7 +1918,7 @@ Parser::evalBody(EvalSharedContext* evalsc) // script. if (hasUsedName(context->names().arguments)) { if (IsArgumentsUsedInLegacyGenerator(context, pc->sc()->compilationEnclosingScope())) { - report(ParseError, false, nullptr, JSMSG_BAD_GENEXP_BODY, js_arguments_str); + zeport(ParseError, false, JSMSG_BAD_GENEXP_BODY, js_arguments_str); return nullptr; } } @@ -2010,7 +2016,7 @@ Parser::moduleBody(ModuleSharedContext* modulesc) if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); if (tt != TOK_EOF) { - report(ParseError, false, null(), JSMSG_GARBAGE_AFTER_INPUT, "module", TokenKindToDesc(tt)); + zeport(ParseError, false, JSMSG_GARBAGE_AFTER_INPUT, "module", TokenKindToDesc(tt)); return null(); } @@ -2330,8 +2336,7 @@ Parser::standaloneFunction(HandleFunction fun, if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); if (tt != TOK_EOF) { - report(ParseError, false, null(), JSMSG_GARBAGE_AFTER_INPUT, - "function body", TokenKindToDesc(tt)); + zeport(ParseError, false, JSMSG_GARBAGE_AFTER_INPUT, "function body", TokenKindToDesc(tt)); return null(); } @@ -2736,7 +2741,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn if (!tokenStream.getToken(&tt, firstTokenModifier)) return false; if (tt != TOK_LP) { - report(ParseError, false, null(), + zeport(ParseError, false, kind == Arrow ? JSMSG_BAD_ARROW_ARGS : JSMSG_PAREN_BEFORE_FORMAL); return false; } @@ -2769,13 +2774,13 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn AtomVector& positionalFormals = pc->positionalFormalParameterNames(); if (IsGetterKind(kind)) { - report(ParseError, false, null(), JSMSG_ACCESSOR_WRONG_ARGS, "getter", "no", "s"); + zeport(ParseError, false, JSMSG_ACCESSOR_WRONG_ARGS, "getter", "no", "s"); return false; } while (true) { if (hasRest) { - report(ParseError, false, null(), JSMSG_PARAMETER_AFTER_REST); + zeport(ParseError, false, JSMSG_PARAMETER_AFTER_REST); return false; } @@ -2787,15 +2792,14 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn if (tt == TOK_TRIPLEDOT) { if (IsSetterKind(kind)) { - report(ParseError, false, null(), - JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); + zeport(ParseError, false, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); return false; } disallowDuplicateParams = true; if (duplicatedParam) { // Has duplicated args before the rest parameter. - report(ParseError, false, null(), JSMSG_BAD_DUP_ARGS); + zeport(ParseError, false, JSMSG_BAD_DUP_ARGS); return false; } @@ -2806,7 +2810,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn return false; if (tt != TOK_NAME && tt != TOK_YIELD && tt != TOK_LB && tt != TOK_LC) { - report(ParseError, false, null(), JSMSG_NO_REST_NAME); + zeport(ParseError, false, JSMSG_NO_REST_NAME); return false; } } @@ -2817,7 +2821,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn disallowDuplicateParams = true; if (duplicatedParam) { // Has duplicated args before the destructuring parameter. - report(ParseError, false, null(), JSMSG_BAD_DUP_ARGS); + zeport(ParseError, false, JSMSG_BAD_DUP_ARGS); return false; } @@ -2845,7 +2849,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn // case: // // async await => 1 - report(ParseError, false, null(), JSMSG_RESERVED_ID, "await"); + zeport(ParseError, false, JSMSG_RESERVED_ID, "await"); return false; } @@ -2865,12 +2869,12 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn } default: - report(ParseError, false, null(), JSMSG_MISSING_FORMAL); + zeport(ParseError, false, JSMSG_MISSING_FORMAL); return false; } if (positionalFormals.length() >= ARGNO_LIMIT) { - report(ParseError, false, null(), JSMSG_TOO_MANY_FUN_ARGS); + zeport(ParseError, false, JSMSG_TOO_MANY_FUN_ARGS); return false; } @@ -2885,12 +2889,12 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn MOZ_ASSERT(!parenFreeArrow); if (hasRest) { - report(ParseError, false, null(), JSMSG_REST_WITH_DEFAULT); + zeport(ParseError, false, JSMSG_REST_WITH_DEFAULT); return false; } disallowDuplicateParams = true; if (duplicatedParam) { - report(ParseError, false, null(), JSMSG_BAD_DUP_ARGS); + zeport(ParseError, false, JSMSG_BAD_DUP_ARGS); return false; } @@ -2934,12 +2938,11 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn return false; if (tt != TOK_RP) { if (IsSetterKind(kind)) { - report(ParseError, false, null(), - JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); + zeport(ParseError, false, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); return false; } - report(ParseError, false, null(), JSMSG_PAREN_AFTER_FORMAL); + zeport(ParseError, false, JSMSG_PAREN_AFTER_FORMAL); return false; } } @@ -2952,7 +2955,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn funbox->function()->setArgCount(positionalFormals.length()); } else if (IsSetterKind(kind)) { - report(ParseError, false, null(), JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); + zeport(ParseError, false, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); return false; } @@ -3082,7 +3085,7 @@ Parser::addExprAndGetNextTemplStrToken(YieldHandling yieldHandling if (!tokenStream.getToken(&tt)) return false; if (tt != TOK_RC) { - report(ParseError, false, null(), JSMSG_TEMPLSTR_UNTERM_EXPR); + zeport(ParseError, false, JSMSG_TEMPLSTR_UNTERM_EXPR); return false; } @@ -3474,7 +3477,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if (!tokenStream.matchToken(&matched, TOK_ARROW)) return false; if (!matched) { - report(ParseError, false, null(), JSMSG_BAD_ARROW_ARGS); + zeport(ParseError, false, JSMSG_BAD_ARROW_ARGS); return false; } } @@ -3482,7 +3485,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, // When parsing something for new Function() we have to make sure to // only treat a certain part of the source as a parameter list. if (parameterListEnd.isSome() && parameterListEnd.value() != pos().begin) { - report(ParseError, false, null(), JSMSG_UNEXPECTED_PARAMLIST_END); + zeport(ParseError, false, JSMSG_UNEXPECTED_PARAMLIST_END); return false; } @@ -3495,7 +3498,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if ((funbox->isStarGenerator() && !funbox->isAsync()) || kind == Method || kind == GetterNoExpressionClosure || kind == SetterNoExpressionClosure || IsConstructorKind(kind)) { - report(ParseError, false, null(), JSMSG_CURLY_BEFORE_BODY); + zeport(ParseError, false, JSMSG_CURLY_BEFORE_BODY); return false; } @@ -3504,7 +3507,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if (!warnOnceAboutExprClosure()) return false; #else - report(ParseError, false, null(), JSMSG_CURLY_BEFORE_BODY); + zeport(ParseError, false, JSMSG_CURLY_BEFORE_BODY); return false; #endif } @@ -3537,7 +3540,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if (!tokenStream.matchToken(&matched, TOK_RC, TokenStream::Operand)) return false; if (!matched) { - report(ParseError, false, null(), JSMSG_CURLY_AFTER_BODY); + zeport(ParseError, false, JSMSG_CURLY_AFTER_BODY); return false; } funbox->bufEnd = pos().end; @@ -3595,7 +3598,7 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan if (tt == TOK_MUL) { if (asyncKind != SyncFunction) { - report(ParseError, false, null(), JSMSG_ASYNC_GENERATOR); + zeport(ParseError, false, JSMSG_ASYNC_GENERATOR); return null(); } generatorKind = StarGenerator; @@ -3612,7 +3615,7 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan tokenStream.ungetToken(); } else { /* Unnamed function expressions are forbidden in statement context. */ - report(ParseError, false, null(), JSMSG_UNNAMED_FUNCTION_STMT); + zeport(ParseError, false, JSMSG_UNNAMED_FUNCTION_STMT); return null(); } @@ -3648,7 +3651,7 @@ Parser::functionExpr(uint32_t preludeStart, InvokedPrediction invo if (tt == TOK_MUL) { if (asyncKind != SyncFunction) { - report(ParseError, false, null(), JSMSG_ASYNC_GENERATOR); + zeport(ParseError, false, JSMSG_ASYNC_GENERATOR); return null(); } generatorKind = StarGenerator; @@ -3693,10 +3696,11 @@ template bool Parser::checkUnescapedName() { - if (!tokenStream.currentToken().nameContainsEscape()) + const Token& token = tokenStream.currentToken(); + if (!token.nameContainsEscape()) return true; - report(ParseError, false, null(), JSMSG_ESCAPED_KEYWORD); + reportWithOffset(ParseError, false, token.pos.begin, JSMSG_ESCAPED_KEYWORD); return false; } @@ -3820,7 +3824,7 @@ Parser::maybeParseDirective(Node list, Node pn, bool* cont) // occur in the directive prologue -- octal escapes -- and // complain now. if (tokenStream.sawOctalEscape()) { - report(ParseError, false, null(), JSMSG_DEPRECATED_OCTAL); + zeport(ParseError, false, JSMSG_DEPRECATED_OCTAL); return false; } pc->sc()->strictScript = true; @@ -3828,7 +3832,7 @@ Parser::maybeParseDirective(Node list, Node pn, bool* cont) } else if (directive == context->names().useAsm) { if (pc->isFunctionBox()) return asmJS(list); - return report(ParseWarning, false, pn, JSMSG_USE_ASM_DIRECTIVE_FAIL); + return reportWithNode(ParseWarning, false, pn, JSMSG_USE_ASM_DIRECTIVE_FAIL); } } return true; @@ -3860,10 +3864,8 @@ Parser::statementList(YieldHandling yieldHandling) if (tt == TOK_EOF || tt == TOK_RC) break; if (afterReturn) { - TokenPos pos(0, 0); - if (!tokenStream.peekTokenPos(&pos, TokenStream::Operand)) + if (!tokenStream.peekOffset(&statementBegin, TokenStream::Operand)) return null(); - statementBegin = pos.begin; } Node next = statementListItem(yieldHandling, canHaveDirectives); if (!next) { @@ -3909,7 +3911,7 @@ Parser::condition(InHandling inHandling, YieldHandling yieldHandli /* Check for (a = b) and warn about possible (a == b) mistype. */ if (handler.isUnparenthesizedAssignment(pn)) { - if (!report(ParseExtraWarning, false, null(), JSMSG_EQUAL_AS_ASSIGN)) + if (!zeport(ParseExtraWarning, false, JSMSG_EQUAL_AS_ASSIGN)) return null(); } return pn; @@ -3966,7 +3968,8 @@ Parser::PossibleError::hasError(ErrorKind kind) template void -Parser::PossibleError::setPending(ErrorKind kind, Node pn, unsigned errorNumber) +Parser::PossibleError::setPending(ErrorKind kind, const TokenPos& pos, + unsigned errorNumber) { // Don't overwrite a previously recorded error. if (hasError(kind)) @@ -3975,23 +3978,25 @@ Parser::PossibleError::setPending(ErrorKind kind, Node pn, unsigne // If we report an error later, we'll do it from the position where we set // the state to pending. Error& err = error(kind); - err.offset_ = (pn ? parser_.handler.getPosition(pn) : parser_.pos()).begin; + err.offset_ = pos.begin; err.errorNumber_ = errorNumber; err.state_ = ErrorState::Pending; } template void -Parser::PossibleError::setPendingDestructuringError(Node pn, unsigned errorNumber) +Parser::PossibleError::setPendingDestructuringErrorAt(const TokenPos& pos, + unsigned errorNumber) { - setPending(ErrorKind::Destructuring, pn, errorNumber); + setPending(ErrorKind::Destructuring, pos, errorNumber); } template void -Parser::PossibleError::setPendingExpressionError(Node pn, unsigned errorNumber) +Parser::PossibleError::setPendingExpressionErrorAt(const TokenPos& pos, + unsigned errorNumber) { - setPending(ErrorKind::Expression, pn, errorNumber); + setPending(ErrorKind::Expression, pos, errorNumber); } template @@ -4066,7 +4071,7 @@ Parser::checkAssignmentToCall(Node target, unsigned msg) // concerned about sites using this in dead code, so forbid it only in // strict mode code (or if the werror option has been set), and otherwise // warn. - return report(ParseStrictError, pc->sc()->strict(), target, msg); + return reportWithNode(ParseStrictError, pc->sc()->strict(), target, msg); } template <> @@ -4079,7 +4084,7 @@ Parser::checkDestructuringName(ParseNode* expr, Maybe::checkDestructuringName(ParseNode* expr, Maybename()); - return noteDeclaredName(name, *maybeDecl, handler.getPosition(expr)); + return noteDeclaredName(name, *maybeDecl, expr->pn_pos); } // Otherwise this is an expression in destructuring outside a declaration. @@ -4171,7 +4176,7 @@ Parser::checkDestructuringArray(ParseNode* arrayPattern, ParseNode* target; if (element->isKind(PNK_SPREAD)) { if (element->pn_next) { - report(ParseError, false, element->pn_next, JSMSG_PARAMETER_AFTER_REST); + reportWithNode(ParseError, false, element->pn_next, JSMSG_PARAMETER_AFTER_REST); return false; } target = element->pn_kid; @@ -4234,7 +4239,7 @@ Parser::checkDestructuringPattern(ParseNode* pattern, PossibleError* possibleError /* = nullptr */) { if (pattern->isKind(PNK_ARRAYCOMP)) { - report(ParseError, false, pattern, JSMSG_ARRAY_COMP_LEFTSIDE); + reportWithNode(ParseError, false, pattern, JSMSG_ARRAY_COMP_LEFTSIDE); return false; } @@ -4373,14 +4378,7 @@ Parser::declarationPattern(Node decl, DeclarationKind declKind, To } } - TokenKind token; - if (!tokenStream.getToken(&token, TokenStream::None)) - return null(); - - if (token != TOK_ASSIGN) { - report(ParseError, false, null(), JSMSG_BAD_DESTRUCT_DECL); - return null(); - } + MUST_MATCH_TOKEN(TOK_ASSIGN, JSMSG_BAD_DESTRUCT_DECL); Node init = assignExpr(forHeadKind ? InProhibited : InAllowed, yieldHandling, TripledotProhibited); @@ -4430,7 +4428,7 @@ Parser::initializerInNameDeclaration(Node decl, Node binding, // // for (var/let/const x = ... of ...); // BAD if (isForOf) { - report(ParseError, false, binding, JSMSG_BAD_FOR_LEFTSIDE); + reportWithNode(ParseError, false, binding, JSMSG_BAD_FOR_LEFTSIDE); return false; } @@ -4439,15 +4437,15 @@ Parser::initializerInNameDeclaration(Node decl, Node binding, // // for (let/const x = ... in ...); // BAD if (DeclarationKindIsLexical(declKind)) { - report(ParseError, false, binding, JSMSG_BAD_FOR_LEFTSIDE); + reportWithNode(ParseError, false, binding, JSMSG_BAD_FOR_LEFTSIDE); return false; } // This leaves only initialized for-in |var| declarations. ES6 // forbids these; later ES un-forbids in non-strict mode code. *forHeadKind = PNK_FORIN; - if (!report(ParseStrictError, pc->sc()->strict(), initializer, - JSMSG_INVALID_FOR_IN_DECL_WITH_INIT)) + if (!reportWithNode(ParseStrictError, pc->sc()->strict(), initializer, + JSMSG_INVALID_FOR_IN_DECL_WITH_INIT)) { return false; } @@ -4495,7 +4493,7 @@ Parser::declarationName(Node decl, DeclarationKind declKind, Token { // Anything other than TOK_YIELD or TOK_NAME is an error. if (tt != TOK_NAME && tt != TOK_YIELD) { - report(ParseError, false, null(), JSMSG_NO_VARIABLE_NAME); + zeport(ParseError, false, JSMSG_NO_VARIABLE_NAME); return null(); } @@ -4555,7 +4553,7 @@ Parser::declarationName(Node decl, DeclarationKind declKind, Token // Normal const declarations, and const declarations in for(;;) // heads, must be initialized. if (declKind == DeclarationKind::Const) { - report(ParseError, false, binding, JSMSG_BAD_CONST_DECL); + reportWithNode(ParseError, false, binding, JSMSG_BAD_CONST_DECL); return null(); } } @@ -4695,7 +4693,7 @@ Parser::namedImportsOrNamespaceImport(TokenKind tt, Node impor return false; if (afterAs != TOK_NAME && afterAs != TOK_YIELD) { - report(ParseError, false, null(), JSMSG_NO_BINDING_NAME); + zeport(ParseError, false, JSMSG_NO_BINDING_NAME); return false; } } else { @@ -4707,7 +4705,7 @@ Parser::namedImportsOrNamespaceImport(TokenKind tt, Node impor JSAutoByteString bytes; if (!AtomToPrintableString(context, importName, &bytes)) return false; - report(ParseError, false, null(), JSMSG_AS_AFTER_RESERVED_WORD, bytes.ptr()); + zeport(ParseError, false, JSMSG_AS_AFTER_RESERVED_WORD, bytes.ptr()); return false; } } @@ -4749,7 +4747,7 @@ Parser::namedImportsOrNamespaceImport(TokenKind tt, Node impor return false; if (tt != TOK_NAME || tokenStream.currentName() != context->names().as) { - report(ParseError, false, null(), JSMSG_AS_AFTER_IMPORT_STAR); + reportWithOffset(ParseError, false, pos().begin, JSMSG_AS_AFTER_IMPORT_STAR); return false; } @@ -4804,7 +4802,7 @@ Parser::importDeclaration() MOZ_ASSERT(tokenStream.currentToken().type == TOK_IMPORT); if (!pc->atModuleLevel()) { - report(ParseError, false, null(), JSMSG_IMPORT_DECL_AT_TOP_LEVEL); + zeport(ParseError, false, JSMSG_IMPORT_DECL_AT_TOP_LEVEL); return null(); } @@ -4853,7 +4851,7 @@ Parser::importDeclaration() return null(); if (tt != TOK_LC && tt != TOK_MUL) { - report(ParseError, false, null(), JSMSG_NAMED_IMPORTS_OR_NAMESPACE_IMPORT); + zeport(ParseError, false, JSMSG_NAMED_IMPORTS_OR_NAMESPACE_IMPORT); return null(); } @@ -4869,7 +4867,7 @@ Parser::importDeclaration() return null(); if (tt != TOK_NAME || tokenStream.currentName() != context->names().from) { - report(ParseError, false, null(), JSMSG_FROM_AFTER_IMPORT_CLAUSE); + zeport(ParseError, false, JSMSG_FROM_AFTER_IMPORT_CLAUSE); return null(); } @@ -4882,7 +4880,7 @@ Parser::importDeclaration() // equivalent to |import {} from 'a'|. importSpecSet->pn_pos.end = importSpecSet->pn_pos.begin; } else { - report(ParseError, false, null(), JSMSG_DECLARATION_AFTER_IMPORT); + zeport(ParseError, false, JSMSG_DECLARATION_AFTER_IMPORT); return null(); } @@ -4920,7 +4918,7 @@ Parser::checkExportedName(JSAtom* exportName) if (!AtomToPrintableString(context, exportName, &str)) return false; - report(ParseError, false, null(), JSMSG_DUPLICATE_EXPORT_NAME, str.ptr()); + zeport(ParseError, false, JSMSG_DUPLICATE_EXPORT_NAME, str.ptr()); return false; } @@ -4963,7 +4961,7 @@ Parser::exportDeclaration() MOZ_ASSERT(tokenStream.currentToken().type == TOK_EXPORT); if (!pc->atModuleLevel()) { - report(ParseError, false, null(), JSMSG_EXPORT_DECL_AT_TOP_LEVEL); + zeport(ParseError, false, JSMSG_EXPORT_DECL_AT_TOP_LEVEL); return null(); } @@ -4996,14 +4994,8 @@ Parser::exportDeclaration() bool foundAs; if (!tokenStream.matchContextualKeyword(&foundAs, context->names().as)) return null(); - if (foundAs) { - if (!tokenStream.getToken(&tt, TokenStream::KeywordIsName)) - return null(); - if (tt != TOK_NAME) { - report(ParseError, false, null(), JSMSG_NO_EXPORT_NAME); - return null(); - } - } + if (foundAs) + MUST_MATCH_TOKEN_MOD(TOK_NAME, TokenStream::KeywordIsName, JSMSG_NO_EXPORT_NAME); Node exportName = newName(tokenStream.currentName()); if (!exportName) @@ -5088,7 +5080,7 @@ Parser::exportDeclaration() if (!tokenStream.getToken(&tt)) return null(); if (tt != TOK_NAME || tokenStream.currentName() != context->names().from) { - report(ParseError, false, null(), JSMSG_FROM_AFTER_EXPORT_STAR); + zeport(ParseError, false, JSMSG_FROM_AFTER_EXPORT_STAR); return null(); } @@ -5224,7 +5216,7 @@ Parser::exportDeclaration() MOZ_FALLTHROUGH; default: - report(ParseError, false, null(), JSMSG_DECLARATION_AFTER_EXPORT); + zeport(ParseError, false, JSMSG_DECLARATION_AFTER_EXPORT); return null(); } @@ -5300,7 +5292,7 @@ Parser::ifStatement(YieldHandling yieldHandling) if (!tokenStream.peekToken(&tt, TokenStream::Operand)) return null(); if (tt == TOK_SEMI) { - if (!report(ParseExtraWarning, false, null(), JSMSG_EMPTY_CONSEQUENT)) + if (!zeport(ParseExtraWarning, false, JSMSG_EMPTY_CONSEQUENT)) return null(); } @@ -5426,7 +5418,7 @@ Parser::validateForInOrOfLHSExpression(Node target, PossibleError* if (handler.isFunctionCall(target)) return checkAssignmentToCall(target, JSMSG_BAD_FOR_LEFTSIDE); - report(ParseError, false, target, JSMSG_BAD_FOR_LEFTSIDE); + reportWithNode(ParseError, false, target, JSMSG_BAD_FOR_LEFTSIDE); return false; } @@ -5547,7 +5539,7 @@ Parser::forHeadStart(YieldHandling yieldHandling, // // See ES6 13.7. if (isForOf && letIsIdentifier) { - report(ParseError, false, *forInitialPart, JSMSG_LET_STARTING_FOROF_LHS); + reportWithNode(ParseError, false, *forInitialPart, JSMSG_LET_STARTING_FOROF_LHS); return false; } @@ -5698,7 +5690,7 @@ Parser::forStatement(YieldHandling yieldHandling) iflags |= JSITER_ENUMERATE; } else { if (isForEach) { - report(ParseError, false, startNode, JSMSG_BAD_FOR_EACH_LOOP); + reportWithNode(ParseError, false, startNode, JSMSG_BAD_FOR_EACH_LOOP); return null(); } @@ -5774,7 +5766,7 @@ Parser::switchStatement(YieldHandling yieldHandling) switch (tt) { case TOK_DEFAULT: if (seenDefault) { - report(ParseError, false, null(), JSMSG_TOO_MANY_DEFAULTS); + zeport(ParseError, false, JSMSG_TOO_MANY_DEFAULTS); return null(); } seenDefault = true; @@ -5788,7 +5780,7 @@ Parser::switchStatement(YieldHandling yieldHandling) break; default: - report(ParseError, false, null(), JSMSG_BAD_SWITCH); + zeport(ParseError, false, JSMSG_BAD_SWITCH); return null(); } @@ -5807,10 +5799,8 @@ Parser::switchStatement(YieldHandling yieldHandling) if (tt == TOK_RC || tt == TOK_CASE || tt == TOK_DEFAULT) break; if (afterReturn) { - TokenPos pos(0, 0); - if (!tokenStream.peekTokenPos(&pos, TokenStream::Operand)) + if (!tokenStream.peekOffset(&statementBegin, TokenStream::Operand)) return null(); - statementBegin = pos.begin; } Node stmt = statementListItem(yieldHandling); if (!stmt) @@ -5872,8 +5862,10 @@ Parser::continueStatement(YieldHandling yieldHandling) for (;;) { stmt = ParseContext::Statement::findNearest(stmt, isLoop); if (!stmt) { - report(ParseError, false, null(), - foundLoop ? JSMSG_LABEL_NOT_FOUND : JSMSG_BAD_CONTINUE); + if (foundLoop) + zeport(ParseError, false, JSMSG_LABEL_NOT_FOUND); + else + reportWithOffset(ParseError, false, begin, JSMSG_BAD_CONTINUE); return null(); } @@ -5893,7 +5885,7 @@ Parser::continueStatement(YieldHandling yieldHandling) break; } } else if (!pc->findInnermostStatement(isLoop)) { - report(ParseError, false, null(), JSMSG_BAD_CONTINUE); + zeport(ParseError, false, JSMSG_BAD_CONTINUE); return null(); } @@ -5923,7 +5915,7 @@ Parser::breakStatement(YieldHandling yieldHandling) }; if (!pc->findInnermostStatement(hasSameLabel)) { - report(ParseError, false, null(), JSMSG_LABEL_NOT_FOUND); + zeport(ParseError, false, JSMSG_LABEL_NOT_FOUND); return null(); } } else { @@ -5932,7 +5924,7 @@ Parser::breakStatement(YieldHandling yieldHandling) }; if (!pc->findInnermostStatement(isBreakTarget)) { - report(ParseError, false, null(), JSMSG_TOUGH_BREAK); + reportWithOffset(ParseError, false, begin, JSMSG_TOUGH_BREAK); return null(); } } @@ -6082,7 +6074,7 @@ Parser::yieldExpression(InHandling inHandling) return null(); if (!pc->isFunctionBox()) { - report(ParseError, false, null(), JSMSG_BAD_RETURN_OR_YIELD, js_yield_str); + zeport(ParseError, false, JSMSG_BAD_RETURN_OR_YIELD, js_yield_str); return null(); } @@ -6170,7 +6162,7 @@ Parser::withStatement(YieldHandling yieldHandling) // warning under JSOPTION_EXTRA_WARNINGS. See // https://bugzilla.mozilla.org/show_bug.cgi?id=514576#c1. if (pc->sc()->strict()) { - if (!report(ParseStrictError, true, null(), JSMSG_STRICT_CODE_WITH)) + if (!zeport(ParseStrictError, true, JSMSG_STRICT_CODE_WITH)) return null(); } @@ -6209,7 +6201,7 @@ Parser::labeledItem(YieldHandling yieldHandling) // GeneratorDeclaration is only matched by HoistableDeclaration in // StatementListItem, so generators can't be inside labels. if (next == TOK_MUL) { - report(ParseError, false, null(), JSMSG_GENERATOR_LABEL); + zeport(ParseError, false, JSMSG_GENERATOR_LABEL); return null(); } @@ -6217,7 +6209,7 @@ Parser::labeledItem(YieldHandling yieldHandling) // is ever matched. Per Annex B.3.2 that modifies this text, this // applies only to strict mode code. if (pc->sc()->strict()) { - report(ParseError, false, null(), JSMSG_FUNCTION_LABEL); + zeport(ParseError, false, JSMSG_FUNCTION_LABEL); return null(); } @@ -6240,13 +6232,13 @@ Parser::labeledStatement(YieldHandling yieldHandling) return stmt->label() == label; }; + uint32_t begin = pos().begin; + if (pc->findInnermostStatement(hasSameLabel)) { - report(ParseError, false, null(), JSMSG_DUPLICATE_LABEL); + reportWithOffset(ParseError, false, begin, JSMSG_DUPLICATE_LABEL); return null(); } - uint32_t begin = pos().begin; - tokenStream.consumeKnownToken(TOK_COLON); /* Push a label struct and parse the statement. */ @@ -6270,11 +6262,11 @@ Parser::throwStatement(YieldHandling yieldHandling) if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand)) return null(); if (tt == TOK_EOF || tt == TOK_SEMI || tt == TOK_RC) { - report(ParseError, false, null(), JSMSG_MISSING_EXPR_AFTER_THROW); + zeport(ParseError, false, JSMSG_MISSING_EXPR_AFTER_THROW); return null(); } if (tt == TOK_EOL) { - report(ParseError, false, null(), JSMSG_LINE_BREAK_AFTER_THROW); + zeport(ParseError, false, JSMSG_LINE_BREAK_AFTER_THROW); return null(); } @@ -6348,7 +6340,7 @@ Parser::tryStatement(YieldHandling yieldHandling) /* Check for another catch after unconditional catch. */ if (hasUnconditionalCatch) { - report(ParseError, false, null(), JSMSG_CATCH_AFTER_GENERAL); + zeport(ParseError, false, JSMSG_CATCH_AFTER_GENERAL); return null(); } @@ -6396,7 +6388,7 @@ Parser::tryStatement(YieldHandling yieldHandling) } default: - report(ParseError, false, null(), JSMSG_CATCH_IDENTIFIER); + zeport(ParseError, false, JSMSG_CATCH_IDENTIFIER); return null(); } @@ -6464,7 +6456,7 @@ Parser::tryStatement(YieldHandling yieldHandling) tokenStream.ungetToken(); } if (!catchList && !finallyBlock) { - report(ParseError, false, null(), JSMSG_CATCH_OR_FINALLY); + zeport(ParseError, false, JSMSG_CATCH_OR_FINALLY); return null(); } @@ -6609,7 +6601,7 @@ Parser::classDefinition(YieldHandling yieldHandling, tokenStream.ungetToken(); } else { // Class statements must have a bound name - report(ParseError, false, null(), JSMSG_UNNAMED_CLASS_STMT); + zeport(ParseError, false, JSMSG_UNNAMED_CLASS_STMT); return null(); } } else { @@ -6670,7 +6662,7 @@ Parser::classDefinition(YieldHandling yieldHandling, return null(); if (tt == TOK_RC) { tokenStream.consumeKnownToken(tt, TokenStream::KeywordIsName); - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(tt)); return null(); } @@ -6702,7 +6694,7 @@ Parser::classDefinition(YieldHandling yieldHandling, propType != PropertyType::AsyncMethod && propType != PropertyType::Constructor && propType != PropertyType::DerivedConstructor) { - report(ParseError, false, null(), JSMSG_BAD_METHOD_DEF); + zeport(ParseError, false, JSMSG_BAD_METHOD_DEF); return null(); } @@ -6712,17 +6704,17 @@ Parser::classDefinition(YieldHandling yieldHandling, propType = PropertyType::SetterNoExpressionClosure; if (!isStatic && propAtom == context->names().constructor) { if (propType != PropertyType::Method) { - report(ParseError, false, propName, JSMSG_BAD_METHOD_DEF); + reportWithNode(ParseError, false, propName, JSMSG_BAD_METHOD_DEF); return null(); } if (seenConstructor) { - report(ParseError, false, propName, JSMSG_DUPLICATE_PROPERTY, "constructor"); + reportWithNode(ParseError, false, propName, JSMSG_DUPLICATE_PROPERTY, "constructor"); return null(); } seenConstructor = true; propType = hasHeritage ? PropertyType::DerivedConstructor : PropertyType::Constructor; } else if (isStatic && propAtom == context->names().prototype) { - report(ParseError, false, propName, JSMSG_BAD_METHOD_DEF); + reportWithNode(ParseError, false, propName, JSMSG_BAD_METHOD_DEF); return null(); } @@ -6949,8 +6941,7 @@ Parser::statement(YieldHandling yieldHandling) } if (forbiddenLetDeclaration) { - report(ParseError, false, null(), JSMSG_FORBIDDEN_AS_STATEMENT, - "lexical declarations"); + zeport(ParseError, false, JSMSG_FORBIDDEN_AS_STATEMENT, "lexical declarations"); return null(); } } @@ -7004,7 +6995,7 @@ Parser::statement(YieldHandling yieldHandling) // detected this way, so don't bother passing around an extra parameter // everywhere. if (!pc->isFunctionBox()) { - report(ParseError, false, null(), JSMSG_BAD_RETURN_OR_YIELD, js_return_str); + zeport(ParseError, false, JSMSG_BAD_RETURN_OR_YIELD, js_return_str); return null(); } return returnStatement(yieldHandling); @@ -7032,12 +7023,12 @@ Parser::statement(YieldHandling yieldHandling) // statement of |if| or |else|, but Parser::consequentOrAlternative // handles that). case TOK_FUNCTION: - report(ParseError, false, null(), JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations"); + zeport(ParseError, false, JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations"); return null(); // |class| is also forbidden by lookahead restriction. case TOK_CLASS: - report(ParseError, false, null(), JSMSG_FORBIDDEN_AS_STATEMENT, "classes"); + zeport(ParseError, false, JSMSG_FORBIDDEN_AS_STATEMENT, "classes"); return null(); // ImportDeclaration (only inside modules) @@ -7051,11 +7042,11 @@ Parser::statement(YieldHandling yieldHandling) // Miscellaneous error cases arguably better caught here than elsewhere. case TOK_CATCH: - report(ParseError, false, null(), JSMSG_CATCH_WITHOUT_TRY); + zeport(ParseError, false, JSMSG_CATCH_WITHOUT_TRY); return null(); case TOK_FINALLY: - report(ParseError, false, null(), JSMSG_FINALLY_WITHOUT_TRY); + zeport(ParseError, false, JSMSG_FINALLY_WITHOUT_TRY); return null(); // NOTE: default case handled in the ExpressionStatement section. @@ -7096,7 +7087,7 @@ Parser::statementListItem(YieldHandling yieldHandling, if (!canHaveDirectives && tokenStream.currentToken().atom() == context->names().useAsm) { if (!abortIfSyntaxParser()) return null(); - if (!report(ParseWarning, false, null(), JSMSG_USE_ASM_DIRECTIVE_FAIL)) + if (!zeport(ParseWarning, false, JSMSG_USE_ASM_DIRECTIVE_FAIL)) return null(); } return expressionStatement(yieldHandling); @@ -7190,7 +7181,7 @@ Parser::statementListItem(YieldHandling yieldHandling, // detected this way, so don't bother passing around an extra parameter // everywhere. if (!pc->isFunctionBox()) { - report(ParseError, false, null(), JSMSG_BAD_RETURN_OR_YIELD, js_return_str); + zeport(ParseError, false, JSMSG_BAD_RETURN_OR_YIELD, js_return_str); return null(); } return returnStatement(yieldHandling); @@ -7242,11 +7233,11 @@ Parser::statementListItem(YieldHandling yieldHandling, // Miscellaneous error cases arguably better caught here than elsewhere. case TOK_CATCH: - report(ParseError, false, null(), JSMSG_CATCH_WITHOUT_TRY); + zeport(ParseError, false, JSMSG_CATCH_WITHOUT_TRY); return null(); case TOK_FINALLY: - report(ParseError, false, null(), JSMSG_FINALLY_WITHOUT_TRY); + zeport(ParseError, false, JSMSG_FINALLY_WITHOUT_TRY); return null(); // NOTE: default case handled in the ExpressionStatement section. @@ -7291,8 +7282,8 @@ Parser::expr(InHandling inHandling, YieldHandling yieldHandling, if (!tokenStream.peekToken(&tt)) return null(); if (tt != TOK_ARROW) { - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, - "expression", TokenKindToDesc(TOK_RP)); + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, + "expression", TokenKindToDesc(TOK_RP)); return null(); } @@ -7449,7 +7440,7 @@ Parser::orExpr1(InHandling inHandling, YieldHandling yieldHandling return null(); // Report an error for unary expressions on the LHS of **. if (tok == TOK_POW && handler.isUnparenthesizedUnaryExpression(pn)) { - report(ParseError, false, null(), JSMSG_BAD_POW_LEFTSIDE); + zeport(ParseError, false, JSMSG_BAD_POW_LEFTSIDE); return null(); } pnk = BinaryOpTokenKindToParseNodeKind(tok); @@ -7530,7 +7521,7 @@ Parser::checkAndMarkAsAssignmentLhs(Node target, AssignmentFlavor if (handler.isUnparenthesizedDestructuringPattern(target)) { if (flavor == CompoundAssignment) { - report(ParseError, false, null(), JSMSG_BAD_DESTRUCT_ASS); + zeport(ParseError, false, JSMSG_BAD_DESTRUCT_ASS); return false; } @@ -7669,7 +7660,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl if (!tokenStream.getToken(&tt)) return null(); if (tt != TOK_ARROW) { - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "'=>' after argument list", TokenKindToDesc(tt)); return null(); @@ -7708,7 +7699,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl MOZ_ASSERT(next == TOK_ARROW || next == TOK_EOL); if (next != TOK_ARROW) { - report(ParseError, false, null(), JSMSG_LINE_BREAK_BEFORE_ARROW); + zeport(ParseError, false, JSMSG_LINE_BREAK_BEFORE_ARROW); return null(); } tokenStream.consumeKnownToken(TOK_ARROW); @@ -7853,10 +7844,11 @@ Parser::reportIfArgumentsEvalTarget(Node nameNode) if (!chars) return true; - if (!report(ParseStrictError, pc->sc()->strict(), nameNode, JSMSG_BAD_STRICT_ASSIGN, chars)) + bool strict = pc->sc()->strict(); + if (!reportWithNode(ParseStrictError, strict, nameNode, JSMSG_BAD_STRICT_ASSIGN, chars)) return false; - MOZ_ASSERT(!pc->sc()->strict(), + MOZ_ASSERT(!strict, "an error should have been reported if this was strict mode " "code"); return true; @@ -7908,7 +7900,7 @@ Parser::reportIfNotValidSimpleAssignmentTarget(Node target, Assign break; } - report(ParseError, pc->sc()->strict(), target, errnum, extra); + reportWithNode(ParseError, pc->sc()->strict(), target, errnum, extra); return false; } @@ -8014,7 +8006,8 @@ Parser::unaryExpr(YieldHandling yieldHandling, TripledotHandling t // Per spec, deleting any unary expression is valid -- it simply // returns true -- except for one case that is illegal in strict mode. if (handler.isNameAnyParentheses(expr)) { - if (!report(ParseStrictError, pc->sc()->strict(), expr, JSMSG_DEPRECATED_DELETE_OPERAND)) + bool strict = pc->sc()->strict(); + if (!reportWithNode(ParseStrictError, strict, expr, JSMSG_DEPRECATED_DELETE_OPERAND)) return null(); pc->sc()->setBindingsAccessedDynamically(); } @@ -8026,7 +8019,7 @@ Parser::unaryExpr(YieldHandling yieldHandling, TripledotHandling t if (!pc->isAsync()) { // TOK_AWAIT can be returned in module, even if it's not inside // async function. - report(ParseError, false, null(), JSMSG_RESERVED_ID, "await"); + zeport(ParseError, false, JSMSG_RESERVED_ID, "await"); return null(); } @@ -8179,7 +8172,7 @@ Parser::comprehensionFor(GeneratorKind comprehensionKind) MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_VARIABLE_NAME); RootedPropertyName name(context, tokenStream.currentName()); if (name == context->names().let) { - report(ParseError, false, null(), JSMSG_LET_COMP_BINDING); + zeport(ParseError, false, JSMSG_LET_COMP_BINDING); return null(); } TokenPos namePos = pos(); @@ -8190,7 +8183,7 @@ Parser::comprehensionFor(GeneratorKind comprehensionKind) if (!tokenStream.matchContextualKeyword(&matched, context->names().of)) return null(); if (!matched) { - report(ParseError, false, null(), JSMSG_OF_AFTER_FOR_NAME); + zeport(ParseError, false, JSMSG_OF_AFTER_FOR_NAME); return null(); } @@ -8251,7 +8244,7 @@ Parser::comprehensionIf(GeneratorKind comprehensionKind) /* Check for (a = b) and warn about possible (a == b) mistype. */ if (handler.isUnparenthesizedAssignment(cond)) { - if (!report(ParseExtraWarning, false, null(), JSMSG_EQUAL_AS_ASSIGN)) + if (!zeport(ParseExtraWarning, false, JSMSG_EQUAL_AS_ASSIGN)) return null(); } @@ -8436,13 +8429,8 @@ Parser::argumentList(YieldHandling yieldHandling, Node listNode, b } } - TokenKind tt; - if (!tokenStream.getToken(&tt)) - return false; - if (tt != TOK_RP) { - report(ParseError, false, null(), JSMSG_PAREN_AFTER_ARGS); - return false; - } + MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_ARGS); + handler.setEndPosition(listNode, pos().end); return true; } @@ -8533,14 +8521,14 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling if (tt == TOK_NAME) { PropertyName* field = tokenStream.currentName(); if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) { - report(ParseError, false, null(), JSMSG_BAD_SUPERPROP, "property"); + zeport(ParseError, false, JSMSG_BAD_SUPERPROP, "property"); return null(); } nextMember = handler.newPropertyAccess(lhs, field, pos().end); if (!nextMember) return null(); } else { - report(ParseError, false, null(), JSMSG_NAME_AFTER_DOT); + zeport(ParseError, false, JSMSG_NAME_AFTER_DOT); return null(); } } else if (tt == TOK_LB) { @@ -8551,7 +8539,7 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX); if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) { - report(ParseError, false, null(), JSMSG_BAD_SUPERPROP, "member"); + zeport(ParseError, false, JSMSG_BAD_SUPERPROP, "member"); return null(); } nextMember = handler.newPropertyByValue(lhs, propExpr, pos().end); @@ -8563,12 +8551,12 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling { if (handler.isSuperBase(lhs)) { if (!pc->sc()->allowSuperCall()) { - report(ParseError, false, null(), JSMSG_BAD_SUPERCALL); + zeport(ParseError, false, JSMSG_BAD_SUPERCALL); return null(); } if (tt != TOK_LP) { - report(ParseError, false, null(), JSMSG_BAD_SUPER); + zeport(ParseError, false, JSMSG_BAD_SUPER); return null(); } @@ -8595,7 +8583,7 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling return null(); } else { if (options().selfHostingMode && handler.isPropertyAccess(lhs)) { - report(ParseError, false, null(), JSMSG_SELFHOSTED_METHOD_CALL); + zeport(ParseError, false, JSMSG_SELFHOSTED_METHOD_CALL); return null(); } @@ -8677,7 +8665,7 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling } if (handler.isSuperBase(lhs)) { - report(ParseError, false, null(), JSMSG_BAD_SUPER); + zeport(ParseError, false, JSMSG_BAD_SUPER); return null(); } @@ -8730,7 +8718,7 @@ Parser::labelOrIdentifierReference(YieldHandling yieldHandling, ? "static" : nullptr; if (badName) { - report(ParseError, false, null(), JSMSG_RESERVED_ID, badName); + zeport(ParseError, false, JSMSG_RESERVED_ID, badName); return nullptr; } } @@ -8739,7 +8727,7 @@ Parser::labelOrIdentifierReference(YieldHandling yieldHandling, pc->sc()->strict() || versionNumber() >= JSVERSION_1_7) { - report(ParseError, false, null(), JSMSG_RESERVED_ID, "yield"); + zeport(ParseError, false, JSMSG_RESERVED_ID, "yield"); return nullptr; } } @@ -8775,7 +8763,7 @@ Parser::bindingIdentifier(YieldHandling yieldHandling) ? "eval" : nullptr; if (badName) { - report(ParseError, false, null(), JSMSG_BAD_STRICT_ASSIGN, badName); + zeport(ParseError, false, JSMSG_BAD_STRICT_ASSIGN, badName); return nullptr; } @@ -8785,7 +8773,7 @@ Parser::bindingIdentifier(YieldHandling yieldHandling) ? "static" : nullptr; if (badName) { - report(ParseError, false, null(), JSMSG_RESERVED_ID, badName); + zeport(ParseError, false, JSMSG_RESERVED_ID, badName); return nullptr; } } @@ -8794,7 +8782,7 @@ Parser::bindingIdentifier(YieldHandling yieldHandling) pc->sc()->strict() || versionNumber() >= JSVERSION_1_7) { - report(ParseError, false, null(), JSMSG_RESERVED_ID, "yield"); + zeport(ParseError, false, JSMSG_RESERVED_ID, "yield"); return nullptr; } } @@ -8893,7 +8881,7 @@ Parser::arrayInitializer(YieldHandling yieldHandling, PossibleErro TokenStream::Modifier modifier = TokenStream::Operand; for (; ; index++) { if (index >= NativeObject::MAX_DENSE_ELEMENTS_COUNT) { - report(ParseError, false, null(), JSMSG_ARRAY_INIT_TOO_BIG); + zeport(ParseError, false, JSMSG_ARRAY_INIT_TOO_BIG); return null(); } @@ -8936,7 +8924,7 @@ Parser::arrayInitializer(YieldHandling yieldHandling, PossibleErro break; } if (tt == TOK_TRIPLEDOT && possibleError) - possibleError->setPendingDestructuringError(null(), JSMSG_REST_WITH_COMMA); + possibleError->setPendingDestructuringErrorAt(pos(), JSMSG_REST_WITH_COMMA); } } @@ -9003,7 +8991,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, } if (isAsync && isGenerator) { - report(ParseError, false, null(), JSMSG_ASYNC_GENERATOR); + zeport(ParseError, false, JSMSG_ASYNC_GENERATOR); return null(); } @@ -9116,7 +9104,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, } default: - report(ParseError, false, null(), JSMSG_BAD_PROP_ID); + zeport(ParseError, false, JSMSG_BAD_PROP_ID); return null(); } @@ -9126,7 +9114,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, if (tt == TOK_COLON) { if (isGenerator) { - report(ParseError, false, null(), JSMSG_BAD_PROP_ID); + zeport(ParseError, false, JSMSG_BAD_PROP_ID); return null(); } *propType = PropertyType::Normal; @@ -9135,7 +9123,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, if (ltok == TOK_NAME && (tt == TOK_COMMA || tt == TOK_RC || tt == TOK_ASSIGN)) { if (isGenerator) { - report(ParseError, false, null(), JSMSG_BAD_PROP_ID); + zeport(ParseError, false, JSMSG_BAD_PROP_ID); return null(); } tokenStream.ungetToken(); @@ -9156,7 +9144,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, return propName; } - report(ParseError, false, null(), JSMSG_COLON_AFTER_ID); + zeport(ParseError, false, JSMSG_COLON_AFTER_ID); return null(); } @@ -9231,14 +9219,15 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* // Directly report the error when we're not in a // destructuring context. if (!possibleError) { - report(ParseError, false, propName, JSMSG_DUPLICATE_PROTO_PROPERTY); + reportWithOffset(ParseError, false, namePos.begin, + JSMSG_DUPLICATE_PROTO_PROPERTY); return null(); } // Otherwise delay error reporting until we've determined // whether or not we're destructuring. - possibleError->setPendingExpressionError(propName, - JSMSG_DUPLICATE_PROTO_PROPERTY); + possibleError->setPendingExpressionErrorAt(namePos, + JSMSG_DUPLICATE_PROTO_PROPERTY); } seenPrototypeMutation = true; @@ -9246,8 +9235,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* // __proto__: v mutates [[Prototype]]. Getters, setters, // method/generator definitions, computed property name // versions of all of these, and shorthands do not. - uint32_t begin = handler.getPosition(propName).begin; - if (!handler.addPrototypeMutation(literal, begin, propExpr)) + if (!handler.addPrototypeMutation(literal, namePos.begin, propExpr)) return null(); } else { if (!handler.isConstant(propExpr)) @@ -9267,7 +9255,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* return null(); if (propToken != TOK_NAME && propToken != TOK_YIELD) { - report(ParseError, false, null(), JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); + zeport(ParseError, false, JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); return null(); } @@ -9292,7 +9280,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* return null(); if (propToken != TOK_NAME && propToken != TOK_YIELD) { - report(ParseError, false, null(), JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); + zeport(ParseError, false, JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); return null(); } @@ -9316,14 +9304,14 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* // Destructuring defaults are definitely not allowed in this object literal, // because of something the caller knows about the preceding code. // For example, maybe the preceding token is an operator: `x + {y=z}`. - report(ParseError, false, null(), JSMSG_COLON_AFTER_ID); + zeport(ParseError, false, JSMSG_COLON_AFTER_ID); return null(); } // Here we set a pending error so that later in the parse, once we've // determined whether or not we're destructuring, the error can be // reported or ignored appropriately. - possibleError->setPendingExpressionError(null(), JSMSG_COLON_AFTER_ID); + possibleError->setPendingExpressionErrorAt(pos(), JSMSG_COLON_AFTER_ID); } Node rhs; @@ -9375,7 +9363,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* if (tt == TOK_RC) break; if (tt != TOK_COMMA) { - report(ParseError, false, null(), JSMSG_CURLY_AFTER_LIST); + zeport(ParseError, false, JSMSG_CURLY_AFTER_LIST); return null(); } } @@ -9424,8 +9412,7 @@ Parser::tryNewTarget(Node &newTarget) if (!tokenStream.getToken(&next)) return false; if (next != TOK_NAME || tokenStream.currentName() != context->names().target) { - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, - "target", TokenKindToDesc(next)); + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "target", TokenKindToDesc(next)); return false; } @@ -9480,7 +9467,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling if (!tokenStream.peekToken(&next)) return null(); if (next != TOK_ARROW) { - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(TOK_RP)); return null(); } @@ -9568,8 +9555,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling // name, closing parenthesis, and arrow, and allow it only if all are // present. if (tripledotHandling != TripledotAllowed) { - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, - "expression", TokenKindToDesc(tt)); + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); return null(); } @@ -9591,7 +9577,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling // or "arguments" should be prohibited. Argument-parsing code // handles that. if (next != TOK_NAME && next != TOK_YIELD) { - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "rest argument name", TokenKindToDesc(next)); return null(); } @@ -9600,7 +9586,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling if (!tokenStream.getToken(&next)) return null(); if (next != TOK_RP) { - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "closing parenthesis", TokenKindToDesc(next)); return null(); } @@ -9610,7 +9596,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling if (next != TOK_ARROW) { // Advance the scanner for proper error location reporting. tokenStream.consumeKnownToken(next); - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "'=>' after argument list", TokenKindToDesc(next)); return null(); } @@ -9622,8 +9608,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling } default: - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, - "expression", TokenKindToDesc(tt)); + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); return null(); } } @@ -9648,7 +9633,7 @@ Parser::warnOnceAboutExprClosure() return true; if (!cx->compartment()->warnedAboutExprClosure) { - if (!report(ParseWarning, false, null(), JSMSG_DEPRECATED_EXPR_CLOSURE)) + if (!zeport(ParseWarning, false, JSMSG_DEPRECATED_EXPR_CLOSURE)) return false; cx->compartment()->warnedAboutExprClosure = true; } @@ -9666,7 +9651,7 @@ Parser::warnOnceAboutForEach() if (!cx->compartment()->warnedAboutForEach) { // Disabled warning spew. - // if (!report(ParseWarning, false, null(), JSMSG_DEPRECATED_FOR_EACH)) + // if (!zeport(ParseWarning, false, JSMSG_DEPRECATED_FOR_EACH)) // return false; cx->compartment()->warnedAboutForEach = true; } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 090931f5b..88d705108 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -769,13 +769,13 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter * * Ex: * PossibleError possibleError(*this); - * possibleError.setPendingExpressionError(pn, JSMSG_BAD_PROP_ID); + * possibleError.setPendingExpressionErrorAt(pos, JSMSG_BAD_PROP_ID); * // A JSMSG_BAD_PROP_ID ParseError is reported, returns false. * if (!possibleError.checkForExpressionError()) * return false; // we reach this point with a pending exception * * PossibleError possibleError(*this); - * possibleError.setPendingExpressionError(pn, JSMSG_BAD_PROP_ID); + * possibleError.setPendingExpressionErrorAt(pos, JSMSG_BAD_PROP_ID); * // Returns true, no error is reported. * if (!possibleError.checkForDestructuringError()) * return false; // not reached, no pending exception @@ -815,7 +815,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter // Set a pending error. Only a single error may be set per instance and // error kind. - void setPending(ErrorKind kind, Node pn, unsigned errorNumber); + void setPending(ErrorKind kind, const TokenPos& pos, unsigned errorNumber); // If there is a pending error, report it and return false, otherwise // return true. @@ -830,12 +830,12 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter // Set a pending destructuring error. Only a single error may be set // per instance, i.e. subsequent calls to this method are ignored and // won't overwrite the existing pending error. - void setPendingDestructuringError(Node pn, unsigned errorNumber); + void setPendingDestructuringErrorAt(const TokenPos& pos, unsigned errorNumber); // Set a pending expression error. Only a single error may be set per // instance, i.e. subsequent calls to this method are ignored and won't // overwrite the existing pending error. - void setPendingExpressionError(Node pn, unsigned errorNumber); + void setPendingExpressionErrorAt(const TokenPos& pos, unsigned errorNumber); // If there is a pending destructuring error, report it and return // false, otherwise return true. Clears any pending expression error. @@ -907,7 +907,8 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool reportHelper(ParseReportKind kind, bool strict, uint32_t offset, unsigned errorNumber, va_list args); public: - bool report(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...); + bool zeport(ParseReportKind kind, bool strict, unsigned errorNumber, ...); + bool reportWithNode(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...); bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...); bool reportWithOffset(ParseReportKind kind, bool strict, uint32_t offset, unsigned errorNumber, ...); diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index 77eea3d81..03a580072 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -577,6 +577,7 @@ class MOZ_STACK_CLASS TokenStream *offset = pos.begin; return true; } + // This is like peekToken(), with one exception: if there is an EOL // between the end of the current token and the start of the next token, it // return true and store TOK_EOL in |*ttp|. In that case, no token with -- cgit v1.2.3 From 68c4eea34dc0ddf680036db62f1b9daeb131cfba Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 5 Apr 2019 21:01:54 +0200 Subject: Remove the |bool strict| argument from the report-at-current-offset Parser function (zeport). zeport => qeport --- js/src/frontend/Parser.cpp | 256 +++++++++++++++++++++++---------------------- js/src/frontend/Parser.h | 9 +- 2 files changed, 140 insertions(+), 125 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 26b3c2c25..a29287850 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -69,7 +69,7 @@ using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr; if (!tokenStream.getToken(&token, modifier)) \ return null(); \ if (token != tt) { \ - zeport(ParseError, false, errno); \ + qeport(ParseError, errno); \ return null(); \ } \ JS_END_MACRO @@ -596,15 +596,26 @@ Parser::reportHelper(ParseReportKind kind, bool strict, uint32_t o template bool -Parser::zeport(ParseReportKind kind, bool strict, unsigned errorNumber, ...) +Parser::qeport(ParseReportKind kind, unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool result = reportHelper(kind, strict, pos().begin, errorNumber, args); + bool result = reportHelper(kind, false, pos().begin, errorNumber, args); va_end(args); return result; } +template +bool +Parser::strictModeError(unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); + bool res = reportHelper(ParseStrictError, pc->sc()->strict(), pos().begin, errorNumber, args); + va_end(args); + return res; +} + template bool Parser::reportWithNode(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...) @@ -837,7 +848,7 @@ Parser::parse() if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); if (tt != TOK_EOF) { - zeport(ParseError, false, JSMSG_GARBAGE_AFTER_INPUT, "script", TokenKindToDesc(tt)); + qeport(ParseError, JSMSG_GARBAGE_AFTER_INPUT, "script", TokenKindToDesc(tt)); return null(); } if (foldConstants) { @@ -951,7 +962,7 @@ Parser::notePositionalFormalParameter(Node fn, HandlePropertyName { if (AddDeclaredNamePtr p = pc->functionScope().lookupDeclaredNameForAdd(name)) { if (disallowDuplicateParams) { - zeport(ParseError, false, JSMSG_BAD_DUP_ARGS); + qeport(ParseError, JSMSG_BAD_DUP_ARGS); return false; } @@ -963,7 +974,7 @@ Parser::notePositionalFormalParameter(Node fn, HandlePropertyName JSAutoByteString bytes; if (!AtomToPrintableString(context, name, &bytes)) return false; - if (!zeport(ParseStrictError, pc->sc()->strict(), JSMSG_DUPLICATE_FORMAL, bytes.ptr())) + if (!strictModeError(JSMSG_DUPLICATE_FORMAL, bytes.ptr())) return false; } @@ -1246,7 +1257,7 @@ Parser::noteDeclaredName(HandlePropertyName name, DeclarationKind AddDeclaredNamePtr p = pc->functionScope().lookupDeclaredNameForAdd(name); if (p) { - zeport(ParseError, false, JSMSG_BAD_DUP_ARGS); + qeport(ParseError, JSMSG_BAD_DUP_ARGS); return false; } @@ -1453,7 +1464,7 @@ Parser::checkStatementsEOF() if (!tokenStream.peekToken(&tt, TokenStream::Operand)) return false; if (tt != TOK_EOF) { - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); return false; } return true; @@ -1918,7 +1929,7 @@ Parser::evalBody(EvalSharedContext* evalsc) // script. if (hasUsedName(context->names().arguments)) { if (IsArgumentsUsedInLegacyGenerator(context, pc->sc()->compilationEnclosingScope())) { - zeport(ParseError, false, JSMSG_BAD_GENEXP_BODY, js_arguments_str); + qeport(ParseError, JSMSG_BAD_GENEXP_BODY, js_arguments_str); return nullptr; } } @@ -2016,7 +2027,7 @@ Parser::moduleBody(ModuleSharedContext* modulesc) if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); if (tt != TOK_EOF) { - zeport(ParseError, false, JSMSG_GARBAGE_AFTER_INPUT, "module", TokenKindToDesc(tt)); + qeport(ParseError, JSMSG_GARBAGE_AFTER_INPUT, "module", TokenKindToDesc(tt)); return null(); } @@ -2336,7 +2347,7 @@ Parser::standaloneFunction(HandleFunction fun, if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); if (tt != TOK_EOF) { - zeport(ParseError, false, JSMSG_GARBAGE_AFTER_INPUT, "function body", TokenKindToDesc(tt)); + qeport(ParseError, JSMSG_GARBAGE_AFTER_INPUT, "function body", TokenKindToDesc(tt)); return null(); } @@ -2741,8 +2752,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn if (!tokenStream.getToken(&tt, firstTokenModifier)) return false; if (tt != TOK_LP) { - zeport(ParseError, false, - kind == Arrow ? JSMSG_BAD_ARROW_ARGS : JSMSG_PAREN_BEFORE_FORMAL); + qeport(ParseError, kind == Arrow ? JSMSG_BAD_ARROW_ARGS : JSMSG_PAREN_BEFORE_FORMAL); return false; } @@ -2774,13 +2784,13 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn AtomVector& positionalFormals = pc->positionalFormalParameterNames(); if (IsGetterKind(kind)) { - zeport(ParseError, false, JSMSG_ACCESSOR_WRONG_ARGS, "getter", "no", "s"); + qeport(ParseError, JSMSG_ACCESSOR_WRONG_ARGS, "getter", "no", "s"); return false; } while (true) { if (hasRest) { - zeport(ParseError, false, JSMSG_PARAMETER_AFTER_REST); + qeport(ParseError, JSMSG_PARAMETER_AFTER_REST); return false; } @@ -2792,14 +2802,14 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn if (tt == TOK_TRIPLEDOT) { if (IsSetterKind(kind)) { - zeport(ParseError, false, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); + qeport(ParseError, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); return false; } disallowDuplicateParams = true; if (duplicatedParam) { // Has duplicated args before the rest parameter. - zeport(ParseError, false, JSMSG_BAD_DUP_ARGS); + qeport(ParseError, JSMSG_BAD_DUP_ARGS); return false; } @@ -2810,7 +2820,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn return false; if (tt != TOK_NAME && tt != TOK_YIELD && tt != TOK_LB && tt != TOK_LC) { - zeport(ParseError, false, JSMSG_NO_REST_NAME); + qeport(ParseError, JSMSG_NO_REST_NAME); return false; } } @@ -2821,7 +2831,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn disallowDuplicateParams = true; if (duplicatedParam) { // Has duplicated args before the destructuring parameter. - zeport(ParseError, false, JSMSG_BAD_DUP_ARGS); + qeport(ParseError, JSMSG_BAD_DUP_ARGS); return false; } @@ -2849,7 +2859,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn // case: // // async await => 1 - zeport(ParseError, false, JSMSG_RESERVED_ID, "await"); + qeport(ParseError, JSMSG_RESERVED_ID, "await"); return false; } @@ -2869,12 +2879,12 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn } default: - zeport(ParseError, false, JSMSG_MISSING_FORMAL); + qeport(ParseError, JSMSG_MISSING_FORMAL); return false; } if (positionalFormals.length() >= ARGNO_LIMIT) { - zeport(ParseError, false, JSMSG_TOO_MANY_FUN_ARGS); + qeport(ParseError, JSMSG_TOO_MANY_FUN_ARGS); return false; } @@ -2889,12 +2899,12 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn MOZ_ASSERT(!parenFreeArrow); if (hasRest) { - zeport(ParseError, false, JSMSG_REST_WITH_DEFAULT); + qeport(ParseError, JSMSG_REST_WITH_DEFAULT); return false; } disallowDuplicateParams = true; if (duplicatedParam) { - zeport(ParseError, false, JSMSG_BAD_DUP_ARGS); + qeport(ParseError, JSMSG_BAD_DUP_ARGS); return false; } @@ -2938,11 +2948,11 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn return false; if (tt != TOK_RP) { if (IsSetterKind(kind)) { - zeport(ParseError, false, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); + qeport(ParseError, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); return false; } - zeport(ParseError, false, JSMSG_PAREN_AFTER_FORMAL); + qeport(ParseError, JSMSG_PAREN_AFTER_FORMAL); return false; } } @@ -2955,7 +2965,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn funbox->function()->setArgCount(positionalFormals.length()); } else if (IsSetterKind(kind)) { - zeport(ParseError, false, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); + qeport(ParseError, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); return false; } @@ -3085,7 +3095,7 @@ Parser::addExprAndGetNextTemplStrToken(YieldHandling yieldHandling if (!tokenStream.getToken(&tt)) return false; if (tt != TOK_RC) { - zeport(ParseError, false, JSMSG_TEMPLSTR_UNTERM_EXPR); + qeport(ParseError, JSMSG_TEMPLSTR_UNTERM_EXPR); return false; } @@ -3477,7 +3487,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if (!tokenStream.matchToken(&matched, TOK_ARROW)) return false; if (!matched) { - zeport(ParseError, false, JSMSG_BAD_ARROW_ARGS); + qeport(ParseError, JSMSG_BAD_ARROW_ARGS); return false; } } @@ -3485,7 +3495,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, // When parsing something for new Function() we have to make sure to // only treat a certain part of the source as a parameter list. if (parameterListEnd.isSome() && parameterListEnd.value() != pos().begin) { - zeport(ParseError, false, JSMSG_UNEXPECTED_PARAMLIST_END); + qeport(ParseError, JSMSG_UNEXPECTED_PARAMLIST_END); return false; } @@ -3498,7 +3508,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if ((funbox->isStarGenerator() && !funbox->isAsync()) || kind == Method || kind == GetterNoExpressionClosure || kind == SetterNoExpressionClosure || IsConstructorKind(kind)) { - zeport(ParseError, false, JSMSG_CURLY_BEFORE_BODY); + qeport(ParseError, JSMSG_CURLY_BEFORE_BODY); return false; } @@ -3507,7 +3517,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if (!warnOnceAboutExprClosure()) return false; #else - zeport(ParseError, false, JSMSG_CURLY_BEFORE_BODY); + qeport(ParseError, JSMSG_CURLY_BEFORE_BODY); return false; #endif } @@ -3540,7 +3550,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if (!tokenStream.matchToken(&matched, TOK_RC, TokenStream::Operand)) return false; if (!matched) { - zeport(ParseError, false, JSMSG_CURLY_AFTER_BODY); + qeport(ParseError, JSMSG_CURLY_AFTER_BODY); return false; } funbox->bufEnd = pos().end; @@ -3598,7 +3608,7 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan if (tt == TOK_MUL) { if (asyncKind != SyncFunction) { - zeport(ParseError, false, JSMSG_ASYNC_GENERATOR); + qeport(ParseError, JSMSG_ASYNC_GENERATOR); return null(); } generatorKind = StarGenerator; @@ -3615,7 +3625,7 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan tokenStream.ungetToken(); } else { /* Unnamed function expressions are forbidden in statement context. */ - zeport(ParseError, false, JSMSG_UNNAMED_FUNCTION_STMT); + qeport(ParseError, JSMSG_UNNAMED_FUNCTION_STMT); return null(); } @@ -3651,7 +3661,7 @@ Parser::functionExpr(uint32_t preludeStart, InvokedPrediction invo if (tt == TOK_MUL) { if (asyncKind != SyncFunction) { - zeport(ParseError, false, JSMSG_ASYNC_GENERATOR); + qeport(ParseError, JSMSG_ASYNC_GENERATOR); return null(); } generatorKind = StarGenerator; @@ -3824,7 +3834,7 @@ Parser::maybeParseDirective(Node list, Node pn, bool* cont) // occur in the directive prologue -- octal escapes -- and // complain now. if (tokenStream.sawOctalEscape()) { - zeport(ParseError, false, JSMSG_DEPRECATED_OCTAL); + qeport(ParseError, JSMSG_DEPRECATED_OCTAL); return false; } pc->sc()->strictScript = true; @@ -3911,7 +3921,7 @@ Parser::condition(InHandling inHandling, YieldHandling yieldHandli /* Check for (a = b) and warn about possible (a == b) mistype. */ if (handler.isUnparenthesizedAssignment(pn)) { - if (!zeport(ParseExtraWarning, false, JSMSG_EQUAL_AS_ASSIGN)) + if (!qeport(ParseExtraWarning, JSMSG_EQUAL_AS_ASSIGN)) return null(); } return pn; @@ -4493,7 +4503,7 @@ Parser::declarationName(Node decl, DeclarationKind declKind, Token { // Anything other than TOK_YIELD or TOK_NAME is an error. if (tt != TOK_NAME && tt != TOK_YIELD) { - zeport(ParseError, false, JSMSG_NO_VARIABLE_NAME); + qeport(ParseError, JSMSG_NO_VARIABLE_NAME); return null(); } @@ -4693,7 +4703,7 @@ Parser::namedImportsOrNamespaceImport(TokenKind tt, Node impor return false; if (afterAs != TOK_NAME && afterAs != TOK_YIELD) { - zeport(ParseError, false, JSMSG_NO_BINDING_NAME); + qeport(ParseError, JSMSG_NO_BINDING_NAME); return false; } } else { @@ -4705,7 +4715,7 @@ Parser::namedImportsOrNamespaceImport(TokenKind tt, Node impor JSAutoByteString bytes; if (!AtomToPrintableString(context, importName, &bytes)) return false; - zeport(ParseError, false, JSMSG_AS_AFTER_RESERVED_WORD, bytes.ptr()); + qeport(ParseError, JSMSG_AS_AFTER_RESERVED_WORD, bytes.ptr()); return false; } } @@ -4802,7 +4812,7 @@ Parser::importDeclaration() MOZ_ASSERT(tokenStream.currentToken().type == TOK_IMPORT); if (!pc->atModuleLevel()) { - zeport(ParseError, false, JSMSG_IMPORT_DECL_AT_TOP_LEVEL); + qeport(ParseError, JSMSG_IMPORT_DECL_AT_TOP_LEVEL); return null(); } @@ -4851,7 +4861,7 @@ Parser::importDeclaration() return null(); if (tt != TOK_LC && tt != TOK_MUL) { - zeport(ParseError, false, JSMSG_NAMED_IMPORTS_OR_NAMESPACE_IMPORT); + qeport(ParseError, JSMSG_NAMED_IMPORTS_OR_NAMESPACE_IMPORT); return null(); } @@ -4867,7 +4877,7 @@ Parser::importDeclaration() return null(); if (tt != TOK_NAME || tokenStream.currentName() != context->names().from) { - zeport(ParseError, false, JSMSG_FROM_AFTER_IMPORT_CLAUSE); + qeport(ParseError, JSMSG_FROM_AFTER_IMPORT_CLAUSE); return null(); } @@ -4880,7 +4890,7 @@ Parser::importDeclaration() // equivalent to |import {} from 'a'|. importSpecSet->pn_pos.end = importSpecSet->pn_pos.begin; } else { - zeport(ParseError, false, JSMSG_DECLARATION_AFTER_IMPORT); + qeport(ParseError, JSMSG_DECLARATION_AFTER_IMPORT); return null(); } @@ -4918,7 +4928,7 @@ Parser::checkExportedName(JSAtom* exportName) if (!AtomToPrintableString(context, exportName, &str)) return false; - zeport(ParseError, false, JSMSG_DUPLICATE_EXPORT_NAME, str.ptr()); + qeport(ParseError, JSMSG_DUPLICATE_EXPORT_NAME, str.ptr()); return false; } @@ -4961,7 +4971,7 @@ Parser::exportDeclaration() MOZ_ASSERT(tokenStream.currentToken().type == TOK_EXPORT); if (!pc->atModuleLevel()) { - zeport(ParseError, false, JSMSG_EXPORT_DECL_AT_TOP_LEVEL); + qeport(ParseError, JSMSG_EXPORT_DECL_AT_TOP_LEVEL); return null(); } @@ -5080,7 +5090,7 @@ Parser::exportDeclaration() if (!tokenStream.getToken(&tt)) return null(); if (tt != TOK_NAME || tokenStream.currentName() != context->names().from) { - zeport(ParseError, false, JSMSG_FROM_AFTER_EXPORT_STAR); + qeport(ParseError, JSMSG_FROM_AFTER_EXPORT_STAR); return null(); } @@ -5216,7 +5226,7 @@ Parser::exportDeclaration() MOZ_FALLTHROUGH; default: - zeport(ParseError, false, JSMSG_DECLARATION_AFTER_EXPORT); + qeport(ParseError, JSMSG_DECLARATION_AFTER_EXPORT); return null(); } @@ -5292,7 +5302,7 @@ Parser::ifStatement(YieldHandling yieldHandling) if (!tokenStream.peekToken(&tt, TokenStream::Operand)) return null(); if (tt == TOK_SEMI) { - if (!zeport(ParseExtraWarning, false, JSMSG_EMPTY_CONSEQUENT)) + if (!qeport(ParseExtraWarning, JSMSG_EMPTY_CONSEQUENT)) return null(); } @@ -5766,7 +5776,7 @@ Parser::switchStatement(YieldHandling yieldHandling) switch (tt) { case TOK_DEFAULT: if (seenDefault) { - zeport(ParseError, false, JSMSG_TOO_MANY_DEFAULTS); + qeport(ParseError, JSMSG_TOO_MANY_DEFAULTS); return null(); } seenDefault = true; @@ -5780,7 +5790,7 @@ Parser::switchStatement(YieldHandling yieldHandling) break; default: - zeport(ParseError, false, JSMSG_BAD_SWITCH); + qeport(ParseError, JSMSG_BAD_SWITCH); return null(); } @@ -5863,7 +5873,7 @@ Parser::continueStatement(YieldHandling yieldHandling) stmt = ParseContext::Statement::findNearest(stmt, isLoop); if (!stmt) { if (foundLoop) - zeport(ParseError, false, JSMSG_LABEL_NOT_FOUND); + qeport(ParseError, JSMSG_LABEL_NOT_FOUND); else reportWithOffset(ParseError, false, begin, JSMSG_BAD_CONTINUE); return null(); @@ -5885,7 +5895,7 @@ Parser::continueStatement(YieldHandling yieldHandling) break; } } else if (!pc->findInnermostStatement(isLoop)) { - zeport(ParseError, false, JSMSG_BAD_CONTINUE); + qeport(ParseError, JSMSG_BAD_CONTINUE); return null(); } @@ -5915,7 +5925,7 @@ Parser::breakStatement(YieldHandling yieldHandling) }; if (!pc->findInnermostStatement(hasSameLabel)) { - zeport(ParseError, false, JSMSG_LABEL_NOT_FOUND); + qeport(ParseError, JSMSG_LABEL_NOT_FOUND); return null(); } } else { @@ -6074,7 +6084,7 @@ Parser::yieldExpression(InHandling inHandling) return null(); if (!pc->isFunctionBox()) { - zeport(ParseError, false, JSMSG_BAD_RETURN_OR_YIELD, js_yield_str); + qeport(ParseError, JSMSG_BAD_RETURN_OR_YIELD, js_yield_str); return null(); } @@ -6155,14 +6165,13 @@ Parser::withStatement(YieldHandling yieldHandling) MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_WITH)); uint32_t begin = pos().begin; - // In most cases, we want the constructs forbidden in strict mode code to be - // a subset of those that JSOPTION_EXTRA_WARNINGS warns about, and we should - // use reportStrictModeError. However, 'with' is the sole instance of a - // construct that is forbidden in strict mode code, but doesn't even merit a - // warning under JSOPTION_EXTRA_WARNINGS. See + // Usually we want the constructs forbidden in strict mode code to be a + // subset of those that ContextOptions::extraWarnings() warns about, and we + // use strictModeError directly. But while 'with' is forbidden in strict + // mode code, it doesn't even merit a warning in non-strict code. See // https://bugzilla.mozilla.org/show_bug.cgi?id=514576#c1. if (pc->sc()->strict()) { - if (!zeport(ParseStrictError, true, JSMSG_STRICT_CODE_WITH)) + if (!strictModeError(JSMSG_STRICT_CODE_WITH)) return null(); } @@ -6201,7 +6210,7 @@ Parser::labeledItem(YieldHandling yieldHandling) // GeneratorDeclaration is only matched by HoistableDeclaration in // StatementListItem, so generators can't be inside labels. if (next == TOK_MUL) { - zeport(ParseError, false, JSMSG_GENERATOR_LABEL); + qeport(ParseError, JSMSG_GENERATOR_LABEL); return null(); } @@ -6209,7 +6218,7 @@ Parser::labeledItem(YieldHandling yieldHandling) // is ever matched. Per Annex B.3.2 that modifies this text, this // applies only to strict mode code. if (pc->sc()->strict()) { - zeport(ParseError, false, JSMSG_FUNCTION_LABEL); + qeport(ParseError, JSMSG_FUNCTION_LABEL); return null(); } @@ -6262,11 +6271,11 @@ Parser::throwStatement(YieldHandling yieldHandling) if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand)) return null(); if (tt == TOK_EOF || tt == TOK_SEMI || tt == TOK_RC) { - zeport(ParseError, false, JSMSG_MISSING_EXPR_AFTER_THROW); + qeport(ParseError, JSMSG_MISSING_EXPR_AFTER_THROW); return null(); } if (tt == TOK_EOL) { - zeport(ParseError, false, JSMSG_LINE_BREAK_AFTER_THROW); + qeport(ParseError, JSMSG_LINE_BREAK_AFTER_THROW); return null(); } @@ -6340,7 +6349,7 @@ Parser::tryStatement(YieldHandling yieldHandling) /* Check for another catch after unconditional catch. */ if (hasUnconditionalCatch) { - zeport(ParseError, false, JSMSG_CATCH_AFTER_GENERAL); + qeport(ParseError, JSMSG_CATCH_AFTER_GENERAL); return null(); } @@ -6388,7 +6397,7 @@ Parser::tryStatement(YieldHandling yieldHandling) } default: - zeport(ParseError, false, JSMSG_CATCH_IDENTIFIER); + qeport(ParseError, JSMSG_CATCH_IDENTIFIER); return null(); } @@ -6456,7 +6465,7 @@ Parser::tryStatement(YieldHandling yieldHandling) tokenStream.ungetToken(); } if (!catchList && !finallyBlock) { - zeport(ParseError, false, JSMSG_CATCH_OR_FINALLY); + qeport(ParseError, JSMSG_CATCH_OR_FINALLY); return null(); } @@ -6601,7 +6610,7 @@ Parser::classDefinition(YieldHandling yieldHandling, tokenStream.ungetToken(); } else { // Class statements must have a bound name - zeport(ParseError, false, JSMSG_UNNAMED_CLASS_STMT); + qeport(ParseError, JSMSG_UNNAMED_CLASS_STMT); return null(); } } else { @@ -6662,8 +6671,7 @@ Parser::classDefinition(YieldHandling yieldHandling, return null(); if (tt == TOK_RC) { tokenStream.consumeKnownToken(tt, TokenStream::KeywordIsName); - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, - "property name", TokenKindToDesc(tt)); + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(tt)); return null(); } @@ -6694,7 +6702,7 @@ Parser::classDefinition(YieldHandling yieldHandling, propType != PropertyType::AsyncMethod && propType != PropertyType::Constructor && propType != PropertyType::DerivedConstructor) { - zeport(ParseError, false, JSMSG_BAD_METHOD_DEF); + qeport(ParseError, JSMSG_BAD_METHOD_DEF); return null(); } @@ -6941,7 +6949,7 @@ Parser::statement(YieldHandling yieldHandling) } if (forbiddenLetDeclaration) { - zeport(ParseError, false, JSMSG_FORBIDDEN_AS_STATEMENT, "lexical declarations"); + qeport(ParseError, JSMSG_FORBIDDEN_AS_STATEMENT, "lexical declarations"); return null(); } } @@ -6995,7 +7003,7 @@ Parser::statement(YieldHandling yieldHandling) // detected this way, so don't bother passing around an extra parameter // everywhere. if (!pc->isFunctionBox()) { - zeport(ParseError, false, JSMSG_BAD_RETURN_OR_YIELD, js_return_str); + qeport(ParseError, JSMSG_BAD_RETURN_OR_YIELD, js_return_str); return null(); } return returnStatement(yieldHandling); @@ -7023,12 +7031,12 @@ Parser::statement(YieldHandling yieldHandling) // statement of |if| or |else|, but Parser::consequentOrAlternative // handles that). case TOK_FUNCTION: - zeport(ParseError, false, JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations"); + qeport(ParseError, JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations"); return null(); // |class| is also forbidden by lookahead restriction. case TOK_CLASS: - zeport(ParseError, false, JSMSG_FORBIDDEN_AS_STATEMENT, "classes"); + qeport(ParseError, JSMSG_FORBIDDEN_AS_STATEMENT, "classes"); return null(); // ImportDeclaration (only inside modules) @@ -7042,11 +7050,11 @@ Parser::statement(YieldHandling yieldHandling) // Miscellaneous error cases arguably better caught here than elsewhere. case TOK_CATCH: - zeport(ParseError, false, JSMSG_CATCH_WITHOUT_TRY); + qeport(ParseError, JSMSG_CATCH_WITHOUT_TRY); return null(); case TOK_FINALLY: - zeport(ParseError, false, JSMSG_FINALLY_WITHOUT_TRY); + qeport(ParseError, JSMSG_FINALLY_WITHOUT_TRY); return null(); // NOTE: default case handled in the ExpressionStatement section. @@ -7087,7 +7095,7 @@ Parser::statementListItem(YieldHandling yieldHandling, if (!canHaveDirectives && tokenStream.currentToken().atom() == context->names().useAsm) { if (!abortIfSyntaxParser()) return null(); - if (!zeport(ParseWarning, false, JSMSG_USE_ASM_DIRECTIVE_FAIL)) + if (!qeport(ParseWarning, JSMSG_USE_ASM_DIRECTIVE_FAIL)) return null(); } return expressionStatement(yieldHandling); @@ -7181,7 +7189,7 @@ Parser::statementListItem(YieldHandling yieldHandling, // detected this way, so don't bother passing around an extra parameter // everywhere. if (!pc->isFunctionBox()) { - zeport(ParseError, false, JSMSG_BAD_RETURN_OR_YIELD, js_return_str); + qeport(ParseError, JSMSG_BAD_RETURN_OR_YIELD, js_return_str); return null(); } return returnStatement(yieldHandling); @@ -7233,11 +7241,11 @@ Parser::statementListItem(YieldHandling yieldHandling, // Miscellaneous error cases arguably better caught here than elsewhere. case TOK_CATCH: - zeport(ParseError, false, JSMSG_CATCH_WITHOUT_TRY); + qeport(ParseError, JSMSG_CATCH_WITHOUT_TRY); return null(); case TOK_FINALLY: - zeport(ParseError, false, JSMSG_FINALLY_WITHOUT_TRY); + qeport(ParseError, JSMSG_FINALLY_WITHOUT_TRY); return null(); // NOTE: default case handled in the ExpressionStatement section. @@ -7282,7 +7290,7 @@ Parser::expr(InHandling inHandling, YieldHandling yieldHandling, if (!tokenStream.peekToken(&tt)) return null(); if (tt != TOK_ARROW) { - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(TOK_RP)); return null(); } @@ -7440,7 +7448,7 @@ Parser::orExpr1(InHandling inHandling, YieldHandling yieldHandling return null(); // Report an error for unary expressions on the LHS of **. if (tok == TOK_POW && handler.isUnparenthesizedUnaryExpression(pn)) { - zeport(ParseError, false, JSMSG_BAD_POW_LEFTSIDE); + qeport(ParseError, JSMSG_BAD_POW_LEFTSIDE); return null(); } pnk = BinaryOpTokenKindToParseNodeKind(tok); @@ -7521,7 +7529,7 @@ Parser::checkAndMarkAsAssignmentLhs(Node target, AssignmentFlavor if (handler.isUnparenthesizedDestructuringPattern(target)) { if (flavor == CompoundAssignment) { - zeport(ParseError, false, JSMSG_BAD_DESTRUCT_ASS); + qeport(ParseError, JSMSG_BAD_DESTRUCT_ASS); return false; } @@ -7660,7 +7668,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl if (!tokenStream.getToken(&tt)) return null(); if (tt != TOK_ARROW) { - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "'=>' after argument list", TokenKindToDesc(tt)); return null(); @@ -7699,7 +7707,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl MOZ_ASSERT(next == TOK_ARROW || next == TOK_EOL); if (next != TOK_ARROW) { - zeport(ParseError, false, JSMSG_LINE_BREAK_BEFORE_ARROW); + qeport(ParseError, JSMSG_LINE_BREAK_BEFORE_ARROW); return null(); } tokenStream.consumeKnownToken(TOK_ARROW); @@ -8019,7 +8027,7 @@ Parser::unaryExpr(YieldHandling yieldHandling, TripledotHandling t if (!pc->isAsync()) { // TOK_AWAIT can be returned in module, even if it's not inside // async function. - zeport(ParseError, false, JSMSG_RESERVED_ID, "await"); + qeport(ParseError, JSMSG_RESERVED_ID, "await"); return null(); } @@ -8172,7 +8180,7 @@ Parser::comprehensionFor(GeneratorKind comprehensionKind) MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_VARIABLE_NAME); RootedPropertyName name(context, tokenStream.currentName()); if (name == context->names().let) { - zeport(ParseError, false, JSMSG_LET_COMP_BINDING); + qeport(ParseError, JSMSG_LET_COMP_BINDING); return null(); } TokenPos namePos = pos(); @@ -8183,7 +8191,7 @@ Parser::comprehensionFor(GeneratorKind comprehensionKind) if (!tokenStream.matchContextualKeyword(&matched, context->names().of)) return null(); if (!matched) { - zeport(ParseError, false, JSMSG_OF_AFTER_FOR_NAME); + qeport(ParseError, JSMSG_OF_AFTER_FOR_NAME); return null(); } @@ -8244,7 +8252,7 @@ Parser::comprehensionIf(GeneratorKind comprehensionKind) /* Check for (a = b) and warn about possible (a == b) mistype. */ if (handler.isUnparenthesizedAssignment(cond)) { - if (!zeport(ParseExtraWarning, false, JSMSG_EQUAL_AS_ASSIGN)) + if (!qeport(ParseExtraWarning, JSMSG_EQUAL_AS_ASSIGN)) return null(); } @@ -8521,14 +8529,14 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling if (tt == TOK_NAME) { PropertyName* field = tokenStream.currentName(); if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) { - zeport(ParseError, false, JSMSG_BAD_SUPERPROP, "property"); + qeport(ParseError, JSMSG_BAD_SUPERPROP, "property"); return null(); } nextMember = handler.newPropertyAccess(lhs, field, pos().end); if (!nextMember) return null(); } else { - zeport(ParseError, false, JSMSG_NAME_AFTER_DOT); + qeport(ParseError, JSMSG_NAME_AFTER_DOT); return null(); } } else if (tt == TOK_LB) { @@ -8539,7 +8547,7 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX); if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) { - zeport(ParseError, false, JSMSG_BAD_SUPERPROP, "member"); + qeport(ParseError, JSMSG_BAD_SUPERPROP, "member"); return null(); } nextMember = handler.newPropertyByValue(lhs, propExpr, pos().end); @@ -8551,12 +8559,12 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling { if (handler.isSuperBase(lhs)) { if (!pc->sc()->allowSuperCall()) { - zeport(ParseError, false, JSMSG_BAD_SUPERCALL); + qeport(ParseError, JSMSG_BAD_SUPERCALL); return null(); } if (tt != TOK_LP) { - zeport(ParseError, false, JSMSG_BAD_SUPER); + qeport(ParseError, JSMSG_BAD_SUPER); return null(); } @@ -8583,7 +8591,7 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling return null(); } else { if (options().selfHostingMode && handler.isPropertyAccess(lhs)) { - zeport(ParseError, false, JSMSG_SELFHOSTED_METHOD_CALL); + qeport(ParseError, JSMSG_SELFHOSTED_METHOD_CALL); return null(); } @@ -8665,7 +8673,7 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling } if (handler.isSuperBase(lhs)) { - zeport(ParseError, false, JSMSG_BAD_SUPER); + qeport(ParseError, JSMSG_BAD_SUPER); return null(); } @@ -8718,7 +8726,7 @@ Parser::labelOrIdentifierReference(YieldHandling yieldHandling, ? "static" : nullptr; if (badName) { - zeport(ParseError, false, JSMSG_RESERVED_ID, badName); + qeport(ParseError, JSMSG_RESERVED_ID, badName); return nullptr; } } @@ -8727,7 +8735,7 @@ Parser::labelOrIdentifierReference(YieldHandling yieldHandling, pc->sc()->strict() || versionNumber() >= JSVERSION_1_7) { - zeport(ParseError, false, JSMSG_RESERVED_ID, "yield"); + qeport(ParseError, JSMSG_RESERVED_ID, "yield"); return nullptr; } } @@ -8763,7 +8771,7 @@ Parser::bindingIdentifier(YieldHandling yieldHandling) ? "eval" : nullptr; if (badName) { - zeport(ParseError, false, JSMSG_BAD_STRICT_ASSIGN, badName); + qeport(ParseError, JSMSG_BAD_STRICT_ASSIGN, badName); return nullptr; } @@ -8773,7 +8781,7 @@ Parser::bindingIdentifier(YieldHandling yieldHandling) ? "static" : nullptr; if (badName) { - zeport(ParseError, false, JSMSG_RESERVED_ID, badName); + qeport(ParseError, JSMSG_RESERVED_ID, badName); return nullptr; } } @@ -8782,7 +8790,7 @@ Parser::bindingIdentifier(YieldHandling yieldHandling) pc->sc()->strict() || versionNumber() >= JSVERSION_1_7) { - zeport(ParseError, false, JSMSG_RESERVED_ID, "yield"); + qeport(ParseError, JSMSG_RESERVED_ID, "yield"); return nullptr; } } @@ -8881,7 +8889,7 @@ Parser::arrayInitializer(YieldHandling yieldHandling, PossibleErro TokenStream::Modifier modifier = TokenStream::Operand; for (; ; index++) { if (index >= NativeObject::MAX_DENSE_ELEMENTS_COUNT) { - zeport(ParseError, false, JSMSG_ARRAY_INIT_TOO_BIG); + qeport(ParseError, JSMSG_ARRAY_INIT_TOO_BIG); return null(); } @@ -8991,7 +8999,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, } if (isAsync && isGenerator) { - zeport(ParseError, false, JSMSG_ASYNC_GENERATOR); + qeport(ParseError, JSMSG_ASYNC_GENERATOR); return null(); } @@ -9104,7 +9112,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, } default: - zeport(ParseError, false, JSMSG_BAD_PROP_ID); + qeport(ParseError, JSMSG_BAD_PROP_ID); return null(); } @@ -9114,7 +9122,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, if (tt == TOK_COLON) { if (isGenerator) { - zeport(ParseError, false, JSMSG_BAD_PROP_ID); + qeport(ParseError, JSMSG_BAD_PROP_ID); return null(); } *propType = PropertyType::Normal; @@ -9123,7 +9131,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, if (ltok == TOK_NAME && (tt == TOK_COMMA || tt == TOK_RC || tt == TOK_ASSIGN)) { if (isGenerator) { - zeport(ParseError, false, JSMSG_BAD_PROP_ID); + qeport(ParseError, JSMSG_BAD_PROP_ID); return null(); } tokenStream.ungetToken(); @@ -9144,7 +9152,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, return propName; } - zeport(ParseError, false, JSMSG_COLON_AFTER_ID); + qeport(ParseError, JSMSG_COLON_AFTER_ID); return null(); } @@ -9255,7 +9263,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* return null(); if (propToken != TOK_NAME && propToken != TOK_YIELD) { - zeport(ParseError, false, JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); + qeport(ParseError, JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); return null(); } @@ -9280,7 +9288,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* return null(); if (propToken != TOK_NAME && propToken != TOK_YIELD) { - zeport(ParseError, false, JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); + qeport(ParseError, JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); return null(); } @@ -9304,7 +9312,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* // Destructuring defaults are definitely not allowed in this object literal, // because of something the caller knows about the preceding code. // For example, maybe the preceding token is an operator: `x + {y=z}`. - zeport(ParseError, false, JSMSG_COLON_AFTER_ID); + qeport(ParseError, JSMSG_COLON_AFTER_ID); return null(); } @@ -9363,7 +9371,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* if (tt == TOK_RC) break; if (tt != TOK_COMMA) { - zeport(ParseError, false, JSMSG_CURLY_AFTER_LIST); + qeport(ParseError, JSMSG_CURLY_AFTER_LIST); return null(); } } @@ -9412,7 +9420,7 @@ Parser::tryNewTarget(Node &newTarget) if (!tokenStream.getToken(&next)) return false; if (next != TOK_NAME || tokenStream.currentName() != context->names().target) { - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "target", TokenKindToDesc(next)); + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "target", TokenKindToDesc(next)); return false; } @@ -9467,7 +9475,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling if (!tokenStream.peekToken(&next)) return null(); if (next != TOK_ARROW) { - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(TOK_RP)); return null(); } @@ -9555,7 +9563,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling // name, closing parenthesis, and arrow, and allow it only if all are // present. if (tripledotHandling != TripledotAllowed) { - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); return null(); } @@ -9577,8 +9585,8 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling // or "arguments" should be prohibited. Argument-parsing code // handles that. if (next != TOK_NAME && next != TOK_YIELD) { - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, - "rest argument name", TokenKindToDesc(next)); + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, + "rest argument name", TokenKindToDesc(next)); return null(); } } @@ -9586,7 +9594,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling if (!tokenStream.getToken(&next)) return null(); if (next != TOK_RP) { - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "closing parenthesis", TokenKindToDesc(next)); return null(); } @@ -9596,7 +9604,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling if (next != TOK_ARROW) { // Advance the scanner for proper error location reporting. tokenStream.consumeKnownToken(next); - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "'=>' after argument list", TokenKindToDesc(next)); return null(); } @@ -9608,7 +9616,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling } default: - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); return null(); } } @@ -9633,7 +9641,7 @@ Parser::warnOnceAboutExprClosure() return true; if (!cx->compartment()->warnedAboutExprClosure) { - if (!zeport(ParseWarning, false, JSMSG_DEPRECATED_EXPR_CLOSURE)) + if (!qeport(ParseWarning, JSMSG_DEPRECATED_EXPR_CLOSURE)) return false; cx->compartment()->warnedAboutExprClosure = true; } @@ -9651,7 +9659,7 @@ Parser::warnOnceAboutForEach() if (!cx->compartment()->warnedAboutForEach) { // Disabled warning spew. - // if (!zeport(ParseWarning, false, JSMSG_DEPRECATED_FOR_EACH)) + // if (!qeport(ParseWarning, JSMSG_DEPRECATED_FOR_EACH)) // return false; cx->compartment()->warnedAboutForEach = true; } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 88d705108..402b977ba 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -907,12 +907,19 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool reportHelper(ParseReportKind kind, bool strict, uint32_t offset, unsigned errorNumber, va_list args); public: - bool zeport(ParseReportKind kind, bool strict, unsigned errorNumber, ...); + bool qeport(ParseReportKind kind, unsigned errorNumber, ...); bool reportWithNode(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...); bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...); bool reportWithOffset(ParseReportKind kind, bool strict, uint32_t offset, unsigned errorNumber, ...); + /* + * Handle a strict mode error at the current offset. Report an error if in + * strict mode code, or warn if not, using the given error number and + * arguments. + */ + MOZ_MUST_USE bool strictModeError(unsigned errorNumber, ...); + Parser(ExclusiveContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options, const char16_t* chars, size_t length, bool foldConstants, UsedNameTracker& usedNames, Parser* syntaxParser, LazyScript* lazyOuterFunction); -- cgit v1.2.3 From 2950deb043a403377a589046acaa38cfe3dc9876 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 5 Apr 2019 21:25:28 +0200 Subject: Change report at current offset to warning(), extraWarning() and error() --- js/src/frontend/Parser.cpp | 261 ++++++++++++++++++++++++--------------------- js/src/frontend/Parser.h | 13 ++- 2 files changed, 152 insertions(+), 122 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index a29287850..8ad8813b5 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -63,13 +63,13 @@ using BindingIter = ParseContext::Scope::BindingIter; using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr; /* Read a token. Report an error and return null() if that token isn't of type tt. */ -#define MUST_MATCH_TOKEN_MOD(tt, modifier, errno) \ +#define MUST_MATCH_TOKEN_MOD(tt, modifier, errorNumber) \ JS_BEGIN_MACRO \ TokenKind token; \ if (!tokenStream.getToken(&token, modifier)) \ return null(); \ if (token != tt) { \ - qeport(ParseError, errno); \ + error(errorNumber); \ return null(); \ } \ JS_END_MACRO @@ -594,13 +594,38 @@ Parser::reportHelper(ParseReportKind kind, bool strict, uint32_t o return result; } +template +void +Parser::error(unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); +#ifdef DEBUG + bool result = +#endif + reportHelper(ParseError, false, pos().begin, errorNumber, args); + MOZ_ASSERT(!result, "reporting an error returned true?"); + va_end(args); +} + +template +bool +Parser::warning(unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); + bool result = reportHelper(ParseWarning, false, pos().begin, errorNumber, args); + va_end(args); + return result; +} + template bool -Parser::qeport(ParseReportKind kind, unsigned errorNumber, ...) +Parser::extraWarning(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool result = reportHelper(kind, false, pos().begin, errorNumber, args); + bool result = reportHelper(ParseExtraWarning, false, pos().begin, errorNumber, args); va_end(args); return result; } @@ -848,7 +873,7 @@ Parser::parse() if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); if (tt != TOK_EOF) { - qeport(ParseError, JSMSG_GARBAGE_AFTER_INPUT, "script", TokenKindToDesc(tt)); + error(JSMSG_GARBAGE_AFTER_INPUT, "script", TokenKindToDesc(tt)); return null(); } if (foldConstants) { @@ -962,7 +987,7 @@ Parser::notePositionalFormalParameter(Node fn, HandlePropertyName { if (AddDeclaredNamePtr p = pc->functionScope().lookupDeclaredNameForAdd(name)) { if (disallowDuplicateParams) { - qeport(ParseError, JSMSG_BAD_DUP_ARGS); + error(JSMSG_BAD_DUP_ARGS); return false; } @@ -1257,7 +1282,7 @@ Parser::noteDeclaredName(HandlePropertyName name, DeclarationKind AddDeclaredNamePtr p = pc->functionScope().lookupDeclaredNameForAdd(name); if (p) { - qeport(ParseError, JSMSG_BAD_DUP_ARGS); + error(JSMSG_BAD_DUP_ARGS); return false; } @@ -1464,7 +1489,7 @@ Parser::checkStatementsEOF() if (!tokenStream.peekToken(&tt, TokenStream::Operand)) return false; if (tt != TOK_EOF) { - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); + error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); return false; } return true; @@ -1929,7 +1954,7 @@ Parser::evalBody(EvalSharedContext* evalsc) // script. if (hasUsedName(context->names().arguments)) { if (IsArgumentsUsedInLegacyGenerator(context, pc->sc()->compilationEnclosingScope())) { - qeport(ParseError, JSMSG_BAD_GENEXP_BODY, js_arguments_str); + error(JSMSG_BAD_GENEXP_BODY, js_arguments_str); return nullptr; } } @@ -2027,7 +2052,7 @@ Parser::moduleBody(ModuleSharedContext* modulesc) if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); if (tt != TOK_EOF) { - qeport(ParseError, JSMSG_GARBAGE_AFTER_INPUT, "module", TokenKindToDesc(tt)); + error(JSMSG_GARBAGE_AFTER_INPUT, "module", TokenKindToDesc(tt)); return null(); } @@ -2347,7 +2372,7 @@ Parser::standaloneFunction(HandleFunction fun, if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); if (tt != TOK_EOF) { - qeport(ParseError, JSMSG_GARBAGE_AFTER_INPUT, "function body", TokenKindToDesc(tt)); + error(JSMSG_GARBAGE_AFTER_INPUT, "function body", TokenKindToDesc(tt)); return null(); } @@ -2752,7 +2777,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn if (!tokenStream.getToken(&tt, firstTokenModifier)) return false; if (tt != TOK_LP) { - qeport(ParseError, kind == Arrow ? JSMSG_BAD_ARROW_ARGS : JSMSG_PAREN_BEFORE_FORMAL); + error(kind == Arrow ? JSMSG_BAD_ARROW_ARGS : JSMSG_PAREN_BEFORE_FORMAL); return false; } @@ -2784,13 +2809,13 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn AtomVector& positionalFormals = pc->positionalFormalParameterNames(); if (IsGetterKind(kind)) { - qeport(ParseError, JSMSG_ACCESSOR_WRONG_ARGS, "getter", "no", "s"); + error(JSMSG_ACCESSOR_WRONG_ARGS, "getter", "no", "s"); return false; } while (true) { if (hasRest) { - qeport(ParseError, JSMSG_PARAMETER_AFTER_REST); + error(JSMSG_PARAMETER_AFTER_REST); return false; } @@ -2802,14 +2827,14 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn if (tt == TOK_TRIPLEDOT) { if (IsSetterKind(kind)) { - qeport(ParseError, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); + error(JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); return false; } disallowDuplicateParams = true; if (duplicatedParam) { // Has duplicated args before the rest parameter. - qeport(ParseError, JSMSG_BAD_DUP_ARGS); + error(JSMSG_BAD_DUP_ARGS); return false; } @@ -2820,7 +2845,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn return false; if (tt != TOK_NAME && tt != TOK_YIELD && tt != TOK_LB && tt != TOK_LC) { - qeport(ParseError, JSMSG_NO_REST_NAME); + error(JSMSG_NO_REST_NAME); return false; } } @@ -2831,7 +2856,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn disallowDuplicateParams = true; if (duplicatedParam) { // Has duplicated args before the destructuring parameter. - qeport(ParseError, JSMSG_BAD_DUP_ARGS); + error(JSMSG_BAD_DUP_ARGS); return false; } @@ -2859,7 +2884,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn // case: // // async await => 1 - qeport(ParseError, JSMSG_RESERVED_ID, "await"); + error(JSMSG_RESERVED_ID, "await"); return false; } @@ -2879,12 +2904,12 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn } default: - qeport(ParseError, JSMSG_MISSING_FORMAL); + error(JSMSG_MISSING_FORMAL); return false; } if (positionalFormals.length() >= ARGNO_LIMIT) { - qeport(ParseError, JSMSG_TOO_MANY_FUN_ARGS); + error(JSMSG_TOO_MANY_FUN_ARGS); return false; } @@ -2899,12 +2924,12 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn MOZ_ASSERT(!parenFreeArrow); if (hasRest) { - qeport(ParseError, JSMSG_REST_WITH_DEFAULT); + error(JSMSG_REST_WITH_DEFAULT); return false; } disallowDuplicateParams = true; if (duplicatedParam) { - qeport(ParseError, JSMSG_BAD_DUP_ARGS); + error(JSMSG_BAD_DUP_ARGS); return false; } @@ -2948,11 +2973,11 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn return false; if (tt != TOK_RP) { if (IsSetterKind(kind)) { - qeport(ParseError, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); + error(JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); return false; } - qeport(ParseError, JSMSG_PAREN_AFTER_FORMAL); + error(JSMSG_PAREN_AFTER_FORMAL); return false; } } @@ -2965,7 +2990,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn funbox->function()->setArgCount(positionalFormals.length()); } else if (IsSetterKind(kind)) { - qeport(ParseError, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); + error(JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); return false; } @@ -3095,7 +3120,7 @@ Parser::addExprAndGetNextTemplStrToken(YieldHandling yieldHandling if (!tokenStream.getToken(&tt)) return false; if (tt != TOK_RC) { - qeport(ParseError, JSMSG_TEMPLSTR_UNTERM_EXPR); + error(JSMSG_TEMPLSTR_UNTERM_EXPR); return false; } @@ -3487,7 +3512,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if (!tokenStream.matchToken(&matched, TOK_ARROW)) return false; if (!matched) { - qeport(ParseError, JSMSG_BAD_ARROW_ARGS); + error(JSMSG_BAD_ARROW_ARGS); return false; } } @@ -3495,7 +3520,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, // When parsing something for new Function() we have to make sure to // only treat a certain part of the source as a parameter list. if (parameterListEnd.isSome() && parameterListEnd.value() != pos().begin) { - qeport(ParseError, JSMSG_UNEXPECTED_PARAMLIST_END); + error(JSMSG_UNEXPECTED_PARAMLIST_END); return false; } @@ -3508,7 +3533,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if ((funbox->isStarGenerator() && !funbox->isAsync()) || kind == Method || kind == GetterNoExpressionClosure || kind == SetterNoExpressionClosure || IsConstructorKind(kind)) { - qeport(ParseError, JSMSG_CURLY_BEFORE_BODY); + error(JSMSG_CURLY_BEFORE_BODY); return false; } @@ -3517,7 +3542,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if (!warnOnceAboutExprClosure()) return false; #else - qeport(ParseError, JSMSG_CURLY_BEFORE_BODY); + error(JSMSG_CURLY_BEFORE_BODY); return false; #endif } @@ -3550,7 +3575,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if (!tokenStream.matchToken(&matched, TOK_RC, TokenStream::Operand)) return false; if (!matched) { - qeport(ParseError, JSMSG_CURLY_AFTER_BODY); + error(JSMSG_CURLY_AFTER_BODY); return false; } funbox->bufEnd = pos().end; @@ -3608,7 +3633,7 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan if (tt == TOK_MUL) { if (asyncKind != SyncFunction) { - qeport(ParseError, JSMSG_ASYNC_GENERATOR); + error(JSMSG_ASYNC_GENERATOR); return null(); } generatorKind = StarGenerator; @@ -3625,7 +3650,7 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan tokenStream.ungetToken(); } else { /* Unnamed function expressions are forbidden in statement context. */ - qeport(ParseError, JSMSG_UNNAMED_FUNCTION_STMT); + error(JSMSG_UNNAMED_FUNCTION_STMT); return null(); } @@ -3661,7 +3686,7 @@ Parser::functionExpr(uint32_t preludeStart, InvokedPrediction invo if (tt == TOK_MUL) { if (asyncKind != SyncFunction) { - qeport(ParseError, JSMSG_ASYNC_GENERATOR); + error(JSMSG_ASYNC_GENERATOR); return null(); } generatorKind = StarGenerator; @@ -3834,7 +3859,7 @@ Parser::maybeParseDirective(Node list, Node pn, bool* cont) // occur in the directive prologue -- octal escapes -- and // complain now. if (tokenStream.sawOctalEscape()) { - qeport(ParseError, JSMSG_DEPRECATED_OCTAL); + error(JSMSG_DEPRECATED_OCTAL); return false; } pc->sc()->strictScript = true; @@ -3921,7 +3946,7 @@ Parser::condition(InHandling inHandling, YieldHandling yieldHandli /* Check for (a = b) and warn about possible (a == b) mistype. */ if (handler.isUnparenthesizedAssignment(pn)) { - if (!qeport(ParseExtraWarning, JSMSG_EQUAL_AS_ASSIGN)) + if (!extraWarning(JSMSG_EQUAL_AS_ASSIGN)) return null(); } return pn; @@ -4503,7 +4528,7 @@ Parser::declarationName(Node decl, DeclarationKind declKind, Token { // Anything other than TOK_YIELD or TOK_NAME is an error. if (tt != TOK_NAME && tt != TOK_YIELD) { - qeport(ParseError, JSMSG_NO_VARIABLE_NAME); + error(JSMSG_NO_VARIABLE_NAME); return null(); } @@ -4703,7 +4728,7 @@ Parser::namedImportsOrNamespaceImport(TokenKind tt, Node impor return false; if (afterAs != TOK_NAME && afterAs != TOK_YIELD) { - qeport(ParseError, JSMSG_NO_BINDING_NAME); + error(JSMSG_NO_BINDING_NAME); return false; } } else { @@ -4715,7 +4740,7 @@ Parser::namedImportsOrNamespaceImport(TokenKind tt, Node impor JSAutoByteString bytes; if (!AtomToPrintableString(context, importName, &bytes)) return false; - qeport(ParseError, JSMSG_AS_AFTER_RESERVED_WORD, bytes.ptr()); + error(JSMSG_AS_AFTER_RESERVED_WORD, bytes.ptr()); return false; } } @@ -4812,7 +4837,7 @@ Parser::importDeclaration() MOZ_ASSERT(tokenStream.currentToken().type == TOK_IMPORT); if (!pc->atModuleLevel()) { - qeport(ParseError, JSMSG_IMPORT_DECL_AT_TOP_LEVEL); + error(JSMSG_IMPORT_DECL_AT_TOP_LEVEL); return null(); } @@ -4861,7 +4886,7 @@ Parser::importDeclaration() return null(); if (tt != TOK_LC && tt != TOK_MUL) { - qeport(ParseError, JSMSG_NAMED_IMPORTS_OR_NAMESPACE_IMPORT); + error(JSMSG_NAMED_IMPORTS_OR_NAMESPACE_IMPORT); return null(); } @@ -4877,7 +4902,7 @@ Parser::importDeclaration() return null(); if (tt != TOK_NAME || tokenStream.currentName() != context->names().from) { - qeport(ParseError, JSMSG_FROM_AFTER_IMPORT_CLAUSE); + error(JSMSG_FROM_AFTER_IMPORT_CLAUSE); return null(); } @@ -4890,7 +4915,7 @@ Parser::importDeclaration() // equivalent to |import {} from 'a'|. importSpecSet->pn_pos.end = importSpecSet->pn_pos.begin; } else { - qeport(ParseError, JSMSG_DECLARATION_AFTER_IMPORT); + error(JSMSG_DECLARATION_AFTER_IMPORT); return null(); } @@ -4928,7 +4953,7 @@ Parser::checkExportedName(JSAtom* exportName) if (!AtomToPrintableString(context, exportName, &str)) return false; - qeport(ParseError, JSMSG_DUPLICATE_EXPORT_NAME, str.ptr()); + error(JSMSG_DUPLICATE_EXPORT_NAME, str.ptr()); return false; } @@ -4971,7 +4996,7 @@ Parser::exportDeclaration() MOZ_ASSERT(tokenStream.currentToken().type == TOK_EXPORT); if (!pc->atModuleLevel()) { - qeport(ParseError, JSMSG_EXPORT_DECL_AT_TOP_LEVEL); + error(JSMSG_EXPORT_DECL_AT_TOP_LEVEL); return null(); } @@ -5090,7 +5115,7 @@ Parser::exportDeclaration() if (!tokenStream.getToken(&tt)) return null(); if (tt != TOK_NAME || tokenStream.currentName() != context->names().from) { - qeport(ParseError, JSMSG_FROM_AFTER_EXPORT_STAR); + error(JSMSG_FROM_AFTER_EXPORT_STAR); return null(); } @@ -5226,7 +5251,7 @@ Parser::exportDeclaration() MOZ_FALLTHROUGH; default: - qeport(ParseError, JSMSG_DECLARATION_AFTER_EXPORT); + error(JSMSG_DECLARATION_AFTER_EXPORT); return null(); } @@ -5302,7 +5327,7 @@ Parser::ifStatement(YieldHandling yieldHandling) if (!tokenStream.peekToken(&tt, TokenStream::Operand)) return null(); if (tt == TOK_SEMI) { - if (!qeport(ParseExtraWarning, JSMSG_EMPTY_CONSEQUENT)) + if (!extraWarning(JSMSG_EMPTY_CONSEQUENT)) return null(); } @@ -5776,7 +5801,7 @@ Parser::switchStatement(YieldHandling yieldHandling) switch (tt) { case TOK_DEFAULT: if (seenDefault) { - qeport(ParseError, JSMSG_TOO_MANY_DEFAULTS); + error(JSMSG_TOO_MANY_DEFAULTS); return null(); } seenDefault = true; @@ -5790,7 +5815,7 @@ Parser::switchStatement(YieldHandling yieldHandling) break; default: - qeport(ParseError, JSMSG_BAD_SWITCH); + error(JSMSG_BAD_SWITCH); return null(); } @@ -5873,7 +5898,7 @@ Parser::continueStatement(YieldHandling yieldHandling) stmt = ParseContext::Statement::findNearest(stmt, isLoop); if (!stmt) { if (foundLoop) - qeport(ParseError, JSMSG_LABEL_NOT_FOUND); + error(JSMSG_LABEL_NOT_FOUND); else reportWithOffset(ParseError, false, begin, JSMSG_BAD_CONTINUE); return null(); @@ -5895,7 +5920,7 @@ Parser::continueStatement(YieldHandling yieldHandling) break; } } else if (!pc->findInnermostStatement(isLoop)) { - qeport(ParseError, JSMSG_BAD_CONTINUE); + error(JSMSG_BAD_CONTINUE); return null(); } @@ -5925,7 +5950,7 @@ Parser::breakStatement(YieldHandling yieldHandling) }; if (!pc->findInnermostStatement(hasSameLabel)) { - qeport(ParseError, JSMSG_LABEL_NOT_FOUND); + error(JSMSG_LABEL_NOT_FOUND); return null(); } } else { @@ -6084,7 +6109,7 @@ Parser::yieldExpression(InHandling inHandling) return null(); if (!pc->isFunctionBox()) { - qeport(ParseError, JSMSG_BAD_RETURN_OR_YIELD, js_yield_str); + error(JSMSG_BAD_RETURN_OR_YIELD, js_yield_str); return null(); } @@ -6210,7 +6235,7 @@ Parser::labeledItem(YieldHandling yieldHandling) // GeneratorDeclaration is only matched by HoistableDeclaration in // StatementListItem, so generators can't be inside labels. if (next == TOK_MUL) { - qeport(ParseError, JSMSG_GENERATOR_LABEL); + error(JSMSG_GENERATOR_LABEL); return null(); } @@ -6218,7 +6243,7 @@ Parser::labeledItem(YieldHandling yieldHandling) // is ever matched. Per Annex B.3.2 that modifies this text, this // applies only to strict mode code. if (pc->sc()->strict()) { - qeport(ParseError, JSMSG_FUNCTION_LABEL); + error(JSMSG_FUNCTION_LABEL); return null(); } @@ -6271,11 +6296,11 @@ Parser::throwStatement(YieldHandling yieldHandling) if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand)) return null(); if (tt == TOK_EOF || tt == TOK_SEMI || tt == TOK_RC) { - qeport(ParseError, JSMSG_MISSING_EXPR_AFTER_THROW); + error(JSMSG_MISSING_EXPR_AFTER_THROW); return null(); } if (tt == TOK_EOL) { - qeport(ParseError, JSMSG_LINE_BREAK_AFTER_THROW); + error(JSMSG_LINE_BREAK_AFTER_THROW); return null(); } @@ -6349,7 +6374,7 @@ Parser::tryStatement(YieldHandling yieldHandling) /* Check for another catch after unconditional catch. */ if (hasUnconditionalCatch) { - qeport(ParseError, JSMSG_CATCH_AFTER_GENERAL); + error(JSMSG_CATCH_AFTER_GENERAL); return null(); } @@ -6397,7 +6422,7 @@ Parser::tryStatement(YieldHandling yieldHandling) } default: - qeport(ParseError, JSMSG_CATCH_IDENTIFIER); + error(JSMSG_CATCH_IDENTIFIER); return null(); } @@ -6465,7 +6490,7 @@ Parser::tryStatement(YieldHandling yieldHandling) tokenStream.ungetToken(); } if (!catchList && !finallyBlock) { - qeport(ParseError, JSMSG_CATCH_OR_FINALLY); + error(JSMSG_CATCH_OR_FINALLY); return null(); } @@ -6610,7 +6635,7 @@ Parser::classDefinition(YieldHandling yieldHandling, tokenStream.ungetToken(); } else { // Class statements must have a bound name - qeport(ParseError, JSMSG_UNNAMED_CLASS_STMT); + error(JSMSG_UNNAMED_CLASS_STMT); return null(); } } else { @@ -6671,7 +6696,7 @@ Parser::classDefinition(YieldHandling yieldHandling, return null(); if (tt == TOK_RC) { tokenStream.consumeKnownToken(tt, TokenStream::KeywordIsName); - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(tt)); + error(JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(tt)); return null(); } @@ -6702,7 +6727,7 @@ Parser::classDefinition(YieldHandling yieldHandling, propType != PropertyType::AsyncMethod && propType != PropertyType::Constructor && propType != PropertyType::DerivedConstructor) { - qeport(ParseError, JSMSG_BAD_METHOD_DEF); + error(JSMSG_BAD_METHOD_DEF); return null(); } @@ -6949,7 +6974,7 @@ Parser::statement(YieldHandling yieldHandling) } if (forbiddenLetDeclaration) { - qeport(ParseError, JSMSG_FORBIDDEN_AS_STATEMENT, "lexical declarations"); + error(JSMSG_FORBIDDEN_AS_STATEMENT, "lexical declarations"); return null(); } } @@ -7003,7 +7028,7 @@ Parser::statement(YieldHandling yieldHandling) // detected this way, so don't bother passing around an extra parameter // everywhere. if (!pc->isFunctionBox()) { - qeport(ParseError, JSMSG_BAD_RETURN_OR_YIELD, js_return_str); + error(JSMSG_BAD_RETURN_OR_YIELD, js_return_str); return null(); } return returnStatement(yieldHandling); @@ -7031,12 +7056,12 @@ Parser::statement(YieldHandling yieldHandling) // statement of |if| or |else|, but Parser::consequentOrAlternative // handles that). case TOK_FUNCTION: - qeport(ParseError, JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations"); + error(JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations"); return null(); // |class| is also forbidden by lookahead restriction. case TOK_CLASS: - qeport(ParseError, JSMSG_FORBIDDEN_AS_STATEMENT, "classes"); + error(JSMSG_FORBIDDEN_AS_STATEMENT, "classes"); return null(); // ImportDeclaration (only inside modules) @@ -7050,11 +7075,11 @@ Parser::statement(YieldHandling yieldHandling) // Miscellaneous error cases arguably better caught here than elsewhere. case TOK_CATCH: - qeport(ParseError, JSMSG_CATCH_WITHOUT_TRY); + error(JSMSG_CATCH_WITHOUT_TRY); return null(); case TOK_FINALLY: - qeport(ParseError, JSMSG_FINALLY_WITHOUT_TRY); + error(JSMSG_FINALLY_WITHOUT_TRY); return null(); // NOTE: default case handled in the ExpressionStatement section. @@ -7095,7 +7120,7 @@ Parser::statementListItem(YieldHandling yieldHandling, if (!canHaveDirectives && tokenStream.currentToken().atom() == context->names().useAsm) { if (!abortIfSyntaxParser()) return null(); - if (!qeport(ParseWarning, JSMSG_USE_ASM_DIRECTIVE_FAIL)) + if (!warning(JSMSG_USE_ASM_DIRECTIVE_FAIL)) return null(); } return expressionStatement(yieldHandling); @@ -7189,7 +7214,7 @@ Parser::statementListItem(YieldHandling yieldHandling, // detected this way, so don't bother passing around an extra parameter // everywhere. if (!pc->isFunctionBox()) { - qeport(ParseError, JSMSG_BAD_RETURN_OR_YIELD, js_return_str); + error(JSMSG_BAD_RETURN_OR_YIELD, js_return_str); return null(); } return returnStatement(yieldHandling); @@ -7241,11 +7266,11 @@ Parser::statementListItem(YieldHandling yieldHandling, // Miscellaneous error cases arguably better caught here than elsewhere. case TOK_CATCH: - qeport(ParseError, JSMSG_CATCH_WITHOUT_TRY); + error(JSMSG_CATCH_WITHOUT_TRY); return null(); case TOK_FINALLY: - qeport(ParseError, JSMSG_FINALLY_WITHOUT_TRY); + error(JSMSG_FINALLY_WITHOUT_TRY); return null(); // NOTE: default case handled in the ExpressionStatement section. @@ -7290,8 +7315,7 @@ Parser::expr(InHandling inHandling, YieldHandling yieldHandling, if (!tokenStream.peekToken(&tt)) return null(); if (tt != TOK_ARROW) { - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, - "expression", TokenKindToDesc(TOK_RP)); + error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(TOK_RP)); return null(); } @@ -7448,7 +7472,7 @@ Parser::orExpr1(InHandling inHandling, YieldHandling yieldHandling return null(); // Report an error for unary expressions on the LHS of **. if (tok == TOK_POW && handler.isUnparenthesizedUnaryExpression(pn)) { - qeport(ParseError, JSMSG_BAD_POW_LEFTSIDE); + error(JSMSG_BAD_POW_LEFTSIDE); return null(); } pnk = BinaryOpTokenKindToParseNodeKind(tok); @@ -7529,7 +7553,7 @@ Parser::checkAndMarkAsAssignmentLhs(Node target, AssignmentFlavor if (handler.isUnparenthesizedDestructuringPattern(target)) { if (flavor == CompoundAssignment) { - qeport(ParseError, JSMSG_BAD_DESTRUCT_ASS); + error(JSMSG_BAD_DESTRUCT_ASS); return false; } @@ -7668,8 +7692,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl if (!tokenStream.getToken(&tt)) return null(); if (tt != TOK_ARROW) { - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, - "'=>' after argument list", TokenKindToDesc(tt)); + error(JSMSG_UNEXPECTED_TOKEN, "'=>' after argument list", TokenKindToDesc(tt)); return null(); } @@ -7707,7 +7730,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl MOZ_ASSERT(next == TOK_ARROW || next == TOK_EOL); if (next != TOK_ARROW) { - qeport(ParseError, JSMSG_LINE_BREAK_BEFORE_ARROW); + error(JSMSG_LINE_BREAK_BEFORE_ARROW); return null(); } tokenStream.consumeKnownToken(TOK_ARROW); @@ -8027,7 +8050,7 @@ Parser::unaryExpr(YieldHandling yieldHandling, TripledotHandling t if (!pc->isAsync()) { // TOK_AWAIT can be returned in module, even if it's not inside // async function. - qeport(ParseError, JSMSG_RESERVED_ID, "await"); + error(JSMSG_RESERVED_ID, "await"); return null(); } @@ -8180,7 +8203,7 @@ Parser::comprehensionFor(GeneratorKind comprehensionKind) MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_VARIABLE_NAME); RootedPropertyName name(context, tokenStream.currentName()); if (name == context->names().let) { - qeport(ParseError, JSMSG_LET_COMP_BINDING); + error(JSMSG_LET_COMP_BINDING); return null(); } TokenPos namePos = pos(); @@ -8191,7 +8214,7 @@ Parser::comprehensionFor(GeneratorKind comprehensionKind) if (!tokenStream.matchContextualKeyword(&matched, context->names().of)) return null(); if (!matched) { - qeport(ParseError, JSMSG_OF_AFTER_FOR_NAME); + error(JSMSG_OF_AFTER_FOR_NAME); return null(); } @@ -8252,7 +8275,7 @@ Parser::comprehensionIf(GeneratorKind comprehensionKind) /* Check for (a = b) and warn about possible (a == b) mistype. */ if (handler.isUnparenthesizedAssignment(cond)) { - if (!qeport(ParseExtraWarning, JSMSG_EQUAL_AS_ASSIGN)) + if (!extraWarning(JSMSG_EQUAL_AS_ASSIGN)) return null(); } @@ -8529,14 +8552,14 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling if (tt == TOK_NAME) { PropertyName* field = tokenStream.currentName(); if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) { - qeport(ParseError, JSMSG_BAD_SUPERPROP, "property"); + error(JSMSG_BAD_SUPERPROP, "property"); return null(); } nextMember = handler.newPropertyAccess(lhs, field, pos().end); if (!nextMember) return null(); } else { - qeport(ParseError, JSMSG_NAME_AFTER_DOT); + error(JSMSG_NAME_AFTER_DOT); return null(); } } else if (tt == TOK_LB) { @@ -8547,7 +8570,7 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX); if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) { - qeport(ParseError, JSMSG_BAD_SUPERPROP, "member"); + error(JSMSG_BAD_SUPERPROP, "member"); return null(); } nextMember = handler.newPropertyByValue(lhs, propExpr, pos().end); @@ -8559,12 +8582,12 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling { if (handler.isSuperBase(lhs)) { if (!pc->sc()->allowSuperCall()) { - qeport(ParseError, JSMSG_BAD_SUPERCALL); + error(JSMSG_BAD_SUPERCALL); return null(); } if (tt != TOK_LP) { - qeport(ParseError, JSMSG_BAD_SUPER); + error(JSMSG_BAD_SUPER); return null(); } @@ -8591,7 +8614,7 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling return null(); } else { if (options().selfHostingMode && handler.isPropertyAccess(lhs)) { - qeport(ParseError, JSMSG_SELFHOSTED_METHOD_CALL); + error(JSMSG_SELFHOSTED_METHOD_CALL); return null(); } @@ -8673,7 +8696,7 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling } if (handler.isSuperBase(lhs)) { - qeport(ParseError, JSMSG_BAD_SUPER); + error(JSMSG_BAD_SUPER); return null(); } @@ -8726,7 +8749,7 @@ Parser::labelOrIdentifierReference(YieldHandling yieldHandling, ? "static" : nullptr; if (badName) { - qeport(ParseError, JSMSG_RESERVED_ID, badName); + error(JSMSG_RESERVED_ID, badName); return nullptr; } } @@ -8735,7 +8758,7 @@ Parser::labelOrIdentifierReference(YieldHandling yieldHandling, pc->sc()->strict() || versionNumber() >= JSVERSION_1_7) { - qeport(ParseError, JSMSG_RESERVED_ID, "yield"); + error(JSMSG_RESERVED_ID, "yield"); return nullptr; } } @@ -8771,7 +8794,7 @@ Parser::bindingIdentifier(YieldHandling yieldHandling) ? "eval" : nullptr; if (badName) { - qeport(ParseError, JSMSG_BAD_STRICT_ASSIGN, badName); + error(JSMSG_BAD_STRICT_ASSIGN, badName); return nullptr; } @@ -8781,7 +8804,7 @@ Parser::bindingIdentifier(YieldHandling yieldHandling) ? "static" : nullptr; if (badName) { - qeport(ParseError, JSMSG_RESERVED_ID, badName); + error(JSMSG_RESERVED_ID, badName); return nullptr; } } @@ -8790,7 +8813,7 @@ Parser::bindingIdentifier(YieldHandling yieldHandling) pc->sc()->strict() || versionNumber() >= JSVERSION_1_7) { - qeport(ParseError, JSMSG_RESERVED_ID, "yield"); + error(JSMSG_RESERVED_ID, "yield"); return nullptr; } } @@ -8889,7 +8912,7 @@ Parser::arrayInitializer(YieldHandling yieldHandling, PossibleErro TokenStream::Modifier modifier = TokenStream::Operand; for (; ; index++) { if (index >= NativeObject::MAX_DENSE_ELEMENTS_COUNT) { - qeport(ParseError, JSMSG_ARRAY_INIT_TOO_BIG); + error(JSMSG_ARRAY_INIT_TOO_BIG); return null(); } @@ -8999,7 +9022,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, } if (isAsync && isGenerator) { - qeport(ParseError, JSMSG_ASYNC_GENERATOR); + error(JSMSG_ASYNC_GENERATOR); return null(); } @@ -9112,7 +9135,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, } default: - qeport(ParseError, JSMSG_BAD_PROP_ID); + error(JSMSG_BAD_PROP_ID); return null(); } @@ -9122,7 +9145,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, if (tt == TOK_COLON) { if (isGenerator) { - qeport(ParseError, JSMSG_BAD_PROP_ID); + error(JSMSG_BAD_PROP_ID); return null(); } *propType = PropertyType::Normal; @@ -9131,7 +9154,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, if (ltok == TOK_NAME && (tt == TOK_COMMA || tt == TOK_RC || tt == TOK_ASSIGN)) { if (isGenerator) { - qeport(ParseError, JSMSG_BAD_PROP_ID); + error(JSMSG_BAD_PROP_ID); return null(); } tokenStream.ungetToken(); @@ -9152,7 +9175,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, return propName; } - qeport(ParseError, JSMSG_COLON_AFTER_ID); + error(JSMSG_COLON_AFTER_ID); return null(); } @@ -9263,7 +9286,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* return null(); if (propToken != TOK_NAME && propToken != TOK_YIELD) { - qeport(ParseError, JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); + error(JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); return null(); } @@ -9288,7 +9311,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* return null(); if (propToken != TOK_NAME && propToken != TOK_YIELD) { - qeport(ParseError, JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); + error(JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); return null(); } @@ -9312,7 +9335,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* // Destructuring defaults are definitely not allowed in this object literal, // because of something the caller knows about the preceding code. // For example, maybe the preceding token is an operator: `x + {y=z}`. - qeport(ParseError, JSMSG_COLON_AFTER_ID); + error(JSMSG_COLON_AFTER_ID); return null(); } @@ -9371,7 +9394,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* if (tt == TOK_RC) break; if (tt != TOK_COMMA) { - qeport(ParseError, JSMSG_CURLY_AFTER_LIST); + error(JSMSG_CURLY_AFTER_LIST); return null(); } } @@ -9420,7 +9443,7 @@ Parser::tryNewTarget(Node &newTarget) if (!tokenStream.getToken(&next)) return false; if (next != TOK_NAME || tokenStream.currentName() != context->names().target) { - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "target", TokenKindToDesc(next)); + error(JSMSG_UNEXPECTED_TOKEN, "target", TokenKindToDesc(next)); return false; } @@ -9475,8 +9498,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling if (!tokenStream.peekToken(&next)) return null(); if (next != TOK_ARROW) { - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, - "expression", TokenKindToDesc(TOK_RP)); + error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(TOK_RP)); return null(); } @@ -9563,7 +9585,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling // name, closing parenthesis, and arrow, and allow it only if all are // present. if (tripledotHandling != TripledotAllowed) { - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); + error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); return null(); } @@ -9585,8 +9607,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling // or "arguments" should be prohibited. Argument-parsing code // handles that. if (next != TOK_NAME && next != TOK_YIELD) { - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, - "rest argument name", TokenKindToDesc(next)); + error(JSMSG_UNEXPECTED_TOKEN, "rest argument name", TokenKindToDesc(next)); return null(); } } @@ -9594,8 +9615,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling if (!tokenStream.getToken(&next)) return null(); if (next != TOK_RP) { - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, - "closing parenthesis", TokenKindToDesc(next)); + error(JSMSG_UNEXPECTED_TOKEN, "closing parenthesis", TokenKindToDesc(next)); return null(); } @@ -9604,8 +9624,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling if (next != TOK_ARROW) { // Advance the scanner for proper error location reporting. tokenStream.consumeKnownToken(next); - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, - "'=>' after argument list", TokenKindToDesc(next)); + error(JSMSG_UNEXPECTED_TOKEN, "'=>' after argument list", TokenKindToDesc(next)); return null(); } @@ -9616,7 +9635,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling } default: - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); + error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); return null(); } } @@ -9641,7 +9660,7 @@ Parser::warnOnceAboutExprClosure() return true; if (!cx->compartment()->warnedAboutExprClosure) { - if (!qeport(ParseWarning, JSMSG_DEPRECATED_EXPR_CLOSURE)) + if (!warning(JSMSG_DEPRECATED_EXPR_CLOSURE)) return false; cx->compartment()->warnedAboutExprClosure = true; } @@ -9659,7 +9678,7 @@ Parser::warnOnceAboutForEach() if (!cx->compartment()->warnedAboutForEach) { // Disabled warning spew. - // if (!qeport(ParseWarning, JSMSG_DEPRECATED_FOR_EACH)) + // if (!warning(JSMSG_DEPRECATED_FOR_EACH)) // return false; cx->compartment()->warnedAboutForEach = true; } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 402b977ba..feead0e63 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -907,12 +907,14 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool reportHelper(ParseReportKind kind, bool strict, uint32_t offset, unsigned errorNumber, va_list args); public: - bool qeport(ParseReportKind kind, unsigned errorNumber, ...); bool reportWithNode(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...); bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...); bool reportWithOffset(ParseReportKind kind, bool strict, uint32_t offset, unsigned errorNumber, ...); + /* Report the given error at the current offset. */ + void error(unsigned errorNumber, ...); + /* * Handle a strict mode error at the current offset. Report an error if in * strict mode code, or warn if not, using the given error number and @@ -920,6 +922,15 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter */ MOZ_MUST_USE bool strictModeError(unsigned errorNumber, ...); + /* Report the given warning at the current offset. */ + MOZ_MUST_USE bool warning(unsigned errorNumber, ...); + + /* + * If extra warnings are enabled, report the given warning at the current + * offset. + */ + MOZ_MUST_USE bool extraWarning(unsigned errorNumber, ...); + Parser(ExclusiveContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options, const char16_t* chars, size_t length, bool foldConstants, UsedNameTracker& usedNames, Parser* syntaxParser, LazyScript* lazyOuterFunction); -- cgit v1.2.3 From 1ee96e39db760004c33a235ea691ab06bac21375 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 5 Apr 2019 21:30:52 +0200 Subject: Specify an explicit offset when warning about "use asm" found in the directive prologue of a script (rather than a function body). --- js/src/frontend/FullParseHandler.h | 2 +- js/src/frontend/Parser.cpp | 9 +++++---- js/src/frontend/SyntaxParseHandler.h | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index 0fd137796..da068e5af 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -845,7 +845,7 @@ class FullParseHandler MOZ_MUST_USE ParseNode* setLikelyIIFE(ParseNode* pn) { return parenthesize(pn); } - void setPrologue(ParseNode* pn) { + void setInDirectivePrologue(ParseNode* pn) { pn->pn_prologue = true; } diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 8ad8813b5..afbf4c4c9 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -3811,10 +3811,10 @@ Parser::asmJS(Node list) */ template bool -Parser::maybeParseDirective(Node list, Node pn, bool* cont) +Parser::maybeParseDirective(Node list, Node possibleDirective, bool* cont) { TokenPos directivePos; - JSAtom* directive = handler.isStringExprStatement(pn, &directivePos); + JSAtom* directive = handler.isStringExprStatement(possibleDirective, &directivePos); *cont = !!directive; if (!*cont) @@ -3831,7 +3831,7 @@ Parser::maybeParseDirective(Node list, Node pn, bool* cont) // directive in the future. We don't want to interfere with people // taking advantage of directive-prologue-enabled features that appear // in other browsers first. - handler.setPrologue(pn); + handler.setInDirectivePrologue(possibleDirective); if (directive == context->names().useStrict) { // Functions with non-simple parameter lists (destructuring, @@ -3867,7 +3867,8 @@ Parser::maybeParseDirective(Node list, Node pn, bool* cont) } else if (directive == context->names().useAsm) { if (pc->isFunctionBox()) return asmJS(list); - return reportWithNode(ParseWarning, false, pn, JSMSG_USE_ASM_DIRECTIVE_FAIL); + return reportWithOffset(ParseWarning, false, directivePos.begin, + JSMSG_USE_ASM_DIRECTIVE_FAIL); } } return true; diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index b7f00605b..85695ba9c 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -519,7 +519,7 @@ class SyntaxParseHandler MOZ_MUST_USE Node setLikelyIIFE(Node pn) { return pn; // Remain in syntax-parse mode. } - void setPrologue(Node pn) {} + void setInDirectivePrologue(Node pn) {} bool isConstant(Node pn) { return false; } -- cgit v1.2.3 From 11a1f58b9a0ebf83c17087a89e6b4ba83748374a Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 5 Apr 2019 21:32:55 +0200 Subject: Track strict mode errors in unary deletions correctly when syntax-parsing. --- js/src/frontend/Parser.cpp | 19 +++++++++++++++++-- js/src/frontend/Parser.h | 7 +++++++ 2 files changed, 24 insertions(+), 2 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index afbf4c4c9..f625595a2 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -641,6 +641,17 @@ Parser::strictModeError(unsigned errorNumber, ...) return res; } +template +bool +Parser::strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); + bool res = reportHelper(ParseStrictError, pc->sc()->strict(), offset, errorNumber, args); + va_end(args); + return res; +} + template bool Parser::reportWithNode(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...) @@ -8031,6 +8042,10 @@ Parser::unaryExpr(YieldHandling yieldHandling, TripledotHandling t } case TOK_DELETE: { + uint32_t exprOffset; + if (!tokenStream.peekOffset(&exprOffset, TokenStream::Operand)) + return null(); + Node expr = unaryExpr(yieldHandling, TripledotProhibited); if (!expr) return null(); @@ -8038,9 +8053,9 @@ Parser::unaryExpr(YieldHandling yieldHandling, TripledotHandling t // Per spec, deleting any unary expression is valid -- it simply // returns true -- except for one case that is illegal in strict mode. if (handler.isNameAnyParentheses(expr)) { - bool strict = pc->sc()->strict(); - if (!reportWithNode(ParseStrictError, strict, expr, JSMSG_DEPRECATED_DELETE_OPERAND)) + if (!strictModeErrorAt(exprOffset, JSMSG_DEPRECATED_DELETE_OPERAND)) return null(); + pc->sc()->setBindingsAccessedDynamically(); } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index feead0e63..c8914a2d7 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -922,6 +922,13 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter */ MOZ_MUST_USE bool strictModeError(unsigned errorNumber, ...); + /* + * Handle a strict mode error at the given offset. Report an error if in + * strict mode code, or warn if not, using the given error number and + * arguments. + */ + MOZ_MUST_USE bool strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...); + /* Report the given warning at the current offset. */ MOZ_MUST_USE bool warning(unsigned errorNumber, ...); -- cgit v1.2.3 From dcf64bd2ffd24d1c0d046af810c3270656081663 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 5 Apr 2019 21:38:21 +0200 Subject: Track strict mode errors in for...in and for...of correctly when syntax-parsing. --- js/src/frontend/Parser.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index f625595a2..5981881d3 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -4458,6 +4458,10 @@ Parser::initializerInNameDeclaration(Node decl, Node binding, { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_ASSIGN)); + uint32_t initializerOffset; + if (!tokenStream.peekOffset(&initializerOffset, TokenStream::Operand)) + return false; + Node initializer = assignExpr(forHeadKind ? InProhibited : InAllowed, yieldHandling, TripledotProhibited); if (!initializer) @@ -4491,11 +4495,8 @@ Parser::initializerInNameDeclaration(Node decl, Node binding, // This leaves only initialized for-in |var| declarations. ES6 // forbids these; later ES un-forbids in non-strict mode code. *forHeadKind = PNK_FORIN; - if (!reportWithNode(ParseStrictError, pc->sc()->strict(), initializer, - JSMSG_INVALID_FOR_IN_DECL_WITH_INIT)) - { + if (!strictModeErrorAt(initializerOffset, JSMSG_INVALID_FOR_IN_DECL_WITH_INIT)) return false; - } *forInOrOfExpression = expressionAfterForInOrOf(PNK_FORIN, yieldHandling); if (!*forInOrOfExpression) -- cgit v1.2.3 From 96899aa847ab7495e3b7baaa413cf50a5eaaffff Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 04:22:27 +0200 Subject: Move part of Parser::functionDefinition into callers. --- js/src/frontend/Parser.cpp | 46 +++++++++++++++++++++++++++++----------------- js/src/frontend/Parser.h | 5 ++--- 2 files changed, 31 insertions(+), 20 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 5981881d3..8466d7c1c 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -3188,22 +3188,14 @@ Parser::templateLiteral(YieldHandling yieldHandling) template typename ParseHandler::Node -Parser::functionDefinition(uint32_t preludeStart, InHandling inHandling, +Parser::functionDefinition(uint32_t preludeStart, Node pn, InHandling inHandling, YieldHandling yieldHandling, HandleAtom funName, FunctionSyntaxKind kind, - GeneratorKind generatorKind, FunctionAsyncKind asyncKind, - InvokedPrediction invoked) + GeneratorKind generatorKind, FunctionAsyncKind asyncKind) { MOZ_ASSERT_IF(kind == Statement, funName); MOZ_ASSERT_IF(asyncKind == AsyncFunction, generatorKind == StarGenerator); - Node pn = handler.newFunctionDefinition(); - if (!pn) - return null(); - - if (invoked) - pn = handler.setLikelyIIFE(pn); - // Note the declared name and check for early errors. bool tryAnnexB = false; if (!checkFunctionDefinition(funName, pn, kind, generatorKind, &tryAnnexB)) @@ -3665,9 +3657,13 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan return null(); } + Node pn = handler.newFunctionDefinition(); + if (!pn) + return null(); + YieldHandling newYieldHandling = GetYieldHandling(generatorKind, asyncKind); - Node fun = functionDefinition(preludeStart, InAllowed, newYieldHandling, name, Statement, - generatorKind, asyncKind, PredictUninvoked); + Node fun = functionDefinition(preludeStart, pn, InAllowed, newYieldHandling, + name, Statement, generatorKind, asyncKind); if (!fun) return null(); @@ -3716,8 +3712,15 @@ Parser::functionExpr(uint32_t preludeStart, InvokedPrediction invo tokenStream.ungetToken(); } - return functionDefinition(preludeStart, InAllowed, yieldHandling, name, Expression, - generatorKind, asyncKind, invoked); + Node pn = handler.newFunctionDefinition(); + if (!pn) + return null(); + + if (invoked) + pn = handler.setLikelyIIFE(pn); + + return functionDefinition(preludeStart, pn, InAllowed, yieldHandling, name, Expression, + generatorKind, asyncKind); } /* @@ -7783,7 +7786,11 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl } } - Node arrowFunc = functionDefinition(preludeStart, inHandling, yieldHandling, nullptr, + Node pn = handler.newFunctionDefinition(); + if (!pn) + return null(); + + Node arrowFunc = functionDefinition(preludeStart, pn, inHandling, yieldHandling, nullptr, Arrow, generatorKind, asyncKind); if (!arrowFunc) return null(); @@ -9429,8 +9436,13 @@ Parser::methodDefinition(uint32_t preludeStart, PropertyType propT GeneratorKind generatorKind = GeneratorKindFromPropertyType(propType); FunctionAsyncKind asyncKind = AsyncKindFromPropertyType(propType); YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind); - return functionDefinition(preludeStart, InAllowed, yieldHandling, funName, kind, - generatorKind, asyncKind); + + Node pn = handler.newFunctionDefinition(); + if (!pn) + return null(); + + return functionDefinition(preludeStart, pn, InAllowed, yieldHandling, funName, + kind, generatorKind, asyncKind); } template diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index c8914a2d7..3bfb4ae31 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1259,11 +1259,10 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind, Node funcpn); - Node functionDefinition(uint32_t preludeStart, + Node functionDefinition(uint32_t preludeStart, Node pn, InHandling inHandling, YieldHandling yieldHandling, HandleAtom name, FunctionSyntaxKind kind, - GeneratorKind generatorKind, FunctionAsyncKind asyncKind, - InvokedPrediction invoked = PredictUninvoked); + GeneratorKind generatorKind, FunctionAsyncKind asyncKind); // Parse a function body. Pass StatementListBody if the body is a list of // statements; pass ExpressionBody if the body is a single expression. -- cgit v1.2.3 From 7333618581b018ca73c3482e2d5547765f6c3a1d Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 06:22:55 +0200 Subject: Move the Parser::checkFunctionDefinition call into its callers. --- js/src/frontend/FullParseHandler.h | 15 ++- js/src/frontend/ParseNode.h | 8 +- js/src/frontend/Parser.cpp | 176 ++++++++++++++++++----------------- js/src/frontend/Parser.h | 5 +- js/src/frontend/SyntaxParseHandler.h | 5 +- js/src/wasm/AsmJS.cpp | 2 +- 6 files changed, 116 insertions(+), 95 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index da068e5af..b619cf24c 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -670,9 +670,18 @@ class FullParseHandler pn->setDirectRHSAnonFunction(true); } - ParseNode* newFunctionDefinition() { - return new_(PNK_FUNCTION, pos()); + ParseNode* newFunctionStatement() { + return new_(PNK_FUNCTION, JSOP_NOP, pos()); } + + ParseNode* newFunctionExpression() { + return new_(PNK_FUNCTION, JSOP_LAMBDA, pos()); + } + + ParseNode* newArrowFunction() { + return new_(PNK_FUNCTION, JSOP_LAMBDA_ARROW, pos()); + } + bool setComprehensionLambdaBody(ParseNode* pn, ParseNode* body) { MOZ_ASSERT(body->isKind(PNK_STATEMENTLIST)); ParseNode* paramsBody = newList(PNK_PARAMSBODY, body); @@ -699,7 +708,7 @@ class FullParseHandler } ParseNode* newModule() { - return new_(PNK_MODULE, pos()); + return new_(PNK_MODULE, JSOP_NOP, pos()); } ParseNode* newLexicalScope(LexicalScope::Data* bindings, ParseNode* body) { diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index c58dab431..c3523afe4 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -926,10 +926,14 @@ struct ListNode : public ParseNode struct CodeNode : public ParseNode { - CodeNode(ParseNodeKind kind, const TokenPos& pos) - : ParseNode(kind, JSOP_NOP, PN_CODE, pos) + CodeNode(ParseNodeKind kind, JSOp op, const TokenPos& pos) + : ParseNode(kind, op, PN_CODE, pos) { MOZ_ASSERT(kind == PNK_FUNCTION || kind == PNK_MODULE); + MOZ_ASSERT_IF(kind == PNK_MODULE, op == JSOP_NOP); + MOZ_ASSERT(op == JSOP_NOP || // statement, module + op == JSOP_LAMBDA_ARROW || // arrow function + op == JSOP_LAMBDA); // expression, method, comprehension, accessor, &c. MOZ_ASSERT(!pn_body); MOZ_ASSERT(!pn_objbox); } diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 8466d7c1c..c34e4d563 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -2352,7 +2352,7 @@ Parser::standaloneFunction(HandleFunction fun, tokenStream.ungetToken(); } - Node fn = handler.newFunctionDefinition(); + Node fn = handler.newFunctionStatement(); if (!fn) return null(); @@ -3010,60 +3010,54 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn template bool -Parser::checkFunctionDefinition(HandleAtom funAtom, Node pn, FunctionSyntaxKind kind, +Parser::checkFunctionDefinition(HandlePropertyName funName, Node pn, GeneratorKind generatorKind, bool* tryAnnexB) { - if (kind == Statement) { - TokenPos pos = handler.getPosition(pn); - RootedPropertyName funName(context, funAtom->asPropertyName()); - - // In sloppy mode, Annex B.3.2 allows labelled function - // declarations. Otherwise it is a parse error. - ParseContext::Statement* declaredInStmt = pc->innermostStatement(); - if (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) { - MOZ_ASSERT(!pc->sc()->strict(), - "labeled functions shouldn't be parsed in strict mode"); - - // Find the innermost non-label statement. Report an error if it's - // unbraced: functions can't appear in it. Otherwise the statement - // (or its absence) determines the scope the function's bound in. - while (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) - declaredInStmt = declaredInStmt->enclosing(); - - if (declaredInStmt && !StatementKindIsBraced(declaredInStmt->kind())) { - reportWithOffset(ParseError, false, pos.begin, JSMSG_SLOPPY_FUNCTION_LABEL); - return false; - } - } + TokenPos pos = handler.getPosition(pn); - if (declaredInStmt) { - MOZ_ASSERT(declaredInStmt->kind() != StatementKind::Label); - MOZ_ASSERT(StatementKindIsBraced(declaredInStmt->kind())); + // In sloppy mode, Annex B.3.2 allows labelled function + // declarations. Otherwise it is a parse error. + ParseContext::Statement* declaredInStmt = pc->innermostStatement(); + if (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) { + MOZ_ASSERT(!pc->sc()->strict(), + "labeled functions shouldn't be parsed in strict mode"); - if (!pc->sc()->strict() && generatorKind == NotGenerator) { - // Under sloppy mode, try Annex B.3.3 semantics. If making an - // additional 'var' binding of the same name does not throw an - // early error, do so. This 'var' binding would be assigned - // the function object when its declaration is reached, not at - // the start of the block. + // Find the innermost non-label statement. Report an error if it's + // unbraced: functions can't appear in it. Otherwise the statement + // (or its absence) determines the scope the function's bound in. + while (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) + declaredInStmt = declaredInStmt->enclosing(); - if (!tryDeclareVarForAnnexBLexicalFunction(funName, tryAnnexB)) - return false; - } + if (declaredInStmt && !StatementKindIsBraced(declaredInStmt->kind())) { + reportWithOffset(ParseError, false, pos.begin, JSMSG_SLOPPY_FUNCTION_LABEL); + return false; + } + } - if (!noteDeclaredName(funName, DeclarationKind::LexicalFunction, pos)) - return false; - } else { - if (!noteDeclaredName(funName, DeclarationKind::BodyLevelFunction, pos)) - return false; + if (declaredInStmt) { + MOZ_ASSERT(declaredInStmt->kind() != StatementKind::Label); + MOZ_ASSERT(StatementKindIsBraced(declaredInStmt->kind())); - // Body-level functions in modules are always closed over. - if (pc->atModuleLevel()) - pc->varScope().lookupDeclaredName(funName)->value()->setClosedOver(); + if (!pc->sc()->strict() && generatorKind == NotGenerator) { + // In sloppy mode, try Annex B.3.3 semantics. If making an + // additional 'var' binding of the same name does not throw an + // early error, do so. This 'var' binding would be assigned + // the function object when its declaration is reached, not at + // the start of the block. + + if (!tryDeclareVarForAnnexBLexicalFunction(funName, tryAnnexB)) + return false; } + + if (!noteDeclaredName(funName, DeclarationKind::LexicalFunction, pos)) + return false; } else { - // A function expression does not introduce any binding. - handler.setOp(pn, kind == Arrow ? JSOP_LAMBDA_ARROW : JSOP_LAMBDA); + if (!noteDeclaredName(funName, DeclarationKind::BodyLevelFunction, pos)) + return false; + + // Body-level functions in modules are always closed over. + if (pc->atModuleLevel()) + pc->varScope().lookupDeclaredName(funName)->value()->setClosedOver(); } return true; @@ -3191,16 +3185,12 @@ typename ParseHandler::Node Parser::functionDefinition(uint32_t preludeStart, Node pn, InHandling inHandling, YieldHandling yieldHandling, HandleAtom funName, FunctionSyntaxKind kind, - GeneratorKind generatorKind, FunctionAsyncKind asyncKind) + GeneratorKind generatorKind, FunctionAsyncKind asyncKind, + bool tryAnnexB /* = false */) { MOZ_ASSERT_IF(kind == Statement, funName); MOZ_ASSERT_IF(asyncKind == AsyncFunction, generatorKind == StarGenerator); - // Note the declared name and check for early errors. - bool tryAnnexB = false; - if (!checkFunctionDefinition(funName, pn, kind, generatorKind, &tryAnnexB)) - return null(); - // When fully parsing a LazyScript, we do not fully reparse its inner // functions, which are also lazy. Instead, their free variables and // source extents are recorded and may be skipped. @@ -3433,7 +3423,7 @@ Parser::standaloneLazyFunction(HandleFunction fun, bool strict { MOZ_ASSERT(checkOptionsCalled); - Node pn = handler.newFunctionDefinition(); + Node pn = handler.newFunctionStatement(); if (!pn) return null(); @@ -3657,13 +3647,18 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan return null(); } - Node pn = handler.newFunctionDefinition(); + Node pn = handler.newFunctionStatement(); if (!pn) return null(); + // Note the declared name and check for early errors. + bool tryAnnexB = false; + if (!checkFunctionDefinition(name, pn, generatorKind, &tryAnnexB)) + return null(); + YieldHandling newYieldHandling = GetYieldHandling(generatorKind, asyncKind); Node fun = functionDefinition(preludeStart, pn, InAllowed, newYieldHandling, - name, Statement, generatorKind, asyncKind); + name, Statement, generatorKind, asyncKind, tryAnnexB); if (!fun) return null(); @@ -3712,7 +3707,7 @@ Parser::functionExpr(uint32_t preludeStart, InvokedPrediction invo tokenStream.ungetToken(); } - Node pn = handler.newFunctionDefinition(); + Node pn = handler.newFunctionExpression(); if (!pn) return null(); @@ -6583,31 +6578,6 @@ JSOpFromPropertyType(PropertyType propType) } } -static FunctionSyntaxKind -FunctionSyntaxKindFromPropertyType(PropertyType propType) -{ - switch (propType) { - case PropertyType::Getter: - return Getter; - case PropertyType::GetterNoExpressionClosure: - return GetterNoExpressionClosure; - case PropertyType::Setter: - return Setter; - case PropertyType::SetterNoExpressionClosure: - return SetterNoExpressionClosure; - case PropertyType::Method: - case PropertyType::GeneratorMethod: - case PropertyType::AsyncMethod: - return Method; - case PropertyType::Constructor: - return ClassConstructor; - case PropertyType::DerivedConstructor: - return DerivedClassConstructor; - default: - MOZ_CRASH("unexpected property type"); - } -} - static GeneratorKind GeneratorKindFromPropertyType(PropertyType propType) { @@ -7786,7 +7756,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl } } - Node pn = handler.newFunctionDefinition(); + Node pn = handler.newArrowFunction(); if (!pn) return null(); @@ -8125,10 +8095,9 @@ template typename ParseHandler::Node Parser::generatorComprehensionLambda(unsigned begin) { - Node genfn = handler.newFunctionDefinition(); + Node genfn = handler.newFunctionExpression(); if (!genfn) return null(); - handler.setOp(genfn, JSOP_LAMBDA); ParseContext* outerpc = pc; @@ -9432,12 +9401,47 @@ typename ParseHandler::Node Parser::methodDefinition(uint32_t preludeStart, PropertyType propType, HandleAtom funName) { - FunctionSyntaxKind kind = FunctionSyntaxKindFromPropertyType(propType); + FunctionSyntaxKind kind; + switch (propType) { + case PropertyType::Getter: + kind = Getter; + break; + + case PropertyType::GetterNoExpressionClosure: + kind = GetterNoExpressionClosure; + break; + + case PropertyType::Setter: + kind = Setter; + break; + + case PropertyType::SetterNoExpressionClosure: + kind = SetterNoExpressionClosure; + break; + + case PropertyType::Method: + case PropertyType::GeneratorMethod: + case PropertyType::AsyncMethod: + kind = Method; + break; + + case PropertyType::Constructor: + kind = ClassConstructor; + break; + + case PropertyType::DerivedConstructor: + kind = DerivedClassConstructor; + break; + + default: + MOZ_CRASH("Parser: methodDefinition: unexpected property type"); + } + GeneratorKind generatorKind = GeneratorKindFromPropertyType(propType); FunctionAsyncKind asyncKind = AsyncKindFromPropertyType(propType); YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind); - Node pn = handler.newFunctionDefinition(); + Node pn = handler.newFunctionExpression(); if (!pn) return null(); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 3bfb4ae31..dc9c16adb 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1262,7 +1262,8 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter Node functionDefinition(uint32_t preludeStart, Node pn, InHandling inHandling, YieldHandling yieldHandling, HandleAtom name, FunctionSyntaxKind kind, - GeneratorKind generatorKind, FunctionAsyncKind asyncKind); + GeneratorKind generatorKind, FunctionAsyncKind asyncKind, + bool tryAnnexB = false); // Parse a function body. Pass StatementListBody if the body is a list of // statements; pass ExpressionBody if the body is a single expression. @@ -1348,7 +1349,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter Node newDotGeneratorName(); bool declareDotGeneratorName(); - bool checkFunctionDefinition(HandleAtom funAtom, Node pn, FunctionSyntaxKind kind, + bool checkFunctionDefinition(HandlePropertyName funName, Node pn, GeneratorKind generatorKind, bool* tryAnnexB); bool skipLazyInnerFunction(Node pn, uint32_t preludeStart, FunctionSyntaxKind kind, bool tryAnnexB); diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index 85695ba9c..00ea9d35d 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -342,7 +342,10 @@ class SyntaxParseHandler void checkAndSetIsDirectRHSAnonFunction(Node pn) {} - Node newFunctionDefinition() { return NodeFunctionDefinition; } + Node newFunctionStatement() { return NodeFunctionDefinition; } + Node newFunctionExpression() { return NodeFunctionDefinition; } + Node newArrowFunction() { return NodeFunctionDefinition; } + bool setComprehensionLambdaBody(Node pn, Node body) { return true; } void setFunctionFormalParametersAndBody(Node pn, Node kid) {} void setFunctionBody(Node pn, Node kid) {} diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp index 2b6690363..a318d67a9 100644 --- a/js/src/wasm/AsmJS.cpp +++ b/js/src/wasm/AsmJS.cpp @@ -7064,7 +7064,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line) if (!name) return false; - ParseNode* fn = m.parser().handler.newFunctionDefinition(); + ParseNode* fn = m.parser().handler.newFunctionStatement(); if (!fn) return false; -- cgit v1.2.3 From 239003468d0617ca34b5e78627f014207b4e63ee Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 06:26:49 +0200 Subject: Inline GeneratorKindFromPropertyType and AsyncKindFromPropertyType. Trivially inlines these into their sole caller. --- js/src/frontend/Parser.cpp | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index c34e4d563..5a42b75b0 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -6578,24 +6578,6 @@ JSOpFromPropertyType(PropertyType propType) } } -static GeneratorKind -GeneratorKindFromPropertyType(PropertyType propType) -{ - if (propType == PropertyType::GeneratorMethod) - return StarGenerator; - if (propType == PropertyType::AsyncMethod) - return StarGenerator; - return NotGenerator; -} - -static FunctionAsyncKind -AsyncKindFromPropertyType(PropertyType propType) -{ - if (propType == PropertyType::AsyncMethod) - return AsyncFunction; - return SyncFunction; -} - template typename ParseHandler::Node Parser::classDefinition(YieldHandling yieldHandling, @@ -9437,8 +9419,15 @@ Parser::methodDefinition(uint32_t preludeStart, PropertyType propT MOZ_CRASH("Parser: methodDefinition: unexpected property type"); } - GeneratorKind generatorKind = GeneratorKindFromPropertyType(propType); - FunctionAsyncKind asyncKind = AsyncKindFromPropertyType(propType); + GeneratorKind generatorKind = (propType == PropertyType::GeneratorMethod || + propType == PropertyType::AsyncMethod) + ? StarGenerator + : NotGenerator; + + FunctionAsyncKind asyncKind = (propType == PropertyType::AsyncMethod) + ? AsyncFunction + : SyncFunction; + YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind); Node pn = handler.newFunctionExpression(); -- cgit v1.2.3 From 386cc5ee17b4e144fdffda1742031aa0cba7373a Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 06:36:09 +0200 Subject: Inline Parser::checkFunctionDefinition into its sole caller. --- js/src/frontend/Parser.cpp | 112 ++++++++++++++++++++------------------------- js/src/frontend/Parser.h | 2 - 2 files changed, 49 insertions(+), 65 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 5a42b75b0..34d87528f 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -1307,7 +1307,7 @@ Parser::noteDeclaredName(HandlePropertyName name, DeclarationKind // Functions in block have complex allowances in sloppy mode for being // labelled that other lexical declarations do not have. Those checks // are more complex than calling checkLexicalDeclarationDirectlyWithin- - // Block and are done in checkFunctionDefinition. + // Block and are done inline in callers. ParseContext::Scope* scope = pc->innermostScope(); if (AddDeclaredNamePtr p = scope->lookupDeclaredNameForAdd(name)) { @@ -3008,61 +3008,6 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn return true; } -template -bool -Parser::checkFunctionDefinition(HandlePropertyName funName, Node pn, - GeneratorKind generatorKind, bool* tryAnnexB) -{ - TokenPos pos = handler.getPosition(pn); - - // In sloppy mode, Annex B.3.2 allows labelled function - // declarations. Otherwise it is a parse error. - ParseContext::Statement* declaredInStmt = pc->innermostStatement(); - if (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) { - MOZ_ASSERT(!pc->sc()->strict(), - "labeled functions shouldn't be parsed in strict mode"); - - // Find the innermost non-label statement. Report an error if it's - // unbraced: functions can't appear in it. Otherwise the statement - // (or its absence) determines the scope the function's bound in. - while (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) - declaredInStmt = declaredInStmt->enclosing(); - - if (declaredInStmt && !StatementKindIsBraced(declaredInStmt->kind())) { - reportWithOffset(ParseError, false, pos.begin, JSMSG_SLOPPY_FUNCTION_LABEL); - return false; - } - } - - if (declaredInStmt) { - MOZ_ASSERT(declaredInStmt->kind() != StatementKind::Label); - MOZ_ASSERT(StatementKindIsBraced(declaredInStmt->kind())); - - if (!pc->sc()->strict() && generatorKind == NotGenerator) { - // In sloppy mode, try Annex B.3.3 semantics. If making an - // additional 'var' binding of the same name does not throw an - // early error, do so. This 'var' binding would be assigned - // the function object when its declaration is reached, not at - // the start of the block. - - if (!tryDeclareVarForAnnexBLexicalFunction(funName, tryAnnexB)) - return false; - } - - if (!noteDeclaredName(funName, DeclarationKind::LexicalFunction, pos)) - return false; - } else { - if (!noteDeclaredName(funName, DeclarationKind::BodyLevelFunction, pos)) - return false; - - // Body-level functions in modules are always closed over. - if (pc->atModuleLevel()) - pc->varScope().lookupDeclaredName(funName)->value()->setClosedOver(); - } - - return true; -} - template <> bool Parser::skipLazyInnerFunction(ParseNode* pn, uint32_t preludeStart, @@ -3618,12 +3563,30 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan } } - RootedPropertyName name(context); - GeneratorKind generatorKind = asyncKind == AsyncFunction ? StarGenerator : NotGenerator; + // In sloppy mode, Annex B.3.2 allows labelled function declarations. + // Otherwise it's a parse error. + ParseContext::Statement* declaredInStmt = pc->innermostStatement(); + if (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) { + MOZ_ASSERT(!pc->sc()->strict(), + "labeled functions shouldn't be parsed in strict mode"); + + // Find the innermost non-label statement. Report an error if it's + // unbraced: functions can't appear in it. Otherwise the statement + // (or its absence) determines the scope the function's bound in. + while (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) + declaredInStmt = declaredInStmt->enclosing(); + + if (declaredInStmt && !StatementKindIsBraced(declaredInStmt->kind())) { + error(JSMSG_SLOPPY_FUNCTION_LABEL); + return null(); + } + } + TokenKind tt; if (!tokenStream.getToken(&tt)) return null(); + GeneratorKind generatorKind = asyncKind == AsyncFunction ? StarGenerator : NotGenerator; if (tt == TOK_MUL) { if (asyncKind != SyncFunction) { error(JSMSG_ASYNC_GENERATOR); @@ -3634,6 +3597,7 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan return null(); } + RootedPropertyName name(context); if (tt == TOK_NAME || tt == TOK_YIELD) { name = bindingIdentifier(yieldHandling); if (!name) @@ -3647,13 +3611,35 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan return null(); } - Node pn = handler.newFunctionStatement(); - if (!pn) - return null(); - // Note the declared name and check for early errors. bool tryAnnexB = false; - if (!checkFunctionDefinition(name, pn, generatorKind, &tryAnnexB)) + if (declaredInStmt) { + MOZ_ASSERT(declaredInStmt->kind() != StatementKind::Label); + MOZ_ASSERT(StatementKindIsBraced(declaredInStmt->kind())); + + if (!pc->sc()->strict() && generatorKind == NotGenerator) { + // In sloppy mode, try Annex B.3.3 semantics. If making an + // additional 'var' binding of the same name does not throw an + // early error, do so. This 'var' binding would be assigned + // the function object when its declaration is reached, not at + // the start of the block. + if (!tryDeclareVarForAnnexBLexicalFunction(name, &tryAnnexB)) + return null(); + } + + if (!noteDeclaredName(name, DeclarationKind::LexicalFunction, pos())) + return null(); + } else { + if (!noteDeclaredName(name, DeclarationKind::BodyLevelFunction, pos())) + return null(); + + // Body-level functions in modules are always closed over. + if (pc->atModuleLevel()) + pc->varScope().lookupDeclaredName(name)->value()->setClosedOver(); + } + + Node pn = handler.newFunctionStatement(); + if (!pn) return null(); YieldHandling newYieldHandling = GetYieldHandling(generatorKind, asyncKind); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index dc9c16adb..13580846b 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1349,8 +1349,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter Node newDotGeneratorName(); bool declareDotGeneratorName(); - bool checkFunctionDefinition(HandlePropertyName funName, Node pn, - GeneratorKind generatorKind, bool* tryAnnexB); bool skipLazyInnerFunction(Node pn, uint32_t preludeStart, FunctionSyntaxKind kind, bool tryAnnexB); bool innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun, uint32_t preludeStart, -- cgit v1.2.3 From 7d56f431ccc11f3b5e2e6deec331bd9c7a06cf80 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 06:39:27 +0200 Subject: Introduce Parser::errorAt This reduces reporting an error at a particular offset to its bare essentials, simplifying calls. --- js/src/frontend/Parser.cpp | 71 +++++++++++++++++++++++++--------------------- js/src/frontend/Parser.h | 3 ++ 2 files changed, 42 insertions(+), 32 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 34d87528f..b494cc966 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -608,6 +608,20 @@ Parser::error(unsigned errorNumber, ...) va_end(args); } +template +void +Parser::errorAt(uint32_t offset, unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); +#ifdef DEBUG + bool result = +#endif + reportHelper(ParseError, false, offset, errorNumber, args); + MOZ_ASSERT(!result, "reporting an error returned true?"); + va_end(args); +} + template bool Parser::warning(unsigned errorNumber, ...) @@ -940,8 +954,7 @@ Parser::checkStrictBinding(PropertyName* name, TokenPos pos) JSAutoByteString bytes; if (!AtomToPrintableString(context, name, &bytes)) return false; - return reportWithOffset(ParseStrictError, pc->sc()->strict(), pos.begin, - JSMSG_BAD_BINDING, bytes.ptr()); + return strictModeErrorAt(pos.begin, JSMSG_BAD_BINDING, bytes.ptr()); } return true; @@ -977,8 +990,7 @@ Parser::reportRedeclaration(HandlePropertyName name, DeclarationKi JSAutoByteString bytes; if (!AtomToPrintableString(context, name, &bytes)) return; - reportWithOffset(ParseError, false, pos.begin, JSMSG_REDECLARED_VAR, - DeclarationKindString(kind), bytes.ptr()); + errorAt(pos.begin, JSMSG_REDECLARED_VAR, DeclarationKindString(kind), bytes.ptr()); } // notePositionalFormalParameter is called for both the arguments of a regular @@ -1247,11 +1259,11 @@ Parser::checkLexicalDeclarationDirectlyWithinBlock(ParseContext::S if (!StatementKindIsBraced(stmt.kind()) && stmt.kind() != StatementKind::ForLoopLexicalHead) { - reportWithOffset(ParseError, false, pos.begin, - stmt.kind() == StatementKind::Label - ? JSMSG_LEXICAL_DECL_LABEL - : JSMSG_LEXICAL_DECL_NOT_IN_BLOCK, - DeclarationKindString(kind)); + errorAt(pos.begin, + stmt.kind() == StatementKind::Label + ? JSMSG_LEXICAL_DECL_LABEL + : JSMSG_LEXICAL_DECL_NOT_IN_BLOCK, + DeclarationKindString(kind)); return false; } @@ -1341,7 +1353,7 @@ Parser::noteDeclaredName(HandlePropertyName name, DeclarationKind // contain 'let'. (CatchParameter is the only lexical binding form // without this restriction.) if (name == context->names().let) { - reportWithOffset(ParseError, false, pos.begin, JSMSG_LEXICAL_DECL_DEFINES_LET); + errorAt(pos.begin, JSMSG_LEXICAL_DECL_DEFINES_LET); return false; } @@ -3730,7 +3742,7 @@ Parser::checkUnescapedName() if (!token.nameContainsEscape()) return true; - reportWithOffset(ParseError, false, token.pos.begin, JSMSG_ESCAPED_KEYWORD); + errorAt(token.pos.begin, JSMSG_ESCAPED_KEYWORD); return false; } @@ -3840,8 +3852,7 @@ Parser::maybeParseDirective(Node list, Node possibleDirective, boo : funbox->hasParameterExprs ? "default" : "rest"; - reportWithOffset(ParseError, false, directivePos.begin, - JSMSG_STRICT_NON_SIMPLE_PARAMS, parameterKind); + errorAt(directivePos.begin, JSMSG_STRICT_NON_SIMPLE_PARAMS, parameterKind); return false; } } @@ -4038,7 +4049,7 @@ Parser::PossibleError::checkForError(ErrorKind kind) return true; Error& err = error(kind); - parser_.reportWithOffset(ParseError, false, err.offset_, err.errorNumber_); + parser_.errorAt(err.offset_, err.errorNumber_); return false; } @@ -4327,11 +4338,11 @@ Parser::destructuringDeclarationWithoutYieldOrAwait(DeclarationKin Node res = destructuringDeclaration(kind, yieldHandling, tt); if (res) { if (pc->lastYieldOffset != startYieldOffset) { - reportWithOffset(ParseError, false, pc->lastYieldOffset, JSMSG_YIELD_IN_DEFAULT); + errorAt(pc->lastYieldOffset, JSMSG_YIELD_IN_DEFAULT); return null(); } if (pc->lastAwaitOffset != startAwaitOffset) { - reportWithOffset(ParseError, false, pc->lastAwaitOffset, JSMSG_AWAIT_IN_DEFAULT); + errorAt(pc->lastAwaitOffset, JSMSG_AWAIT_IN_DEFAULT); return null(); } } @@ -4779,7 +4790,7 @@ Parser::namedImportsOrNamespaceImport(TokenKind tt, Node impor return false; if (tt != TOK_NAME || tokenStream.currentName() != context->names().as) { - reportWithOffset(ParseError, false, pos().begin, JSMSG_AS_AFTER_IMPORT_STAR); + error(JSMSG_AS_AFTER_IMPORT_STAR); return false; } @@ -5662,7 +5673,7 @@ Parser::forStatement(YieldHandling yieldHandling) Node init = startNode; if (isForEach) { - reportWithOffset(ParseError, false, begin, JSMSG_BAD_FOR_EACH_LOOP); + errorAt(begin, JSMSG_BAD_FOR_EACH_LOOP); return null(); } @@ -5897,7 +5908,7 @@ Parser::continueStatement(YieldHandling yieldHandling) if (foundLoop) error(JSMSG_LABEL_NOT_FOUND); else - reportWithOffset(ParseError, false, begin, JSMSG_BAD_CONTINUE); + errorAt(begin, JSMSG_BAD_CONTINUE); return null(); } @@ -5956,7 +5967,7 @@ Parser::breakStatement(YieldHandling yieldHandling) }; if (!pc->findInnermostStatement(isBreakTarget)) { - reportWithOffset(ParseError, false, begin, JSMSG_TOUGH_BREAK); + errorAt(begin, JSMSG_TOUGH_BREAK); return null(); } } @@ -6111,8 +6122,7 @@ Parser::yieldExpression(InHandling inHandling) } if (pc->functionBox()->isArrow()) { - reportWithOffset(ParseError, false, begin, - JSMSG_YIELD_IN_ARROW, js_yield_str); + errorAt(begin, JSMSG_YIELD_IN_ARROW, js_yield_str); return null(); } @@ -6120,8 +6130,7 @@ Parser::yieldExpression(InHandling inHandling) pc->functionBox()->function()->isGetter() || pc->functionBox()->function()->isSetter()) { - reportWithOffset(ParseError, false, begin, - JSMSG_YIELD_IN_METHOD, js_yield_str); + errorAt(begin, JSMSG_YIELD_IN_METHOD, js_yield_str); return null(); } @@ -6266,7 +6275,7 @@ Parser::labeledStatement(YieldHandling yieldHandling) uint32_t begin = pos().begin; if (pc->findInnermostStatement(hasSameLabel)) { - reportWithOffset(ParseError, false, begin, JSMSG_DUPLICATE_LABEL); + errorAt(begin, JSMSG_DUPLICATE_LABEL); return null(); } @@ -8297,8 +8306,7 @@ Parser::comprehension(GeneratorKind comprehensionKind) return null(); if (comprehensionKind != NotGenerator && pc->lastYieldOffset != startYieldOffset) { - reportWithOffset(ParseError, false, pc->lastYieldOffset, - JSMSG_BAD_GENEXP_BODY, js_yield_str); + errorAt(pc->lastYieldOffset, JSMSG_BAD_GENEXP_BODY, js_yield_str); return null(); } @@ -8360,11 +8368,11 @@ Parser::assignExprWithoutYieldOrAwait(YieldHandling yieldHandling) Node res = assignExpr(InAllowed, yieldHandling, TripledotProhibited); if (res) { if (pc->lastYieldOffset != startYieldOffset) { - reportWithOffset(ParseError, false, pc->lastYieldOffset, JSMSG_YIELD_IN_DEFAULT); + errorAt(pc->lastYieldOffset, JSMSG_YIELD_IN_DEFAULT); return null(); } if (pc->lastAwaitOffset != startAwaitOffset) { - reportWithOffset(ParseError, false, pc->lastAwaitOffset, JSMSG_AWAIT_IN_DEFAULT); + errorAt(pc->lastAwaitOffset, JSMSG_AWAIT_IN_DEFAULT); return null(); } } @@ -9211,8 +9219,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* // Directly report the error when we're not in a // destructuring context. if (!possibleError) { - reportWithOffset(ParseError, false, namePos.begin, - JSMSG_DUPLICATE_PROTO_PROPERTY); + errorAt(namePos.begin, JSMSG_DUPLICATE_PROTO_PROPERTY); return null(); } @@ -9459,7 +9466,7 @@ Parser::tryNewTarget(Node &newTarget) return false; if (!pc->sc()->allowNewTarget()) { - reportWithOffset(ParseError, false, begin, JSMSG_BAD_NEWTARGET); + errorAt(begin, JSMSG_BAD_NEWTARGET); return false; } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 13580846b..efbaebafd 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -915,6 +915,9 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter /* Report the given error at the current offset. */ void error(unsigned errorNumber, ...); + /* Report the given error at the given offset. */ + void errorAt(uint32_t offset, unsigned errorNumber, ...); + /* * Handle a strict mode error at the current offset. Report an error if in * strict mode code, or warn if not, using the given error number and -- cgit v1.2.3 From 4c4f8091e620a35d6d20a5b0ccc6c118e9b8e5e5 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 06:54:09 +0200 Subject: Remove Parser::reportBadReturn Report simpler errors that don't use the offset of a node as location. --- js/src/frontend/Parser.cpp | 23 +++-------------------- js/src/frontend/Parser.h | 2 -- js/src/js.msg | 4 ++-- js/src/tests/js1_7/geniter/regress-352197.js | 2 +- js/src/tests/js1_8/genexps/regress-683738.js | 8 ++++---- 5 files changed, 10 insertions(+), 29 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index b494cc966..0099ed19d 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -909,21 +909,6 @@ Parser::parse() return pn; } -template -bool -Parser::reportBadReturn(Node pn, ParseReportKind kind, - unsigned errnum, unsigned anonerrnum) -{ - JSAutoByteString name; - if (JSAtom* atom = pc->functionBox()->function()->explicitName()) { - if (!AtomToPrintableString(context, atom, &name)) - return false; - } else { - errnum = anonerrnum; - } - return reportWithNode(kind, pc->sc()->strict(), pn, errnum, name.ptr()); -} - /* * Strict mode forbids introducing new definitions for 'eval', 'arguments', or * for any strict mode reserved keyword. @@ -6023,10 +6008,9 @@ Parser::returnStatement(YieldHandling yieldHandling) if (!pn) return null(); + /* Disallow "return v;" in legacy generators. */ if (pc->isLegacyGenerator() && exprNode) { - /* Disallow "return v;" in legacy generators. */ - reportBadReturn(pn, ParseError, JSMSG_BAD_GENERATOR_RETURN, - JSMSG_BAD_ANON_GENERATOR_RETURN); + errorAt(begin, JSMSG_BAD_GENERATOR_RETURN); return null(); } @@ -6141,8 +6125,7 @@ Parser::yieldExpression(InHandling inHandling) ) { /* As in Python (see PEP-255), disallow return v; in generators. */ - reportBadReturn(null(), ParseError, JSMSG_BAD_GENERATOR_RETURN, - JSMSG_BAD_ANON_GENERATOR_RETURN); + errorAt(begin, JSMSG_BAD_GENERATOR_RETURN); return null(); } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index efbaebafd..27a10458b 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1445,8 +1445,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter static Node null() { return ParseHandler::null(); } - bool reportBadReturn(Node pn, ParseReportKind kind, unsigned errnum, unsigned anonerrnum); - JSAtom* prefixAccessorName(PropertyType propType, HandleAtom propAtom); TokenPos pos() const { return tokenStream.currentToken().pos; } diff --git a/js/src/js.msg b/js/src/js.msg index a276dab94..42a48c3a5 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -186,7 +186,6 @@ MSG_DEF(JSMSG_AS_AFTER_IMPORT_STAR, 0, JSEXN_SYNTAXERR, "missing keyword 'as' MSG_DEF(JSMSG_AS_AFTER_RESERVED_WORD, 1, JSEXN_SYNTAXERR, "missing keyword 'as' after reserved word '{0}'") MSG_DEF(JSMSG_ASYNC_GENERATOR, 0, JSEXN_SYNTAXERR, "generator function or method can't be async") MSG_DEF(JSMSG_AWAIT_IN_DEFAULT, 0, JSEXN_SYNTAXERR, "await can't be used in default expression") -MSG_DEF(JSMSG_BAD_ANON_GENERATOR_RETURN, 0, JSEXN_TYPEERR, "anonymous generator function returns a value") MSG_DEF(JSMSG_BAD_ARROW_ARGS, 0, JSEXN_SYNTAXERR, "invalid arrow-function arguments (parentheses around the arrow-function may help)") MSG_DEF(JSMSG_BAD_BINDING, 1, JSEXN_SYNTAXERR, "redefining {0} is deprecated") MSG_DEF(JSMSG_BAD_CONST_DECL, 0, JSEXN_SYNTAXERR, "missing = in const declaration") @@ -200,7 +199,8 @@ MSG_DEF(JSMSG_BAD_FOR_EACH_LOOP, 0, JSEXN_SYNTAXERR, "invalid for each loo MSG_DEF(JSMSG_BAD_FOR_LEFTSIDE, 0, JSEXN_SYNTAXERR, "invalid for-in/of left-hand side") MSG_DEF(JSMSG_LEXICAL_DECL_DEFINES_LET,0, JSEXN_SYNTAXERR, "a lexical declaration can't define a 'let' binding") MSG_DEF(JSMSG_LET_STARTING_FOROF_LHS, 0, JSEXN_SYNTAXERR, "an expression X in 'for (X of Y)' must not start with 'let'") -MSG_DEF(JSMSG_BAD_GENERATOR_RETURN, 1, JSEXN_TYPEERR, "generator function {0} returns a value") +MSG_DEF(JSMSG_BAD_FUNCTION_YIELD, 0, JSEXN_TYPEERR, "can't use 'yield' in a function that can return a value") +MSG_DEF(JSMSG_BAD_GENERATOR_RETURN, 0, JSEXN_TYPEERR, "generator function can't return a value") MSG_DEF(JSMSG_BAD_GENEXP_BODY, 1, JSEXN_SYNTAXERR, "illegal use of {0} in generator expression") MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 0, JSEXN_REFERENCEERR, "invalid increment/decrement operand") MSG_DEF(JSMSG_BAD_METHOD_DEF, 0, JSEXN_SYNTAXERR, "bad method definition") diff --git a/js/src/tests/js1_7/geniter/regress-352197.js b/js/src/tests/js1_7/geniter/regress-352197.js index 7982e12ee..495717af7 100644 --- a/js/src/tests/js1_7/geniter/regress-352197.js +++ b/js/src/tests/js1_7/geniter/regress-352197.js @@ -20,7 +20,7 @@ function test() printBugNumber(BUGNUMBER); printStatus (summary); - expect = /TypeError: anonymous generator function returns a value/; + expect = /TypeError: can't use 'yield' in a function that can return a value/; try { var gen = eval('(function() { { return 5; } yield 3; })'); diff --git a/js/src/tests/js1_8/genexps/regress-683738.js b/js/src/tests/js1_8/genexps/regress-683738.js index de563645d..b0309a90e 100644 --- a/js/src/tests/js1_8/genexps/regress-683738.js +++ b/js/src/tests/js1_8/genexps/regress-683738.js @@ -20,7 +20,7 @@ function test() printBugNumber(BUGNUMBER); printStatus (summary); - expect = "generator function foo returns a value"; + expect = "can't use 'yield' in a function that can return a value"; try { actual = 'No Error'; @@ -32,7 +32,7 @@ function test() } reportCompare(expect, actual, summary + ": 1"); - expect = "generator function foo returns a value"; + expect = "generator function can't return a value"; try { actual = 'No Error'; @@ -44,7 +44,7 @@ function test() } reportCompare(expect, actual, summary + ": 2"); - expect = "generator function foo returns a value"; + expect = "can't use 'yield' in a function that can return a value"; try { actual = 'No Error'; @@ -56,7 +56,7 @@ function test() } reportCompare(expect, actual, summary + ": 3"); - expect = "generator function foo returns a value"; + expect = "generator function can't return a value"; try { actual = 'No Error'; -- cgit v1.2.3 From f5c293d3e82581740558c79cf752bccc0420199c Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 07:30:00 +0200 Subject: Report bad-class-member errors using a specified offset instead of a node's offset. --- js/src/frontend/Parser.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 0099ed19d..2702f3075 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -6673,7 +6673,7 @@ Parser::classDefinition(YieldHandling yieldHandling, propType != PropertyType::AsyncMethod && propType != PropertyType::Constructor && propType != PropertyType::DerivedConstructor) { - error(JSMSG_BAD_METHOD_DEF); + errorAt(nameOffset, JSMSG_BAD_METHOD_DEF); return null(); } @@ -6683,17 +6683,17 @@ Parser::classDefinition(YieldHandling yieldHandling, propType = PropertyType::SetterNoExpressionClosure; if (!isStatic && propAtom == context->names().constructor) { if (propType != PropertyType::Method) { - reportWithNode(ParseError, false, propName, JSMSG_BAD_METHOD_DEF); + errorAt(nameOffset, JSMSG_BAD_METHOD_DEF); return null(); } if (seenConstructor) { - reportWithNode(ParseError, false, propName, JSMSG_DUPLICATE_PROPERTY, "constructor"); + errorAt(nameOffset, JSMSG_DUPLICATE_PROPERTY, "constructor"); return null(); } seenConstructor = true; propType = hasHeritage ? PropertyType::DerivedConstructor : PropertyType::Constructor; } else if (isStatic && propAtom == context->names().prototype) { - reportWithNode(ParseError, false, propName, JSMSG_BAD_METHOD_DEF); + errorAt(nameOffset, JSMSG_BAD_METHOD_DEF); return null(); } -- cgit v1.2.3 From d7b76a5a5286475fcba1663028032a7ea834daed Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:31:01 +0200 Subject: Report for-loop-decl-with-initializer errors using a specified offset instead of a node's offset. --- js/src/frontend/Parser.cpp | 4 ++-- js/src/js.msg | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 2702f3075..a26520477 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -4459,7 +4459,7 @@ Parser::initializerInNameDeclaration(Node decl, Node binding, // // for (var/let/const x = ... of ...); // BAD if (isForOf) { - reportWithNode(ParseError, false, binding, JSMSG_BAD_FOR_LEFTSIDE); + errorAt(initializerOffset, JSMSG_OF_AFTER_FOR_LOOP_DECL); return false; } @@ -4468,7 +4468,7 @@ Parser::initializerInNameDeclaration(Node decl, Node binding, // // for (let/const x = ... in ...); // BAD if (DeclarationKindIsLexical(declKind)) { - reportWithNode(ParseError, false, binding, JSMSG_BAD_FOR_LEFTSIDE); + errorAt(initializerOffset, JSMSG_IN_AFTER_LEXICAL_FOR_DECL); return false; } diff --git a/js/src/js.msg b/js/src/js.msg index 42a48c3a5..a19e3aa85 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -262,6 +262,8 @@ MSG_DEF(JSMSG_GARBAGE_AFTER_INPUT, 2, JSEXN_SYNTAXERR, "unexpected garbage a MSG_DEF(JSMSG_IDSTART_AFTER_NUMBER, 0, JSEXN_SYNTAXERR, "identifier starts immediately after numeric literal") MSG_DEF(JSMSG_ILLEGAL_CHARACTER, 0, JSEXN_SYNTAXERR, "illegal character") MSG_DEF(JSMSG_IMPORT_DECL_AT_TOP_LEVEL, 0, JSEXN_SYNTAXERR, "import declarations may only appear at top level of a module") +MSG_DEF(JSMSG_OF_AFTER_FOR_LOOP_DECL, 0, JSEXN_SYNTAXERR, "a declaration in the head of a for-of loop can't have an initializer") +MSG_DEF(JSMSG_IN_AFTER_LEXICAL_FOR_DECL,0,JSEXN_SYNTAXERR, "a lexical declaration in the head of a for-in loop can't have an initializer") MSG_DEF(JSMSG_INVALID_FOR_IN_DECL_WITH_INIT,0,JSEXN_SYNTAXERR,"for-in loop head declarations may not have initializers") MSG_DEF(JSMSG_LABEL_NOT_FOUND, 0, JSEXN_SYNTAXERR, "label not found") MSG_DEF(JSMSG_LET_COMP_BINDING, 0, JSEXN_SYNTAXERR, "'let' is not a valid name for a comprehension variable") -- cgit v1.2.3 From 940a6ceb9a5b3d8c7c2ed53da67f5c14cc84925c Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:33:24 +0200 Subject: Introduce Parser::warningAt This reduces reporting an warning at a particular offset to its bare essentials, simplifying calls. --- js/src/frontend/Parser.cpp | 26 ++++++++++++++++---------- js/src/frontend/Parser.h | 5 +++-- 2 files changed, 19 insertions(+), 12 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index a26520477..43f39dc23 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -633,6 +633,17 @@ Parser::warning(unsigned errorNumber, ...) return result; } +template +bool +Parser::warningAt(uint32_t offset, unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); + bool result = reportHelper(ParseWarning, false, offset, errorNumber, args); + va_end(args); + return result; +} + template bool Parser::extraWarning(unsigned errorNumber, ...) @@ -3858,8 +3869,7 @@ Parser::maybeParseDirective(Node list, Node possibleDirective, boo } else if (directive == context->names().useAsm) { if (pc->isFunctionBox()) return asmJS(list); - return reportWithOffset(ParseWarning, false, directivePos.begin, - JSMSG_USE_ASM_DIRECTIVE_FAIL); + return warningAt(directivePos.begin, JSMSG_USE_ASM_DIRECTIVE_FAIL); } } return true; @@ -3903,11 +3913,9 @@ Parser::statementList(YieldHandling yieldHandling) if (!warnedAboutStatementsAfterReturn) { if (afterReturn) { if (!handler.isStatementPermittedAfterReturnStatement(next)) { - if (!reportWithOffset(ParseWarning, false, statementBegin, - JSMSG_STMT_AFTER_RETURN)) - { + if (!warningAt(statementBegin, JSMSG_STMT_AFTER_RETURN)) return null(); - } + warnedAboutStatementsAfterReturn = true; } } else if (handler.isReturnStatement(next)) { @@ -5836,11 +5844,9 @@ Parser::switchStatement(YieldHandling yieldHandling) if (!warnedAboutStatementsAfterReturn) { if (afterReturn) { if (!handler.isStatementPermittedAfterReturnStatement(stmt)) { - if (!reportWithOffset(ParseWarning, false, statementBegin, - JSMSG_STMT_AFTER_RETURN)) - { + if (!warningAt(statementBegin, JSMSG_STMT_AFTER_RETURN)) return null(); - } + warnedAboutStatementsAfterReturn = true; } } else if (handler.isReturnStatement(stmt)) { diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 27a10458b..6bd7e586e 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -909,8 +909,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter public: bool reportWithNode(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...); bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...); - bool reportWithOffset(ParseReportKind kind, bool strict, uint32_t offset, unsigned errorNumber, - ...); /* Report the given error at the current offset. */ void error(unsigned errorNumber, ...); @@ -935,6 +933,9 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter /* Report the given warning at the current offset. */ MOZ_MUST_USE bool warning(unsigned errorNumber, ...); + /* Report the given warning at the given offset. */ + MOZ_MUST_USE bool warningAt(uint32_t offset, unsigned errorNumber, ...); + /* * If extra warnings are enabled, report the given warning at the current * offset. -- cgit v1.2.3 From 51e2758e02a6187228e35f58bfa0e1752870476b Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:34:17 +0200 Subject: Remove Parser::reportWithOffset since it's no longer used. --- js/src/frontend/Parser.cpp | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 43f39dc23..9f9169950 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -701,18 +701,6 @@ Parser::reportNoOffset(ParseReportKind kind, bool strict, unsigned return result; } -template -bool -Parser::reportWithOffset(ParseReportKind kind, bool strict, uint32_t offset, - unsigned errorNumber, ...) -{ - va_list args; - va_start(args, errorNumber); - bool result = reportHelper(kind, strict, offset, errorNumber, args); - va_end(args); - return result; -} - template <> bool Parser::abortIfSyntaxParser() -- cgit v1.2.3 From d60cfce5e4b2e7ecf344b86c1bd4a712490a8c52 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:37:12 +0200 Subject: Report the error for uninitialized const-declaration in for(;;) loop head using an explicit offset. --- js/src/frontend/Parser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 9f9169950..fe30328de 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -4577,7 +4577,7 @@ Parser::declarationName(Node decl, DeclarationKind declKind, Token // Normal const declarations, and const declarations in for(;;) // heads, must be initialized. if (declKind == DeclarationKind::Const) { - reportWithNode(ParseError, false, binding, JSMSG_BAD_CONST_DECL); + errorAt(namePos.begin, JSMSG_BAD_CONST_DECL); return null(); } } -- cgit v1.2.3 From 4a62cbec61620f54bfb3949d9165c4dd406c2444 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:41:42 +0200 Subject: Report some errors about invalid left-hand-sides in for-in/of loop heads using code with an explicitly computed offset. --- js/src/frontend/Parser.cpp | 62 +++++++++++++++++++--------------------------- js/src/frontend/Parser.h | 2 -- 2 files changed, 26 insertions(+), 38 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index fe30328de..94573fce7 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -5415,37 +5415,6 @@ Parser::matchInOrOf(bool* isForInp, bool* isForOfp) return true; } -template -bool -Parser::validateForInOrOfLHSExpression(Node target, PossibleError* possibleError) -{ - if (handler.isUnparenthesizedDestructuringPattern(target)) - return checkDestructuringPattern(target, Nothing(), possibleError); - - // All other permitted targets are simple. - if (!reportIfNotValidSimpleAssignmentTarget(target, ForInOrOfTarget)) - return false; - - if (handler.isPropertyAccess(target)) - return true; - - if (handler.isNameAnyParentheses(target)) { - // The arguments/eval identifiers are simple in non-strict mode code, - // but warn to discourage use nonetheless. - if (!reportIfArgumentsEvalTarget(target)) - return false; - - handler.adjustGetToSet(target); - return true; - } - - if (handler.isFunctionCall(target)) - return checkAssignmentToCall(target, JSMSG_BAD_FOR_LEFTSIDE); - - reportWithNode(ParseError, false, target, JSMSG_BAD_FOR_LEFTSIDE); - return false; -} - template bool Parser::forHeadStart(YieldHandling yieldHandling, @@ -5526,6 +5495,10 @@ Parser::forHeadStart(YieldHandling yieldHandling, return *forInitialPart != null(); } + uint32_t exprOffset; + if (!tokenStream.peekOffset(&exprOffset, TokenStream::Operand)) + return false; + // Finally, handle for-loops that start with expressions. Pass // |InProhibited| so that |in| isn't parsed in a RelationalExpression as a // binary operator. |in| makes it a for-in loop, *not* an |in| expression. @@ -5569,8 +5542,29 @@ Parser::forHeadStart(YieldHandling yieldHandling, *forHeadKind = isForIn ? PNK_FORIN : PNK_FOROF; - if (!validateForInOrOfLHSExpression(*forInitialPart, &possibleError)) + // Verify the left-hand side expression doesn't have a forbidden form. + if (handler.isUnparenthesizedDestructuringPattern(*forInitialPart)) { + if (!checkDestructuringPattern(*forInitialPart, Nothing(), &possibleError)) + return false; + } else if (handler.isNameAnyParentheses(*forInitialPart)) { + const char* chars = handler.nameIsArgumentsEvalAnyParentheses(*forInitialPart, context); + if (chars) { + // |chars| is "arguments" or "eval" here. + if (!strictModeErrorAt(exprOffset, JSMSG_BAD_STRICT_ASSIGN, chars)) + return false; + } + + handler.adjustGetToSet(*forInitialPart); + } else if (handler.isPropertyAccess(*forInitialPart)) { + // Permitted: no additional testing/fixup needed. + } else if (handler.isFunctionCall(*forInitialPart)) { + if (!strictModeErrorAt(exprOffset, JSMSG_BAD_FOR_LEFTSIDE)) + return false; + } else { + errorAt(exprOffset, JSMSG_BAD_FOR_LEFTSIDE); return false; + } + if (!possibleError.checkForExpressionError()) return false; @@ -7869,10 +7863,6 @@ Parser::reportIfNotValidSimpleAssignmentTarget(Node target, Assign case CompoundAssignment: errnum = JSMSG_BAD_LEFTSIDE_OF_ASS; break; - - case ForInOrOfTarget: - errnum = JSMSG_BAD_FOR_LEFTSIDE; - break; } reportWithNode(ParseError, pc->sc()->strict(), target, errnum, extra); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 6bd7e586e..e3827d953 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1139,7 +1139,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter Node* forInitialPart, mozilla::Maybe& forLetImpliedScope, Node* forInOrOfExpression); - bool validateForInOrOfLHSExpression(Node target, PossibleError* possibleError); Node expressionAfterForInOrOf(ParseNodeKind forHeadKind, YieldHandling yieldHandling); Node switchStatement(YieldHandling yieldHandling); @@ -1338,7 +1337,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter KeyedDestructuringAssignment, IncrementAssignment, DecrementAssignment, - ForInOrOfTarget }; bool checkAndMarkAsAssignmentLhs(Node pn, AssignmentFlavor flavor, -- cgit v1.2.3 From 8e8d0ed75c076b4b92e2971ff877b104dafeffca Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:44:48 +0200 Subject: Remove for-in/of loop parsing code that redundantly marks the loop target as assigned -- Parser::forHeadStart already does this. --- js/src/frontend/Parser.cpp | 6 ------ 1 file changed, 6 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 94573fce7..c979e38c3 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -5715,12 +5715,6 @@ Parser::forStatement(YieldHandling yieldHandling) stmt.refineForKind(StatementKind::ForOfLoop); } - if (!handler.isDeclarationList(target)) { - MOZ_ASSERT(!forLoopLexicalScope); - if (!checkAndMarkAsAssignmentLhs(target, PlainAssignment)) - return null(); - } - // Parser::declaration consumed everything up to the closing ')'. That // token follows an {Assignment,}Expression, so the next token must be // consumed as if an operator continued the expression, i.e. as None. -- cgit v1.2.3 From b579e0567c887743d24c2745065b71bb06fea4f8 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:46:15 +0200 Subject: Simplify checking of the left-hand side of assignment and compound assignment expressions. --- js/src/frontend/Parser.cpp | 74 ++++++++++++++++++---------------------------- js/src/frontend/Parser.h | 4 --- 2 files changed, 28 insertions(+), 50 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index c979e38c3..3a5b5d6d7 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -7470,45 +7470,6 @@ Parser::condExpr1(InHandling inHandling, YieldHandling yieldHandli return handler.newConditional(condition, thenExpr, elseExpr); } -template -bool -Parser::checkAndMarkAsAssignmentLhs(Node target, AssignmentFlavor flavor, - PossibleError* possibleError) -{ - MOZ_ASSERT(flavor != KeyedDestructuringAssignment, - "destructuring must use special checking/marking code, not " - "this method"); - - if (handler.isUnparenthesizedDestructuringPattern(target)) { - if (flavor == CompoundAssignment) { - error(JSMSG_BAD_DESTRUCT_ASS); - return false; - } - - return checkDestructuringPattern(target, Nothing(), possibleError); - } - - // All other permitted targets are simple. - if (!reportIfNotValidSimpleAssignmentTarget(target, flavor)) - return false; - - if (handler.isPropertyAccess(target)) - return true; - - if (handler.isNameAnyParentheses(target)) { - // The arguments/eval identifiers are simple in non-strict mode code, - // but warn to discourage use nonetheless. - if (!reportIfArgumentsEvalTarget(target)) - return false; - - handler.adjustGetToSet(target); - return true; - } - - MOZ_ASSERT(handler.isFunctionCall(target)); - return checkAssignmentToCall(target, JSMSG_BAD_LEFTSIDE_OF_ASS); -} - class AutoClearInDestructuringDecl { ParseContext* pc_; @@ -7553,6 +7514,8 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); + uint32_t exprOffset = pos().begin; + bool endsExpr; if (tt == TOK_NAME) { @@ -7752,9 +7715,33 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl return lhs; } - AssignmentFlavor flavor = kind == PNK_ASSIGN ? PlainAssignment : CompoundAssignment; - if (!checkAndMarkAsAssignmentLhs(lhs, flavor, &possibleErrorInner)) + // Verify the left-hand side expression doesn't have a forbidden form. + if (handler.isUnparenthesizedDestructuringPattern(lhs)) { + if (kind != PNK_ASSIGN) { + error(JSMSG_BAD_DESTRUCT_ASS); + return null(); + } + + if (!checkDestructuringPattern(lhs, Nothing(), &possibleErrorInner)) + return null(); + } else if (handler.isNameAnyParentheses(lhs)) { + if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(lhs, context)) { + // |chars| is "arguments" or "eval" here. + if (!strictModeErrorAt(exprOffset, JSMSG_BAD_STRICT_ASSIGN, chars)) + return null(); + } + + handler.adjustGetToSet(lhs); + } else if (handler.isPropertyAccess(lhs)) { + // Permitted: no additional testing/fixup needed. + } else if (handler.isFunctionCall(lhs)) { + if (!strictModeErrorAt(exprOffset, JSMSG_BAD_LEFTSIDE_OF_ASS)) + return null(); + } else { + errorAt(exprOffset, JSMSG_BAD_LEFTSIDE_OF_ASS); return null(); + } + if (!possibleErrorInner.checkForExpressionError()) return null(); @@ -7852,11 +7839,6 @@ Parser::reportIfNotValidSimpleAssignmentTarget(Node target, Assign case KeyedDestructuringAssignment: errnum = JSMSG_BAD_DESTRUCT_TARGET; break; - - case PlainAssignment: - case CompoundAssignment: - errnum = JSMSG_BAD_LEFTSIDE_OF_ASS; - break; } reportWithNode(ParseError, pc->sc()->strict(), target, errnum, extra); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index e3827d953..70d382501 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1332,15 +1332,11 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter } enum AssignmentFlavor { - PlainAssignment, - CompoundAssignment, KeyedDestructuringAssignment, IncrementAssignment, DecrementAssignment, }; - bool checkAndMarkAsAssignmentLhs(Node pn, AssignmentFlavor flavor, - PossibleError* possibleError=nullptr); bool matchInOrOf(bool* isForInp, bool* isForOfp); bool hasUsedFunctionSpecialName(HandlePropertyName name); -- cgit v1.2.3 From f4fec66e094281465ce1d143e00b0c9bda4863af Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:47:27 +0200 Subject: Specify an explicit offset when reporting an error for a for-of loop whose target is an expression that begins with 'let'. --- js/src/frontend/Parser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 3a5b5d6d7..3f793ffcf 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -5536,7 +5536,7 @@ Parser::forHeadStart(YieldHandling yieldHandling, // // See ES6 13.7. if (isForOf && letIsIdentifier) { - reportWithNode(ParseError, false, *forInitialPart, JSMSG_LET_STARTING_FOROF_LHS); + errorAt(exprOffset, JSMSG_LET_STARTING_FOROF_LHS); return false; } -- cgit v1.2.3 From 194e6155211353738bb14ffd1ca9e9662a455b0e Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:55:02 +0200 Subject: Inline Parser::checkAssignmentToCall into its sole caller. --- js/src/frontend/Parser.cpp | 19 +++++-------------- js/src/frontend/Parser.h | 2 -- 2 files changed, 5 insertions(+), 16 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 3f793ffcf..041c92fa7 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -4084,19 +4084,6 @@ Parser::PossibleError::transferErrorsTo(PossibleError* other) transferErrorTo(ErrorKind::Expression, other); } -template -bool -Parser::checkAssignmentToCall(Node target, unsigned msg) -{ - MOZ_ASSERT(handler.isFunctionCall(target)); - - // Assignment to function calls is forbidden in ES6. We're still somewhat - // concerned about sites using this in dead code, so forbid it only in - // strict mode code (or if the werror option has been set), and otherwise - // warn. - return reportWithNode(ParseStrictError, pc->sc()->strict(), target, msg); -} - template <> bool Parser::checkDestructuringName(ParseNode* expr, Maybe maybeDecl) @@ -7862,7 +7849,11 @@ Parser::checkAndMarkAsIncOperand(Node target, AssignmentFlavor fla if (!reportIfArgumentsEvalTarget(target)) return false; } else if (handler.isFunctionCall(target)) { - if (!checkAssignmentToCall(target, JSMSG_BAD_INCOP_OPERAND)) + // Assignment to function calls is forbidden in ES6. We're still + // somewhat concerned about sites using this in dead code, so forbid it + // only in strict mode code (or if the werror option has been set), and + // otherwise warn. + if (!reportWithNode(ParseStrictError, pc->sc()->strict(), target, JSMSG_BAD_INCOP_OPERAND)) return false; } return true; diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 70d382501..8bffafc42 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1432,8 +1432,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool checkDestructuringObject(Node objectPattern, mozilla::Maybe maybeDecl); bool checkDestructuringName(Node expr, mozilla::Maybe maybeDecl); - bool checkAssignmentToCall(Node node, unsigned errnum); - Node newNumber(const Token& tok) { return handler.newNumber(tok.number(), tok.decimalPoint(), tok.pos); } -- cgit v1.2.3 From 8580bf233e69da042e3d33cad56ca6f42ce441a4 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:56:39 +0200 Subject: Simplify increment/decrement operand checking. --- js/src/frontend/Parser.cpp | 34 ++++++++++++++++++---------------- js/src/frontend/Parser.h | 2 +- js/src/js.msg | 2 +- 3 files changed, 20 insertions(+), 18 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 041c92fa7..5c4d509dd 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -7834,20 +7834,18 @@ Parser::reportIfNotValidSimpleAssignmentTarget(Node target, Assign template bool -Parser::checkAndMarkAsIncOperand(Node target, AssignmentFlavor flavor) +Parser::checkAndMarkAsIncOperand(Node target) { - MOZ_ASSERT(flavor == IncrementAssignment || flavor == DecrementAssignment); - - // Check. - if (!reportIfNotValidSimpleAssignmentTarget(target, flavor)) - return false; - - // Mark. if (handler.isNameAnyParentheses(target)) { - // Assignment to arguments/eval is allowed outside strict mode code, - // but it's dodgy. Report a strict warning (error, if werror was set). - if (!reportIfArgumentsEvalTarget(target)) - return false; + if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(target, context)) { + if (!reportWithNode(ParseStrictError, pc->sc()->strict(), target, + JSMSG_BAD_STRICT_ASSIGN, chars)) + { + return false; + } + } + } else if (handler.isPropertyAccess(target)) { + // Permitted: no additional testing/fixup needed. } else if (handler.isFunctionCall(target)) { // Assignment to function calls is forbidden in ES6. We're still // somewhat concerned about sites using this in dead code, so forbid it @@ -7855,7 +7853,13 @@ Parser::checkAndMarkAsIncOperand(Node target, AssignmentFlavor fla // otherwise warn. if (!reportWithNode(ParseStrictError, pc->sc()->strict(), target, JSMSG_BAD_INCOP_OPERAND)) return false; + } else { + reportWithNode(ParseError, pc->sc()->strict(), target, JSMSG_BAD_INCOP_OPERAND); + return false; } + + MOZ_ASSERT(isValidSimpleAssignmentTarget(target, PermitAssignmentToFunctionCalls), + "inconsistent increment/decrement operand validation"); return true; } @@ -7922,8 +7926,7 @@ Parser::unaryExpr(YieldHandling yieldHandling, TripledotHandling t Node pn2 = memberExpr(yieldHandling, TripledotProhibited, tt2); if (!pn2) return null(); - AssignmentFlavor flavor = (tt == TOK_INC) ? IncrementAssignment : DecrementAssignment; - if (!checkAndMarkAsIncOperand(pn2, flavor)) + if (!checkAndMarkAsIncOperand(pn2)) return null(); return handler.newUpdate((tt == TOK_INC) ? PNK_PREINCREMENT : PNK_PREDECREMENT, begin, @@ -7977,8 +7980,7 @@ Parser::unaryExpr(YieldHandling yieldHandling, TripledotHandling t return null(); if (tt == TOK_INC || tt == TOK_DEC) { tokenStream.consumeKnownToken(tt); - AssignmentFlavor flavor = (tt == TOK_INC) ? IncrementAssignment : DecrementAssignment; - if (!checkAndMarkAsIncOperand(pn, flavor)) + if (!checkAndMarkAsIncOperand(pn)) return null(); return handler.newUpdate((tt == TOK_INC) ? PNK_POSTINCREMENT : PNK_POSTDECREMENT, begin, diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 8bffafc42..c50f8e47d 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1377,7 +1377,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool reportIfArgumentsEvalTarget(Node nameNode); bool reportIfNotValidSimpleAssignmentTarget(Node target, AssignmentFlavor flavor); - bool checkAndMarkAsIncOperand(Node kid, AssignmentFlavor flavor); + bool checkAndMarkAsIncOperand(Node kid); bool checkStrictAssignment(Node lhs); bool checkStrictBinding(PropertyName* name, TokenPos pos); diff --git a/js/src/js.msg b/js/src/js.msg index a19e3aa85..2901b88cc 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -202,7 +202,7 @@ MSG_DEF(JSMSG_LET_STARTING_FOROF_LHS, 0, JSEXN_SYNTAXERR, "an expression X in ' MSG_DEF(JSMSG_BAD_FUNCTION_YIELD, 0, JSEXN_TYPEERR, "can't use 'yield' in a function that can return a value") MSG_DEF(JSMSG_BAD_GENERATOR_RETURN, 0, JSEXN_TYPEERR, "generator function can't return a value") MSG_DEF(JSMSG_BAD_GENEXP_BODY, 1, JSEXN_SYNTAXERR, "illegal use of {0} in generator expression") -MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 0, JSEXN_REFERENCEERR, "invalid increment/decrement operand") +MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 0, JSEXN_SYNTAXERR, "invalid increment/decrement operand") MSG_DEF(JSMSG_BAD_METHOD_DEF, 0, JSEXN_SYNTAXERR, "bad method definition") MSG_DEF(JSMSG_BAD_OCTAL, 1, JSEXN_SYNTAXERR, "{0} is not a legal ECMA-262 octal constant") MSG_DEF(JSMSG_BAD_OPERAND, 1, JSEXN_SYNTAXERR, "invalid {0} operand") -- cgit v1.2.3 From 74672745e6d1932a4aa7fa6a8cd6ab09fd9de4fe Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 11:05:22 +0200 Subject: Simplify checking of targets within destructuring patterns. --- js/src/frontend/Parser.cpp | 86 ++++++++-------------------------------------- js/src/frontend/Parser.h | 9 ----- js/src/js.msg | 1 - 3 files changed, 14 insertions(+), 82 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 5c4d509dd..3e7c25c19 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -4113,22 +4113,23 @@ Parser::checkDestructuringName(ParseNode* expr, Maybesc()->strict(), expr, + JSMSG_BAD_STRICT_ASSIGN, chars)) + { + return false; + } + } + + return true; } - // Nothing further to do for property accesses. - MOZ_ASSERT(handler.isPropertyAccess(expr)); - return true; + if (handler.isPropertyAccess(expr)) + return true; + + reportWithNode(ParseError, pc->sc()->strict(), expr, JSMSG_BAD_DESTRUCT_TARGET); + return false; } template <> @@ -7773,65 +7774,6 @@ Parser::isValidSimpleAssignmentTarget(Node node, return false; } -template -bool -Parser::reportIfArgumentsEvalTarget(Node nameNode) -{ - const char* chars = handler.nameIsArgumentsEvalAnyParentheses(nameNode, context); - if (!chars) - return true; - - bool strict = pc->sc()->strict(); - if (!reportWithNode(ParseStrictError, strict, nameNode, JSMSG_BAD_STRICT_ASSIGN, chars)) - return false; - - MOZ_ASSERT(!strict, - "an error should have been reported if this was strict mode " - "code"); - return true; -} - -template -bool -Parser::reportIfNotValidSimpleAssignmentTarget(Node target, AssignmentFlavor flavor) -{ - FunctionCallBehavior behavior = flavor == KeyedDestructuringAssignment - ? ForbidAssignmentToFunctionCalls - : PermitAssignmentToFunctionCalls; - if (isValidSimpleAssignmentTarget(target, behavior)) - return true; - - if (handler.isNameAnyParentheses(target)) { - // Use a special error if the target is arguments/eval. This ensures - // targeting these names is consistently a SyntaxError (which error numbers - // below don't guarantee) while giving us a nicer error message. - if (!reportIfArgumentsEvalTarget(target)) - return false; - } - - unsigned errnum = 0; - const char* extra = nullptr; - - switch (flavor) { - case IncrementAssignment: - errnum = JSMSG_BAD_OPERAND; - extra = "increment"; - break; - - case DecrementAssignment: - errnum = JSMSG_BAD_OPERAND; - extra = "decrement"; - break; - - case KeyedDestructuringAssignment: - errnum = JSMSG_BAD_DESTRUCT_TARGET; - break; - } - - reportWithNode(ParseError, pc->sc()->strict(), target, errnum, extra); - return false; -} - template bool Parser::checkAndMarkAsIncOperand(Node target) diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index c50f8e47d..0baaac3bc 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1331,12 +1331,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter #endif } - enum AssignmentFlavor { - KeyedDestructuringAssignment, - IncrementAssignment, - DecrementAssignment, - }; - bool matchInOrOf(bool* isForInp, bool* isForOfp); bool hasUsedFunctionSpecialName(HandlePropertyName name); @@ -1374,9 +1368,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter FunctionCallBehavior behavior = ForbidAssignmentToFunctionCalls); private: - bool reportIfArgumentsEvalTarget(Node nameNode); - bool reportIfNotValidSimpleAssignmentTarget(Node target, AssignmentFlavor flavor); - bool checkAndMarkAsIncOperand(Node kid); bool checkStrictAssignment(Node lhs); bool checkStrictBinding(PropertyName* name, TokenPos pos); diff --git a/js/src/js.msg b/js/src/js.msg index 2901b88cc..4ded69a25 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -205,7 +205,6 @@ MSG_DEF(JSMSG_BAD_GENEXP_BODY, 1, JSEXN_SYNTAXERR, "illegal use of {0} i MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 0, JSEXN_SYNTAXERR, "invalid increment/decrement operand") MSG_DEF(JSMSG_BAD_METHOD_DEF, 0, JSEXN_SYNTAXERR, "bad method definition") MSG_DEF(JSMSG_BAD_OCTAL, 1, JSEXN_SYNTAXERR, "{0} is not a legal ECMA-262 octal constant") -MSG_DEF(JSMSG_BAD_OPERAND, 1, JSEXN_SYNTAXERR, "invalid {0} operand") MSG_DEF(JSMSG_BAD_POW_LEFTSIDE, 0, JSEXN_SYNTAXERR, "unparenthesized unary expression can't appear on the left-hand side of '**'") MSG_DEF(JSMSG_BAD_PROP_ID, 0, JSEXN_SYNTAXERR, "invalid property id") MSG_DEF(JSMSG_BAD_RETURN_OR_YIELD, 1, JSEXN_SYNTAXERR, "{0} not in function") -- cgit v1.2.3 From 7ea8efe0cb3199566b86a2b7ad4cb99df8620324 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 11:11:04 +0200 Subject: Report errors for bad increment/decrement operands using explicitly-specified offsets. --- js/src/frontend/Parser.cpp | 55 ++++++++++++++++++++++------------------------ js/src/frontend/Parser.h | 2 +- 2 files changed, 27 insertions(+), 30 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 3e7c25c19..3b1cadbff 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -7776,31 +7776,28 @@ Parser::isValidSimpleAssignmentTarget(Node node, template bool -Parser::checkAndMarkAsIncOperand(Node target) +Parser::checkIncDecOperand(Node operand, uint32_t operandOffset) { - if (handler.isNameAnyParentheses(target)) { - if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(target, context)) { - if (!reportWithNode(ParseStrictError, pc->sc()->strict(), target, - JSMSG_BAD_STRICT_ASSIGN, chars)) - { + if (handler.isNameAnyParentheses(operand)) { + if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(operand, context)) { + if (!strictModeErrorAt(operandOffset, JSMSG_BAD_STRICT_ASSIGN, chars)) return false; - } } - } else if (handler.isPropertyAccess(target)) { + } else if (handler.isPropertyAccess(operand)) { // Permitted: no additional testing/fixup needed. - } else if (handler.isFunctionCall(target)) { + } else if (handler.isFunctionCall(operand)) { // Assignment to function calls is forbidden in ES6. We're still // somewhat concerned about sites using this in dead code, so forbid it // only in strict mode code (or if the werror option has been set), and // otherwise warn. - if (!reportWithNode(ParseStrictError, pc->sc()->strict(), target, JSMSG_BAD_INCOP_OPERAND)) + if (!strictModeErrorAt(operandOffset, JSMSG_BAD_INCOP_OPERAND)) return false; } else { - reportWithNode(ParseError, pc->sc()->strict(), target, JSMSG_BAD_INCOP_OPERAND); + errorAt(operandOffset, JSMSG_BAD_INCOP_OPERAND); return false; } - MOZ_ASSERT(isValidSimpleAssignmentTarget(target, PermitAssignmentToFunctionCalls), + MOZ_ASSERT(isValidSimpleAssignmentTarget(operand, PermitAssignmentToFunctionCalls), "inconsistent increment/decrement operand validation"); return true; } @@ -7865,14 +7862,14 @@ Parser::unaryExpr(YieldHandling yieldHandling, TripledotHandling t TokenKind tt2; if (!tokenStream.getToken(&tt2, TokenStream::Operand)) return null(); - Node pn2 = memberExpr(yieldHandling, TripledotProhibited, tt2); - if (!pn2) - return null(); - if (!checkAndMarkAsIncOperand(pn2)) + + uint32_t operandOffset = pos().begin; + Node operand = memberExpr(yieldHandling, TripledotProhibited, tt2); + if (!operand || !checkIncDecOperand(operand, operandOffset)) return null(); + return handler.newUpdate((tt == TOK_INC) ? PNK_PREINCREMENT : PNK_PREDECREMENT, - begin, - pn2); + begin, operand); } case TOK_DELETE: { @@ -7912,23 +7909,23 @@ Parser::unaryExpr(YieldHandling yieldHandling, TripledotHandling t } default: { - Node pn = memberExpr(yieldHandling, tripledotHandling, tt, /* allowCallSyntax = */ true, + Node expr = memberExpr(yieldHandling, tripledotHandling, tt, /* allowCallSyntax = */ true, possibleError, invoked); - if (!pn) + if (!expr) return null(); /* Don't look across a newline boundary for a postfix incop. */ if (!tokenStream.peekTokenSameLine(&tt)) return null(); - if (tt == TOK_INC || tt == TOK_DEC) { - tokenStream.consumeKnownToken(tt); - if (!checkAndMarkAsIncOperand(pn)) - return null(); - return handler.newUpdate((tt == TOK_INC) ? PNK_POSTINCREMENT : PNK_POSTDECREMENT, - begin, - pn); - } - return pn; + + if (tt != TOK_INC && tt != TOK_DEC) + return expr; + + tokenStream.consumeKnownToken(tt); + if (!checkIncDecOperand(expr, begin)) + return null(); + return handler.newUpdate((tt == TOK_INC) ? PNK_POSTINCREMENT : PNK_POSTDECREMENT, + begin, expr); } } } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 0baaac3bc..a7e48c1a4 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1368,7 +1368,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter FunctionCallBehavior behavior = ForbidAssignmentToFunctionCalls); private: - bool checkAndMarkAsIncOperand(Node kid); + bool checkIncDecOperand(Node operand, uint32_t operandOffset); bool checkStrictAssignment(Node lhs); bool checkStrictBinding(PropertyName* name, TokenPos pos); -- cgit v1.2.3 From 4f62fda966af85252f8345e51d694cd6d3a063c8 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 11:18:36 +0200 Subject: Remove Parser::reportWithNode and its remaining callers. All of the callsites have a full ParseNode* at hand, of which the offset can be directly accessed. --- js/src/frontend/Parser.cpp | 30 +++++++----------------------- js/src/frontend/Parser.h | 1 - 2 files changed, 7 insertions(+), 24 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 3b1cadbff..c08ba4889 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -677,19 +677,6 @@ Parser::strictModeErrorAt(uint32_t offset, unsigned errorNumber, . return res; } -template -bool -Parser::reportWithNode(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...) -{ - uint32_t offset = (pn ? handler.getPosition(pn) : pos()).begin; - - va_list args; - va_start(args, errorNumber); - bool result = reportHelper(kind, strict, offset, errorNumber, args); - va_end(args); - return result; -} - template bool Parser::reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...) @@ -4094,7 +4081,7 @@ Parser::checkDestructuringName(ParseNode* expr, Maybepn_pos.begin, JSMSG_BAD_DESTRUCT_PARENS); return false; } @@ -4104,7 +4091,7 @@ Parser::checkDestructuringName(ParseNode* expr, Maybepn_pos.begin, JSMSG_NO_VARIABLE_NAME); return false; } @@ -4115,11 +4102,8 @@ Parser::checkDestructuringName(ParseNode* expr, Maybesc()->strict(), expr, - JSMSG_BAD_STRICT_ASSIGN, chars)) - { + if (!strictModeErrorAt(expr->pn_pos.begin, JSMSG_BAD_STRICT_ASSIGN, chars)) return false; - } } return true; @@ -4128,7 +4112,7 @@ Parser::checkDestructuringName(ParseNode* expr, Maybesc()->strict(), expr, JSMSG_BAD_DESTRUCT_TARGET); + errorAt(expr->pn_pos.begin, JSMSG_BAD_DESTRUCT_TARGET); return false; } @@ -4187,7 +4171,7 @@ Parser::checkDestructuringArray(ParseNode* arrayPattern, ParseNode* target; if (element->isKind(PNK_SPREAD)) { if (element->pn_next) { - reportWithNode(ParseError, false, element->pn_next, JSMSG_PARAMETER_AFTER_REST); + errorAt(element->pn_next->pn_pos.begin, JSMSG_PARAMETER_AFTER_REST); return false; } target = element->pn_kid; @@ -4250,7 +4234,7 @@ Parser::checkDestructuringPattern(ParseNode* pattern, PossibleError* possibleError /* = nullptr */) { if (pattern->isKind(PNK_ARRAYCOMP)) { - reportWithNode(ParseError, false, pattern, JSMSG_ARRAY_COMP_LEFTSIDE); + errorAt(pattern->pn_pos.begin, JSMSG_ARRAY_COMP_LEFTSIDE); return false; } @@ -5696,7 +5680,7 @@ Parser::forStatement(YieldHandling yieldHandling) iflags |= JSITER_ENUMERATE; } else { if (isForEach) { - reportWithNode(ParseError, false, startNode, JSMSG_BAD_FOR_EACH_LOOP); + errorAt(begin, JSMSG_BAD_FOR_EACH_LOOP); return null(); } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index a7e48c1a4..196c71fa5 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -907,7 +907,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool reportHelper(ParseReportKind kind, bool strict, uint32_t offset, unsigned errorNumber, va_list args); public: - bool reportWithNode(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...); bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...); /* Report the given error at the current offset. */ -- cgit v1.2.3 From f38ef66b7b9f1d1c85c5d8a7a5bbaa5f6c3c9948 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 11:20:43 +0200 Subject: Inline Parser::reportHelper into its callers. --- js/src/frontend/Parser.cpp | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index c08ba4889..30a627a65 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -603,7 +603,7 @@ Parser::error(unsigned errorNumber, ...) #ifdef DEBUG bool result = #endif - reportHelper(ParseError, false, pos().begin, errorNumber, args); + tokenStream.reportCompileErrorNumberVA(pos().begin, JSREPORT_ERROR, errorNumber, args); MOZ_ASSERT(!result, "reporting an error returned true?"); va_end(args); } @@ -617,7 +617,7 @@ Parser::errorAt(uint32_t offset, unsigned errorNumber, ...) #ifdef DEBUG bool result = #endif - reportHelper(ParseError, false, offset, errorNumber, args); + tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_ERROR, errorNumber, args); MOZ_ASSERT(!result, "reporting an error returned true?"); va_end(args); } @@ -628,7 +628,8 @@ Parser::warning(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool result = reportHelper(ParseWarning, false, pos().begin, errorNumber, args); + bool result = + tokenStream.reportCompileErrorNumberVA(pos().begin, JSREPORT_WARNING, errorNumber, args); va_end(args); return result; } @@ -639,7 +640,8 @@ Parser::warningAt(uint32_t offset, unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool result = reportHelper(ParseWarning, false, offset, errorNumber, args); + bool result = + tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_WARNING, errorNumber, args); va_end(args); return result; } @@ -650,7 +652,7 @@ Parser::extraWarning(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool result = reportHelper(ParseExtraWarning, false, pos().begin, errorNumber, args); + bool result = tokenStream.reportStrictWarningErrorNumberVA(pos().begin, errorNumber, args); va_end(args); return result; } @@ -661,7 +663,9 @@ Parser::strictModeError(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool res = reportHelper(ParseStrictError, pc->sc()->strict(), pos().begin, errorNumber, args); + bool res = + tokenStream.reportStrictModeErrorNumberVA(pos().begin, pc->sc()->strict(), + errorNumber, args); va_end(args); return res; } @@ -672,7 +676,8 @@ Parser::strictModeErrorAt(uint32_t offset, unsigned errorNumber, . { va_list args; va_start(args, errorNumber); - bool res = reportHelper(ParseStrictError, pc->sc()->strict(), offset, errorNumber, args); + bool res = + tokenStream.reportStrictModeErrorNumberVA(offset, pc->sc()->strict(), errorNumber, args); va_end(args); return res; } @@ -683,7 +688,23 @@ Parser::reportNoOffset(ParseReportKind kind, bool strict, unsigned { va_list args; va_start(args, errorNumber); - bool result = reportHelper(kind, strict, TokenStream::NoOffset, errorNumber, args); + bool result = false; + uint32_t offset = TokenStream::NoOffset; + switch (kind) { + case ParseError: + result = tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_ERROR, errorNumber, args); + break; + case ParseWarning: + result = + tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_WARNING, errorNumber, args); + break; + case ParseExtraWarning: + result = tokenStream.reportStrictWarningErrorNumberVA(offset, errorNumber, args); + break; + case ParseStrictError: + result = tokenStream.reportStrictModeErrorNumberVA(offset, strict, errorNumber, args); + break; + } va_end(args); return result; } -- cgit v1.2.3 From e88f15157f90cb2115d30dd7fc61704637536cd5 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 11:22:00 +0200 Subject: Remove Parser::reportHelper since it's no longer used. --- js/src/frontend/Parser.cpp | 24 ------------------------ js/src/frontend/Parser.h | 3 --- 2 files changed, 27 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 30a627a65..189f27bc4 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -570,30 +570,6 @@ FunctionBox::initWithEnclosingScope(Scope* enclosingScope) computeInWith(enclosingScope); } -template -bool -Parser::reportHelper(ParseReportKind kind, bool strict, uint32_t offset, - unsigned errorNumber, va_list args) -{ - bool result = false; - switch (kind) { - case ParseError: - result = tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_ERROR, errorNumber, args); - break; - case ParseWarning: - result = - tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_WARNING, errorNumber, args); - break; - case ParseExtraWarning: - result = tokenStream.reportStrictWarningErrorNumberVA(offset, errorNumber, args); - break; - case ParseStrictError: - result = tokenStream.reportStrictModeErrorNumberVA(offset, strict, errorNumber, args); - break; - } - return result; -} - template void Parser::error(unsigned errorNumber, ...) diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 196c71fa5..156a1c1b0 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -903,9 +903,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter void prepareNodeForMutation(Node node) { handler.prepareNodeForMutation(node); } void freeTree(Node node) { handler.freeTree(node); } - private: - bool reportHelper(ParseReportKind kind, bool strict, uint32_t offset, - unsigned errorNumber, va_list args); public: bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...); -- cgit v1.2.3 From a5d22aa6106fbd3c8cec12333b14d4c65cd98647 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 11:26:49 +0200 Subject: Rename TokenStream::reportStrictWarningErrorNumberVA to TokenStream::reportExtraWarningErrorNumberVA for clarity. Emit Extra Warnings instead of Strict Warnings from the BCE where it makes sense. --- js/src/frontend/BytecodeEmitter.cpp | 8 ++++---- js/src/frontend/BytecodeEmitter.h | 2 +- js/src/frontend/Parser.cpp | 4 ++-- js/src/frontend/TokenStream.cpp | 2 +- js/src/frontend/TokenStream.h | 3 +-- 5 files changed, 9 insertions(+), 10 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 71289e84a..b3dd6d777 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -3608,13 +3608,13 @@ BytecodeEmitter::reportError(ParseNode* pn, unsigned errorNumber, ...) } bool -BytecodeEmitter::reportStrictWarning(ParseNode* pn, unsigned errorNumber, ...) +BytecodeEmitter::reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...) { TokenPos pos = pn ? pn->pn_pos : tokenStream()->currentToken().pos; va_list args; va_start(args, errorNumber); - bool result = tokenStream()->reportStrictWarningErrorNumberVA(pos.begin, errorNumber, args); + bool result = tokenStream()->reportExtraWarningErrorNumberVA(pos.begin, errorNumber, args); va_end(args); return result; } @@ -8707,13 +8707,13 @@ BytecodeEmitter::emitStatement(ParseNode* pn) } if (directive) { - if (!reportStrictWarning(pn2, JSMSG_CONTRARY_NONDIRECTIVE, directive)) + if (!reportExtraWarning(pn2, JSMSG_CONTRARY_NONDIRECTIVE, directive)) return false; } } else { current->currentLine = parser->tokenStream.srcCoords.lineNum(pn2->pn_pos.begin); current->lastColumn = 0; - if (!reportStrictWarning(pn2, JSMSG_USELESS_EXPR)) + if (!reportExtraWarning(pn2, JSMSG_USELESS_EXPR)) return false; } } diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index 04307c8c1..32668a34c 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -388,7 +388,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter } bool reportError(ParseNode* pn, unsigned errorNumber, ...); - bool reportStrictWarning(ParseNode* pn, unsigned errorNumber, ...); + bool reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...); bool reportStrictModeError(ParseNode* pn, unsigned errorNumber, ...); // If pn contains a useful expression, return true with *answer set to true. diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 189f27bc4..daacbb50b 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -628,7 +628,7 @@ Parser::extraWarning(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool result = tokenStream.reportStrictWarningErrorNumberVA(pos().begin, errorNumber, args); + bool result = tokenStream.reportExtraWarningErrorNumberVA(pos().begin, errorNumber, args); va_end(args); return result; } @@ -675,7 +675,7 @@ Parser::reportNoOffset(ParseReportKind kind, bool strict, unsigned tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_WARNING, errorNumber, args); break; case ParseExtraWarning: - result = tokenStream.reportStrictWarningErrorNumberVA(offset, errorNumber, args); + result = tokenStream.reportExtraWarningErrorNumberVA(offset, errorNumber, args); break; case ParseStrictError: result = tokenStream.reportStrictModeErrorNumberVA(offset, strict, errorNumber, args); diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index b040d2998..8438ff7c5 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -786,7 +786,7 @@ TokenStream::reportWarning(unsigned errorNumber, ...) } bool -TokenStream::reportStrictWarningErrorNumberVA(uint32_t offset, unsigned errorNumber, va_list args) +TokenStream::reportExtraWarningErrorNumberVA(uint32_t offset, unsigned errorNumber, va_list args) { if (!options().extraWarningsOption) return true; diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index 03a580072..6ba9fba5a 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -375,8 +375,7 @@ class MOZ_STACK_CLASS TokenStream va_list args); bool reportStrictModeErrorNumberVA(uint32_t offset, bool strictMode, unsigned errorNumber, va_list args); - bool reportStrictWarningErrorNumberVA(uint32_t offset, unsigned errorNumber, - va_list args); + bool reportExtraWarningErrorNumberVA(uint32_t offset, unsigned errorNumber, va_list args); // asm.js reporter void reportAsmJSError(uint32_t offset, unsigned errorNumber, ...); -- cgit v1.2.3 From 51af3decb97f7eed3fa92dfddb89be22828a0275 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 25 Apr 2019 16:45:28 +0200 Subject: Remove useless assert. Resolves #1055. --- js/src/frontend/Parser.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index daacbb50b..3b7a0e612 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -2310,7 +2310,6 @@ Parser::standaloneFunction(HandleFunction fun, if (!tokenStream.getToken(&tt)) return null(); if (asyncKind == AsyncFunction) { - MOZ_ASSERT(tt == TOK_ASYNC); if (!tokenStream.getToken(&tt)) return null(); } -- cgit v1.2.3 From 5a65d8739d0ad6ef446b278a25fd955f0c734fb1 Mon Sep 17 00:00:00 2001 From: win7-7 Date: Mon, 29 Apr 2019 11:59:46 +0300 Subject: Improve dead compartment collection js/src --- js/src/jsgc.cpp | 198 +++++++++++++++++++++++++++++------------------- js/src/jsgc.h | 13 +++- js/src/jswatchpoint.cpp | 21 ++--- 3 files changed, 141 insertions(+), 91 deletions(-) (limited to 'js/src') diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 8cee9ec09..1e8e4fc8d 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -1524,20 +1524,11 @@ GCMarker::delayMarkingChildren(const void* thing) } inline void -ArenaLists::prepareForIncrementalGC(JSRuntime* rt) +ArenaLists::prepareForIncrementalGC() { - for (auto i : AllAllocKinds()) { - FreeSpan* span = freeLists[i]; - if (span != &placeholder) { - if (!span->isEmpty()) { - Arena* arena = span->getArena(); - arena->allocatedDuringIncremental = true; - rt->gc.marker.delayMarkingArena(arena); - } else { - freeLists[i] = &placeholder; - } - } - } + purge(); + for (auto i : AllAllocKinds()) + arenaLists[i].moveCursorToEnd(); } /* Compacting GC */ @@ -2251,7 +2242,7 @@ GCRuntime::updateTypeDescrObjects(MovingTracer* trc, Zone* zone) { zone->typeDescrObjects.sweep(); for (auto r = zone->typeDescrObjects.all(); !r.empty(); r.popFront()) - UpdateCellPointers(trc, r.front().get()); + UpdateCellPointers(trc, r.front()); } void @@ -3579,6 +3570,23 @@ RelazifyFunctions(Zone* zone, AllocKind kind) } } +static bool +ShouldCollectZone(Zone* zone, JS::gcreason::Reason reason) +{ + // Normally we collect all scheduled zones. + if (reason != JS::gcreason::COMPARTMENT_REVIVED) + return zone->isGCScheduled(); + + // If we are repeating a GC becuase we noticed dead compartments haven't + // been collected, then only collect zones contianing those compartments. + for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) { + if (comp->scheduledForDestruction) + return true; + } + + return false; +} + bool GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAccess& lock) { @@ -3602,7 +3610,7 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces #endif /* Set up which zones will be collected. */ - if (zone->isGCScheduled()) { + if (ShouldCollectZone(zone, reason)) { if (!zone->isAtomsZone()) { any = true; zone->setGCState(Zone::Mark); @@ -3621,7 +3629,7 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces for (CompartmentsIter c(rt, WithAtoms); !c.done(); c.next()) { c->marked = false; c->scheduledForDestruction = false; - c->maybeAlive = false; + c->maybeAlive = c->hasBeenEntered() || !c->zone()->isGCScheduled(); if (shouldPreserveJITCode(c, currentTime, reason, canAllocateMoreCode)) c->zone()->setPreservingCode(true); } @@ -3640,6 +3648,12 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces * keepAtoms() will only change on the main thread, which we are currently * on. If the value of keepAtoms() changes between GC slices, then we'll * cancel the incremental GC. See IsIncrementalGCSafe. + + + + + + */ if (isFull && !rt->keepAtoms()) { Zone* atomsZone = rt->atomsCompartment(lock)->zone(); @@ -3655,15 +3669,12 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces return false; /* - * At the end of each incremental slice, we call prepareForIncrementalGC, - * which marks objects in all arenas that we're currently allocating - * into. This can cause leaks if unreachable objects are in these - * arenas. This purge call ensures that we only mark arenas that have had - * allocations after the incremental GC started. + * Ensure that after the start of a collection we don't allocate into any + * existing arenas, as this can cause unreachable things to be marked. */ if (isIncremental) { for (GCZonesIter zone(rt); !zone.done(); zone.next()) - zone->arenas.purge(); + zone->arenas.prepareForIncrementalGC(); } MemProfiler::MarkTenuredStart(rt); @@ -3747,13 +3758,11 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces gcstats::AutoPhase ap2(stats, gcstats::PHASE_MARK_ROOTS); - if (isIncremental) { - gcstats::AutoPhase ap3(stats, gcstats::PHASE_BUFFER_GRAY_ROOTS); - bufferGrayRoots(); - } - - markCompartments(); - + if (isIncremental) { + bufferGrayRoots(); + markCompartments(); + } + return true; } @@ -3766,9 +3775,14 @@ GCRuntime::markCompartments() * This code ensures that if a compartment is "dead", then it will be * collected in this GC. A compartment is considered dead if its maybeAlive * flag is false. The maybeAlive flag is set if: - * (1) the compartment has incoming cross-compartment edges, or - * (2) an object in the compartment was marked during root marking, either - * as a black root or a gray root. + * (1) the compartment has been entered (set in beginMarkPhase() above) + * (2) the compartment is not being collected (set in beginMarkPhase() + * above) + * (3) an object in the compartment was marked during root marking, either + * as a black root or a gray root (set in RootMarking.cpp), or + * (4) the compartment has incoming cross-compartment edges from another + * compartment that has maybeAlive set (set by this method). + * * If the maybeAlive is false, then we set the scheduledForDestruction flag. * At the end of the GC, we look for compartments where * scheduledForDestruction is true. These are compartments that were somehow @@ -3786,26 +3800,37 @@ GCRuntime::markCompartments() * allocation and read barriers during JS_TransplantObject and the like. */ - /* Set the maybeAlive flag based on cross-compartment edges. */ - for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) { - for (JSCompartment::WrapperEnum e(c); !e.empty(); e.popFront()) { + /* Propagate the maybeAlive flag via cross-compartment edges. */ + + Vector workList; + + for (CompartmentsIter comp(rt, SkipAtoms); !comp.done(); comp.next()) { + if (comp->maybeAlive) { + if (!workList.append(comp)) + return; + } + } + while (!workList.empty()) { + JSCompartment* comp = workList.popCopy(); + for (JSCompartment::WrapperEnum e(comp); !e.empty(); e.popFront()) { if (e.front().key().is()) continue; JSCompartment* dest = e.front().mutableKey().compartment(); - if (dest) + if (dest && !dest->maybeAlive) { dest->maybeAlive = true; + if (!workList.append(dest)) + return; + } } } - /* - * For black roots, code in gc/Marking.cpp will already have set maybeAlive - * during MarkRuntime. - */ - - /* Propogate maybeAlive to scheduleForDestruction. */ - for (GCCompartmentsIter c(rt); !c.done(); c.next()) { - if (!c->maybeAlive && !rt->isAtomsCompartment(c)) - c->scheduledForDestruction = true; + + /* Set scheduleForDestruction based on maybeAlive. */ + + for (GCCompartmentsIter comp(rt); !comp.done(); comp.next()) { + MOZ_ASSERT(!comp->scheduledForDestruction); + if (!comp->maybeAlive && !rt->isAtomsCompartment(comp)) + comp->scheduledForDestruction = true; } } @@ -5306,7 +5331,7 @@ AutoGCSlice::~AutoGCSlice() for (ZonesIter zone(runtime, WithAtoms); !zone.done(); zone.next()) { if (zone->isGCMarking()) { zone->setNeedsIncrementalBarrier(true, Zone::UpdateJit); - zone->arenas.prepareForIncrementalGC(runtime); + zone->arenas.purge(); } else { zone->setNeedsIncrementalBarrier(false, Zone::UpdateJit); } @@ -5487,9 +5512,9 @@ gc::AbortReason gc::IsIncrementalGCUnsafe(JSRuntime* rt) { MOZ_ASSERT(!rt->mainThread.suppressGC); - - if (rt->keepAtoms()) - return gc::AbortReason::KeepAtomsSet; + + if (rt->keepAtoms()) + return gc::AbortReason::KeepAtomsSet; if (!rt->gc.isIncrementalGCAllowed()) return gc::AbortReason::IncrementalDisabled; @@ -5498,9 +5523,17 @@ gc::IsIncrementalGCUnsafe(JSRuntime* rt) } void -GCRuntime::budgetIncrementalGC(SliceBudget& budget, AutoLockForExclusiveAccess& lock) +GCRuntime::budgetIncrementalGC(JS::gcreason::Reason reason, SliceBudget& budget, + AutoLockForExclusiveAccess& lock) { AbortReason unsafeReason = IsIncrementalGCUnsafe(rt); + if (unsafeReason == AbortReason::None) { + if (reason == JS::gcreason::COMPARTMENT_REVIVED) + unsafeReason = gc::AbortReason::CompartmentRevived; + else if (mode != JSGC_MODE_INCREMENTAL) + unsafeReason = gc::AbortReason::ModeChange; + } + if (unsafeReason != AbortReason::None) { resetIncrementalGC(unsafeReason, lock); budget.makeUnlimited(); @@ -5508,12 +5541,7 @@ GCRuntime::budgetIncrementalGC(SliceBudget& budget, AutoLockForExclusiveAccess& return; } - if (mode != JSGC_MODE_INCREMENTAL) { - resetIncrementalGC(AbortReason::ModeChange, lock); - budget.makeUnlimited(); - stats.nonincremental(AbortReason::ModeChange); - return; - } + if (isTooMuchMalloc()) { budget.makeUnlimited(); @@ -5660,6 +5688,10 @@ GCRuntime::gcCycle(bool nonincrementalByAPI, SliceBudget& budget, JS::gcreason:: } State prevState = incrementalState; + + + + if (nonincrementalByAPI) { // Reset any in progress incremental GC if this was triggered via the @@ -5672,7 +5704,7 @@ GCRuntime::gcCycle(bool nonincrementalByAPI, SliceBudget& budget, JS::gcreason:: stats.nonincremental(gc::AbortReason::NonIncrementalRequested); budget.makeUnlimited(); } else { - budgetIncrementalGC(budget, session.lock); + budgetIncrementalGC(reason, budget, session.lock); } /* The GC was reset, so we need a do-over. */ @@ -5764,6 +5796,22 @@ GCRuntime::checkIfGCAllowedInCurrentState(JS::gcreason::Reason reason) return true; } +bool +GCRuntime::shouldRepeatForDeadZone(JS::gcreason::Reason reason) +{ + MOZ_ASSERT_IF(reason == JS::gcreason::COMPARTMENT_REVIVED, !isIncremental); + + if (!isIncremental || isIncrementalGCInProgress()) + return false; + + for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) { + if (c->scheduledForDestruction) + return true; + } + + return false; +} + void GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::Reason reason) { @@ -5782,27 +5830,23 @@ GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::R do { poked = false; bool wasReset = gcCycle(nonincrementalByAPI, budget, reason); - - /* Need to re-schedule all zones for GC. */ - if (poked && cleanUpEverything) + + bool repeatForDeadZone = false; + if (poked && cleanUpEverything) { + /* Need to re-schedule all zones for GC. */ JS::PrepareForFullGC(rt->contextFromMainThread()); - /* - * This code makes an extra effort to collect compartments that we - * thought were dead at the start of the GC. See the large comment in - * beginMarkPhase. - */ - bool repeatForDeadZone = false; - if (!nonincrementalByAPI && !isIncrementalGCInProgress()) { - for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) { - if (c->scheduledForDestruction) { - nonincrementalByAPI = true; - repeatForDeadZone = true; - reason = JS::gcreason::COMPARTMENT_REVIVED; - c->zone()->scheduleGC(); - } - } - } + + } else if (shouldRepeatForDeadZone(reason) && !wasReset) { + /* + * This code makes an extra effort to collect compartments that we + * thought were dead at the start of the GC. See the large comment + * in beginMarkPhase. + */ + repeatForDeadZone = true; + reason = JS::gcreason::COMPARTMENT_REVIVED; + } + /* * If we reset an existing GC, we need to start a new one. Also, we @@ -7070,4 +7114,4 @@ js::gc::detail::CellIsMarkedGrayIfKnown(const Cell* cell) } return detail::CellIsMarkedGray(tc); -} +} \ No newline at end of file diff --git a/js/src/jsgc.h b/js/src/jsgc.h index d3cf31fe7..aa42d474c 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -61,7 +61,8 @@ enum class State { D(ModeChange) \ D(MallocBytesTrigger) \ D(GCBytesTrigger) \ - D(ZoneChange) + D(ZoneChange) \ + D(CompartmentRevived) enum class AbortReason { #define MAKE_REASON(name) name, GC_ABORT_REASONS(MAKE_REASON) @@ -353,7 +354,6 @@ struct SortedArenaListSegment * be treated as an invariant, however, as the free lists may be cleared, * leaving arenas previously used for allocation partially full. Sorting order * is restored during sweeping. - * Arenas following the cursor should not be full. */ class ArenaList { @@ -453,6 +453,11 @@ class ArenaList { check(); return !*cursorp_; } + + void moveCursorToEnd() { + while (!isCursorAtEnd()) + cursorp_ = &(*cursorp_)->next; + } // This can return nullptr. Arena* arenaAfterCursor() const { @@ -739,7 +744,7 @@ class ArenaLists freeLists[i] = &placeholder; } - inline void prepareForIncrementalGC(JSRuntime* rt); + inline void prepareForIncrementalGC(); /* Check if this arena is in use. */ bool arenaIsInUse(Arena* arena, AllocKind kind) const { @@ -1504,4 +1509,4 @@ UninlinedIsInsideNursery(const gc::Cell* cell); } /* namespace js */ -#endif /* jsgc_h */ +#endif /* jsgc_h */ \ No newline at end of file diff --git a/js/src/jswatchpoint.cpp b/js/src/jswatchpoint.cpp index 3cf43e219..68afa4a59 100644 --- a/js/src/jswatchpoint.cpp +++ b/js/src/jswatchpoint.cpp @@ -185,17 +185,18 @@ WatchpointMap::markAll(JSTracer* trc) { for (Map::Enum e(map); !e.empty(); e.popFront()) { Map::Entry& entry = e.front(); - WatchKey key = entry.key(); - WatchKey prior = key; - MOZ_ASSERT(JSID_IS_STRING(prior.id) || JSID_IS_INT(prior.id) || JSID_IS_SYMBOL(prior.id)); - - TraceEdge(trc, const_cast(&key.object), - "held Watchpoint object"); - TraceEdge(trc, const_cast(&key.id), "WatchKey::id"); + JSObject* object = entry.key().object; + jsid id = entry.key().id; + JSObject* priorObject = object; + jsid priorId = id; + MOZ_ASSERT(JSID_IS_STRING(priorId) || JSID_IS_INT(priorId) || JSID_IS_SYMBOL(priorId)); + + TraceManuallyBarrieredEdge(trc, &object, "held Watchpoint object"); + TraceManuallyBarrieredEdge(trc, &id, "WatchKey::id"); TraceEdge(trc, &entry.value().closure, "Watchpoint::closure"); - if (prior.object != key.object || prior.id != key.id) - e.rekeyFront(key); + if (priorObject != object || priorId != id) + e.rekeyFront(WatchKey(object, id)); } } @@ -242,4 +243,4 @@ WatchpointMap::trace(WeakMapTracer* trc) JS::GCCellPtr(entry.key().object.get()), JS::GCCellPtr(entry.value().closure.get())); } -} +} \ No newline at end of file -- cgit v1.2.3 From 2cb4d2ee571b91ec2480d2fba17e600a3843ddba Mon Sep 17 00:00:00 2001 From: win7-7 Date: Mon, 29 Apr 2019 12:02:24 +0300 Subject: Improve dead compartment collection js/src/gc --- js/src/gc/GCRuntime.h | 6 ++++-- js/src/gc/RootMarking.cpp | 4 ++-- js/src/gc/Zone.cpp | 17 ++++++++++++++++- js/src/gc/Zone.h | 13 ++++++++++--- 4 files changed, 32 insertions(+), 8 deletions(-) (limited to 'js/src') diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h index 5c2576efd..16260a4e3 100644 --- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -900,7 +900,8 @@ class GCRuntime void requestMajorGC(JS::gcreason::Reason reason); SliceBudget defaultBudget(JS::gcreason::Reason reason, int64_t millis); - void budgetIncrementalGC(SliceBudget& budget, AutoLockForExclusiveAccess& lock); + void budgetIncrementalGC(JS::gcreason::Reason reason, SliceBudget& budget, + AutoLockForExclusiveAccess& lock); void resetIncrementalGC(AbortReason reason, AutoLockForExclusiveAccess& lock); // Assert if the system state is such that we should never @@ -915,6 +916,7 @@ class GCRuntime void collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::Reason reason) JS_HAZ_GC_CALL; MOZ_MUST_USE bool gcCycle(bool nonincrementalByAPI, SliceBudget& budget, JS::gcreason::Reason reason); + bool shouldRepeatForDeadZone(JS::gcreason::Reason reason); void incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason reason, AutoLockForExclusiveAccess& lock); @@ -1348,4 +1350,4 @@ class MOZ_RAII AutoMaybeStartBackgroundAllocation } /* namespace js */ -#endif +#endif \ No newline at end of file diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index 93264084b..ed7b8fb6f 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -478,6 +478,7 @@ js::gc::GCRuntime::bufferGrayRoots() for (GCZonesIter zone(rt); !zone.done(); zone.next()) MOZ_ASSERT(zone->gcGrayRoots.empty()); + gcstats::AutoPhase ap(stats, gcstats::PHASE_BUFFER_GRAY_ROOTS); BufferGrayRootsTracer grayBufferer(rt); if (JSTraceDataOp op = grayRootTracer.op) @@ -539,5 +540,4 @@ GCRuntime::resetBufferedGrayRoots() const "Do not clear the gray buffers unless we are Failed or becoming Unused"); for (GCZonesIter zone(rt); !zone.done(); zone.next()) zone->gcGrayRoots.clearAndFree(); -} - +} \ No newline at end of file diff --git a/js/src/gc/Zone.cpp b/js/src/gc/Zone.cpp index ed099341c..ecfb9a38c 100644 --- a/js/src/gc/Zone.cpp +++ b/js/src/gc/Zone.cpp @@ -370,6 +370,21 @@ Zone::fixupAfterMovingGC() fixupInitialShapeTable(); } +bool +Zone::addTypeDescrObject(JSContext* cx, HandleObject obj) +{ + // Type descriptor objects are always tenured so we don't need post barriers + // on the set. + MOZ_ASSERT(!IsInsideNursery(obj)); + + if (!typeDescrObjects.put(obj)) { + ReportOutOfMemory(cx); + return false; + } + + return true; +} + ZoneList::ZoneList() : head(nullptr), tail(nullptr) {} @@ -468,4 +483,4 @@ JS_PUBLIC_API(void) JS::shadow::RegisterWeakCache(JS::Zone* zone, WeakCache* cachep) { zone->registerWeakCache(cachep); -} +} \ No newline at end of file diff --git a/js/src/gc/Zone.h b/js/src/gc/Zone.h index 50d06319d..24f4648f7 100644 --- a/js/src/gc/Zone.h +++ b/js/src/gc/Zone.h @@ -349,10 +349,17 @@ struct Zone : public JS::shadow::Zone, // Keep track of all TypeDescr and related objects in this compartment. // This is used by the GC to trace them all first when compacting, since the // TypedObject trace hook may access these objects. - using TypeDescrObjectSet = js::GCHashSet, - js::MovableCellHasher>, + + // + // There are no barriers here - the set contains only tenured objects so no + // post-barrier is required, and these are weak references so no pre-barrier + // is required. + using TypeDescrObjectSet = js::GCHashSet, js::SystemAllocPolicy>; JS::WeakCache typeDescrObjects; + + bool addTypeDescrObject(JSContext* cx, HandleObject obj); // Malloc counter to measure memory pressure for GC scheduling. It runs from @@ -734,4 +741,4 @@ class ZoneAllocPolicy } // namespace js -#endif // gc_Zone_h +#endif // gc_Zone_h \ No newline at end of file -- cgit v1.2.3 From bb1fad0fa728c7e95c6e06dfae63254b2c2e2966 Mon Sep 17 00:00:00 2001 From: win7-7 Date: Mon, 29 Apr 2019 12:05:03 +0300 Subject: Improve dead compartment collection js/src/builtin --- js/src/builtin/TypedObject.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'js/src') diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index ae74f01bf..95704ee46 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -652,7 +652,7 @@ ArrayMetaTypeDescr::create(JSContext* cx, if (!CreateTraceList(cx, obj)) return nullptr; - if (!cx->zone()->typeDescrObjects.put(obj)) { + if (!cx->zone()->addTypeDescrObject(cx, obj)) { ReportOutOfMemory(cx); return nullptr; } @@ -993,8 +993,8 @@ StructMetaTypeDescr::create(JSContext* cx, if (!CreateTraceList(cx, descr)) return nullptr; - if (!cx->zone()->typeDescrObjects.put(descr) || - !cx->zone()->typeDescrObjects.put(fieldTypeVec)) + if (!cx->zone()->addTypeDescrObject(cx, descr) || + !cx->zone()->addTypeDescrObject(cx, fieldTypeVec)) { ReportOutOfMemory(cx); return nullptr; @@ -1165,10 +1165,8 @@ DefineSimpleTypeDescr(JSContext* cx, if (!CreateTraceList(cx, descr)) return false; - if (!cx->zone()->typeDescrObjects.put(descr)) { - ReportOutOfMemory(cx); + if (!cx->zone()->addTypeDescrObject(cx, descr)) return false; - } return true; } @@ -3005,4 +3003,4 @@ TypeDescr::finalize(FreeOp* fop, JSObject* obj) TypeDescr& descr = obj->as(); if (descr.hasTraceList()) js_free(const_cast(descr.traceList())); -} +} \ No newline at end of file -- cgit v1.2.3 From 44e59151e3e7678626202482c72e2696bcc17769 Mon Sep 17 00:00:00 2001 From: win7-7 Date: Mon, 29 Apr 2019 12:32:23 +0300 Subject: Space to comment. --- js/src/jsgc.h | 1 + 1 file changed, 1 insertion(+) (limited to 'js/src') diff --git a/js/src/jsgc.h b/js/src/jsgc.h index aa42d474c..8626e3e38 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -354,6 +354,7 @@ struct SortedArenaListSegment * be treated as an invariant, however, as the free lists may be cleared, * leaving arenas previously used for allocation partially full. Sorting order * is restored during sweeping. + * Arenas following the cursor should not be full. */ class ArenaList { -- cgit v1.2.3 From d57c13c6d8700eebfe7042ae52e31a6ac1bb28a1 Mon Sep 17 00:00:00 2001 From: win7-7 Date: Mon, 29 Apr 2019 15:31:58 +0300 Subject: Add newline at end of files js/src --- js/src/jsgc.cpp | 2 +- js/src/jsgc.h | 2 +- js/src/jswatchpoint.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'js/src') diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 1e8e4fc8d..ad3d7093d 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -7114,4 +7114,4 @@ js::gc::detail::CellIsMarkedGrayIfKnown(const Cell* cell) } return detail::CellIsMarkedGray(tc); -} \ No newline at end of file +} diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 8626e3e38..5d3c37286 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -1510,4 +1510,4 @@ UninlinedIsInsideNursery(const gc::Cell* cell); } /* namespace js */ -#endif /* jsgc_h */ \ No newline at end of file +#endif /* jsgc_h */ diff --git a/js/src/jswatchpoint.cpp b/js/src/jswatchpoint.cpp index 68afa4a59..f147a07dc 100644 --- a/js/src/jswatchpoint.cpp +++ b/js/src/jswatchpoint.cpp @@ -243,4 +243,4 @@ WatchpointMap::trace(WeakMapTracer* trc) JS::GCCellPtr(entry.key().object.get()), JS::GCCellPtr(entry.value().closure.get())); } -} \ No newline at end of file +} -- cgit v1.2.3 From 22116f9a70e23e69d0830265901736f6d6dcf6f6 Mon Sep 17 00:00:00 2001 From: win7-7 Date: Mon, 29 Apr 2019 15:33:52 +0300 Subject: add newline at end of files js/src/gc --- js/src/gc/GCRuntime.h | 2 +- js/src/gc/RootMarking.cpp | 2 +- js/src/gc/Zone.cpp | 2 +- js/src/gc/Zone.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'js/src') diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h index 16260a4e3..72910c615 100644 --- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -1350,4 +1350,4 @@ class MOZ_RAII AutoMaybeStartBackgroundAllocation } /* namespace js */ -#endif \ No newline at end of file +#endif diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index ed7b8fb6f..b09ee6e00 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -540,4 +540,4 @@ GCRuntime::resetBufferedGrayRoots() const "Do not clear the gray buffers unless we are Failed or becoming Unused"); for (GCZonesIter zone(rt); !zone.done(); zone.next()) zone->gcGrayRoots.clearAndFree(); -} \ No newline at end of file +} diff --git a/js/src/gc/Zone.cpp b/js/src/gc/Zone.cpp index ecfb9a38c..7681f15c5 100644 --- a/js/src/gc/Zone.cpp +++ b/js/src/gc/Zone.cpp @@ -483,4 +483,4 @@ JS_PUBLIC_API(void) JS::shadow::RegisterWeakCache(JS::Zone* zone, WeakCache* cachep) { zone->registerWeakCache(cachep); -} \ No newline at end of file +} diff --git a/js/src/gc/Zone.h b/js/src/gc/Zone.h index 24f4648f7..d337fe85c 100644 --- a/js/src/gc/Zone.h +++ b/js/src/gc/Zone.h @@ -741,4 +741,4 @@ class ZoneAllocPolicy } // namespace js -#endif // gc_Zone_h \ No newline at end of file +#endif // gc_Zone_h -- cgit v1.2.3 From 6f15c693f77159c83189de7c6610b8a6e1317736 Mon Sep 17 00:00:00 2001 From: win7-7 Date: Mon, 29 Apr 2019 15:36:04 +0300 Subject: Add newline at end of file js/src/builtin --- js/src/builtin/TypedObject.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'js/src') diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index 95704ee46..0dfc1123a 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -3003,4 +3003,4 @@ TypeDescr::finalize(FreeOp* fop, JSObject* obj) TypeDescr& descr = obj->as(); if (descr.hasTraceList()) js_free(const_cast(descr.traceList())); -} \ No newline at end of file +} -- cgit v1.2.3 From 0e70828f2c84cc0ac9afd85d14eb30b5fc8358dd Mon Sep 17 00:00:00 2001 From: win7-7 Date: Tue, 30 Apr 2019 02:16:38 +0300 Subject: tab to spaces js/src --- js/src/jsgc.cpp | 78 ++++++++++++++++++++++++------------------------- js/src/jsgc.h | 10 +++---- js/src/jswatchpoint.cpp | 4 +-- 3 files changed, 46 insertions(+), 46 deletions(-) (limited to 'js/src') diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index ad3d7093d..283eb22b0 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -1527,7 +1527,7 @@ inline void ArenaLists::prepareForIncrementalGC() { purge(); - for (auto i : AllAllocKinds()) + for (auto i : AllAllocKinds()) arenaLists[i].moveCursorToEnd(); } @@ -3573,18 +3573,18 @@ RelazifyFunctions(Zone* zone, AllocKind kind) static bool ShouldCollectZone(Zone* zone, JS::gcreason::Reason reason) { - // Normally we collect all scheduled zones. - if (reason != JS::gcreason::COMPARTMENT_REVIVED) - return zone->isGCScheduled(); + // Normally we collect all scheduled zones. + if (reason != JS::gcreason::COMPARTMENT_REVIVED) + return zone->isGCScheduled(); - // If we are repeating a GC becuase we noticed dead compartments haven't - // been collected, then only collect zones contianing those compartments. - for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) { - if (comp->scheduledForDestruction) - return true; - } - - return false; + // If we are repeating a GC becuase we noticed dead compartments haven't + // been collected, then only collect zones contianing those compartments. + for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) { + if (comp->scheduledForDestruction) + return true; + } + + return false; } bool @@ -5527,12 +5527,12 @@ GCRuntime::budgetIncrementalGC(JS::gcreason::Reason reason, SliceBudget& budget, AutoLockForExclusiveAccess& lock) { AbortReason unsafeReason = IsIncrementalGCUnsafe(rt); - if (unsafeReason == AbortReason::None) { - if (reason == JS::gcreason::COMPARTMENT_REVIVED) - unsafeReason = gc::AbortReason::CompartmentRevived; - else if (mode != JSGC_MODE_INCREMENTAL) - unsafeReason = gc::AbortReason::ModeChange; - } + if (unsafeReason == AbortReason::None) { + if (reason == JS::gcreason::COMPARTMENT_REVIVED) + unsafeReason = gc::AbortReason::CompartmentRevived; + else if (mode != JSGC_MODE_INCREMENTAL) + unsafeReason = gc::AbortReason::ModeChange; + } if (unsafeReason != AbortReason::None) { resetIncrementalGC(unsafeReason, lock); @@ -5799,17 +5799,17 @@ GCRuntime::checkIfGCAllowedInCurrentState(JS::gcreason::Reason reason) bool GCRuntime::shouldRepeatForDeadZone(JS::gcreason::Reason reason) { - MOZ_ASSERT_IF(reason == JS::gcreason::COMPARTMENT_REVIVED, !isIncremental); - - if (!isIncremental || isIncrementalGCInProgress()) - return false; - - for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) { - if (c->scheduledForDestruction) - return true; - } - - return false; + MOZ_ASSERT_IF(reason == JS::gcreason::COMPARTMENT_REVIVED, !isIncremental); + + if (!isIncremental || isIncrementalGCInProgress()) + return false; + + for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) { + if (c->scheduledForDestruction) + return true; + } + + return false; } void @@ -5831,21 +5831,21 @@ GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::R poked = false; bool wasReset = gcCycle(nonincrementalByAPI, budget, reason); - bool repeatForDeadZone = false; + bool repeatForDeadZone = false; if (poked && cleanUpEverything) { - /* Need to re-schedule all zones for GC. */ + /* Need to re-schedule all zones for GC. */ JS::PrepareForFullGC(rt->contextFromMainThread()); } else if (shouldRepeatForDeadZone(reason) && !wasReset) { - /* - * This code makes an extra effort to collect compartments that we - * thought were dead at the start of the GC. See the large comment - * in beginMarkPhase. - */ - repeatForDeadZone = true; - reason = JS::gcreason::COMPARTMENT_REVIVED; - } + /* + * This code makes an extra effort to collect compartments that we + * thought were dead at the start of the GC. See the large comment + * in beginMarkPhase. + */ + repeatForDeadZone = true; + reason = JS::gcreason::COMPARTMENT_REVIVED; + } /* diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 5d3c37286..85b9f5f4a 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -62,7 +62,7 @@ enum class State { D(MallocBytesTrigger) \ D(GCBytesTrigger) \ D(ZoneChange) \ - D(CompartmentRevived) + D(CompartmentRevived) enum class AbortReason { #define MAKE_REASON(name) name, GC_ABORT_REASONS(MAKE_REASON) @@ -455,10 +455,10 @@ class ArenaList { return !*cursorp_; } - void moveCursorToEnd() { - while (!isCursorAtEnd()) - cursorp_ = &(*cursorp_)->next; - } + void moveCursorToEnd() { + while (!isCursorAtEnd()) + cursorp_ = &(*cursorp_)->next; + } // This can return nullptr. Arena* arenaAfterCursor() const { diff --git a/js/src/jswatchpoint.cpp b/js/src/jswatchpoint.cpp index f147a07dc..e37323555 100644 --- a/js/src/jswatchpoint.cpp +++ b/js/src/jswatchpoint.cpp @@ -187,8 +187,8 @@ WatchpointMap::markAll(JSTracer* trc) Map::Entry& entry = e.front(); JSObject* object = entry.key().object; jsid id = entry.key().id; - JSObject* priorObject = object; - jsid priorId = id; + JSObject* priorObject = object; + jsid priorId = id; MOZ_ASSERT(JSID_IS_STRING(priorId) || JSID_IS_INT(priorId) || JSID_IS_SYMBOL(priorId)); TraceManuallyBarrieredEdge(trc, &object, "held Watchpoint object"); -- cgit v1.2.3 From 9fb6b925fb249d3dd9f467142410a2e605736784 Mon Sep 17 00:00:00 2001 From: win7-7 Date: Tue, 30 Apr 2019 02:20:36 +0300 Subject: tab to spaces js/src/gc --- js/src/gc/GCRuntime.h | 4 ++-- js/src/gc/RootMarking.cpp | 2 +- js/src/gc/Zone.cpp | 24 ++++++++++++------------ js/src/gc/Zone.h | 12 ++++++------ 4 files changed, 21 insertions(+), 21 deletions(-) (limited to 'js/src') diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h index 72910c615..f102e9ef0 100644 --- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -901,7 +901,7 @@ class GCRuntime void requestMajorGC(JS::gcreason::Reason reason); SliceBudget defaultBudget(JS::gcreason::Reason reason, int64_t millis); void budgetIncrementalGC(JS::gcreason::Reason reason, SliceBudget& budget, - AutoLockForExclusiveAccess& lock); + AutoLockForExclusiveAccess& lock); void resetIncrementalGC(AbortReason reason, AutoLockForExclusiveAccess& lock); // Assert if the system state is such that we should never @@ -916,7 +916,7 @@ class GCRuntime void collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::Reason reason) JS_HAZ_GC_CALL; MOZ_MUST_USE bool gcCycle(bool nonincrementalByAPI, SliceBudget& budget, JS::gcreason::Reason reason); - bool shouldRepeatForDeadZone(JS::gcreason::Reason reason); + bool shouldRepeatForDeadZone(JS::gcreason::Reason reason); void incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason reason, AutoLockForExclusiveAccess& lock); diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index b09ee6e00..f5969bc1f 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -478,7 +478,7 @@ js::gc::GCRuntime::bufferGrayRoots() for (GCZonesIter zone(rt); !zone.done(); zone.next()) MOZ_ASSERT(zone->gcGrayRoots.empty()); - gcstats::AutoPhase ap(stats, gcstats::PHASE_BUFFER_GRAY_ROOTS); + gcstats::AutoPhase ap(stats, gcstats::PHASE_BUFFER_GRAY_ROOTS); BufferGrayRootsTracer grayBufferer(rt); if (JSTraceDataOp op = grayRootTracer.op) diff --git a/js/src/gc/Zone.cpp b/js/src/gc/Zone.cpp index 7681f15c5..f0cdde012 100644 --- a/js/src/gc/Zone.cpp +++ b/js/src/gc/Zone.cpp @@ -373,18 +373,18 @@ Zone::fixupAfterMovingGC() bool Zone::addTypeDescrObject(JSContext* cx, HandleObject obj) { - // Type descriptor objects are always tenured so we don't need post barriers - // on the set. - MOZ_ASSERT(!IsInsideNursery(obj)); - - if (!typeDescrObjects.put(obj)) { - ReportOutOfMemory(cx); - return false; - } - - return true; -} - + // Type descriptor objects are always tenured so we don't need post barriers + // on the set. + MOZ_ASSERT(!IsInsideNursery(obj)); + + if (!typeDescrObjects.put(obj)) { + ReportOutOfMemory(cx); + return false; + } + + return true; +} + ZoneList::ZoneList() : head(nullptr), tail(nullptr) {} diff --git a/js/src/gc/Zone.h b/js/src/gc/Zone.h index d337fe85c..c8520ed55 100644 --- a/js/src/gc/Zone.h +++ b/js/src/gc/Zone.h @@ -350,16 +350,16 @@ struct Zone : public JS::shadow::Zone, // This is used by the GC to trace them all first when compacting, since the // TypedObject trace hook may access these objects. - // - // There are no barriers here - the set contains only tenured objects so no - // post-barrier is required, and these are weak references so no pre-barrier - // is required. - using TypeDescrObjectSet = js::GCHashSet, js::SystemAllocPolicy>; JS::WeakCache typeDescrObjects; - bool addTypeDescrObject(JSContext* cx, HandleObject obj); + bool addTypeDescrObject(JSContext* cx, HandleObject obj); // Malloc counter to measure memory pressure for GC scheduling. It runs from -- cgit v1.2.3 From 4d03ec5c22ff2ac288808ad008a94634a53745da Mon Sep 17 00:00:00 2001 From: win7-7 Date: Tue, 30 Apr 2019 02:43:47 +0300 Subject: remaining tabs to space js/src/jsgc.cpp --- js/src/jsgc.cpp | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) (limited to 'js/src') diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 283eb22b0..589e478f4 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -3758,11 +3758,11 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces gcstats::AutoPhase ap2(stats, gcstats::PHASE_MARK_ROOTS); - if (isIncremental) { + if (isIncremental) { bufferGrayRoots(); - markCompartments(); - } - + markCompartments(); + } + return true; } @@ -3778,11 +3778,11 @@ GCRuntime::markCompartments() * (1) the compartment has been entered (set in beginMarkPhase() above) * (2) the compartment is not being collected (set in beginMarkPhase() * above) - * (3) an object in the compartment was marked during root marking, either - * as a black root or a gray root (set in RootMarking.cpp), or + * (3) an object in the compartment was marked during root marking, either + * as a black root or a gray root (set in RootMarking.cpp), or * (4) the compartment has incoming cross-compartment edges from another - * compartment that has maybeAlive set (set by this method). - * + * compartment that has maybeAlive set (set by this method). + * * If the maybeAlive is false, then we set the scheduledForDestruction flag. * At the end of the GC, we look for compartments where * scheduledForDestruction is true. These are compartments that were somehow @@ -3802,35 +3802,35 @@ GCRuntime::markCompartments() /* Propagate the maybeAlive flag via cross-compartment edges. */ - Vector workList; - - for (CompartmentsIter comp(rt, SkipAtoms); !comp.done(); comp.next()) { - if (comp->maybeAlive) { - if (!workList.append(comp)) - return; - } - } - while (!workList.empty()) { - JSCompartment* comp = workList.popCopy(); - for (JSCompartment::WrapperEnum e(comp); !e.empty(); e.popFront()) { + Vector workList; + + for (CompartmentsIter comp(rt, SkipAtoms); !comp.done(); comp.next()) { + if (comp->maybeAlive) { + if (!workList.append(comp)) + return; + } + } + while (!workList.empty()) { + JSCompartment* comp = workList.popCopy(); + for (JSCompartment::WrapperEnum e(comp); !e.empty(); e.popFront()) { if (e.front().key().is()) continue; JSCompartment* dest = e.front().mutableKey().compartment(); if (dest && !dest->maybeAlive) { dest->maybeAlive = true; - if (!workList.append(dest)) - return; - } + if (!workList.append(dest)) + return; + } } } /* Set scheduleForDestruction based on maybeAlive. */ - for (GCCompartmentsIter comp(rt); !comp.done(); comp.next()) { - MOZ_ASSERT(!comp->scheduledForDestruction); - if (!comp->maybeAlive && !rt->isAtomsCompartment(comp)) - comp->scheduledForDestruction = true; + for (GCCompartmentsIter comp(rt); !comp.done(); comp.next()) { + MOZ_ASSERT(!comp->scheduledForDestruction); + if (!comp->maybeAlive && !rt->isAtomsCompartment(comp)) + comp->scheduledForDestruction = true; } } -- cgit v1.2.3 From a2dbd23b0428ccc09a8daf52ebbc50d7141d0cd5 Mon Sep 17 00:00:00 2001 From: win7-7 Date: Tue, 30 Apr 2019 12:22:51 +0300 Subject: Remove some empty lines --- js/src/jsgc.cpp | 7 ------- 1 file changed, 7 deletions(-) (limited to 'js/src') diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 589e478f4..70d392973 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -3649,10 +3649,6 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces * on. If the value of keepAtoms() changes between GC slices, then we'll * cancel the incremental GC. See IsIncrementalGCSafe. - - - - */ if (isFull && !rt->keepAtoms()) { @@ -5689,9 +5685,6 @@ GCRuntime::gcCycle(bool nonincrementalByAPI, SliceBudget& budget, JS::gcreason:: State prevState = incrementalState; - - - if (nonincrementalByAPI) { // Reset any in progress incremental GC if this was triggered via the -- cgit v1.2.3 From 0c8c58314cb4e22d975a5802094073cd03c99d17 Mon Sep 17 00:00:00 2001 From: win7-7 Date: Tue, 30 Apr 2019 12:37:16 +0300 Subject: Remove rest of empty lines. --- js/src/jsgc.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'js/src') diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 70d392973..a1296f0d8 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -3648,9 +3648,8 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces * keepAtoms() will only change on the main thread, which we are currently * on. If the value of keepAtoms() changes between GC slices, then we'll * cancel the incremental GC. See IsIncrementalGCSafe. - - */ + if (isFull && !rt->keepAtoms()) { Zone* atomsZone = rt->atomsCompartment(lock)->zone(); if (atomsZone->isGCScheduled()) { @@ -5684,7 +5683,6 @@ GCRuntime::gcCycle(bool nonincrementalByAPI, SliceBudget& budget, JS::gcreason:: } State prevState = incrementalState; - if (nonincrementalByAPI) { // Reset any in progress incremental GC if this was triggered via the -- cgit v1.2.3 From 31ea8c7e934bd4dd78ef44dc9dfd47bd27bdf0a3 Mon Sep 17 00:00:00 2001 From: win7-7 Date: Tue, 30 Apr 2019 13:22:57 +0300 Subject: Whitespaces, typo, tabs to space Remove whitespaces, correct comment typo, one more tab to space --- js/src/jsgc.cpp | 12 ++++++------ js/src/jsgc.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'js/src') diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index a1296f0d8..f528b2d70 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -3578,7 +3578,7 @@ ShouldCollectZone(Zone* zone, JS::gcreason::Reason reason) return zone->isGCScheduled(); // If we are repeating a GC becuase we noticed dead compartments haven't - // been collected, then only collect zones contianing those compartments. + // been collected, then only collect zones containing those compartments. for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) { if (comp->scheduledForDestruction) return true; @@ -3753,8 +3753,8 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces gcstats::AutoPhase ap2(stats, gcstats::PHASE_MARK_ROOTS); - if (isIncremental) { - bufferGrayRoots(); + if (isIncremental) { + bufferGrayRoots(); markCompartments(); } @@ -5508,8 +5508,8 @@ gc::IsIncrementalGCUnsafe(JSRuntime* rt) { MOZ_ASSERT(!rt->mainThread.suppressGC); - if (rt->keepAtoms()) - return gc::AbortReason::KeepAtomsSet; + if (rt->keepAtoms()) + return gc::AbortReason::KeepAtomsSet; if (!rt->gc.isIncrementalGCAllowed()) return gc::AbortReason::IncrementalDisabled; @@ -5519,7 +5519,7 @@ gc::IsIncrementalGCUnsafe(JSRuntime* rt) void GCRuntime::budgetIncrementalGC(JS::gcreason::Reason reason, SliceBudget& budget, - AutoLockForExclusiveAccess& lock) + AutoLockForExclusiveAccess& lock) { AbortReason unsafeReason = IsIncrementalGCUnsafe(rt); if (unsafeReason == AbortReason::None) { diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 85b9f5f4a..d00d2aef6 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -354,7 +354,7 @@ struct SortedArenaListSegment * be treated as an invariant, however, as the free lists may be cleared, * leaving arenas previously used for allocation partially full. Sorting order * is restored during sweeping. - + * Arenas following the cursor should not be full. */ class ArenaList { -- cgit v1.2.3 From 2ec2389d7f887d263b76e43af1d40e8b529db40e Mon Sep 17 00:00:00 2001 From: win7-7 Date: Tue, 30 Apr 2019 15:07:04 +0300 Subject: Braces and one more typo fix for comment --- js/src/jsgc.cpp | 5 +++-- js/src/jsgc.h | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'js/src') diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index f528b2d70..194468c5d 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -1527,8 +1527,9 @@ inline void ArenaLists::prepareForIncrementalGC() { purge(); - for (auto i : AllAllocKinds()) + for (auto i : AllAllocKinds()) { arenaLists[i].moveCursorToEnd(); + } } /* Compacting GC */ @@ -3577,7 +3578,7 @@ ShouldCollectZone(Zone* zone, JS::gcreason::Reason reason) if (reason != JS::gcreason::COMPARTMENT_REVIVED) return zone->isGCScheduled(); - // If we are repeating a GC becuase we noticed dead compartments haven't + // If we are repeating a GC because we noticed dead compartments haven't // been collected, then only collect zones containing those compartments. for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) { if (comp->scheduledForDestruction) diff --git a/js/src/jsgc.h b/js/src/jsgc.h index d00d2aef6..952fd6bae 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -456,8 +456,9 @@ class ArenaList { } void moveCursorToEnd() { - while (!isCursorAtEnd()) + while (!isCursorAtEnd()) { cursorp_ = &(*cursorp_)->next; + } } // This can return nullptr. -- cgit v1.2.3 From 3ded48cbe3529811f8638fde9f392bc915c35163 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Mon, 13 May 2019 15:45:32 +0000 Subject: Unhook Unboxed Objects option --- js/src/jsapi.cpp | 3 --- js/src/jsapi.h | 25 ++++++++++++------------- js/src/shell/js.cpp | 3 --- 3 files changed, 12 insertions(+), 19 deletions(-) (limited to 'js/src') diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index f78f94dc1..9ee29ffe4 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -6434,9 +6434,6 @@ JS_SetGlobalJitCompilerOption(JSContext* cx, JSJitCompilerOption opt, uint32_t v } jit::JitOptions.jumpThreshold = value; break; - case JSJITCOMPILER_UNBOXED_OBJECTS: - jit::JitOptions.disableUnboxedObjects = !value; - break; case JSJITCOMPILER_ASMJS_ATOMICS_ENABLE: jit::JitOptions.asmJSAtomicsEnable = !!value; break; diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 1f726f2e5..005d2278e 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -5783,20 +5783,19 @@ JS_SetParallelParsingEnabled(JSContext* cx, bool enabled); extern JS_PUBLIC_API(void) JS_SetOffthreadIonCompilationEnabled(JSContext* cx, bool enabled); -#define JIT_COMPILER_OPTIONS(Register) \ - Register(BASELINE_WARMUP_TRIGGER, "baseline.warmup.trigger") \ - Register(ION_WARMUP_TRIGGER, "ion.warmup.trigger") \ - Register(ION_GVN_ENABLE, "ion.gvn.enable") \ - Register(ION_FORCE_IC, "ion.forceinlineCaches") \ - Register(ION_ENABLE, "ion.enable") \ +#define JIT_COMPILER_OPTIONS(Register) \ + Register(BASELINE_WARMUP_TRIGGER, "baseline.warmup.trigger") \ + Register(ION_WARMUP_TRIGGER, "ion.warmup.trigger") \ + Register(ION_GVN_ENABLE, "ion.gvn.enable") \ + Register(ION_FORCE_IC, "ion.forceinlineCaches") \ + Register(ION_ENABLE, "ion.enable") \ Register(ION_INTERRUPT_WITHOUT_SIGNAL, "ion.interrupt-without-signals") \ - Register(ION_CHECK_RANGE_ANALYSIS, "ion.check-range-analysis") \ - Register(BASELINE_ENABLE, "baseline.enable") \ - Register(OFFTHREAD_COMPILATION_ENABLE, "offthread-compilation.enable") \ - Register(JUMP_THRESHOLD, "jump-threshold") \ - Register(UNBOXED_OBJECTS, "unboxed_objects") \ - Register(ASMJS_ATOMICS_ENABLE, "asmjs.atomics.enable") \ - Register(WASM_TEST_MODE, "wasm.test-mode") \ + Register(ION_CHECK_RANGE_ANALYSIS, "ion.check-range-analysis") \ + Register(BASELINE_ENABLE, "baseline.enable") \ + Register(OFFTHREAD_COMPILATION_ENABLE, "offthread-compilation.enable") \ + Register(JUMP_THRESHOLD, "jump-threshold") \ + Register(ASMJS_ATOMICS_ENABLE, "asmjs.atomics.enable") \ + Register(WASM_TEST_MODE, "wasm.test-mode") \ Register(WASM_FOLD_OFFSETS, "wasm.fold-offsets") typedef enum JSJitCompilerOption { diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 8d144417a..193d8d22b 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -7276,9 +7276,6 @@ SetContextOptions(JSContext* cx, const OptionParser& op) if (op.getBoolOption("wasm-check-bce")) jit::JitOptions.wasmAlwaysCheckBounds = true; - if (op.getBoolOption("no-unboxed-objects")) - jit::JitOptions.disableUnboxedObjects = true; - if (const char* str = op.getStringOption("cache-ir-stubs")) { if (strcmp(str, "on") == 0) jit::JitOptions.disableCacheIR = false; -- cgit v1.2.3 From 9a3141515f051b6622f564ba75c171822854a7ac Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Tue, 14 May 2019 11:44:11 +0000 Subject: remove unboxed code chunk (wip1) --- js/src/jit/BaselineInspector.cpp | 31 +-- js/src/jit/BaselineInspector.h | 9 +- js/src/jit/IonBuilder.cpp | 80 +------- js/src/jit/IonBuilder.h | 4 - js/src/jit/MCallOptimize.cpp | 8 +- js/src/vm/UnboxedObject.cpp | 400 --------------------------------------- 6 files changed, 25 insertions(+), 507 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/BaselineInspector.cpp b/js/src/jit/BaselineInspector.cpp index c9e09bed7..9c7b88fb2 100644 --- a/js/src/jit/BaselineInspector.cpp +++ b/js/src/jit/BaselineInspector.cpp @@ -96,13 +96,8 @@ VectorAppendNoDuplicate(S& list, T value) static bool AddReceiver(const ReceiverGuard& receiver, - BaselineInspector::ReceiverVector& receivers, - BaselineInspector::ObjectGroupVector& convertUnboxedGroups) + BaselineInspector::ReceiverVector& receivers) { - if (receiver.group && receiver.group->maybeUnboxedLayout()) { - if (receiver.group->unboxedLayout().nativeGroup()) - return VectorAppendNoDuplicate(convertUnboxedGroups, receiver.group); - } return VectorAppendNoDuplicate(receivers, receiver); } @@ -170,16 +165,12 @@ GetCacheIRReceiverForUnboxedProperty(ICCacheIR_Monitored* stub, ReceiverGuard* r } bool -BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receivers, - ObjectGroupVector& convertUnboxedGroups) +BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receivers) { // Return a list of the receivers seen by the baseline IC for the current // op. Empty lists indicate no receivers are known, or there was an - // uncacheable access. convertUnboxedGroups is used for unboxed object - // groups which have been seen, but have had instances converted to native - // objects and should be eagerly converted by Ion. + // uncacheable access. MOZ_ASSERT(receivers.empty()); - MOZ_ASSERT(convertUnboxedGroups.empty()); if (!hasBaselineScript()) return true; @@ -207,7 +198,7 @@ BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receiv return true; } - if (!AddReceiver(receiver, receivers, convertUnboxedGroups)) + if (!AddReceiver(receiver, receivers)) return false; stub = stub->next(); @@ -700,14 +691,12 @@ bool BaselineInspector::commonGetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape, JSFunction** commonGetter, Shape** globalShape, bool* isOwnProperty, - ReceiverVector& receivers, - ObjectGroupVector& convertUnboxedGroups) + ReceiverVector& receivers) { if (!hasBaselineScript()) return false; MOZ_ASSERT(receivers.empty()); - MOZ_ASSERT(convertUnboxedGroups.empty()); *holder = nullptr; const ICEntry& entry = icEntryFromPC(pc); @@ -719,7 +708,7 @@ BaselineInspector::commonGetPropFunction(jsbytecode* pc, JSObject** holder, Shap { ICGetPropCallGetter* nstub = static_cast(stub); bool isOwn = nstub->isOwnGetter(); - if (!isOwn && !AddReceiver(nstub->receiverGuard(), receivers, convertUnboxedGroups)) + if (!isOwn && !AddReceiver(nstub->receiverGuard(), receivers)) return false; if (!*holder) { @@ -751,21 +740,19 @@ BaselineInspector::commonGetPropFunction(jsbytecode* pc, JSObject** holder, Shap if (!*holder) return false; - MOZ_ASSERT(*isOwnProperty == (receivers.empty() && convertUnboxedGroups.empty())); + MOZ_ASSERT(*isOwnProperty == (receivers.empty())); return true; } bool BaselineInspector::commonSetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape, JSFunction** commonSetter, bool* isOwnProperty, - ReceiverVector& receivers, - ObjectGroupVector& convertUnboxedGroups) + ReceiverVector& receivers) { if (!hasBaselineScript()) return false; MOZ_ASSERT(receivers.empty()); - MOZ_ASSERT(convertUnboxedGroups.empty()); *holder = nullptr; const ICEntry& entry = icEntryFromPC(pc); @@ -774,7 +761,7 @@ BaselineInspector::commonSetPropFunction(jsbytecode* pc, JSObject** holder, Shap if (stub->isSetProp_CallScripted() || stub->isSetProp_CallNative()) { ICSetPropCallSetter* nstub = static_cast(stub); bool isOwn = nstub->isOwnSetter(); - if (!isOwn && !AddReceiver(nstub->receiverGuard(), receivers, convertUnboxedGroups)) + if (!isOwn && !AddReceiver(nstub->receiverGuard(), receivers)) return false; if (!*holder) { diff --git a/js/src/jit/BaselineInspector.h b/js/src/jit/BaselineInspector.h index 961df18aa..4a1791798 100644 --- a/js/src/jit/BaselineInspector.h +++ b/js/src/jit/BaselineInspector.h @@ -95,8 +95,7 @@ class BaselineInspector public: typedef Vector ReceiverVector; typedef Vector ObjectGroupVector; - MOZ_MUST_USE bool maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receivers, - ObjectGroupVector& convertUnboxedGroups); + MOZ_MUST_USE bool maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receivers); SetElemICInspector setElemICInspector(jsbytecode* pc) { return makeICInspector(pc, ICStub::SetElem_Fallback); @@ -131,12 +130,10 @@ class BaselineInspector MOZ_MUST_USE bool commonGetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape, JSFunction** commonGetter, Shape** globalShape, - bool* isOwnProperty, ReceiverVector& receivers, - ObjectGroupVector& convertUnboxedGroups); + bool* isOwnProperty, ReceiverVector& receivers); MOZ_MUST_USE bool commonSetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape, JSFunction** commonSetter, bool* isOwnProperty, - ReceiverVector& receivers, - ObjectGroupVector& convertUnboxedGroups); + ReceiverVector& receivers); MOZ_MUST_USE bool instanceOfData(jsbytecode* pc, Shape** shape, uint32_t* slot, JSObject** prototypeObject); diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 54d05cac4..28fa53aa8 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -9012,8 +9012,6 @@ IonBuilder::jsop_getelem() } obj = maybeUnboxForPropertyAccess(obj); - if (obj->type() == MIRType::Object) - obj = convertUnboxedObjects(obj); bool emitted = false; @@ -10137,7 +10135,7 @@ IonBuilder::jsop_setelem() MDefinition* value = current->pop(); MDefinition* index = current->pop(); - MDefinition* object = convertUnboxedObjects(current->pop()); + MDefinition* object = current->pop(); trackTypeInfo(TrackedTypeSite::Receiver, object->type(), object->resultTypeSet()); trackTypeInfo(TrackedTypeSite::Index, index->type(), index->resultTypeSet()); @@ -11496,8 +11494,6 @@ IonBuilder::jsop_getprop(PropertyName* name) } obj = maybeUnboxForPropertyAccess(obj); - if (obj->type() == MIRType::Object) - obj = convertUnboxedObjects(obj); BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), obj, name, types); @@ -11939,49 +11935,6 @@ IonBuilder::getPropTryComplexPropOfTypedObject(bool* emitted, fieldPrediction, fieldTypeObj); } -MDefinition* -IonBuilder::convertUnboxedObjects(MDefinition* obj) -{ - // If obj might be in any particular unboxed group which should be - // converted to a native representation, perform that conversion. This does - // not guarantee the object will not have such a group afterwards, if the - // object's possible groups are not precisely known. - TemporaryTypeSet* types = obj->resultTypeSet(); - if (!types || types->unknownObject() || !types->objectOrSentinel()) - return obj; - - BaselineInspector::ObjectGroupVector list(alloc()); - for (size_t i = 0; i < types->getObjectCount(); i++) { - TypeSet::ObjectKey* key = obj->resultTypeSet()->getObject(i); - if (!key || !key->isGroup()) - continue; - - if (UnboxedLayout* layout = key->group()->maybeUnboxedLayout()) { - AutoEnterOOMUnsafeRegion oomUnsafe; - if (layout->nativeGroup() && !list.append(key->group())) - oomUnsafe.crash("IonBuilder::convertUnboxedObjects"); - } - } - - return convertUnboxedObjects(obj, list); -} - -MDefinition* -IonBuilder::convertUnboxedObjects(MDefinition* obj, - const BaselineInspector::ObjectGroupVector& list) -{ - for (size_t i = 0; i < list.length(); i++) { - ObjectGroup* group = list[i]; - if (TemporaryTypeSet* types = obj->resultTypeSet()) { - if (!types->hasType(TypeSet::ObjectType(group))) - continue; - } - obj = MConvertUnboxedObjectToNative::New(alloc(), obj, group); - current->add(obj->toInstruction()); - } - return obj; -} - bool IonBuilder::getPropTryDefiniteSlot(bool* emitted, MDefinition* obj, PropertyName* name, BarrierKind barrier, TemporaryTypeSet* types) @@ -12163,14 +12116,11 @@ IonBuilder::getPropTryUnboxed(bool* emitted, MDefinition* obj, PropertyName* nam MDefinition* IonBuilder::addShapeGuardsForGetterSetter(MDefinition* obj, JSObject* holder, Shape* holderShape, const BaselineInspector::ReceiverVector& receivers, - const BaselineInspector::ObjectGroupVector& convertUnboxedGroups, bool isOwnProperty) { MOZ_ASSERT(holder); MOZ_ASSERT(holderShape); - obj = convertUnboxedObjects(obj, convertUnboxedGroups); - if (isOwnProperty) { MOZ_ASSERT(receivers.empty()); return addShapeGuard(obj, holderShape, Bailout_ShapeGuard); @@ -12194,10 +12144,8 @@ IonBuilder::getPropTryCommonGetter(bool* emitted, MDefinition* obj, PropertyName JSObject* foundProto = nullptr; bool isOwnProperty = false; BaselineInspector::ReceiverVector receivers(alloc()); - BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc()); if (!inspector->commonGetPropFunction(pc, &foundProto, &lastProperty, &commonGetter, - &globalShape, &isOwnProperty, - receivers, convertUnboxedGroups)) + &globalShape, &isOwnProperty, receivers)) { return true; } @@ -12213,8 +12161,7 @@ IonBuilder::getPropTryCommonGetter(bool* emitted, MDefinition* obj, PropertyName // If type information is bad, we can still optimize the getter if we // shape guard. obj = addShapeGuardsForGetterSetter(obj, foundProto, lastProperty, - receivers, convertUnboxedGroups, - isOwnProperty); + receivers, isOwnProperty); if (!obj) return false; } @@ -12381,15 +12328,12 @@ IonBuilder::getPropTryInlineAccess(bool* emitted, MDefinition* obj, PropertyName MOZ_ASSERT(*emitted == false); BaselineInspector::ReceiverVector receivers(alloc()); - BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc()); - if (!inspector->maybeInfoForPropertyOp(pc, receivers, convertUnboxedGroups)) + if (!inspector->maybeInfoForPropertyOp(pc, receivers)) return false; if (!canInlinePropertyOpShapes(receivers)) return true; - obj = convertUnboxedObjects(obj, convertUnboxedGroups); - MIRType rvalType = types->getKnownMIRType(); if (barrier != BarrierKind::NoBarrier || IsNullOrUndefined(rvalType)) rvalType = MIRType::Value; @@ -12692,7 +12636,7 @@ bool IonBuilder::jsop_setprop(PropertyName* name) { MDefinition* value = current->pop(); - MDefinition* obj = convertUnboxedObjects(current->pop()); + MDefinition* obj = current->pop(); bool emitted = false; startTrackingOptimizations(); @@ -12765,10 +12709,8 @@ IonBuilder::setPropTryCommonSetter(bool* emitted, MDefinition* obj, JSObject* foundProto = nullptr; bool isOwnProperty; BaselineInspector::ReceiverVector receivers(alloc()); - BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc()); if (!inspector->commonSetPropFunction(pc, &foundProto, &lastProperty, &commonSetter, - &isOwnProperty, - receivers, convertUnboxedGroups)) + &isOwnProperty, receivers)) { trackOptimizationOutcome(TrackedOutcome::NoProtoFound); return true; @@ -12783,8 +12725,7 @@ IonBuilder::setPropTryCommonSetter(bool* emitted, MDefinition* obj, // If type information is bad, we can still optimize the setter if we // shape guard. obj = addShapeGuardsForGetterSetter(obj, foundProto, lastProperty, - receivers, convertUnboxedGroups, - isOwnProperty); + receivers, isOwnProperty); if (!obj) return false; } @@ -13146,15 +13087,12 @@ IonBuilder::setPropTryInlineAccess(bool* emitted, MDefinition* obj, } BaselineInspector::ReceiverVector receivers(alloc()); - BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc()); - if (!inspector->maybeInfoForPropertyOp(pc, receivers, convertUnboxedGroups)) + if (!inspector->maybeInfoForPropertyOp(pc, receivers)) return false; if (!canInlinePropertyOpShapes(receivers)) return true; - obj = convertUnboxedObjects(obj, convertUnboxedGroups); - if (receivers.length() == 1) { if (!receivers[0].group) { // Monomorphic store to a native object. @@ -13884,7 +13822,7 @@ IonBuilder::jsop_setaliasedvar(EnvironmentCoordinate ec) bool IonBuilder::jsop_in() { - MDefinition* obj = convertUnboxedObjects(current->pop()); + MDefinition* obj = current->pop(); MDefinition* id = current->pop(); bool emitted = false; diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index f24ef30c8..2880c7ea1 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -1041,7 +1041,6 @@ class IonBuilder MDefinition* addShapeGuardsForGetterSetter(MDefinition* obj, JSObject* holder, Shape* holderShape, const BaselineInspector::ReceiverVector& receivers, - const BaselineInspector::ObjectGroupVector& convertUnboxedGroups, bool isOwnProperty); MOZ_MUST_USE bool annotateGetPropertyCache(MDefinition* obj, PropertyName* name, @@ -1059,9 +1058,6 @@ class IonBuilder ResultWithOOM testNotDefinedProperty(MDefinition* obj, jsid id); uint32_t getDefiniteSlot(TemporaryTypeSet* types, PropertyName* name, uint32_t* pnfixed); - MDefinition* convertUnboxedObjects(MDefinition* obj); - MDefinition* convertUnboxedObjects(MDefinition* obj, - const BaselineInspector::ObjectGroupVector& list); uint32_t getUnboxedOffset(TemporaryTypeSet* types, PropertyName* name, JSValueType* punboxedType); MInstruction* loadUnboxedProperty(MDefinition* obj, size_t offset, JSValueType unboxedType, diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 01755094a..41ccd0ca7 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -615,7 +615,7 @@ IonBuilder::inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode) OBJECT_FLAG_LENGTH_OVERFLOW | OBJECT_FLAG_ITERATED; - MDefinition* obj = convertUnboxedObjects(callInfo.thisArg()); + MDefinition* obj = callInfo.thisArg(); TemporaryTypeSet* thisTypes = obj->resultTypeSet(); if (!thisTypes) return InliningStatus_NotInlined; @@ -743,7 +743,7 @@ IonBuilder::inlineArrayPush(CallInfo& callInfo) return InliningStatus_NotInlined; } - MDefinition* obj = convertUnboxedObjects(callInfo.thisArg()); + MDefinition* obj = callInfo.thisArg(); MDefinition* value = callInfo.getArg(0); if (PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current, &obj, nullptr, &value, /* canModify = */ false)) @@ -822,7 +822,7 @@ IonBuilder::inlineArraySlice(CallInfo& callInfo) return InliningStatus_NotInlined; } - MDefinition* obj = convertUnboxedObjects(callInfo.thisArg()); + MDefinition* obj = callInfo.thisArg(); // Ensure |this| and result are objects. if (getInlineReturnType() != MIRType::Object) @@ -2152,7 +2152,7 @@ IonBuilder::inlineDefineDataProperty(CallInfo& callInfo) if (callInfo.argc() != 3) return InliningStatus_NotInlined; - MDefinition* obj = convertUnboxedObjects(callInfo.getArg(0)); + MDefinition* obj = callInfo.getArg(0); MDefinition* id = callInfo.getArg(1); MDefinition* value = callInfo.getArg(2); diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp index 3018ace67..d7ad91de4 100644 --- a/js/src/vm/UnboxedObject.cpp +++ b/js/src/vm/UnboxedObject.cpp @@ -1655,227 +1655,12 @@ const Class UnboxedArrayObject::class_ = { // API ///////////////////////////////////////////////////////////////////// -static bool -UnboxedTypeIncludes(JSValueType supertype, JSValueType subtype) -{ - if (supertype == JSVAL_TYPE_DOUBLE && subtype == JSVAL_TYPE_INT32) - return true; - if (supertype == JSVAL_TYPE_OBJECT && subtype == JSVAL_TYPE_NULL) - return true; - return false; -} - -static bool -CombineUnboxedTypes(const Value& value, JSValueType* existing) -{ - JSValueType type = value.isDouble() ? JSVAL_TYPE_DOUBLE : value.extractNonDoubleType(); - - if (*existing == JSVAL_TYPE_MAGIC || *existing == type || UnboxedTypeIncludes(type, *existing)) { - *existing = type; - return true; - } - if (UnboxedTypeIncludes(*existing, type)) - return true; - return false; -} - -// Return whether the property names and types in layout are a subset of the -// specified vector. -static bool -PropertiesAreSuperset(const UnboxedLayout::PropertyVector& properties, UnboxedLayout* layout) -{ - for (size_t i = 0; i < layout->properties().length(); i++) { - const UnboxedLayout::Property& layoutProperty = layout->properties()[i]; - bool found = false; - for (size_t j = 0; j < properties.length(); j++) { - if (layoutProperty.name == properties[j].name) { - found = (layoutProperty.type == properties[j].type); - break; - } - } - if (!found) - return false; - } - return true; -} - -static bool -CombinePlainObjectProperties(PlainObject* obj, Shape* templateShape, - UnboxedLayout::PropertyVector& properties) -{ - // All preliminary objects must have been created with enough space to - // fill in their unboxed data inline. This is ensured either by using - // the largest allocation kind (which limits the maximum size of an - // unboxed object), or by using an allocation kind that covers all - // properties in the template, as the space used by unboxed properties - // is less than or equal to that used by boxed properties. - MOZ_ASSERT(gc::GetGCKindSlots(obj->asTenured().getAllocKind()) >= - Min(NativeObject::MAX_FIXED_SLOTS, templateShape->slotSpan())); - - if (obj->lastProperty() != templateShape || obj->hasDynamicElements()) { - // Only use an unboxed representation if all created objects match - // the template shape exactly. - return false; - } - - for (size_t i = 0; i < templateShape->slotSpan(); i++) { - Value val = obj->getSlot(i); - - JSValueType& existing = properties[i].type; - if (!CombineUnboxedTypes(val, &existing)) - return false; - } - - return true; -} - -static bool -CombineArrayObjectElements(ExclusiveContext* cx, ArrayObject* obj, JSValueType* elementType) -{ - if (obj->inDictionaryMode() || - obj->lastProperty()->propid() != AtomToId(cx->names().length) || - !obj->lastProperty()->previous()->isEmptyShape()) - { - // Only use an unboxed representation if the object has no properties. - return false; - } - - for (size_t i = 0; i < obj->getDenseInitializedLength(); i++) { - Value val = obj->getDenseElement(i); - - // For now, unboxed arrays cannot have holes. - if (val.isMagic(JS_ELEMENTS_HOLE)) - return false; - - if (!CombineUnboxedTypes(val, elementType)) - return false; - } - - return true; -} - -static size_t -ComputePlainObjectLayout(ExclusiveContext* cx, Shape* templateShape, - UnboxedLayout::PropertyVector& properties) -{ - // Fill in the names for all the object's properties. - for (Shape::Range r(templateShape); !r.empty(); r.popFront()) { - size_t slot = r.front().slot(); - MOZ_ASSERT(!properties[slot].name); - properties[slot].name = JSID_TO_ATOM(r.front().propid())->asPropertyName(); - } - - // Fill in all the unboxed object's property offsets. - uint32_t offset = 0; - - // Search for an existing unboxed layout which is a subset of this one. - // If there are multiple such layouts, use the largest one. If we're able - // to find such a layout, use the same property offsets for the shared - // properties, which will allow us to generate better code if the objects - // have a subtype/supertype relation and are accessed at common sites. - UnboxedLayout* bestExisting = nullptr; - for (UnboxedLayout* existing : cx->compartment()->unboxedLayouts) { - if (PropertiesAreSuperset(properties, existing)) { - if (!bestExisting || - existing->properties().length() > bestExisting->properties().length()) - { - bestExisting = existing; - } - } - } - if (bestExisting) { - for (size_t i = 0; i < bestExisting->properties().length(); i++) { - const UnboxedLayout::Property& existingProperty = bestExisting->properties()[i]; - for (size_t j = 0; j < templateShape->slotSpan(); j++) { - if (existingProperty.name == properties[j].name) { - MOZ_ASSERT(existingProperty.type == properties[j].type); - properties[j].offset = existingProperty.offset; - } - } - } - offset = bestExisting->size(); - } - - // Order remaining properties from the largest down for the best space - // utilization. - static const size_t typeSizes[] = { 8, 4, 1 }; - - for (size_t i = 0; i < ArrayLength(typeSizes); i++) { - size_t size = typeSizes[i]; - for (size_t j = 0; j < templateShape->slotSpan(); j++) { - if (properties[j].offset != UINT32_MAX) - continue; - JSValueType type = properties[j].type; - if (UnboxedTypeSize(type) == size) { - offset = JS_ROUNDUP(offset, size); - properties[j].offset = offset; - offset += size; - } - } - } - - // The final offset is the amount of data needed by the object. - return offset; -} - -static bool -SetLayoutTraceList(ExclusiveContext* cx, UnboxedLayout* layout) -{ - // Figure out the offsets of any objects or string properties. - Vector objectOffsets, stringOffsets; - for (size_t i = 0; i < layout->properties().length(); i++) { - const UnboxedLayout::Property& property = layout->properties()[i]; - MOZ_ASSERT(property.offset != UINT32_MAX); - if (property.type == JSVAL_TYPE_OBJECT) { - if (!objectOffsets.append(property.offset)) - return false; - } else if (property.type == JSVAL_TYPE_STRING) { - if (!stringOffsets.append(property.offset)) - return false; - } - } - - // Construct the layout's trace list. - if (!objectOffsets.empty() || !stringOffsets.empty()) { - Vector entries; - if (!entries.appendAll(stringOffsets) || - !entries.append(-1) || - !entries.appendAll(objectOffsets) || - !entries.append(-1) || - !entries.append(-1)) - { - return false; - } - int32_t* traceList = cx->zone()->pod_malloc(entries.length()); - if (!traceList) - return false; - PodCopy(traceList, entries.begin(), entries.length()); - layout->setTraceList(traceList); - } - - return true; -} - static inline Value NextValue(Handle> values, size_t* valueCursor) { return values[(*valueCursor)++]; } -static bool -GetValuesFromPreliminaryArrayObject(ArrayObject* obj, MutableHandle> values) -{ - if (!values.append(Int32Value(obj->length()))) - return false; - if (!values.append(Int32Value(obj->getDenseInitializedLength()))) - return false; - for (size_t i = 0; i < obj->getDenseInitializedLength(); i++) { - if (!values.append(obj->getDenseElement(i))) - return false; - } - return true; -} - void UnboxedArrayObject::fillAfterConvert(ExclusiveContext* cx, Handle> values, size_t* valueCursor) @@ -1901,16 +1686,6 @@ UnboxedArrayObject::fillAfterConvert(ExclusiveContext* cx, JS_ALWAYS_TRUE(initElement(cx, i, NextValue(values, valueCursor))); } -static bool -GetValuesFromPreliminaryPlainObject(PlainObject* obj, MutableHandle> values) -{ - for (size_t i = 0; i < obj->slotSpan(); i++) { - if (!values.append(obj->getSlot(i))) - return false; - } - return true; -} - void UnboxedPlainObject::fillAfterConvert(ExclusiveContext* cx, Handle> values, size_t* valueCursor) @@ -1921,181 +1696,6 @@ UnboxedPlainObject::fillAfterConvert(ExclusiveContext* cx, JS_ALWAYS_TRUE(setValue(cx, layout().properties()[i], NextValue(values, valueCursor))); } -bool -js::TryConvertToUnboxedLayout(ExclusiveContext* cx, AutoEnterAnalysis& enter, Shape* templateShape, - ObjectGroup* group, PreliminaryObjectArray* objects) -{ - bool isArray = !templateShape; - - // Unboxed arrays are nightly only for now. The getenv() call will be - // removed when they are on by default. See bug 1153266. - if (isArray) { -#ifdef NIGHTLY_BUILD - if (!getenv("JS_OPTION_USE_UNBOXED_ARRAYS")) { - if (!cx->options().unboxedArrays()) - return true; - } -#else - return true; -#endif - } else { - if (jit::JitOptions.disableUnboxedObjects) - return true; - } - - MOZ_ASSERT_IF(templateShape, !templateShape->getObjectFlags()); - - if (group->runtimeFromAnyThread()->isSelfHostingGlobal(cx->global())) - return true; - - if (!isArray && templateShape->slotSpan() == 0) - return true; - - UnboxedLayout::PropertyVector properties; - if (!isArray) { - if (!properties.appendN(UnboxedLayout::Property(), templateShape->slotSpan())) - return false; - } - JSValueType elementType = JSVAL_TYPE_MAGIC; - - size_t objectCount = 0; - for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) { - JSObject* obj = objects->get(i); - if (!obj) - continue; - - if (obj->isSingleton() || obj->group() != group) - return true; - - objectCount++; - - if (isArray) { - if (!CombineArrayObjectElements(cx, &obj->as(), &elementType)) - return true; - } else { - if (!CombinePlainObjectProperties(&obj->as(), templateShape, properties)) - return true; - } - } - - size_t layoutSize = 0; - if (isArray) { - // Don't use an unboxed representation if we couldn't determine an - // element type for the objects. - if (UnboxedTypeSize(elementType) == 0) - return true; - } else { - if (objectCount <= 1) { - // If only one of the objects has been created, it is more likely - // to have new properties added later. This heuristic is not used - // for array objects, where we might want an unboxed representation - // even if there is only one large array. - return true; - } - - for (size_t i = 0; i < templateShape->slotSpan(); i++) { - // We can't use an unboxed representation if e.g. all the objects have - // a null value for one of the properties, as we can't decide what type - // it is supposed to have. - if (UnboxedTypeSize(properties[i].type) == 0) - return true; - } - - // Make sure that all properties on the template shape are property - // names, and not indexes. - for (Shape::Range r(templateShape); !r.empty(); r.popFront()) { - jsid id = r.front().propid(); - uint32_t dummy; - if (!JSID_IS_ATOM(id) || JSID_TO_ATOM(id)->isIndex(&dummy)) - return true; - } - - layoutSize = ComputePlainObjectLayout(cx, templateShape, properties); - - // The entire object must be allocatable inline. - if (UnboxedPlainObject::offsetOfData() + layoutSize > JSObject::MAX_BYTE_SIZE) - return true; - } - - UniquePtr& layout = enter.unboxedLayoutToCleanUp; - MOZ_ASSERT(!layout); - layout = group->zone()->make_unique(); - if (!layout) - return false; - - if (isArray) { - layout->initArray(elementType); - } else { - if (!layout->initProperties(properties, layoutSize)) - return false; - - // The unboxedLayouts list only tracks layouts for plain objects. - cx->compartment()->unboxedLayouts.insertFront(layout.get()); - - if (!SetLayoutTraceList(cx, layout.get())) - return false; - } - - // We've determined that all the preliminary objects can use the new layout - // just constructed, so convert the existing group to use the unboxed class, - // and update the preliminary objects to use the new layout. Do the - // fallible stuff first before modifying any objects. - - // Get an empty shape which we can use for the preliminary objects. - const Class* clasp = isArray ? &UnboxedArrayObject::class_ : &UnboxedPlainObject::class_; - Shape* newShape = EmptyShape::getInitialShape(cx, clasp, group->proto(), 0); - if (!newShape) { - cx->recoverFromOutOfMemory(); - return false; - } - - // Accumulate a list of all the values in each preliminary object, and - // update their shapes. - Rooted> values(cx, GCVector(cx)); - for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) { - JSObject* obj = objects->get(i); - if (!obj) - continue; - - bool ok; - if (isArray) - ok = GetValuesFromPreliminaryArrayObject(&obj->as(), &values); - else - ok = GetValuesFromPreliminaryPlainObject(&obj->as(), &values); - - if (!ok) { - cx->recoverFromOutOfMemory(); - return false; - } - } - - if (TypeNewScript* newScript = group->newScript()) - layout->setNewScript(newScript); - - for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) { - if (JSObject* obj = objects->get(i)) - obj->as().setLastPropertyMakeNonNative(newShape); - } - - group->setClasp(clasp); - group->setUnboxedLayout(layout.release()); - - size_t valueCursor = 0; - for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) { - JSObject* obj = objects->get(i); - if (!obj) - continue; - - if (isArray) - obj->as().fillAfterConvert(cx, values, &valueCursor); - else - obj->as().fillAfterConvert(cx, values, &valueCursor); - } - - MOZ_ASSERT(valueCursor == values.length()); - return true; -} - DefineBoxedOrUnboxedFunctor6(SetOrExtendBoxedOrUnboxedDenseElements, ExclusiveContext*, JSObject*, uint32_t, const Value*, uint32_t, ShouldUpdateTypes); -- cgit v1.2.3 From 3b36a43e8ecc34199759691897e18168bbb261e2 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Wed, 15 May 2019 02:06:04 +0000 Subject: Remove initial chunk of Unboxed Objects machinery part 2 --- js/src/vm/TypeInference.cpp | 5 ----- js/src/vm/UnboxedObject.h | 7 ------- 2 files changed, 12 deletions(-) (limited to 'js/src') diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index 4775a2dea..fe89fac9c 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -3577,7 +3577,6 @@ PreliminaryObjectArrayWithTemplate::maybeAnalyze(ExclusiveContext* cx, ObjectGro } } - TryConvertToUnboxedLayout(cx, enter, shape(), group, preliminaryObjects); if (group->maybeUnboxedLayout()) return; @@ -3861,10 +3860,6 @@ TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate, PodCopy(initializerList, initializerVector.begin(), initializerVector.length()); } - // Try to use an unboxed representation for the group. - if (!TryConvertToUnboxedLayout(cx, enter, templateObject()->lastProperty(), group, preliminaryObjects)) - return false; - js_delete(preliminaryObjects); preliminaryObjects = nullptr; diff --git a/js/src/vm/UnboxedObject.h b/js/src/vm/UnboxedObject.h index ecff8be5b..779dd14c7 100644 --- a/js/src/vm/UnboxedObject.h +++ b/js/src/vm/UnboxedObject.h @@ -317,13 +317,6 @@ class UnboxedPlainObject : public JSObject } }; -// Try to construct an UnboxedLayout for each of the preliminary objects, -// provided they all match the template shape. If successful, converts the -// preliminary objects and their group to the new unboxed representation. -bool -TryConvertToUnboxedLayout(ExclusiveContext* cx, AutoEnterAnalysis& enter, Shape* templateShape, - ObjectGroup* group, PreliminaryObjectArray* objects); - inline gc::AllocKind UnboxedLayout::getAllocKind() const { -- cgit v1.2.3 From d40bcc350ce47de4a92dd1dc7f7162dc1154678b Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Wed, 15 May 2019 13:18:33 +0000 Subject: Remove Unboxed Objects in ScalarReplacement A note about the Scalar Replacement Changes: The M{Load,Store}Unboxed* instructions in theory could be used to manipulate and analyze typed arrays. However, TypedArrays should already be excluded from eligibility because of the potential for cross-thread sharing in a SharedArrayBuffer world, and so the only support in Scalar Replacement here is for Unboxed Objects, meaning it can all be removed. --- js/src/jit/ScalarReplacement.cpp | 112 --------------------------------------- 1 file changed, 112 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/ScalarReplacement.cpp b/js/src/jit/ScalarReplacement.cpp index 4614b2162..2065c0371 100644 --- a/js/src/jit/ScalarReplacement.cpp +++ b/js/src/jit/ScalarReplacement.cpp @@ -13,7 +13,6 @@ #include "jit/MIR.h" #include "jit/MIRGenerator.h" #include "jit/MIRGraph.h" -#include "vm/UnboxedObject.h" #include "jsobjinlines.h" @@ -183,25 +182,6 @@ IsObjectEscaped(MInstruction* ins, JSObject* objDefault) JitSpewDef(JitSpew_Escape, "is escaped by\n", def); return true; - case MDefinition::Op_LoadUnboxedScalar: - case MDefinition::Op_StoreUnboxedScalar: - case MDefinition::Op_LoadUnboxedObjectOrNull: - case MDefinition::Op_StoreUnboxedObjectOrNull: - case MDefinition::Op_LoadUnboxedString: - case MDefinition::Op_StoreUnboxedString: - // Not escaped if it is the first argument. - if (def->indexOf(*i) != 0) { - JitSpewDef(JitSpew_Escape, "is escaped by\n", def); - return true; - } - - if (!def->getOperand(1)->isConstant()) { - JitSpewDef(JitSpew_Escape, "is addressed with unknown index\n", def); - return true; - } - - break; - case MDefinition::Op_PostWriteBarrier: break; @@ -305,12 +285,6 @@ class ObjectMemoryView : public MDefinitionVisitorDefaultNoop void visitGuardShape(MGuardShape* ins); void visitFunctionEnvironment(MFunctionEnvironment* ins); void visitLambda(MLambda* ins); - void visitStoreUnboxedScalar(MStoreUnboxedScalar* ins); - void visitLoadUnboxedScalar(MLoadUnboxedScalar* ins); - void visitStoreUnboxedObjectOrNull(MStoreUnboxedObjectOrNull* ins); - void visitLoadUnboxedObjectOrNull(MLoadUnboxedObjectOrNull* ins); - void visitStoreUnboxedString(MStoreUnboxedString* ins); - void visitLoadUnboxedString(MLoadUnboxedString* ins); private: void storeOffset(MInstruction* ins, size_t offset, MDefinition* value); @@ -656,21 +630,6 @@ ObjectMemoryView::visitLambda(MLambda* ins) ins->setIncompleteObject(); } -static size_t -GetOffsetOf(MDefinition* index, size_t width, int32_t baseOffset) -{ - int32_t idx = index->toConstant()->toInt32(); - MOZ_ASSERT(idx >= 0); - MOZ_ASSERT(baseOffset >= 0 && size_t(baseOffset) >= UnboxedPlainObject::offsetOfData()); - return idx * width + baseOffset - UnboxedPlainObject::offsetOfData(); -} - -static size_t -GetOffsetOf(MDefinition* index, Scalar::Type type, int32_t baseOffset) -{ - return GetOffsetOf(index, Scalar::byteSize(type), baseOffset); -} - void ObjectMemoryView::storeOffset(MInstruction* ins, size_t offset, MDefinition* value) { @@ -700,77 +659,6 @@ ObjectMemoryView::loadOffset(MInstruction* ins, size_t offset) ins->block()->discard(ins); } -void -ObjectMemoryView::visitStoreUnboxedScalar(MStoreUnboxedScalar* ins) -{ - // Skip stores made on other objects. - if (ins->elements() != obj_) - return; - - size_t offset = GetOffsetOf(ins->index(), ins->storageType(), ins->offsetAdjustment()); - storeOffset(ins, offset, ins->value()); -} - -void -ObjectMemoryView::visitLoadUnboxedScalar(MLoadUnboxedScalar* ins) -{ - // Skip loads made on other objects. - if (ins->elements() != obj_) - return; - - // Replace load by the slot value. - size_t offset = GetOffsetOf(ins->index(), ins->storageType(), ins->offsetAdjustment()); - loadOffset(ins, offset); -} - -void -ObjectMemoryView::visitStoreUnboxedObjectOrNull(MStoreUnboxedObjectOrNull* ins) -{ - // Skip stores made on other objects. - if (ins->elements() != obj_) - return; - - // Clone the state and update the slot value. - size_t offset = GetOffsetOf(ins->index(), sizeof(uintptr_t), ins->offsetAdjustment()); - storeOffset(ins, offset, ins->value()); -} - -void -ObjectMemoryView::visitLoadUnboxedObjectOrNull(MLoadUnboxedObjectOrNull* ins) -{ - // Skip loads made on other objects. - if (ins->elements() != obj_) - return; - - // Replace load by the slot value. - size_t offset = GetOffsetOf(ins->index(), sizeof(uintptr_t), ins->offsetAdjustment()); - loadOffset(ins, offset); -} - -void -ObjectMemoryView::visitStoreUnboxedString(MStoreUnboxedString* ins) -{ - // Skip stores made on other objects. - if (ins->elements() != obj_) - return; - - // Clone the state and update the slot value. - size_t offset = GetOffsetOf(ins->index(), sizeof(uintptr_t), ins->offsetAdjustment()); - storeOffset(ins, offset, ins->value()); -} - -void -ObjectMemoryView::visitLoadUnboxedString(MLoadUnboxedString* ins) -{ - // Skip loads made on other objects. - if (ins->elements() != obj_) - return; - - // Replace load by the slot value. - size_t offset = GetOffsetOf(ins->index(), sizeof(uintptr_t), ins->offsetAdjustment()); - loadOffset(ins, offset); -} - static bool IndexOf(MDefinition* ins, int32_t* res) { -- cgit v1.2.3 From 5fd4b87267ba8f3c667533b0336554a7cc008876 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Wed, 15 May 2019 19:37:25 +0000 Subject: Remove unboxed objects from GC --- js/src/gc/Marking.cpp | 46 +--------------------------------- js/src/gc/Tracer.cpp | 69 ++------------------------------------------------- js/src/jsgc.cpp | 6 ----- 3 files changed, 3 insertions(+), 118 deletions(-) (limited to 'js/src') diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index 3ea4c9d29..47d2314c1 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -18,6 +18,7 @@ #include "builtin/ModuleObject.h" #include "gc/GCInternals.h" #include "gc/Policy.h" +#include "gc/StoreBuffer-inl.h" #include "jit/IonCode.h" #include "js/SliceBudget.h" #include "vm/ArgumentsObject.h" @@ -28,7 +29,6 @@ #include "vm/Shape.h" #include "vm/Symbol.h" #include "vm/TypedArrayObject.h" -#include "vm/UnboxedObject.h" #include "wasm/WasmJS.h" #include "jscompartmentinlines.h" @@ -37,7 +37,6 @@ #include "gc/Nursery-inl.h" #include "vm/String-inl.h" -#include "vm/UnboxedObject-inl.h" using namespace js; using namespace js::gc; @@ -1395,14 +1394,6 @@ js::ObjectGroup::traceChildren(JSTracer* trc) if (maybePreliminaryObjects()) maybePreliminaryObjects()->trace(trc); - if (maybeUnboxedLayout()) - unboxedLayout().trace(trc); - - if (ObjectGroup* unboxedGroup = maybeOriginalUnboxedGroup()) { - TraceManuallyBarrieredEdge(trc, &unboxedGroup, "group_original_unboxed_group"); - setOriginalUnboxedGroup(unboxedGroup); - } - if (JSObject* descr = maybeTypeDescr()) { TraceManuallyBarrieredEdge(trc, &descr, "group_type_descr"); setTypeDescr(&descr->as()); @@ -1436,12 +1427,6 @@ js::GCMarker::lazilyMarkChildren(ObjectGroup* group) if (group->maybePreliminaryObjects()) group->maybePreliminaryObjects()->trace(this); - if (group->maybeUnboxedLayout()) - group->unboxedLayout().trace(this); - - if (ObjectGroup* unboxedGroup = group->maybeOriginalUnboxedGroup()) - traverseEdge(group, unboxedGroup); - if (TypeDescr* descr = group->maybeTypeDescr()) traverseEdge(group, static_cast(descr)); @@ -1484,23 +1469,6 @@ CallTraceHook(Functor f, JSTracer* trc, JSObject* obj, CheckGeneration check, Ar return nullptr; } - if (clasp == &UnboxedPlainObject::class_) { - JSObject** pexpando = obj->as().addressOfExpando(); - if (*pexpando) - f(pexpando, mozilla::Forward(args)...); - - UnboxedPlainObject& unboxed = obj->as(); - const UnboxedLayout& layout = check == CheckGeneration::DoChecks - ? unboxed.layout() - : unboxed.layoutDontCheckGeneration(); - if (layout.traceList()) { - VisitTraceList(f, layout.traceList(), unboxed.data(), - mozilla::Forward(args)...); - } - - return nullptr; - } - clasp->doTrace(trc, obj); if (!clasp->isNative()) @@ -2293,18 +2261,6 @@ static inline void TraceWholeCell(TenuringTracer& mover, JSObject* object) { mover.traceObject(object); - - // Additionally trace the expando object attached to any unboxed plain - // objects. Baseline and Ion can write properties to the expando while - // only adding a post barrier to the owning unboxed object. Note that - // it isn't possible for a nursery unboxed object to have a tenured - // expando, so that adding a post barrier on the original object will - // capture any tenured->nursery edges in the expando as well. - - if (object->is()) { - if (UnboxedExpandoObject* expando = object->as().maybeExpando()) - expando->traceChildren(&mover); - } } static inline void diff --git a/js/src/gc/Tracer.cpp b/js/src/gc/Tracer.cpp index 63cd9b08a..3416464dd 100644 --- a/js/src/gc/Tracer.cpp +++ b/js/src/gc/Tracer.cpp @@ -201,80 +201,15 @@ gc::TraceCycleCollectorChildren(JS::CallbackTracer* trc, Shape* shape) } while (shape); } -// Object groups can point to other object groups via an UnboxedLayout or the -// the original unboxed group link. There can potentially be deep or cyclic -// chains of such groups to trace through without going through a thing that -// participates in cycle collection. These need to be handled iteratively to -// avoid blowing the stack when running the cycle collector's callback tracer. -struct ObjectGroupCycleCollectorTracer : public JS::CallbackTracer -{ - explicit ObjectGroupCycleCollectorTracer(JS::CallbackTracer* innerTracer) - : JS::CallbackTracer(innerTracer->runtime(), DoNotTraceWeakMaps), - innerTracer(innerTracer) - {} - - void onChild(const JS::GCCellPtr& thing) override; - - JS::CallbackTracer* innerTracer; - Vector seen, worklist; -}; - -void -ObjectGroupCycleCollectorTracer::onChild(const JS::GCCellPtr& thing) -{ - if (thing.is()) { - // The CC does not care about BaseShapes, and no additional GC things - // will be reached by following this edge. - return; - } - - if (thing.is() || thing.is()) { - // Invoke the inner cycle collector callback on this child. It will not - // recurse back into TraceChildren. - innerTracer->onChild(thing); - return; - } - - if (thing.is()) { - // If this group is required to be in an ObjectGroup chain, trace it - // via the provided worklist rather than continuing to recurse. - ObjectGroup& group = thing.as(); - if (group.maybeUnboxedLayout()) { - for (size_t i = 0; i < seen.length(); i++) { - if (seen[i] == &group) - return; - } - if (seen.append(&group) && worklist.append(&group)) { - return; - } else { - // If append fails, keep tracing normally. The worst that will - // happen is we end up overrecursing. - } - } - } - - TraceChildren(this, thing.asCell(), thing.kind()); -} - void gc::TraceCycleCollectorChildren(JS::CallbackTracer* trc, ObjectGroup* group) { MOZ_ASSERT(trc->isCallbackTracer()); - // Early return if this group is not required to be in an ObjectGroup chain. - if (!group->maybeUnboxedLayout()) - return group->traceChildren(trc); - - ObjectGroupCycleCollectorTracer groupTracer(trc->asCallbackTracer()); - group->traceChildren(&groupTracer); - - while (!groupTracer.worklist.empty()) { - ObjectGroup* innerGroup = groupTracer.worklist.popCopy(); - innerGroup->traceChildren(&groupTracer); - } + group->traceChildren(trc); } - + /*** Traced Edge Printer *************************************************************************/ static size_t diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 194468c5d..b2ee8d67b 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -6190,12 +6190,6 @@ gc::MergeCompartments(JSCompartment* source, JSCompartment* target) for (auto group = source->zone()->cellIter(); !group.done(); group.next()) { group->setGeneration(target->zone()->types.generation); group->compartment_ = target; - - // Remove any unboxed layouts from the list in the off thread - // compartment. These do not need to be reinserted in the target - // compartment's list, as the list is not required to be complete. - if (UnboxedLayout* layout = group->maybeUnboxedLayoutDontCheckGeneration()) - layout->detachFromCompartment(); } // Fixup zone pointers in source's zone to refer to target's zone. -- cgit v1.2.3 From 8feffe7079e516a63a6cc5fd9b2c759c7431cf33 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Wed, 15 May 2019 20:56:36 +0000 Subject: Remove unboxed object code from iteration. --- js/src/jsiter.cpp | 42 ++++++++++-------------------------------- 1 file changed, 10 insertions(+), 32 deletions(-) (limited to 'js/src') diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index c1ae5dc15..004c7fc0d 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -157,8 +157,11 @@ SortComparatorIntegerIds(jsid a, jsid b, bool* lessOrEqualp) } static bool -EnumerateNativeProperties(JSContext* cx, HandleNativeObject pobj, unsigned flags, Maybe& ht, - AutoIdVector* props, Handle unboxed = nullptr) +EnumerateNativeProperties(JSContext* cx, + HandleNativeObject pobj, + unsigned flags, + Maybe& ht, + AutoIdVector* props) { bool enumerateSymbols; if (flags & JSITER_SYMBOLSONLY) { @@ -220,16 +223,6 @@ EnumerateNativeProperties(JSContext* cx, HandleNativeObject pobj, unsigned flags return false; } - if (unboxed) { - // If |unboxed| is set then |pobj| is the expando for an unboxed - // plain object we are enumerating. Add the unboxed properties - // themselves here since they are all property names that were - // given to the object before any of the expando's properties. - MOZ_ASSERT(pobj->is()); - if (!EnumerateExtraProperties(cx, unboxed, flags, ht, props)) - return false; - } - size_t initialLength = props->length(); /* Collect all unique property names from this object's shape. */ @@ -355,22 +348,12 @@ Snapshot(JSContext* cx, HandleObject pobj_, unsigned flags, AutoIdVector* props) do { if (pobj->getOpsEnumerate()) { - if (pobj->is() && pobj->as().maybeExpando()) { - // Special case unboxed objects with an expando object. - RootedNativeObject expando(cx, pobj->as().maybeExpando()); - if (!EnumerateNativeProperties(cx, expando, flags, ht, props, - pobj.as())) - { - return false; - } - } else { - if (!EnumerateExtraProperties(cx, pobj, flags, ht, props)) - return false; + if (!EnumerateExtraProperties(cx, pobj, flags, ht, props)) + return false; - if (pobj->isNative()) { - if (!EnumerateNativeProperties(cx, pobj.as(), flags, ht, props)) - return false; - } + if (pobj->isNative()) { + if (!EnumerateNativeProperties(cx, pobj.as(), flags, ht, props)) + return false; } } else if (pobj->isNative()) { // Give the object a chance to resolve all lazy properties @@ -785,11 +768,6 @@ CanCompareIterableObjectToCache(JSObject* obj) { if (obj->isNative()) return obj->as().hasEmptyElements(); - if (obj->is()) { - if (UnboxedExpandoObject* expando = obj->as().maybeExpando()) - return expando->hasEmptyElements(); - return true; - } return false; } -- cgit v1.2.3 From a5c2961c4e8c0459959fc35e493e58be8e7763d6 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 16 May 2019 00:50:49 +0000 Subject: Remove array header --- js/src/jsarray.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'js/src') diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 7a67c0095..1c05704b8 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -45,7 +45,6 @@ #include "vm/Caches-inl.h" #include "vm/Interpreter-inl.h" #include "vm/NativeObject-inl.h" -#include "vm/UnboxedObject-inl.h" using namespace js; using namespace js::gc; -- cgit v1.2.3 From 543fa1674bcb4f8c40f0ef6e4c5514ea161def5a Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 16 May 2019 13:13:36 +0000 Subject: Remove Unboxed Objects from vm/ Part 1 + fix deprot --- js/src/jit/OptimizationTracking.cpp | 2 ++ js/src/jit/SharedIC.cpp | 1 + js/src/jsarray.cpp | 1 + js/src/jsobj.cpp | 1 + js/src/vm/Interpreter-inl.h | 13 ++++--------- js/src/vm/Interpreter.cpp | 7 +------ 6 files changed, 10 insertions(+), 15 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/OptimizationTracking.cpp b/js/src/jit/OptimizationTracking.cpp index 308def041..b42634d43 100644 --- a/js/src/jit/OptimizationTracking.cpp +++ b/js/src/jit/OptimizationTracking.cpp @@ -15,9 +15,11 @@ #include "jit/JitcodeMap.h" #include "jit/JitSpewer.h" #include "js/TrackedOptimizationInfo.h" +#include "vm/UnboxedObject.h" #include "vm/ObjectGroup-inl.h" #include "vm/TypeInference-inl.h" +#include "vm/UnboxedObject-inl.h" using namespace js; using namespace js::jit; diff --git a/js/src/jit/SharedIC.cpp b/js/src/jit/SharedIC.cpp index 767cff661..2475dfb22 100644 --- a/js/src/jit/SharedIC.cpp +++ b/js/src/jit/SharedIC.cpp @@ -27,6 +27,7 @@ #endif #include "jit/VMFunctions.h" #include "vm/Interpreter.h" +#include "vm/NativeObject-inl.h" #include "jit/MacroAssembler-inl.h" #include "vm/Interpreter-inl.h" diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 1c05704b8..7a67c0095 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -45,6 +45,7 @@ #include "vm/Caches-inl.h" #include "vm/Interpreter-inl.h" #include "vm/NativeObject-inl.h" +#include "vm/UnboxedObject-inl.h" using namespace js; using namespace js::gc; diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index b17c845bb..7852b3365 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -54,6 +54,7 @@ #include "vm/RegExpStaticsObject.h" #include "vm/Shape.h" #include "vm/TypedArrayCommon.h" +#include "vm/UnboxedObject-inl.h" #include "jsatominlines.h" #include "jsboolinlines.h" diff --git a/js/src/vm/Interpreter-inl.h b/js/src/vm/Interpreter-inl.h index 5f476c4ff..710f1d89b 100644 --- a/js/src/vm/Interpreter-inl.h +++ b/js/src/vm/Interpreter-inl.h @@ -22,7 +22,6 @@ #include "vm/EnvironmentObject-inl.h" #include "vm/Stack-inl.h" #include "vm/String-inl.h" -#include "vm/UnboxedObject-inl.h" namespace js { @@ -337,14 +336,10 @@ InitGlobalLexicalOperation(JSContext* cx, LexicalEnvironmentObject* lexicalEnvAr inline bool InitPropertyOperation(JSContext* cx, JSOp op, HandleObject obj, HandleId id, HandleValue rhs) { - if (obj->is() || obj->is()) { - unsigned propAttrs = GetInitDataPropAttrs(op); - return NativeDefineProperty(cx, obj.as(), id, rhs, nullptr, nullptr, - propAttrs); - } - - MOZ_ASSERT(obj->as().layout().lookup(id)); - return PutProperty(cx, obj, id, rhs, false); + MOZ_ASSERT(obj->is() || obj->is()); + unsigned propAttrs = GetInitDataPropAttrs(op); + return NativeDefineProperty(cx, obj.as(), id, rhs, + nullptr, nullptr, propAttrs); } inline bool diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index e6d6630c4..3cf2deb83 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -4111,7 +4111,7 @@ CASE(JSOP_INITHOMEOBJECT) /* Load the home object */ ReservedRooted obj(&rootObject0); obj = ®S.sp[int(-2 - skipOver)].toObject(); - MOZ_ASSERT(obj->is() || obj->is() || obj->is()); + MOZ_ASSERT(obj->is() || obj->is()); func->setExtendedSlot(FunctionExtended::METHOD_HOMEOBJECT_SLOT, ObjectValue(*obj)); } @@ -4927,15 +4927,10 @@ js::NewObjectOperation(JSContext* cx, HandleScript script, jsbytecode* pc, return nullptr; if (group->maybePreliminaryObjects()) { group->maybePreliminaryObjects()->maybeAnalyze(cx, group); - if (group->maybeUnboxedLayout()) - group->maybeUnboxedLayout()->setAllocationSite(script, pc); } if (group->shouldPreTenure() || group->maybePreliminaryObjects()) newKind = TenuredObject; - - if (group->maybeUnboxedLayout()) - return UnboxedPlainObject::create(cx, group, newKind); } RootedObject obj(cx); -- cgit v1.2.3 From fa8bfa1a00ca88dd0ff5f8dcfb89dee5fd01c639 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 16 May 2019 19:54:19 +0000 Subject: Remove unboxed object code from jit, Part 1 --- js/src/jit/AliasAnalysisShared.cpp | 2 - js/src/jit/CodeGenerator.cpp | 61 ------------ js/src/jit/CodeGenerator.h | 3 - js/src/jit/IonAnalysis.cpp | 2 - js/src/jit/IonBuilder.cpp | 192 +----------------------------------- js/src/jit/IonBuilder.h | 6 -- js/src/jit/Lowering.cpp | 26 ----- js/src/jit/Lowering.h | 3 - js/src/jit/MIR.cpp | 161 +++++------------------------- js/src/jit/MIR.h | 131 ------------------------ js/src/jit/MOpcodes.h | 3 - js/src/jit/shared/LIR-shared.h | 48 --------- js/src/jit/shared/LOpcodes-shared.h | 3 - js/src/vm/TypeInference.cpp | 11 --- js/src/vm/TypeInference.h | 1 - 15 files changed, 26 insertions(+), 627 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/AliasAnalysisShared.cpp b/js/src/jit/AliasAnalysisShared.cpp index 81c0fd067..3b83df74e 100644 --- a/js/src/jit/AliasAnalysisShared.cpp +++ b/js/src/jit/AliasAnalysisShared.cpp @@ -114,8 +114,6 @@ GetObject(const MDefinition* ins) case MDefinition::Op_GuardObjectGroup: case MDefinition::Op_GuardObjectIdentity: case MDefinition::Op_GuardClass: - case MDefinition::Op_GuardUnboxedExpando: - case MDefinition::Op_LoadUnboxedExpando: case MDefinition::Op_LoadSlot: case MDefinition::Op_StoreSlot: case MDefinition::Op_InArray: diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 16d026092..6d1fb6b9b 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -3031,15 +3031,6 @@ GuardReceiver(MacroAssembler& masm, const ReceiverGuard& guard, { if (guard.group) { masm.branchTestObjGroup(Assembler::NotEqual, obj, guard.group, miss); - - Address expandoAddress(obj, UnboxedPlainObject::offsetOfExpando()); - if (guard.shape) { - masm.loadPtr(expandoAddress, scratch); - masm.branchPtr(Assembler::Equal, scratch, ImmWord(0), miss); - masm.branchTestObjShape(Assembler::NotEqual, scratch, guard.shape, miss); - } else if (checkNullExpando) { - masm.branchPtr(Assembler::NotEqual, expandoAddress, ImmWord(0), miss); - } } else { masm.branchTestObjShape(Assembler::NotEqual, obj, guard.shape, miss); } @@ -3077,13 +3068,6 @@ CodeGenerator::emitGetPropertyPolymorphic(LInstruction* ins, Register obj, Regis masm.loadPtr(Address(target, NativeObject::offsetOfSlots()), scratch); masm.loadTypedOrValue(Address(scratch, offset), output); } - } else { - masm.comment("loadUnboxedProperty"); - const UnboxedLayout::Property* property = - receiver.group->unboxedLayout().lookup(mir->name()); - Address propertyAddr(obj, UnboxedPlainObject::offsetOfData() + property->offset); - - masm.loadUnboxedProperty(propertyAddr, property->type, output); } if (i == mir->numReceivers() - 1) { @@ -3124,8 +3108,6 @@ EmitUnboxedPreBarrier(MacroAssembler &masm, T address, JSValueType type) masm.patchableCallPreBarrier(address, MIRType::Object); else if (type == JSVAL_TYPE_STRING) masm.patchableCallPreBarrier(address, MIRType::String); - else - MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(type)); } void @@ -3161,13 +3143,6 @@ CodeGenerator::emitSetPropertyPolymorphic(LInstruction* ins, Register obj, Regis emitPreBarrier(addr); masm.storeConstantOrRegister(value, addr); } - } else { - const UnboxedLayout::Property* property = - receiver.group->unboxedLayout().lookup(mir->name()); - Address propertyAddr(obj, UnboxedPlainObject::offsetOfData() + property->offset); - - EmitUnboxedPreBarrier(masm, propertyAddr, property->type); - masm.storeUnboxedProperty(propertyAddr, property->type, value, nullptr); } if (i == mir->numReceivers() - 1) { @@ -3332,27 +3307,6 @@ CodeGenerator::visitGuardReceiverPolymorphic(LGuardReceiverPolymorphic* lir) masm.bind(&done); } -void -CodeGenerator::visitGuardUnboxedExpando(LGuardUnboxedExpando* lir) -{ - Label miss; - - Register obj = ToRegister(lir->object()); - masm.branchPtr(lir->mir()->requireExpando() ? Assembler::Equal : Assembler::NotEqual, - Address(obj, UnboxedPlainObject::offsetOfExpando()), ImmWord(0), &miss); - - bailoutFrom(&miss, lir->snapshot()); -} - -void -CodeGenerator::visitLoadUnboxedExpando(LLoadUnboxedExpando* lir) -{ - Register obj = ToRegister(lir->object()); - Register result = ToRegister(lir->getDef(0)); - - masm.loadPtr(Address(obj, UnboxedPlainObject::offsetOfExpando()), result); -} - void CodeGenerator::visitTypeBarrierV(LTypeBarrierV* lir) { @@ -8576,21 +8530,6 @@ static const VMFunction ConvertUnboxedArrayObjectToNativeInfo = FunctionInfo(UnboxedArrayObject::convertToNative, "UnboxedArrayObject::convertToNative"); -void -CodeGenerator::visitConvertUnboxedObjectToNative(LConvertUnboxedObjectToNative* lir) -{ - Register object = ToRegister(lir->getOperand(0)); - - OutOfLineCode* ool = oolCallVM(lir->mir()->group()->unboxedLayoutDontCheckGeneration().isArray() - ? ConvertUnboxedArrayObjectToNativeInfo - : ConvertUnboxedPlainObjectToNativeInfo, - lir, ArgList(object), StoreNothing()); - - masm.branchPtr(Assembler::Equal, Address(object, JSObject::offsetOfGroup()), - ImmGCPtr(lir->mir()->group()), ool->entry()); - masm.bind(ool->rejoin()); -} - typedef bool (*ArrayPopShiftFn)(JSContext*, HandleObject, MutableHandleValue); static const VMFunction ArrayPopDenseInfo = FunctionInfo(jit::ArrayPopDense, "ArrayPopDense"); diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h index b226f6cc9..292f163b5 100644 --- a/js/src/jit/CodeGenerator.h +++ b/js/src/jit/CodeGenerator.h @@ -148,8 +148,6 @@ class CodeGenerator final : public CodeGeneratorSpecific void visitMaybeCopyElementsForWrite(LMaybeCopyElementsForWrite* lir); void visitGuardObjectIdentity(LGuardObjectIdentity* guard); void visitGuardReceiverPolymorphic(LGuardReceiverPolymorphic* lir); - void visitGuardUnboxedExpando(LGuardUnboxedExpando* lir); - void visitLoadUnboxedExpando(LLoadUnboxedExpando* lir); void visitTypeBarrierV(LTypeBarrierV* lir); void visitTypeBarrierO(LTypeBarrierO* lir); void visitMonitorTypes(LMonitorTypes* lir); @@ -310,7 +308,6 @@ class CodeGenerator final : public CodeGeneratorSpecific void visitFallibleStoreElementV(LFallibleStoreElementV* lir); void visitFallibleStoreElementT(LFallibleStoreElementT* lir); void visitStoreUnboxedPointer(LStoreUnboxedPointer* lir); - void visitConvertUnboxedObjectToNative(LConvertUnboxedObjectToNative* lir); void emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, Register obj, Register elementsTemp, Register lengthTemp, TypedOrValueRegister out); void visitArrayPopShiftV(LArrayPopShiftV* lir); diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index d255c32a8..41c71c9c3 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -3515,8 +3515,6 @@ PassthroughOperand(MDefinition* def) return def->toConvertElementsToDoubles()->elements(); if (def->isMaybeCopyElementsForWrite()) return def->toMaybeCopyElementsForWrite()->object(); - if (def->isConvertUnboxedObjectToNative()) - return def->toConvertUnboxedObjectToNative()->object(); return nullptr; } diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 28fa53aa8..af85011be 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -32,7 +32,6 @@ #include "vm/EnvironmentObject-inl.h" #include "vm/NativeObject-inl.h" #include "vm/ObjectGroup-inl.h" -#include "vm/UnboxedObject-inl.h" using namespace js; using namespace js::jit; @@ -6392,7 +6391,7 @@ IonBuilder::createThisScriptedSingleton(JSFunction* target, MDefinition* callee) JSObject* templateObject = inspector->getTemplateObject(pc); if (!templateObject) return nullptr; - if (!templateObject->is() && !templateObject->is()) + if (!templateObject->is()) return nullptr; if (templateObject->staticPrototype() != proto) return nullptr; @@ -6429,7 +6428,7 @@ IonBuilder::createThisScriptedBaseline(MDefinition* callee) JSObject* templateObject = inspector->getTemplateObject(pc); if (!templateObject) return nullptr; - if (!templateObject->is() && !templateObject->is()) + if (!templateObject->is()) return nullptr; Shape* shape = target->lookupPure(compartment->runtime()->names().prototype); @@ -7718,8 +7717,6 @@ IonBuilder::jsop_initprop(PropertyName* name) if (templateObject->is()) { if (!templateObject->as().containsPure(name)) useSlowPath = true; - } else { - MOZ_ASSERT(templateObject->as().layout().lookup(name)); } } else { useSlowPath = true; @@ -8178,8 +8175,7 @@ IonBuilder::maybeMarkEmpty(MDefinition* ins) static bool ClassHasEffectlessLookup(const Class* clasp) { - return (clasp == &UnboxedPlainObject::class_) || - (clasp == &UnboxedArrayObject::class_) || + return (clasp == &UnboxedArrayObject::class_) || IsTypedObjectClass(clasp) || (clasp->isNative() && !clasp->getOpsLookupProperty()); } @@ -10970,11 +10966,8 @@ IonBuilder::getDefiniteSlot(TemporaryTypeSet* types, PropertyName* name, uint32_ } // Definite slots will always be fixed slots when they are in the - // allowable range for fixed slots, except for objects which were - // converted from unboxed objects and have a smaller allocation size. + // allowable range for fixed slots. size_t nfixed = NativeObject::MAX_FIXED_SLOTS; - if (ObjectGroup* group = key->group()->maybeOriginalUnboxedGroup()) - nfixed = gc::GetGCKindSlots(group->unboxedLayout().getAllocKind()); uint32_t propertySlot = property.maybeTypes()->definiteSlot(); if (slot == UINT32_MAX) { @@ -11031,8 +11024,6 @@ IonBuilder::getUnboxedOffset(TemporaryTypeSet* types, PropertyName* name, JSValu return UINT32_MAX; } - key->watchStateChangeForUnboxedConvertedToNative(constraints()); - if (offset == UINT32_MAX) { offset = property->offset; *punboxedType = property->type; @@ -11565,11 +11556,6 @@ IonBuilder::jsop_getprop(PropertyName* name) if (!getPropTryDefiniteSlot(&emitted, obj, name, barrier, types) || emitted) return emitted; - // Try to emit loads from unboxed objects. - trackOptimizationAttempt(TrackedStrategy::GetProp_Unboxed); - if (!getPropTryUnboxed(&emitted, obj, name, barrier, types) || emitted) - return emitted; - // Try to inline a common property getter, or make a call. trackOptimizationAttempt(TrackedStrategy::GetProp_CommonGetter); if (!getPropTryCommonGetter(&emitted, obj, name, types) || emitted) @@ -12085,34 +12071,6 @@ IonBuilder::loadUnboxedValue(MDefinition* elements, size_t elementsOffset, return load; } -bool -IonBuilder::getPropTryUnboxed(bool* emitted, MDefinition* obj, PropertyName* name, - BarrierKind barrier, TemporaryTypeSet* types) -{ - MOZ_ASSERT(*emitted == false); - - JSValueType unboxedType; - uint32_t offset = getUnboxedOffset(obj->resultTypeSet(), name, &unboxedType); - if (offset == UINT32_MAX) - return true; - - if (obj->type() != MIRType::Object) { - MGuardObject* guard = MGuardObject::New(alloc(), obj); - current->add(guard); - obj = guard; - } - - MInstruction* load = loadUnboxedProperty(obj, offset, unboxedType, barrier, types); - current->push(load); - - if (!pushTypeBarrier(load, types, barrier)) - return false; - - trackOptimizationSuccess(); - *emitted = true; - return true; -} - MDefinition* IonBuilder::addShapeGuardsForGetterSetter(MDefinition* obj, JSObject* holder, Shape* holderShape, const BaselineInspector::ReceiverVector& receivers, @@ -12356,45 +12314,6 @@ IonBuilder::getPropTryInlineAccess(bool* emitted, MDefinition* obj, PropertyName return true; } - if (receivers[0].shape) { - // Monomorphic load from an unboxed object expando. - spew("Inlining monomorphic unboxed expando GETPROP"); - - obj = addGroupGuard(obj, receivers[0].group, Bailout_ShapeGuard); - obj = addUnboxedExpandoGuard(obj, /* hasExpando = */ true, Bailout_ShapeGuard); - - MInstruction* expando = MLoadUnboxedExpando::New(alloc(), obj); - current->add(expando); - - expando = addShapeGuard(expando, receivers[0].shape, Bailout_ShapeGuard); - - Shape* shape = receivers[0].shape->searchLinear(NameToId(name)); - MOZ_ASSERT(shape); - - if (!loadSlot(expando, shape, rvalType, barrier, types)) - return false; - - trackOptimizationOutcome(TrackedOutcome::Monomorphic); - *emitted = true; - return true; - } - - // Monomorphic load from an unboxed object. - ObjectGroup* group = receivers[0].group; - if (obj->resultTypeSet() && !obj->resultTypeSet()->hasType(TypeSet::ObjectType(group))) - return true; - - obj = addGroupGuard(obj, group, Bailout_ShapeGuard); - - const UnboxedLayout::Property* property = group->unboxedLayout().lookup(name); - MInstruction* load = loadUnboxedProperty(obj, property->offset, property->type, barrier, types); - current->push(load); - - if (!pushTypeBarrier(load, types, barrier)) - return false; - - trackOptimizationOutcome(TrackedOutcome::Monomorphic); - *emitted = true; return true; } @@ -12669,13 +12588,6 @@ IonBuilder::jsop_setprop(PropertyName* name) bool barrier = PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current, &obj, name, &value, /* canModify = */ true); - if (!forceInlineCaches()) { - // Try to emit stores to unboxed objects. - trackOptimizationAttempt(TrackedStrategy::SetProp_Unboxed); - if (!setPropTryUnboxed(&emitted, obj, name, value, barrier, objTypes) || emitted) - return emitted; - } - // Add post barrier if needed. The instructions above manage any post // barriers they need directly. if (NeedsPostBarrier(value)) @@ -13040,40 +12952,6 @@ IonBuilder::storeUnboxedValue(MDefinition* obj, MDefinition* elements, int32_t e return store; } -bool -IonBuilder::setPropTryUnboxed(bool* emitted, MDefinition* obj, - PropertyName* name, MDefinition* value, - bool barrier, TemporaryTypeSet* objTypes) -{ - MOZ_ASSERT(*emitted == false); - - if (barrier) { - trackOptimizationOutcome(TrackedOutcome::NeedsTypeBarrier); - return true; - } - - JSValueType unboxedType; - uint32_t offset = getUnboxedOffset(obj->resultTypeSet(), name, &unboxedType); - if (offset == UINT32_MAX) - return true; - - if (obj->type() != MIRType::Object) { - MGuardObject* guard = MGuardObject::New(alloc(), obj); - current->add(guard); - obj = guard; - } - - MInstruction* store = storeUnboxedProperty(obj, offset, unboxedType, value); - - current->push(value); - - if (!resumeAfter(store)) - return false; - - *emitted = true; - return true; -} - bool IonBuilder::setPropTryInlineAccess(bool* emitted, MDefinition* obj, PropertyName* name, MDefinition* value, @@ -13112,46 +12990,6 @@ IonBuilder::setPropTryInlineAccess(bool* emitted, MDefinition* obj, return true; } - if (receivers[0].shape) { - // Monomorphic store to an unboxed object expando. - spew("Inlining monomorphic unboxed expando SETPROP"); - - obj = addGroupGuard(obj, receivers[0].group, Bailout_ShapeGuard); - obj = addUnboxedExpandoGuard(obj, /* hasExpando = */ true, Bailout_ShapeGuard); - - MInstruction* expando = MLoadUnboxedExpando::New(alloc(), obj); - current->add(expando); - - expando = addShapeGuard(expando, receivers[0].shape, Bailout_ShapeGuard); - - Shape* shape = receivers[0].shape->searchLinear(NameToId(name)); - MOZ_ASSERT(shape); - - bool needsBarrier = objTypes->propertyNeedsBarrier(constraints(), NameToId(name)); - if (!storeSlot(expando, shape, value, needsBarrier)) - return false; - - trackOptimizationOutcome(TrackedOutcome::Monomorphic); - *emitted = true; - return true; - } - - // Monomorphic store to an unboxed object. - spew("Inlining monomorphic unboxed SETPROP"); - - ObjectGroup* group = receivers[0].group; - if (!objTypes->hasType(TypeSet::ObjectType(group))) - return true; - - obj = addGroupGuard(obj, group, Bailout_ShapeGuard); - - const UnboxedLayout::Property* property = group->unboxedLayout().lookup(name); - storeUnboxedProperty(obj, property->offset, property->type, value); - - current->push(value); - - trackOptimizationOutcome(TrackedOutcome::Monomorphic); - *emitted = true; return true; } @@ -14178,19 +14016,6 @@ IonBuilder::addGroupGuard(MDefinition* obj, ObjectGroup* group, BailoutKind bail return guard; } -MInstruction* -IonBuilder::addUnboxedExpandoGuard(MDefinition* obj, bool hasExpando, BailoutKind bailoutKind) -{ - MGuardUnboxedExpando* guard = MGuardUnboxedExpando::New(alloc(), obj, hasExpando, bailoutKind); - current->add(guard); - - // If a shape guard failed in the past, don't optimize group guards. - if (failedShapeGuard_) - guard->setNotMovable(); - - return guard; -} - MInstruction* IonBuilder::addGuardReceiverPolymorphic(MDefinition* obj, const BaselineInspector::ReceiverVector& receivers) @@ -14200,15 +14025,6 @@ IonBuilder::addGuardReceiverPolymorphic(MDefinition* obj, // Monomorphic guard on a native object. return addShapeGuard(obj, receivers[0].shape, Bailout_ShapeGuard); } - - if (!receivers[0].shape) { - // Guard on an unboxed object that does not have an expando. - obj = addGroupGuard(obj, receivers[0].group, Bailout_ShapeGuard); - return addUnboxedExpandoGuard(obj, /* hasExpando = */ false, Bailout_ShapeGuard); - } - - // Monomorphic receiver guards are not yet supported when the receiver - // is an unboxed object with an expando. } MGuardReceiverPolymorphic* guard = MGuardReceiverPolymorphic::New(alloc(), obj); diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index 2880c7ea1..77528ad37 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -401,7 +401,6 @@ class IonBuilder MInstruction* addBoundsCheck(MDefinition* index, MDefinition* length); MInstruction* addShapeGuard(MDefinition* obj, Shape* const shape, BailoutKind bailoutKind); MInstruction* addGroupGuard(MDefinition* obj, ObjectGroup* group, BailoutKind bailoutKind); - MInstruction* addUnboxedExpandoGuard(MDefinition* obj, bool hasExpando, BailoutKind bailoutKind); MInstruction* addSharedTypedArrayGuard(MDefinition* obj); MInstruction* @@ -441,8 +440,6 @@ class IonBuilder BarrierKind barrier, TemporaryTypeSet* types); MOZ_MUST_USE bool getPropTryModuleNamespace(bool* emitted, MDefinition* obj, PropertyName* name, BarrierKind barrier, TemporaryTypeSet* types); - MOZ_MUST_USE bool getPropTryUnboxed(bool* emitted, MDefinition* obj, PropertyName* name, - BarrierKind barrier, TemporaryTypeSet* types); MOZ_MUST_USE bool getPropTryCommonGetter(bool* emitted, MDefinition* obj, PropertyName* name, TemporaryTypeSet* types); MOZ_MUST_USE bool getPropTryInlineAccess(bool* emitted, MDefinition* obj, PropertyName* name, @@ -475,9 +472,6 @@ class IonBuilder MOZ_MUST_USE bool setPropTryDefiniteSlot(bool* emitted, MDefinition* obj, PropertyName* name, MDefinition* value, bool barrier, TemporaryTypeSet* objTypes); - MOZ_MUST_USE bool setPropTryUnboxed(bool* emitted, MDefinition* obj, - PropertyName* name, MDefinition* value, - bool barrier, TemporaryTypeSet* objTypes); MOZ_MUST_USE bool setPropTryInlineAccess(bool* emitted, MDefinition* obj, PropertyName* name, MDefinition* value, bool barrier, TemporaryTypeSet* objTypes); diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 709de9987..aafa57c09 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -3251,14 +3251,6 @@ LIRGenerator::visitStoreUnboxedString(MStoreUnboxedString* ins) add(lir, ins); } -void -LIRGenerator::visitConvertUnboxedObjectToNative(MConvertUnboxedObjectToNative* ins) -{ - LInstruction* check = new(alloc()) LConvertUnboxedObjectToNative(useRegister(ins->object())); - add(check, ins); - assignSafepoint(check, ins); -} - void LIRGenerator::visitEffectiveAddress(MEffectiveAddress* ins) { @@ -3776,24 +3768,6 @@ LIRGenerator::visitGuardReceiverPolymorphic(MGuardReceiverPolymorphic* ins) redefine(ins, ins->object()); } -void -LIRGenerator::visitGuardUnboxedExpando(MGuardUnboxedExpando* ins) -{ - LGuardUnboxedExpando* guard = - new(alloc()) LGuardUnboxedExpando(useRegister(ins->object())); - assignSnapshot(guard, ins->bailoutKind()); - add(guard, ins); - redefine(ins, ins->object()); -} - -void -LIRGenerator::visitLoadUnboxedExpando(MLoadUnboxedExpando* ins) -{ - LLoadUnboxedExpando* lir = - new(alloc()) LLoadUnboxedExpando(useRegisterAtStart(ins->object())); - define(lir, ins); -} - void LIRGenerator::visitAssertRange(MAssertRange* ins) { diff --git a/js/src/jit/Lowering.h b/js/src/jit/Lowering.h index 9b4095aec..e36620bce 100644 --- a/js/src/jit/Lowering.h +++ b/js/src/jit/Lowering.h @@ -232,7 +232,6 @@ class LIRGenerator : public LIRGeneratorSpecific void visitFallibleStoreElement(MFallibleStoreElement* ins); void visitStoreUnboxedObjectOrNull(MStoreUnboxedObjectOrNull* ins); void visitStoreUnboxedString(MStoreUnboxedString* ins); - void visitConvertUnboxedObjectToNative(MConvertUnboxedObjectToNative* ins); void visitEffectiveAddress(MEffectiveAddress* ins); void visitArrayPopShift(MArrayPopShift* ins); void visitArrayPush(MArrayPush* ins); @@ -256,8 +255,6 @@ class LIRGenerator : public LIRGeneratorSpecific void visitGuardObject(MGuardObject* ins); void visitGuardString(MGuardString* ins); void visitGuardReceiverPolymorphic(MGuardReceiverPolymorphic* ins); - void visitGuardUnboxedExpando(MGuardUnboxedExpando* ins); - void visitLoadUnboxedExpando(MLoadUnboxedExpando* ins); void visitPolyInlineGuard(MPolyInlineGuard* ins); void visitAssertRange(MAssertRange* ins); void visitCallGetProperty(MCallGetProperty* ins); diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 287b87582..1f33b2174 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -4810,35 +4810,8 @@ MBeta::printOpcode(GenericPrinter& out) const bool MCreateThisWithTemplate::canRecoverOnBailout() const { - MOZ_ASSERT(templateObject()->is() || templateObject()->is()); - MOZ_ASSERT_IF(templateObject()->is(), - !templateObject()->as().denseElementsAreCopyOnWrite()); - return true; -} - -bool -OperandIndexMap::init(TempAllocator& alloc, JSObject* templateObject) -{ - const UnboxedLayout& layout = - templateObject->as().layoutDontCheckGeneration(); - - const UnboxedLayout::PropertyVector& properties = layout.properties(); - MOZ_ASSERT(properties.length() < 255); - - // Allocate an array of indexes, where the top of each field correspond to - // the index of the operand in the MObjectState instance. - if (!map.init(alloc, layout.size())) - return false; - - // Reset all indexes to 0, which is an error code. - for (size_t i = 0; i < map.length(); i++) - map[i] = 0; - - // Map the property offsets to the indexes of MObjectState operands. - uint8_t index = 1; - for (size_t i = 0; i < properties.length(); i++, index++) - map[properties[i].offset] = index; - + MOZ_ASSERT(templateObject()->is()); + MOZ_ASSERT(!templateObject()->as().denseElementsAreCopyOnWrite()); return true; } @@ -4858,17 +4831,11 @@ MObjectState::MObjectState(JSObject *templateObject, OperandIndexMap* operandInd setResultType(MIRType::Object); setRecoveredOnBailout(); - if (templateObject->is()) { - NativeObject* nativeObject = &templateObject->as(); - numSlots_ = nativeObject->slotSpan(); - numFixedSlots_ = nativeObject->numFixedSlots(); - } else { - const UnboxedLayout& layout = - templateObject->as().layoutDontCheckGeneration(); - // Same as UnboxedLayout::makeNativeGroup - numSlots_ = layout.properties().length(); - numFixedSlots_ = gc::GetGCKindSlots(layout.getAllocKind()); - } + MOZ_ASSERT(templateObject->is()); + + NativeObject* nativeObject = &templateObject->as(); + numSlots_ = nativeObject->slotSpan(); + numFixedSlots_ = nativeObject->numFixedSlots(); operandIndex_ = operandIndex; } @@ -4905,39 +4872,21 @@ MObjectState::initFromTemplateObject(TempAllocator& alloc, MDefinition* undefine // the template object. This is needed to account values which are baked in // the template objects and not visible in IonMonkey, such as the // uninitialized-lexical magic value of call objects. - if (templateObject->is()) { - UnboxedPlainObject& unboxedObject = templateObject->as(); - const UnboxedLayout& layout = unboxedObject.layoutDontCheckGeneration(); - const UnboxedLayout::PropertyVector& properties = layout.properties(); - - for (size_t i = 0; i < properties.length(); i++) { - Value val = unboxedObject.getValue(properties[i], /* maybeUninitialized = */ true); - MDefinition *def = undefinedVal; - if (!val.isUndefined()) { - MConstant* ins = val.isObject() ? - MConstant::NewConstraintlessObject(alloc, &val.toObject()) : - MConstant::New(alloc, val); - block()->insertBefore(this, ins); - def = ins; - } - initSlot(i, def); - } - } else { - NativeObject& nativeObject = templateObject->as(); - MOZ_ASSERT(nativeObject.slotSpan() == numSlots()); - - for (size_t i = 0; i < numSlots(); i++) { - Value val = nativeObject.getSlot(i); - MDefinition *def = undefinedVal; - if (!val.isUndefined()) { - MConstant* ins = val.isObject() ? - MConstant::NewConstraintlessObject(alloc, &val.toObject()) : - MConstant::New(alloc, val); - block()->insertBefore(this, ins); - def = ins; - } - initSlot(i, def); + NativeObject& nativeObject = templateObject->as(); + MOZ_ASSERT(nativeObject.slotSpan() == numSlots()); + + MOZ_ASSERT(templateObject->is()); + for (size_t i = 0; i < numSlots(); i++) { + Value val = nativeObject.getSlot(i); + MDefinition *def = undefinedVal; + if (!val.isUndefined()) { + MConstant* ins = val.isObject() ? + MConstant::NewConstraintlessObject(alloc, &val.toObject()) : + MConstant::New(alloc, val); + block()->insertBefore(this, ins); + def = ins; } + initSlot(i, def); } return true; } @@ -4948,14 +4897,7 @@ MObjectState::New(TempAllocator& alloc, MDefinition* obj) JSObject* templateObject = templateObjectOf(obj); MOZ_ASSERT(templateObject, "Unexpected object creation."); - OperandIndexMap* operandIndex = nullptr; - if (templateObject->is()) { - operandIndex = new(alloc) OperandIndexMap; - if (!operandIndex || !operandIndex->init(alloc, templateObject)) - return nullptr; - } - - MObjectState* res = new(alloc) MObjectState(templateObject, operandIndex); + MObjectState* res = new(alloc) MObjectState(templateObject, nullptr); if (!res || !res->init(alloc, obj)) return nullptr; return res; @@ -5862,35 +5804,6 @@ MGetFirstDollarIndex::foldsTo(TempAllocator& alloc) return MConstant::New(alloc, Int32Value(index)); } -MConvertUnboxedObjectToNative* -MConvertUnboxedObjectToNative::New(TempAllocator& alloc, MDefinition* obj, ObjectGroup* group) -{ - MConvertUnboxedObjectToNative* res = new(alloc) MConvertUnboxedObjectToNative(obj, group); - - ObjectGroup* nativeGroup = group->unboxedLayout().nativeGroup(); - - // Make a new type set for the result of this instruction which replaces - // the input group with the native group we will convert it to. - TemporaryTypeSet* types = obj->resultTypeSet(); - if (types && !types->unknownObject()) { - TemporaryTypeSet* newTypes = types->cloneWithoutObjects(alloc.lifoAlloc()); - if (newTypes) { - for (size_t i = 0; i < types->getObjectCount(); i++) { - TypeSet::ObjectKey* key = types->getObject(i); - if (!key) - continue; - if (key->unknownProperties() || !key->isGroup() || key->group() != group) - newTypes->addType(TypeSet::ObjectType(key), alloc.lifoAlloc()); - else - newTypes->addType(TypeSet::ObjectType(nativeGroup), alloc.lifoAlloc()); - } - res->setResultTypeSet(newTypes); - } - } - - return res; -} - bool jit::ElementAccessIsDenseNative(CompilerConstraintList* constraints, MDefinition* obj, MDefinition* id) @@ -5945,8 +5858,6 @@ jit::UnboxedArrayElementType(CompilerConstraintList* constraints, MDefinition* o elementType = layout.elementType(); else return JSVAL_TYPE_MAGIC; - - key->watchStateChangeForUnboxedConvertedToNative(constraints); } return elementType; @@ -6579,23 +6490,6 @@ jit::PropertyWriteNeedsTypeBarrier(TempAllocator& alloc, CompilerConstraintList* } } - // Perform additional filtering to make sure that any unboxed property - // being written can accommodate the value. - for (size_t i = 0; i < types->getObjectCount(); i++) { - TypeSet::ObjectKey* key = types->getObject(i); - if (key && key->isGroup() && key->group()->maybeUnboxedLayout()) { - const UnboxedLayout& layout = key->group()->unboxedLayout(); - if (name) { - const UnboxedLayout::Property* property = layout.lookup(name); - if (property && !CanStoreUnboxedType(alloc, property->type, *pvalue)) - return true; - } else { - if (layout.isArray() && !CanStoreUnboxedType(alloc, layout.elementType(), *pvalue)) - return true; - } - } - } - if (success) return false; @@ -6626,17 +6520,6 @@ jit::PropertyWriteNeedsTypeBarrier(TempAllocator& alloc, CompilerConstraintList* MOZ_ASSERT(excluded); - // If the excluded object is a group with an unboxed layout, make sure it - // does not have a corresponding native group. Objects with the native - // group might appear even though they are not in the type set. - if (excluded->isGroup()) { - if (UnboxedLayout* layout = excluded->group()->maybeUnboxedLayout()) { - if (layout->nativeGroup()) - return true; - excluded->watchStateChangeForUnboxedConvertedToNative(constraints); - } - } - *pobj = AddGroupGuard(alloc, current, *pobj, excluded, /* bailOnEquality = */ true); return false; } diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index fb0f22fc3..3e0421789 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -30,7 +30,6 @@ #include "vm/EnvironmentObject.h" #include "vm/SharedMem.h" #include "vm/TypedArrayCommon.h" -#include "vm/UnboxedObject.h" // Undo windows.h damage on Win64 #undef MemoryBarrier @@ -9742,59 +9741,6 @@ class MStoreUnboxedString ALLOW_CLONE(MStoreUnboxedString) }; -// Passes through an object, after ensuring it is converted from an unboxed -// object to a native representation. -class MConvertUnboxedObjectToNative - : public MUnaryInstruction, - public SingleObjectPolicy::Data -{ - CompilerObjectGroup group_; - - explicit MConvertUnboxedObjectToNative(MDefinition* obj, ObjectGroup* group) - : MUnaryInstruction(obj), - group_(group) - { - setGuard(); - setMovable(); - setResultType(MIRType::Object); - } - - public: - INSTRUCTION_HEADER(ConvertUnboxedObjectToNative) - NAMED_OPERANDS((0, object)) - - static MConvertUnboxedObjectToNative* New(TempAllocator& alloc, MDefinition* obj, - ObjectGroup* group); - - ObjectGroup* group() const { - return group_; - } - bool congruentTo(const MDefinition* ins) const override { - if (!congruentIfOperandsEqual(ins)) - return false; - return ins->toConvertUnboxedObjectToNative()->group() == group(); - } - AliasSet getAliasSet() const override { - // This instruction can read and write to all parts of the object, but - // is marked as non-effectful so it can be consolidated by LICM and GVN - // and avoid inhibiting other optimizations. - // - // This is valid to do because when unboxed objects might have a native - // group they can be converted to, we do not optimize accesses to the - // unboxed objects and do not guard on their group or shape (other than - // in this opcode). - // - // Later accesses can assume the object has a native representation - // and optimize accordingly. Those accesses cannot be reordered before - // this instruction, however. This is prevented by chaining this - // instruction with the object itself, in the same way as MBoundsCheck. - return AliasSet::None(); - } - bool appendRoots(MRootList& roots) const override { - return roots.append(group_); - } -}; - // Array.prototype.pop or Array.prototype.shift on a dense array. class MArrayPopShift : public MUnaryInstruction, @@ -11174,11 +11120,6 @@ class MGuardShape setMovable(); setResultType(MIRType::Object); setResultTypeSet(obj->resultTypeSet()); - - // Disallow guarding on unboxed object shapes. The group is better to - // guard on, and guarding on the shape can interact badly with - // MConvertUnboxedObjectToNative. - MOZ_ASSERT(shape->getObjectClass() != &UnboxedPlainObject::class_); } public: @@ -11273,11 +11214,6 @@ class MGuardObjectGroup setGuard(); setMovable(); setResultType(MIRType::Object); - - // Unboxed groups which might be converted to natives can't be guarded - // on, due to MConvertUnboxedObjectToNative. - MOZ_ASSERT_IF(group->maybeUnboxedLayoutDontCheckGeneration(), - !group->unboxedLayoutDontCheckGeneration().nativeGroup()); } public: @@ -11386,73 +11322,6 @@ class MGuardClass ALLOW_CLONE(MGuardClass) }; -// Guard on the presence or absence of an unboxed object's expando. -class MGuardUnboxedExpando - : public MUnaryInstruction, - public SingleObjectPolicy::Data -{ - bool requireExpando_; - BailoutKind bailoutKind_; - - MGuardUnboxedExpando(MDefinition* obj, bool requireExpando, BailoutKind bailoutKind) - : MUnaryInstruction(obj), - requireExpando_(requireExpando), - bailoutKind_(bailoutKind) - { - setGuard(); - setMovable(); - setResultType(MIRType::Object); - } - - public: - INSTRUCTION_HEADER(GuardUnboxedExpando) - TRIVIAL_NEW_WRAPPERS - NAMED_OPERANDS((0, object)) - - bool requireExpando() const { - return requireExpando_; - } - BailoutKind bailoutKind() const { - return bailoutKind_; - } - bool congruentTo(const MDefinition* ins) const override { - if (!congruentIfOperandsEqual(ins)) - return false; - if (requireExpando() != ins->toGuardUnboxedExpando()->requireExpando()) - return false; - return true; - } - AliasSet getAliasSet() const override { - return AliasSet::Load(AliasSet::ObjectFields); - } -}; - -// Load an unboxed plain object's expando. -class MLoadUnboxedExpando - : public MUnaryInstruction, - public SingleObjectPolicy::Data -{ - private: - explicit MLoadUnboxedExpando(MDefinition* object) - : MUnaryInstruction(object) - { - setResultType(MIRType::Object); - setMovable(); - } - - public: - INSTRUCTION_HEADER(LoadUnboxedExpando) - TRIVIAL_NEW_WRAPPERS - NAMED_OPERANDS((0, object)) - - bool congruentTo(const MDefinition* ins) const override { - return congruentIfOperandsEqual(ins); - } - AliasSet getAliasSet() const override { - return AliasSet::Load(AliasSet::ObjectFields); - } -}; - // Load from vp[slot] (slots that are not inline in an object). class MLoadSlot : public MUnaryInstruction, diff --git a/js/src/jit/MOpcodes.h b/js/src/jit/MOpcodes.h index fddc1e637..b80d1baf9 100644 --- a/js/src/jit/MOpcodes.h +++ b/js/src/jit/MOpcodes.h @@ -187,8 +187,6 @@ namespace jit { _(GuardObjectGroup) \ _(GuardObjectIdentity) \ _(GuardClass) \ - _(GuardUnboxedExpando) \ - _(LoadUnboxedExpando) \ _(ArrayLength) \ _(SetArrayLength) \ _(GetNextEntryForIterator) \ @@ -219,7 +217,6 @@ namespace jit { _(StoreUnboxedScalar) \ _(StoreUnboxedObjectOrNull) \ _(StoreUnboxedString) \ - _(ConvertUnboxedObjectToNative) \ _(ArrayPopShift) \ _(ArrayPush) \ _(ArraySlice) \ diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h index f4adcc63c..f386d5256 100644 --- a/js/src/jit/shared/LIR-shared.h +++ b/js/src/jit/shared/LIR-shared.h @@ -5891,22 +5891,6 @@ class LStoreUnboxedPointer : public LInstructionHelper<0, 3, 0> } }; -// If necessary, convert an unboxed object in a particular group to its native -// representation. -class LConvertUnboxedObjectToNative : public LInstructionHelper<0, 1, 0> -{ - public: - LIR_HEADER(ConvertUnboxedObjectToNative) - - explicit LConvertUnboxedObjectToNative(const LAllocation& object) { - setOperand(0, object); - } - - MConvertUnboxedObjectToNative* mir() { - return mir_->toConvertUnboxedObjectToNative(); - } -}; - class LArrayPopShiftV : public LInstructionHelper { public: @@ -7429,38 +7413,6 @@ class LGuardReceiverPolymorphic : public LInstructionHelper<0, 1, 1> } }; -class LGuardUnboxedExpando : public LInstructionHelper<0, 1, 0> -{ - public: - LIR_HEADER(GuardUnboxedExpando) - - explicit LGuardUnboxedExpando(const LAllocation& in) { - setOperand(0, in); - } - const LAllocation* object() { - return getOperand(0); - } - const MGuardUnboxedExpando* mir() const { - return mir_->toGuardUnboxedExpando(); - } -}; - -class LLoadUnboxedExpando : public LInstructionHelper<1, 1, 0> -{ - public: - LIR_HEADER(LoadUnboxedExpando) - - explicit LLoadUnboxedExpando(const LAllocation& in) { - setOperand(0, in); - } - const LAllocation* object() { - return getOperand(0); - } - const MLoadUnboxedExpando* mir() const { - return mir_->toLoadUnboxedExpando(); - } -}; - // Guard that a value is in a TypeSet. class LTypeBarrierV : public LInstructionHelper<0, BOX_PIECES, 1> { diff --git a/js/src/jit/shared/LOpcodes-shared.h b/js/src/jit/shared/LOpcodes-shared.h index fe2ab5ea3..6912e8904 100644 --- a/js/src/jit/shared/LOpcodes-shared.h +++ b/js/src/jit/shared/LOpcodes-shared.h @@ -258,8 +258,6 @@ _(GuardObjectGroup) \ _(GuardObjectIdentity) \ _(GuardClass) \ - _(GuardUnboxedExpando) \ - _(LoadUnboxedExpando) \ _(TypeBarrierV) \ _(TypeBarrierO) \ _(MonitorTypes) \ @@ -287,7 +285,6 @@ _(StoreElementT) \ _(StoreUnboxedScalar) \ _(StoreUnboxedPointer) \ - _(ConvertUnboxedObjectToNative) \ _(ArrayPopShiftV) \ _(ArrayPopShiftT) \ _(ArrayPushV) \ diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index fe89fac9c..9e0342382 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -1995,17 +1995,6 @@ TypeSet::ObjectKey::watchStateChangeForTypedArrayData(CompilerConstraintList* co ConstraintDataFreezeObjectForTypedArrayData(tarray))); } -void -TypeSet::ObjectKey::watchStateChangeForUnboxedConvertedToNative(CompilerConstraintList* constraints) -{ - HeapTypeSetKey objectProperty = property(JSID_EMPTY); - LifoAlloc* alloc = constraints->alloc(); - - typedef CompilerConstraintInstance T; - constraints->add(alloc->new_(alloc, objectProperty, - ConstraintDataFreezeObjectForUnboxedConvertedToNative())); -} - static void ObjectStateChange(ExclusiveContext* cxArg, ObjectGroup* group, bool markingUnknown) { diff --git a/js/src/vm/TypeInference.h b/js/src/vm/TypeInference.h index 0f1cd4936..04fed448c 100644 --- a/js/src/vm/TypeInference.h +++ b/js/src/vm/TypeInference.h @@ -262,7 +262,6 @@ class TypeSet bool hasStableClassAndProto(CompilerConstraintList* constraints); void watchStateChangeForInlinedCall(CompilerConstraintList* constraints); void watchStateChangeForTypedArrayData(CompilerConstraintList* constraints); - void watchStateChangeForUnboxedConvertedToNative(CompilerConstraintList* constraints); HeapTypeSetKey property(jsid id); void ensureTrackedProperty(JSContext* cx, jsid id); -- cgit v1.2.3 From 201d8ee48926569fee200fbc9b4d506554869b5d Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 16 May 2019 21:34:42 +0000 Subject: Remove Unboxed Objects from vm/ - Part 2 --- js/src/jsobj.cpp | 75 ++++++++++----------------------------------- js/src/vm/ReceiverGuard.cpp | 1 - js/src/vm/ReceiverGuard.h | 5 --- 3 files changed, 17 insertions(+), 64 deletions(-) (limited to 'js/src') diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 7852b3365..f22ecb445 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -870,9 +870,6 @@ static inline JSObject* CreateThisForFunctionWithGroup(JSContext* cx, HandleObjectGroup group, NewObjectKind newKind) { - if (group->maybeUnboxedLayout() && newKind != SingletonObject) - return UnboxedPlainObject::create(cx, group, newKind); - if (TypeNewScript* newScript = group->newScript()) { if (newScript->analyzed()) { // The definite properties analysis has been performed for this @@ -1167,46 +1164,27 @@ static bool GetScriptPlainObjectProperties(JSContext* cx, HandleObject obj, MutableHandle properties) { - if (obj->is()) { - PlainObject* nobj = &obj->as(); - - if (!properties.appendN(IdValuePair(), nobj->slotSpan())) - return false; + MOZ_ASSERT(obj->is()); + PlainObject* nobj = &obj->as(); - for (Shape::Range r(nobj->lastProperty()); !r.empty(); r.popFront()) { - Shape& shape = r.front(); - MOZ_ASSERT(shape.isDataDescriptor()); - uint32_t slot = shape.slot(); - properties[slot].get().id = shape.propid(); - properties[slot].get().value = nobj->getSlot(slot); - } - - for (size_t i = 0; i < nobj->getDenseInitializedLength(); i++) { - Value v = nobj->getDenseElement(i); - if (!v.isMagic(JS_ELEMENTS_HOLE) && !properties.append(IdValuePair(INT_TO_JSID(i), v))) - return false; - } + if (!properties.appendN(IdValuePair(), nobj->slotSpan())) + return false; - return true; + for (Shape::Range r(nobj->lastProperty()); !r.empty(); r.popFront()) { + Shape& shape = r.front(); + MOZ_ASSERT(shape.isDataDescriptor()); + uint32_t slot = shape.slot(); + properties[slot].get().id = shape.propid(); + properties[slot].get().value = nobj->getSlot(slot); } - if (obj->is()) { - UnboxedPlainObject* nobj = &obj->as(); - - const UnboxedLayout& layout = nobj->layout(); - if (!properties.appendN(IdValuePair(), layout.properties().length())) + for (size_t i = 0; i < nobj->getDenseInitializedLength(); i++) { + Value v = nobj->getDenseElement(i); + if (!v.isMagic(JS_ELEMENTS_HOLE) && !properties.append(IdValuePair(INT_TO_JSID(i), v))) return false; - - for (size_t i = 0; i < layout.properties().length(); i++) { - const UnboxedLayout::Property& property = layout.properties()[i]; - properties[i].get().id = NameToId(property.name); - properties[i].get().value = nobj->getValue(property); - } - - return true; } - MOZ_CRASH("Bad object kind"); + return true; } static bool @@ -1228,8 +1206,9 @@ js::DeepCloneObjectLiteral(JSContext* cx, HandleObject obj, NewObjectKind newKin /* NB: Keep this in sync with XDRObjectLiteral. */ MOZ_ASSERT_IF(obj->isSingleton(), cx->compartment()->behaviors().getSingletonsAsTemplates()); - MOZ_ASSERT(obj->is() || obj->is() || - obj->is() || obj->is()); + MOZ_ASSERT(obj->is() || + obj->is() || + obj->is()); MOZ_ASSERT(newKind != SingletonObject); if (obj->is() || obj->is()) { @@ -1348,7 +1327,6 @@ js::XDRObjectLiteral(XDRState* xdr, MutableHandleObject obj) { if (mode == XDR_ENCODE) { MOZ_ASSERT(obj->is() || - obj->is() || obj->is() || obj->is()); isArray = (obj->is() || obj->is()) ? 1 : 0; @@ -2334,11 +2312,6 @@ js::LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Shape** // us the resolve hook won't define a property with this id. if (ClassMayResolveId(cx->names(), obj->getClass(), id, obj)) return false; - } else if (obj->is()) { - if (obj->as().containsUnboxedOrExpandoProperty(cx, id)) { - MarkNonNativePropertyFound(propp); - return true; - } } else if (obj->is()) { if (obj->as().containsProperty(cx, id)) { MarkNonNativePropertyFound(propp); @@ -2591,11 +2564,6 @@ js::SetPrototype(JSContext* cx, HandleObject obj, HandleObject proto, JS::Object break; } - // Convert unboxed objects to their native representations before changing - // their prototype/group, as they depend on the group for their layout. - if (!MaybeConvertUnboxedObjectToNative(cx, obj)) - return false; - Rooted taggedProto(cx, TaggedProto(proto)); if (!SetClassAndProto(cx, obj, obj->getClass(), taggedProto)) return false; @@ -2619,9 +2587,6 @@ js::PreventExtensions(JSContext* cx, HandleObject obj, ObjectOpResult& result, I if (!obj->nonProxyIsExtensible()) return result.succeed(); - if (!MaybeConvertUnboxedObjectToNative(cx, obj)) - return false; - // Force lazy properties to be resolved. AutoIdVector props(cx); if (!js::GetPropertyKeys(cx, obj, JSITER_HIDDEN | JSITER_OWNONLY, &props)) @@ -3715,12 +3680,6 @@ JSObject::allocKindForTenure(const js::Nursery& nursery) const if (IsProxy(this)) return as().allocKindForTenure(); - // Unboxed plain objects are sized according to the data they store. - if (is()) { - size_t nbytes = as().layoutDontCheckGeneration().size(); - return GetGCObjectKindForBytes(UnboxedPlainObject::offsetOfData() + nbytes); - } - // Unboxed arrays use inline data if their size is small enough. if (is()) { const UnboxedArrayObject* nobj = &as(); diff --git a/js/src/vm/ReceiverGuard.cpp b/js/src/vm/ReceiverGuard.cpp index 97df908c3..11c2d0727 100644 --- a/js/src/vm/ReceiverGuard.cpp +++ b/js/src/vm/ReceiverGuard.cpp @@ -7,7 +7,6 @@ #include "vm/ReceiverGuard.h" #include "builtin/TypedObject.h" -#include "vm/UnboxedObject.h" #include "jsobjinlines.h" using namespace js; diff --git a/js/src/vm/ReceiverGuard.h b/js/src/vm/ReceiverGuard.h index 459cc0012..c14f0d83b 100644 --- a/js/src/vm/ReceiverGuard.h +++ b/js/src/vm/ReceiverGuard.h @@ -28,11 +28,6 @@ namespace js { // TypedObject: The structure of a typed object is determined by its group. // All typed objects with the same group have the same class, prototype, and // own properties. -// -// UnboxedPlainObject: The structure of an unboxed plain object is determined -// by its group and its expando object's shape, if there is one. All unboxed -// plain objects with the same group and expando shape have the same -// properties except those stored in the expando's dense elements. class HeapReceiverGuard; class RootedReceiverGuard; -- cgit v1.2.3 From 354c6dceecdad5e58e2763e937ad5053e8b7d897 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 17 May 2019 01:04:30 +0000 Subject: Implement String.prototype.trimStart and trimEnd. This renames our internal function names because *Left and *Right might be deprecated and have to be removed later, making that trivial. Resolves #1089 --- js/src/builtin/String.js | 12 ++++++------ js/src/jsstr.cpp | 16 ++++++++++------ js/src/jsstr.h | 4 ++-- js/src/vm/SelfHosting.cpp | 6 ++++-- 4 files changed, 22 insertions(+), 16 deletions(-) (limited to 'js/src') diff --git a/js/src/builtin/String.js b/js/src/builtin/String.js index e5b2ad552..f830b1aa2 100644 --- a/js/src/builtin/String.js +++ b/js/src/builtin/String.js @@ -828,16 +828,16 @@ function String_static_trim(string) { return callFunction(std_String_trim, string); } -function String_static_trimLeft(string) { +function String_static_trimStart(string) { if (arguments.length < 1) - ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.trimLeft'); - return callFunction(std_String_trimLeft, string); + ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.trimStart'); + return callFunction(std_String_trimStart, string); } -function String_static_trimRight(string) { +function String_static_trimEnd(string) { if (arguments.length < 1) - ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.trimRight'); - return callFunction(std_String_trimRight, string); + ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.trimEnd'); + return callFunction(std_String_trimEnd, string); } function String_static_toLocaleLowerCase(string) { diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index e3b5708ca..7765b1197 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -1970,14 +1970,14 @@ js::str_trim(JSContext* cx, unsigned argc, Value* vp) } bool -js::str_trimLeft(JSContext* cx, unsigned argc, Value* vp) +js::str_trimStart(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); return TrimString(cx, args, true, false); } bool -js::str_trimRight(JSContext* cx, unsigned argc, Value* vp) +js::str_trimEnd(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); return TrimString(cx, args, false, true); @@ -2568,8 +2568,10 @@ static const JSFunctionSpec string_methods[] = { JS_FN("startsWith", str_startsWith, 1,0), JS_FN("endsWith", str_endsWith, 1,0), JS_FN("trim", str_trim, 0,0), - JS_FN("trimLeft", str_trimLeft, 0,0), - JS_FN("trimRight", str_trimRight, 0,0), + JS_FN("trimLeft", str_trimStart, 0,0), + JS_FN("trimStart", str_trimStart, 0,0), + JS_FN("trimRight", str_trimEnd, 0,0), + JS_FN("trimEnd", str_trimEnd, 0,0), JS_FN("toLocaleLowerCase", str_toLocaleLowerCase, 0,0), JS_FN("toLocaleUpperCase", str_toLocaleUpperCase, 0,0), JS_SELF_HOSTED_FN("localeCompare", "String_localeCompare", 1,0), @@ -2881,8 +2883,10 @@ static const JSFunctionSpec string_static_methods[] = { JS_SELF_HOSTED_FN("startsWith", "String_static_startsWith", 2,0), JS_SELF_HOSTED_FN("endsWith", "String_static_endsWith", 2,0), JS_SELF_HOSTED_FN("trim", "String_static_trim", 1,0), - JS_SELF_HOSTED_FN("trimLeft", "String_static_trimLeft", 1,0), - JS_SELF_HOSTED_FN("trimRight", "String_static_trimRight", 1,0), + JS_SELF_HOSTED_FN("trimLeft", "String_static_trimStart", 1,0), + JS_SELF_HOSTED_FN("trimStart", "String_static_trimStart", 1,0), + JS_SELF_HOSTED_FN("trimRight", "String_static_trimEnd", 1,0), + JS_SELF_HOSTED_FN("trimEnd", "String_static_trimEnd", 1,0), JS_SELF_HOSTED_FN("toLocaleLowerCase","String_static_toLocaleLowerCase",1,0), JS_SELF_HOSTED_FN("toLocaleUpperCase","String_static_toLocaleUpperCase",1,0), JS_SELF_HOSTED_FN("normalize", "String_static_normalize", 1,0), diff --git a/js/src/jsstr.h b/js/src/jsstr.h index 118118839..38fbfa85e 100644 --- a/js/src/jsstr.h +++ b/js/src/jsstr.h @@ -367,10 +367,10 @@ extern bool str_trim(JSContext* cx, unsigned argc, Value* vp); extern bool -str_trimLeft(JSContext* cx, unsigned argc, Value* vp); +str_trimStart(JSContext* cx, unsigned argc, Value* vp); extern bool -str_trimRight(JSContext* cx, unsigned argc, Value* vp); +str_trimEnd(JSContext* cx, unsigned argc, Value* vp); extern bool str_toLocaleLowerCase(JSContext* cx, unsigned argc, Value* vp); diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index 328a960b6..ccd4cc8d7 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -2200,8 +2200,10 @@ static const JSFunctionSpec intrinsic_functions[] = { JS_INLINABLE_FN("std_String_charAt", str_charAt, 1,0, StringCharAt), JS_FN("std_String_endsWith", str_endsWith, 1,0), JS_FN("std_String_trim", str_trim, 0,0), - JS_FN("std_String_trimLeft", str_trimLeft, 0,0), - JS_FN("std_String_trimRight", str_trimRight, 0,0), + JS_FN("std_String_trimLeft", str_trimStart, 0,0), + JS_FN("std_String_trimStart", str_trimStart, 0,0), + JS_FN("std_String_trimRight", str_trimEnd, 0,0), + JS_FN("std_String_trimEnd", str_trimEnd, 0,0), JS_FN("std_String_toLocaleLowerCase", str_toLocaleLowerCase, 0,0), JS_FN("std_String_toLocaleUpperCase", str_toLocaleUpperCase, 0,0), JS_FN("std_String_normalize", str_normalize, 0,0), -- cgit v1.2.3 From 162e22a7de3026b676156a2aad29909fe3795dba Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sun, 19 May 2019 23:11:17 +0200 Subject: Implement array.flat and array.flatMap Self-hosted implementation that adds both functions and adds them to @@unscopables as specced in ES2019. Resolves #1095 --- js/src/builtin/Array.js | 108 +++++++++++++++++++++++++++++++ js/src/jsarray.cpp | 7 ++ js/src/tests/ecma_6/Array/unscopables.js | 2 + js/src/vm/CommonPropertyNames.h | 2 + 4 files changed, 119 insertions(+) (limited to 'js/src') diff --git a/js/src/builtin/Array.js b/js/src/builtin/Array.js index 30e6fb35f..05fc41bc1 100644 --- a/js/src/builtin/Array.js +++ b/js/src/builtin/Array.js @@ -1073,6 +1073,114 @@ function ArrayConcat(arg1) { return A; } +// https://tc39.github.io/proposal-flatMap/ +// January 4, 2019 +function ArrayFlatMap(mapperFunction/*, thisArg*/) { + // Step 1. + var O = ToObject(this); + + // Step 2. + var sourceLen = ToLength(O.length); + + // Step 3. + if (!IsCallable(mapperFunction)) + ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, mapperFunction)); + + // Step 4. + var T = arguments.length > 1 ? arguments[1] : undefined; + + // Step 5. + var A = ArraySpeciesCreate(O, 0); + + // Step 6. + FlattenIntoArray(A, O, sourceLen, 0, 1, mapperFunction, T); + + // Step 7. + return A; +} + +// https://tc39.github.io/proposal-flatMap/ +// January 4, 2019 +function ArrayFlat(/* depth */) { + // Step 1. + var O = ToObject(this); + + // Step 2. + var sourceLen = ToLength(O.length); + + // Step 3. + var depthNum = 1; + + // Step 4. + if (arguments.length > 0 && arguments[0] !== undefined) + depthNum = ToInteger(arguments[0]); + + // Step 5. + var A = ArraySpeciesCreate(O, 0); + + // Step 6. + FlattenIntoArray(A, O, sourceLen, 0, depthNum); + + // Step 7. + return A; +} + +// https://tc39.github.io/proposal-flatMap/ +// January 4, 2019 +function FlattenIntoArray(target, source, sourceLen, start, depth, mapperFunction, thisArg) { + // Step 1. + var targetIndex = start; + + // Steps 2-3. + for (var sourceIndex = 0; sourceIndex < sourceLen; sourceIndex++) { + // Steps 3.a-c. + if (sourceIndex in source) { + // Step 3.c.i. + var element = source[sourceIndex]; + + if (mapperFunction) { + // Step 3.c.ii.1. + assert(arguments.length === 7, "thisArg is present"); + + // Step 3.c.ii.2. + element = callContentFunction(mapperFunction, thisArg, element, sourceIndex, source); + } + + // Step 3.c.iii. + var shouldFlatten = false; + + // Step 3.c.iv. + if (depth > 0) { + // Step 3.c.iv.1. + shouldFlatten = IsArray(element); + } + + // Step 3.c.v. + if (shouldFlatten) { + // Step 3.c.v.1. + var elementLen = ToLength(element.length); + + // Step 3.c.v.2. + // Recursive call to walk the depth. + targetIndex = FlattenIntoArray(target, element, elementLen, targetIndex, depth - 1); + } else { + // Step 3.c.vi.1. + if (targetIndex >= MAX_NUMERIC_INDEX) + ThrowTypeError(JSMSG_TOO_LONG_ARRAY); + + // Step 3.c.vi.2. + _DefineDataProperty(target, targetIndex, element); + + // Step 3.c.vi.3. + targetIndex++; + } + } + } + + // Step 4. + return targetIndex; +} + function ArrayStaticConcat(arr, arg1) { if (arguments.length < 1) ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'Array.concat'); diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 7a67c0095..3b4c957dc 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -3169,6 +3169,11 @@ static const JSFunctionSpec array_methods[] = { /* ES7 additions */ JS_SELF_HOSTED_FN("includes", "ArrayIncludes", 2,0), + + /* ES2019 additions */ + JS_SELF_HOSTED_FN("flat", "ArrayFlat", 0,0), + JS_SELF_HOSTED_FN("flatMap", "ArrayFlatMap", 1,0), + JS_FS_END }; @@ -3333,6 +3338,8 @@ array_proto_finish(JSContext* cx, JS::HandleObject ctor, JS::HandleObject proto) !DefineProperty(cx, unscopables, cx->names().fill, value) || !DefineProperty(cx, unscopables, cx->names().find, value) || !DefineProperty(cx, unscopables, cx->names().findIndex, value) || + !DefineProperty(cx, unscopables, cx->names().flat, value) || + !DefineProperty(cx, unscopables, cx->names().flatMap, value) || !DefineProperty(cx, unscopables, cx->names().includes, value) || !DefineProperty(cx, unscopables, cx->names().keys, value) || !DefineProperty(cx, unscopables, cx->names().values, value)) diff --git a/js/src/tests/ecma_6/Array/unscopables.js b/js/src/tests/ecma_6/Array/unscopables.js index 6685309a0..56b3aa520 100644 --- a/js/src/tests/ecma_6/Array/unscopables.js +++ b/js/src/tests/ecma_6/Array/unscopables.js @@ -26,6 +26,8 @@ assertDeepEq(keys, [ "fill", "find", "findIndex", + "flat", + "flatMap", "includes", "keys", "values" diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h index e971dc844..8a36df083 100644 --- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -115,6 +115,8 @@ macro(firstDayOfWeek, firstDayOfWeek, "firstDayOfWeek") \ macro(fix, fix, "fix") \ macro(flags, flags, "flags") \ + macro(flat, flat, "flat") \ + macro(flatMap, flatMap, "flatMap") \ macro(float32, float32, "float32") \ macro(Float32x4, Float32x4, "Float32x4") \ macro(float64, float64, "float64") \ -- cgit v1.2.3 From 41731a7f31a1724e74b32eb7be87de2719f977c3 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Mon, 20 May 2019 02:50:01 +0200 Subject: =?UTF-8?q?Implement=20Symbol=E2=80=8B.prototype=E2=80=8B.descript?= =?UTF-8?q?ion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves #1096 --- js/src/builtin/SymbolObject.cpp | 29 +++++++++++++++++++++++++++++ js/src/builtin/SymbolObject.h | 4 ++++ 2 files changed, 33 insertions(+) (limited to 'js/src') diff --git a/js/src/builtin/SymbolObject.cpp b/js/src/builtin/SymbolObject.cpp index cf48402d6..ae38d5371 100644 --- a/js/src/builtin/SymbolObject.cpp +++ b/js/src/builtin/SymbolObject.cpp @@ -33,6 +33,7 @@ SymbolObject::create(JSContext* cx, JS::HandleSymbol symbol) } const JSPropertySpec SymbolObject::properties[] = { + JS_PSG("description", descriptionGetter, 0), JS_PS_END }; @@ -227,6 +228,34 @@ SymbolObject::toPrimitive(JSContext* cx, unsigned argc, Value* vp) return CallNonGenericMethod(cx, args); } +// ES2019 Stage 4 Draft / November 28, 2018 +// Symbol description accessor +// See: https://tc39.github.io/proposal-Symbol-description/ +bool +SymbolObject::descriptionGetter_impl(JSContext* cx, const CallArgs& args) +{ + // Get symbol object pointer. + HandleValue thisv = args.thisv(); + MOZ_ASSERT(IsSymbol(thisv)); + Rooted sym(cx, thisv.isSymbol() + ? thisv.toSymbol() + : thisv.toObject().as().unbox()); + + // Return the symbol's description if present, otherwise return undefined. + if (JSString* str = sym->description()) + args.rval().setString(str); + else + args.rval().setUndefined(); + return true; +} + +bool +SymbolObject::descriptionGetter(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + return CallNonGenericMethod(cx, args); +} + JSObject* js::InitSymbolClass(JSContext* cx, HandleObject obj) { diff --git a/js/src/builtin/SymbolObject.h b/js/src/builtin/SymbolObject.h index 0f204b494..e10b42d53 100644 --- a/js/src/builtin/SymbolObject.h +++ b/js/src/builtin/SymbolObject.h @@ -52,6 +52,10 @@ class SymbolObject : public NativeObject static MOZ_MUST_USE bool valueOf(JSContext* cx, unsigned argc, Value* vp); static MOZ_MUST_USE bool toPrimitive(JSContext* cx, unsigned argc, Value* vp); + // Properties defined on Symbol.prototype. + static MOZ_MUST_USE bool descriptionGetter_impl(JSContext* cx, const CallArgs& args); + static MOZ_MUST_USE bool descriptionGetter(JSContext* cx, unsigned argc, Value *vp); + static const JSPropertySpec properties[]; static const JSFunctionSpec methods[]; static const JSFunctionSpec staticMethods[]; -- cgit v1.2.3 From c2b5f396eb4ed1bd9be5a6625bd823d7a3e63678 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 23 May 2019 02:48:13 +0000 Subject: Remove UnboxedArray code part 1 --- js/src/builtin/ModuleObject.cpp | 2 +- js/src/jit/AliasAnalysisShared.cpp | 4 - js/src/jit/BaselineCacheIR.cpp | 16 -- js/src/jit/BaselineIC.cpp | 146 +-------------- js/src/jit/CacheIR.cpp | 9 +- js/src/jit/CacheIR.h | 5 - js/src/jit/CodeGenerator.cpp | 341 ++++++++---------------------------- js/src/jit/CodeGenerator.h | 4 - js/src/jit/IonBuilder.cpp | 199 +++++++-------------- js/src/jit/IonBuilder.h | 12 +- js/src/jit/IonCaches.cpp | 135 ++------------ js/src/jit/Lowering.cpp | 30 ---- js/src/jit/Lowering.h | 4 - js/src/jit/MCallOptimize.cpp | 71 ++------ js/src/jit/MIR.cpp | 45 ----- js/src/jit/MIR.h | 176 ++----------------- js/src/jit/MOpcodes.h | 4 - js/src/jit/MacroAssembler.cpp | 35 ---- js/src/jit/MacroAssembler.h | 5 +- js/src/jit/ScalarReplacement.cpp | 5 - js/src/jit/SharedIC.cpp | 9 - js/src/jit/VMFunctions.cpp | 12 +- js/src/jit/shared/LIR-shared.h | 66 ------- js/src/jit/shared/LOpcodes-shared.h | 4 - js/src/jsarray.cpp | 141 ++++++--------- js/src/jsfriendapi.cpp | 2 +- 26 files changed, 251 insertions(+), 1231 deletions(-) (limited to 'js/src') diff --git a/js/src/builtin/ModuleObject.cpp b/js/src/builtin/ModuleObject.cpp index 710c7a76c..c6bd2d300 100644 --- a/js/src/builtin/ModuleObject.cpp +++ b/js/src/builtin/ModuleObject.cpp @@ -947,7 +947,7 @@ ModuleObject::evaluate(JSContext* cx, HandleModuleObject self, MutableHandleValu ModuleObject::createNamespace(JSContext* cx, HandleModuleObject self, HandleObject exports) { MOZ_ASSERT(!self->namespace_()); - MOZ_ASSERT(exports->is() || exports->is()); + MOZ_ASSERT(exports->is()); RootedModuleNamespaceObject ns(cx, ModuleNamespaceObject::create(cx, self)); if (!ns) diff --git a/js/src/jit/AliasAnalysisShared.cpp b/js/src/jit/AliasAnalysisShared.cpp index 3b83df74e..0f0d4a66a 100644 --- a/js/src/jit/AliasAnalysisShared.cpp +++ b/js/src/jit/AliasAnalysisShared.cpp @@ -93,10 +93,6 @@ GetObject(const MDefinition* ins) case MDefinition::Op_Elements: case MDefinition::Op_MaybeCopyElementsForWrite: case MDefinition::Op_MaybeToDoubleElement: - case MDefinition::Op_UnboxedArrayLength: - case MDefinition::Op_UnboxedArrayInitializedLength: - case MDefinition::Op_IncrementUnboxedArrayInitializedLength: - case MDefinition::Op_SetUnboxedArrayInitializedLength: case MDefinition::Op_TypedArrayLength: case MDefinition::Op_SetTypedObjectOffset: case MDefinition::Op_SetDisjointTypedElements: diff --git a/js/src/jit/BaselineCacheIR.cpp b/js/src/jit/BaselineCacheIR.cpp index bf96932d1..7fb586811 100644 --- a/js/src/jit/BaselineCacheIR.cpp +++ b/js/src/jit/BaselineCacheIR.cpp @@ -787,9 +787,6 @@ BaselineCacheIRCompiler::emitGuardClass() case GuardClassKind::Array: clasp = &ArrayObject::class_; break; - case GuardClassKind::UnboxedArray: - clasp = &UnboxedArrayObject::class_; - break; case GuardClassKind::MappedArguments: clasp = &MappedArgumentsObject::class_; break; @@ -1003,19 +1000,6 @@ BaselineCacheIRCompiler::emitLoadInt32ArrayLengthResult() return true; } -bool -BaselineCacheIRCompiler::emitLoadUnboxedArrayLengthResult() -{ - Register obj = allocator.useRegister(masm, reader.objOperandId()); - masm.load32(Address(obj, UnboxedArrayObject::offsetOfLength()), R0.scratchReg()); - masm.tagValue(JSVAL_TYPE_INT32, R0.scratchReg(), R0); - - // The int32 type was monitored when attaching the stub, so we can - // just return. - emitReturnFromIC(); - return true; -} - bool BaselineCacheIRCompiler::emitLoadArgumentsObjectLengthResult() { diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 863c61161..f43fc5bf9 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -280,12 +280,6 @@ DoTypeUpdateFallback(JSContext* cx, BaselineFrame* frame, ICUpdatedStub* stub, H RootedId id(cx); switch(stub->kind()) { - case ICStub::SetElem_DenseOrUnboxedArray: - case ICStub::SetElem_DenseOrUnboxedArrayAdd: { - id = JSID_VOID; - AddTypePropertyId(cx, obj, id, value); - break; - } case ICStub::SetProp_Native: case ICStub::SetProp_NativeAdd: case ICStub::SetProp_Unboxed: { @@ -1366,7 +1360,7 @@ IsNativeDenseElementAccess(HandleObject obj, HandleValue key) static bool IsNativeOrUnboxedDenseElementAccess(HandleObject obj, HandleValue key) { - if (!obj->isNative() && !obj->is()) + if (!obj->isNative()) return false; if (key.isInt32() && key.toInt32() >= 0 && !obj->is()) return true; @@ -1470,20 +1464,6 @@ TryAttachGetElemStub(JSContext* cx, JSScript* script, jsbytecode* pc, ICGetElem_ script = rootedScript; } - // Check for UnboxedArray[int] accesses. - if (obj->is() && rhs.isInt32() && rhs.toInt32() >= 0) { - JitSpew(JitSpew_BaselineIC, " Generating GetElem(UnboxedArray[Int32]) stub"); - ICGetElem_UnboxedArray::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(), - obj->group()); - ICStub* unboxedStub = compiler.getStub(compiler.getStubSpace(script)); - if (!unboxedStub) - return false; - - stub->addNewStub(unboxedStub); - *attached = true; - return true; - } - // Check for TypedArray[int] => Number and TypedObject[int] => Number accesses. if ((obj->is() || IsPrimitiveArrayTypedObject(obj)) && rhs.isNumber() && @@ -2089,56 +2069,6 @@ ICGetElem_Dense::Compiler::generateStubCode(MacroAssembler& masm) return true; } -// -// GetElem_UnboxedArray -// - -bool -ICGetElem_UnboxedArray::Compiler::generateStubCode(MacroAssembler& masm) -{ - MOZ_ASSERT(engine_ == Engine::Baseline); - - Label failure; - masm.branchTestObject(Assembler::NotEqual, R0, &failure); - masm.branchTestInt32(Assembler::NotEqual, R1, &failure); - - AllocatableGeneralRegisterSet regs(availableGeneralRegs(2)); - Register scratchReg = regs.takeAny(); - - // Unbox R0 and group guard. - Register obj = masm.extractObject(R0, ExtractTemp0); - masm.loadPtr(Address(ICStubReg, ICGetElem_UnboxedArray::offsetOfGroup()), scratchReg); - masm.branchTestObjGroup(Assembler::NotEqual, obj, scratchReg, &failure); - - // Unbox key. - Register key = masm.extractInt32(R1, ExtractTemp1); - - // Bounds check. - masm.load32(Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), - scratchReg); - masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), scratchReg); - masm.branch32(Assembler::BelowOrEqual, scratchReg, key, &failure); - - // Load obj->elements. - masm.loadPtr(Address(obj, UnboxedArrayObject::offsetOfElements()), scratchReg); - - // Load value. - size_t width = UnboxedTypeSize(elementType_); - BaseIndex addr(scratchReg, key, ScaleFromElemWidth(width)); - masm.loadUnboxedProperty(addr, elementType_, R0); - - // Only monitor the result if its type might change. - if (elementType_ == JSVAL_TYPE_OBJECT) - EmitEnterTypeMonitorIC(masm); - else - EmitReturnFromIC(masm); - - // Failure case - jump to next stub - masm.bind(&failure); - EmitStubGuardFailure(masm); - return true; -} - // // GetElem_TypedArray // @@ -2447,10 +2377,6 @@ CanOptimizeDenseOrUnboxedArraySetElem(JSObject* obj, uint32_t index, if (initLength < oldInitLength || capacity < oldCapacity) return false; - // Unboxed arrays need to be able to emit floating point code. - if (obj->is() && !obj->runtimeFromMainThread()->jitSupportsFloatingPoint) - return false; - Shape* shape = obj->maybeShape(); // Cannot optimize if the shape changed. @@ -2871,29 +2797,6 @@ ICSetElem_DenseOrUnboxedArray::Compiler::generateStubCode(MacroAssembler& masm) masm.loadValue(valueAddr, tmpVal); EmitPreBarrier(masm, element, MIRType::Value); masm.storeValue(tmpVal, element); - } else { - // Set element on an unboxed array. - - // Bounds check. - Address initLength(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()); - masm.load32(initLength, scratchReg); - masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), scratchReg); - masm.branch32(Assembler::BelowOrEqual, scratchReg, key, &failure); - - // Load obj->elements. - masm.loadPtr(Address(obj, UnboxedArrayObject::offsetOfElements()), scratchReg); - - // Compute the address being written to. - BaseIndex address(scratchReg, key, ScaleFromElemWidth(UnboxedTypeSize(unboxedType_))); - - EmitUnboxedPreBarrierForBaseline(masm, address, unboxedType_); - - Address valueAddr(masm.getStackPointer(), ICStackValueOffset + sizeof(Value)); - masm.Push(R0); - masm.loadValue(valueAddr, R0); - masm.storeUnboxedProperty(address, unboxedType_, - ConstantOrRegister(TypedOrValueRegister(R0)), &failurePopR0); - masm.Pop(R0); } EmitReturnFromIC(masm); @@ -3087,40 +2990,6 @@ ICSetElemDenseOrUnboxedArrayAddCompiler::generateStubCode(MacroAssembler& masm) BaseIndex element(scratchReg, key, TimesEight); masm.loadValue(valueAddr, tmpVal); masm.storeValue(tmpVal, element); - } else { - // Adding element to an unboxed array. - - // Bounds check (key == initLength) - Address initLengthAddr(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()); - masm.load32(initLengthAddr, scratchReg); - masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), scratchReg); - masm.branch32(Assembler::NotEqual, scratchReg, key, &failure); - - // Capacity check. - masm.checkUnboxedArrayCapacity(obj, RegisterOrInt32Constant(key), scratchReg, &failure); - - // Load obj->elements. - masm.loadPtr(Address(obj, UnboxedArrayObject::offsetOfElements()), scratchReg); - - // Write the value first, since this can fail. No need for pre-barrier - // since we're not overwriting an old value. - masm.Push(R0); - Address valueAddr(masm.getStackPointer(), ICStackValueOffset + sizeof(Value)); - masm.loadValue(valueAddr, R0); - BaseIndex address(scratchReg, key, ScaleFromElemWidth(UnboxedTypeSize(unboxedType_))); - masm.storeUnboxedProperty(address, unboxedType_, - ConstantOrRegister(TypedOrValueRegister(R0)), &failurePopR0); - masm.Pop(R0); - - // Increment initialized length. - masm.add32(Imm32(1), initLengthAddr); - - // If length is now <= key, increment length. - Address lengthAddr(obj, UnboxedArrayObject::offsetOfLength()); - Label skipIncrementLength; - masm.branch32(Assembler::Above, lengthAddr, key, &skipIncrementLength); - masm.add32(Imm32(1), lengthAddr); - masm.bind(&skipIncrementLength); } EmitReturnFromIC(masm); @@ -8301,19 +8170,6 @@ ICGetElem_Dense::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorSt return New(cx, space, other.jitCode(), firstMonitorStub, other.shape_); } -ICGetElem_UnboxedArray::ICGetElem_UnboxedArray(JitCode* stubCode, ICStub* firstMonitorStub, - ObjectGroup *group) - : ICMonitoredStub(GetElem_UnboxedArray, stubCode, firstMonitorStub), - group_(group) -{ } - -/* static */ ICGetElem_UnboxedArray* -ICGetElem_UnboxedArray::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub, - ICGetElem_UnboxedArray& other) -{ - return New(cx, space, other.jitCode(), firstMonitorStub, other.group_); -} - ICGetElem_TypedArray::ICGetElem_TypedArray(JitCode* stubCode, Shape* shape, Scalar::Type type) : ICStub(GetElem_TypedArray, stubCode), shape_(shape) diff --git a/js/src/jit/CacheIR.cpp b/js/src/jit/CacheIR.cpp index f1061af70..6822a70af 100644 --- a/js/src/jit/CacheIR.cpp +++ b/js/src/jit/CacheIR.cpp @@ -175,7 +175,7 @@ TestMatchingReceiver(CacheIRWriter& writer, JSObject* obj, Shape* shape, ObjOper } else { writer.guardNoUnboxedExpando(objId); } - } else if (obj->is() || obj->is()) { + } else if (obj->is()) { writer.guardGroup(objId, obj->group()); } else { Shape* shape = obj->maybeShape(); @@ -368,13 +368,6 @@ GetPropIRGenerator::tryAttachObjectLength(CacheIRWriter& writer, HandleObject ob return true; } - if (obj->is()) { - writer.guardClass(objId, GuardClassKind::UnboxedArray); - writer.loadUnboxedArrayLengthResult(objId); - emitted_ = true; - return true; - } - if (obj->is() && !obj->as().hasOverriddenLength()) { if (obj->is()) { writer.guardClass(objId, GuardClassKind::MappedArguments); diff --git a/js/src/jit/CacheIR.h b/js/src/jit/CacheIR.h index 51e55f48b..4fd8575f0 100644 --- a/js/src/jit/CacheIR.h +++ b/js/src/jit/CacheIR.h @@ -96,7 +96,6 @@ class ObjOperandId : public OperandId _(LoadUnboxedPropertyResult) \ _(LoadTypedObjectResult) \ _(LoadInt32ArrayLengthResult) \ - _(LoadUnboxedArrayLengthResult) \ _(LoadArgumentsObjectLengthResult) \ _(LoadUndefinedResult) @@ -128,7 +127,6 @@ struct StubField { enum class GuardClassKind { Array, - UnboxedArray, MappedArguments, UnmappedArguments, }; @@ -327,9 +325,6 @@ class MOZ_RAII CacheIRWriter void loadInt32ArrayLengthResult(ObjOperandId obj) { writeOpWithOperandId(CacheOp::LoadInt32ArrayLengthResult, obj); } - void loadUnboxedArrayLengthResult(ObjOperandId obj) { - writeOpWithOperandId(CacheOp::LoadUnboxedArrayLengthResult, obj); - } void loadArgumentsObjectLengthResult(ObjOperandId obj) { writeOpWithOperandId(CacheOp::LoadArgumentsObjectLengthResult, obj); } diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 6d1fb6b9b..bd275a2c1 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -3183,9 +3183,7 @@ CodeGenerator::visitSetPropertyPolymorphicT(LSetPropertyPolymorphicT* ins) void CodeGenerator::visitElements(LElements* lir) { - Address elements(ToRegister(lir->object()), - lir->mir()->unboxed() ? UnboxedArrayObject::offsetOfElements() - : NativeObject::offsetOfElements()); + Address elements(ToRegister(lir->object()), NativeObject::offsetOfElements()); masm.loadPtr(elements, ToRegister(lir->output())); } @@ -5341,21 +5339,11 @@ CodeGenerator::visitNewArrayDynamicLength(LNewArrayDynamicLength* lir) bool canInline = true; size_t inlineLength = 0; - if (templateObject->is()) { - if (templateObject->as().hasFixedElements()) { - size_t numSlots = gc::GetGCKindSlots(templateObject->asTenured().getAllocKind()); - inlineLength = numSlots - ObjectElements::VALUES_PER_HEADER; - } else { - canInline = false; - } + if (templateObject->as().hasFixedElements()) { + size_t numSlots = gc::GetGCKindSlots(templateObject->asTenured().getAllocKind()); + inlineLength = numSlots - ObjectElements::VALUES_PER_HEADER; } else { - if (templateObject->as().hasInlineElements()) { - size_t nbytes = - templateObject->tenuredSizeOfThis() - UnboxedArrayObject::offsetOfInlineElements(); - inlineLength = nbytes / templateObject->as().elementSize(); - } else { - canInline = false; - } + canInline = false; } if (canInline) { @@ -7811,49 +7799,6 @@ CodeGenerator::visitSetInitializedLength(LSetInitializedLength* lir) masm.dec32(&index); } -void -CodeGenerator::visitUnboxedArrayLength(LUnboxedArrayLength* lir) -{ - Register obj = ToRegister(lir->object()); - Register result = ToRegister(lir->output()); - masm.load32(Address(obj, UnboxedArrayObject::offsetOfLength()), result); -} - -void -CodeGenerator::visitUnboxedArrayInitializedLength(LUnboxedArrayInitializedLength* lir) -{ - Register obj = ToRegister(lir->object()); - Register result = ToRegister(lir->output()); - masm.load32(Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), result); - masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), result); -} - -void -CodeGenerator::visitIncrementUnboxedArrayInitializedLength(LIncrementUnboxedArrayInitializedLength* lir) -{ - Register obj = ToRegister(lir->object()); - masm.add32(Imm32(1), Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength())); -} - -void -CodeGenerator::visitSetUnboxedArrayInitializedLength(LSetUnboxedArrayInitializedLength* lir) -{ - Register obj = ToRegister(lir->object()); - RegisterOrInt32Constant key = ToRegisterOrInt32Constant(lir->length()); - Register temp = ToRegister(lir->temp()); - - Address initLengthAddr(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()); - masm.load32(initLengthAddr, temp); - masm.and32(Imm32(UnboxedArrayObject::CapacityMask), temp); - - if (key.isRegister()) - masm.or32(key.reg(), temp); - else - masm.or32(Imm32(key.constant()), temp); - - masm.store32(temp, initLengthAddr); -} - void CodeGenerator::visitNotO(LNotO* lir) { @@ -8150,46 +8095,19 @@ CodeGenerator::emitStoreElementHoleT(T* lir) OutOfLineStoreElementHole* ool = new(alloc()) OutOfLineStoreElementHole(lir); addOutOfLineCode(ool, lir->mir()); - Register obj = ToRegister(lir->object()); Register elements = ToRegister(lir->elements()); const LAllocation* index = lir->index(); RegisterOrInt32Constant key = ToRegisterOrInt32Constant(index); - JSValueType unboxedType = lir->mir()->unboxedType(); - if (unboxedType == JSVAL_TYPE_MAGIC) { - Address initLength(elements, ObjectElements::offsetOfInitializedLength()); - masm.branch32(Assembler::BelowOrEqual, initLength, key, ool->entry()); - - if (lir->mir()->needsBarrier()) - emitPreBarrier(elements, index, 0); + Address initLength(elements, ObjectElements::offsetOfInitializedLength()); + masm.branch32(Assembler::BelowOrEqual, initLength, key, ool->entry()); - masm.bind(ool->rejoinStore()); - emitStoreElementTyped(lir->value(), lir->mir()->value()->type(), lir->mir()->elementType(), - elements, index, 0); - } else { - Register temp = ToRegister(lir->getTemp(0)); - Address initLength(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()); - masm.load32(initLength, temp); - masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), temp); - masm.branch32(Assembler::BelowOrEqual, temp, key, ool->entry()); - - ConstantOrRegister v = ToConstantOrRegister(lir->value(), lir->mir()->value()->type()); - - if (index->isConstant()) { - Address address(elements, ToInt32(index) * UnboxedTypeSize(unboxedType)); - EmitUnboxedPreBarrier(masm, address, unboxedType); - - masm.bind(ool->rejoinStore()); - masm.storeUnboxedProperty(address, unboxedType, v, nullptr); - } else { - BaseIndex address(elements, ToRegister(index), - ScaleFromElemWidth(UnboxedTypeSize(unboxedType))); - EmitUnboxedPreBarrier(masm, address, unboxedType); + if (lir->mir()->needsBarrier()) + emitPreBarrier(elements, index, 0); - masm.bind(ool->rejoinStore()); - masm.storeUnboxedProperty(address, unboxedType, v, nullptr); - } - } + masm.bind(ool->rejoinStore()); + emitStoreElementTyped(lir->value(), lir->mir()->value()->type(), lir->mir()->elementType(), + elements, index, 0); masm.bind(ool->rejoin()); } @@ -8209,47 +8127,22 @@ CodeGenerator::emitStoreElementHoleV(T* lir) OutOfLineStoreElementHole* ool = new(alloc()) OutOfLineStoreElementHole(lir); addOutOfLineCode(ool, lir->mir()); - Register obj = ToRegister(lir->object()); Register elements = ToRegister(lir->elements()); const LAllocation* index = lir->index(); const ValueOperand value = ToValue(lir, T::Value); RegisterOrInt32Constant key = ToRegisterOrInt32Constant(index); - JSValueType unboxedType = lir->mir()->unboxedType(); - if (unboxedType == JSVAL_TYPE_MAGIC) { - Address initLength(elements, ObjectElements::offsetOfInitializedLength()); - masm.branch32(Assembler::BelowOrEqual, initLength, key, ool->entry()); - - if (lir->mir()->needsBarrier()) - emitPreBarrier(elements, index, 0); + Address initLength(elements, ObjectElements::offsetOfInitializedLength()); + masm.branch32(Assembler::BelowOrEqual, initLength, key, ool->entry()); - masm.bind(ool->rejoinStore()); - if (index->isConstant()) - masm.storeValue(value, Address(elements, ToInt32(index) * sizeof(js::Value))); - else - masm.storeValue(value, BaseIndex(elements, ToRegister(index), TimesEight)); - } else { - Register temp = ToRegister(lir->getTemp(0)); - Address initLength(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()); - masm.load32(initLength, temp); - masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), temp); - masm.branch32(Assembler::BelowOrEqual, temp, key, ool->entry()); - - if (index->isConstant()) { - Address address(elements, ToInt32(index) * UnboxedTypeSize(unboxedType)); - EmitUnboxedPreBarrier(masm, address, unboxedType); - - masm.bind(ool->rejoinStore()); - masm.storeUnboxedProperty(address, unboxedType, ConstantOrRegister(value), nullptr); - } else { - BaseIndex address(elements, ToRegister(index), - ScaleFromElemWidth(UnboxedTypeSize(unboxedType))); - EmitUnboxedPreBarrier(masm, address, unboxedType); + if (lir->mir()->needsBarrier()) + emitPreBarrier(elements, index, 0); - masm.bind(ool->rejoinStore()); - masm.storeUnboxedProperty(address, unboxedType, ConstantOrRegister(value), nullptr); - } - } + masm.bind(ool->rejoinStore()); + if (index->isConstant()) + masm.storeValue(value, Address(elements, ToInt32(index) * sizeof(js::Value))); + else + masm.storeValue(value, BaseIndex(elements, ToRegister(index), TimesEight)); masm.bind(ool->rejoin()); } @@ -8334,8 +8227,6 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool) const LAllocation* index; MIRType valueType; ConstantOrRegister value; - JSValueType unboxedType; - LDefinition *temp = nullptr; if (ins->isStoreElementHoleV()) { LStoreElementHoleV* store = ins->toStoreElementHoleV(); @@ -8344,8 +8235,6 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool) index = store->index(); valueType = store->mir()->value()->type(); value = TypedOrValueRegister(ToValue(store, LStoreElementHoleV::Value)); - unboxedType = store->mir()->unboxedType(); - temp = store->getTemp(0); } else if (ins->isFallibleStoreElementV()) { LFallibleStoreElementV* store = ins->toFallibleStoreElementV(); object = ToRegister(store->object()); @@ -8353,8 +8242,6 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool) index = store->index(); valueType = store->mir()->value()->type(); value = TypedOrValueRegister(ToValue(store, LFallibleStoreElementV::Value)); - unboxedType = store->mir()->unboxedType(); - temp = store->getTemp(0); } else if (ins->isStoreElementHoleT()) { LStoreElementHoleT* store = ins->toStoreElementHoleT(); object = ToRegister(store->object()); @@ -8365,8 +8252,6 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool) value = ConstantOrRegister(store->value()->toConstant()->toJSValue()); else value = TypedOrValueRegister(valueType, ToAnyRegister(store->value())); - unboxedType = store->mir()->unboxedType(); - temp = store->getTemp(0); } else { // ins->isFallibleStoreElementT() LFallibleStoreElementT* store = ins->toFallibleStoreElementT(); object = ToRegister(store->object()); @@ -8377,8 +8262,6 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool) value = ConstantOrRegister(store->value()->toConstant()->toJSValue()); else value = TypedOrValueRegister(valueType, ToAnyRegister(store->value())); - unboxedType = store->mir()->unboxedType(); - temp = store->getTemp(0); } RegisterOrInt32Constant key = ToRegisterOrInt32Constant(index); @@ -8389,54 +8272,32 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool) Label callStub; #if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) // Had to reimplement for MIPS because there are no flags. - if (unboxedType == JSVAL_TYPE_MAGIC) { - Address initLength(elements, ObjectElements::offsetOfInitializedLength()); - masm.branch32(Assembler::NotEqual, initLength, key, &callStub); - } else { - Address initLength(object, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()); - masm.load32(initLength, ToRegister(temp)); - masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), ToRegister(temp)); - masm.branch32(Assembler::NotEqual, ToRegister(temp), key, &callStub); - } + Address initLength(elements, ObjectElements::offsetOfInitializedLength()); + masm.branch32(Assembler::NotEqual, initLength, key, &callStub); #else masm.j(Assembler::NotEqual, &callStub); #endif - if (unboxedType == JSVAL_TYPE_MAGIC) { - // Check array capacity. - masm.branch32(Assembler::BelowOrEqual, Address(elements, ObjectElements::offsetOfCapacity()), - key, &callStub); - - // Update initialized length. The capacity guard above ensures this won't overflow, - // due to MAX_DENSE_ELEMENTS_COUNT. - masm.inc32(&key); - masm.store32(key, Address(elements, ObjectElements::offsetOfInitializedLength())); - - // Update length if length < initializedLength. - Label dontUpdate; - masm.branch32(Assembler::AboveOrEqual, Address(elements, ObjectElements::offsetOfLength()), - key, &dontUpdate); - masm.store32(key, Address(elements, ObjectElements::offsetOfLength())); - masm.bind(&dontUpdate); + // Check array capacity. + masm.branch32(Assembler::BelowOrEqual, Address(elements, ObjectElements::offsetOfCapacity()), + key, &callStub); - masm.dec32(&key); - } else { - // Check array capacity. - masm.checkUnboxedArrayCapacity(object, key, ToRegister(temp), &callStub); + // Update initialized length. The capacity guard above ensures this won't overflow, + // due to MAX_DENSE_ELEMENTS_COUNT. + masm.inc32(&key); + masm.store32(key, Address(elements, ObjectElements::offsetOfInitializedLength())); - // Update initialized length. - masm.add32(Imm32(1), Address(object, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength())); + // Update length if length < initializedLength. + Label dontUpdate; + masm.branch32(Assembler::AboveOrEqual, Address(elements, ObjectElements::offsetOfLength()), + key, &dontUpdate); + masm.store32(key, Address(elements, ObjectElements::offsetOfLength())); + masm.bind(&dontUpdate); - // Update length if length < initializedLength. - Address lengthAddr(object, UnboxedArrayObject::offsetOfLength()); - Label dontUpdate; - masm.branch32(Assembler::Above, lengthAddr, key, &dontUpdate); - masm.add32(Imm32(1), lengthAddr); - masm.bind(&dontUpdate); - } + masm.dec32(&key); if ((ins->isStoreElementHoleT() || ins->isFallibleStoreElementT()) && - unboxedType == JSVAL_TYPE_MAGIC && valueType != MIRType::Double) + valueType != MIRType::Double) { // The inline path for StoreElementHoleT and FallibleStoreElementT does not always store // the type tag, so we do the store on the OOL path. We use MIRType::None for the element @@ -8526,9 +8387,6 @@ typedef bool (*ConvertUnboxedObjectToNativeFn)(JSContext*, JSObject*); static const VMFunction ConvertUnboxedPlainObjectToNativeInfo = FunctionInfo(UnboxedPlainObject::convertToNative, "UnboxedPlainObject::convertToNative"); -static const VMFunction ConvertUnboxedArrayObjectToNativeInfo = - FunctionInfo(UnboxedArrayObject::convertToNative, - "UnboxedArrayObject::convertToNative"); typedef bool (*ArrayPopShiftFn)(JSContext*, HandleObject, MutableHandleValue); static const VMFunction ArrayPopDenseInfo = @@ -8554,20 +8412,11 @@ CodeGenerator::emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, R // Load elements and length, and VM call if length != initializedLength. RegisterOrInt32Constant key = RegisterOrInt32Constant(lengthTemp); - if (mir->unboxedType() == JSVAL_TYPE_MAGIC) { - masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp); - masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), lengthTemp); + masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp); + masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), lengthTemp); - Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength()); - masm.branch32(Assembler::NotEqual, initLength, key, ool->entry()); - } else { - masm.loadPtr(Address(obj, UnboxedArrayObject::offsetOfElements()), elementsTemp); - masm.load32(Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), lengthTemp); - masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), lengthTemp); - - Address lengthAddr(obj, UnboxedArrayObject::offsetOfLength()); - masm.branch32(Assembler::NotEqual, lengthAddr, key, ool->entry()); - } + Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength()); + masm.branch32(Assembler::NotEqual, initLength, key, ool->entry()); // Test for length != 0. On zero length either take a VM call or generate // an undefined value, depending on whether the call is known to produce @@ -8579,13 +8428,10 @@ CodeGenerator::emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, R // According to the spec we need to set the length 0 (which is already 0). // This is observable when the array length is made non-writable. - // Handle this case in the OOL. When freezing an unboxed array it is converted - // to an normal array. - if (mir->unboxedType() == JSVAL_TYPE_MAGIC) { - Address elementFlags(elementsTemp, ObjectElements::offsetOfFlags()); - Imm32 bit(ObjectElements::NONWRITABLE_ARRAY_LENGTH); - masm.branchTest32(Assembler::NonZero, elementFlags, bit, ool->entry()); - } + // Handle this case in the OOL. + Address elementFlags(elementsTemp, ObjectElements::offsetOfFlags()); + Imm32 bit(ObjectElements::NONWRITABLE_ARRAY_LENGTH); + masm.branchTest32(Assembler::NonZero, elementFlags, bit, ool->entry()); masm.moveValue(UndefinedValue(), out.valueReg()); masm.jump(&done); @@ -8597,41 +8443,25 @@ CodeGenerator::emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, R masm.dec32(&key); if (mir->mode() == MArrayPopShift::Pop) { - if (mir->unboxedType() == JSVAL_TYPE_MAGIC) { - BaseIndex addr(elementsTemp, lengthTemp, TimesEight); - masm.loadElementTypedOrValue(addr, out, mir->needsHoleCheck(), ool->entry()); - } else { - size_t elemSize = UnboxedTypeSize(mir->unboxedType()); - BaseIndex addr(elementsTemp, lengthTemp, ScaleFromElemWidth(elemSize)); - masm.loadUnboxedProperty(addr, mir->unboxedType(), out); - } + BaseIndex addr(elementsTemp, lengthTemp, TimesEight); + masm.loadElementTypedOrValue(addr, out, mir->needsHoleCheck(), ool->entry()); } else { MOZ_ASSERT(mir->mode() == MArrayPopShift::Shift); Address addr(elementsTemp, 0); - if (mir->unboxedType() == JSVAL_TYPE_MAGIC) - masm.loadElementTypedOrValue(addr, out, mir->needsHoleCheck(), ool->entry()); - else - masm.loadUnboxedProperty(addr, mir->unboxedType(), out); + masm.loadElementTypedOrValue(addr, out, mir->needsHoleCheck(), ool->entry()); } - if (mir->unboxedType() == JSVAL_TYPE_MAGIC) { - // Handle the failure case when the array length is non-writable in the - // OOL path. (Unlike in the adding-an-element cases, we can't rely on the - // capacity <= length invariant for such arrays to avoid an explicit - // check.) - Address elementFlags(elementsTemp, ObjectElements::offsetOfFlags()); - Imm32 bit(ObjectElements::NONWRITABLE_ARRAY_LENGTH); - masm.branchTest32(Assembler::NonZero, elementFlags, bit, ool->entry()); + // Handle the failure case when the array length is non-writable in the + // OOL path. (Unlike in the adding-an-element cases, we can't rely on the + // capacity <= length invariant for such arrays to avoid an explicit + // check.) + Address elementFlags(elementsTemp, ObjectElements::offsetOfFlags()); + Imm32 bit(ObjectElements::NONWRITABLE_ARRAY_LENGTH); + masm.branchTest32(Assembler::NonZero, elementFlags, bit, ool->entry()); - // Now adjust length and initializedLength. - masm.store32(lengthTemp, Address(elementsTemp, ObjectElements::offsetOfLength())); - masm.store32(lengthTemp, Address(elementsTemp, ObjectElements::offsetOfInitializedLength())); - } else { - // Unboxed arrays always have writable lengths. Adjust length and - // initializedLength. - masm.store32(lengthTemp, Address(obj, UnboxedArrayObject::offsetOfLength())); - masm.add32(Imm32(-1), Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength())); - } + // Now adjust length and initializedLength. + masm.store32(lengthTemp, Address(elementsTemp, ObjectElements::offsetOfLength())); + masm.store32(lengthTemp, Address(elementsTemp, ObjectElements::offsetOfInitializedLength())); if (mir->mode() == MArrayPopShift::Shift) { // Don't save the temp registers. @@ -8681,50 +8511,27 @@ CodeGenerator::emitArrayPush(LInstruction* lir, const MArrayPush* mir, Register OutOfLineCode* ool = oolCallVM(ArrayPushDenseInfo, lir, ArgList(obj, value), StoreRegisterTo(length)); RegisterOrInt32Constant key = RegisterOrInt32Constant(length); - if (mir->unboxedType() == JSVAL_TYPE_MAGIC) { - // Load elements and length. - masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp); - masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), length); - - // Guard length == initializedLength. - Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength()); - masm.branch32(Assembler::NotEqual, initLength, key, ool->entry()); - // Guard length < capacity. - Address capacity(elementsTemp, ObjectElements::offsetOfCapacity()); - masm.branch32(Assembler::BelowOrEqual, capacity, key, ool->entry()); + // Load elements and length. + masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp); + masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), length); - // Do the store. - masm.storeConstantOrRegister(value, BaseIndex(elementsTemp, length, TimesEight)); - } else { - // Load initialized length. - masm.load32(Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), length); - masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), length); - - // Guard length == initializedLength. - Address lengthAddr(obj, UnboxedArrayObject::offsetOfLength()); - masm.branch32(Assembler::NotEqual, lengthAddr, key, ool->entry()); + // Guard length == initializedLength. + Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength()); + masm.branch32(Assembler::NotEqual, initLength, key, ool->entry()); - // Guard length < capacity. - masm.checkUnboxedArrayCapacity(obj, key, elementsTemp, ool->entry()); + // Guard length < capacity. + Address capacity(elementsTemp, ObjectElements::offsetOfCapacity()); + masm.branch32(Assembler::BelowOrEqual, capacity, key, ool->entry()); - // Load elements and do the store. - masm.loadPtr(Address(obj, UnboxedArrayObject::offsetOfElements()), elementsTemp); - size_t elemSize = UnboxedTypeSize(mir->unboxedType()); - BaseIndex addr(elementsTemp, length, ScaleFromElemWidth(elemSize)); - masm.storeUnboxedProperty(addr, mir->unboxedType(), value, nullptr); - } + // Do the store. + masm.storeConstantOrRegister(value, BaseIndex(elementsTemp, length, TimesEight)); masm.inc32(&key); // Update length and initialized length. - if (mir->unboxedType() == JSVAL_TYPE_MAGIC) { - masm.store32(length, Address(elementsTemp, ObjectElements::offsetOfLength())); - masm.store32(length, Address(elementsTemp, ObjectElements::offsetOfInitializedLength())); - } else { - masm.store32(length, Address(obj, UnboxedArrayObject::offsetOfLength())); - masm.add32(Imm32(1), Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength())); - } + masm.store32(length, Address(elementsTemp, ObjectElements::offsetOfLength())); + masm.store32(length, Address(elementsTemp, ObjectElements::offsetOfInitializedLength())); masm.bind(ool->rejoin()); } @@ -10922,7 +10729,7 @@ CodeGenerator::visitInArray(LInArray* lir) } masm.branch32(Assembler::BelowOrEqual, initLength, Imm32(index), failedInitLength); - if (mir->needsHoleCheck() && mir->unboxedType() == JSVAL_TYPE_MAGIC) { + if (mir->needsHoleCheck()) { NativeObject::elementsSizeMustNotOverflow(); Address address = Address(elements, index * sizeof(Value)); masm.branchTestMagic(Assembler::Equal, address, &falseBranch); @@ -10935,7 +10742,7 @@ CodeGenerator::visitInArray(LInArray* lir) failedInitLength = &negativeIntCheck; masm.branch32(Assembler::BelowOrEqual, initLength, index, failedInitLength); - if (mir->needsHoleCheck() && mir->unboxedType() == JSVAL_TYPE_MAGIC) { + if (mir->needsHoleCheck()) { BaseIndex address = BaseIndex(elements, ToRegister(lir->index()), TimesEight); masm.branchTestMagic(Assembler::Equal, address, &falseBranch); } diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h index 292f163b5..b5f170d84 100644 --- a/js/src/jit/CodeGenerator.h +++ b/js/src/jit/CodeGenerator.h @@ -234,10 +234,6 @@ class CodeGenerator final : public CodeGeneratorSpecific void visitSubstr(LSubstr* lir); void visitInitializedLength(LInitializedLength* lir); void visitSetInitializedLength(LSetInitializedLength* lir); - void visitUnboxedArrayLength(LUnboxedArrayLength* lir); - void visitUnboxedArrayInitializedLength(LUnboxedArrayInitializedLength* lir); - void visitIncrementUnboxedArrayInitializedLength(LIncrementUnboxedArrayInitializedLength* lir); - void visitSetUnboxedArrayInitializedLength(LSetUnboxedArrayInitializedLength* lir); void visitNotO(LNotO* ins); void visitNotV(LNotV* ins); void visitBoundsCheck(LBoundsCheck* lir); diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index af85011be..3d964d1c6 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -7336,12 +7336,6 @@ IonBuilder::newArrayTryTemplateObject(bool* emitted, JSObject* templateObject, u if (!templateObject) return true; - if (templateObject->is()) { - MOZ_ASSERT(templateObject->as().capacity() >= length); - if (!templateObject->as().hasInlineElements()) - return true; - } - MOZ_ASSERT(length <= NativeObject::MAX_DENSE_ELEMENTS_COUNT); size_t arraySlots = @@ -7597,7 +7591,6 @@ IonBuilder::jsop_initelem_array() // intializer, and that arrays are marked as non-packed when writing holes // to them during initialization. bool needStub = false; - JSValueType unboxedType = JSVAL_TYPE_MAGIC; if (shouldAbortOnPreliminaryGroups(obj)) { needStub = true; } else if (!obj->resultTypeSet() || @@ -7608,12 +7601,6 @@ IonBuilder::jsop_initelem_array() } else { MOZ_ASSERT(obj->resultTypeSet()->getObjectCount() == 1); TypeSet::ObjectKey* initializer = obj->resultTypeSet()->getObject(0); - if (initializer->clasp() == &UnboxedArrayObject::class_) { - if (initializer->group()->unboxedLayout().nativeGroup()) - needStub = true; - else - unboxedType = initializer->group()->unboxedLayout().elementType(); - } if (value->type() == MIRType::MagicHole) { if (!initializer->hasFlags(constraints(), OBJECT_FLAG_NON_PACKED)) needStub = true; @@ -7633,60 +7620,46 @@ IonBuilder::jsop_initelem_array() return resumeAfter(store); } - return initializeArrayElement(obj, index, value, unboxedType, /* addResumePoint = */ true); + return initializeArrayElement(obj, index, value, /* addResumePoint = */ true); } bool IonBuilder::initializeArrayElement(MDefinition* obj, size_t index, MDefinition* value, - JSValueType unboxedType, bool addResumePointAndIncrementInitializedLength) { MConstant* id = MConstant::New(alloc(), Int32Value(index)); current->add(id); // Get the elements vector. - MElements* elements = MElements::New(alloc(), obj, unboxedType != JSVAL_TYPE_MAGIC); + MElements* elements = MElements::New(alloc(), obj); current->add(elements); - if (unboxedType != JSVAL_TYPE_MAGIC) { - // Note: storeUnboxedValue takes care of any post barriers on the value. - storeUnboxedValue(obj, elements, 0, id, unboxedType, value, /* preBarrier = */ false); - - if (addResumePointAndIncrementInitializedLength) { - MInstruction* increment = MIncrementUnboxedArrayInitializedLength::New(alloc(), obj); - current->add(increment); - - if (!resumeAfter(increment)) - return false; - } - } else { - if (NeedsPostBarrier(value)) - current->add(MPostWriteBarrier::New(alloc(), obj, value)); + if (NeedsPostBarrier(value)) + current->add(MPostWriteBarrier::New(alloc(), obj, value)); - if ((obj->isNewArray() && obj->toNewArray()->convertDoubleElements()) || - (obj->isNullarySharedStub() && - obj->resultTypeSet()->convertDoubleElements(constraints()) == TemporaryTypeSet::AlwaysConvertToDoubles)) - { - MInstruction* valueDouble = MToDouble::New(alloc(), value); - current->add(valueDouble); - value = valueDouble; - } + if ((obj->isNewArray() && obj->toNewArray()->convertDoubleElements()) || + (obj->isNullarySharedStub() && + obj->resultTypeSet()->convertDoubleElements(constraints()) == TemporaryTypeSet::AlwaysConvertToDoubles)) + { + MInstruction* valueDouble = MToDouble::New(alloc(), value); + current->add(valueDouble); + value = valueDouble; + } - // Store the value. - MStoreElement* store = MStoreElement::New(alloc(), elements, id, value, + // Store the value. + MStoreElement* store = MStoreElement::New(alloc(), elements, id, value, /* needsHoleCheck = */ false); - current->add(store); + current->add(store); - if (addResumePointAndIncrementInitializedLength) { - // Update the initialized length. (The template object for this - // array has the array's ultimate length, so the length field is - // already correct: no updating needed.) - MSetInitializedLength* initLength = MSetInitializedLength::New(alloc(), elements, id); - current->add(initLength); + if (addResumePointAndIncrementInitializedLength) { + // Update the initialized length. (The template object for this + // array has the array's ultimate length, so the length field is + // already correct: no updating needed.) + MSetInitializedLength* initLength = MSetInitializedLength::New(alloc(), elements, id); + current->add(initLength); - if (!resumeAfter(initLength)) - return false; - } + if (!resumeAfter(initLength)) + return false; } return true; @@ -8175,8 +8148,7 @@ IonBuilder::maybeMarkEmpty(MDefinition* ins) static bool ClassHasEffectlessLookup(const Class* clasp) { - return (clasp == &UnboxedArrayObject::class_) || - IsTypedObjectClass(clasp) || + return IsTypedObjectClass(clasp) || (clasp->isNative() && !clasp->getOpsLookupProperty()); } @@ -9452,12 +9424,9 @@ IonBuilder::getElemTryDense(bool* emitted, MDefinition* obj, MDefinition* index) { MOZ_ASSERT(*emitted == false); - JSValueType unboxedType = UnboxedArrayElementType(constraints(), obj, index); - if (unboxedType == JSVAL_TYPE_MAGIC) { - if (!ElementAccessIsDenseNative(constraints(), obj, index)) { - trackOptimizationOutcome(TrackedOutcome::AccessNotDense); - return true; - } + if (!ElementAccessIsDenseNative(constraints(), obj, index)) { + trackOptimizationOutcome(TrackedOutcome::AccessNotDense); + return true; } // Don't generate a fast path if there have been bounds check failures @@ -9474,7 +9443,7 @@ IonBuilder::getElemTryDense(bool* emitted, MDefinition* obj, MDefinition* index) return true; } - if (!jsop_getelem_dense(obj, index, unboxedType)) + if (!jsop_getelem_dense(obj, index)) return false; trackOptimizationSuccess(); @@ -9826,7 +9795,7 @@ IonBuilder::computeHeapType(const TemporaryTypeSet* objTypes, const jsid id) } bool -IonBuilder::jsop_getelem_dense(MDefinition* obj, MDefinition* index, JSValueType unboxedType) +IonBuilder::jsop_getelem_dense(MDefinition* obj, MDefinition* index) { TemporaryTypeSet* types = bytecodeTypes(pc); @@ -9850,7 +9819,7 @@ IonBuilder::jsop_getelem_dense(MDefinition* obj, MDefinition* index, JSValueType !ElementAccessHasExtraIndexedProperty(this, obj); MIRType knownType = MIRType::Value; - if (unboxedType == JSVAL_TYPE_MAGIC && barrier == BarrierKind::NoBarrier) + if (barrier == BarrierKind::NoBarrier) knownType = GetElemKnownType(needsHoleCheck, types); // Ensure index is an integer. @@ -9859,13 +9828,13 @@ IonBuilder::jsop_getelem_dense(MDefinition* obj, MDefinition* index, JSValueType index = idInt32; // Get the elements vector. - MInstruction* elements = MElements::New(alloc(), obj, unboxedType != JSVAL_TYPE_MAGIC); + MInstruction* elements = MElements::New(alloc(), obj); current->add(elements); // Note: to help GVN, use the original MElements instruction and not // MConvertElementsToDoubles as operand. This is fine because converting // elements to double does not change the initialized length. - MInstruction* initLength = initializedLength(obj, elements, unboxedType); + MInstruction* initLength = initializedLength(obj, elements); // If we can load the element as a definite double, make sure to check that // the array has been converted to homogenous doubles first. @@ -9881,7 +9850,6 @@ IonBuilder::jsop_getelem_dense(MDefinition* obj, MDefinition* index, JSValueType } bool loadDouble = - unboxedType == JSVAL_TYPE_MAGIC && barrier == BarrierKind::NoBarrier && loopDepth_ && inBounds && @@ -9900,18 +9868,13 @@ IonBuilder::jsop_getelem_dense(MDefinition* obj, MDefinition* index, JSValueType // hoisting. index = addBoundsCheck(index, initLength); - if (unboxedType != JSVAL_TYPE_MAGIC) { - load = loadUnboxedValue(elements, 0, index, unboxedType, barrier, types); - } else { - load = MLoadElement::New(alloc(), elements, index, needsHoleCheck, loadDouble); - current->add(load); - } + load = MLoadElement::New(alloc(), elements, index, needsHoleCheck, loadDouble); + current->add(load); } else { // This load may return undefined, so assume that we *can* read holes, // or that we can read out-of-bounds accesses. In this case, the bounds // check is part of the opcode. - load = MLoadElementHole::New(alloc(), elements, index, initLength, - unboxedType, needsHoleCheck); + load = MLoadElementHole::New(alloc(), elements, index, initLength, needsHoleCheck); current->add(load); // If maybeUndefined was true, the typeset must have undefined, and @@ -9921,8 +9884,7 @@ IonBuilder::jsop_getelem_dense(MDefinition* obj, MDefinition* index, JSValueType } if (knownType != MIRType::Value) { - if (unboxedType == JSVAL_TYPE_MAGIC) - load->setResultType(knownType); + load->setResultType(knownType); load->setResultTypeSet(types); } @@ -10369,12 +10331,9 @@ IonBuilder::setElemTryDense(bool* emitted, MDefinition* object, { MOZ_ASSERT(*emitted == false); - JSValueType unboxedType = UnboxedArrayElementType(constraints(), object, index); - if (unboxedType == JSVAL_TYPE_MAGIC) { - if (!ElementAccessIsDenseNative(constraints(), object, index)) { - trackOptimizationOutcome(TrackedOutcome::AccessNotDense); - return true; - } + if (!ElementAccessIsDenseNative(constraints(), object, index)) { + trackOptimizationOutcome(TrackedOutcome::AccessNotDense); + return true; } if (PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current, @@ -10408,7 +10367,7 @@ IonBuilder::setElemTryDense(bool* emitted, MDefinition* object, } // Emit dense setelem variant. - if (!jsop_setelem_dense(conversion, object, index, value, unboxedType, writeHole, emitted)) + if (!jsop_setelem_dense(conversion, object, index, value, writeHole, emitted)) return false; if (!*emitted) { @@ -10498,13 +10457,11 @@ IonBuilder::setElemTryCache(bool* emitted, MDefinition* object, bool IonBuilder::jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion, MDefinition* obj, MDefinition* id, MDefinition* value, - JSValueType unboxedType, bool writeHole, bool* emitted) + bool writeHole, bool* emitted) { MOZ_ASSERT(*emitted == false); - MIRType elementType = MIRType::None; - if (unboxedType == JSVAL_TYPE_MAGIC) - elementType = DenseNativeElementType(constraints(), obj); + MIRType elementType = DenseNativeElementType(constraints(), obj); bool packed = ElementAccessIsPacked(constraints(), obj); // Writes which are on holes in the object do not have to bail out if they @@ -10534,7 +10491,7 @@ IonBuilder::jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion, obj = addMaybeCopyElementsForWrite(obj, /* checkNative = */ false); // Get the elements vector. - MElements* elements = MElements::New(alloc(), obj, unboxedType != JSVAL_TYPE_MAGIC); + MElements* elements = MElements::New(alloc(), obj); current->add(elements); // Ensure the value is a double, if double conversion might be needed. @@ -10571,7 +10528,7 @@ IonBuilder::jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion, MInstruction* store; MStoreElementCommon* common = nullptr; if (writeHole && hasNoExtraIndexedProperty && !mayBeFrozen) { - MStoreElementHole* ins = MStoreElementHole::New(alloc(), obj, elements, id, newValue, unboxedType); + MStoreElementHole* ins = MStoreElementHole::New(alloc(), obj, elements, id, newValue); store = ins; common = ins; @@ -10583,27 +10540,23 @@ IonBuilder::jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion, bool strict = IsStrictSetPC(pc); MFallibleStoreElement* ins = MFallibleStoreElement::New(alloc(), obj, elements, id, - newValue, unboxedType, strict); + newValue, strict); store = ins; common = ins; current->add(ins); current->push(value); } else { - MInstruction* initLength = initializedLength(obj, elements, unboxedType); + MInstruction* initLength = initializedLength(obj, elements); id = addBoundsCheck(id, initLength); bool needsHoleCheck = !packed && !hasNoExtraIndexedProperty; - if (unboxedType != JSVAL_TYPE_MAGIC) { - store = storeUnboxedValue(obj, elements, 0, id, unboxedType, newValue); - } else { - MStoreElement* ins = MStoreElement::New(alloc(), elements, id, newValue, needsHoleCheck); - store = ins; - common = ins; + MStoreElement* ins = MStoreElement::New(alloc(), elements, id, newValue, needsHoleCheck); + store = ins; + common = ins; - current->add(store); - } + current->add(store); current->push(value); } @@ -10721,18 +10674,6 @@ IonBuilder::jsop_length_fastPath() return true; } - // Compute the length for unboxed array objects. - if (UnboxedArrayElementType(constraints(), obj, nullptr) != JSVAL_TYPE_MAGIC && - !objTypes->hasObjectFlags(constraints(), OBJECT_FLAG_LENGTH_OVERFLOW)) - { - current->pop(); - - MUnboxedArrayLength* length = MUnboxedArrayLength::New(alloc(), obj); - current->add(length); - current->push(length); - return true; - } - // Compute the length for array typed objects. TypedObjectPrediction prediction = typedObjectPrediction(obj); if (!prediction.isUseless()) { @@ -13687,11 +13628,8 @@ IonBuilder::inTryDense(bool* emitted, MDefinition* obj, MDefinition* id) if (shouldAbortOnPreliminaryGroups(obj)) return true; - JSValueType unboxedType = UnboxedArrayElementType(constraints(), obj, id); - if (unboxedType == JSVAL_TYPE_MAGIC) { - if (!ElementAccessIsDenseNative(constraints(), obj, id)) - return true; - } + if (!ElementAccessIsDenseNative(constraints(), obj, id)) + return true; if (ElementAccessHasExtraIndexedProperty(this, obj)) return true; @@ -13706,10 +13644,10 @@ IonBuilder::inTryDense(bool* emitted, MDefinition* obj, MDefinition* id) id = idInt32; // Get the elements vector. - MElements* elements = MElements::New(alloc(), obj, unboxedType != JSVAL_TYPE_MAGIC); + MElements* elements = MElements::New(alloc(), obj); current->add(elements); - MInstruction* initLength = initializedLength(obj, elements, unboxedType); + MInstruction* initLength = initializedLength(obj, elements); // If there are no holes, speculate the InArray check will not fail. if (!needsHoleCheck && !failedBoundsCheck_) { @@ -13719,8 +13657,7 @@ IonBuilder::inTryDense(bool* emitted, MDefinition* obj, MDefinition* id) } // Check if id < initLength and elem[id] not a hole. - MInArray* ins = MInArray::New(alloc(), elements, id, initLength, obj, needsHoleCheck, - unboxedType); + MInArray* ins = MInArray::New(alloc(), elements, id, initLength, obj, needsHoleCheck); current->add(ins); current->push(ins); @@ -14398,32 +14335,24 @@ IonBuilder::constantInt(int32_t i) } MInstruction* -IonBuilder::initializedLength(MDefinition* obj, MDefinition* elements, JSValueType unboxedType) +IonBuilder::initializedLength(MDefinition* obj, MDefinition* elements) { - MInstruction* res; - if (unboxedType != JSVAL_TYPE_MAGIC) - res = MUnboxedArrayInitializedLength::New(alloc(), obj); - else - res = MInitializedLength::New(alloc(), elements); + MInstruction* res = MInitializedLength::New(alloc(), elements); current->add(res); return res; } MInstruction* -IonBuilder::setInitializedLength(MDefinition* obj, JSValueType unboxedType, size_t count) +IonBuilder::setInitializedLength(MDefinition* obj, size_t count) { MOZ_ASSERT(count); - MInstruction* res; - if (unboxedType != JSVAL_TYPE_MAGIC) { - res = MSetUnboxedArrayInitializedLength::New(alloc(), obj, constant(Int32Value(count))); - } else { - // MSetInitializedLength takes the index of the last element, rather - // than the count itself. - MInstruction* elements = MElements::New(alloc(), obj, /* unboxed = */ false); - current->add(elements); - res = MSetInitializedLength::New(alloc(), elements, constant(Int32Value(count - 1))); - } + // MSetInitializedLength takes the index of the last element, rather + // than the count itself. + MInstruction* elements = MElements::New(alloc(), obj, /* unboxed = */ false); + current->add(elements); + MInstruction* res = + MSetInitializedLength::New(alloc(), elements, constant(Int32Value(count - 1))); current->add(res); return res; } diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index 77528ad37..1b97c4743 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -346,9 +346,8 @@ class IonBuilder MConstant* constant(const Value& v); MConstant* constantInt(int32_t i); - MInstruction* initializedLength(MDefinition* obj, MDefinition* elements, - JSValueType unboxedType); - MInstruction* setInitializedLength(MDefinition* obj, JSValueType unboxedType, size_t count); + MInstruction* initializedLength(MDefinition* obj, MDefinition* elements); + MInstruction* setInitializedLength(MDefinition* obj, size_t count); // Improve the type information at tests MOZ_MUST_USE bool improveTypesAtTest(MDefinition* ins, bool trueBranch, MTest* test); @@ -611,7 +610,6 @@ class IonBuilder TypedObjectPrediction elemTypeReprs, uint32_t elemSize); MOZ_MUST_USE bool initializeArrayElement(MDefinition* obj, size_t index, MDefinition* value, - JSValueType unboxedType, bool addResumePointAndIncrementInitializedLength); // jsop_getelem() helpers. @@ -723,15 +721,13 @@ class IonBuilder MOZ_MUST_USE bool jsop_bindname(PropertyName* name); MOZ_MUST_USE bool jsop_bindvar(); MOZ_MUST_USE bool jsop_getelem(); - MOZ_MUST_USE bool jsop_getelem_dense(MDefinition* obj, MDefinition* index, - JSValueType unboxedType); + MOZ_MUST_USE bool jsop_getelem_dense(MDefinition* obj, MDefinition* index); MOZ_MUST_USE bool jsop_getelem_typed(MDefinition* obj, MDefinition* index, ScalarTypeDescr::Type arrayType); MOZ_MUST_USE bool jsop_setelem(); MOZ_MUST_USE bool jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion, MDefinition* object, MDefinition* index, - MDefinition* value, JSValueType unboxedType, - bool writeHole, bool* emitted); + MDefinition* value, bool writeHole, bool* emitted); MOZ_MUST_USE bool jsop_setelem_typed(ScalarTypeDescr::Type arrayType, MDefinition* object, MDefinition* index, MDefinition* value); diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index 96e488ea8..0a53f178f 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -638,9 +638,6 @@ TestMatchingReceiver(MacroAssembler& masm, IonCache::StubAttacher& attacher, } else { masm.branchPtr(Assembler::NotEqual, expandoAddress, ImmWord(0), failure); } - } else if (obj->is()) { - MOZ_ASSERT(failure); - masm.branchTestObjGroup(Assembler::NotEqual, object, obj->group(), failure); } else if (obj->is()) { attacher.branchNextStubOrLabel(masm, Assembler::NotEqual, Address(object, JSObject::offsetOfGroup()), @@ -1187,39 +1184,6 @@ GenerateArrayLength(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& return true; } -static void -GenerateUnboxedArrayLength(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& attacher, - JSObject* array, Register object, TypedOrValueRegister output, - Label* failures) -{ - Register outReg; - if (output.hasValue()) { - outReg = output.valueReg().scratchReg(); - } else { - MOZ_ASSERT(output.type() == MIRType::Int32); - outReg = output.typedReg().gpr(); - } - MOZ_ASSERT(object != outReg); - - TestMatchingReceiver(masm, attacher, object, array, failures); - - // Load length. - masm.load32(Address(object, UnboxedArrayObject::offsetOfLength()), outReg); - - // Check for a length that fits in an int32. - masm.branchTest32(Assembler::Signed, outReg, outReg, failures); - - if (output.hasValue()) - masm.tagValue(JSVAL_TYPE_INT32, outReg, output.valueReg()); - - // Success. - attacher.jumpRejoin(masm); - - // Failure. - masm.bind(failures); - attacher.jumpNextStub(masm); -} - // In this case, the code for TypedArray and SharedTypedArray is not the same, // because the code embeds pointers to the respective class arrays. Code that // caches the stub code must distinguish between the two cases. @@ -1593,40 +1557,6 @@ GetPropertyIC::tryAttachUnboxedExpando(JSContext* cx, HandleScript outerScript, JS::TrackedOutcome::ICGetPropStub_UnboxedReadExpando); } -bool -GetPropertyIC::tryAttachUnboxedArrayLength(JSContext* cx, HandleScript outerScript, IonScript* ion, - HandleObject obj, HandleId id, void* returnAddr, - bool* emitted) -{ - MOZ_ASSERT(canAttachStub()); - MOZ_ASSERT(!*emitted); - MOZ_ASSERT(outerScript->ionScript() == ion); - - if (!obj->is()) - return true; - - if (!JSID_IS_ATOM(id, cx->names().length)) - return true; - - if (obj->as().length() > INT32_MAX) - return true; - - if (!allowArrayLength(cx)) - return true; - - *emitted = true; - - MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_); - - Label failures; - emitIdGuard(masm, id, &failures); - - StubAttacher attacher(*this); - GenerateUnboxedArrayLength(cx, masm, attacher, obj, object(), output(), &failures); - return linkAndAttachStub(cx, masm, attacher, ion, "unboxed array length", - JS::TrackedOutcome::ICGetPropStub_UnboxedArrayLength); -} - bool GetPropertyIC::tryAttachTypedArrayLength(JSContext* cx, HandleScript outerScript, IonScript* ion, HandleObject obj, HandleId id, bool* emitted) @@ -2202,9 +2132,6 @@ GetPropertyIC::tryAttachStub(JSContext* cx, HandleScript outerScript, IonScript* if (!*emitted && !tryAttachUnboxedExpando(cx, outerScript, ion, obj, id, returnAddr, emitted)) return false; - if (!*emitted && !tryAttachUnboxedArrayLength(cx, outerScript, ion, obj, id, returnAddr, emitted)) - return false; - if (!*emitted && !tryAttachTypedArrayLength(cx, outerScript, ion, obj, id, emitted)) return false; } @@ -4025,7 +3952,7 @@ GetPropertyIC::tryAttachDenseElementHole(JSContext* cx, HandleScript outerScript GetPropertyIC::canAttachTypedOrUnboxedArrayElement(JSObject* obj, const Value& idval, TypedOrValueRegister output) { - if (!obj->is() && !obj->is()) + if (!obj->is()) return false; MOZ_ASSERT(idval.isInt32() || idval.isString()); @@ -4056,13 +3983,6 @@ GetPropertyIC::canAttachTypedOrUnboxedArrayElement(JSObject* obj, const Value& i return output.hasValue() || !output.typedReg().isFloat(); } - if (index >= obj->as().initializedLength()) - return false; - - JSValueType elementType = obj->as().elementType(); - if (elementType == JSVAL_TYPE_DOUBLE) - return output.hasValue(); - return output.hasValue() || !output.typedReg().isFloat(); } @@ -4139,46 +4059,27 @@ GenerateGetTypedOrUnboxedArrayElement(JSContext* cx, MacroAssembler& masm, Label popObjectAndFail; - if (array->is()) { - // Guard on the initialized length. - Address length(object, TypedArrayObject::lengthOffset()); - masm.branch32(Assembler::BelowOrEqual, length, indexReg, &failures); + // Guard on the initialized length. + Address length(object, TypedArrayObject::lengthOffset()); + masm.branch32(Assembler::BelowOrEqual, length, indexReg, &failures); - // Save the object register on the stack in case of failure. - Register elementReg = object; - masm.push(object); + // Save the object register on the stack in case of failure. + Register elementReg = object; + masm.push(object); - // Load elements vector. - masm.loadPtr(Address(object, TypedArrayObject::dataOffset()), elementReg); + // Load elements vector. + masm.loadPtr(Address(object, TypedArrayObject::dataOffset()), elementReg); - // Load the value. We use an invalid register because the destination - // register is necessary a non double register. - Scalar::Type arrayType = array->as().type(); - int width = Scalar::byteSize(arrayType); - BaseIndex source(elementReg, indexReg, ScaleFromElemWidth(width)); - if (output.hasValue()) { - masm.loadFromTypedArray(arrayType, source, output.valueReg(), allowDoubleResult, - elementReg, &popObjectAndFail); - } else { - masm.loadFromTypedArray(arrayType, source, output.typedReg(), elementReg, &popObjectAndFail); - } + // Load the value. We use an invalid register because the destination + // register is necessary a non double register. + Scalar::Type arrayType = array->as().type(); + int width = Scalar::byteSize(arrayType); + BaseIndex source(elementReg, indexReg, ScaleFromElemWidth(width)); + if (output.hasValue()) { + masm.loadFromTypedArray(arrayType, source, output.valueReg(), allowDoubleResult, + elementReg, &popObjectAndFail); } else { - // Save the object register on the stack in case of failure. - masm.push(object); - - // Guard on the initialized length. - masm.load32(Address(object, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), object); - masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), object); - masm.branch32(Assembler::BelowOrEqual, object, indexReg, &popObjectAndFail); - - // Load elements vector. - Register elementReg = object; - masm.loadPtr(Address(masm.getStackPointer(), 0), object); - masm.loadPtr(Address(object, UnboxedArrayObject::offsetOfElements()), elementReg); - - JSValueType elementType = array->as().elementType(); - BaseIndex source(elementReg, indexReg, ScaleFromElemWidth(UnboxedTypeSize(elementType))); - masm.loadUnboxedProperty(source, elementType, output); + masm.loadFromTypedArray(arrayType, source, output.typedReg(), elementReg, &popObjectAndFail); } masm.pop(object); diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index aafa57c09..e185b5746 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -2888,32 +2888,6 @@ LIRGenerator::visitSetInitializedLength(MSetInitializedLength* ins) useRegisterOrConstant(ins->index())), ins); } -void -LIRGenerator::visitUnboxedArrayLength(MUnboxedArrayLength* ins) -{ - define(new(alloc()) LUnboxedArrayLength(useRegisterAtStart(ins->object())), ins); -} - -void -LIRGenerator::visitUnboxedArrayInitializedLength(MUnboxedArrayInitializedLength* ins) -{ - define(new(alloc()) LUnboxedArrayInitializedLength(useRegisterAtStart(ins->object())), ins); -} - -void -LIRGenerator::visitIncrementUnboxedArrayInitializedLength(MIncrementUnboxedArrayInitializedLength* ins) -{ - add(new(alloc()) LIncrementUnboxedArrayInitializedLength(useRegister(ins->object())), ins); -} - -void -LIRGenerator::visitSetUnboxedArrayInitializedLength(MSetUnboxedArrayInitializedLength* ins) -{ - add(new(alloc()) LSetUnboxedArrayInitializedLength(useRegister(ins->object()), - useRegisterOrConstant(ins->length()), - temp()), ins); -} - void LIRGenerator::visitNot(MNot* ins) { @@ -3165,8 +3139,6 @@ LIRGenerator::visitStoreElementHole(MStoreElementHole* ins) // Use a temp register when adding new elements to unboxed arrays. LDefinition tempDef = LDefinition::BogusTemp(); - if (ins->unboxedType() != JSVAL_TYPE_MAGIC) - tempDef = temp(); LInstruction* lir; switch (ins->value()->type()) { @@ -3199,8 +3171,6 @@ LIRGenerator::visitFallibleStoreElement(MFallibleStoreElement* ins) // Use a temp register when adding new elements to unboxed arrays. LDefinition tempDef = LDefinition::BogusTemp(); - if (ins->unboxedType() != JSVAL_TYPE_MAGIC) - tempDef = temp(); LInstruction* lir; switch (ins->value()->type()) { diff --git a/js/src/jit/Lowering.h b/js/src/jit/Lowering.h index e36620bce..b096bb143 100644 --- a/js/src/jit/Lowering.h +++ b/js/src/jit/Lowering.h @@ -216,10 +216,6 @@ class LIRGenerator : public LIRGeneratorSpecific void visitTypedObjectDescr(MTypedObjectDescr* ins); void visitInitializedLength(MInitializedLength* ins); void visitSetInitializedLength(MSetInitializedLength* ins); - void visitUnboxedArrayLength(MUnboxedArrayLength* ins); - void visitUnboxedArrayInitializedLength(MUnboxedArrayInitializedLength* ins); - void visitIncrementUnboxedArrayInitializedLength(MIncrementUnboxedArrayInitializedLength* ins); - void visitSetUnboxedArrayInitializedLength(MSetUnboxedArrayInitializedLength* ins); void visitNot(MNot* ins); void visitBoundsCheck(MBoundsCheck* ins); void visitBoundsCheckLower(MBoundsCheckLower* ins); diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 41ccd0ca7..7283497ea 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -475,11 +475,6 @@ IonBuilder::inlineArray(CallInfo& callInfo) return InliningStatus_NotInlined; } - if (templateObject->is()) { - if (templateObject->group()->unboxedLayout().nativeGroup()) - return InliningStatus_NotInlined; - } - // Multiple arguments imply array initialization, not just construction. if (callInfo.argc() >= 2) { initLength = callInfo.argc(); @@ -542,16 +537,15 @@ IonBuilder::inlineArray(CallInfo& callInfo) MDefinition* array = current->peek(-1); if (callInfo.argc() >= 2) { - JSValueType unboxedType = GetBoxedOrUnboxedType(templateObject); for (uint32_t i = 0; i < initLength; i++) { if (!alloc().ensureBallast()) return InliningStatus_Error; MDefinition* value = callInfo.getArg(i); - if (!initializeArrayElement(array, i, value, unboxedType, /* addResumePoint = */ false)) + if (!initializeArrayElement(array, i, /* addResumePoint = */ false)) return InliningStatus_Error; } - MInstruction* setLength = setInitializedLength(array, unboxedType, initLength); + MInstruction* setLength = setInitializedLength(array, initLength); if (!resumeAfter(setLength)) return InliningStatus_Error; } @@ -620,7 +614,7 @@ IonBuilder::inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode) if (!thisTypes) return InliningStatus_NotInlined; const Class* clasp = thisTypes->getKnownClass(constraints()); - if (clasp != &ArrayObject::class_ && clasp != &UnboxedArrayObject::class_) + if (clasp != &ArrayObject::class_) return InliningStatus_NotInlined; if (thisTypes->hasObjectFlags(constraints(), unhandledFlags)) { trackOptimizationOutcome(TrackedOutcome::ArrayBadFlags); @@ -632,17 +626,9 @@ IonBuilder::inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode) return InliningStatus_NotInlined; } - JSValueType unboxedType = JSVAL_TYPE_MAGIC; - if (clasp == &UnboxedArrayObject::class_) { - unboxedType = UnboxedArrayElementType(constraints(), obj, nullptr); - if (unboxedType == JSVAL_TYPE_MAGIC) - return InliningStatus_NotInlined; - } - callInfo.setImplicitlyUsedUnchecked(); - if (clasp == &ArrayObject::class_) - obj = addMaybeCopyElementsForWrite(obj, /* checkNative = */ false); + obj = addMaybeCopyElementsForWrite(obj, /* checkNative = */ false); TemporaryTypeSet* returnTypes = getInlineReturnTypeSet(); bool needsHoleCheck = thisTypes->hasObjectFlags(constraints(), OBJECT_FLAG_NON_PACKED); @@ -653,8 +639,7 @@ IonBuilder::inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode) if (barrier != BarrierKind::NoBarrier) returnType = MIRType::Value; - MArrayPopShift* ins = MArrayPopShift::New(alloc(), obj, mode, - unboxedType, needsHoleCheck, maybeUndefined); + MArrayPopShift* ins = MArrayPopShift::New(alloc(), obj, mode, needsHoleCheck, maybeUndefined); current->add(ins); current->push(ins); ins->setResultType(returnType); @@ -761,7 +746,7 @@ IonBuilder::inlineArrayPush(CallInfo& callInfo) if (!thisTypes) return InliningStatus_NotInlined; const Class* clasp = thisTypes->getKnownClass(constraints()); - if (clasp != &ArrayObject::class_ && clasp != &UnboxedArrayObject::class_) + if (clasp != &ArrayObject::class_) return InliningStatus_NotInlined; if (thisTypes->hasObjectFlags(constraints(), OBJECT_FLAG_SPARSE_INDEXES | OBJECT_FLAG_LENGTH_OVERFLOW)) @@ -782,13 +767,6 @@ IonBuilder::inlineArrayPush(CallInfo& callInfo) return InliningStatus_NotInlined; } - JSValueType unboxedType = JSVAL_TYPE_MAGIC; - if (clasp == &UnboxedArrayObject::class_) { - unboxedType = UnboxedArrayElementType(constraints(), obj, nullptr); - if (unboxedType == JSVAL_TYPE_MAGIC) - return InliningStatus_NotInlined; - } - callInfo.setImplicitlyUsedUnchecked(); if (conversion == TemporaryTypeSet::AlwaysConvertToDoubles || @@ -799,13 +777,12 @@ IonBuilder::inlineArrayPush(CallInfo& callInfo) value = valueDouble; } - if (unboxedType == JSVAL_TYPE_MAGIC) - obj = addMaybeCopyElementsForWrite(obj, /* checkNative = */ false); + obj = addMaybeCopyElementsForWrite(obj, /* checkNative = */ false); if (NeedsPostBarrier(value)) current->add(MPostWriteBarrier::New(alloc(), obj, value)); - MArrayPush* ins = MArrayPush::New(alloc(), obj, value, unboxedType); + MArrayPush* ins = MArrayPush::New(alloc(), obj, value); current->add(ins); current->push(ins); @@ -846,7 +823,7 @@ IonBuilder::inlineArraySlice(CallInfo& callInfo) return InliningStatus_NotInlined; const Class* clasp = thisTypes->getKnownClass(constraints()); - if (clasp != &ArrayObject::class_ && clasp != &UnboxedArrayObject::class_) + if (clasp != &ArrayObject::class_) return InliningStatus_NotInlined; if (thisTypes->hasObjectFlags(constraints(), OBJECT_FLAG_SPARSE_INDEXES | OBJECT_FLAG_LENGTH_OVERFLOW)) @@ -855,13 +832,6 @@ IonBuilder::inlineArraySlice(CallInfo& callInfo) return InliningStatus_NotInlined; } - JSValueType unboxedType = JSVAL_TYPE_MAGIC; - if (clasp == &UnboxedArrayObject::class_) { - unboxedType = UnboxedArrayElementType(constraints(), obj, nullptr); - if (unboxedType == JSVAL_TYPE_MAGIC) - return InliningStatus_NotInlined; - } - // Watch out for indexed properties on the prototype. if (ArrayPrototypeHasIndexedProperty(this, script())) { trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps); @@ -882,15 +852,8 @@ IonBuilder::inlineArraySlice(CallInfo& callInfo) if (!templateObj) return InliningStatus_NotInlined; - if (unboxedType == JSVAL_TYPE_MAGIC) { - if (!templateObj->is()) - return InliningStatus_NotInlined; - } else { - if (!templateObj->is()) - return InliningStatus_NotInlined; - if (templateObj->as().elementType() != unboxedType) - return InliningStatus_NotInlined; - } + if (!templateObj->is()) + return InliningStatus_NotInlined; callInfo.setImplicitlyUsedUnchecked(); @@ -909,16 +872,12 @@ IonBuilder::inlineArraySlice(CallInfo& callInfo) end = MArrayLength::New(alloc(), elements); current->add(end->toInstruction()); - } else { - end = MUnboxedArrayLength::New(alloc(), obj); - current->add(end->toInstruction()); } MArraySlice* ins = MArraySlice::New(alloc(), constraints(), obj, begin, end, templateObj, - templateObj->group()->initialHeap(constraints()), - unboxedType); + templateObj->group()->initialHeap(constraints())); current->add(ins); current->push(ins); @@ -1500,8 +1459,6 @@ IonBuilder::inlineConstantStringSplitString(CallInfo& callInfo) return InliningStatus_Inlined; } - JSValueType unboxedType = GetBoxedOrUnboxedType(templateObject); - // Store all values, no need to initialize the length after each as // jsop_initelem_array is doing because we do not expect to bailout // because the memory is supposed to be allocated by now. @@ -1512,11 +1469,11 @@ IonBuilder::inlineConstantStringSplitString(CallInfo& callInfo) MConstant* value = arrayValues[i]; current->add(value); - if (!initializeArrayElement(array, i, value, unboxedType, /* addResumePoint = */ false)) + if (!initializeArrayElement(array, i, value, /* addResumePoint = */ false)) return InliningStatus_Error; } - MInstruction* setLength = setInitializedLength(array, unboxedType, initLength); + MInstruction* setLength = setInitializedLength(array, initLength); if (!resumeAfter(setLength)) return InliningStatus_Error; diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 1f33b2174..6aa46be4b 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -5823,46 +5823,6 @@ jit::ElementAccessIsDenseNative(CompilerConstraintList* constraints, return clasp && clasp->isNative() && !IsTypedArrayClass(clasp); } -JSValueType -jit::UnboxedArrayElementType(CompilerConstraintList* constraints, MDefinition* obj, - MDefinition* id) -{ - if (obj->mightBeType(MIRType::String)) - return JSVAL_TYPE_MAGIC; - - if (id && id->type() != MIRType::Int32 && id->type() != MIRType::Double) - return JSVAL_TYPE_MAGIC; - - TemporaryTypeSet* types = obj->resultTypeSet(); - if (!types || types->unknownObject()) - return JSVAL_TYPE_MAGIC; - - JSValueType elementType = JSVAL_TYPE_MAGIC; - for (unsigned i = 0; i < types->getObjectCount(); i++) { - TypeSet::ObjectKey* key = types->getObject(i); - if (!key) - continue; - - if (key->unknownProperties() || !key->isGroup()) - return JSVAL_TYPE_MAGIC; - - if (key->clasp() != &UnboxedArrayObject::class_) - return JSVAL_TYPE_MAGIC; - - const UnboxedLayout &layout = key->group()->unboxedLayout(); - - if (layout.nativeGroup()) - return JSVAL_TYPE_MAGIC; - - if (elementType == layout.elementType() || elementType == JSVAL_TYPE_MAGIC) - elementType = layout.elementType(); - else - return JSVAL_TYPE_MAGIC; - } - - return elementType; -} - bool jit::ElementAccessIsTypedArray(CompilerConstraintList* constraints, MDefinition* obj, MDefinition* id, @@ -6022,11 +5982,6 @@ ObjectSubsumes(TypeSet::ObjectKey* first, TypeSet::ObjectKey* second) firstElements.maybeTypes()->equals(secondElements.maybeTypes()); } - if (first->clasp() == &UnboxedArrayObject::class_) { - return first->group()->unboxedLayout().elementType() == - second->group()->unboxedLayout().elementType(); - } - return false; } diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 3e0421789..cdd737b56 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -375,8 +375,7 @@ class AliasSet { Element = 1 << 1, // A Value member of obj->elements or // a typed object. UnboxedElement = 1 << 2, // An unboxed scalar or reference member of - // a typed array, typed object, or unboxed - // object. + // typed object or unboxed object. DynamicSlot = 1 << 3, // A Value member of obj->slots. FixedSlot = 1 << 4, // A Value member of obj->fixedSlots(). DOMProperty = 1 << 5, // A DOM property @@ -433,9 +432,6 @@ class AliasSet { MOZ_ASSERT(flags && !(flags & Store_)); return AliasSet(flags | Store_); } - static uint32_t BoxedOrUnboxedElements(JSValueType type) { - return (type == JSVAL_TYPE_MAGIC) ? Element : UnboxedElement; - } }; typedef Vector MDefinitionVector; @@ -8745,102 +8741,6 @@ class MSetInitializedLength ALLOW_CLONE(MSetInitializedLength) }; -// Load the length from an unboxed array. -class MUnboxedArrayLength - : public MUnaryInstruction, - public SingleObjectPolicy::Data -{ - explicit MUnboxedArrayLength(MDefinition* object) - : MUnaryInstruction(object) - { - setResultType(MIRType::Int32); - setMovable(); - } - - public: - INSTRUCTION_HEADER(UnboxedArrayLength) - TRIVIAL_NEW_WRAPPERS - NAMED_OPERANDS((0, object)) - - bool congruentTo(const MDefinition* ins) const override { - return congruentIfOperandsEqual(ins); - } - AliasSet getAliasSet() const override { - return AliasSet::Load(AliasSet::ObjectFields); - } - - ALLOW_CLONE(MUnboxedArrayLength) -}; - -// Load the initialized length from an unboxed array. -class MUnboxedArrayInitializedLength - : public MUnaryInstruction, - public SingleObjectPolicy::Data -{ - explicit MUnboxedArrayInitializedLength(MDefinition* object) - : MUnaryInstruction(object) - { - setResultType(MIRType::Int32); - setMovable(); - } - - public: - INSTRUCTION_HEADER(UnboxedArrayInitializedLength) - TRIVIAL_NEW_WRAPPERS - NAMED_OPERANDS((0, object)) - - bool congruentTo(const MDefinition* ins) const override { - return congruentIfOperandsEqual(ins); - } - AliasSet getAliasSet() const override { - return AliasSet::Load(AliasSet::ObjectFields); - } - - ALLOW_CLONE(MUnboxedArrayInitializedLength) -}; - -// Increment the initialized length of an unboxed array object. -class MIncrementUnboxedArrayInitializedLength - : public MUnaryInstruction, - public SingleObjectPolicy::Data -{ - explicit MIncrementUnboxedArrayInitializedLength(MDefinition* obj) - : MUnaryInstruction(obj) - {} - - public: - INSTRUCTION_HEADER(IncrementUnboxedArrayInitializedLength) - TRIVIAL_NEW_WRAPPERS - NAMED_OPERANDS((0, object)) - - AliasSet getAliasSet() const override { - return AliasSet::Store(AliasSet::ObjectFields); - } - - ALLOW_CLONE(MIncrementUnboxedArrayInitializedLength) -}; - -// Set the initialized length of an unboxed array object. -class MSetUnboxedArrayInitializedLength - : public MBinaryInstruction, - public SingleObjectPolicy::Data -{ - explicit MSetUnboxedArrayInitializedLength(MDefinition* obj, MDefinition* length) - : MBinaryInstruction(obj, length) - {} - - public: - INSTRUCTION_HEADER(SetUnboxedArrayInitializedLength) - TRIVIAL_NEW_WRAPPERS - NAMED_OPERANDS((0, object), (1, length)) - - AliasSet getAliasSet() const override { - return AliasSet::Store(AliasSet::ObjectFields); - } - - ALLOW_CLONE(MSetUnboxedArrayInitializedLength) -}; - // Load the array length from an elements header. class MArrayLength : public MUnaryInstruction, @@ -9341,16 +9241,12 @@ class MLoadElementHole : public MTernaryInstruction, public SingleObjectPolicy::Data { - // Unboxed element type, JSVAL_TYPE_MAGIC for dense native elements. - JSValueType unboxedType_; - bool needsNegativeIntCheck_; bool needsHoleCheck_; MLoadElementHole(MDefinition* elements, MDefinition* index, MDefinition* initLength, JSValueType unboxedType, bool needsHoleCheck) : MTernaryInstruction(elements, index, initLength), - unboxedType_(unboxedType), needsNegativeIntCheck_(true), needsHoleCheck_(needsHoleCheck) { @@ -9372,9 +9268,6 @@ class MLoadElementHole TRIVIAL_NEW_WRAPPERS NAMED_OPERANDS((0, elements), (1, index), (2, initLength)) - JSValueType unboxedType() const { - return unboxedType_; - } bool needsNegativeIntCheck() const { return needsNegativeIntCheck_; } @@ -9385,8 +9278,6 @@ class MLoadElementHole if (!ins->isLoadElementHole()) return false; const MLoadElementHole* other = ins->toLoadElementHole(); - if (unboxedType() != other->unboxedType()) - return false; if (needsHoleCheck() != other->needsHoleCheck()) return false; if (needsNegativeIntCheck() != other->needsNegativeIntCheck()) @@ -9394,7 +9285,7 @@ class MLoadElementHole return congruentIfOperandsEqual(other); } AliasSet getAliasSet() const override { - return AliasSet::Load(AliasSet::BoxedOrUnboxedElements(unboxedType())); + return AliasSet::Load(AliasSet::Element); } void collectRangeInfoPreTrunc() override; @@ -9583,11 +9474,8 @@ class MStoreElementHole public MStoreElementCommon, public MixPolicy >::Data { - JSValueType unboxedType_; - MStoreElementHole(MDefinition* object, MDefinition* elements, - MDefinition* index, MDefinition* value, JSValueType unboxedType) - : unboxedType_(unboxedType) + MDefinition* index, MDefinition* value) { initOperand(0, object); initOperand(1, elements); @@ -9602,14 +9490,10 @@ class MStoreElementHole TRIVIAL_NEW_WRAPPERS NAMED_OPERANDS((0, object), (1, elements), (2, index), (3, value)) - JSValueType unboxedType() const { - return unboxedType_; - } AliasSet getAliasSet() const override { // StoreElementHole can update the initialized length, the array length // or reallocate obj->elements. - return AliasSet::Store(AliasSet::ObjectFields | - AliasSet::BoxedOrUnboxedElements(unboxedType())); + return AliasSet::Store(AliasSet::ObjectFields | AliasSet::Element); } ALLOW_CLONE(MStoreElementHole) @@ -9622,13 +9506,11 @@ class MFallibleStoreElement public MStoreElementCommon, public MixPolicy >::Data { - JSValueType unboxedType_; bool strict_; MFallibleStoreElement(MDefinition* object, MDefinition* elements, MDefinition* index, MDefinition* value, - JSValueType unboxedType, bool strict) - : unboxedType_(unboxedType) + bool strict) { initOperand(0, object); initOperand(1, elements); @@ -9644,12 +9526,8 @@ class MFallibleStoreElement TRIVIAL_NEW_WRAPPERS NAMED_OPERANDS((0, object), (1, elements), (2, index), (3, value)) - JSValueType unboxedType() const { - return unboxedType_; - } AliasSet getAliasSet() const override { - return AliasSet::Store(AliasSet::ObjectFields | - AliasSet::BoxedOrUnboxedElements(unboxedType())); + return AliasSet::Store(AliasSet::ObjectFields | AliasSet::Element); } bool strict() const { return strict_; @@ -9754,13 +9632,12 @@ class MArrayPopShift private: Mode mode_; - JSValueType unboxedType_; bool needsHoleCheck_; bool maybeUndefined_; - MArrayPopShift(MDefinition* object, Mode mode, JSValueType unboxedType, + MArrayPopShift(MDefinition* object, Mode mode, bool needsHoleCheck, bool maybeUndefined) - : MUnaryInstruction(object), mode_(mode), unboxedType_(unboxedType), + : MUnaryInstruction(object), mode_(mode), needsHoleCheck_(needsHoleCheck), maybeUndefined_(maybeUndefined) { } @@ -9778,12 +9655,8 @@ class MArrayPopShift bool mode() const { return mode_; } - JSValueType unboxedType() const { - return unboxedType_; - } AliasSet getAliasSet() const override { - return AliasSet::Store(AliasSet::ObjectFields | - AliasSet::BoxedOrUnboxedElements(unboxedType())); + return AliasSet::Store(AliasSet::ObjectFields | AliasSet::Element); } ALLOW_CLONE(MArrayPopShift) @@ -9794,10 +9667,8 @@ class MArrayPush : public MBinaryInstruction, public MixPolicy >::Data { - JSValueType unboxedType_; - - MArrayPush(MDefinition* object, MDefinition* value, JSValueType unboxedType) - : MBinaryInstruction(object, value), unboxedType_(unboxedType) + MArrayPush(MDefinition* object, MDefinition* value) + : MBinaryInstruction(object, value) { setResultType(MIRType::Int32); } @@ -9807,12 +9678,8 @@ class MArrayPush TRIVIAL_NEW_WRAPPERS NAMED_OPERANDS((0, object), (1, value)) - JSValueType unboxedType() const { - return unboxedType_; - } AliasSet getAliasSet() const override { - return AliasSet::Store(AliasSet::ObjectFields | - AliasSet::BoxedOrUnboxedElements(unboxedType())); + return AliasSet::Store(AliasSet::ObjectFields | AliasSet::Element); } void computeRange(TempAllocator& alloc) override; @@ -9826,15 +9693,13 @@ class MArraySlice { CompilerObject templateObj_; gc::InitialHeap initialHeap_; - JSValueType unboxedType_; MArraySlice(CompilerConstraintList* constraints, MDefinition* obj, MDefinition* begin, MDefinition* end, - JSObject* templateObj, gc::InitialHeap initialHeap, JSValueType unboxedType) + JSObject* templateObj, gc::InitialHeap initialHeap) : MTernaryInstruction(obj, begin, end), templateObj_(templateObj), - initialHeap_(initialHeap), - unboxedType_(unboxedType) + initialHeap_(initialHeap) { setResultType(MIRType::Object); } @@ -12224,15 +12089,13 @@ class MInArray { bool needsHoleCheck_; bool needsNegativeIntCheck_; - JSValueType unboxedType_; MInArray(MDefinition* elements, MDefinition* index, MDefinition* initLength, MDefinition* object, - bool needsHoleCheck, JSValueType unboxedType) + bool needsHoleCheck) : MQuaternaryInstruction(elements, index, initLength, object), needsHoleCheck_(needsHoleCheck), - needsNegativeIntCheck_(true), - unboxedType_(unboxedType) + needsNegativeIntCheck_(true) { setResultType(MIRType::Boolean); setMovable(); @@ -12252,9 +12115,6 @@ class MInArray bool needsNegativeIntCheck() const { return needsNegativeIntCheck_; } - JSValueType unboxedType() const { - return unboxedType_; - } void collectRangeInfoPreTrunc() override; AliasSet getAliasSet() const override { return AliasSet::Load(AliasSet::Element); @@ -12267,8 +12127,6 @@ class MInArray return false; if (needsNegativeIntCheck() != other->needsNegativeIntCheck()) return false; - if (unboxedType() != other->unboxedType()) - return false; return congruentIfOperandsEqual(other); } }; @@ -14169,8 +14027,6 @@ MDefinition::maybeConstantValue() bool ElementAccessIsDenseNative(CompilerConstraintList* constraints, MDefinition* obj, MDefinition* id); -JSValueType UnboxedArrayElementType(CompilerConstraintList* constraints, MDefinition* obj, - MDefinition* id); bool ElementAccessIsTypedArray(CompilerConstraintList* constraints, MDefinition* obj, MDefinition* id, Scalar::Type* arrayType); diff --git a/js/src/jit/MOpcodes.h b/js/src/jit/MOpcodes.h index b80d1baf9..ab37604b4 100644 --- a/js/src/jit/MOpcodes.h +++ b/js/src/jit/MOpcodes.h @@ -198,10 +198,6 @@ namespace jit { _(SetTypedObjectOffset) \ _(InitializedLength) \ _(SetInitializedLength) \ - _(UnboxedArrayLength) \ - _(UnboxedArrayInitializedLength) \ - _(IncrementUnboxedArrayInitializedLength) \ - _(SetUnboxedArrayInitializedLength) \ _(Not) \ _(BoundsCheck) \ _(BoundsCheckLower) \ diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp index f633b9b7b..e50f68722 100644 --- a/js/src/jit/MacroAssembler.cpp +++ b/js/src/jit/MacroAssembler.cpp @@ -705,31 +705,6 @@ template void MacroAssembler::storeUnboxedProperty(BaseIndex address, JSValueType type, const ConstantOrRegister& value, Label* failure); -void -MacroAssembler::checkUnboxedArrayCapacity(Register obj, const RegisterOrInt32Constant& index, - Register temp, Label* failure) -{ - Address initLengthAddr(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()); - Address lengthAddr(obj, UnboxedArrayObject::offsetOfLength()); - - Label capacityIsIndex, done; - load32(initLengthAddr, temp); - branchTest32(Assembler::NonZero, temp, Imm32(UnboxedArrayObject::CapacityMask), &capacityIsIndex); - branch32(Assembler::BelowOrEqual, lengthAddr, index, failure); - jump(&done); - bind(&capacityIsIndex); - - // Do a partial shift so that we can get an absolute offset from the base - // of CapacityArray to use. - JS_STATIC_ASSERT(sizeof(UnboxedArrayObject::CapacityArray[0]) == 4); - rshiftPtr(Imm32(UnboxedArrayObject::CapacityShift - 2), temp); - and32(Imm32(~0x3), temp); - - addPtr(ImmPtr(&UnboxedArrayObject::CapacityArray), temp); - branch32(Assembler::BelowOrEqual, Address(temp, 0), index, failure); - bind(&done); -} - // Inlined version of gc::CheckAllocatorState that checks the bare essentials // and bails for anything that cannot be handled with our jit allocators. void @@ -1281,16 +1256,6 @@ MacroAssembler::initGCThing(Register obj, Register temp, JSObject* templateObj, storePtr(ImmWord(0), Address(obj, UnboxedPlainObject::offsetOfExpando())); if (initContents) initUnboxedObjectContents(obj, &templateObj->as()); - } else if (templateObj->is()) { - MOZ_ASSERT(templateObj->as().hasInlineElements()); - int elementsOffset = UnboxedArrayObject::offsetOfInlineElements(); - computeEffectiveAddress(Address(obj, elementsOffset), temp); - storePtr(temp, Address(obj, UnboxedArrayObject::offsetOfElements())); - store32(Imm32(templateObj->as().length()), - Address(obj, UnboxedArrayObject::offsetOfLength())); - uint32_t capacityIndex = templateObj->as().capacityIndex(); - store32(Imm32(capacityIndex << UnboxedArrayObject::CapacityShift), - Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength())); } else { MOZ_CRASH("Unknown object"); } diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index b6616321c..6ee989463 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -1626,7 +1626,7 @@ class MacroAssembler : public MacroAssemblerSpecific void storeToTypedFloatArray(Scalar::Type arrayType, FloatRegister value, const Address& dest, unsigned numElems = 0); - // Load a property from an UnboxedPlainObject or UnboxedArrayObject. + // Load a property from an UnboxedPlainObject. template void loadUnboxedProperty(T address, JSValueType type, TypedOrValueRegister output); @@ -1637,9 +1637,6 @@ class MacroAssembler : public MacroAssemblerSpecific void storeUnboxedProperty(T address, JSValueType type, const ConstantOrRegister& value, Label* failure); - void checkUnboxedArrayCapacity(Register obj, const RegisterOrInt32Constant& index, - Register temp, Label* failure); - Register extractString(const Address& address, Register scratch) { return extractObject(address, scratch); } diff --git a/js/src/jit/ScalarReplacement.cpp b/js/src/jit/ScalarReplacement.cpp index 2065c0371..be9ceee2e 100644 --- a/js/src/jit/ScalarReplacement.cpp +++ b/js/src/jit/ScalarReplacement.cpp @@ -795,11 +795,6 @@ IsArrayEscaped(MInstruction* ins) return true; } - if (obj->is()) { - JitSpew(JitSpew_Escape, "Template object is an unboxed plain object."); - return true; - } - if (length >= 16) { JitSpew(JitSpew_Escape, "Array has too many elements"); return true; diff --git a/js/src/jit/SharedIC.cpp b/js/src/jit/SharedIC.cpp index 2475dfb22..313957462 100644 --- a/js/src/jit/SharedIC.cpp +++ b/js/src/jit/SharedIC.cpp @@ -286,11 +286,6 @@ ICStub::trace(JSTracer* trc) TraceEdge(trc, &getElemStub->shape(), "baseline-getelem-dense-shape"); break; } - case ICStub::GetElem_UnboxedArray: { - ICGetElem_UnboxedArray* getElemStub = toGetElem_UnboxedArray(); - TraceEdge(trc, &getElemStub->group(), "baseline-getelem-unboxed-array-group"); - break; - } case ICStub::GetElem_TypedArray: { ICGetElem_TypedArray* getElemStub = toGetElem_TypedArray(); TraceEdge(trc, &getElemStub->shape(), "baseline-getelem-typedarray-shape"); @@ -2250,7 +2245,6 @@ IsCacheableProtoChain(JSObject* obj, JSObject* holder, bool isDOMProxy) if (obj == holder) return false; if (!obj->is() && - !obj->is() && !obj->is()) { return false; @@ -2582,9 +2576,6 @@ CheckHasNoSuchProperty(JSContext* cx, JSObject* obj, PropertyName* name, } else if (curObj->is()) { if (curObj->as().containsUnboxedOrExpandoProperty(cx, NameToId(name))) return false; - } else if (curObj->is()) { - if (name == cx->names().length) - return false; } else if (curObj->is()) { if (curObj->as().typeDescr().hasProperty(cx->names(), NameToId(name))) return false; diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 77b9e3647..0717bb86d 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -318,7 +318,7 @@ ArraySpliceDense(JSContext* cx, HandleObject obj, uint32_t start, uint32_t delet bool ArrayPopDense(JSContext* cx, HandleObject obj, MutableHandleValue rval) { - MOZ_ASSERT(obj->is() || obj->is()); + MOZ_ASSERT(obj->is()); AutoDetectInvalidation adi(cx, rval); @@ -341,8 +341,8 @@ ArrayPushDense(JSContext* cx, HandleObject obj, HandleValue v, uint32_t* length) { *length = GetAnyBoxedOrUnboxedArrayLength(obj); DenseElementResult result = - SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, *length, v.address(), 1, - ShouldUpdateTypes::DontUpdate); + SetOrExtendBoxedOrUnboxedDenseElements(cx, obj, *length, v.address(), 1, + ShouldUpdateTypes::DontUpdate); if (result != DenseElementResult::Incomplete) { (*length)++; return result == DenseElementResult::Success; @@ -362,7 +362,7 @@ ArrayPushDense(JSContext* cx, HandleObject obj, HandleValue v, uint32_t* length) bool ArrayShiftDense(JSContext* cx, HandleObject obj, MutableHandleValue rval) { - MOZ_ASSERT(obj->is() || obj->is()); + MOZ_ASSERT(obj->is()); AutoDetectInvalidation adi(cx, rval); @@ -1151,8 +1151,8 @@ SetDenseOrUnboxedArrayElement(JSContext* cx, HandleObject obj, int32_t index, // no type changes are needed. DenseElementResult result = - SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, index, value.address(), 1, - ShouldUpdateTypes::DontUpdate); + SetOrExtendBoxedOrUnboxedDenseElements(cx, obj, index, value.address(), 1, + ShouldUpdateTypes::DontUpdate); if (result != DenseElementResult::Incomplete) return result == DenseElementResult::Success; diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h index f386d5256..35c7e7442 100644 --- a/js/src/jit/shared/LIR-shared.h +++ b/js/src/jit/shared/LIR-shared.h @@ -5165,72 +5165,6 @@ class LSetInitializedLength : public LInstructionHelper<0, 2, 0> } }; -class LUnboxedArrayLength : public LInstructionHelper<1, 1, 0> -{ - public: - LIR_HEADER(UnboxedArrayLength) - - explicit LUnboxedArrayLength(const LAllocation& object) { - setOperand(0, object); - } - - const LAllocation* object() { - return getOperand(0); - } -}; - -class LUnboxedArrayInitializedLength : public LInstructionHelper<1, 1, 0> -{ - public: - LIR_HEADER(UnboxedArrayInitializedLength) - - explicit LUnboxedArrayInitializedLength(const LAllocation& object) { - setOperand(0, object); - } - - const LAllocation* object() { - return getOperand(0); - } -}; - -class LIncrementUnboxedArrayInitializedLength : public LInstructionHelper<0, 1, 0> -{ - public: - LIR_HEADER(IncrementUnboxedArrayInitializedLength) - - explicit LIncrementUnboxedArrayInitializedLength(const LAllocation& object) { - setOperand(0, object); - } - - const LAllocation* object() { - return getOperand(0); - } -}; - -class LSetUnboxedArrayInitializedLength : public LInstructionHelper<0, 2, 1> -{ - public: - LIR_HEADER(SetUnboxedArrayInitializedLength) - - explicit LSetUnboxedArrayInitializedLength(const LAllocation& object, - const LAllocation& length, - const LDefinition& temp) { - setOperand(0, object); - setOperand(1, length); - setTemp(0, temp); - } - - const LAllocation* object() { - return getOperand(0); - } - const LAllocation* length() { - return getOperand(1); - } - const LDefinition* temp() { - return getTemp(0); - } -}; - // Load the length from an elements header. class LArrayLength : public LInstructionHelper<1, 1, 0> { diff --git a/js/src/jit/shared/LOpcodes-shared.h b/js/src/jit/shared/LOpcodes-shared.h index 6912e8904..deae92839 100644 --- a/js/src/jit/shared/LOpcodes-shared.h +++ b/js/src/jit/shared/LOpcodes-shared.h @@ -267,10 +267,6 @@ _(PostWriteElementBarrierV) \ _(InitializedLength) \ _(SetInitializedLength) \ - _(UnboxedArrayLength) \ - _(UnboxedArrayInitializedLength) \ - _(IncrementUnboxedArrayInitializedLength) \ - _(SetUnboxedArrayInitializedLength) \ _(BoundsCheck) \ _(BoundsCheckRange) \ _(BoundsCheckLower) \ diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 7a67c0095..190439d4b 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -64,7 +64,7 @@ using JS::ToUint32; bool JS::IsArray(JSContext* cx, HandleObject obj, IsArrayAnswer* answer) { - if (obj->is() || obj->is()) { + if (obj->is()) { *answer = IsArrayAnswer::Array; return true; } @@ -100,11 +100,6 @@ js::GetLengthProperty(JSContext* cx, HandleObject obj, uint32_t* lengthp) return true; } - if (obj->is()) { - *lengthp = obj->as().length(); - return true; - } - if (obj->is()) { ArgumentsObject& argsobj = obj->as(); if (!argsobj.hasOverriddenLength()) { @@ -284,7 +279,7 @@ ElementAdder::append(JSContext* cx, HandleValue v) MOZ_ASSERT(index_ < length_); if (resObj_) { DenseElementResult result = - SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, resObj_, index_, v.address(), 1); + SetOrExtendBoxedOrUnboxedDenseElements(cx, resObj_, index_, v.address(), 1); if (result == DenseElementResult::Failure) return false; if (result == DenseElementResult::Incomplete) { @@ -342,11 +337,11 @@ GetBoxedOrUnboxedDenseElements(JSObject* aobj, uint32_t length, Value* vp) { MOZ_ASSERT(!ObjectMayHaveExtraIndexedProperties(aobj)); - if (length > GetBoxedOrUnboxedInitializedLength(aobj)) + if (length > GetBoxedOrUnboxedInitializedLength(aobj)) return DenseElementResult::Incomplete; for (size_t i = 0; i < length; i++) { - vp[i] = GetBoxedOrUnboxedDenseElement(aobj, i); + vp[i] = GetBoxedOrUnboxedDenseElement(aobj, i); // No other indexed properties so hole => undefined. if (vp[i].isMagic(JS_ELEMENTS_HOLE)) @@ -398,7 +393,7 @@ SetArrayElement(JSContext* cx, HandleObject obj, double index, HandleValue v) { MOZ_ASSERT(index >= 0); - if ((obj->is() || obj->is()) && !obj->isIndexed() && index <= UINT32_MAX) { + if (obj->is() && !obj->isIndexed() && index <= UINT32_MAX) { DenseElementResult result = SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, uint32_t(index), v.address(), 1); if (result != DenseElementResult::Incomplete) @@ -823,7 +818,7 @@ array_addProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v) static inline bool ObjectMayHaveExtraIndexedOwnProperties(JSObject* obj) { - return (!obj->isNative() && !obj->is()) || + return !obj->isNative() || obj->isIndexed() || obj->is() || ClassMayResolveId(*obj->runtimeFromAnyThread()->commonNames, @@ -1288,10 +1283,6 @@ array_toLocaleString(JSContext* cx, unsigned argc, Value* vp) args.rval().setString(cx->names().empty); return true; } - if (obj->is() && obj->as().length() == 0) { - args.rval().setString(cx->names().empty); - return true; - } AutoCycleDetector detector(cx, obj); if (!detector.init()) @@ -1371,46 +1362,38 @@ ArrayReverseDenseKernel(JSContext* cx, HandleObject obj, uint32_t length) if (length == 0 || GetBoxedOrUnboxedInitializedLength(obj) == 0) return DenseElementResult::Success; - if (Type == JSVAL_TYPE_MAGIC) { - if (obj->as().denseElementsAreFrozen()) - return DenseElementResult::Incomplete; + if (obj->as().denseElementsAreFrozen()) + return DenseElementResult::Incomplete; - /* - * It's actually surprisingly complicated to reverse an array due to the - * orthogonality of array length and array capacity while handling - * leading and trailing holes correctly. Reversing seems less likely to - * be a common operation than other array mass-mutation methods, so for - * now just take a probably-small memory hit (in the absence of too many - * holes in the array at its start) and ensure that the capacity is - * sufficient to hold all the elements in the array if it were full. - */ - DenseElementResult result = obj->as().ensureDenseElements(cx, length, 0); - if (result != DenseElementResult::Success) - return result; + /* + * It's actually surprisingly complicated to reverse an array due to the + * orthogonality of array length and array capacity while handling + * leading and trailing holes correctly. Reversing seems less likely to + * be a common operation than other array mass-mutation methods, so for + * now just take a probably-small memory hit (in the absence of too many + * holes in the array at its start) and ensure that the capacity is + * sufficient to hold all the elements in the array if it were full. + */ + DenseElementResult result = obj->as().ensureDenseElements(cx, length, 0); + if (result != DenseElementResult::Success) + return result; - /* Fill out the array's initialized length to its proper length. */ - obj->as().ensureDenseInitializedLength(cx, length, 0); - } else { - // Unboxed arrays can only be reversed here if their initialized length - // matches their actual length. Otherwise the reversal will place holes - // at the beginning of the array, which we don't support. - if (length != obj->as().initializedLength()) - return DenseElementResult::Incomplete; - } + /* Fill out the array's initialized length to its proper length. */ + obj->as().ensureDenseInitializedLength(cx, length, 0); RootedValue origlo(cx), orighi(cx); uint32_t lo = 0, hi = length - 1; for (; lo < hi; lo++, hi--) { - origlo = GetBoxedOrUnboxedDenseElement(obj, lo); - orighi = GetBoxedOrUnboxedDenseElement(obj, hi); - SetBoxedOrUnboxedDenseElementNoTypeChange(obj, lo, orighi); + origlo = GetBoxedOrUnboxedDenseElement(obj, lo); + orighi = GetBoxedOrUnboxedDenseElement(obj, hi); + SetBoxedOrUnboxedDenseElementNoTypeChange(obj, lo, orighi); if (orighi.isMagic(JS_ELEMENTS_HOLE) && !SuppressDeletedProperty(cx, obj, INT_TO_JSID(lo))) { return DenseElementResult::Failure; } - SetBoxedOrUnboxedDenseElementNoTypeChange(obj, hi, origlo); + SetBoxedOrUnboxedDenseElementNoTypeChange(obj, hi, origlo); if (origlo.isMagic(JS_ELEMENTS_HOLE) && !SuppressDeletedProperty(cx, obj, INT_TO_JSID(hi))) { @@ -2082,8 +2065,8 @@ js::array_push(JSContext* cx, unsigned argc, Value* vp) if (!ObjectMayHaveExtraIndexedProperties(obj)) { DenseElementResult result = - SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, length, - args.array(), args.length()); + SetOrExtendBoxedOrUnboxedDenseElements(cx, obj, length, + args.array(), args.length()); if (result != DenseElementResult::Incomplete) { if (result == DenseElementResult::Failure) return false; @@ -2158,21 +2141,15 @@ template static inline DenseElementResult ShiftMoveBoxedOrUnboxedDenseElements(JSObject* obj) { - MOZ_ASSERT(HasBoxedOrUnboxedDenseElements(obj)); + MOZ_ASSERT(HasBoxedOrUnboxedDenseElements(obj)); /* * At this point the length and initialized length have already been * decremented and the result fetched, so just shift the array elements * themselves. */ - size_t initlen = GetBoxedOrUnboxedInitializedLength(obj); - if (Type == JSVAL_TYPE_MAGIC) { - obj->as().moveDenseElementsNoPreBarrier(0, 1, initlen); - } else { - uint8_t* data = obj->as().elements(); - size_t elementSize = UnboxedTypeSize(Type); - memmove(data, data + elementSize, initlen * elementSize); - } + size_t initlen = GetBoxedOrUnboxedInitializedLength(obj); + obj->as().moveDenseElementsNoPreBarrier(0, 1, initlen); return DenseElementResult::Success; } @@ -2202,19 +2179,19 @@ ArrayShiftDenseKernel(JSContext* cx, HandleObject obj, MutableHandleValue rval) if (MOZ_UNLIKELY(group->hasAllFlags(OBJECT_FLAG_ITERATED))) return DenseElementResult::Incomplete; - size_t initlen = GetBoxedOrUnboxedInitializedLength(obj); + size_t initlen = GetBoxedOrUnboxedInitializedLength(obj); if (initlen == 0) return DenseElementResult::Incomplete; - rval.set(GetBoxedOrUnboxedDenseElement(obj, 0)); + rval.set(GetBoxedOrUnboxedDenseElement(obj, 0)); if (rval.isMagic(JS_ELEMENTS_HOLE)) rval.setUndefined(); - DenseElementResult result = MoveBoxedOrUnboxedDenseElements(cx, obj, 0, 1, initlen - 1); + DenseElementResult result = MoveBoxedOrUnboxedDenseElements(cx, obj, 0, 1, initlen - 1); if (result != DenseElementResult::Success) return result; - SetBoxedOrUnboxedInitializedLength(cx, obj, initlen - 1); + SetBoxedOrUnboxedInitializedLength(cx, obj, initlen - 1); return DenseElementResult::Success; } @@ -2520,7 +2497,7 @@ js::array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueI /* Steps 10-11. */ DebugOnly result = - CopyAnyBoxedOrUnboxedDenseElements(cx, arr, obj, 0, actualStart, actualDeleteCount); + CopyBoxedOrUnboxedDenseElements(cx, arr, obj, 0, actualStart, actualDeleteCount); MOZ_ASSERT(result.value == DenseElementResult::Success); /* Step 12 (implicit). */ @@ -2557,14 +2534,14 @@ js::array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueI if (CanOptimizeForDenseStorage(obj, 0, len, cx)) { /* Steps 15.a-b. */ DenseElementResult result = - MoveAnyBoxedOrUnboxedDenseElements(cx, obj, targetIndex, sourceIndex, - len - sourceIndex); + MoveBoxedOrUnboxedDenseElements(cx, obj, targetIndex, sourceIndex, + len - sourceIndex); MOZ_ASSERT(result != DenseElementResult::Incomplete); if (result == DenseElementResult::Failure) return false; /* Steps 15.c-d. */ - SetAnyBoxedOrUnboxedInitializedLength(cx, obj, finalLength); + SetBoxedOrUnboxedInitializedLength(cx, obj, finalLength); } else { /* * This is all very slow if the length is very large. We don't yet @@ -2644,15 +2621,15 @@ js::array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueI if (CanOptimizeForDenseStorage(obj, len, itemCount - actualDeleteCount, cx)) { DenseElementResult result = - MoveAnyBoxedOrUnboxedDenseElements(cx, obj, actualStart + itemCount, - actualStart + actualDeleteCount, - len - (actualStart + actualDeleteCount)); + MoveBoxedOrUnboxedDenseElements(cx, obj, actualStart + itemCount, + actualStart + actualDeleteCount, + len - (actualStart + actualDeleteCount)); MOZ_ASSERT(result != DenseElementResult::Incomplete); if (result == DenseElementResult::Failure) return false; /* Steps 16.a-b. */ - SetAnyBoxedOrUnboxedInitializedLength(cx, obj, len + itemCount - actualDeleteCount); + SetBoxedOrUnboxedInitializedLength(cx, obj, len + itemCount - actualDeleteCount); } else { RootedValue fromValue(cx); for (double k = len - actualDeleteCount; k > actualStart; k--) { @@ -3022,14 +2999,14 @@ ArraySliceDenseKernel(JSContext* cx, JSObject* obj, int32_t beginArg, int32_t en if (begin > end) begin = end; - size_t initlen = GetBoxedOrUnboxedInitializedLength(obj); + size_t initlen = GetBoxedOrUnboxedInitializedLength(obj); if (initlen > begin) { size_t count = Min(initlen - begin, end - begin); if (count) { - DenseElementResult rv = EnsureBoxedOrUnboxedDenseElements(cx, result, count); + DenseElementResult rv = EnsureBoxedOrUnboxedDenseElements(cx, result, count); if (rv != DenseElementResult::Success) return rv; - CopyBoxedOrUnboxedDenseElements(cx, result, obj, 0, begin, count); + CopyBoxedOrUnboxedDenseElements(cx, result, obj, 0, begin, count); } } @@ -3589,12 +3566,6 @@ NewArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length newKind = TenuredObject; RootedObject proto(cx, group->proto().toObject()); - if (group->maybeUnboxedLayout()) { - if (length > UnboxedArrayObject::MaximumCapacity) - return NewArray(cx, length, proto, newKind); - return UnboxedArrayObject::create(cx, group, length, newKind, maxLength); - } - ArrayObject* res = NewArray(cx, length, proto, newKind); if (!res) return nullptr; @@ -3701,8 +3672,8 @@ js::MaybeAnalyzeBeforeCreatingLargeArray(ExclusiveContext* cx, HandleObjectGroup if (!obj) return false; DebugOnly result = - SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, 0, vp, nlength, - ShouldUpdateTypes::Update); + SetOrExtendBoxedOrUnboxedDenseElements(cx, obj, 0, vp, nlength, + ShouldUpdateTypes::Update); MOZ_ASSERT(result.value == DenseElementResult::Success); } objects->maybeAnalyze(cx, group, /* forceAnalyze = */ true); @@ -3724,22 +3695,10 @@ js::NewCopiedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, return nullptr; DenseElementResult result = - SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, 0, vp, length, updateTypes); + SetOrExtendBoxedOrUnboxedDenseElements(cx, obj, 0, vp, length, updateTypes); if (result == DenseElementResult::Failure) return nullptr; - if (result == DenseElementResult::Success) - return obj; - - MOZ_ASSERT(obj->is()); - if (!UnboxedArrayObject::convertToNative(cx->asJSContext(), obj)) - return nullptr; - - result = SetOrExtendBoxedOrUnboxedDenseElements(cx, obj, 0, vp, length, - updateTypes); - MOZ_ASSERT(result != DenseElementResult::Incomplete); - if (result == DenseElementResult::Failure) - return nullptr; - + MOZ_ASSERT(result == DenseElementResult::Success); return obj; } diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index f5cd56a9b..1fd9d1d28 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -271,7 +271,7 @@ js::GetBuiltinClass(JSContext* cx, HandleObject obj, ESClass* cls) if (obj->is() || obj->is()) *cls = ESClass::Object; - else if (obj->is() || obj->is()) + else if (obj->is()) *cls = ESClass::Array; else if (obj->is()) *cls = ESClass::Number; -- cgit v1.2.3 From c8300fbd6ae08925736c32f8b02c980ce1531f3f Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 23 May 2019 10:51:09 +0000 Subject: Remove UnboxedArray code part 2 --- js/src/gc/Marking.cpp | 2 - js/src/jit/BaselineIC.cpp | 8 +- js/src/jit/BaselineIC.h | 56 +-- js/src/jit/CodeGenerator.cpp | 19 +- js/src/jit/MCallOptimize.cpp | 4 +- js/src/jit/MIR.h | 6 +- js/src/jsarray.cpp | 18 +- js/src/jsobj.cpp | 27 +- js/src/jsobjinlines.h | 2 - js/src/vm/Interpreter-inl.h | 2 +- js/src/vm/Interpreter.cpp | 9 - js/src/vm/ObjectGroup.cpp | 73 +--- js/src/vm/ReceiverGuard.cpp | 8 +- js/src/vm/TypeInference.cpp | 2 +- js/src/vm/UnboxedObject-inl.h | 466 +++--------------------- js/src/vm/UnboxedObject.cpp | 826 +----------------------------------------- js/src/vm/UnboxedObject.h | 207 +---------- 17 files changed, 124 insertions(+), 1611 deletions(-) (limited to 'js/src') diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index 47d2314c1..da3ef7d0d 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -2504,8 +2504,6 @@ js::TenuringTracer::moveObjectToTenured(JSObject* dst, JSObject* src, AllocKind InlineTypedObject::objectMovedDuringMinorGC(this, dst, src); } else if (src->is()) { tenuredSize += TypedArrayObject::objectMovedDuringMinorGC(this, dst, src, dstKind); - } else if (src->is()) { - tenuredSize += UnboxedArrayObject::objectMovedDuringMinorGC(this, dst, src, dstKind); } else if (src->is()) { tenuredSize += ArgumentsObject::objectMovedDuringMinorGC(this, dst, src); } else if (src->is()) { diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index f43fc5bf9..1d230e083 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -280,6 +280,12 @@ DoTypeUpdateFallback(JSContext* cx, BaselineFrame* frame, ICUpdatedStub* stub, H RootedId id(cx); switch(stub->kind()) { + case ICStub::SetElem_DenseOrUnboxedArray: + case ICStub::SetElem_DenseOrUnboxedArrayAdd: { + id = JSID_VOID; + AddTypePropertyId(cx, obj, id, value); + break; + } case ICStub::SetProp_Native: case ICStub::SetProp_NativeAdd: case ICStub::SetProp_Unboxed: { @@ -5763,7 +5769,7 @@ CopyArray(JSContext* cx, HandleObject obj, MutableHandleValue result) if (!nobj) return false; EnsureArrayGroupAnalyzed(cx, nobj); - CopyAnyBoxedOrUnboxedDenseElements(cx, nobj, obj, 0, 0, length); + CopyBoxedOrUnboxedDenseElements(cx, nobj, obj, 0, 0, length); result.setObject(*nobj); return true; diff --git a/js/src/jit/BaselineIC.h b/js/src/jit/BaselineIC.h index a57556d99..afbea3b69 100644 --- a/js/src/jit/BaselineIC.h +++ b/js/src/jit/BaselineIC.h @@ -892,54 +892,6 @@ class ICGetElem_Dense : public ICMonitoredStub }; }; -class ICGetElem_UnboxedArray : public ICMonitoredStub -{ - friend class ICStubSpace; - - GCPtrObjectGroup group_; - - ICGetElem_UnboxedArray(JitCode* stubCode, ICStub* firstMonitorStub, ObjectGroup* group); - - public: - static ICGetElem_UnboxedArray* Clone(JSContext* cx, ICStubSpace* space, - ICStub* firstMonitorStub, ICGetElem_UnboxedArray& other); - - static size_t offsetOfGroup() { - return offsetof(ICGetElem_UnboxedArray, group_); - } - - GCPtrObjectGroup& group() { - return group_; - } - - class Compiler : public ICStubCompiler { - ICStub* firstMonitorStub_; - RootedObjectGroup group_; - JSValueType elementType_; - - protected: - MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm); - - virtual int32_t getKey() const { - return static_cast(engine_) | - (static_cast(kind) << 1) | - (static_cast(elementType_) << 17); - } - - public: - Compiler(JSContext* cx, ICStub* firstMonitorStub, ObjectGroup* group) - : ICStubCompiler(cx, ICStub::GetElem_UnboxedArray, Engine::Baseline), - firstMonitorStub_(firstMonitorStub), - group_(cx, group), - elementType_(group->unboxedLayoutDontCheckGeneration().elementType()) - {} - - ICStub* getStub(ICStubSpace* space) { - return newStub(space, getStubCode(), firstMonitorStub_, group_); - } - }; -}; - // Accesses scalar elements of a typed array or typed object. class ICGetElem_TypedArray : public ICStub { @@ -1115,9 +1067,7 @@ class ICSetElem_DenseOrUnboxedArray : public ICUpdatedStub : ICStubCompiler(cx, ICStub::SetElem_DenseOrUnboxedArray, Engine::Baseline), shape_(cx, shape), group_(cx, group), - unboxedType_(shape - ? JSVAL_TYPE_MAGIC - : group->unboxedLayoutDontCheckGeneration().elementType()) + unboxedType_(JSVAL_TYPE_MAGIC) {} ICUpdatedStub* getStub(ICStubSpace* space) { @@ -1225,9 +1175,7 @@ class ICSetElemDenseOrUnboxedArrayAddCompiler : public ICStubCompiler { : ICStubCompiler(cx, ICStub::SetElem_DenseOrUnboxedArrayAdd, Engine::Baseline), obj_(cx, obj), protoChainDepth_(protoChainDepth), - unboxedType_(obj->is() - ? obj->as().elementType() - : JSVAL_TYPE_MAGIC) + unboxedType_(JSVAL_TYPE_MAGIC) {} template diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index bd275a2c1..485e881fe 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -10336,22 +10336,11 @@ CodeGenerator::visitLoadElementHole(LLoadElementHole* lir) else masm.branch32(Assembler::BelowOrEqual, initLength, ToRegister(lir->index()), &undefined); - if (mir->unboxedType() != JSVAL_TYPE_MAGIC) { - size_t width = UnboxedTypeSize(mir->unboxedType()); - if (lir->index()->isConstant()) { - Address addr(elements, ToInt32(lir->index()) * width); - masm.loadUnboxedProperty(addr, mir->unboxedType(), out); - } else { - BaseIndex addr(elements, ToRegister(lir->index()), ScaleFromElemWidth(width)); - masm.loadUnboxedProperty(addr, mir->unboxedType(), out); - } + if (lir->index()->isConstant()) { + NativeObject::elementsSizeMustNotOverflow(); + masm.loadValue(Address(elements, ToInt32(lir->index()) * sizeof(Value)), out); } else { - if (lir->index()->isConstant()) { - NativeObject::elementsSizeMustNotOverflow(); - masm.loadValue(Address(elements, ToInt32(lir->index()) * sizeof(Value)), out); - } else { - masm.loadValue(BaseObjectElementIndex(elements, ToRegister(lir->index())), out); - } + masm.loadValue(BaseObjectElementIndex(elements, ToRegister(lir->index())), out); } // If a hole check is needed, and the value wasn't a hole, we're done. diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 7283497ea..748a70973 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -541,7 +541,7 @@ IonBuilder::inlineArray(CallInfo& callInfo) if (!alloc().ensureBallast()) return InliningStatus_Error; MDefinition* value = callInfo.getArg(i); - if (!initializeArrayElement(array, i, /* addResumePoint = */ false)) + if (!initializeArrayElement(array, i, value, /* addResumePoint = */ false)) return InliningStatus_Error; } @@ -578,7 +578,7 @@ IonBuilder::inlineArrayIsArray(CallInfo& callInfo) if (!clasp || clasp->isProxy()) return InliningStatus_NotInlined; - isArray = (clasp == &ArrayObject::class_ || clasp == &UnboxedArrayObject::class_); + isArray = (clasp == &ArrayObject::class_); } pushConstant(BooleanValue(isArray)); diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index cdd737b56..f316827dc 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -9245,7 +9245,7 @@ class MLoadElementHole bool needsHoleCheck_; MLoadElementHole(MDefinition* elements, MDefinition* index, MDefinition* initLength, - JSValueType unboxedType, bool needsHoleCheck) + bool needsHoleCheck) : MTernaryInstruction(elements, index, initLength), needsNegativeIntCheck_(true), needsHoleCheck_(needsHoleCheck) @@ -9717,10 +9717,6 @@ class MArraySlice return initialHeap_; } - JSValueType unboxedType() const { - return unboxedType_; - } - bool possiblyCalls() const override { return true; } diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 190439d4b..fa5ef2ab3 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -395,7 +395,7 @@ SetArrayElement(JSContext* cx, HandleObject obj, double index, HandleValue v) if (obj->is() && !obj->isIndexed() && index <= UINT32_MAX) { DenseElementResult result = - SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, uint32_t(index), v.address(), 1); + SetOrExtendBoxedOrUnboxedDenseElements(cx, obj, uint32_t(index), v.address(), 1); if (result != DenseElementResult::Incomplete) return result == DenseElementResult::Success; } @@ -1068,12 +1068,12 @@ ArrayJoinDenseKernel(JSContext* cx, SeparatorOp sepOp, HandleObject obj, uint32_ // length > initLength we rely on the second loop to add the // other elements. MOZ_ASSERT(*numProcessed == 0); - uint32_t initLength = Min(GetBoxedOrUnboxedInitializedLength(obj), length); + uint32_t initLength = Min(GetBoxedOrUnboxedInitializedLength(obj), length); while (*numProcessed < initLength) { if (!CheckForInterrupt(cx)) return DenseElementResult::Failure; - Value elem = GetBoxedOrUnboxedDenseElement(obj, *numProcessed); + Value elem = GetBoxedOrUnboxedDenseElement(obj, *numProcessed); if (elem.isString()) { if (!sb.append(elem.toString())) @@ -1320,7 +1320,7 @@ InitArrayElements(JSContext* cx, HandleObject obj, uint32_t start, if (!ObjectMayHaveExtraIndexedProperties(obj)) { DenseElementResult result = - SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, start, vector, count, updateTypes); + SetOrExtendBoxedOrUnboxedDenseElements(cx, obj, start, vector, count, updateTypes); if (result != DenseElementResult::Incomplete) return result == DenseElementResult::Success; } @@ -1359,7 +1359,7 @@ DenseElementResult ArrayReverseDenseKernel(JSContext* cx, HandleObject obj, uint32_t length) { /* An empty array or an array with no elements is already reversed. */ - if (length == 0 || GetBoxedOrUnboxedInitializedLength(obj) == 0) + if (length == 0 || GetBoxedOrUnboxedInitializedLength(obj) == 0) return DenseElementResult::Success; if (obj->as().denseElementsAreFrozen()) @@ -2074,7 +2074,7 @@ js::array_push(JSContext* cx, unsigned argc, Value* vp) uint32_t newlength = length + args.length(); args.rval().setNumber(newlength); - // SetOrExtendAnyBoxedOrUnboxedDenseElements takes care of updating the + // SetOrExtendBoxedOrUnboxedDenseElements takes care of updating the // length for boxed and unboxed arrays. Handle updates to the length of // non-arrays here. bool isArray; @@ -2360,7 +2360,7 @@ CanOptimizeForDenseStorage(HandleObject arr, uint32_t startingIndex, uint32_t co return false; /* There's no optimizing possible if it's not an array. */ - if (!arr->is() && !arr->is()) + if (!arr->is()) return false; /* If it's a frozen array, always pick the slow path */ @@ -2863,7 +2863,7 @@ ArraySliceOrdinary(JSContext* cx, HandleObject obj, uint32_t length, uint32_t be if (count) { DebugOnly result = - CopyAnyBoxedOrUnboxedDenseElements(cx, narr, obj, 0, begin, count); + CopyBoxedOrUnboxedDenseElements(cx, narr, obj, 0, begin, count); MOZ_ASSERT(result.value == DenseElementResult::Success); } arr.set(narr); @@ -3608,7 +3608,7 @@ static inline JSObject* NewArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length, NewObjectKind newKind = GenericObject) { - if (!obj->is() && !obj->is()) + if (!obj->is()) return NewArray(cx, length, nullptr, newKind); if (obj->staticPrototype() != cx->global()->maybeGetArrayPrototype()) diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index f22ecb445..c26a42f48 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -1146,7 +1146,7 @@ static bool GetScriptArrayObjectElements(JSContext* cx, HandleObject obj, MutableHandle> values) { MOZ_ASSERT(!obj->isSingleton()); - MOZ_ASSERT(obj->is() || obj->is()); + MOZ_ASSERT(obj->is()); MOZ_ASSERT(!obj->isIndexed()); size_t length = GetAnyBoxedOrUnboxedArrayLength(obj); @@ -1207,11 +1207,10 @@ js::DeepCloneObjectLiteral(JSContext* cx, HandleObject obj, NewObjectKind newKin MOZ_ASSERT_IF(obj->isSingleton(), cx->compartment()->behaviors().getSingletonsAsTemplates()); MOZ_ASSERT(obj->is() || - obj->is() || - obj->is()); + obj->is()); MOZ_ASSERT(newKind != SingletonObject); - if (obj->is() || obj->is()) { + if (obj->is()) { Rooted> values(cx, GCVector(cx)); if (!GetScriptArrayObjectElements(cx, obj, &values)) return nullptr; @@ -1327,9 +1326,8 @@ js::XDRObjectLiteral(XDRState* xdr, MutableHandleObject obj) { if (mode == XDR_ENCODE) { MOZ_ASSERT(obj->is() || - obj->is() || - obj->is()); - isArray = (obj->is() || obj->is()) ? 1 : 0; + obj->is()); + isArray = obj->is() ? 1 : 0; } if (!xdr->codeUint32(&isArray)) @@ -2312,11 +2310,6 @@ js::LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Shape** // us the resolve hook won't define a property with this id. if (ClassMayResolveId(cx->names(), obj->getClass(), id, obj)) return false; - } else if (obj->is()) { - if (obj->as().containsProperty(cx, id)) { - MarkNonNativePropertyFound(propp); - return true; - } } else if (obj->is()) { if (obj->as().typeDescr().hasProperty(cx->names(), id)) { MarkNonNativePropertyFound(propp); @@ -3680,16 +3673,6 @@ JSObject::allocKindForTenure(const js::Nursery& nursery) const if (IsProxy(this)) return as().allocKindForTenure(); - // Unboxed arrays use inline data if their size is small enough. - if (is()) { - const UnboxedArrayObject* nobj = &as(); - size_t nbytes = UnboxedArrayObject::offsetOfInlineElements() + - nobj->capacity() * nobj->elementSize(); - if (nbytes <= JSObject::MAX_BYTE_SIZE) - return GetGCObjectKindForBytes(nbytes); - return AllocKind::OBJECT0; - } - // Inlined typed objects are followed by their data, so make sure we copy // it all over to the new object. if (is()) { diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 6be4d0d28..26f9eacce 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -40,8 +40,6 @@ MaybeConvertUnboxedObjectToNative(ExclusiveContext* cx, JSObject* obj) { if (obj->is()) return UnboxedPlainObject::convertToNative(cx->asJSContext(), obj); - if (obj->is()) - return UnboxedArrayObject::convertToNative(cx->asJSContext(), obj); return true; } diff --git a/js/src/vm/Interpreter-inl.h b/js/src/vm/Interpreter-inl.h index 710f1d89b..a2c8e220a 100644 --- a/js/src/vm/Interpreter-inl.h +++ b/js/src/vm/Interpreter-inl.h @@ -593,7 +593,7 @@ InitArrayElemOperation(JSContext* cx, jsbytecode* pc, HandleObject obj, uint32_t JSOp op = JSOp(*pc); MOZ_ASSERT(op == JSOP_INITELEM_ARRAY || op == JSOP_INITELEM_INC); - MOZ_ASSERT(obj->is() || obj->is()); + MOZ_ASSERT(obj->is()); if (op == JSOP_INITELEM_INC && index == INT32_MAX) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SPREAD_TOO_LARGE); diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 3cf2deb83..7d05b2d4c 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -5001,9 +5001,6 @@ js::NewArrayOperation(JSContext* cx, HandleScript script, jsbytecode* pc, uint32 if (group->shouldPreTenure() || group->maybePreliminaryObjects()) newKind = TenuredObject; - - if (group->maybeUnboxedLayout()) - return UnboxedArrayObject::create(cx, group, length, newKind); } ArrayObject* obj = NewDenseFullyAllocatedArray(cx, length, nullptr, newKind); @@ -5029,12 +5026,6 @@ js::NewArrayOperationWithTemplate(JSContext* cx, HandleObject templateObject) NewObjectKind newKind = templateObject->group()->shouldPreTenure() ? TenuredObject : GenericObject; - if (templateObject->is()) { - uint32_t length = templateObject->as().length(); - RootedObjectGroup group(cx, templateObject->group()); - return UnboxedArrayObject::create(cx, group, length, newKind); - } - ArrayObject* obj = NewDenseFullyAllocatedArray(cx, templateObject->as().length(), nullptr, newKind); if (!obj) diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp index 46159a972..a227b7c9c 100644 --- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -861,32 +861,6 @@ ObjectGroup::newArrayObject(ExclusiveContext* cx, return nullptr; if (group->maybePreliminaryObjects()) group->maybePreliminaryObjects()->maybeAnalyze(cx, group); - if (group->maybeUnboxedLayout()) { - switch (group->unboxedLayout().elementType()) { - case JSVAL_TYPE_BOOLEAN: - if (elementType != TypeSet::BooleanType()) - updateTypes = ShouldUpdateTypes::Update; - break; - case JSVAL_TYPE_INT32: - if (elementType != TypeSet::Int32Type()) - updateTypes = ShouldUpdateTypes::Update; - break; - case JSVAL_TYPE_DOUBLE: - if (elementType != TypeSet::Int32Type() && elementType != TypeSet::DoubleType()) - updateTypes = ShouldUpdateTypes::Update; - break; - case JSVAL_TYPE_STRING: - if (elementType != TypeSet::StringType()) - updateTypes = ShouldUpdateTypes::Update; - break; - case JSVAL_TYPE_OBJECT: - if (elementType != TypeSet::NullType() && !elementType.get().isObjectUnchecked()) - updateTypes = ShouldUpdateTypes::Update; - break; - default: - MOZ_CRASH(); - } - } return NewCopiedArrayTryUseGroup(cx, group, vp, length, newKind, updateTypes); } @@ -897,7 +871,7 @@ GiveObjectGroup(ExclusiveContext* cx, JSObject* source, JSObject* target) { MOZ_ASSERT(source->group() != target->group()); - if (!target->is() && !target->is()) + if (!target->is()) return true; if (target->group()->maybePreliminaryObjects()) { @@ -905,41 +879,21 @@ GiveObjectGroup(ExclusiveContext* cx, JSObject* source, JSObject* target) target->group()->maybePreliminaryObjects()->maybeAnalyze(cx, target->group(), force); } - if (target->is()) { - ObjectGroup* sourceGroup = source->group(); - - if (source->is()) { - Shape* shape = target->as().lastProperty(); - if (!UnboxedArrayObject::convertToNativeWithGroup(cx, source, target->group(), shape)) - return false; - } else if (source->is()) { - source->setGroup(target->group()); - } else { - return true; - } - - if (sourceGroup->maybePreliminaryObjects()) - sourceGroup->maybePreliminaryObjects()->unregisterObject(source); - if (target->group()->maybePreliminaryObjects()) - target->group()->maybePreliminaryObjects()->registerNewObject(source); - - for (size_t i = 0; i < source->as().getDenseInitializedLength(); i++) { - Value v = source->as().getDenseElement(i); - AddTypePropertyId(cx, source->group(), source, JSID_VOID, v); - } + ObjectGroup* sourceGroup = source->group(); + if (source->is()) { + source->setGroup(target->group()); + } else { return true; } - if (target->is()) { - if (!source->is()) - return true; - if (source->as().elementType() != JSVAL_TYPE_INT32) - return true; - if (target->as().elementType() != JSVAL_TYPE_DOUBLE) - return true; - - return source->as().convertInt32ToDouble(cx, target->group()); + if (sourceGroup->maybePreliminaryObjects()) + sourceGroup->maybePreliminaryObjects()->unregisterObject(source); + if (target->group()->maybePreliminaryObjects()) + target->group()->maybePreliminaryObjects()->registerNewObject(source); + for (size_t i = 0; i < source->as().getDenseInitializedLength(); i++) { + Value v = source->as().getDenseElement(i); + AddTypePropertyId(cx, source->group(), source, JSID_VOID, v); } return true; @@ -1503,7 +1457,8 @@ ObjectGroup::allocationSiteGroup(JSContext* cx, JSScript* scriptArg, jsbytecode* } } - if (kind == JSProto_Array && + // FIXME: This block can probably go because of cx->options().unboxedArrays() + if (kind == JSProto_Array && (JSOp(*pc) == JSOP_NEWARRAY || IsCallPC(pc)) && cx->options().unboxedArrays()) { diff --git a/js/src/vm/ReceiverGuard.cpp b/js/src/vm/ReceiverGuard.cpp index 11c2d0727..e37bf8ee5 100644 --- a/js/src/vm/ReceiverGuard.cpp +++ b/js/src/vm/ReceiverGuard.cpp @@ -19,7 +19,7 @@ ReceiverGuard::ReceiverGuard(JSObject* obj) group = obj->group(); if (UnboxedExpandoObject* expando = obj->as().maybeExpando()) shape = expando->lastProperty(); - } else if (obj->is() || obj->is()) { + } else if (obj->is()) { group = obj->group(); } else { shape = obj->maybeShape(); @@ -34,7 +34,7 @@ ReceiverGuard::ReceiverGuard(ObjectGroup* group, Shape* shape) const Class* clasp = group->clasp(); if (clasp == &UnboxedPlainObject::class_) { // Keep both group and shape. - } else if (clasp == &UnboxedArrayObject::class_ || IsTypedObjectClass(clasp)) { + } else if (IsTypedObjectClass(clasp)) { this->shape = nullptr; } else { this->group = nullptr; @@ -49,8 +49,8 @@ HeapReceiverGuard::keyBits(JSObject* obj) // Both the group and shape need to be guarded for unboxed plain objects. return obj->as().maybeExpando() ? 0 : 1; } - if (obj->is() || obj->is()) { - // Only the group needs to be guarded for unboxed arrays and typed objects. + if (obj->is()) { + // Only the group needs to be guarded for typed objects. return 2; } // Other objects only need the shape to be guarded. diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index 9e0342382..2160dbc51 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -2505,7 +2505,7 @@ TemporaryTypeSet::propertyNeedsBarrier(CompilerConstraintList* constraints, jsid bool js::ClassCanHaveExtraProperties(const Class* clasp) { - if (clasp == &UnboxedPlainObject::class_ || clasp == &UnboxedArrayObject::class_) + if (clasp == &UnboxedPlainObject::class_) return false; return clasp->getResolve() || clasp->getOpsLookupProperty() diff --git a/js/src/vm/UnboxedObject-inl.h b/js/src/vm/UnboxedObject-inl.h index 93ad7bf28..499f3604b 100644 --- a/js/src/vm/UnboxedObject-inl.h +++ b/js/src/vm/UnboxedObject-inl.h @@ -172,123 +172,6 @@ UnboxedPlainObject::layout() const return group()->unboxedLayout(); } -///////////////////////////////////////////////////////////////////// -// UnboxedArrayObject -///////////////////////////////////////////////////////////////////// - -inline const UnboxedLayout& -UnboxedArrayObject::layout() const -{ - return group()->unboxedLayout(); -} - -inline void -UnboxedArrayObject::setLength(ExclusiveContext* cx, uint32_t length) -{ - if (length > INT32_MAX) { - // Track objects with overflowing lengths in type information. - MarkObjectGroupFlags(cx, this, OBJECT_FLAG_LENGTH_OVERFLOW); - } - - length_ = length; -} - -inline void -UnboxedArrayObject::setInitializedLength(uint32_t initlen) -{ - if (initlen < initializedLength()) { - switch (elementType()) { - case JSVAL_TYPE_STRING: - for (size_t i = initlen; i < initializedLength(); i++) - triggerPreBarrier(i); - break; - case JSVAL_TYPE_OBJECT: - for (size_t i = initlen; i < initializedLength(); i++) - triggerPreBarrier(i); - break; - default: - MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(elementType())); - } - } - setInitializedLengthNoBarrier(initlen); -} - -template -inline bool -UnboxedArrayObject::setElementSpecific(ExclusiveContext* cx, size_t index, const Value& v) -{ - MOZ_ASSERT(index < initializedLength()); - MOZ_ASSERT(Type == elementType()); - uint8_t* p = elements() + index * UnboxedTypeSize(Type); - return SetUnboxedValue(cx, this, JSID_VOID, p, elementType(), v, /* preBarrier = */ true); -} - -template -inline void -UnboxedArrayObject::setElementNoTypeChangeSpecific(size_t index, const Value& v) -{ - MOZ_ASSERT(index < initializedLength()); - MOZ_ASSERT(Type == elementType()); - uint8_t* p = elements() + index * UnboxedTypeSize(Type); - return SetUnboxedValueNoTypeChange(this, p, elementType(), v, /* preBarrier = */ true); -} - -template -inline bool -UnboxedArrayObject::initElementSpecific(ExclusiveContext* cx, size_t index, const Value& v) -{ - MOZ_ASSERT(index < initializedLength()); - MOZ_ASSERT(Type == elementType()); - uint8_t* p = elements() + index * UnboxedTypeSize(Type); - return SetUnboxedValue(cx, this, JSID_VOID, p, elementType(), v, /* preBarrier = */ false); -} - -template -inline void -UnboxedArrayObject::initElementNoTypeChangeSpecific(size_t index, const Value& v) -{ - MOZ_ASSERT(index < initializedLength()); - MOZ_ASSERT(Type == elementType()); - uint8_t* p = elements() + index * UnboxedTypeSize(Type); - return SetUnboxedValueNoTypeChange(this, p, elementType(), v, /* preBarrier = */ false); -} - -template -inline Value -UnboxedArrayObject::getElementSpecific(size_t index) -{ - MOZ_ASSERT(index < initializedLength()); - MOZ_ASSERT(Type == elementType()); - uint8_t* p = elements() + index * UnboxedTypeSize(Type); - return GetUnboxedValue(p, Type, /* maybeUninitialized = */ false); -} - -template -inline void -UnboxedArrayObject::triggerPreBarrier(size_t index) -{ - MOZ_ASSERT(UnboxedTypeNeedsPreBarrier(Type)); - - uint8_t* p = elements() + index * UnboxedTypeSize(Type); - - switch (Type) { - case JSVAL_TYPE_STRING: { - JSString** np = reinterpret_cast(p); - JSString::writeBarrierPre(*np); - break; - } - - case JSVAL_TYPE_OBJECT: { - JSObject** np = reinterpret_cast(p); - JSObject::writeBarrierPre(*np); - break; - } - - default: - MOZ_CRASH("Bad type"); - } -} - ///////////////////////////////////////////////////////////////////// // Combined methods for NativeObject and UnboxedArrayObject accesses. ///////////////////////////////////////////////////////////////////// @@ -296,7 +179,7 @@ UnboxedArrayObject::triggerPreBarrier(size_t index) static inline bool HasAnyBoxedOrUnboxedDenseElements(JSObject* obj) { - return obj->isNative() || obj->is(); + return obj->isNative(); } static inline size_t @@ -304,8 +187,6 @@ GetAnyBoxedOrUnboxedInitializedLength(JSObject* obj) { if (obj->isNative()) return obj->as().getDenseInitializedLength(); - if (obj->is()) - return obj->as().initializedLength(); return 0; } @@ -314,57 +195,40 @@ GetAnyBoxedOrUnboxedCapacity(JSObject* obj) { if (obj->isNative()) return obj->as().getDenseCapacity(); - if (obj->is()) - return obj->as().capacity(); return 0; } static inline Value GetAnyBoxedOrUnboxedDenseElement(JSObject* obj, size_t index) { - if (obj->isNative()) - return obj->as().getDenseElement(index); - return obj->as().getElement(index); + return obj->as().getDenseElement(index); } static inline size_t GetAnyBoxedOrUnboxedArrayLength(JSObject* obj) { - if (obj->is()) - return obj->as().length(); - return obj->as().length(); + return obj->as().length(); } static inline void SetAnyBoxedOrUnboxedArrayLength(JSContext* cx, JSObject* obj, size_t length) { - if (obj->is()) { - MOZ_ASSERT(length >= obj->as().length()); - obj->as().setLength(cx, length); - } else { - MOZ_ASSERT(length >= obj->as().length()); - obj->as().setLength(cx, length); - } + MOZ_ASSERT(length >= obj->as().length()); + obj->as().setLength(cx, length); } static inline bool SetAnyBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, const Value& value) { - if (obj->isNative()) { - obj->as().setDenseElementWithType(cx, index, value); - return true; - } - return obj->as().setElement(cx, index, value); + obj->as().setDenseElementWithType(cx, index, value); + return true; } static inline bool InitAnyBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, const Value& value) { - if (obj->isNative()) { - obj->as().initDenseElementWithType(cx, index, value); - return true; - } - return obj->as().initElement(cx, index, value); + obj->as().initDenseElementWithType(cx, index, value); + return true; } ///////////////////////////////////////////////////////////////////// @@ -374,273 +238,128 @@ InitAnyBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, co static inline JSValueType GetBoxedOrUnboxedType(JSObject* obj) { - if (obj->isNative()) - return JSVAL_TYPE_MAGIC; - return obj->as().elementType(); + return JSVAL_TYPE_MAGIC; } -template static inline bool HasBoxedOrUnboxedDenseElements(JSObject* obj) { - if (Type == JSVAL_TYPE_MAGIC) - return obj->isNative(); - return obj->is() && obj->as().elementType() == Type; + return obj->isNative(); } -template static inline size_t GetBoxedOrUnboxedInitializedLength(JSObject* obj) { - if (Type == JSVAL_TYPE_MAGIC) - return obj->as().getDenseInitializedLength(); - return obj->as().initializedLength(); + return obj->as().getDenseInitializedLength(); } -template static inline DenseElementResult SetBoxedOrUnboxedInitializedLength(JSContext* cx, JSObject* obj, size_t initlen) { - size_t oldInitlen = GetBoxedOrUnboxedInitializedLength(obj); - if (Type == JSVAL_TYPE_MAGIC) { - obj->as().setDenseInitializedLength(initlen); - if (initlen < oldInitlen) - obj->as().shrinkElements(cx, initlen); - } else { - obj->as().setInitializedLength(initlen); - if (initlen < oldInitlen) - obj->as().shrinkElements(cx, initlen); - } + size_t oldInitlen = GetBoxedOrUnboxedInitializedLength(obj); + obj->as().setDenseInitializedLength(initlen); + if (initlen < oldInitlen) + obj->as().shrinkElements(cx, initlen); return DenseElementResult::Success; } -template static inline size_t GetBoxedOrUnboxedCapacity(JSObject* obj) { - if (Type == JSVAL_TYPE_MAGIC) - return obj->as().getDenseCapacity(); - return obj->as().capacity(); + return obj->as().getDenseCapacity(); } -template static inline Value GetBoxedOrUnboxedDenseElement(JSObject* obj, size_t index) { - if (Type == JSVAL_TYPE_MAGIC) - return obj->as().getDenseElement(index); - return obj->as().getElementSpecific(index); + return obj->as().getDenseElement(index); } -template static inline void SetBoxedOrUnboxedDenseElementNoTypeChange(JSObject* obj, size_t index, const Value& value) { - if (Type == JSVAL_TYPE_MAGIC) - obj->as().setDenseElement(index, value); - else - obj->as().setElementNoTypeChangeSpecific(index, value); + obj->as().setDenseElement(index, value); } -template static inline bool SetBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, const Value& value) { - if (Type == JSVAL_TYPE_MAGIC) { - obj->as().setDenseElementWithType(cx, index, value); - return true; - } - return obj->as().setElementSpecific(cx, index, value); + obj->as().setDenseElementWithType(cx, index, value); + return true; } -template static inline DenseElementResult EnsureBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t count) { - if (Type == JSVAL_TYPE_MAGIC) { - if (!obj->as().ensureElements(cx, count)) - return DenseElementResult::Failure; - } else { - if (obj->as().capacity() < count) { - if (!obj->as().growElements(cx, count)) - return DenseElementResult::Failure; - } - } + if (!obj->as().ensureElements(cx, count)) + return DenseElementResult::Failure; return DenseElementResult::Success; } -template static inline DenseElementResult SetOrExtendBoxedOrUnboxedDenseElements(ExclusiveContext* cx, JSObject* obj, uint32_t start, const Value* vp, uint32_t count, ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update) { - if (Type == JSVAL_TYPE_MAGIC) { - NativeObject* nobj = &obj->as(); - - if (nobj->denseElementsAreFrozen()) - return DenseElementResult::Incomplete; - - if (obj->is() && - !obj->as().lengthIsWritable() && - start + count >= obj->as().length()) - { - return DenseElementResult::Incomplete; - } - - DenseElementResult result = nobj->ensureDenseElements(cx, start, count); - if (result != DenseElementResult::Success) - return result; - - if (obj->is() && start + count >= obj->as().length()) - obj->as().setLengthInt32(start + count); - - if (updateTypes == ShouldUpdateTypes::DontUpdate && !nobj->shouldConvertDoubleElements()) { - nobj->copyDenseElements(start, vp, count); - } else { - for (size_t i = 0; i < count; i++) - nobj->setDenseElementWithType(cx, start + i, vp[i]); - } - - return DenseElementResult::Success; - } - - UnboxedArrayObject* nobj = &obj->as(); + NativeObject* nobj = &obj->as(); - if (start > nobj->initializedLength()) + if (nobj->denseElementsAreFrozen()) return DenseElementResult::Incomplete; - if (start + count >= UnboxedArrayObject::MaximumCapacity) + if (obj->is() && + !obj->as().lengthIsWritable() && + start + count >= obj->as().length()) + { return DenseElementResult::Incomplete; + } - if (start + count > nobj->capacity() && !nobj->growElements(cx, start + count)) - return DenseElementResult::Failure; + DenseElementResult result = nobj->ensureDenseElements(cx, start, count); + if (result != DenseElementResult::Success) + return result; - size_t oldInitlen = nobj->initializedLength(); - - // Overwrite any existing elements covered by the new range. If we fail - // after this point due to some incompatible type being written to the - // object's elements, afterwards the contents will be different from when - // we started. The caller must retry the operation using a generic path, - // which will overwrite the already-modified elements as well as the ones - // that were left alone. - size_t i = 0; - if (updateTypes == ShouldUpdateTypes::DontUpdate) { - for (size_t j = start; i < count && j < oldInitlen; i++, j++) - nobj->setElementNoTypeChangeSpecific(j, vp[i]); - } else { - for (size_t j = start; i < count && j < oldInitlen; i++, j++) { - if (!nobj->setElementSpecific(cx, j, vp[i])) - return DenseElementResult::Incomplete; - } - } + if (obj->is() && start + count >= obj->as().length()) + obj->as().setLengthInt32(start + count); - if (i != count) { - obj->as().setInitializedLength(start + count); - if (updateTypes == ShouldUpdateTypes::DontUpdate) { - for (; i < count; i++) - nobj->initElementNoTypeChangeSpecific(start + i, vp[i]); - } else { - for (; i < count; i++) { - if (!nobj->initElementSpecific(cx, start + i, vp[i])) { - nobj->setInitializedLengthNoBarrier(oldInitlen); - return DenseElementResult::Incomplete; - } - } - } + if (updateTypes == ShouldUpdateTypes::DontUpdate && !nobj->shouldConvertDoubleElements()) { + nobj->copyDenseElements(start, vp, count); + } else { + for (size_t i = 0; i < count; i++) + nobj->setDenseElementWithType(cx, start + i, vp[i]); } - if (start + count >= nobj->length()) - nobj->setLength(cx, start + count); - return DenseElementResult::Success; } -template static inline DenseElementResult MoveBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, uint32_t dstStart, uint32_t srcStart, uint32_t length) { - MOZ_ASSERT(HasBoxedOrUnboxedDenseElements(obj)); - - if (Type == JSVAL_TYPE_MAGIC) { - if (obj->as().denseElementsAreFrozen()) - return DenseElementResult::Incomplete; + MOZ_ASSERT(HasBoxedOrUnboxedDenseElements(obj)); - if (!obj->as().maybeCopyElementsForWrite(cx)) - return DenseElementResult::Failure; - obj->as().moveDenseElements(dstStart, srcStart, length); - } else { - uint8_t* data = obj->as().elements(); - size_t elementSize = UnboxedTypeSize(Type); - - if (UnboxedTypeNeedsPreBarrier(Type) && - JS::shadow::Zone::asShadowZone(obj->zone())->needsIncrementalBarrier()) - { - // Trigger pre barriers on any elements we are overwriting. See - // NativeObject::moveDenseElements. No post barrier is needed as - // only whole cell post barriers are used with unboxed objects. - for (size_t i = 0; i < length; i++) - obj->as().triggerPreBarrier(dstStart + i); - } + if (obj->as().denseElementsAreFrozen()) + return DenseElementResult::Incomplete; - memmove(data + dstStart * elementSize, - data + srcStart * elementSize, - length * elementSize); - } + if (!obj->as().maybeCopyElementsForWrite(cx)) + return DenseElementResult::Failure; + obj->as().moveDenseElements(dstStart, srcStart, length); return DenseElementResult::Success; } -template static inline DenseElementResult CopyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src, uint32_t dstStart, uint32_t srcStart, uint32_t length) { - MOZ_ASSERT(HasBoxedOrUnboxedDenseElements(src)); - MOZ_ASSERT(HasBoxedOrUnboxedDenseElements(dst)); - MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength(dst) == dstStart); - MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength(src) >= srcStart + length); - MOZ_ASSERT(GetBoxedOrUnboxedCapacity(dst) >= dstStart + length); - - SetBoxedOrUnboxedInitializedLength(cx, dst, dstStart + length); - - if (DstType == JSVAL_TYPE_MAGIC) { - if (SrcType == JSVAL_TYPE_MAGIC) { - const Value* vp = src->as().getDenseElements() + srcStart; - dst->as().initDenseElements(dstStart, vp, length); - } else { - for (size_t i = 0; i < length; i++) { - Value v = GetBoxedOrUnboxedDenseElement(src, srcStart + i); - dst->as().initDenseElement(dstStart + i, v); - } - } - } else if (DstType == SrcType) { - uint8_t* dstData = dst->as().elements(); - uint8_t* srcData = src->as().elements(); - size_t elementSize = UnboxedTypeSize(DstType); - - memcpy(dstData + dstStart * elementSize, - srcData + srcStart * elementSize, - length * elementSize); - - // Add a store buffer entry if we might have copied a nursery pointer to dst. - if (UnboxedTypeNeedsPostBarrier(DstType) && !IsInsideNursery(dst)) - dst->runtimeFromMainThread()->gc.storeBuffer.putWholeCell(dst); - } else if (DstType == JSVAL_TYPE_DOUBLE && SrcType == JSVAL_TYPE_INT32) { - uint8_t* dstData = dst->as().elements(); - uint8_t* srcData = src->as().elements(); - - for (size_t i = 0; i < length; i++) { - int32_t v = *reinterpret_cast(srcData + (srcStart + i) * sizeof(int32_t)); - *reinterpret_cast(dstData + (dstStart + i) * sizeof(double)) = v; - } - } else { - for (size_t i = 0; i < length; i++) { - Value v = GetBoxedOrUnboxedDenseElement(src, srcStart + i); - dst->as().initElementNoTypeChangeSpecific(dstStart + i, v); - } - } + MOZ_ASSERT(HasBoxedOrUnboxedDenseElements(src)); + MOZ_ASSERT(HasBoxedOrUnboxedDenseElements(dst)); + MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength(dst) == dstStart); + MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength(src) >= srcStart + length); + MOZ_ASSERT(GetBoxedOrUnboxedCapacity(dst) >= dstStart + length); + + SetBoxedOrUnboxedInitializedLength(cx, dst, dstStart + length); + + const Value* vp = src->as().getDenseElements() + srcStart; + dst->as().initDenseElements(dstStart, vp, length); return DenseElementResult::Success; } @@ -666,22 +385,7 @@ CallBoxedOrUnboxedSpecialization(F f, JSObject* obj) { if (!HasAnyBoxedOrUnboxedDenseElements(obj)) return DenseElementResult::Incomplete; - switch (GetBoxedOrUnboxedType(obj)) { - case JSVAL_TYPE_MAGIC: - return f. DEPENDENT_TEMPLATE_HINT operator()(); - case JSVAL_TYPE_BOOLEAN: - return f. DEPENDENT_TEMPLATE_HINT operator()(); - case JSVAL_TYPE_INT32: - return f. DEPENDENT_TEMPLATE_HINT operator()(); - case JSVAL_TYPE_DOUBLE: - return f. DEPENDENT_TEMPLATE_HINT operator()(); - case JSVAL_TYPE_STRING: - return f. DEPENDENT_TEMPLATE_HINT operator()(); - case JSVAL_TYPE_OBJECT: - return f. DEPENDENT_TEMPLATE_HINT operator()(); - default: - MOZ_CRASH(); - } + return f. DEPENDENT_TEMPLATE_HINT operator()(); } // As above, except the specialization can reflect the unboxed type of two objects. @@ -692,42 +396,7 @@ CallBoxedOrUnboxedSpecialization(F f, JSObject* obj1, JSObject* obj2) if (!HasAnyBoxedOrUnboxedDenseElements(obj1) || !HasAnyBoxedOrUnboxedDenseElements(obj2)) return DenseElementResult::Incomplete; -#define SPECIALIZE_OBJ2(TYPE) \ - switch (GetBoxedOrUnboxedType(obj2)) { \ - case JSVAL_TYPE_MAGIC: \ - return f. DEPENDENT_TEMPLATE_HINT operator()(); \ - case JSVAL_TYPE_BOOLEAN: \ - return f. DEPENDENT_TEMPLATE_HINT operator()(); \ - case JSVAL_TYPE_INT32: \ - return f. DEPENDENT_TEMPLATE_HINT operator()(); \ - case JSVAL_TYPE_DOUBLE: \ - return f. DEPENDENT_TEMPLATE_HINT operator()(); \ - case JSVAL_TYPE_STRING: \ - return f. DEPENDENT_TEMPLATE_HINT operator()(); \ - case JSVAL_TYPE_OBJECT: \ - return f. DEPENDENT_TEMPLATE_HINT operator()(); \ - default: \ - MOZ_CRASH(); \ - } - - switch (GetBoxedOrUnboxedType(obj1)) { - case JSVAL_TYPE_MAGIC: - SPECIALIZE_OBJ2(JSVAL_TYPE_MAGIC) - case JSVAL_TYPE_BOOLEAN: - SPECIALIZE_OBJ2(JSVAL_TYPE_BOOLEAN) - case JSVAL_TYPE_INT32: - SPECIALIZE_OBJ2(JSVAL_TYPE_INT32) - case JSVAL_TYPE_DOUBLE: - SPECIALIZE_OBJ2(JSVAL_TYPE_DOUBLE) - case JSVAL_TYPE_STRING: - SPECIALIZE_OBJ2(JSVAL_TYPE_STRING) - case JSVAL_TYPE_OBJECT: - SPECIALIZE_OBJ2(JSVAL_TYPE_OBJECT) - default: - MOZ_CRASH(); - } - -#undef SPECIALIZE_OBJ2 + return f. DEPENDENT_TEMPLATE_HINT operator()(); } #undef DEPENDENT_TEMPLATE_HINT @@ -816,25 +485,6 @@ struct Signature ## Functor { \ } \ } -DenseElementResult -SetOrExtendAnyBoxedOrUnboxedDenseElements(ExclusiveContext* cx, JSObject* obj, - uint32_t start, const Value* vp, uint32_t count, - ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update); - -DenseElementResult -MoveAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, - uint32_t dstStart, uint32_t srcStart, uint32_t length); - -DenseElementResult -CopyAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src, - uint32_t dstStart, uint32_t srcStart, uint32_t length); - -void -SetAnyBoxedOrUnboxedInitializedLength(JSContext* cx, JSObject* obj, size_t initlen); - -DenseElementResult -EnsureAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t count); - } // namespace js #endif // vm_UnboxedObject_inl_h diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp index d7ad91de4..806a9db81 100644 --- a/js/src/vm/UnboxedObject.cpp +++ b/js/src/vm/UnboxedObject.cpp @@ -417,8 +417,6 @@ UnboxedLayout::makeNativeGroup(JSContext* cx, ObjectGroup* group) RootedObjectGroup replacementGroup(cx); - const Class* clasp = layout.isArray() ? &ArrayObject::class_ : &PlainObject::class_; - // Immediately clear any new script on the group. This is done by replacing // the existing new script with one for a replacement default new group. // This is done so that the size of the replacment group's objects is the @@ -426,8 +424,6 @@ UnboxedLayout::makeNativeGroup(JSContext* cx, ObjectGroup* group) // slot accesses later on for sites that see converted objects from this // group and objects that were allocated using the replacement new group. if (layout.newScript()) { - MOZ_ASSERT(!layout.isArray()); - replacementGroup = ObjectGroupCompartment::makeGroup(cx, &PlainObject::class_, proto); if (!replacementGroup) return false; @@ -453,15 +449,14 @@ UnboxedLayout::makeNativeGroup(JSContext* cx, ObjectGroup* group) RootedScript script(cx, layout.allocationScript()); jsbytecode* pc = layout.allocationPc(); - replacementGroup = ObjectGroupCompartment::makeGroup(cx, clasp, proto); + replacementGroup = ObjectGroupCompartment::makeGroup(cx, &PlainObject::class_, proto); if (!replacementGroup) return false; PlainObject* templateObject = &script->getObject(pc)->as(); replacementGroup->addDefiniteProperties(cx, templateObject->lastProperty()); - JSProtoKey key = layout.isArray() ? JSProto_Array : JSProto_Object; - cx->compartment()->objectGroups.replaceAllocationSiteGroup(script, pc, key, + cx->compartment()->objectGroups.replaceAllocationSiteGroup(script, pc, JSProto_Object, replacementGroup); // Clear any baseline information at this opcode which might use the old group. @@ -477,22 +472,12 @@ UnboxedLayout::makeNativeGroup(JSContext* cx, ObjectGroup* group) } } - size_t nfixed = layout.isArray() ? 0 : gc::GetGCKindSlots(layout.getAllocKind()); - - if (layout.isArray()) { - // The length shape to use for arrays is cached via a modified initial - // shape for array objects. Create an array now to make sure this entry - // is instantiated. - if (!NewDenseEmptyArray(cx)) - return false; - } + size_t nfixed = gc::GetGCKindSlots(layout.getAllocKind()); - RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, proto, nfixed, 0)); + RootedShape shape(cx, EmptyShape::getInitialShape(cx, &PlainObject::class_, proto, nfixed, 0)); if (!shape) return false; - MOZ_ASSERT_IF(layout.isArray(), !shape->isEmptyShape() && shape->slotSpan() == 0); - // Add shapes for each property, if this is for a plain object. for (size_t i = 0; i < layout.properties().length(); i++) { const UnboxedLayout::Property& property = layout.properties()[i]; @@ -505,7 +490,7 @@ UnboxedLayout::makeNativeGroup(JSContext* cx, ObjectGroup* group) } ObjectGroup* nativeGroup = - ObjectGroupCompartment::makeGroup(cx, clasp, proto, + ObjectGroupCompartment::makeGroup(cx, &PlainObject::class_, proto, group->flags() & OBJECT_FLAG_DYNAMIC_MASK); if (!nativeGroup) return false; @@ -513,24 +498,19 @@ UnboxedLayout::makeNativeGroup(JSContext* cx, ObjectGroup* group) // No sense propagating if we don't know what we started with. if (!group->unknownProperties()) { // Propagate all property types from the old group to the new group. - if (layout.isArray()) { - if (!PropagatePropertyTypes(cx, JSID_VOID, group, nativeGroup)) + for (size_t i = 0; i < layout.properties().length(); i++) { + const UnboxedLayout::Property& property = layout.properties()[i]; + jsid id = NameToId(property.name); + if (!PropagatePropertyTypes(cx, id, group, nativeGroup)) return false; - } else { - for (size_t i = 0; i < layout.properties().length(); i++) { - const UnboxedLayout::Property& property = layout.properties()[i]; - jsid id = NameToId(property.name); - if (!PropagatePropertyTypes(cx, id, group, nativeGroup)) - return false; - // If we are OOM we may not be able to propagate properties. - if (nativeGroup->unknownProperties()) - break; + // If we are OOM we may not be able to propagate properties. + if (nativeGroup->unknownProperties()) + break; - HeapTypeSet* nativeProperty = nativeGroup->maybeGetProperty(id); - if (nativeProperty && nativeProperty->canSetDefinite(i)) - nativeProperty->setDefinite(i); - } + HeapTypeSet* nativeProperty = nativeGroup->maybeGetProperty(id); + if (nativeProperty && nativeProperty->canSetDefinite(i)) + nativeProperty->setDefinite(i); } } else { // If we skip, though, the new group had better agree. @@ -955,702 +935,6 @@ const Class UnboxedPlainObject::class_ = { &UnboxedPlainObjectObjectOps }; -///////////////////////////////////////////////////////////////////// -// UnboxedArrayObject -///////////////////////////////////////////////////////////////////// - -template -DenseElementResult -AppendUnboxedDenseElements(UnboxedArrayObject* obj, uint32_t initlen, - MutableHandle> values) -{ - for (size_t i = 0; i < initlen; i++) - values.infallibleAppend(obj->getElementSpecific(i)); - return DenseElementResult::Success; -} - -DefineBoxedOrUnboxedFunctor3(AppendUnboxedDenseElements, - UnboxedArrayObject*, uint32_t, MutableHandle>); - -/* static */ bool -UnboxedArrayObject::convertToNativeWithGroup(ExclusiveContext* cx, JSObject* obj, - ObjectGroup* group, Shape* shape) -{ - size_t length = obj->as().length(); - size_t initlen = obj->as().initializedLength(); - - Rooted> values(cx, GCVector(cx)); - if (!values.reserve(initlen)) - return false; - - AppendUnboxedDenseElementsFunctor functor(&obj->as(), initlen, &values); - DebugOnly result = CallBoxedOrUnboxedSpecialization(functor, obj); - MOZ_ASSERT(result.value == DenseElementResult::Success); - - obj->setGroup(group); - - ArrayObject* aobj = &obj->as(); - aobj->setLastPropertyMakeNative(cx, shape); - - // Make sure there is at least one element, so that this array does not - // use emptyObjectElements / emptyObjectElementsShared. - if (!aobj->ensureElements(cx, Max(initlen, 1))) - return false; - - MOZ_ASSERT(!aobj->getDenseInitializedLength()); - aobj->setDenseInitializedLength(initlen); - aobj->initDenseElements(0, values.begin(), initlen); - aobj->setLengthInt32(length); - - return true; -} - -/* static */ bool -UnboxedArrayObject::convertToNative(JSContext* cx, JSObject* obj) -{ - const UnboxedLayout& layout = obj->as().layout(); - - if (!layout.nativeGroup()) { - if (!UnboxedLayout::makeNativeGroup(cx, obj->group())) - return false; - } - - return convertToNativeWithGroup(cx, obj, layout.nativeGroup(), layout.nativeShape()); -} - -bool -UnboxedArrayObject::convertInt32ToDouble(ExclusiveContext* cx, ObjectGroup* group) -{ - MOZ_ASSERT(elementType() == JSVAL_TYPE_INT32); - MOZ_ASSERT(group->unboxedLayout().elementType() == JSVAL_TYPE_DOUBLE); - - Vector values(cx); - if (!values.reserve(initializedLength())) - return false; - for (size_t i = 0; i < initializedLength(); i++) - values.infallibleAppend(getElementSpecific(i).toInt32()); - - uint8_t* newElements; - if (hasInlineElements()) { - newElements = AllocateObjectBuffer(cx, this, capacity() * sizeof(double)); - } else { - newElements = ReallocateObjectBuffer(cx, this, elements(), - capacity() * sizeof(int32_t), - capacity() * sizeof(double)); - } - if (!newElements) - return false; - - setGroup(group); - elements_ = newElements; - - for (size_t i = 0; i < initializedLength(); i++) - setElementNoTypeChangeSpecific(i, DoubleValue(values[i])); - - return true; -} - -/* static */ UnboxedArrayObject* -UnboxedArrayObject::create(ExclusiveContext* cx, HandleObjectGroup group, uint32_t length, - NewObjectKind newKind, uint32_t maxLength) -{ - MOZ_ASSERT(length <= MaximumCapacity); - - MOZ_ASSERT(group->clasp() == &class_); - uint32_t elementSize = UnboxedTypeSize(group->unboxedLayout().elementType()); - uint32_t capacity = Min(length, maxLength); - uint32_t nbytes = offsetOfInlineElements() + elementSize * capacity; - - UnboxedArrayObject* res; - if (nbytes <= JSObject::MAX_BYTE_SIZE) { - gc::AllocKind allocKind = gc::GetGCObjectKindForBytes(nbytes); - - // If there was no provided length information, pick an allocation kind - // to accommodate small arrays (as is done for normal native arrays). - if (capacity == 0) - allocKind = gc::AllocKind::OBJECT8; - - res = NewObjectWithGroup(cx, group, allocKind, newKind); - if (!res) - return nullptr; - res->setInitializedLengthNoBarrier(0); - res->setInlineElements(); - - size_t actualCapacity = (GetGCKindBytes(allocKind) - offsetOfInlineElements()) / elementSize; - MOZ_ASSERT(actualCapacity >= capacity); - res->setCapacityIndex(exactCapacityIndex(actualCapacity)); - } else { - res = NewObjectWithGroup(cx, group, gc::AllocKind::OBJECT0, newKind); - if (!res) - return nullptr; - res->setInitializedLengthNoBarrier(0); - - uint32_t capacityIndex = (capacity == length) - ? CapacityMatchesLengthIndex - : chooseCapacityIndex(capacity, length); - uint32_t actualCapacity = computeCapacity(capacityIndex, length); - - res->elements_ = AllocateObjectBuffer(cx, res, actualCapacity * elementSize); - if (!res->elements_) { - // Make the object safe for GC. - res->setInlineElements(); - return nullptr; - } - - res->setCapacityIndex(capacityIndex); - } - - res->setLength(cx, length); - return res; -} - -bool -UnboxedArrayObject::setElement(ExclusiveContext* cx, size_t index, const Value& v) -{ - MOZ_ASSERT(index < initializedLength()); - uint8_t* p = elements() + index * elementSize(); - return SetUnboxedValue(cx, this, JSID_VOID, p, elementType(), v, /* preBarrier = */ true); -} - -bool -UnboxedArrayObject::initElement(ExclusiveContext* cx, size_t index, const Value& v) -{ - MOZ_ASSERT(index < initializedLength()); - uint8_t* p = elements() + index * elementSize(); - return SetUnboxedValue(cx, this, JSID_VOID, p, elementType(), v, /* preBarrier = */ false); -} - -void -UnboxedArrayObject::initElementNoTypeChange(size_t index, const Value& v) -{ - MOZ_ASSERT(index < initializedLength()); - uint8_t* p = elements() + index * elementSize(); - if (UnboxedTypeNeedsPreBarrier(elementType())) - *reinterpret_cast(p) = nullptr; - SetUnboxedValueNoTypeChange(this, p, elementType(), v, /* preBarrier = */ false); -} - -Value -UnboxedArrayObject::getElement(size_t index) -{ - MOZ_ASSERT(index < initializedLength()); - uint8_t* p = elements() + index * elementSize(); - return GetUnboxedValue(p, elementType(), /* maybeUninitialized = */ false); -} - -/* static */ void -UnboxedArrayObject::trace(JSTracer* trc, JSObject* obj) -{ - JSValueType type = obj->as().elementType(); - if (!UnboxedTypeNeedsPreBarrier(type)) - return; - - MOZ_ASSERT(obj->as().elementSize() == sizeof(uintptr_t)); - size_t initlen = obj->as().initializedLength(); - void** elements = reinterpret_cast(obj->as().elements()); - - switch (type) { - case JSVAL_TYPE_OBJECT: - for (size_t i = 0; i < initlen; i++) { - GCPtrObject* heap = reinterpret_cast(elements + i); - TraceNullableEdge(trc, heap, "unboxed_object"); - } - break; - - case JSVAL_TYPE_STRING: - for (size_t i = 0; i < initlen; i++) { - GCPtrString* heap = reinterpret_cast(elements + i); - TraceEdge(trc, heap, "unboxed_string"); - } - break; - - default: - MOZ_CRASH(); - } -} - -/* static */ void -UnboxedArrayObject::objectMoved(JSObject* obj, const JSObject* old) -{ - UnboxedArrayObject& dst = obj->as(); - const UnboxedArrayObject& src = old->as(); - - // Fix up possible inline data pointer. - if (src.hasInlineElements()) - dst.setInlineElements(); -} - -/* static */ void -UnboxedArrayObject::finalize(FreeOp* fop, JSObject* obj) -{ - MOZ_ASSERT(!IsInsideNursery(obj)); - if (!obj->as().hasInlineElements()) - js_free(obj->as().elements()); -} - -/* static */ size_t -UnboxedArrayObject::objectMovedDuringMinorGC(JSTracer* trc, JSObject* dst, JSObject* src, - gc::AllocKind allocKind) -{ - UnboxedArrayObject* ndst = &dst->as(); - UnboxedArrayObject* nsrc = &src->as(); - MOZ_ASSERT(ndst->elements() == nsrc->elements()); - - Nursery& nursery = trc->runtime()->gc.nursery; - - if (!nursery.isInside(nsrc->elements())) { - nursery.removeMallocedBuffer(nsrc->elements()); - return 0; - } - - // Determine if we can use inline data for the target array. If this is - // possible, the nursery will have picked an allocation size that is large - // enough. - size_t nbytes = nsrc->capacity() * nsrc->elementSize(); - if (offsetOfInlineElements() + nbytes <= GetGCKindBytes(allocKind)) { - ndst->setInlineElements(); - } else { - MOZ_ASSERT(allocKind == gc::AllocKind::OBJECT0); - - AutoEnterOOMUnsafeRegion oomUnsafe; - uint8_t* data = nsrc->zone()->pod_malloc(nbytes); - if (!data) - oomUnsafe.crash("Failed to allocate unboxed array elements while tenuring."); - ndst->elements_ = data; - } - - PodCopy(ndst->elements(), nsrc->elements(), nsrc->initializedLength() * nsrc->elementSize()); - - // Set a forwarding pointer for the element buffers in case they were - // preserved on the stack by Ion. - bool direct = nsrc->capacity() * nsrc->elementSize() >= sizeof(uintptr_t); - nursery.maybeSetForwardingPointer(trc, nsrc->elements(), ndst->elements(), direct); - - return ndst->hasInlineElements() ? 0 : nbytes; -} - -// Possible capacities for unboxed arrays. Some of these capacities might seem -// a little weird, but were chosen to allow the inline data of objects of each -// size to be fully utilized for arrays of the various types on both 32 bit and -// 64 bit platforms. -// -// To find the possible inline capacities, the following script was used: -// -// var fixedSlotCapacities = [0, 2, 4, 8, 12, 16]; -// var dataSizes = [1, 4, 8]; -// var header32 = 4 * 2 + 4 * 2; -// var header64 = 8 * 2 + 4 * 2; -// -// for (var i = 0; i < fixedSlotCapacities.length; i++) { -// var nfixed = fixedSlotCapacities[i]; -// var size32 = 4 * 4 + 8 * nfixed - header32; -// var size64 = 8 * 4 + 8 * nfixed - header64; -// for (var j = 0; j < dataSizes.length; j++) { -// print(size32 / dataSizes[j]); -// print(size64 / dataSizes[j]); -// } -// } -// -/* static */ const uint32_t -UnboxedArrayObject::CapacityArray[] = { - UINT32_MAX, // For CapacityMatchesLengthIndex. - 0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 13, 16, 17, 18, 24, 26, 32, 34, 40, 64, 72, 96, 104, 128, 136, - 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, - 1048576, 2097152, 3145728, 4194304, 5242880, 6291456, 7340032, 8388608, 9437184, 11534336, - 13631488, 15728640, 17825792, 20971520, 24117248, 27262976, 31457280, 35651584, 40894464, - 46137344, 52428800, 59768832, MaximumCapacity -}; - -static const uint32_t -Pow2CapacityIndexes[] = { - 2, // 1 - 3, // 2 - 5, // 4 - 8, // 8 - 13, // 16 - 18, // 32 - 21, // 64 - 25, // 128 - 27, // 256 - 28, // 512 - 29, // 1024 - 30, // 2048 - 31, // 4096 - 32, // 8192 - 33, // 16384 - 34, // 32768 - 35, // 65536 - 36, // 131072 - 37, // 262144 - 38, // 524288 - 39 // 1048576 -}; - -static const uint32_t MebiCapacityIndex = 39; - -/* static */ uint32_t -UnboxedArrayObject::chooseCapacityIndex(uint32_t capacity, uint32_t length) -{ - // Note: the structure and behavior of this method follow along with - // NativeObject::goodAllocated. Changes to the allocation strategy in one - // should generally be matched by the other. - - // Make sure we have enough space to store all possible values for the capacity index. - // This ought to be a static_assert, but MSVC doesn't like that. - MOZ_ASSERT(mozilla::ArrayLength(CapacityArray) - 1 <= (CapacityMask >> CapacityShift)); - - // The caller should have ensured the capacity is possible for an unboxed array. - MOZ_ASSERT(capacity <= MaximumCapacity); - - static const uint32_t Mebi = 1024 * 1024; - - if (capacity <= Mebi) { - capacity = mozilla::RoundUpPow2(capacity); - - // When the required capacity is close to the array length, then round - // up to the array length itself, as for NativeObject. - if (length >= capacity && capacity > (length / 3) * 2) - return CapacityMatchesLengthIndex; - - if (capacity < MinimumDynamicCapacity) - capacity = MinimumDynamicCapacity; - - uint32_t bit = mozilla::FloorLog2Size(capacity); - MOZ_ASSERT(capacity == uint32_t(1 << bit)); - MOZ_ASSERT(bit <= 20); - MOZ_ASSERT(mozilla::ArrayLength(Pow2CapacityIndexes) == 21); - - uint32_t index = Pow2CapacityIndexes[bit]; - MOZ_ASSERT(CapacityArray[index] == capacity); - - return index; - } - - MOZ_ASSERT(CapacityArray[MebiCapacityIndex] == Mebi); - - for (uint32_t i = MebiCapacityIndex + 1;; i++) { - if (CapacityArray[i] >= capacity) - return i; - } - - MOZ_CRASH("Invalid capacity"); -} - -/* static */ uint32_t -UnboxedArrayObject::exactCapacityIndex(uint32_t capacity) -{ - for (size_t i = CapacityMatchesLengthIndex + 1; i < ArrayLength(CapacityArray); i++) { - if (CapacityArray[i] == capacity) - return i; - } - MOZ_CRASH(); -} - -bool -UnboxedArrayObject::growElements(ExclusiveContext* cx, size_t cap) -{ - // The caller should have checked if this capacity is possible for an - // unboxed array, so the only way this call can fail is from OOM. - MOZ_ASSERT(cap <= MaximumCapacity); - - uint32_t oldCapacity = capacity(); - uint32_t newCapacityIndex = chooseCapacityIndex(cap, length()); - uint32_t newCapacity = computeCapacity(newCapacityIndex, length()); - - MOZ_ASSERT(oldCapacity < cap); - MOZ_ASSERT(cap <= newCapacity); - - // The allocation size computation below cannot have integer overflows. - JS_STATIC_ASSERT(MaximumCapacity < UINT32_MAX / sizeof(double)); - - uint8_t* newElements; - if (hasInlineElements()) { - newElements = AllocateObjectBuffer(cx, this, newCapacity * elementSize()); - if (!newElements) - return false; - js_memcpy(newElements, elements(), initializedLength() * elementSize()); - } else { - newElements = ReallocateObjectBuffer(cx, this, elements(), - oldCapacity * elementSize(), - newCapacity * elementSize()); - if (!newElements) - return false; - } - - elements_ = newElements; - setCapacityIndex(newCapacityIndex); - - return true; -} - -void -UnboxedArrayObject::shrinkElements(ExclusiveContext* cx, size_t cap) -{ - if (hasInlineElements()) - return; - - uint32_t oldCapacity = capacity(); - uint32_t newCapacityIndex = chooseCapacityIndex(cap, 0); - uint32_t newCapacity = computeCapacity(newCapacityIndex, 0); - - MOZ_ASSERT(cap < oldCapacity); - MOZ_ASSERT(cap <= newCapacity); - - if (newCapacity >= oldCapacity) - return; - - uint8_t* newElements = ReallocateObjectBuffer(cx, this, elements(), - oldCapacity * elementSize(), - newCapacity * elementSize()); - if (!newElements) - return; - - elements_ = newElements; - setCapacityIndex(newCapacityIndex); -} - -bool -UnboxedArrayObject::containsProperty(ExclusiveContext* cx, jsid id) -{ - if (JSID_IS_INT(id) && uint32_t(JSID_TO_INT(id)) < initializedLength()) - return true; - if (JSID_IS_ATOM(id) && JSID_TO_ATOM(id) == cx->names().length) - return true; - return false; -} - -/* static */ bool -UnboxedArrayObject::obj_lookupProperty(JSContext* cx, HandleObject obj, - HandleId id, MutableHandleObject objp, - MutableHandleShape propp) -{ - if (obj->as().containsProperty(cx, id)) { - MarkNonNativePropertyFound(propp); - objp.set(obj); - return true; - } - - RootedObject proto(cx, obj->staticPrototype()); - if (!proto) { - objp.set(nullptr); - propp.set(nullptr); - return true; - } - - return LookupProperty(cx, proto, id, objp, propp); -} - -/* static */ bool -UnboxedArrayObject::obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id, - Handle desc, - ObjectOpResult& result) -{ - if (JSID_IS_INT(id) && !desc.getter() && !desc.setter() && desc.attributes() == JSPROP_ENUMERATE) { - UnboxedArrayObject* nobj = &obj->as(); - - uint32_t index = JSID_TO_INT(id); - if (index < nobj->initializedLength()) { - if (nobj->setElement(cx, index, desc.value())) - return result.succeed(); - } else if (index == nobj->initializedLength() && index < MaximumCapacity) { - if (nobj->initializedLength() == nobj->capacity()) { - if (!nobj->growElements(cx, index + 1)) - return false; - } - nobj->setInitializedLength(index + 1); - if (nobj->initElement(cx, index, desc.value())) { - if (nobj->length() <= index) - nobj->setLengthInt32(index + 1); - return result.succeed(); - } - nobj->setInitializedLengthNoBarrier(index); - } - } - - if (!convertToNative(cx, obj)) - return false; - - return DefineProperty(cx, obj, id, desc, result); -} - -/* static */ bool -UnboxedArrayObject::obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp) -{ - if (obj->as().containsProperty(cx, id)) { - *foundp = true; - return true; - } - - RootedObject proto(cx, obj->staticPrototype()); - if (!proto) { - *foundp = false; - return true; - } - - return HasProperty(cx, proto, id, foundp); -} - -/* static */ bool -UnboxedArrayObject::obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver, - HandleId id, MutableHandleValue vp) -{ - if (obj->as().containsProperty(cx, id)) { - if (JSID_IS_INT(id)) - vp.set(obj->as().getElement(JSID_TO_INT(id))); - else - vp.set(Int32Value(obj->as().length())); - return true; - } - - RootedObject proto(cx, obj->staticPrototype()); - if (!proto) { - vp.setUndefined(); - return true; - } - - return GetProperty(cx, proto, receiver, id, vp); -} - -/* static */ bool -UnboxedArrayObject::obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v, - HandleValue receiver, ObjectOpResult& result) -{ - if (obj->as().containsProperty(cx, id)) { - if (receiver.isObject() && obj == &receiver.toObject()) { - if (JSID_IS_INT(id)) { - if (obj->as().setElement(cx, JSID_TO_INT(id), v)) - return result.succeed(); - } else { - uint32_t len; - if (!CanonicalizeArrayLengthValue(cx, v, &len)) - return false; - UnboxedArrayObject* nobj = &obj->as(); - if (len < nobj->initializedLength()) { - nobj->setInitializedLength(len); - nobj->shrinkElements(cx, len); - } - nobj->setLength(cx, len); - return result.succeed(); - } - - if (!convertToNative(cx, obj)) - return false; - return SetProperty(cx, obj, id, v, receiver, result); - } - - return SetPropertyByDefining(cx, id, v, receiver, result); - } - - return SetPropertyOnProto(cx, obj, id, v, receiver, result); -} - -/* static */ bool -UnboxedArrayObject::obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id, - MutableHandle desc) -{ - if (obj->as().containsProperty(cx, id)) { - if (JSID_IS_INT(id)) { - desc.value().set(obj->as().getElement(JSID_TO_INT(id))); - desc.setAttributes(JSPROP_ENUMERATE); - } else { - desc.value().set(Int32Value(obj->as().length())); - desc.setAttributes(JSPROP_PERMANENT); - } - desc.object().set(obj); - return true; - } - - desc.object().set(nullptr); - return true; -} - -/* static */ bool -UnboxedArrayObject::obj_deleteProperty(JSContext* cx, HandleObject obj, HandleId id, - ObjectOpResult& result) -{ - if (obj->as().containsProperty(cx, id)) { - size_t initlen = obj->as().initializedLength(); - if (JSID_IS_INT(id) && JSID_TO_INT(id) == int32_t(initlen - 1)) { - obj->as().setInitializedLength(initlen - 1); - obj->as().shrinkElements(cx, initlen - 1); - return result.succeed(); - } - } - - if (!convertToNative(cx, obj)) - return false; - return DeleteProperty(cx, obj, id, result); -} - -/* static */ bool -UnboxedArrayObject::obj_watch(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable) -{ - if (!convertToNative(cx, obj)) - return false; - return WatchProperty(cx, obj, id, callable); -} - -/* static */ bool -UnboxedArrayObject::obj_enumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties, - bool enumerableOnly) -{ - for (size_t i = 0; i < obj->as().initializedLength(); i++) { - if (!properties.append(INT_TO_JSID(i))) - return false; - } - - if (!enumerableOnly && !properties.append(NameToId(cx->names().length))) - return false; - - return true; -} - -static const ClassOps UnboxedArrayObjectClassOps = { - nullptr, /* addProperty */ - nullptr, /* delProperty */ - nullptr, /* getProperty */ - nullptr, /* setProperty */ - nullptr, /* enumerate */ - nullptr, /* resolve */ - nullptr, /* mayResolve */ - UnboxedArrayObject::finalize, - nullptr, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - UnboxedArrayObject::trace, -}; - -static const ClassExtension UnboxedArrayObjectClassExtension = { - nullptr, /* weakmapKeyDelegateOp */ - UnboxedArrayObject::objectMoved -}; - -static const ObjectOps UnboxedArrayObjectObjectOps = { - UnboxedArrayObject::obj_lookupProperty, - UnboxedArrayObject::obj_defineProperty, - UnboxedArrayObject::obj_hasProperty, - UnboxedArrayObject::obj_getProperty, - UnboxedArrayObject::obj_setProperty, - UnboxedArrayObject::obj_getOwnPropertyDescriptor, - UnboxedArrayObject::obj_deleteProperty, - UnboxedArrayObject::obj_watch, - nullptr, /* No unwatch needed, as watch() converts the object to native */ - nullptr, /* getElements */ - UnboxedArrayObject::obj_enumerate, - nullptr /* funToString */ -}; - -const Class UnboxedArrayObject::class_ = { - "Array", - Class::NON_NATIVE | - JSCLASS_SKIP_NURSERY_FINALIZE | - JSCLASS_BACKGROUND_FINALIZE, - &UnboxedArrayObjectClassOps, - JS_NULL_CLASS_SPEC, - &UnboxedArrayObjectClassExtension, - &UnboxedArrayObjectObjectOps -}; - ///////////////////////////////////////////////////////////////////// // API ///////////////////////////////////////////////////////////////////// @@ -1661,31 +945,6 @@ NextValue(Handle> values, size_t* valueCursor) return values[(*valueCursor)++]; } -void -UnboxedArrayObject::fillAfterConvert(ExclusiveContext* cx, - Handle> values, size_t* valueCursor) -{ - MOZ_ASSERT(CapacityArray[1] == 0); - setCapacityIndex(1); - setInitializedLengthNoBarrier(0); - setInlineElements(); - - setLength(cx, NextValue(values, valueCursor).toInt32()); - - int32_t initlen = NextValue(values, valueCursor).toInt32(); - if (!initlen) - return; - - AutoEnterOOMUnsafeRegion oomUnsafe; - if (!growElements(cx, initlen)) - oomUnsafe.crash("UnboxedArrayObject::fillAfterConvert"); - - setInitializedLength(initlen); - - for (size_t i = 0; i < size_t(initlen); i++) - JS_ALWAYS_TRUE(initElement(cx, i, NextValue(values, valueCursor))); -} - void UnboxedPlainObject::fillAfterConvert(ExclusiveContext* cx, Handle> values, size_t* valueCursor) @@ -1695,58 +954,3 @@ UnboxedPlainObject::fillAfterConvert(ExclusiveContext* cx, for (size_t i = 0; i < layout().properties().length(); i++) JS_ALWAYS_TRUE(setValue(cx, layout().properties()[i], NextValue(values, valueCursor))); } - -DefineBoxedOrUnboxedFunctor6(SetOrExtendBoxedOrUnboxedDenseElements, - ExclusiveContext*, JSObject*, uint32_t, const Value*, uint32_t, - ShouldUpdateTypes); - -DenseElementResult -js::SetOrExtendAnyBoxedOrUnboxedDenseElements(ExclusiveContext* cx, JSObject* obj, - uint32_t start, const Value* vp, uint32_t count, - ShouldUpdateTypes updateTypes) -{ - SetOrExtendBoxedOrUnboxedDenseElementsFunctor functor(cx, obj, start, vp, count, updateTypes); - return CallBoxedOrUnboxedSpecialization(functor, obj); -}; - -DefineBoxedOrUnboxedFunctor5(MoveBoxedOrUnboxedDenseElements, - JSContext*, JSObject*, uint32_t, uint32_t, uint32_t); - -DenseElementResult -js::MoveAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, - uint32_t dstStart, uint32_t srcStart, uint32_t length) -{ - MoveBoxedOrUnboxedDenseElementsFunctor functor(cx, obj, dstStart, srcStart, length); - return CallBoxedOrUnboxedSpecialization(functor, obj); -} - -DefineBoxedOrUnboxedFunctorPair6(CopyBoxedOrUnboxedDenseElements, - JSContext*, JSObject*, JSObject*, uint32_t, uint32_t, uint32_t); - -DenseElementResult -js::CopyAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src, - uint32_t dstStart, uint32_t srcStart, uint32_t length) -{ - CopyBoxedOrUnboxedDenseElementsFunctor functor(cx, dst, src, dstStart, srcStart, length); - return CallBoxedOrUnboxedSpecialization(functor, dst, src); -} - -DefineBoxedOrUnboxedFunctor3(SetBoxedOrUnboxedInitializedLength, - JSContext*, JSObject*, size_t); - -void -js::SetAnyBoxedOrUnboxedInitializedLength(JSContext* cx, JSObject* obj, size_t initlen) -{ - SetBoxedOrUnboxedInitializedLengthFunctor functor(cx, obj, initlen); - JS_ALWAYS_TRUE(CallBoxedOrUnboxedSpecialization(functor, obj) == DenseElementResult::Success); -} - -DefineBoxedOrUnboxedFunctor3(EnsureBoxedOrUnboxedDenseElements, - JSContext*, JSObject*, size_t); - -DenseElementResult -js::EnsureAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t initlen) -{ - EnsureBoxedOrUnboxedDenseElementsFunctor functor(cx, obj, initlen); - return CallBoxedOrUnboxedSpecialization(functor, obj); -} diff --git a/js/src/vm/UnboxedObject.h b/js/src/vm/UnboxedObject.h index 779dd14c7..ba66434bc 100644 --- a/js/src/vm/UnboxedObject.h +++ b/js/src/vm/UnboxedObject.h @@ -96,17 +96,11 @@ class UnboxedLayout : public mozilla::LinkedListElement // from an array of values. GCPtrJitCode constructorCode_; - // The following members are only used for unboxed arrays. - - // The type of array elements. - JSValueType elementType_; - public: UnboxedLayout() : nativeGroup_(nullptr), nativeShape_(nullptr), allocationScript_(nullptr), allocationPc_(nullptr), replacementGroup_(nullptr), - size_(0), newScript_(nullptr), traceList_(nullptr), constructorCode_(nullptr), - elementType_(JSVAL_TYPE_MAGIC) + size_(0), newScript_(nullptr), traceList_(nullptr), constructorCode_(nullptr) {} bool initProperties(const PropertyVector& properties, size_t size) { @@ -114,10 +108,6 @@ class UnboxedLayout : public mozilla::LinkedListElement return properties_.appendAll(properties); } - void initArray(JSValueType elementType) { - elementType_ = elementType; - } - ~UnboxedLayout() { if (newScript_) newScript_->clear(); @@ -130,10 +120,6 @@ class UnboxedLayout : public mozilla::LinkedListElement constructorCode_.init(nullptr); } - bool isArray() const { - return elementType_ != JSVAL_TYPE_MAGIC; - } - void detachFromCompartment(); const PropertyVector& properties() const { @@ -201,10 +187,6 @@ class UnboxedLayout : public mozilla::LinkedListElement constructorCode_ = code; } - JSValueType elementType() const { - return elementType_; - } - inline gc::AllocKind getAllocKind() const; void trace(JSTracer* trc); @@ -324,193 +306,6 @@ UnboxedLayout::getAllocKind() const return gc::GetGCObjectKindForBytes(UnboxedPlainObject::offsetOfData() + size()); } -// Class for an array object using an unboxed representation. -class UnboxedArrayObject : public JSObject -{ - // Elements pointer for the object. - uint8_t* elements_; - - // The nominal array length. This always fits in an int32_t. - uint32_t length_; - - // Value indicating the allocated capacity and initialized length of the - // array. The top CapacityBits bits are an index into CapacityArray, which - // indicates the elements capacity. The low InitializedLengthBits store the - // initialized length of the array. - uint32_t capacityIndexAndInitializedLength_; - - // If the elements are inline, they will point here. - uint8_t inlineElements_[1]; - - public: - static const uint32_t CapacityBits = 6; - static const uint32_t CapacityShift = 26; - - static const uint32_t CapacityMask = uint32_t(-1) << CapacityShift; - static const uint32_t InitializedLengthMask = (1 << CapacityShift) - 1; - - static const uint32_t MaximumCapacity = InitializedLengthMask; - static const uint32_t MinimumDynamicCapacity = 8; - - static const uint32_t CapacityArray[]; - - // Capacity index which indicates the array's length is also its capacity. - static const uint32_t CapacityMatchesLengthIndex = 0; - - private: - static inline uint32_t computeCapacity(uint32_t index, uint32_t length) { - if (index == CapacityMatchesLengthIndex) - return length; - return CapacityArray[index]; - } - - static uint32_t chooseCapacityIndex(uint32_t capacity, uint32_t length); - static uint32_t exactCapacityIndex(uint32_t capacity); - - public: - static const Class class_; - - static bool obj_lookupProperty(JSContext* cx, HandleObject obj, - HandleId id, MutableHandleObject objp, - MutableHandleShape propp); - - static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id, - Handle desc, - ObjectOpResult& result); - - static bool obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp); - - static bool obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver, - HandleId id, MutableHandleValue vp); - - static bool obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v, - HandleValue receiver, ObjectOpResult& result); - - static bool obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id, - MutableHandle desc); - - static bool obj_deleteProperty(JSContext* cx, HandleObject obj, HandleId id, - ObjectOpResult& result); - - static bool obj_enumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties, - bool enumerableOnly); - static bool obj_watch(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable); - - inline const UnboxedLayout& layout() const; - - const UnboxedLayout& layoutDontCheckGeneration() const { - return group()->unboxedLayoutDontCheckGeneration(); - } - - JSValueType elementType() const { - return layoutDontCheckGeneration().elementType(); - } - - uint32_t elementSize() const { - return UnboxedTypeSize(elementType()); - } - - static bool convertToNative(JSContext* cx, JSObject* obj); - static UnboxedArrayObject* create(ExclusiveContext* cx, HandleObjectGroup group, - uint32_t length, NewObjectKind newKind, - uint32_t maxLength = MaximumCapacity); - - static bool convertToNativeWithGroup(ExclusiveContext* cx, JSObject* obj, - ObjectGroup* group, Shape* shape); - bool convertInt32ToDouble(ExclusiveContext* cx, ObjectGroup* group); - - void fillAfterConvert(ExclusiveContext* cx, - Handle> values, size_t* valueCursor); - - static void trace(JSTracer* trc, JSObject* object); - static void objectMoved(JSObject* obj, const JSObject* old); - static void finalize(FreeOp* fop, JSObject* obj); - - static size_t objectMovedDuringMinorGC(JSTracer* trc, JSObject* dst, JSObject* src, - gc::AllocKind allocKind); - - uint8_t* elements() { - return elements_; - } - - bool hasInlineElements() const { - return elements_ == &inlineElements_[0]; - } - - uint32_t length() const { - return length_; - } - - uint32_t initializedLength() const { - return capacityIndexAndInitializedLength_ & InitializedLengthMask; - } - - uint32_t capacityIndex() const { - return (capacityIndexAndInitializedLength_ & CapacityMask) >> CapacityShift; - } - - uint32_t capacity() const { - return computeCapacity(capacityIndex(), length()); - } - - bool containsProperty(ExclusiveContext* cx, jsid id); - - bool setElement(ExclusiveContext* cx, size_t index, const Value& v); - bool initElement(ExclusiveContext* cx, size_t index, const Value& v); - void initElementNoTypeChange(size_t index, const Value& v); - Value getElement(size_t index); - - template inline bool setElementSpecific(ExclusiveContext* cx, size_t index, - const Value& v); - template inline void setElementNoTypeChangeSpecific(size_t index, const Value& v); - template inline bool initElementSpecific(ExclusiveContext* cx, size_t index, - const Value& v); - template inline void initElementNoTypeChangeSpecific(size_t index, const Value& v); - template inline Value getElementSpecific(size_t index); - template inline void triggerPreBarrier(size_t index); - - bool growElements(ExclusiveContext* cx, size_t cap); - void shrinkElements(ExclusiveContext* cx, size_t cap); - - static uint32_t offsetOfElements() { - return offsetof(UnboxedArrayObject, elements_); - } - static uint32_t offsetOfLength() { - return offsetof(UnboxedArrayObject, length_); - } - static uint32_t offsetOfCapacityIndexAndInitializedLength() { - return offsetof(UnboxedArrayObject, capacityIndexAndInitializedLength_); - } - static uint32_t offsetOfInlineElements() { - return offsetof(UnboxedArrayObject, inlineElements_); - } - - void setLengthInt32(uint32_t length) { - MOZ_ASSERT(length <= INT32_MAX); - length_ = length; - } - - inline void setLength(ExclusiveContext* cx, uint32_t len); - inline void setInitializedLength(uint32_t initlen); - - inline void setInitializedLengthNoBarrier(uint32_t initlen) { - MOZ_ASSERT(initlen <= InitializedLengthMask); - capacityIndexAndInitializedLength_ = - (capacityIndexAndInitializedLength_ & CapacityMask) | initlen; - } - - private: - void setInlineElements() { - elements_ = &inlineElements_[0]; - } - - void setCapacityIndex(uint32_t index) { - MOZ_ASSERT(index <= (CapacityMask >> CapacityShift)); - capacityIndexAndInitializedLength_ = - (index << CapacityShift) | initializedLength(); - } -}; - } // namespace js namespace JS { -- cgit v1.2.3 From e24e6346b70d3d212e9c9b7aa14f79f1d3ea86e8 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 25 May 2019 00:31:24 +0200 Subject: Fix architecture flag for PPC64 Fixes #1092 --- js/src/jstypes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'js/src') diff --git a/js/src/jstypes.h b/js/src/jstypes.h index 6cfb3d4ad..04ffbe00d 100644 --- a/js/src/jstypes.h +++ b/js/src/jstypes.h @@ -147,7 +147,7 @@ # define JS_64BIT # endif #elif defined(__GNUC__) -# if defined(__x86_64__) || defined(__64BIT__) +# if defined(__x86_64__) || defined(__LP64__) # define JS_64BIT # endif #elif defined(__xlc__) || defined(__xlC__) /* IBM XL C/C++ */ -- cgit v1.2.3 From a24d62130932b8104f931f925288d3abc9105684 Mon Sep 17 00:00:00 2001 From: Lars T Hansen Date: Sat, 25 May 2019 15:41:06 +0200 Subject: [js, ARM] Always check error return from BufferOffset::diffB. We were missing error checks at two points. In one case an error return is meaningful; in another case it is not, as the problem should have been guarded against at a higher level by emitting far jump islands soon enough during pasteup of compiled code. --- js/src/jit/arm/Assembler-arm.cpp | 7 ++++++- js/src/jit/arm/MacroAssembler-arm.cpp | 5 ++++- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/arm/Assembler-arm.cpp b/js/src/jit/arm/Assembler-arm.cpp index 2830f0695..1e20da1c8 100644 --- a/js/src/jit/arm/Assembler-arm.cpp +++ b/js/src/jit/arm/Assembler-arm.cpp @@ -2401,7 +2401,12 @@ Assembler::as_b(Label* l, Condition c) if (oom()) return BufferOffset(); - as_b(BufferOffset(l).diffB(ret), c, ret); + BOffImm off = BufferOffset(l).diffB(ret); + if (off.isInvalid()) { + m_buffer.fail_bail(); + return BufferOffset(); + } + as_b(off, c, ret); #ifdef JS_DISASM_ARM spewBranch(m_buffer.getInstOrNull(ret), l); #endif diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index d40578514..a4161ab00 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -5012,7 +5012,10 @@ void MacroAssembler::patchCall(uint32_t callerOffset, uint32_t calleeOffset) { BufferOffset inst(callerOffset - 4); - as_bl(BufferOffset(calleeOffset).diffB(inst), Always, inst); + BOffImm off = BufferOffset(calleeOffset).diffB(inst); + MOZ_RELEASE_ASSERT(!off.isInvalid(), + "Failed to insert necessary far jump islands"); + as_bl(off, Always, inst); } CodeOffset -- cgit v1.2.3 From 6cc615bbe5224cf74fc302a6fb72d0de56feb719 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Tue, 28 May 2019 18:03:08 +0200 Subject: Improve efficiency of (C++) heap allocations related to BytecodeEmitter::code. While there, also add some sanity checks and clean up code. --- js/src/frontend/BytecodeEmitter.cpp | 28 ++++++++++++++++++---------- js/src/frontend/BytecodeEmitter.h | 10 ++++++---- 2 files changed, 24 insertions(+), 14 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index b3dd6d777..c524184d6 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -2260,12 +2260,14 @@ BytecodeEmitter::locationOfNameBoundInFunctionScope(JSAtom* name, EmitterScope* bool BytecodeEmitter::emitCheck(ptrdiff_t delta, ptrdiff_t* offset) { - *offset = code().length(); + size_t oldLength = code().length(); + *offset = ptrdiff_t(oldLength); - // Start it off moderately large to avoid repeated resizings early on. - // ~98% of cases fit within 1024 bytes. - if (code().capacity() == 0 && !code().reserve(1024)) - return false; + size_t newLength = oldLength + size_t(delta); + if (MOZ_UNLIKELY(newLength > MaxBytecodeLength)) { + ReportAllocationOverflow(cx); + return false; + } if (!code().growBy(delta)) { ReportOutOfMemory(cx); @@ -10697,17 +10699,19 @@ BytecodeEmitter::emitTreeInBranch(ParseNode* pn) static bool AllocSrcNote(ExclusiveContext* cx, SrcNotesVector& notes, unsigned* index) { - // Start it off moderately large to avoid repeated resizings early on. - // ~99% of cases fit within 256 bytes. - if (notes.capacity() == 0 && !notes.reserve(256)) - return false; + size_t oldLength = notes.length(); + if (MOZ_UNLIKELY(oldLength + 1 > MaxSrcNotesLength)) { + ReportAllocationOverflow(cx); + return false; + } + if (!notes.growBy(1)) { ReportOutOfMemory(cx); return false; } - *index = notes.length() - 1; + *index = oldLength; return true; } @@ -10833,6 +10837,10 @@ BytecodeEmitter::setSrcNoteOffset(unsigned index, unsigned which, ptrdiff_t offs /* Maybe this offset was already set to a four-byte value. */ if (!(*sn & SN_4BYTE_OFFSET_FLAG)) { /* Insert three dummy bytes that will be overwritten shortly. */ + if (MOZ_UNLIKELY(notes.length() + 3 > MaxSrcNotesLength)) { + ReportAllocationOverflow(cx); + return false; + } jssrcnote dummy = 0; if (!(sn = notes.insert(sn, dummy)) || !(sn = notes.insert(sn, dummy)) || diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index 32668a34c..814fa11d4 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -109,10 +109,12 @@ struct CGYieldOffsetList { void finish(YieldOffsetArray& array, uint32_t prologueLength); }; -// Use zero inline elements because these go on the stack and affect how many -// nested functions are possible. -typedef Vector BytecodeVector; -typedef Vector SrcNotesVector; +static size_t MaxBytecodeLength = INT32_MAX; +static size_t MaxSrcNotesLength = INT32_MAX; + +// Have a few inline elements to avoid heap allocation for tiny sequences. +typedef Vector BytecodeVector; +typedef Vector SrcNotesVector; // Linked list of jump instructions that need to be patched. The linked list is // stored in the bytes of the incomplete bytecode that will be patched, so no -- cgit v1.2.3 From 50062bdfc004c8e24e3344ffe6991894ee0e6d09 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Wed, 29 May 2019 11:08:31 +0200 Subject: Fix #1091 deprot --- js/src/jit/IonCaches.cpp | 1 + js/src/jit/Recover.cpp | 1 + 2 files changed, 2 insertions(+) (limited to 'js/src') diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index 96e488ea8..0208db6ae 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -31,6 +31,7 @@ #include "jit/shared/Lowering-shared-inl.h" #include "vm/Interpreter-inl.h" #include "vm/Shape-inl.h" +#include "vm/UnboxedObject-inl.h" using namespace js; using namespace js::jit; diff --git a/js/src/jit/Recover.cpp b/js/src/jit/Recover.cpp index 13bf9224b..6fd71f377 100644 --- a/js/src/jit/Recover.cpp +++ b/js/src/jit/Recover.cpp @@ -30,6 +30,7 @@ #include "vm/Interpreter-inl.h" #include "vm/NativeObject-inl.h" +#include "vm/UnboxedObject-inl.h" using namespace js; using namespace js::jit; -- cgit v1.2.3 From e34920575d6dac353cb3d8a5d1b9c11ae05c5a8c Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Mon, 10 Jun 2019 16:49:47 +0000 Subject: Inline combined methods for NativeObject and UnboxedArrayObject accesses. --- js/src/jit/BaselineIC.cpp | 34 +++++----- js/src/jit/BaselineIC.h | 12 ++-- js/src/jit/BaselineInspector.cpp | 2 +- js/src/jit/BaselineInspector.h | 2 +- js/src/jit/MCallOptimize.cpp | 10 +-- js/src/jit/VMFunctions.cpp | 2 +- js/src/jsarray.cpp | 117 ++++++++++++++++++--------------- js/src/jsobj.cpp | 22 ++++--- js/src/vm/UnboxedObject-inl.h | 138 +++------------------------------------ 9 files changed, 115 insertions(+), 224 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 1d230e083..28e263ac7 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -2373,8 +2373,8 @@ CanOptimizeDenseOrUnboxedArraySetElem(JSObject* obj, uint32_t index, Shape* oldShape, uint32_t oldCapacity, uint32_t oldInitLength, bool* isAddingCaseOut, size_t* protoDepthOut) { - uint32_t initLength = GetAnyBoxedOrUnboxedInitializedLength(obj); - uint32_t capacity = GetAnyBoxedOrUnboxedCapacity(obj); + uint32_t initLength = obj->as().getDenseInitializedLength(); + uint32_t capacity = obj->as().getDenseCapacity(); *isAddingCaseOut = false; *protoDepthOut = 0; @@ -2464,8 +2464,8 @@ DoSetElemFallback(JSContext* cx, BaselineFrame* frame, ICSetElem_Fallback* stub_ uint32_t oldCapacity = 0; uint32_t oldInitLength = 0; if (index.isInt32() && index.toInt32() >= 0) { - oldCapacity = GetAnyBoxedOrUnboxedCapacity(obj); - oldInitLength = GetAnyBoxedOrUnboxedInitializedLength(obj); + oldCapacity = obj->as().getDenseCapacity(); + oldInitLength = obj->as().getDenseInitializedLength(); } if (op == JSOP_INITELEM || op == JSOP_INITHIDDENELEM) { @@ -5762,14 +5762,14 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb } static bool -CopyArray(JSContext* cx, HandleObject obj, MutableHandleValue result) +CopyArray(JSContext* cx, HandleArrayObject arr, MutableHandleValue result) { - uint32_t length = GetAnyBoxedOrUnboxedArrayLength(obj); - JSObject* nobj = NewFullyAllocatedArrayTryReuseGroup(cx, obj, length, TenuredObject); + uint32_t length = arr->length(); + JSObject* nobj = NewFullyAllocatedArrayTryReuseGroup(cx, arr, length, TenuredObject); if (!nobj) return false; EnsureArrayGroupAnalyzed(cx, nobj); - CopyBoxedOrUnboxedDenseElements(cx, nobj, obj, 0, 0, length); + CopyBoxedOrUnboxedDenseElements(cx, nobj, arr, 0, 0, length); result.setObject(*nobj); return true; @@ -5801,26 +5801,22 @@ TryAttachStringSplit(JSContext* cx, ICCall_Fallback* stub, HandleScript script, RootedValue arr(cx); // Copy the array before storing in stub. - if (!CopyArray(cx, obj, &arr)) + if (!CopyArray(cx, obj.as(), &arr)) return false; // Atomize all elements of the array. - RootedObject arrObj(cx, &arr.toObject()); - uint32_t initLength = GetAnyBoxedOrUnboxedArrayLength(arrObj); + RootedArrayObject arrObj(cx, &arr.toObject().as()); + uint32_t initLength = arrObj->length(); for (uint32_t i = 0; i < initLength; i++) { - JSAtom* str = js::AtomizeString(cx, GetAnyBoxedOrUnboxedDenseElement(arrObj, i).toString()); + JSAtom* str = js::AtomizeString(cx, arrObj->getDenseElement(i).toString()); if (!str) return false; - if (!SetAnyBoxedOrUnboxedDenseElement(cx, arrObj, i, StringValue(str))) { - // The value could not be stored to an unboxed dense element. - return true; - } + arrObj->setDenseElementWithType(cx, i, StringValue(str)); } ICCall_StringSplit::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(), - script->pcToOffset(pc), str, sep, - arr); + script->pcToOffset(pc), str, sep, arrObj); ICStub* newStub = compiler.getStub(compiler.getStubSpace(script)); if (!newStub) return false; @@ -6705,7 +6701,7 @@ ICCallScriptedCompiler::generateStubCode(MacroAssembler& masm) return true; } -typedef bool (*CopyArrayFn)(JSContext*, HandleObject, MutableHandleValue); +typedef bool (*CopyArrayFn)(JSContext*, HandleArrayObject, MutableHandleValue); static const VMFunction CopyArrayInfo = FunctionInfo(CopyArray, "CopyArray"); bool diff --git a/js/src/jit/BaselineIC.h b/js/src/jit/BaselineIC.h index afbea3b69..901fca9cc 100644 --- a/js/src/jit/BaselineIC.h +++ b/js/src/jit/BaselineIC.h @@ -2818,10 +2818,10 @@ class ICCall_StringSplit : public ICMonitoredStub uint32_t pcOffset_; GCPtrString expectedStr_; GCPtrString expectedSep_; - GCPtrObject templateObject_; + GCPtrArrayObject templateObject_; ICCall_StringSplit(JitCode* stubCode, ICStub* firstMonitorStub, uint32_t pcOffset, JSString* str, - JSString* sep, JSObject* templateObject) + JSString* sep, ArrayObject* templateObject) : ICMonitoredStub(ICStub::Call_StringSplit, stubCode, firstMonitorStub), pcOffset_(pcOffset), expectedStr_(str), expectedSep_(sep), templateObject_(templateObject) @@ -2848,7 +2848,7 @@ class ICCall_StringSplit : public ICMonitoredStub return expectedSep_; } - GCPtrObject& templateObject() { + GCPtrArrayObject& templateObject() { return templateObject_; } @@ -2858,7 +2858,7 @@ class ICCall_StringSplit : public ICMonitoredStub uint32_t pcOffset_; RootedString expectedStr_; RootedString expectedSep_; - RootedObject templateObject_; + RootedArrayObject templateObject_; MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm); @@ -2869,13 +2869,13 @@ class ICCall_StringSplit : public ICMonitoredStub public: Compiler(JSContext* cx, ICStub* firstMonitorStub, uint32_t pcOffset, HandleString str, - HandleString sep, HandleValue templateObject) + HandleString sep, HandleArrayObject templateObject) : ICCallStubCompiler(cx, ICStub::Call_StringSplit), firstMonitorStub_(firstMonitorStub), pcOffset_(pcOffset), expectedStr_(cx, str), expectedSep_(cx, sep), - templateObject_(cx, &templateObject.toObject()) + templateObject_(cx, templateObject) { } ICStub* getStub(ICStubSpace* space) { diff --git a/js/src/jit/BaselineInspector.cpp b/js/src/jit/BaselineInspector.cpp index 9c7b88fb2..bcb527516 100644 --- a/js/src/jit/BaselineInspector.cpp +++ b/js/src/jit/BaselineInspector.cpp @@ -580,7 +580,7 @@ BaselineInspector::getTemplateObjectForNative(jsbytecode* pc, Native native) bool BaselineInspector::isOptimizableCallStringSplit(jsbytecode* pc, JSString** strOut, JSString** sepOut, - JSObject** objOut) + ArrayObject** objOut) { if (!hasBaselineScript()) return false; diff --git a/js/src/jit/BaselineInspector.h b/js/src/jit/BaselineInspector.h index 4a1791798..1ed4b5547 100644 --- a/js/src/jit/BaselineInspector.h +++ b/js/src/jit/BaselineInspector.h @@ -113,7 +113,7 @@ class BaselineInspector bool hasSeenNonStringIterMore(jsbytecode* pc); MOZ_MUST_USE bool isOptimizableCallStringSplit(jsbytecode* pc, JSString** strOut, - JSString** sepOut, JSObject** objOut); + JSString** sepOut, ArrayObject** objOut); JSObject* getTemplateObject(jsbytecode* pc); JSObject* getTemplateObjectForNative(jsbytecode* pc, Native native); JSObject* getTemplateObjectForClassHook(jsbytecode* pc, const Class* clasp); diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 748a70973..0d5779cee 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -522,7 +522,7 @@ IonBuilder::inlineArray(CallInfo& callInfo) // Make sure initLength matches the template object's length. This is // not guaranteed to be the case, for instance if we're inlining the // MConstant may come from an outer script. - if (initLength != GetAnyBoxedOrUnboxedArrayLength(templateObject)) + if (initLength != templateObject->as().length()) return InliningStatus_NotInlined; // Don't inline large allocations. @@ -1396,7 +1396,7 @@ IonBuilder::inlineConstantStringSplitString(CallInfo& callInfo) // Check if exist a template object in stub. JSString* stringStr = nullptr; JSString* stringSep = nullptr; - JSObject* templateObject = nullptr; + ArrayObject* templateObject = nullptr; if (!inspector->isOptimizableCallStringSplit(pc, &stringStr, &stringSep, &templateObject)) return InliningStatus_NotInlined; @@ -1422,13 +1422,13 @@ IonBuilder::inlineConstantStringSplitString(CallInfo& callInfo) if (!key.maybeTypes()->hasType(TypeSet::StringType())) return InliningStatus_NotInlined; - uint32_t initLength = GetAnyBoxedOrUnboxedArrayLength(templateObject); - if (GetAnyBoxedOrUnboxedInitializedLength(templateObject) != initLength) + uint32_t initLength = templateObject->length(); + if (templateObject->getDenseInitializedLength() != initLength) return InliningStatus_NotInlined; Vector arrayValues; for (uint32_t i = 0; i < initLength; i++) { - Value str = GetAnyBoxedOrUnboxedDenseElement(templateObject, i); + Value str = templateObject->getDenseElement(i); MOZ_ASSERT(str.toString()->isAtom()); MConstant* value = MConstant::New(alloc().fallible(), str, constraints()); if (!value) diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 0717bb86d..7b1e1cad6 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -339,7 +339,7 @@ ArrayPopDense(JSContext* cx, HandleObject obj, MutableHandleValue rval) bool ArrayPushDense(JSContext* cx, HandleObject obj, HandleValue v, uint32_t* length) { - *length = GetAnyBoxedOrUnboxedArrayLength(obj); + *length = obj->as().length(); DenseElementResult result = SetOrExtendBoxedOrUnboxedDenseElements(cx, obj, *length, v.address(), 1, ShouldUpdateTypes::DontUpdate); diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index a8bd3f028..da692c1b5 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -248,18 +248,20 @@ static bool GetElement(JSContext* cx, HandleObject obj, HandleObject receiver, uint32_t index, bool* hole, MutableHandleValue vp) { - AssertGreaterThanZero(index); - if (index < GetAnyBoxedOrUnboxedInitializedLength(obj)) { - vp.set(GetAnyBoxedOrUnboxedDenseElement(obj, uint32_t(index))); - if (!vp.isMagic(JS_ELEMENTS_HOLE)) { - *hole = false; - return true; + if (obj->isNative()) { + NativeObject* nobj = &obj->as(); + if (index < nobj->getDenseInitializedLength()) { + vp.set(nobj->getDenseElement(size_t(index))); + if (!vp.isMagic(JS_ELEMENTS_HOLE)) { + *hole = false; + return true; + } } - } - if (obj->is()) { - if (obj->as().maybeGetElement(uint32_t(index), vp)) { - *hole = false; - return true; + if (nobj->is() && index <= UINT32_MAX) { + if (nobj->as().maybeGetElement(uint32_t(index), vp)) { + *hole = false; + return true; + } } } @@ -337,11 +339,11 @@ GetBoxedOrUnboxedDenseElements(JSObject* aobj, uint32_t length, Value* vp) { MOZ_ASSERT(!ObjectMayHaveExtraIndexedProperties(aobj)); - if (length > GetBoxedOrUnboxedInitializedLength(aobj)) + if (length > aobj->as().getDenseInitializedLength()) return DenseElementResult::Incomplete; for (size_t i = 0; i < length; i++) { - vp[i] = GetBoxedOrUnboxedDenseElement(aobj, i); + vp[i] = aobj->as().getDenseElement(i); // No other indexed properties so hole => undefined. if (vp[i].isMagic(JS_ELEMENTS_HOLE)) @@ -849,7 +851,7 @@ js::ObjectMayHaveExtraIndexedProperties(JSObject* obj) if (ObjectMayHaveExtraIndexedOwnProperties(obj)) return true; - if (GetAnyBoxedOrUnboxedInitializedLength(obj) != 0) + if (obj->as().getDenseInitializedLength() != 0) return true; } while (true); } @@ -1068,12 +1070,13 @@ ArrayJoinDenseKernel(JSContext* cx, SeparatorOp sepOp, HandleObject obj, uint32_ // length > initLength we rely on the second loop to add the // other elements. MOZ_ASSERT(*numProcessed == 0); - uint32_t initLength = Min(GetBoxedOrUnboxedInitializedLength(obj), length); + uint32_t initLength = Min(obj->as().getDenseInitializedLength(), + length); while (*numProcessed < initLength) { if (!CheckForInterrupt(cx)) return DenseElementResult::Failure; - Value elem = GetBoxedOrUnboxedDenseElement(obj, *numProcessed); + Value elem = obj->as().getDenseElement(*numProcessed); if (elem.isString()) { if (!sb.append(elem.toString())) @@ -1207,11 +1210,14 @@ js::array_join(JSContext* cx, unsigned argc, Value* vp) // An optimized version of a special case of steps 7-11: when length==1 and // the 0th element is a string, ToString() of that element is a no-op and // so it can be immediately returned as the result. - if (length == 1 && GetAnyBoxedOrUnboxedInitializedLength(obj) == 1) { - Value elem0 = GetAnyBoxedOrUnboxedDenseElement(obj, 0); - if (elem0.isString()) { - args.rval().set(elem0); - return true; + if (length == 1 && obj->isNative()) { + NativeObject* nobj = &obj->as(); + if (nobj->getDenseInitializedLength() == 1) { + Value elem0 = nobj->getDenseElement(0); + if (elem0.isString()) { + args.rval().set(elem0); + return true; + } } } @@ -1359,7 +1365,7 @@ DenseElementResult ArrayReverseDenseKernel(JSContext* cx, HandleObject obj, uint32_t length) { /* An empty array or an array with no elements is already reversed. */ - if (length == 0 || GetBoxedOrUnboxedInitializedLength(obj) == 0) + if (length == 0 || obj->as().getDenseInitializedLength() == 0) return DenseElementResult::Success; if (obj->as().denseElementsAreFrozen()) @@ -1385,15 +1391,15 @@ ArrayReverseDenseKernel(JSContext* cx, HandleObject obj, uint32_t length) uint32_t lo = 0, hi = length - 1; for (; lo < hi; lo++, hi--) { - origlo = GetBoxedOrUnboxedDenseElement(obj, lo); - orighi = GetBoxedOrUnboxedDenseElement(obj, hi); - SetBoxedOrUnboxedDenseElementNoTypeChange(obj, lo, orighi); + origlo = obj->as().getDenseElement(lo); + orighi = obj->as().getDenseElement(hi); + obj->as().setDenseElement(lo, orighi); if (orighi.isMagic(JS_ELEMENTS_HOLE) && !SuppressDeletedProperty(cx, obj, INT_TO_JSID(lo))) { return DenseElementResult::Failure; } - SetBoxedOrUnboxedDenseElementNoTypeChange(obj, hi, origlo); + obj->as().setDenseElement(hi, origlo); if (origlo.isMagic(JS_ELEMENTS_HOLE) && !SuppressDeletedProperty(cx, obj, INT_TO_JSID(hi))) { @@ -2074,14 +2080,8 @@ js::array_push(JSContext* cx, unsigned argc, Value* vp) uint32_t newlength = length + args.length(); args.rval().setNumber(newlength); - // SetOrExtendBoxedOrUnboxedDenseElements takes care of updating the - // length for boxed and unboxed arrays. Handle updates to the length of - // non-arrays here. - bool isArray; - if (!IsArray(cx, obj, &isArray)) - return false; - - if (!isArray) + // Handle updates to the length of non-arrays here. + if (!obj->is()) return SetLengthProperty(cx, obj, newlength); return true; @@ -2141,14 +2141,15 @@ template static inline DenseElementResult ShiftMoveBoxedOrUnboxedDenseElements(JSObject* obj) { - MOZ_ASSERT(HasBoxedOrUnboxedDenseElements(obj)); + MOZ_ASSERT(obj->isNative()); + + size_t initlen = obj->as().getDenseInitializedLength(); /* * At this point the length and initialized length have already been * decremented and the result fetched, so just shift the array elements * themselves. */ - size_t initlen = GetBoxedOrUnboxedInitializedLength(obj); obj->as().moveDenseElementsNoPreBarrier(0, 1, initlen); return DenseElementResult::Success; @@ -2165,6 +2166,15 @@ js::ArrayShiftMoveElements(JSObject* obj) JS_ALWAYS_TRUE(CallBoxedOrUnboxedSpecialization(functor, obj) == DenseElementResult::Success); } +static inline void +SetInitializedLength(JSContext* cx, NativeObject* obj, size_t initlen) +{ + size_t oldInitlen = obj->getDenseInitializedLength(); + obj->setDenseInitializedLength(initlen); + if (initlen < oldInitlen) + obj->shrinkElements(cx, initlen); +} + template DenseElementResult ArrayShiftDenseKernel(JSContext* cx, HandleObject obj, MutableHandleValue rval) @@ -2179,11 +2189,11 @@ ArrayShiftDenseKernel(JSContext* cx, HandleObject obj, MutableHandleValue rval) if (MOZ_UNLIKELY(group->hasAllFlags(OBJECT_FLAG_ITERATED))) return DenseElementResult::Incomplete; - size_t initlen = GetBoxedOrUnboxedInitializedLength(obj); + size_t initlen = obj->as().getDenseInitializedLength(); if (initlen == 0) return DenseElementResult::Incomplete; - rval.set(GetBoxedOrUnboxedDenseElement(obj, 0)); + rval.set(obj->as().getDenseElement(0)); if (rval.isMagic(JS_ELEMENTS_HOLE)) rval.setUndefined(); @@ -2191,7 +2201,7 @@ ArrayShiftDenseKernel(JSContext* cx, HandleObject obj, MutableHandleValue rval) if (result != DenseElementResult::Success) return result; - SetBoxedOrUnboxedInitializedLength(cx, obj, initlen - 1); + SetInitializedLength(cx, obj.as(), initlen - 1); return DenseElementResult::Success; } @@ -2364,7 +2374,7 @@ CanOptimizeForDenseStorage(HandleObject arr, uint32_t startingIndex, uint32_t co return false; /* If it's a frozen array, always pick the slow path */ - if (arr->is() && arr->as().denseElementsAreFrozen()) + if (arr->as().denseElementsAreFrozen()) return false; /* @@ -2396,7 +2406,7 @@ CanOptimizeForDenseStorage(HandleObject arr, uint32_t startingIndex, uint32_t co * is subsumed by the initializedLength comparison.) */ return !ObjectMayHaveExtraIndexedProperties(arr) && - startingIndex + count <= GetAnyBoxedOrUnboxedInitializedLength(arr); + startingIndex + count <= arr->as().getDenseInitializedLength(); } /* ES 2016 draft Mar 25, 2016 22.1.3.26. */ @@ -2541,7 +2551,7 @@ js::array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueI return false; /* Steps 15.c-d. */ - SetBoxedOrUnboxedInitializedLength(cx, obj, finalLength); + SetInitializedLength(cx, obj.as(), finalLength); } else { /* * This is all very slow if the length is very large. We don't yet @@ -2629,7 +2639,7 @@ js::array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueI return false; /* Steps 16.a-b. */ - SetBoxedOrUnboxedInitializedLength(cx, obj, len + itemCount - actualDeleteCount); + SetInitializedLength(cx, obj.as(), len + itemCount - actualDeleteCount); } else { RootedValue fromValue(cx); for (double k = len - actualDeleteCount; k > actualStart; k--) { @@ -2851,7 +2861,7 @@ ArraySliceOrdinary(JSContext* cx, HandleObject obj, uint32_t length, uint32_t be begin = end; if (!ObjectMayHaveExtraIndexedProperties(obj)) { - size_t initlen = GetAnyBoxedOrUnboxedInitializedLength(obj); + size_t initlen = obj->as().getDenseInitializedLength(); size_t count = 0; if (initlen > begin) count = Min(initlen - begin, end - begin); @@ -2859,7 +2869,9 @@ ArraySliceOrdinary(JSContext* cx, HandleObject obj, uint32_t length, uint32_t be RootedObject narr(cx, NewFullyAllocatedArrayTryReuseGroup(cx, obj, count)); if (!narr) return false; - SetAnyBoxedOrUnboxedArrayLength(cx, narr, end - begin); + + MOZ_ASSERT(count >= narr->as().length()); + narr->as().setLength(cx, count); if (count) { DebugOnly result = @@ -2991,7 +3003,7 @@ template DenseElementResult ArraySliceDenseKernel(JSContext* cx, JSObject* obj, int32_t beginArg, int32_t endArg, JSObject* result) { - int32_t length = GetAnyBoxedOrUnboxedArrayLength(obj); + int32_t length = obj->as().length(); uint32_t begin = NormalizeSliceTerm(beginArg, length); uint32_t end = NormalizeSliceTerm(endArg, length); @@ -2999,18 +3011,19 @@ ArraySliceDenseKernel(JSContext* cx, JSObject* obj, int32_t beginArg, int32_t en if (begin > end) begin = end; - size_t initlen = GetBoxedOrUnboxedInitializedLength(obj); + size_t initlen = obj->as().getDenseInitializedLength(); + size_t count = Min(initlen - begin, end - begin); if (initlen > begin) { - size_t count = Min(initlen - begin, end - begin); if (count) { - DenseElementResult rv = EnsureBoxedOrUnboxedDenseElements(cx, result, count); - if (rv != DenseElementResult::Success) - return rv; + if (!result->as().ensureElements(cx, count)) + return DenseElementResult::Failure; CopyBoxedOrUnboxedDenseElements(cx, result, obj, 0, begin, count); } } - SetAnyBoxedOrUnboxedArrayLength(cx, result, end - begin); + MOZ_ASSERT(count >= result->as().length()); + result->as().setLength(cx, count); + return DenseElementResult::Success; } diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index c26a42f48..deaa1d53e 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -1143,19 +1143,18 @@ js::CloneObject(JSContext* cx, HandleObject obj, Handle proto) } static bool -GetScriptArrayObjectElements(JSContext* cx, HandleObject obj, MutableHandle> values) +GetScriptArrayObjectElements(JSContext* cx, HandleArrayObject arr, MutableHandle> values) { - MOZ_ASSERT(!obj->isSingleton()); - MOZ_ASSERT(obj->is()); - MOZ_ASSERT(!obj->isIndexed()); + MOZ_ASSERT(!arr->isSingleton()); + MOZ_ASSERT(!arr->isIndexed()); - size_t length = GetAnyBoxedOrUnboxedArrayLength(obj); + size_t length = arr->length(); if (!values.appendN(MagicValue(JS_ELEMENTS_HOLE), length)) return false; - size_t initlen = GetAnyBoxedOrUnboxedInitializedLength(obj); + size_t initlen = arr->getDenseInitializedLength(); for (size_t i = 0; i < initlen; i++) - values[i].set(GetAnyBoxedOrUnboxedDenseElement(obj, i)); + values[i].set(arr->getDenseElement(i)); return true; } @@ -1212,7 +1211,7 @@ js::DeepCloneObjectLiteral(JSContext* cx, HandleObject obj, NewObjectKind newKin if (obj->is()) { Rooted> values(cx, GCVector(cx)); - if (!GetScriptArrayObjectElements(cx, obj, &values)) + if (!GetScriptArrayObjectElements(cx, obj.as(), &values)) return nullptr; // Deep clone any elements. @@ -1339,8 +1338,11 @@ js::XDRObjectLiteral(XDRState* xdr, MutableHandleObject obj) if (isArray) { Rooted> values(cx, GCVector(cx)); - if (mode == XDR_ENCODE && !GetScriptArrayObjectElements(cx, obj, &values)) - return false; + if (mode == XDR_ENCODE) { + RootedArrayObject arr(cx, &obj->as()); + if (!GetScriptArrayObjectElements(cx, arr, &values)) + return false; + } uint32_t initialized; if (mode == XDR_ENCODE) diff --git a/js/src/vm/UnboxedObject-inl.h b/js/src/vm/UnboxedObject-inl.h index 499f3604b..b308464fe 100644 --- a/js/src/vm/UnboxedObject-inl.h +++ b/js/src/vm/UnboxedObject-inl.h @@ -172,130 +172,10 @@ UnboxedPlainObject::layout() const return group()->unboxedLayout(); } -///////////////////////////////////////////////////////////////////// -// Combined methods for NativeObject and UnboxedArrayObject accesses. -///////////////////////////////////////////////////////////////////// - -static inline bool -HasAnyBoxedOrUnboxedDenseElements(JSObject* obj) -{ - return obj->isNative(); -} - -static inline size_t -GetAnyBoxedOrUnboxedInitializedLength(JSObject* obj) -{ - if (obj->isNative()) - return obj->as().getDenseInitializedLength(); - return 0; -} - -static inline size_t -GetAnyBoxedOrUnboxedCapacity(JSObject* obj) -{ - if (obj->isNative()) - return obj->as().getDenseCapacity(); - return 0; -} - -static inline Value -GetAnyBoxedOrUnboxedDenseElement(JSObject* obj, size_t index) -{ - return obj->as().getDenseElement(index); -} - -static inline size_t -GetAnyBoxedOrUnboxedArrayLength(JSObject* obj) -{ - return obj->as().length(); -} - -static inline void -SetAnyBoxedOrUnboxedArrayLength(JSContext* cx, JSObject* obj, size_t length) -{ - MOZ_ASSERT(length >= obj->as().length()); - obj->as().setLength(cx, length); -} - -static inline bool -SetAnyBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, const Value& value) -{ - obj->as().setDenseElementWithType(cx, index, value); - return true; -} - -static inline bool -InitAnyBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, const Value& value) -{ - obj->as().initDenseElementWithType(cx, index, value); - return true; -} - ///////////////////////////////////////////////////////////////////// // Template methods for NativeObject and UnboxedArrayObject accesses. ///////////////////////////////////////////////////////////////////// -static inline JSValueType -GetBoxedOrUnboxedType(JSObject* obj) -{ - return JSVAL_TYPE_MAGIC; -} - -static inline bool -HasBoxedOrUnboxedDenseElements(JSObject* obj) -{ - return obj->isNative(); -} - -static inline size_t -GetBoxedOrUnboxedInitializedLength(JSObject* obj) -{ - return obj->as().getDenseInitializedLength(); -} - -static inline DenseElementResult -SetBoxedOrUnboxedInitializedLength(JSContext* cx, JSObject* obj, size_t initlen) -{ - size_t oldInitlen = GetBoxedOrUnboxedInitializedLength(obj); - obj->as().setDenseInitializedLength(initlen); - if (initlen < oldInitlen) - obj->as().shrinkElements(cx, initlen); - return DenseElementResult::Success; -} - -static inline size_t -GetBoxedOrUnboxedCapacity(JSObject* obj) -{ - return obj->as().getDenseCapacity(); -} - -static inline Value -GetBoxedOrUnboxedDenseElement(JSObject* obj, size_t index) -{ - return obj->as().getDenseElement(index); -} - -static inline void -SetBoxedOrUnboxedDenseElementNoTypeChange(JSObject* obj, size_t index, const Value& value) -{ - obj->as().setDenseElement(index, value); -} - -static inline bool -SetBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, const Value& value) -{ - obj->as().setDenseElementWithType(cx, index, value); - return true; -} - -static inline DenseElementResult -EnsureBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t count) -{ - if (!obj->as().ensureElements(cx, count)) - return DenseElementResult::Failure; - return DenseElementResult::Success; -} - static inline DenseElementResult SetOrExtendBoxedOrUnboxedDenseElements(ExclusiveContext* cx, JSObject* obj, uint32_t start, const Value* vp, uint32_t count, @@ -334,7 +214,7 @@ static inline DenseElementResult MoveBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, uint32_t dstStart, uint32_t srcStart, uint32_t length) { - MOZ_ASSERT(HasBoxedOrUnboxedDenseElements(obj)); + MOZ_ASSERT(obj->isNative()); if (obj->as().denseElementsAreFrozen()) return DenseElementResult::Incomplete; @@ -350,13 +230,13 @@ static inline DenseElementResult CopyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src, uint32_t dstStart, uint32_t srcStart, uint32_t length) { - MOZ_ASSERT(HasBoxedOrUnboxedDenseElements(src)); - MOZ_ASSERT(HasBoxedOrUnboxedDenseElements(dst)); - MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength(dst) == dstStart); - MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength(src) >= srcStart + length); - MOZ_ASSERT(GetBoxedOrUnboxedCapacity(dst) >= dstStart + length); + MOZ_ASSERT(src->isNative()); + MOZ_ASSERT(dst->isNative()); + MOZ_ASSERT(dst->as().getDenseInitializedLength() == dstStart); + MOZ_ASSERT(src->as().getDenseInitializedLength() >= srcStart + length); + MOZ_ASSERT(dst->as().getDenseCapacity() >= dstStart + length); - SetBoxedOrUnboxedInitializedLength(cx, dst, dstStart + length); + dst->as().setDenseInitializedLength(dstStart + length); const Value* vp = src->as().getDenseElements() + srcStart; dst->as().initDenseElements(dstStart, vp, length); @@ -383,7 +263,7 @@ template DenseElementResult CallBoxedOrUnboxedSpecialization(F f, JSObject* obj) { - if (!HasAnyBoxedOrUnboxedDenseElements(obj)) + if (!obj->isNative()) return DenseElementResult::Incomplete; return f. DEPENDENT_TEMPLATE_HINT operator()(); } @@ -393,7 +273,7 @@ template DenseElementResult CallBoxedOrUnboxedSpecialization(F f, JSObject* obj1, JSObject* obj2) { - if (!HasAnyBoxedOrUnboxedDenseElements(obj1) || !HasAnyBoxedOrUnboxedDenseElements(obj2)) + if (!obj1->isNative() || !obj2->isNative()) return DenseElementResult::Incomplete; return f. DEPENDENT_TEMPLATE_HINT operator()(); -- cgit v1.2.3 From 284b4cffd7a7ccc311b64744d46b29e219eb132a Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Wed, 12 Jun 2019 03:36:54 +0200 Subject: Add Atomics.notify instead of Atomics.wake according to revised spec. - Keep .wake as an alias until we're certain it can be removed. - Enable SAB memory --- js/src/builtin/AtomicsObject.cpp | 23 ++++++++++++----------- js/src/builtin/AtomicsObject.h | 26 ++++++++++++-------------- js/src/tests/shell/futex.js | 8 +++++--- js/src/vm/Runtime.cpp | 2 +- 4 files changed, 30 insertions(+), 29 deletions(-) (limited to 'js/src') diff --git a/js/src/builtin/AtomicsObject.cpp b/js/src/builtin/AtomicsObject.cpp index 2551f3b7d..3de3f5f4c 100644 --- a/js/src/builtin/AtomicsObject.cpp +++ b/js/src/builtin/AtomicsObject.cpp @@ -834,7 +834,7 @@ js::atomics_wait(JSContext* cx, unsigned argc, Value* vp) } bool -js::atomics_wake(JSContext* cx, unsigned argc, Value* vp) +js::atomics_notify(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); HandleValue objv = args.get(0); @@ -874,7 +874,7 @@ js::atomics_wake(JSContext* cx, unsigned argc, Value* vp) iter = iter->lower_pri; if (c->offset != offset || !c->rt->fx.isWaiting()) continue; - c->rt->fx.wake(FutexRuntime::WakeExplicit); + c->rt->fx.notify(FutexRuntime::NotifyExplicit); ++woken; --count; } while (count > 0 && iter != waiters); @@ -950,7 +950,7 @@ js::FutexRuntime::isWaiting() // When a worker is awoken for an interrupt it goes into state // WaitingNotifiedForInterrupt for a short time before it actually // wakes up and goes into WaitingInterrupted. In those states the - // worker is still waiting, and if an explicit wake arrives the + // worker is still waiting, and if an explicit notify arrives the // worker transitions to Woken. See further comments in // FutexRuntime::wait(). return state_ == Waiting || state_ == WaitingInterrupted || state_ == WaitingNotifiedForInterrupt; @@ -1029,14 +1029,14 @@ js::FutexRuntime::wait(JSContext* cx, js::UniqueLock& locked, // should be woken when the interrupt handler returns. // To that end, we flag the thread as interrupted around // the interrupt and check state_ when the interrupt - // handler returns. A wake() call that reaches the + // handler returns. A notify() call that reaches the // runtime during the interrupt sets state_ to Woken. // // - It is in principle possible for wait() to be // reentered on the same thread/runtime and waiting on the // same location and to yet again be interrupted and enter // the interrupt handler. In this case, it is important - // that when another agent wakes waiters, all waiters using + // that when another agent notifies waiters, all waiters using // the same runtime on the same location are woken in LIFO // order; FIFO may be the required order, but FIFO would // fail to wake up the innermost call. Interrupts are @@ -1073,25 +1073,25 @@ finished: } void -js::FutexRuntime::wake(WakeReason reason) +js::FutexRuntime::notify(NotifyReason reason) { MOZ_ASSERT(isWaiting()); - if ((state_ == WaitingInterrupted || state_ == WaitingNotifiedForInterrupt) && reason == WakeExplicit) { + if ((state_ == WaitingInterrupted || state_ == WaitingNotifiedForInterrupt) && reason == NotifyExplicit) { state_ = Woken; return; } switch (reason) { - case WakeExplicit: + case NotifyExplicit: state_ = Woken; break; - case WakeForJSInterrupt: + case NotifyForJSInterrupt: if (state_ == WaitingNotifiedForInterrupt) return; state_ = WaitingNotifiedForInterrupt; break; default: - MOZ_CRASH("bad WakeReason in FutexRuntime::wake()"); + MOZ_CRASH("bad NotifyReason in FutexRuntime::notify()"); } cond_->notify_all(); } @@ -1108,7 +1108,8 @@ const JSFunctionSpec AtomicsMethods[] = { JS_INLINABLE_FN("xor", atomics_xor, 3,0, AtomicsXor), JS_INLINABLE_FN("isLockFree", atomics_isLockFree, 1,0, AtomicsIsLockFree), JS_FN("wait", atomics_wait, 4,0), - JS_FN("wake", atomics_wake, 3,0), + JS_FN("notify", atomics_notify, 3,0), + JS_FN("wake", atomics_notify, 3,0), //Legacy name JS_FS_END }; diff --git a/js/src/builtin/AtomicsObject.h b/js/src/builtin/AtomicsObject.h index adb6fb986..6511dc8bf 100644 --- a/js/src/builtin/AtomicsObject.h +++ b/js/src/builtin/AtomicsObject.h @@ -36,7 +36,7 @@ MOZ_MUST_USE bool atomics_or(JSContext* cx, unsigned argc, Value* vp); MOZ_MUST_USE bool atomics_xor(JSContext* cx, unsigned argc, Value* vp); MOZ_MUST_USE bool atomics_isLockFree(JSContext* cx, unsigned argc, Value* vp); MOZ_MUST_USE bool atomics_wait(JSContext* cx, unsigned argc, Value* vp); -MOZ_MUST_USE bool atomics_wake(JSContext* cx, unsigned argc, Value* vp); +MOZ_MUST_USE bool atomics_notify(JSContext* cx, unsigned argc, Value* vp); /* asm.js callouts */ namespace wasm { class Instance; } @@ -63,10 +63,10 @@ public: MOZ_MUST_USE bool initInstance(); void destroyInstance(); - // Parameters to wake(). - enum WakeReason { - WakeExplicit, // Being asked to wake up by another thread - WakeForJSInterrupt // Interrupt requested + // Parameters to notify(). + enum NotifyReason { + NotifyExplicit, // Being asked to wake up by another thread + NotifyForJSInterrupt // Interrupt requested }; // Result code from wait(). @@ -83,29 +83,27 @@ public: // times allowed; specify mozilla::Nothing() for an indefinite // wait. // - // wait() will not wake up spuriously. It will return true and - // set *result to a return code appropriate for - // Atomics.wait() on success, and return false on error. + // wait() will not wake up spuriously. MOZ_MUST_USE bool wait(JSContext* cx, js::UniqueLock& locked, mozilla::Maybe& timeout, WaitResult* result); - // Wake the thread represented by this Runtime. + // Notify the thread represented by this Runtime. // // The futex lock must be held around this call. (The sleeping - // thread will not wake up until the caller of Atomics.wake() + // thread will not wake up until the caller of Atomics.notify() // releases the lock.) // // If the thread is not waiting then this method does nothing. // // If the thread is waiting in a call to wait() and the - // reason is WakeExplicit then the wait() call will return + // reason is NotifyExplicit then the wait() call will return // with Woken. // // If the thread is waiting in a call to wait() and the - // reason is WakeForJSInterrupt then the wait() will return + // reason is NotifyForJSInterrupt then the wait() will return // with WaitingNotifiedForInterrupt; in the latter case the caller // of wait() must handle the interrupt. - void wake(WakeReason reason); + void notify(NotifyReason reason); bool isWaiting(); @@ -128,7 +126,7 @@ public: // interrupt handler WaitingInterrupted, // We are waiting, but have been interrupted // and are running the interrupt handler - Woken // Woken by a script call to Atomics.wake + Woken // Woken by a script call to Atomics.notify }; // Condition variable that this runtime will wait on. diff --git a/js/src/tests/shell/futex.js b/js/src/tests/shell/futex.js index b0951f12e..8ba61d71c 100644 --- a/js/src/tests/shell/futex.js +++ b/js/src/tests/shell/futex.js @@ -67,6 +67,8 @@ if (helperThreadCount() === 0) { quit(); } +var mem = new Int32Array(new SharedArrayBuffer(1024)); + //////////////////////////////////////////////////////////// // wait() returns "not-equal" if the value is not the expected one. @@ -102,7 +104,7 @@ dprint("Sleeping for 2 seconds"); sleep(2); dprint("Waking the main thread now"); setSharedArrayBuffer(null); -assertEq(Atomics.wake(mem, 0, 1), 1); // Can fail spuriously but very unlikely +assertEq(Atomics.notify(mem, 0, 1), 1); // Can fail spuriously but very unlikely `); var then = Date.now(); @@ -113,14 +115,14 @@ assertEq(getSharedArrayBuffer(), null); // The worker's clearing of the mbx is v //////////////////////////////////////////////////////////// -// Test the default argument to atomics.wake() +// Test the default argument to atomics.notify() setSharedArrayBuffer(mem.buffer); evalInWorker(` var mem = new Int32Array(getSharedArrayBuffer()); sleep(2); // Probably long enough to avoid a spurious error next -assertEq(Atomics.wake(mem, 0), 1); // Last argument to wake should default to +Infinity +assertEq(Atomics.notify(mem, 0), 1); // Last argument to wake should default to +Infinity `); var then = Date.now(); diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index 8eb997c71..5fc8e0e17 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -589,7 +589,7 @@ JSRuntime::requestInterrupt(InterruptMode mode) // Atomics.wait(). fx.lock(); if (fx.isWaiting()) - fx.wake(FutexRuntime::WakeForJSInterrupt); + fx.notify(FutexRuntime::NotifyForJSInterrupt); fx.unlock(); InterruptRunningJitCode(this); } -- cgit v1.2.3 From e95089d84ac71276bd059e52293ab42c2259d89e Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Wed, 12 Jun 2019 03:19:09 +0000 Subject: Make use of ArrayObjects in favor of generic JS objects. ArrayObjects has been a thing for years but been under-used. About time they are used where prudent. --- js/src/frontend/BytecodeEmitter.cpp | 4 +-- js/src/jit/BaselineCompiler.cpp | 6 ++-- js/src/jit/BaselineIC.cpp | 8 ++--- js/src/jit/CodeGenerator.cpp | 8 ++--- js/src/jit/Recover.cpp | 2 +- js/src/jsarray.cpp | 68 ++++++++++--------------------------- js/src/jsarray.h | 24 ++++++------- js/src/jsstr.cpp | 6 ++-- js/src/jsstr.h | 2 +- js/src/vm/JSONParser.cpp | 4 +-- js/src/vm/ObjectGroup.cpp | 7 ++-- js/src/vm/ObjectGroup.h | 10 +++--- js/src/vm/Stack.cpp | 2 +- js/src/vm/Stack.h | 2 +- 14 files changed, 57 insertions(+), 96 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index c524184d6..ea6baeec7 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -6281,8 +6281,8 @@ ParseNode::getConstantValue(ExclusiveContext* cx, AllowConstantObjects allowObje } MOZ_ASSERT(idx == count); - JSObject* obj = ObjectGroup::newArrayObject(cx, values.begin(), values.length(), - newKind, arrayKind); + ArrayObject* obj = ObjectGroup::newArrayObject(cx, values.begin(), values.length(), + newKind, arrayKind); if (!obj) return false; diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index 3fa5a80ed..93e3759b9 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -2055,7 +2055,7 @@ BaselineCompiler::emit_JSOP_SPREADCALLARRAY() return emit_JSOP_NEWARRAY(); } -typedef JSObject* (*NewArrayCopyOnWriteFn)(JSContext*, HandleArrayObject, gc::InitialHeap); +typedef ArrayObject* (*NewArrayCopyOnWriteFn)(JSContext*, HandleArrayObject, gc::InitialHeap); const VMFunction jit::NewArrayCopyOnWriteInfo = FunctionInfo(js::NewDenseCopyOnWriteArray, "NewDenseCopyOnWriteArray"); @@ -4136,14 +4136,14 @@ BaselineCompiler::emit_JSOP_REST() { frame.syncStack(0); - JSObject* templateObject = + ArrayObject* templateObject = ObjectGroup::newArrayObject(cx, nullptr, 0, TenuredObject, ObjectGroup::NewArrayKind::UnknownIndex); if (!templateObject) return false; // Call IC. - ICRest_Fallback::Compiler compiler(cx, &templateObject->as()); + ICRest_Fallback::Compiler compiler(cx, templateObject); if (!emitOpIC(compiler.getStub(&stubSpace_))) return false; diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 28e263ac7..2b0822655 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -5765,10 +5765,10 @@ static bool CopyArray(JSContext* cx, HandleArrayObject arr, MutableHandleValue result) { uint32_t length = arr->length(); - JSObject* nobj = NewFullyAllocatedArrayTryReuseGroup(cx, arr, length, TenuredObject); + ArrayObject* nobj = NewFullyAllocatedArrayTryReuseGroup(cx, arr, length, TenuredObject); if (!nobj) return false; - EnsureArrayGroupAnalyzed(cx, nobj); + EnsureArrayGroupAnalyzed(cx, nobj); //XXX CopyBoxedOrUnboxedDenseElements(cx, nobj, arr, 0, 0, length); result.setObject(*nobj); @@ -8547,8 +8547,8 @@ static bool DoRestFallback(JSContext* cx, BaselineFrame* frame, ICRest_Fallback* unsigned numRest = numActuals > numFormals ? numActuals - numFormals : 0; Value* rest = frame->argv() + numFormals; - JSObject* obj = ObjectGroup::newArrayObject(cx, rest, numRest, GenericObject, - ObjectGroup::NewArrayKind::UnknownIndex); + ArrayObject* obj = ObjectGroup::newArrayObject(cx, rest, numRest, GenericObject, + ObjectGroup::NewArrayKind::UnknownIndex); if (!obj) return false; res.setObject(*obj); diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 485e881fe..ae9c61031 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -5169,11 +5169,11 @@ static JSObject* NewArrayWithGroup(JSContext* cx, uint32_t length, HandleObjectGroup group, bool convertDoubleElements) { - JSObject* res = NewFullyAllocatedArrayTryUseGroup(cx, group, length); + ArrayObject* res = NewFullyAllocatedArrayTryUseGroup(cx, group, length); if (!res) return nullptr; if (convertDoubleElements) - res->as().setShouldConvertDoubleElements(); + res->setShouldConvertDoubleElements(); return res; } @@ -5319,7 +5319,7 @@ CodeGenerator::visitNewArrayCopyOnWrite(LNewArrayCopyOnWrite* lir) masm.bind(ool->rejoin()); } -typedef JSObject* (*ArrayConstructorOneArgFn)(JSContext*, HandleObjectGroup, int32_t length); +typedef ArrayObject* (*ArrayConstructorOneArgFn)(JSContext*, HandleObjectGroup, int32_t length); static const VMFunction ArrayConstructorOneArgInfo = FunctionInfo(ArrayConstructorOneArg, "ArrayConstructorOneArg"); @@ -7765,7 +7765,7 @@ CodeGenerator::visitSinCos(LSinCos *lir) masm.freeStack(sizeof(double) * 2); } -typedef JSObject* (*StringSplitFn)(JSContext*, HandleObjectGroup, HandleString, HandleString, uint32_t); +typedef ArrayObject* (*StringSplitFn)(JSContext*, HandleObjectGroup, HandleString, HandleString, uint32_t); static const VMFunction StringSplitInfo = FunctionInfo(js::str_split_string, "str_split_string"); diff --git a/js/src/jit/Recover.cpp b/js/src/jit/Recover.cpp index 6fd71f377..8fe6ee3fb 100644 --- a/js/src/jit/Recover.cpp +++ b/js/src/jit/Recover.cpp @@ -1355,7 +1355,7 @@ RNewArray::recover(JSContext* cx, SnapshotIterator& iter) const RootedValue result(cx); RootedObjectGroup group(cx, templateObject->group()); - JSObject* resultObject = NewFullyAllocatedArrayTryUseGroup(cx, group, count_); + ArrayObject* resultObject = NewFullyAllocatedArrayTryUseGroup(cx, group, count_); if (!resultObject) return false; diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index da692c1b5..0d6f78fcf 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -2811,7 +2811,7 @@ SliceSlowly(JSContext* cx, HandleObject obj, HandleObject receiver, } static bool -SliceSparse(JSContext* cx, HandleObject obj, uint32_t begin, uint32_t end, HandleObject result) +SliceSparse(JSContext* cx, HandleObject obj, uint32_t begin, uint32_t end, HandleArrayObject result) { MOZ_ASSERT(begin <= end); @@ -2866,7 +2866,7 @@ ArraySliceOrdinary(JSContext* cx, HandleObject obj, uint32_t length, uint32_t be if (initlen > begin) count = Min(initlen - begin, end - begin); - RootedObject narr(cx, NewFullyAllocatedArrayTryReuseGroup(cx, obj, count)); + RootedArrayObject narr(cx, NewFullyAllocatedArrayTryReuseGroup(cx, obj, count)); if (!narr) return false; @@ -2882,7 +2882,7 @@ ArraySliceOrdinary(JSContext* cx, HandleObject obj, uint32_t length, uint32_t be return true; } - RootedObject narr(cx, NewPartlyAllocatedArrayTryReuseGroup(cx, obj, end - begin)); + RootedArrayObject narr(cx, NewPartlyAllocatedArrayTryReuseGroup(cx, obj, end - begin)); if (!narr) return false; @@ -3069,7 +3069,7 @@ array_isArray(JSContext* cx, unsigned argc, Value* vp) static bool ArrayFromCallArgs(JSContext* cx, CallArgs& args, HandleObject proto = nullptr) { - JSObject* obj = NewCopiedArrayForCallingAllocationSite(cx, args.array(), args.length(), proto); + ArrayObject* obj = NewCopiedArrayForCallingAllocationSite(cx, args.array(), args.length(), proto); if (!obj) return false; @@ -3234,7 +3234,7 @@ ArrayConstructorImpl(JSContext* cx, CallArgs& args, bool isConstructor) } } - JSObject* obj = NewPartlyAllocatedArrayForCallingAllocationSite(cx, length, proto); + ArrayObject* obj = NewPartlyAllocatedArrayForCallingAllocationSite(cx, length, proto); if (!obj) return false; @@ -3260,7 +3260,7 @@ js::array_construct(JSContext* cx, unsigned argc, Value* vp) return ArrayConstructorImpl(cx, args, /* isConstructor = */ false); } -JSObject* +ArrayObject* js::ArrayConstructorOneArg(JSContext* cx, HandleObjectGroup group, int32_t lengthInt) { if (lengthInt < 0) { @@ -3555,7 +3555,7 @@ js::NewDenseFullyAllocatedArrayWithTemplate(JSContext* cx, uint32_t length, JSOb return arr; } -JSObject* +ArrayObject* js::NewDenseCopyOnWriteArray(JSContext* cx, HandleArrayObject templateObject, gc::InitialHeap heap) { MOZ_ASSERT(!gc::IsInsideNursery(templateObject)); @@ -3573,7 +3573,7 @@ js::NewDenseCopyOnWriteArray(JSContext* cx, HandleArrayObject templateObject, gc // specified group cannot be used, ensure that the created array at least has // the given [[Prototype]]. template -static inline JSObject* +static inline ArrayObject* NewArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length, NewObjectKind newKind = GenericObject) { @@ -3603,14 +3603,14 @@ NewArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length return res; } -JSObject* +ArrayObject* js::NewFullyAllocatedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length, NewObjectKind newKind) { return NewArrayTryUseGroup(cx, group, length, newKind); } -JSObject* +ArrayObject* js::NewPartlyAllocatedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length) { return NewArrayTryUseGroup(cx, group, length); @@ -3624,7 +3624,7 @@ js::NewPartlyAllocatedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup g // |length| is larger than the input object's initialized length (in which case // UnboxedArrayObject::MaximumCapacity might be exceeded). template -static inline JSObject* +static inline ArrayObject* NewArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length, NewObjectKind newKind = GenericObject) { @@ -3641,20 +3641,20 @@ NewArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length, return NewArrayTryUseGroup(cx, group, length, newKind); } -JSObject* +ArrayObject* js::NewFullyAllocatedArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length, NewObjectKind newKind) { return NewArrayTryReuseGroup(cx, obj, length, newKind); } -JSObject* +ArrayObject* js::NewPartlyAllocatedArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length) { return NewArrayTryReuseGroup(cx, obj, length); } -JSObject* +ArrayObject* js::NewFullyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length, NewObjectKind newKind) { @@ -3664,7 +3664,7 @@ js::NewFullyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length, return NewArrayTryUseGroup(cx, group, length, newKind); } -JSObject* +ArrayObject* js::NewPartlyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length, HandleObject proto) { RootedObjectGroup group(cx, ObjectGroup::callingAllocationSiteGroup(cx, JSProto_Array, proto)); @@ -3673,44 +3673,12 @@ js::NewPartlyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length return NewArrayTryUseGroup(cx, group, length); } -bool -js::MaybeAnalyzeBeforeCreatingLargeArray(ExclusiveContext* cx, HandleObjectGroup group, - const Value* vp, size_t length) -{ - static const size_t EagerPreliminaryObjectAnalysisThreshold = 800; - - // Force analysis to see if an unboxed array can be used when making a - // sufficiently large array, to avoid excessive analysis and copying later - // on. If this is the first array of its group that is being created, first - // make a dummy array with the initial elements of the array we are about - // to make, so there is some basis for the unboxed array analysis. - if (length > EagerPreliminaryObjectAnalysisThreshold) { - if (PreliminaryObjectArrayWithTemplate* objects = group->maybePreliminaryObjects()) { - if (objects->empty()) { - size_t nlength = Min(length, 100); - JSObject* obj = NewFullyAllocatedArrayTryUseGroup(cx, group, nlength); - if (!obj) - return false; - DebugOnly result = - SetOrExtendBoxedOrUnboxedDenseElements(cx, obj, 0, vp, nlength, - ShouldUpdateTypes::Update); - MOZ_ASSERT(result.value == DenseElementResult::Success); - } - objects->maybeAnalyze(cx, group, /* forceAnalyze = */ true); - } - } - return true; -} - -JSObject* +ArrayObject* js::NewCopiedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, const Value* vp, size_t length, NewObjectKind newKind, ShouldUpdateTypes updateTypes) { - if (!MaybeAnalyzeBeforeCreatingLargeArray(cx, group, vp, length)) - return nullptr; - - JSObject* obj = NewFullyAllocatedArrayTryUseGroup(cx, group, length, newKind); + ArrayObject* obj = NewFullyAllocatedArrayTryUseGroup(cx, group, length, newKind); if (!obj) return nullptr; @@ -3722,7 +3690,7 @@ js::NewCopiedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, return obj; } -JSObject* +ArrayObject* js::NewCopiedArrayForCallingAllocationSite(JSContext* cx, const Value* vp, size_t length, HandleObject proto /* = nullptr */) { diff --git a/js/src/jsarray.h b/js/src/jsarray.h index e22cde881..ecde87c3b 100644 --- a/js/src/jsarray.h +++ b/js/src/jsarray.h @@ -72,30 +72,30 @@ extern ArrayObject* NewDenseFullyAllocatedArrayWithTemplate(JSContext* cx, uint32_t length, JSObject* templateObject); /* Create a dense array with the same copy-on-write elements as another object. */ -extern JSObject* +extern ArrayObject* NewDenseCopyOnWriteArray(JSContext* cx, HandleArrayObject templateObject, gc::InitialHeap heap); // The methods below can create either boxed or unboxed arrays. -extern JSObject* +extern ArrayObject* NewFullyAllocatedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length, NewObjectKind newKind = GenericObject); -extern JSObject* +extern ArrayObject* NewPartlyAllocatedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length); -extern JSObject* +extern ArrayObject* NewFullyAllocatedArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length, NewObjectKind newKind = GenericObject); -extern JSObject* +extern ArrayObject* NewPartlyAllocatedArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length); -extern JSObject* +extern ArrayObject* NewFullyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length, NewObjectKind newKind = GenericObject); -extern JSObject* +extern ArrayObject* NewPartlyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length, HandleObject proto); enum class ShouldUpdateTypes @@ -104,17 +104,13 @@ enum class ShouldUpdateTypes DontUpdate }; -extern bool -MaybeAnalyzeBeforeCreatingLargeArray(ExclusiveContext* cx, HandleObjectGroup group, - const Value* vp, size_t length); - -extern JSObject* +extern ArrayObject* NewCopiedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, const Value* vp, size_t length, NewObjectKind newKind = GenericObject, ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update); -extern JSObject* +extern ArrayObject* NewCopiedArrayForCallingAllocationSite(JSContext* cx, const Value* vp, size_t length, HandleObject proto = nullptr); @@ -202,7 +198,7 @@ array_splice(JSContext* cx, unsigned argc, js::Value* vp); extern bool NewbornArrayPush(JSContext* cx, HandleObject obj, const Value& v); -extern JSObject* +extern ArrayObject* ArrayConstructorOneArg(JSContext* cx, HandleObjectGroup group, int32_t lengthInt); #ifdef DEBUG diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 7765b1197..d7db5129d 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -2369,7 +2369,7 @@ js::str_replace_string_raw(JSContext* cx, HandleString string, HandleString patt } // ES 2016 draft Mar 25, 2016 21.1.3.17 steps 4, 8, 12-18. -static JSObject* +static ArrayObject* SplitHelper(JSContext* cx, HandleLinearString str, uint32_t limit, HandleLinearString sep, HandleObjectGroup group) { @@ -2466,7 +2466,7 @@ SplitHelper(JSContext* cx, HandleLinearString str, uint32_t limit, HandleLinearS } // Fast-path for splitting a string into a character array via split(""). -static JSObject* +static ArrayObject* CharSplitHelper(JSContext* cx, HandleLinearString str, uint32_t limit, HandleObjectGroup group) { size_t strLength = str->length(); @@ -2491,7 +2491,7 @@ CharSplitHelper(JSContext* cx, HandleLinearString str, uint32_t limit, HandleObj } // ES 2016 draft Mar 25, 2016 21.1.3.17 steps 4, 8, 12-18. -JSObject* +ArrayObject* js::str_split_string(JSContext* cx, HandleObjectGroup group, HandleString str, HandleString sep, uint32_t limit) { diff --git a/js/src/jsstr.h b/js/src/jsstr.h index 38fbfa85e..68175c826 100644 --- a/js/src/jsstr.h +++ b/js/src/jsstr.h @@ -465,7 +465,7 @@ FileEscapedString(FILE* fp, const char* chars, size_t length, uint32_t quote) return res; } -JSObject* +ArrayObject* str_split_string(JSContext* cx, HandleObjectGroup group, HandleString str, HandleString sep, uint32_t limit); diff --git a/js/src/vm/JSONParser.cpp b/js/src/vm/JSONParser.cpp index 01883bb15..e50da3bc4 100644 --- a/js/src/vm/JSONParser.cpp +++ b/js/src/vm/JSONParser.cpp @@ -606,8 +606,8 @@ JSONParserBase::finishArray(MutableHandleValue vp, ElementVector& elements) { MOZ_ASSERT(&elements == &stack.back().elements()); - JSObject* obj = ObjectGroup::newArrayObject(cx, elements.begin(), elements.length(), - GenericObject); + ArrayObject* obj = ObjectGroup::newArrayObject(cx, elements.begin(), elements.length(), + GenericObject); if (!obj) return false; diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp index a227b7c9c..c2866f5ae 100644 --- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -774,7 +774,7 @@ GetValueTypeForTable(const Value& v) return type; } -/* static */ JSObject* +/* static */ ArrayObject* ObjectGroup::newArrayObject(ExclusiveContext* cx, const Value* vp, size_t length, NewObjectKind newKind, NewArrayKind arrayKind) @@ -854,11 +854,8 @@ ObjectGroup::newArrayObject(ExclusiveContext* cx, } // The type of the elements being added will already be reflected in type - // information, but make sure when creating an unboxed array that the - // common element type is suitable for the unboxed representation. + // information. ShouldUpdateTypes updateTypes = ShouldUpdateTypes::DontUpdate; - if (!MaybeAnalyzeBeforeCreatingLargeArray(cx, group, vp, length)) - return nullptr; if (group->maybePreliminaryObjects()) group->maybePreliminaryObjects()->maybeAnalyze(cx, group); diff --git a/js/src/vm/ObjectGroup.h b/js/src/vm/ObjectGroup.h index 4e24de9f1..553cb8366 100644 --- a/js/src/vm/ObjectGroup.h +++ b/js/src/vm/ObjectGroup.h @@ -505,11 +505,11 @@ class ObjectGroup : public gc::TenuredCell UnknownIndex // Make an array with an unknown element type. }; - // Create an ArrayObject or UnboxedArrayObject with the specified elements - // and a group specialized for the elements. - static JSObject* newArrayObject(ExclusiveContext* cx, const Value* vp, size_t length, - NewObjectKind newKind, - NewArrayKind arrayKind = NewArrayKind::Normal); + // Create an ArrayObject with the specified elements and a group specialized + // for the elements. + static ArrayObject* newArrayObject(ExclusiveContext* cx, const Value* vp, size_t length, + NewObjectKind newKind, + NewArrayKind arrayKind = NewArrayKind::Normal); // Create a PlainObject or UnboxedPlainObject with the specified properties // and a group specialized for those properties. diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 87e95c893..c5f2cf5f3 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -82,7 +82,7 @@ InterpreterFrame::isNonGlobalEvalFrame() const return isEvalFrame() && script()->bodyScope()->as().isNonGlobal(); } -JSObject* +ArrayObject* InterpreterFrame::createRestParameter(JSContext* cx) { MOZ_ASSERT(script()->hasRest()); diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index 552738d89..dc9306c99 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -523,7 +523,7 @@ class InterpreterFrame ArgumentsObject& argsObj() const; void initArgsObj(ArgumentsObject& argsobj); - JSObject* createRestParameter(JSContext* cx); + ArrayObject* createRestParameter(JSContext* cx); /* * Environment chain -- cgit v1.2.3 From 93ce7c7372b20f6e6c6778f9c196b723a1df27a8 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Wed, 12 Jun 2019 09:09:53 +0000 Subject: Remove unused LIR temp register for unboxed arrays. --- js/src/jit/Lowering.cpp | 16 ++++------------ js/src/jit/shared/LIR-shared.h | 24 ++++++++---------------- 2 files changed, 12 insertions(+), 28 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index e185b5746..68417138b 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -3137,20 +3137,16 @@ LIRGenerator::visitStoreElementHole(MStoreElementHole* ins) const LUse elements = useRegister(ins->elements()); const LAllocation index = useRegisterOrConstant(ins->index()); - // Use a temp register when adding new elements to unboxed arrays. - LDefinition tempDef = LDefinition::BogusTemp(); - LInstruction* lir; switch (ins->value()->type()) { case MIRType::Value: - lir = new(alloc()) LStoreElementHoleV(object, elements, index, useBox(ins->value()), - tempDef); + lir = new(alloc()) LStoreElementHoleV(object, elements, index, useBox(ins->value())); break; default: { const LAllocation value = useRegisterOrNonDoubleConstant(ins->value()); - lir = new(alloc()) LStoreElementHoleT(object, elements, index, value, tempDef); + lir = new(alloc()) LStoreElementHoleT(object, elements, index, value); break; } } @@ -3169,18 +3165,14 @@ LIRGenerator::visitFallibleStoreElement(MFallibleStoreElement* ins) const LUse elements = useRegister(ins->elements()); const LAllocation index = useRegisterOrConstant(ins->index()); - // Use a temp register when adding new elements to unboxed arrays. - LDefinition tempDef = LDefinition::BogusTemp(); - LInstruction* lir; switch (ins->value()->type()) { case MIRType::Value: - lir = new(alloc()) LFallibleStoreElementV(object, elements, index, useBox(ins->value()), - tempDef); + lir = new(alloc()) LFallibleStoreElementV(object, elements, index, useBox(ins->value())); break; default: const LAllocation value = useRegisterOrNonDoubleConstant(ins->value()); - lir = new(alloc()) LFallibleStoreElementT(object, elements, index, value, tempDef); + lir = new(alloc()) LFallibleStoreElementT(object, elements, index, value); break; } diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h index 35c7e7442..ffa4d8367 100644 --- a/js/src/jit/shared/LIR-shared.h +++ b/js/src/jit/shared/LIR-shared.h @@ -5669,19 +5669,17 @@ class LStoreElementT : public LInstructionHelper<0, 3, 0> }; // Like LStoreElementV, but supports indexes >= initialized length. -class LStoreElementHoleV : public LInstructionHelper<0, 3 + BOX_PIECES, 1> +class LStoreElementHoleV : public LInstructionHelper<0, 3 + BOX_PIECES, 0> { public: LIR_HEADER(StoreElementHoleV) LStoreElementHoleV(const LAllocation& object, const LAllocation& elements, - const LAllocation& index, const LBoxAllocation& value, - const LDefinition& temp) { + const LAllocation& index, const LBoxAllocation& value) { setOperand(0, object); setOperand(1, elements); setOperand(2, index); setBoxOperand(Value, value); - setTemp(0, temp); } static const size_t Value = 3; @@ -5701,19 +5699,17 @@ class LStoreElementHoleV : public LInstructionHelper<0, 3 + BOX_PIECES, 1> }; // Like LStoreElementT, but supports indexes >= initialized length. -class LStoreElementHoleT : public LInstructionHelper<0, 4, 1> +class LStoreElementHoleT : public LInstructionHelper<0, 4, 0> { public: LIR_HEADER(StoreElementHoleT) LStoreElementHoleT(const LAllocation& object, const LAllocation& elements, - const LAllocation& index, const LAllocation& value, - const LDefinition& temp) { + const LAllocation& index, const LAllocation& value) { setOperand(0, object); setOperand(1, elements); setOperand(2, index); setOperand(3, value); - setTemp(0, temp); } const MStoreElementHole* mir() const { @@ -5734,19 +5730,17 @@ class LStoreElementHoleT : public LInstructionHelper<0, 4, 1> }; // Like LStoreElementV, but can just ignore assignment (for eg. frozen objects) -class LFallibleStoreElementV : public LInstructionHelper<0, 3 + BOX_PIECES, 1> +class LFallibleStoreElementV : public LInstructionHelper<0, 3 + BOX_PIECES, 0> { public: LIR_HEADER(FallibleStoreElementV) LFallibleStoreElementV(const LAllocation& object, const LAllocation& elements, - const LAllocation& index, const LBoxAllocation& value, - const LDefinition& temp) { + const LAllocation& index, const LBoxAllocation& value) { setOperand(0, object); setOperand(1, elements); setOperand(2, index); setBoxOperand(Value, value); - setTemp(0, temp); } static const size_t Value = 3; @@ -5766,19 +5760,17 @@ class LFallibleStoreElementV : public LInstructionHelper<0, 3 + BOX_PIECES, 1> }; // Like LStoreElementT, but can just ignore assignment (for eg. frozen objects) -class LFallibleStoreElementT : public LInstructionHelper<0, 4, 1> +class LFallibleStoreElementT : public LInstructionHelper<0, 4, 0> { public: LIR_HEADER(FallibleStoreElementT) LFallibleStoreElementT(const LAllocation& object, const LAllocation& elements, - const LAllocation& index, const LAllocation& value, - const LDefinition& temp) { + const LAllocation& index, const LAllocation& value) { setOperand(0, object); setOperand(1, elements); setOperand(2, index); setOperand(3, value); - setTemp(0, temp); } const MFallibleStoreElement* mir() const { -- cgit v1.2.3 From ec96ef3b7712da562d9f2f26c4099a5700c4eea4 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Wed, 12 Jun 2019 09:56:41 +0000 Subject: Remove unboxed array context option and shell flag. --- js/src/jsapi.h | 8 -------- js/src/shell/js.cpp | 4 ---- js/src/vm/ObjectGroup.cpp | 13 ------------- 3 files changed, 25 deletions(-) (limited to 'js/src') diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 005d2278e..3f65dad34 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -1093,7 +1093,6 @@ class JS_PUBLIC_API(ContextOptions) { wasmAlwaysBaseline_(false), throwOnAsmJSValidationFailure_(false), nativeRegExp_(true), - unboxedArrays_(false), asyncStack_(true), throwOnDebuggeeWouldRun_(true), dumpStackOnDebuggeeWouldRun_(false), @@ -1170,12 +1169,6 @@ class JS_PUBLIC_API(ContextOptions) { return *this; } - bool unboxedArrays() const { return unboxedArrays_; } - ContextOptions& setUnboxedArrays(bool flag) { - unboxedArrays_ = flag; - return *this; - } - bool asyncStack() const { return asyncStack_; } ContextOptions& setAsyncStack(bool flag) { asyncStack_ = flag; @@ -1238,7 +1231,6 @@ class JS_PUBLIC_API(ContextOptions) { bool wasmAlwaysBaseline_ : 1; bool throwOnAsmJSValidationFailure_ : 1; bool nativeRegExp_ : 1; - bool unboxedArrays_ : 1; bool asyncStack_ : 1; bool throwOnDebuggeeWouldRun_ : 1; bool dumpStackOnDebuggeeWouldRun_ : 1; diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 193d8d22b..29cbd9762 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -320,7 +320,6 @@ static bool enableIon = false; static bool enableAsmJS = false; static bool enableWasm = false; static bool enableNativeRegExp = false; -static bool enableUnboxedArrays = false; static bool enableSharedMemory = SHARED_MEMORY_DEFAULT; static bool enableWasmAlwaysBaseline = false; static bool enableArrayProtoValues = true; @@ -7260,7 +7259,6 @@ SetContextOptions(JSContext* cx, const OptionParser& op) enableAsmJS = !op.getBoolOption("no-asmjs"); enableWasm = !op.getBoolOption("no-wasm"); enableNativeRegExp = !op.getBoolOption("no-native-regexp"); - enableUnboxedArrays = op.getBoolOption("unboxed-arrays"); enableWasmAlwaysBaseline = op.getBoolOption("wasm-always-baseline"); enableArrayProtoValues = !op.getBoolOption("no-array-proto-values"); @@ -7270,7 +7268,6 @@ SetContextOptions(JSContext* cx, const OptionParser& op) .setWasm(enableWasm) .setWasmAlwaysBaseline(enableWasmAlwaysBaseline) .setNativeRegExp(enableNativeRegExp) - .setUnboxedArrays(enableUnboxedArrays) .setArrayProtoValues(enableArrayProtoValues); if (op.getBoolOption("wasm-check-bce")) @@ -7710,7 +7707,6 @@ main(int argc, char** argv, char** envp) || !op.addBoolOption('\0', "no-wasm", "Disable WebAssembly compilation") || !op.addBoolOption('\0', "no-native-regexp", "Disable native regexp compilation") || !op.addBoolOption('\0', "no-unboxed-objects", "Disable creating unboxed plain objects") - || !op.addBoolOption('\0', "unboxed-arrays", "Allow creating unboxed arrays") || !op.addBoolOption('\0', "wasm-always-baseline", "Enable wasm baseline compiler when possible") || !op.addBoolOption('\0', "wasm-check-bce", "Always generate wasm bounds check, even redundant ones.") || !op.addBoolOption('\0', "no-array-proto-values", "Remove Array.prototype.values") diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp index c2866f5ae..6b984a803 100644 --- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -1454,19 +1454,6 @@ ObjectGroup::allocationSiteGroup(JSContext* cx, JSScript* scriptArg, jsbytecode* } } - // FIXME: This block can probably go because of cx->options().unboxedArrays() - if (kind == JSProto_Array && - (JSOp(*pc) == JSOP_NEWARRAY || IsCallPC(pc)) && - cx->options().unboxedArrays()) - { - PreliminaryObjectArrayWithTemplate* preliminaryObjects = - cx->new_(nullptr); - if (preliminaryObjects) - res->setPreliminaryObjects(preliminaryObjects); - else - cx->recoverFromOutOfMemory(); - } - if (!table->add(p, key, res)) { ReportOutOfMemory(cx); return nullptr; -- cgit v1.2.3 From ef8e0ce6075150ed4501edad1376e4046cd8e3cb Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Wed, 12 Jun 2019 11:03:35 +0000 Subject: Remove functors for array natives. --- js/src/jsarray.cpp | 166 +++++++++++++++--------------------------- js/src/jsarray.h | 2 +- js/src/vm/UnboxedObject-inl.h | 121 ------------------------------ 3 files changed, 59 insertions(+), 230 deletions(-) (limited to 'js/src') diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 0d6f78fcf..9abc99e34 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -333,37 +333,31 @@ js::GetElementsWithAdder(JSContext* cx, HandleObject obj, HandleObject receiver, return true; } -template -DenseElementResult -GetBoxedOrUnboxedDenseElements(JSObject* aobj, uint32_t length, Value* vp) +static bool +GetDenseElements(NativeObject* aobj, uint32_t length, Value* vp) { MOZ_ASSERT(!ObjectMayHaveExtraIndexedProperties(aobj)); - if (length > aobj->as().getDenseInitializedLength()) - return DenseElementResult::Incomplete; + if (length > aobj->getDenseInitializedLength()) + return false; for (size_t i = 0; i < length; i++) { - vp[i] = aobj->as().getDenseElement(i); + vp[i] = aobj->getDenseElement(i); // No other indexed properties so hole => undefined. if (vp[i].isMagic(JS_ELEMENTS_HOLE)) vp[i] = UndefinedValue(); } - return DenseElementResult::Success; + return true; } -DefineBoxedOrUnboxedFunctor3(GetBoxedOrUnboxedDenseElements, - JSObject*, uint32_t, Value*); - bool js::GetElements(JSContext* cx, HandleObject aobj, uint32_t length, Value* vp) { if (!ObjectMayHaveExtraIndexedProperties(aobj)) { - GetBoxedOrUnboxedDenseElementsFunctor functor(aobj, length, vp); - DenseElementResult result = CallBoxedOrUnboxedSpecialization(functor, aobj); - if (result != DenseElementResult::Incomplete) - return result == DenseElementResult::Success; + if (GetDenseElements(&aobj->as(), length, vp)) + return true; } if (aobj->is()) { @@ -1061,32 +1055,32 @@ struct StringSeparatorOp } }; -template -static DenseElementResult -ArrayJoinDenseKernel(JSContext* cx, SeparatorOp sepOp, HandleObject obj, uint32_t length, +template +static bool +ArrayJoinDenseKernel(JSContext* cx, SeparatorOp sepOp, HandleNativeObject obj, uint64_t length, StringBuffer& sb, uint32_t* numProcessed) { // This loop handles all elements up to initializedLength. If // length > initLength we rely on the second loop to add the // other elements. MOZ_ASSERT(*numProcessed == 0); - uint32_t initLength = Min(obj->as().getDenseInitializedLength(), + uint32_t initLength = Min(obj->getDenseInitializedLength(), length); while (*numProcessed < initLength) { if (!CheckForInterrupt(cx)) - return DenseElementResult::Failure; + return false; Value elem = obj->as().getDenseElement(*numProcessed); if (elem.isString()) { if (!sb.append(elem.toString())) - return DenseElementResult::Failure; + return false; } else if (elem.isNumber()) { if (!NumberValueToStringBuffer(cx, elem, sb)) - return DenseElementResult::Failure; + return false; } else if (elem.isBoolean()) { if (!BooleanToStringBuffer(elem.toBoolean(), sb)) - return DenseElementResult::Failure; + return false; } else if (elem.isObject() || elem.isSymbol()) { /* * Object stringifying could modify the initialized length or make @@ -1102,32 +1096,12 @@ ArrayJoinDenseKernel(JSContext* cx, SeparatorOp sepOp, HandleObject obj, uint32_ } if (++(*numProcessed) != length && !sepOp(cx, sb)) - return DenseElementResult::Failure; + return false; } - return DenseElementResult::Incomplete; + return true; } -template -struct ArrayJoinDenseKernelFunctor { - JSContext* cx; - SeparatorOp sepOp; - HandleObject obj; - uint32_t length; - StringBuffer& sb; - uint32_t* numProcessed; - - ArrayJoinDenseKernelFunctor(JSContext* cx, SeparatorOp sepOp, HandleObject obj, - uint32_t length, StringBuffer& sb, uint32_t* numProcessed) - : cx(cx), sepOp(sepOp), obj(obj), length(length), sb(sb), numProcessed(numProcessed) - {} - - template - DenseElementResult operator()() { - return ArrayJoinDenseKernel(cx, sepOp, obj, length, sb, numProcessed); - } -}; - template static bool ArrayJoinKernel(JSContext* cx, SeparatorOp sepOp, HandleObject obj, uint32_t length, @@ -1136,10 +1110,10 @@ ArrayJoinKernel(JSContext* cx, SeparatorOp sepOp, HandleObject obj, uint32_t len uint32_t i = 0; if (!ObjectMayHaveExtraIndexedProperties(obj)) { - ArrayJoinDenseKernelFunctor functor(cx, sepOp, obj, length, sb, &i); - DenseElementResult result = CallBoxedOrUnboxedSpecialization(functor, obj); - if (result == DenseElementResult::Failure) + if (!ArrayJoinDenseKernel(cx, sepOp, obj.as(), length, sb, &i)) + { return false; + } } if (i != length) { @@ -1260,7 +1234,7 @@ js::array_join(JSContext* cx, unsigned argc, Value* vp) } // Step 11 - JSString *str = sb.finishString(); + JSString* str = sb.finishString(); if (!str) return false; @@ -1360,15 +1334,14 @@ InitArrayElements(JSContext* cx, HandleObject obj, uint32_t start, return true; } -template -DenseElementResult -ArrayReverseDenseKernel(JSContext* cx, HandleObject obj, uint32_t length) +static DenseElementResult +ArrayReverseDenseKernel(JSContext* cx, HandleNativeObject obj, uint32_t length) { /* An empty array or an array with no elements is already reversed. */ - if (length == 0 || obj->as().getDenseInitializedLength() == 0) + if (length == 0 || obj->getDenseInitializedLength() == 0) return DenseElementResult::Success; - if (obj->as().denseElementsAreFrozen()) + if (obj->denseElementsAreFrozen()) return DenseElementResult::Incomplete; /* @@ -1380,26 +1353,26 @@ ArrayReverseDenseKernel(JSContext* cx, HandleObject obj, uint32_t length) * holes in the array at its start) and ensure that the capacity is * sufficient to hold all the elements in the array if it were full. */ - DenseElementResult result = obj->as().ensureDenseElements(cx, length, 0); + DenseElementResult result = obj->ensureDenseElements(cx, length, 0); if (result != DenseElementResult::Success) return result; /* Fill out the array's initialized length to its proper length. */ - obj->as().ensureDenseInitializedLength(cx, length, 0); + obj->ensureDenseInitializedLength(cx, length, 0); RootedValue origlo(cx), orighi(cx); uint32_t lo = 0, hi = length - 1; for (; lo < hi; lo++, hi--) { - origlo = obj->as().getDenseElement(lo); - orighi = obj->as().getDenseElement(hi); - obj->as().setDenseElement(lo, orighi); + origlo = obj->getDenseElement(lo); + orighi = obj->getDenseElement(hi); + obj->setDenseElement(lo, orighi); if (orighi.isMagic(JS_ELEMENTS_HOLE) && !SuppressDeletedProperty(cx, obj, INT_TO_JSID(lo))) { return DenseElementResult::Failure; } - obj->as().setDenseElement(hi, origlo); + obj->setDenseElement(hi, origlo); if (origlo.isMagic(JS_ELEMENTS_HOLE) && !SuppressDeletedProperty(cx, obj, INT_TO_JSID(hi))) { @@ -1410,9 +1383,6 @@ ArrayReverseDenseKernel(JSContext* cx, HandleObject obj, uint32_t length) return DenseElementResult::Success; } -DefineBoxedOrUnboxedFunctor3(ArrayReverseDenseKernel, - JSContext*, HandleObject, uint32_t); - bool js::array_reverse(JSContext* cx, unsigned argc, Value* vp) { @@ -1427,8 +1397,8 @@ js::array_reverse(JSContext* cx, unsigned argc, Value* vp) return false; if (!ObjectMayHaveExtraIndexedProperties(obj)) { - ArrayReverseDenseKernelFunctor functor(cx, obj, len); - DenseElementResult result = CallBoxedOrUnboxedSpecialization(functor, obj); + DenseElementResult result = + ArrayReverseDenseKernel(cx, obj.as(), uint32_t(len)); if (result != DenseElementResult::Incomplete) { /* * Per ECMA-262, don't update the length of the array, even if the new @@ -2137,33 +2107,20 @@ js::array_pop(JSContext* cx, unsigned argc, Value* vp) return SetLengthProperty(cx, obj, index); } -template -static inline DenseElementResult -ShiftMoveBoxedOrUnboxedDenseElements(JSObject* obj) +void +js::ArrayShiftMoveElements(NativeObject* obj) { - MOZ_ASSERT(obj->isNative()); + MOZ_ASSERT_IF(obj->is(), obj->as().lengthIsWritable()); - size_t initlen = obj->as().getDenseInitializedLength(); + size_t initlen = obj->getDenseInitializedLength(); + MOZ_ASSERT(initlen > 0); /* * At this point the length and initialized length have already been * decremented and the result fetched, so just shift the array elements * themselves. */ - obj->as().moveDenseElementsNoPreBarrier(0, 1, initlen); - - return DenseElementResult::Success; -} - -DefineBoxedOrUnboxedFunctor1(ShiftMoveBoxedOrUnboxedDenseElements, JSObject*); - -void -js::ArrayShiftMoveElements(JSObject* obj) -{ - MOZ_ASSERT_IF(obj->is(), obj->as().lengthIsWritable()); - - ShiftMoveBoxedOrUnboxedDenseElementsFunctor functor(obj); - JS_ALWAYS_TRUE(CallBoxedOrUnboxedSpecialization(functor, obj) == DenseElementResult::Success); + obj->moveDenseElementsNoPreBarrier(0, 1, initlen - 1); } static inline void @@ -2175,8 +2132,7 @@ SetInitializedLength(JSContext* cx, NativeObject* obj, size_t initlen) obj->shrinkElements(cx, initlen); } -template -DenseElementResult +static DenseElementResult ArrayShiftDenseKernel(JSContext* cx, HandleObject obj, MutableHandleValue rval) { if (ObjectMayHaveExtraIndexedProperties(obj)) @@ -2205,9 +2161,6 @@ ArrayShiftDenseKernel(JSContext* cx, HandleObject obj, MutableHandleValue rval) return DenseElementResult::Success; } -DefineBoxedOrUnboxedFunctor3(ArrayShiftDenseKernel, - JSContext*, HandleObject, MutableHandleValue); - /* ES5 15.4.4.9 */ bool js::array_shift(JSContext* cx, unsigned argc, Value* vp) @@ -2239,8 +2192,7 @@ js::array_shift(JSContext* cx, unsigned argc, Value* vp) uint32_t newlen = len - 1; /* Fast paths. */ - ArrayShiftDenseKernelFunctor functor(cx, obj, args.rval()); - DenseElementResult result = CallBoxedOrUnboxedSpecialization(functor, obj); + DenseElementResult result = ArrayShiftDenseKernel(cx, obj, args.rval()); if (result != DenseElementResult::Incomplete) { if (result == DenseElementResult::Failure) return false; @@ -2999,11 +2951,10 @@ js::array_slice(JSContext* cx, unsigned argc, Value* vp) return true; } -template -DenseElementResult -ArraySliceDenseKernel(JSContext* cx, JSObject* obj, int32_t beginArg, int32_t endArg, JSObject* result) +static bool +ArraySliceDenseKernel(JSContext* cx, ArrayObject* arr, int32_t beginArg, int32_t endArg, ArrayObject* result) { - int32_t length = obj->as().length(); + int32_t length = arr->length(); uint32_t begin = NormalizeSliceTerm(beginArg, length); uint32_t end = NormalizeSliceTerm(endArg, length); @@ -3011,34 +2962,33 @@ ArraySliceDenseKernel(JSContext* cx, JSObject* obj, int32_t beginArg, int32_t en if (begin > end) begin = end; - size_t initlen = obj->as().getDenseInitializedLength(); + size_t initlen = arr->getDenseInitializedLength(); size_t count = Min(initlen - begin, end - begin); if (initlen > begin) { if (count) { - if (!result->as().ensureElements(cx, count)) - return DenseElementResult::Failure; - CopyBoxedOrUnboxedDenseElements(cx, result, obj, 0, begin, count); + if (!result->ensureElements(cx, count)) + return false; + CopyBoxedOrUnboxedDenseElements(cx, result, arr, 0, begin, count); } } - MOZ_ASSERT(count >= result->as().length()); - result->as().setLength(cx, count); + MOZ_ASSERT(count >= result->length()); + result->setLength(cx, count); - return DenseElementResult::Success; + return true; } -DefineBoxedOrUnboxedFunctor5(ArraySliceDenseKernel, - JSContext*, JSObject*, int32_t, int32_t, JSObject*); - JSObject* js::array_slice_dense(JSContext* cx, HandleObject obj, int32_t begin, int32_t end, HandleObject result) { if (result && IsArraySpecies(cx, obj)) { - ArraySliceDenseKernelFunctor functor(cx, obj, begin, end, result); - DenseElementResult rv = CallBoxedOrUnboxedSpecialization(functor, result); - MOZ_ASSERT(rv != DenseElementResult::Incomplete); - return rv == DenseElementResult::Success ? result : nullptr; + if (!ArraySliceDenseKernel(cx, &obj->as(), begin, end, + &result->as())) + { + return nullptr; + } + return result; } // Slower path if the JIT wasn't able to allocate an object inline. diff --git a/js/src/jsarray.h b/js/src/jsarray.h index ecde87c3b..1bee742ce 100644 --- a/js/src/jsarray.h +++ b/js/src/jsarray.h @@ -168,7 +168,7 @@ extern bool array_join(JSContext* cx, unsigned argc, js::Value* vp); extern void -ArrayShiftMoveElements(JSObject* obj); +ArrayShiftMoveElements(NativeObject* obj); extern bool array_shift(JSContext* cx, unsigned argc, js::Value* vp); diff --git a/js/src/vm/UnboxedObject-inl.h b/js/src/vm/UnboxedObject-inl.h index b308464fe..711a064f2 100644 --- a/js/src/vm/UnboxedObject-inl.h +++ b/js/src/vm/UnboxedObject-inl.h @@ -244,127 +244,6 @@ CopyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src, return DenseElementResult::Success; } -///////////////////////////////////////////////////////////////////// -// Dispatch to specialized methods based on the type of an object. -///////////////////////////////////////////////////////////////////// - -// Goop to fix MSVC. See DispatchTraceKindTyped in TraceKind.h. -// The clang-cl front end defines _MSC_VER, but still requires the explicit -// template declaration, so we must test for __clang__ here as well. -#if defined(_MSC_VER) && !defined(__clang__) -# define DEPENDENT_TEMPLATE_HINT -#else -# define DEPENDENT_TEMPLATE_HINT template -#endif - -// Function to dispatch a method specialized to whatever boxed or unboxed dense -// elements which an input object has. -template -DenseElementResult -CallBoxedOrUnboxedSpecialization(F f, JSObject* obj) -{ - if (!obj->isNative()) - return DenseElementResult::Incomplete; - return f. DEPENDENT_TEMPLATE_HINT operator()(); -} - -// As above, except the specialization can reflect the unboxed type of two objects. -template -DenseElementResult -CallBoxedOrUnboxedSpecialization(F f, JSObject* obj1, JSObject* obj2) -{ - if (!obj1->isNative() || !obj2->isNative()) - return DenseElementResult::Incomplete; - - return f. DEPENDENT_TEMPLATE_HINT operator()(); -} - -#undef DEPENDENT_TEMPLATE_HINT - -#define DefineBoxedOrUnboxedFunctor1(Signature, A) \ -struct Signature ## Functor { \ - A a; \ - explicit Signature ## Functor(A a) \ - : a(a) \ - {} \ - template \ - DenseElementResult operator()() { \ - return Signature(a); \ - } \ -} - -#define DefineBoxedOrUnboxedFunctor3(Signature, A, B, C) \ -struct Signature ## Functor { \ - A a; B b; C c; \ - Signature ## Functor(A a, B b, C c) \ - : a(a), b(b), c(c) \ - {} \ - template \ - DenseElementResult operator()() { \ - return Signature(a, b, c); \ - } \ -} - -#define DefineBoxedOrUnboxedFunctor4(Signature, A, B, C, D) \ -struct Signature ## Functor { \ - A a; B b; C c; D d; \ - Signature ## Functor(A a, B b, C c, D d) \ - : a(a), b(b), c(c), d(d) \ - {} \ - template \ - DenseElementResult operator()() { \ - return Signature(a, b, c, d); \ - } \ -} - -#define DefineBoxedOrUnboxedFunctorPair4(Signature, A, B, C, D) \ -struct Signature ## Functor { \ - A a; B b; C c; D d; \ - Signature ## Functor(A a, B b, C c, D d) \ - : a(a), b(b), c(c), d(d) \ - {} \ - template \ - DenseElementResult operator()() { \ - return Signature(a, b, c, d); \ - } \ -} - -#define DefineBoxedOrUnboxedFunctor5(Signature, A, B, C, D, E) \ -struct Signature ## Functor { \ - A a; B b; C c; D d; E e; \ - Signature ## Functor(A a, B b, C c, D d, E e) \ - : a(a), b(b), c(c), d(d), e(e) \ - {} \ - template \ - DenseElementResult operator()() { \ - return Signature(a, b, c, d, e); \ - } \ -} - -#define DefineBoxedOrUnboxedFunctor6(Signature, A, B, C, D, E, F) \ -struct Signature ## Functor { \ - A a; B b; C c; D d; E e; F f; \ - Signature ## Functor(A a, B b, C c, D d, E e, F f) \ - : a(a), b(b), c(c), d(d), e(e), f(f) \ - {} \ - template \ - DenseElementResult operator()() { \ - return Signature(a, b, c, d, e, f); \ - } \ -} - -#define DefineBoxedOrUnboxedFunctorPair6(Signature, A, B, C, D, E, F) \ -struct Signature ## Functor { \ - A a; B b; C c; D d; E e; F f; \ - Signature ## Functor(A a, B b, C c, D d, E e, F f) \ - : a(a), b(b), c(c), d(d), e(e), f(f) \ - {} \ - template \ - DenseElementResult operator()() { \ - return Signature(a, b, c, d, e, f); \ - } \ -} - } // namespace js #endif // vm_UnboxedObject_inl_h -- cgit v1.2.3 From b17a1f211efb85ddb36abfa769aac3a4292d17ee Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 15 Jun 2019 23:03:07 +0200 Subject: Update tzdata SpiderMonkey files --- js/src/builtin/IntlTimeZoneData.h | 2 +- js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js | 5 +++-- js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js | 2 +- js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js | 2 +- js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) (limited to 'js/src') diff --git a/js/src/builtin/IntlTimeZoneData.h b/js/src/builtin/IntlTimeZoneData.h index fa808c0b9..8f963ffbc 100644 --- a/js/src/builtin/IntlTimeZoneData.h +++ b/js/src/builtin/IntlTimeZoneData.h @@ -1,5 +1,5 @@ // Generated by make_intl_data.py. DO NOT EDIT. -// tzdata version = 2018e +// tzdata version = 2019a #ifndef builtin_IntlTimeZoneData_h #define builtin_IntlTimeZoneData_h diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js b/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js index d87abd7be..8cda44d87 100644 --- a/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js +++ b/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js @@ -1,7 +1,7 @@ // |reftest| skip-if(!this.hasOwnProperty("Intl")) // Generated by make_intl_data.py. DO NOT EDIT. -// tzdata version = 2018e +// tzdata version = 2019a const tzMapper = [ x => x, @@ -67,6 +67,7 @@ const links = { "Cuba": "America/Havana", "Egypt": "Africa/Cairo", "Eire": "Europe/Dublin", + "Etc/UCT": "Etc/UTC", "GB": "Europe/London", "GB-Eire": "Europe/London", "GMT+0": "Etc/GMT", @@ -98,7 +99,7 @@ const links = { "ROK": "Asia/Seoul", "Singapore": "Asia/Singapore", "Turkey": "Europe/Istanbul", - "UCT": "Etc/UCT", + "UCT": "Etc/UTC", "US/Alaska": "America/Anchorage", "US/Aleutian": "America/Adak", "US/Arizona": "America/Phoenix", diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js index b96dac96f..a3efe0310 100644 --- a/js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js +++ b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js @@ -1,7 +1,7 @@ // |reftest| skip-if(!this.hasOwnProperty("Intl")) // Generated by make_intl_data.py. DO NOT EDIT. -// tzdata version = 2018e +// tzdata version = 2019a const tzMapper = [ x => x, diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js index 66ef3075d..b61593f78 100644 --- a/js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js +++ b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js @@ -1,7 +1,7 @@ // |reftest| skip-if(!this.hasOwnProperty("Intl")) // Generated by make_intl_data.py. DO NOT EDIT. -// tzdata version = 2018e +// tzdata version = 2019a const tzMapper = [ x => x, diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js b/js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js index 8d44204bc..12b55c214 100644 --- a/js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js +++ b/js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js @@ -1,7 +1,7 @@ // |reftest| skip-if(!this.hasOwnProperty("Intl")) // Generated by make_intl_data.py. DO NOT EDIT. -// tzdata version = 2018e +// tzdata version = 2019a const tzMapper = [ x => x, -- cgit v1.2.3 From 9153838ea299da3bd00767394ff021318c1e0f12 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Mon, 17 Jun 2019 15:09:05 +0000 Subject: Fix typo in ArrayShiftMoveElements --- js/src/jsarray.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'js/src') diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 9abc99e34..7af7c9800 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -2120,7 +2120,7 @@ js::ArrayShiftMoveElements(NativeObject* obj) * decremented and the result fetched, so just shift the array elements * themselves. */ - obj->moveDenseElementsNoPreBarrier(0, 1, initlen - 1); + obj->moveDenseElementsNoPreBarrier(0, 1, initlen); } static inline void -- cgit v1.2.3 From 3c878b1e3bbb043b22ab032bce1fe111b8062ca9 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Mon, 17 Jun 2019 18:37:23 +0000 Subject: Convert CopyBoxedOrUnboxedDenseElements to something that doesn't crash. --- js/src/jit/BaselineIC.cpp | 14 ++++++++++++-- js/src/jsarray.cpp | 24 +++++++++++++++++++++--- js/src/vm/UnboxedObject-inl.h | 18 ------------------ 3 files changed, 33 insertions(+), 23 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 2b0822655..17fdb1807 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -5769,8 +5769,18 @@ CopyArray(JSContext* cx, HandleArrayObject arr, MutableHandleValue result) if (!nobj) return false; EnsureArrayGroupAnalyzed(cx, nobj); //XXX - CopyBoxedOrUnboxedDenseElements(cx, nobj, arr, 0, 0, length); - + + MOZ_ASSERT(arr->isNative()); + MOZ_ASSERT(nobj->isNative()); + MOZ_ASSERT(nobj->as().getDenseInitializedLength() == 0); + MOZ_ASSERT(arr->as().getDenseInitializedLength() >= length); + MOZ_ASSERT(nobj->as().getDenseCapacity() >= length); + + nobj->as().setDenseInitializedLength(length); + + const Value* vp = arr->as().getDenseElements(); + nobj->as().initDenseElements(0, vp, length); + result.setObject(*nobj); return true; } diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 7af7c9800..159717fea 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -2361,6 +2361,22 @@ CanOptimizeForDenseStorage(HandleObject arr, uint32_t startingIndex, uint32_t co startingIndex + count <= arr->as().getDenseInitializedLength(); } +static inline DenseElementResult +CopyDenseElements(JSContext* cx, NativeObject* dst, NativeObject* src, + uint32_t dstStart, uint32_t srcStart, uint32_t length) +{ + MOZ_ASSERT(dst->getDenseInitializedLength() == dstStart); + MOZ_ASSERT(src->getDenseInitializedLength() >= srcStart + length); + MOZ_ASSERT(dst->getDenseCapacity() >= dstStart + length); + + dst->setDenseInitializedLength(dstStart + length); + + const Value* vp = src->getDenseElements() + srcStart; + dst->initDenseElements(dstStart, vp, length); + + return DenseElementResult::Success; +} + /* ES 2016 draft Mar 25, 2016 22.1.3.26. */ bool js::array_splice(JSContext* cx, unsigned argc, Value* vp) @@ -2459,7 +2475,9 @@ js::array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueI /* Steps 10-11. */ DebugOnly result = - CopyBoxedOrUnboxedDenseElements(cx, arr, obj, 0, actualStart, actualDeleteCount); + CopyDenseElements(cx, &arr->as(), + &obj->as(), 0, + actualStart, actualDeleteCount); MOZ_ASSERT(result.value == DenseElementResult::Success); /* Step 12 (implicit). */ @@ -2827,7 +2845,7 @@ ArraySliceOrdinary(JSContext* cx, HandleObject obj, uint32_t length, uint32_t be if (count) { DebugOnly result = - CopyBoxedOrUnboxedDenseElements(cx, narr, obj, 0, begin, count); + CopyDenseElements(cx, &narr->as(), &obj->as(), 0, begin, count); MOZ_ASSERT(result.value == DenseElementResult::Success); } arr.set(narr); @@ -2968,7 +2986,7 @@ ArraySliceDenseKernel(JSContext* cx, ArrayObject* arr, int32_t beginArg, int32_t if (count) { if (!result->ensureElements(cx, count)) return false; - CopyBoxedOrUnboxedDenseElements(cx, result, arr, 0, begin, count); + CopyDenseElements(cx, &result->as(), &arr->as(), 0, begin, count); } } diff --git a/js/src/vm/UnboxedObject-inl.h b/js/src/vm/UnboxedObject-inl.h index 711a064f2..069527141 100644 --- a/js/src/vm/UnboxedObject-inl.h +++ b/js/src/vm/UnboxedObject-inl.h @@ -226,24 +226,6 @@ MoveBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, uint32_t dstStart, return DenseElementResult::Success; } -static inline DenseElementResult -CopyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src, - uint32_t dstStart, uint32_t srcStart, uint32_t length) -{ - MOZ_ASSERT(src->isNative()); - MOZ_ASSERT(dst->isNative()); - MOZ_ASSERT(dst->as().getDenseInitializedLength() == dstStart); - MOZ_ASSERT(src->as().getDenseInitializedLength() >= srcStart + length); - MOZ_ASSERT(dst->as().getDenseCapacity() >= dstStart + length); - - dst->as().setDenseInitializedLength(dstStart + length); - - const Value* vp = src->as().getDenseElements() + srcStart; - dst->as().initDenseElements(dstStart, vp, length); - - return DenseElementResult::Success; -} - } // namespace js #endif // vm_UnboxedObject_inl_h -- cgit v1.2.3 From 8d2929313f6f8be66770f1137fa54a0825a3c768 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 13 Jun 2019 11:42:21 +0000 Subject: Clean up and rename MoveBoxedOrUnboxedDenseElements. --- js/src/jsarray.cpp | 25 +++++++++++++++++++------ js/src/vm/UnboxedObject-inl.h | 16 ---------------- 2 files changed, 19 insertions(+), 22 deletions(-) (limited to 'js/src') diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 159717fea..97f035fd9 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -2132,6 +2132,20 @@ SetInitializedLength(JSContext* cx, NativeObject* obj, size_t initlen) obj->shrinkElements(cx, initlen); } +static DenseElementResult +MoveDenseElements(JSContext* cx, NativeObject* obj, uint32_t dstStart, uint32_t srcStart, + uint32_t length) +{ + if (obj->denseElementsAreFrozen()) + return DenseElementResult::Incomplete; + + if (!obj->maybeCopyElementsForWrite(cx)) + return DenseElementResult::Failure; + obj->moveDenseElements(dstStart, srcStart, length); + + return DenseElementResult::Success; +} + static DenseElementResult ArrayShiftDenseKernel(JSContext* cx, HandleObject obj, MutableHandleValue rval) { @@ -2153,7 +2167,7 @@ ArrayShiftDenseKernel(JSContext* cx, HandleObject obj, MutableHandleValue rval) if (rval.isMagic(JS_ELEMENTS_HOLE)) rval.setUndefined(); - DenseElementResult result = MoveBoxedOrUnboxedDenseElements(cx, obj, 0, 1, initlen - 1); + DenseElementResult result = MoveDenseElements(cx, &obj->as(), 0, 1, initlen - 1); if (result != DenseElementResult::Success) return result; @@ -2514,8 +2528,7 @@ js::array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueI if (CanOptimizeForDenseStorage(obj, 0, len, cx)) { /* Steps 15.a-b. */ DenseElementResult result = - MoveBoxedOrUnboxedDenseElements(cx, obj, targetIndex, sourceIndex, - len - sourceIndex); + MoveDenseElements(cx, &obj->as(), targetIndex, sourceIndex, len - sourceIndex); MOZ_ASSERT(result != DenseElementResult::Incomplete); if (result == DenseElementResult::Failure) return false; @@ -2601,9 +2614,9 @@ js::array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueI if (CanOptimizeForDenseStorage(obj, len, itemCount - actualDeleteCount, cx)) { DenseElementResult result = - MoveBoxedOrUnboxedDenseElements(cx, obj, actualStart + itemCount, - actualStart + actualDeleteCount, - len - (actualStart + actualDeleteCount)); + MoveDenseElements(cx, &obj->as(), actualStart + itemCount, + actualStart + actualDeleteCount, + len - (actualStart + actualDeleteCount)); MOZ_ASSERT(result != DenseElementResult::Incomplete); if (result == DenseElementResult::Failure) return false; diff --git a/js/src/vm/UnboxedObject-inl.h b/js/src/vm/UnboxedObject-inl.h index 069527141..193ca75c8 100644 --- a/js/src/vm/UnboxedObject-inl.h +++ b/js/src/vm/UnboxedObject-inl.h @@ -210,22 +210,6 @@ SetOrExtendBoxedOrUnboxedDenseElements(ExclusiveContext* cx, JSObject* obj, return DenseElementResult::Success; } -static inline DenseElementResult -MoveBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, uint32_t dstStart, uint32_t srcStart, - uint32_t length) -{ - MOZ_ASSERT(obj->isNative()); - - if (obj->as().denseElementsAreFrozen()) - return DenseElementResult::Incomplete; - - if (!obj->as().maybeCopyElementsForWrite(cx)) - return DenseElementResult::Failure; - obj->as().moveDenseElements(dstStart, srcStart, length); - - return DenseElementResult::Success; -} - } // namespace js #endif // vm_UnboxedObject_inl_h -- cgit v1.2.3 From 85f9a95ddbc39a1b120eeb8280685e1ae40dc5dc Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 14 Jun 2019 11:33:28 +0000 Subject: Replace SetOrExtendBoxedOrUnboxedDenseElements with direct calls. --- js/src/jit/CodeGenerator.cpp | 13 ++++++------- js/src/jit/VMFunctions.cpp | 23 ++++++++++------------- js/src/jit/VMFunctions.h | 6 +++--- js/src/jsarray.cpp | 20 ++++++++++---------- js/src/jsarray.h | 6 ------ js/src/vm/NativeObject-inl.h | 32 ++++++++++++++++++++++++++++++++ js/src/vm/NativeObject.h | 9 +++++++++ js/src/vm/UnboxedObject-inl.h | 38 -------------------------------------- 8 files changed, 70 insertions(+), 77 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index ae9c61031..e0b8a7f28 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -8213,11 +8213,10 @@ CodeGenerator::visitFallibleStoreElementV(LFallibleStoreElementV* lir) masm.bind(&isFrozen); } -typedef bool (*SetDenseOrUnboxedArrayElementFn)(JSContext*, HandleObject, int32_t, - HandleValue, bool strict); -static const VMFunction SetDenseOrUnboxedArrayElementInfo = - FunctionInfo(SetDenseOrUnboxedArrayElement, - "SetDenseOrUnboxedArrayElement"); +typedef bool (*SetDenseElementFn)(JSContext*, HandleNativeObject, int32_t, HandleValue, + bool strict); +static const VMFunction SetDenseElementInfo = + FunctionInfo(jit::SetDenseElement, "SetDenseElement"); void CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool) @@ -8326,7 +8325,7 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool) else pushArg(ToRegister(index)); pushArg(object); - callVM(SetDenseOrUnboxedArrayElementInfo, ins); + callVM(SetDenseElementInfo, ins); restoreLive(ins); masm.jump(ool->rejoin()); @@ -8500,7 +8499,7 @@ CodeGenerator::visitArrayPopShiftT(LArrayPopShiftT* lir) emitArrayPopShift(lir, lir->mir(), obj, elements, length, out); } -typedef bool (*ArrayPushDenseFn)(JSContext*, HandleObject, HandleValue, uint32_t*); +typedef bool (*ArrayPushDenseFn)(JSContext*, HandleArrayObject, HandleValue, uint32_t*); static const VMFunction ArrayPushDenseInfo = FunctionInfo(jit::ArrayPushDense, "ArrayPushDense"); diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 7b1e1cad6..297357b1e 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -337,12 +337,11 @@ ArrayPopDense(JSContext* cx, HandleObject obj, MutableHandleValue rval) } bool -ArrayPushDense(JSContext* cx, HandleObject obj, HandleValue v, uint32_t* length) +ArrayPushDense(JSContext* cx, HandleArrayObject arr, HandleValue v, uint32_t* length) { - *length = obj->as().length(); - DenseElementResult result = - SetOrExtendBoxedOrUnboxedDenseElements(cx, obj, *length, v.address(), 1, - ShouldUpdateTypes::DontUpdate); + *length = arr->length(); + DenseElementResult result = arr->setOrExtendDenseElements(cx, *length, v.address(), 1, + ShouldUpdateTypes::DontUpdate); if (result != DenseElementResult::Incomplete) { (*length)++; return result == DenseElementResult::Success; @@ -350,7 +349,7 @@ ArrayPushDense(JSContext* cx, HandleObject obj, HandleValue v, uint32_t* length) JS::AutoValueArray<3> argv(cx); argv[0].setUndefined(); - argv[1].setObject(*obj); + argv[1].setObject(*arr); argv[2].set(v); if (!js::array_push(cx, 1, argv.begin())) return false; @@ -1143,16 +1142,14 @@ Recompile(JSContext* cx) } bool -SetDenseOrUnboxedArrayElement(JSContext* cx, HandleObject obj, int32_t index, - HandleValue value, bool strict) +SetDenseElement(JSContext* cx, HandleNativeObject obj, int32_t index, HandleValue value, bool strict) { // This function is called from Ion code for StoreElementHole's OOL path. - // In this case we know the object is native or an unboxed array and that - // no type changes are needed. + // In this case we know the object is native and that no type changes are + // needed. - DenseElementResult result = - SetOrExtendBoxedOrUnboxedDenseElements(cx, obj, index, value.address(), 1, - ShouldUpdateTypes::DontUpdate); + DenseElementResult result = obj->setOrExtendDenseElements(cx, index, value.address(), 1, + ShouldUpdateTypes::DontUpdate); if (result != DenseElementResult::Incomplete) return result == DenseElementResult::Success; diff --git a/js/src/jit/VMFunctions.h b/js/src/jit/VMFunctions.h index 572f05373..9a2edd0f3 100644 --- a/js/src/jit/VMFunctions.h +++ b/js/src/jit/VMFunctions.h @@ -622,7 +622,7 @@ template bool StringsEqual(JSContext* cx, HandleString left, HandleString right, bool* res); MOZ_MUST_USE bool ArrayPopDense(JSContext* cx, HandleObject obj, MutableHandleValue rval); -MOZ_MUST_USE bool ArrayPushDense(JSContext* cx, HandleObject obj, HandleValue v, uint32_t* length); +MOZ_MUST_USE bool ArrayPushDense(JSContext* cx, HandleArrayObject obj, HandleValue v, uint32_t* length); MOZ_MUST_USE bool ArrayShiftDense(JSContext* cx, HandleObject obj, MutableHandleValue rval); JSString* ArrayJoin(JSContext* cx, HandleObject array, HandleString sep); @@ -748,8 +748,8 @@ ForcedRecompile(JSContext* cx); JSString* StringReplace(JSContext* cx, HandleString string, HandleString pattern, HandleString repl); -MOZ_MUST_USE bool SetDenseOrUnboxedArrayElement(JSContext* cx, HandleObject obj, int32_t index, - HandleValue value, bool strict); +MOZ_MUST_USE bool SetDenseElement(JSContext* cx, HandleNativeObject obj, int32_t index, + HandleValue value, bool strict); void AssertValidObjectPtr(JSContext* cx, JSObject* obj); void AssertValidObjectOrNullPtr(JSContext* cx, JSObject* obj); diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 97f035fd9..b77a5bce8 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -280,8 +280,8 @@ ElementAdder::append(JSContext* cx, HandleValue v) { MOZ_ASSERT(index_ < length_); if (resObj_) { - DenseElementResult result = - SetOrExtendBoxedOrUnboxedDenseElements(cx, resObj_, index_, v.address(), 1); + NativeObject* resObj = &resObj_->as(); + DenseElementResult result = resObj->setOrExtendDenseElements(cx, index_, v.address(), 1); if (result == DenseElementResult::Failure) return false; if (result == DenseElementResult::Incomplete) { @@ -390,8 +390,8 @@ SetArrayElement(JSContext* cx, HandleObject obj, double index, HandleValue v) MOZ_ASSERT(index >= 0); if (obj->is() && !obj->isIndexed() && index <= UINT32_MAX) { - DenseElementResult result = - SetOrExtendBoxedOrUnboxedDenseElements(cx, obj, uint32_t(index), v.address(), 1); + NativeObject* nobj = &obj->as(); + DenseElementResult result = nobj->setOrExtendDenseElements(cx, uint32_t(index), v.address(), 1); if (result != DenseElementResult::Incomplete) return result == DenseElementResult::Success; } @@ -1299,8 +1299,9 @@ InitArrayElements(JSContext* cx, HandleObject obj, uint32_t start, return false; if (!ObjectMayHaveExtraIndexedProperties(obj)) { - DenseElementResult result = - SetOrExtendBoxedOrUnboxedDenseElements(cx, obj, start, vector, count, updateTypes); + NativeObject* nobj = &obj->as(); + DenseElementResult result = nobj->setOrExtendDenseElements(cx, uint32_t(start), vector, + count, updateTypes); if (result != DenseElementResult::Incomplete) return result == DenseElementResult::Success; } @@ -2041,8 +2042,8 @@ js::array_push(JSContext* cx, unsigned argc, Value* vp) if (!ObjectMayHaveExtraIndexedProperties(obj)) { DenseElementResult result = - SetOrExtendBoxedOrUnboxedDenseElements(cx, obj, length, - args.array(), args.length()); + obj->as().setOrExtendDenseElements(cx, uint32_t(length), + args.array(), args.length()); if (result != DenseElementResult::Incomplete) { if (result == DenseElementResult::Failure) return false; @@ -3663,8 +3664,7 @@ js::NewCopiedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, if (!obj) return nullptr; - DenseElementResult result = - SetOrExtendBoxedOrUnboxedDenseElements(cx, obj, 0, vp, length, updateTypes); + DenseElementResult result = obj->setOrExtendDenseElements(cx->asJSContext(), 0, vp, length, updateTypes); if (result == DenseElementResult::Failure) return nullptr; MOZ_ASSERT(result == DenseElementResult::Success); diff --git a/js/src/jsarray.h b/js/src/jsarray.h index 1bee742ce..36cac743d 100644 --- a/js/src/jsarray.h +++ b/js/src/jsarray.h @@ -98,12 +98,6 @@ NewFullyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length, extern ArrayObject* NewPartlyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length, HandleObject proto); -enum class ShouldUpdateTypes -{ - Update, - DontUpdate -}; - extern ArrayObject* NewCopiedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, const Value* vp, size_t length, diff --git a/js/src/vm/NativeObject-inl.h b/js/src/vm/NativeObject-inl.h index 48a42a8db..052a3385c 100644 --- a/js/src/vm/NativeObject-inl.h +++ b/js/src/vm/NativeObject-inl.h @@ -235,6 +235,38 @@ NativeObject::ensureDenseElements(ExclusiveContext* cx, uint32_t index, uint32_t return DenseElementResult::Success; } +inline DenseElementResult +NativeObject::setOrExtendDenseElements(JSContext* cx, uint32_t start, const Value* vp, + uint32_t count, + ShouldUpdateTypes updateTypes) +{ + if (denseElementsAreFrozen()) + return DenseElementResult::Incomplete; + + if (is() && + !as().lengthIsWritable() && + start + count >= as().length()) + { + return DenseElementResult::Incomplete; + } + + DenseElementResult result = ensureDenseElements(cx, start, count); + if (result != DenseElementResult::Success) + return result; + + if (is() && start + count >= as().length()) + as().setLengthInt32(start + count); + + if (updateTypes == ShouldUpdateTypes::DontUpdate && !shouldConvertDoubleElements()) { + copyDenseElements(start, vp, count); + } else { + for (size_t i = 0; i < count; i++) + setDenseElementWithType(cx, start + i, vp[i]); + } + + return DenseElementResult::Success; +} + inline Value NativeObject::getDenseOrTypedArrayElement(uint32_t idx) { diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h index 4dbc167ab..4957a01d2 100644 --- a/js/src/vm/NativeObject.h +++ b/js/src/vm/NativeObject.h @@ -349,6 +349,11 @@ enum class DenseElementResult { Incomplete }; +enum class ShouldUpdateTypes { + Update, + DontUpdate +}; + /* * NativeObject specifies the internal implementation of a native object. * @@ -1147,6 +1152,10 @@ class NativeObject : public ShapedObject elementsRangeWriteBarrierPost(dstStart, count); } + inline DenseElementResult + setOrExtendDenseElements(JSContext* cx, uint32_t start, const Value* vp, uint32_t count, + ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update); + bool shouldConvertDoubleElements() { return getElementsHeader()->shouldConvertDoubleElements(); } diff --git a/js/src/vm/UnboxedObject-inl.h b/js/src/vm/UnboxedObject-inl.h index 193ca75c8..c1468a5b1 100644 --- a/js/src/vm/UnboxedObject-inl.h +++ b/js/src/vm/UnboxedObject-inl.h @@ -172,44 +172,6 @@ UnboxedPlainObject::layout() const return group()->unboxedLayout(); } -///////////////////////////////////////////////////////////////////// -// Template methods for NativeObject and UnboxedArrayObject accesses. -///////////////////////////////////////////////////////////////////// - -static inline DenseElementResult -SetOrExtendBoxedOrUnboxedDenseElements(ExclusiveContext* cx, JSObject* obj, - uint32_t start, const Value* vp, uint32_t count, - ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update) -{ - NativeObject* nobj = &obj->as(); - - if (nobj->denseElementsAreFrozen()) - return DenseElementResult::Incomplete; - - if (obj->is() && - !obj->as().lengthIsWritable() && - start + count >= obj->as().length()) - { - return DenseElementResult::Incomplete; - } - - DenseElementResult result = nobj->ensureDenseElements(cx, start, count); - if (result != DenseElementResult::Success) - return result; - - if (obj->is() && start + count >= obj->as().length()) - obj->as().setLengthInt32(start + count); - - if (updateTypes == ShouldUpdateTypes::DontUpdate && !nobj->shouldConvertDoubleElements()) { - nobj->copyDenseElements(start, vp, count); - } else { - for (size_t i = 0; i < count; i++) - nobj->setDenseElementWithType(cx, start + i, vp[i]); - } - - return DenseElementResult::Success; -} - } // namespace js #endif // vm_UnboxedObject_inl_h -- cgit v1.2.3 From e9aac71c6d7fa67c7581e2bd75accae5a9699165 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sun, 16 Jun 2019 19:55:05 +0000 Subject: Remove and clean up more code. --- js/src/jit/BaselineIC.cpp | 23 +++-------------------- js/src/jit/MIR.h | 10 +++++----- js/src/jsarray.cpp | 32 ++++++++++---------------------- js/src/jsarray.h | 2 -- js/src/vm/Interpreter.cpp | 5 +---- js/src/vm/ObjectGroup.cpp | 34 +++------------------------------- js/src/vm/TypeInference.cpp | 4 ++-- js/src/vm/TypeInference.h | 4 ++-- 8 files changed, 26 insertions(+), 88 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 17fdb1807..9151d9634 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -5365,13 +5365,6 @@ GetTemplateObjectForSimd(JSContext* cx, JSFunction* target, MutableHandleObject return true; } -static void -EnsureArrayGroupAnalyzed(JSContext* cx, JSObject* obj) -{ - if (PreliminaryObjectArrayWithTemplate* objects = obj->group()->maybePreliminaryObjects()) - objects->maybeAnalyze(cx, obj->group(), /* forceAnalyze = */ true); -} - static bool GetTemplateObjectForNative(JSContext* cx, HandleFunction target, const CallArgs& args, MutableHandleObject res, bool* skipAttach) @@ -5403,10 +5396,7 @@ GetTemplateObjectForNative(JSContext* cx, HandleFunction target, const CallArgs& // With this and other array templates, analyze the group so that // we don't end up with a template whose structure might change later. res.set(NewFullyAllocatedArrayForCallingAllocationSite(cx, count, TenuredObject)); - if (!res) - return false; - EnsureArrayGroupAnalyzed(cx, res); - return true; + return !!res; } } @@ -5432,10 +5422,7 @@ GetTemplateObjectForNative(JSContext* cx, HandleFunction target, const CallArgs& } res.set(NewFullyAllocatedArrayTryReuseGroup(cx, &args.thisv().toObject(), 0, TenuredObject)); - if (!res) - return false; - EnsureArrayGroupAnalyzed(cx, res); - return true; + return !!res; } } } @@ -5452,10 +5439,7 @@ GetTemplateObjectForNative(JSContext* cx, HandleFunction target, const CallArgs& } res.set(NewFullyAllocatedArrayForCallingAllocationSite(cx, 0, TenuredObject)); - if (!res) - return false; - EnsureArrayGroupAnalyzed(cx, res); - return true; + return !!res; } if (native == StringConstructor) { @@ -5768,7 +5752,6 @@ CopyArray(JSContext* cx, HandleArrayObject arr, MutableHandleValue result) ArrayObject* nobj = NewFullyAllocatedArrayTryReuseGroup(cx, arr, length, TenuredObject); if (!nobj) return false; - EnsureArrayGroupAnalyzed(cx, nobj); //XXX MOZ_ASSERT(arr->isNative()); MOZ_ASSERT(nobj->isNative()); diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index f316827dc..4bedfb268 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -9234,7 +9234,7 @@ class MLoadElement ALLOW_CLONE(MLoadElement) }; -// Load a value from the elements vector for a dense native or unboxed array. +// Load a value from the elements vector of a native object. // If the index is out-of-bounds, or the indexed slot has a hole, undefined is // returned instead. class MLoadElementHole @@ -9465,10 +9465,10 @@ class MStoreElement ALLOW_CLONE(MStoreElement) }; -// Like MStoreElement, but supports indexes >= initialized length, and can -// handle unboxed arrays. The downside is that we cannot hoist the elements -// vector and bounds check, since this instruction may update the (initialized) -// length and reallocate the elements vector. +// Like MStoreElement, but supports indexes >= initialized length. The downside +// is that we cannot hoist the elements vector and bounds check, since this +// instruction may update the (initialized) length and reallocate the elements +// vector. class MStoreElementHole : public MAryInstruction<4>, public MStoreElementCommon, diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index b77a5bce8..6129b2b65 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -2261,9 +2261,6 @@ js::array_unshift(JSContext* cx, unsigned argc, Value* vp) if (args.length() > 0) { /* Slide up the array to make room for all args at the bottom. */ if (length > 0) { - // Only include a fast path for boxed arrays. Unboxed arrays can'nt - // be optimized here because unshifting temporarily places holes at - // the start of the array. bool optimized = false; do { if (!obj->is()) @@ -2323,10 +2320,10 @@ js::array_unshift(JSContext* cx, unsigned argc, Value* vp) } /* - * Returns true if this is a dense or unboxed array whose |count| properties - * starting from |startingIndex| may be accessed (get, set, delete) directly - * through its contiguous vector of elements without fear of getters, setters, - * etc. along the prototype chain, or of enumerators requiring notification of + * Returns true if this is a dense array whose properties ending at |endIndex| + * (exclusive) may be accessed (get, set, delete) directly through its + * contiguous vector of elements without fear of getters, setters, etc. along + * the prototype chain, or of enumerators requiring notification of * modifications. */ static inline bool @@ -3550,10 +3547,10 @@ js::NewDenseCopyOnWriteArray(JSContext* cx, HandleArrayObject templateObject, gc return arr; } -// Return a new boxed or unboxed array with the specified length and allocated -// capacity (up to maxLength), using the specified group if possible. If the -// specified group cannot be used, ensure that the created array at least has -// the given [[Prototype]]. +// Return a new array with the specified length and allocated capacity (up to +// maxLength), using the specified group if possible. If the specified group +// cannot be used, ensure that the created array at least has the given +// [[Prototype]]. template static inline ArrayObject* NewArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length, @@ -3561,10 +3558,7 @@ NewArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length { MOZ_ASSERT(newKind != SingletonObject); - if (group->maybePreliminaryObjects()) - group->maybePreliminaryObjects()->maybeAnalyze(cx, group); - - if (group->shouldPreTenure() || group->maybePreliminaryObjects()) + if (group->shouldPreTenure()) newKind = TenuredObject; RootedObject proto(cx, group->proto().toObject()); @@ -3579,9 +3573,6 @@ NewArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length if (res->length() > INT32_MAX) res->setLength(cx, res->length()); - if (PreliminaryObjectArray* preliminaryObjects = group->maybePreliminaryObjects()) - preliminaryObjects->registerNewObject(res); - return res; } @@ -3601,10 +3592,7 @@ js::NewPartlyAllocatedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup g // Return a new array with the default prototype and specified allocated // capacity and length. If possible, try to reuse the group of the input // object. The resulting array will either reuse the input object's group or -// will have unknown property types. Additionally, the result will have the -// same boxed/unboxed elements representation as the input object, unless -// |length| is larger than the input object's initialized length (in which case -// UnboxedArrayObject::MaximumCapacity might be exceeded). +// will have unknown property types. template static inline ArrayObject* NewArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length, diff --git a/js/src/jsarray.h b/js/src/jsarray.h index 36cac743d..f9e11149f 100644 --- a/js/src/jsarray.h +++ b/js/src/jsarray.h @@ -75,8 +75,6 @@ NewDenseFullyAllocatedArrayWithTemplate(JSContext* cx, uint32_t length, JSObject extern ArrayObject* NewDenseCopyOnWriteArray(JSContext* cx, HandleArrayObject templateObject, gc::InitialHeap heap); -// The methods below can create either boxed or unboxed arrays. - extern ArrayObject* NewFullyAllocatedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length, NewObjectKind newKind = GenericObject); diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 7d05b2d4c..f4f6c0da4 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -4933,7 +4933,7 @@ js::NewObjectOperation(JSContext* cx, HandleScript script, jsbytecode* pc, newKind = TenuredObject; } - RootedObject obj(cx); + RootedPlainObject obj(cx); if (*pc == JSOP_NEWOBJECT) { RootedPlainObject baseObject(cx, &script->getObject(pc)->as()); @@ -5011,9 +5011,6 @@ js::NewArrayOperation(JSContext* cx, HandleScript script, jsbytecode* pc, uint32 MOZ_ASSERT(obj->isSingleton()); } else { obj->setGroup(group); - - if (PreliminaryObjectArray* preliminaryObjects = group->maybePreliminaryObjects()) - preliminaryObjects->registerNewObject(obj); } return obj; diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp index 6b984a803..63ac33eea 100644 --- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -838,17 +838,6 @@ ObjectGroup::newArrayObject(ExclusiveContext* cx, AddTypePropertyId(cx, group, nullptr, JSID_VOID, elementType); - if (elementType != TypeSet::UnknownType()) { - // Keep track of the initial objects we create with this type. - // If the initial ones have a consistent shape and property types, we - // will try to use an unboxed layout for the group. - PreliminaryObjectArrayWithTemplate* preliminaryObjects = - cx->new_(nullptr); - if (!preliminaryObjects) - return nullptr; - group->setPreliminaryObjects(preliminaryObjects); - } - if (!p.add(cx, *table, ObjectGroupCompartment::ArrayObjectKey(elementType), group)) return nullptr; } @@ -856,9 +845,6 @@ ObjectGroup::newArrayObject(ExclusiveContext* cx, // The type of the elements being added will already be reflected in type // information. ShouldUpdateTypes updateTypes = ShouldUpdateTypes::DontUpdate; - if (group->maybePreliminaryObjects()) - group->maybePreliminaryObjects()->maybeAnalyze(cx, group); - return NewCopiedArrayTryUseGroup(cx, group, vp, length, newKind, updateTypes); } @@ -868,27 +854,13 @@ GiveObjectGroup(ExclusiveContext* cx, JSObject* source, JSObject* target) { MOZ_ASSERT(source->group() != target->group()); - if (!target->is()) + if (!target->is() || !source->is()) { return true; - - if (target->group()->maybePreliminaryObjects()) { - bool force = IsInsideNursery(source); - target->group()->maybePreliminaryObjects()->maybeAnalyze(cx, target->group(), force); } - ObjectGroup* sourceGroup = source->group(); - - if (source->is()) { - source->setGroup(target->group()); - } else { - return true; - } + source->setGroup(target->group()); - if (sourceGroup->maybePreliminaryObjects()) - sourceGroup->maybePreliminaryObjects()->unregisterObject(source); - if (target->group()->maybePreliminaryObjects()) - target->group()->maybePreliminaryObjects()->registerNewObject(source); - for (size_t i = 0; i < source->as().getDenseInitializedLength(); i++) { + for (size_t i = 0; i < source->as().getDenseInitializedLength(); i++) { Value v = source->as().getDenseElement(i); AddTypePropertyId(cx, source->group(), source, JSID_VOID, v); } diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index 2160dbc51..0551e2c58 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -3393,7 +3393,7 @@ JSFunction::setTypeForScriptedFunction(ExclusiveContext* cx, HandleFunction fun, ///////////////////////////////////////////////////////////////////// void -PreliminaryObjectArray::registerNewObject(JSObject* res) +PreliminaryObjectArray::registerNewObject(PlainObject* res) { // The preliminary object pointers are weak, and won't be swept properly // during nursery collections, so the preliminary objects need to be @@ -3411,7 +3411,7 @@ PreliminaryObjectArray::registerNewObject(JSObject* res) } void -PreliminaryObjectArray::unregisterObject(JSObject* obj) +PreliminaryObjectArray::unregisterObject(PlainObject* obj) { for (size_t i = 0; i < COUNT; i++) { if (objects[i] == obj) { diff --git a/js/src/vm/TypeInference.h b/js/src/vm/TypeInference.h index 04fed448c..94ce7e871 100644 --- a/js/src/vm/TypeInference.h +++ b/js/src/vm/TypeInference.h @@ -814,8 +814,8 @@ class PreliminaryObjectArray public: PreliminaryObjectArray() = default; - void registerNewObject(JSObject* res); - void unregisterObject(JSObject* obj); + void registerNewObject(PlainObject* res); + void unregisterObject(PlainObject* obj); JSObject* get(size_t i) const { MOZ_ASSERT(i < COUNT); -- cgit v1.2.3 From 625366321008cc464f4295db80c48dd5a19f3ee4 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sun, 16 Jun 2019 20:06:39 +0000 Subject: Update comment --- js/src/vm/NativeObject.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'js/src') diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h index 4957a01d2..da4f873a6 100644 --- a/js/src/vm/NativeObject.h +++ b/js/src/vm/NativeObject.h @@ -339,10 +339,8 @@ IsObjectValueInCompartment(const Value& v, JSCompartment* comp); #endif // Operations which change an object's dense elements can either succeed, fail, -// or be unable to complete. For native objects, the latter is used when the -// object's elements must become sparse instead. The enum below is used for -// such operations, and for similar operations on unboxed arrays and methods -// that work on both kinds of objects. +// or be unable to complete. The latter is used when the object's elements must +// become sparse instead. The enum below is used for such operations. enum class DenseElementResult { Failure, Success, -- cgit v1.2.3 From 772cd4b188fd9f30521d4983f60363f4a830e2aa Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sun, 16 Jun 2019 23:13:47 +0000 Subject: Remove JSOP_SPREADCALLARRAY and just use JSOP_NEWARRAY again. --- js/src/frontend/BytecodeEmitter.cpp | 9 ++++----- js/src/frontend/BytecodeEmitter.h | 2 +- js/src/jit/BaselineCompiler.cpp | 6 ------ js/src/jit/BaselineCompiler.h | 1 - js/src/jit/IonBuilder.cpp | 2 ++ js/src/vm/Interpreter.cpp | 2 +- js/src/vm/Opcodes.h | 12 +----------- 7 files changed, 9 insertions(+), 25 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index ea6baeec7..7f9fa8a5d 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -9192,7 +9192,7 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn) return false; } - if (!emitArray(args, argc, JSOP_SPREADCALLARRAY)) + if (!emitArray(args, argc)) return false; if (optCodeEmitted) { @@ -9683,11 +9683,11 @@ BytecodeEmitter::emitArrayLiteral(ParseNode* pn) } } - return emitArray(pn->pn_head, pn->pn_count, JSOP_NEWARRAY); + return emitArray(pn->pn_head, pn->pn_count); } bool -BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count, JSOp op) +BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count) { /* @@ -9698,7 +9698,6 @@ BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count, JSOp op) * to avoid dup'ing and popping the array as each element is added, as * JSOP_SETELEM/JSOP_SETPROP would do. */ - MOZ_ASSERT(op == JSOP_NEWARRAY || op == JSOP_SPREADCALLARRAY); uint32_t nspread = 0; for (ParseNode* elt = pn; elt; elt = elt->pn_next) { @@ -9719,7 +9718,7 @@ BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count, JSOp op) // For arrays with spread, this is a very pessimistic allocation, the // minimum possible final size. - if (!emitUint32Operand(op, count - nspread)) // ARRAY + if (!emitUint32Operand(JSOP_NEWARRAY, count - nspread)) // ARRAY return false; ParseNode* pn2 = pn; diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index 814fa11d4..29050c846 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -521,7 +521,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter MOZ_MUST_USE bool emitAtomOp(ParseNode* pn, JSOp op); MOZ_MUST_USE bool emitArrayLiteral(ParseNode* pn); - MOZ_MUST_USE bool emitArray(ParseNode* pn, uint32_t count, JSOp op); + MOZ_MUST_USE bool emitArray(ParseNode* pn, uint32_t count); MOZ_MUST_USE bool emitArrayComp(ParseNode* pn); MOZ_MUST_USE bool emitInternedScopeOp(uint32_t index, JSOp op); diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index 93e3759b9..6b64bfb44 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -2049,12 +2049,6 @@ BaselineCompiler::emit_JSOP_NEWARRAY() return true; } -bool -BaselineCompiler::emit_JSOP_SPREADCALLARRAY() -{ - return emit_JSOP_NEWARRAY(); -} - typedef ArrayObject* (*NewArrayCopyOnWriteFn)(JSContext*, HandleArrayObject, gc::InitialHeap); const VMFunction jit::NewArrayCopyOnWriteInfo = FunctionInfo(js::NewDenseCopyOnWriteArray, "NewDenseCopyOnWriteArray"); diff --git a/js/src/jit/BaselineCompiler.h b/js/src/jit/BaselineCompiler.h index 6b5bf009e..910a52980 100644 --- a/js/src/jit/BaselineCompiler.h +++ b/js/src/jit/BaselineCompiler.h @@ -100,7 +100,6 @@ namespace jit { _(JSOP_BITNOT) \ _(JSOP_NEG) \ _(JSOP_NEWARRAY) \ - _(JSOP_SPREADCALLARRAY) \ _(JSOP_NEWARRAY_COPYONWRITE) \ _(JSOP_INITELEM_ARRAY) \ _(JSOP_NEWOBJECT) \ diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 3d964d1c6..fc864a197 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -2218,6 +2218,8 @@ IonBuilder::inspectOpcode(JSOp op) // update that stale value. #endif default: + // Any unused opcodes and JSOP_LIMIT will end up here without having + // to explicitly specify break; } diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index f4f6c0da4..74a1ef3e9 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -1916,6 +1916,7 @@ CASE(EnableInterruptsPseudoOpcode) /* Various 1-byte no-ops. */ CASE(JSOP_NOP) CASE(JSOP_NOP_DESTRUCTURING) +CASE(JSOP_UNUSED126) CASE(JSOP_UNUSED192) CASE(JSOP_UNUSED209) CASE(JSOP_UNUSED210) @@ -3636,7 +3637,6 @@ CASE(JSOP_NEWINIT) END_CASE(JSOP_NEWINIT) CASE(JSOP_NEWARRAY) -CASE(JSOP_SPREADCALLARRAY) { uint32_t length = GET_UINT32(REGS.pc); JSObject* obj = NewArrayOperation(cx, script, REGS.pc, length); diff --git a/js/src/vm/Opcodes.h b/js/src/vm/Opcodes.h index 4b044c8d8..095ef57ae 100644 --- a/js/src/vm/Opcodes.h +++ b/js/src/vm/Opcodes.h @@ -1281,17 +1281,7 @@ * Stack: receiver, obj, propval => obj[propval] */ \ macro(JSOP_GETELEM_SUPER, 125, "getelem-super", NULL, 1, 3, 1, JOF_BYTE |JOF_ELEM|JOF_LEFTASSOC) \ - /* - * Pushes newly created array for a spread call onto the stack. This has - * the same semantics as JSOP_NEWARRAY, but is distinguished to avoid - * using unboxed arrays in spread calls, which would make compiling spread - * calls in baseline more complex. - * Category: Literals - * Type: Array - * Operands: uint32_t length - * Stack: => obj - */ \ - macro(JSOP_SPREADCALLARRAY, 126, "spreadcallarray", NULL, 5, 0, 1, JOF_UINT32) \ + macro(JSOP_UNUSED126, 126, "unused126", NULL, 5, 0, 1, JOF_UINT32) \ \ /* * Defines the given function on the current scope. -- cgit v1.2.3 From ccb3f2b730992b65ce404e8c6fbdc297485413ac Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sun, 16 Jun 2019 23:17:34 +0000 Subject: Remove/inline CanonicalizeArrayLengthValue. --- js/src/jsarray.cpp | 36 ++++++++++++++---------------------- js/src/jsarray.h | 7 ------- 2 files changed, 14 insertions(+), 29 deletions(-) (limited to 'js/src') diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 6129b2b65..a33735143 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -511,24 +511,6 @@ struct ReverseIndexComparator } }; -bool -js::CanonicalizeArrayLengthValue(JSContext* cx, HandleValue v, uint32_t* newLen) -{ - double d; - - if (!ToUint32(cx, v, newLen)) - return false; - - if (!ToNumber(cx, v, &d)) - return false; - - if (d == *newLen) - return true; - - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH); - return false; -} - /* ES6 draft rev 34 (2015 Feb 20) 9.4.2.4 ArraySetLength */ bool js::ArraySetLength(JSContext* cx, Handle arr, HandleId id, @@ -550,12 +532,22 @@ js::ArraySetLength(JSContext* cx, Handle arr, HandleId id, } else { // Step 2 is irrelevant in our implementation. - // Steps 3-7. - MOZ_ASSERT_IF(attrs & JSPROP_IGNORE_VALUE, value.isUndefined()); - if (!CanonicalizeArrayLengthValue(cx, value, &newLen)) + // Step 3. + if (!ToUint32(cx, value, &newLen)) + return false; + + // Step 4. + double d; + if (!ToNumber(cx, value, &d)) return false; - // Step 8 is irrelevant in our implementation. + // Step 5. + if (d != newLen) { + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH); + return false; + } + + // Steps 6-8 are irrelevant in our implementation. } // Steps 9-11. diff --git a/js/src/jsarray.h b/js/src/jsarray.h index f9e11149f..ec2e4f514 100644 --- a/js/src/jsarray.h +++ b/js/src/jsarray.h @@ -117,13 +117,6 @@ NewValuePair(JSContext* cx, const Value& val1, const Value& val2, MutableHandleV extern bool WouldDefinePastNonwritableLength(HandleNativeObject obj, uint32_t index); -/* - * Canonicalize |vp| to a uint32_t value potentially suitable for use as an - * array length. - */ -extern bool -CanonicalizeArrayLengthValue(JSContext* cx, HandleValue v, uint32_t* canonicalized); - extern bool GetLengthProperty(JSContext* cx, HandleObject obj, uint32_t* lengthp); -- cgit v1.2.3 From fcc11b2fec61c37c90ffe40e8f406eba64654a9c Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Tue, 18 Jun 2019 12:59:22 +0000 Subject: Tabs -> Spaces (no code change) --- js/src/jit/BaselineIC.cpp | 4 ++-- js/src/jsarray.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 9151d9634..64cdf01a6 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -5752,7 +5752,7 @@ CopyArray(JSContext* cx, HandleArrayObject arr, MutableHandleValue result) ArrayObject* nobj = NewFullyAllocatedArrayTryReuseGroup(cx, arr, length, TenuredObject); if (!nobj) return false; - + MOZ_ASSERT(arr->isNative()); MOZ_ASSERT(nobj->isNative()); MOZ_ASSERT(nobj->as().getDenseInitializedLength() == 0); @@ -5763,7 +5763,7 @@ CopyArray(JSContext* cx, HandleArrayObject arr, MutableHandleValue result) const Value* vp = arr->as().getDenseElements(); nobj->as().initDenseElements(0, vp, length); - + result.setObject(*nobj); return true; } diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index a33735143..5854fda4c 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -2480,8 +2480,8 @@ js::array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueI /* Steps 10-11. */ DebugOnly result = CopyDenseElements(cx, &arr->as(), - &obj->as(), 0, - actualStart, actualDeleteCount); + &obj->as(), 0, + actualStart, actualDeleteCount); MOZ_ASSERT(result.value == DenseElementResult::Success); /* Step 12 (implicit). */ -- cgit v1.2.3 From 32d13a1648a64fe26be66de026bffca8c1afa88f Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 20 Jun 2019 12:56:32 +0200 Subject: Call a more generic function when inlining array natives. This simplifies the code a bit because ElementAccessHasExtraIndexedProperty checks for length-overflow (directly) and sparse-indexes (through TypeCanHaveExtraIndexedProperties) so the callers don't have to do that anymore. --- js/src/jit/MCallOptimize.cpp | 21 +++++---------------- js/src/jit/MIR.cpp | 9 --------- js/src/jit/MIR.h | 1 - 3 files changed, 5 insertions(+), 26 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 0d5779cee..fed5aefe5 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -621,7 +621,8 @@ IonBuilder::inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode) return InliningStatus_NotInlined; } - if (ArrayPrototypeHasIndexedProperty(this, script())) { + // Watch out for extra indexed properties on the object or its prototype. + if (ElementAccessHasExtraIndexedProperty(this, obj)) { trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps); return InliningStatus_NotInlined; } @@ -748,14 +749,8 @@ IonBuilder::inlineArrayPush(CallInfo& callInfo) const Class* clasp = thisTypes->getKnownClass(constraints()); if (clasp != &ArrayObject::class_) return InliningStatus_NotInlined; - if (thisTypes->hasObjectFlags(constraints(), OBJECT_FLAG_SPARSE_INDEXES | - OBJECT_FLAG_LENGTH_OVERFLOW)) - { - trackOptimizationOutcome(TrackedOutcome::ArrayBadFlags); - return InliningStatus_NotInlined; - } - if (ArrayPrototypeHasIndexedProperty(this, script())) { + if (ElementAccessHasExtraIndexedProperty(this, obj)) { trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps); return InliningStatus_NotInlined; } @@ -825,15 +820,9 @@ IonBuilder::inlineArraySlice(CallInfo& callInfo) const Class* clasp = thisTypes->getKnownClass(constraints()); if (clasp != &ArrayObject::class_) return InliningStatus_NotInlined; - if (thisTypes->hasObjectFlags(constraints(), OBJECT_FLAG_SPARSE_INDEXES | - OBJECT_FLAG_LENGTH_OVERFLOW)) - { - trackOptimizationOutcome(TrackedOutcome::ArrayBadFlags); - return InliningStatus_NotInlined; - } - // Watch out for indexed properties on the prototype. - if (ArrayPrototypeHasIndexedProperty(this, script())) { + // Watch out for indexed properties on the object or its prototype. + if (ElementAccessHasExtraIndexedProperty(this, obj)) { trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps); return InliningStatus_NotInlined; } diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 6aa46be4b..190b40bb2 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -6221,15 +6221,6 @@ PrototypeHasIndexedProperty(IonBuilder* builder, JSObject* obj) return false; } -// Whether Array.prototype, or an object on its proto chain, has an indexed property. -bool -jit::ArrayPrototypeHasIndexedProperty(IonBuilder* builder, JSScript* script) -{ - if (JSObject* proto = script->global().maybeGetArrayPrototype()) - return PrototypeHasIndexedProperty(builder, proto); - return true; -} - // Whether obj or any of its prototypes have an indexed property. bool jit::TypeCanHaveExtraIndexedProperties(IonBuilder* builder, TemporaryTypeSet* types) diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 4bedfb268..6526e0931 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -14054,7 +14054,6 @@ bool PropertyWriteNeedsTypeBarrier(TempAllocator& alloc, CompilerConstraintList* MBasicBlock* current, MDefinition** pobj, PropertyName* name, MDefinition** pvalue, bool canModify, MIRType implicitType = MIRType::None); -bool ArrayPrototypeHasIndexedProperty(IonBuilder* builder, JSScript* script); bool TypeCanHaveExtraIndexedProperties(IonBuilder* builder, TemporaryTypeSet* types); inline MIRType -- cgit v1.2.3 From 6cebf2549e9c7b9eea978332e58b55589da6274f Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sun, 23 Jun 2019 19:41:16 +0000 Subject: Remove Unboxed Object code from jit, Part 2. --- js/src/jit/BaselineCacheIR.cpp | 52 +------- js/src/jit/BaselineIC.cpp | 114 ----------------- js/src/jit/BaselineInspector.cpp | 46 +------ js/src/jit/CacheIR.cpp | 72 +---------- js/src/jit/CacheIR.h | 20 --- js/src/jit/IonCaches.cpp | 262 -------------------------------------- js/src/jit/IonCaches.h | 12 -- js/src/jit/MacroAssembler.cpp | 264 --------------------------------------- js/src/jit/MacroAssembler.h | 14 --- js/src/vm/UnboxedObject.cpp | 201 +---------------------------- 10 files changed, 9 insertions(+), 1048 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/BaselineCacheIR.cpp b/js/src/jit/BaselineCacheIR.cpp index 7fb586811..67c80473b 100644 --- a/js/src/jit/BaselineCacheIR.cpp +++ b/js/src/jit/BaselineCacheIR.cpp @@ -16,7 +16,7 @@ using namespace js; using namespace js::jit; // OperandLocation represents the location of an OperandId. The operand is -// either in a register or on the stack, and is either boxed or unboxed. +// either in a register or on the stack. class OperandLocation { public: @@ -814,36 +814,6 @@ BaselineCacheIRCompiler::emitGuardSpecificObject() return true; } -bool -BaselineCacheIRCompiler::emitGuardNoUnboxedExpando() -{ - Register obj = allocator.useRegister(masm, reader.objOperandId()); - - FailurePath* failure; - if (!addFailurePath(&failure)) - return false; - - Address expandoAddr(obj, UnboxedPlainObject::offsetOfExpando()); - masm.branchPtr(Assembler::NotEqual, expandoAddr, ImmWord(0), failure->label()); - return true; -} - -bool -BaselineCacheIRCompiler::emitGuardAndLoadUnboxedExpando() -{ - Register obj = allocator.useRegister(masm, reader.objOperandId()); - Register output = allocator.defineRegister(masm, reader.objOperandId()); - - FailurePath* failure; - if (!addFailurePath(&failure)) - return false; - - Address expandoAddr(obj, UnboxedPlainObject::offsetOfExpando()); - masm.loadPtr(expandoAddr, output); - masm.branchTestPtr(Assembler::Zero, output, output, failure->label()); - return true; -} - bool BaselineCacheIRCompiler::emitLoadFixedSlotResult() { @@ -870,26 +840,6 @@ BaselineCacheIRCompiler::emitLoadDynamicSlotResult() return true; } -bool -BaselineCacheIRCompiler::emitLoadUnboxedPropertyResult() -{ - Register obj = allocator.useRegister(masm, reader.objOperandId()); - AutoScratchRegister scratch(allocator, masm); - - JSValueType fieldType = reader.valueType(); - - Address fieldOffset(stubAddress(reader.stubOffset())); - masm.load32(fieldOffset, scratch); - masm.loadUnboxedProperty(BaseIndex(obj, scratch, TimesOne), fieldType, R0); - - if (fieldType == JSVAL_TYPE_OBJECT) - emitEnterTypeMonitorIC(); - else - emitReturnFromIC(); - - return true; -} - bool BaselineCacheIRCompiler::emitGuardNoDetachedTypedObjects() { diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 64cdf01a6..ba855dac9 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -1920,13 +1920,6 @@ ICGetElemNativeCompiler::generateStubCode(MacroAssembler& masm) if (popR1) masm.addToStackPtr(ImmWord(sizeof(size_t))); - } else if (acctype_ == ICGetElemNativeStub::UnboxedProperty) { - masm.load32(Address(ICStubReg, ICGetElemNativeSlotStub::offsetOfOffset()), - scratchReg); - masm.loadUnboxedProperty(BaseIndex(objReg, scratchReg, TimesOne), unboxedType_, - TypedOrValueRegister(R0)); - if (popR1) - masm.addToStackPtr(ImmWord(sizeof(size_t))); } else { MOZ_ASSERT(acctype_ == ICGetElemNativeStub::NativeGetter || acctype_ == ICGetElemNativeStub::ScriptedGetter); @@ -4292,40 +4285,6 @@ TryAttachSetAccessorPropStub(JSContext* cx, HandleScript script, jsbytecode* pc, return true; } -static bool -TryAttachUnboxedSetPropStub(JSContext* cx, HandleScript script, - ICSetProp_Fallback* stub, HandleId id, - HandleObject obj, HandleValue rhs, bool* attached) -{ - MOZ_ASSERT(!*attached); - - if (!cx->runtime()->jitSupportsFloatingPoint) - return true; - - if (!obj->is()) - return true; - - const UnboxedLayout::Property* property = obj->as().layout().lookup(id); - if (!property) - return true; - - ICSetProp_Unboxed::Compiler compiler(cx, obj->group(), - property->offset + UnboxedPlainObject::offsetOfData(), - property->type); - ICUpdatedStub* newStub = compiler.getStub(compiler.getStubSpace(script)); - if (!newStub) - return false; - if (compiler.needsUpdateStubs() && !newStub->addUpdateStubForValue(cx, script, obj, id, rhs)) - return false; - - stub->addNewStub(newStub); - - StripPreliminaryObjectStubs(cx, stub); - - *attached = true; - return true; -} - static bool TryAttachTypedObjectSetPropStub(JSContext* cx, HandleScript script, ICSetProp_Fallback* stub, HandleId id, @@ -4485,15 +4444,6 @@ DoSetPropFallback(JSContext* cx, BaselineFrame* frame, ICSetProp_Fallback* stub_ if (attached) return true; - if (!attached && - lhs.isObject() && - !TryAttachUnboxedSetPropStub(cx, script, stub, id, obj, rhs, &attached)) - { - return false; - } - if (attached) - return true; - if (!attached && lhs.isObject() && !TryAttachTypedObjectSetPropStub(cx, script, stub, id, obj, rhs, &attached)) @@ -4828,70 +4778,6 @@ ICSetPropNativeAddCompiler::generateStubCode(MacroAssembler& masm) return true; } -bool -ICSetProp_Unboxed::Compiler::generateStubCode(MacroAssembler& masm) -{ - MOZ_ASSERT(engine_ == Engine::Baseline); - - Label failure; - - // Guard input is an object. - masm.branchTestObject(Assembler::NotEqual, R0, &failure); - - AllocatableGeneralRegisterSet regs(availableGeneralRegs(2)); - Register scratch = regs.takeAny(); - - // Unbox and group guard. - Register object = masm.extractObject(R0, ExtractTemp0); - masm.loadPtr(Address(ICStubReg, ICSetProp_Unboxed::offsetOfGroup()), scratch); - masm.branchPtr(Assembler::NotEqual, Address(object, JSObject::offsetOfGroup()), scratch, - &failure); - - if (needsUpdateStubs()) { - // Stow both R0 and R1 (object and value). - EmitStowICValues(masm, 2); - - // Move RHS into R0 for TypeUpdate check. - masm.moveValue(R1, R0); - - // Call the type update stub. - if (!callTypeUpdateIC(masm, sizeof(Value))) - return false; - - // Unstow R0 and R1 (object and key) - EmitUnstowICValues(masm, 2); - - // The TypeUpdate IC may have smashed object. Rederive it. - masm.unboxObject(R0, object); - - // Trigger post barriers here on the values being written. Fields which - // objects can be written to also need update stubs. - LiveGeneralRegisterSet saveRegs; - saveRegs.add(R0); - saveRegs.add(R1); - saveRegs.addUnchecked(object); - saveRegs.add(ICStubReg); - emitPostWriteBarrierSlot(masm, object, R1, scratch, saveRegs); - } - - // Compute the address being written to. - masm.load32(Address(ICStubReg, ICSetProp_Unboxed::offsetOfFieldOffset()), scratch); - BaseIndex address(object, scratch, TimesOne); - - EmitUnboxedPreBarrierForBaseline(masm, address, fieldType_); - masm.storeUnboxedProperty(address, fieldType_, - ConstantOrRegister(TypedOrValueRegister(R1)), &failure); - - // The RHS has to be in R0. - masm.moveValue(R1, R0); - - EmitReturnFromIC(masm); - - masm.bind(&failure); - EmitStubGuardFailure(masm); - return true; -} - bool ICSetProp_TypedObject::Compiler::generateStubCode(MacroAssembler& masm) { diff --git a/js/src/jit/BaselineInspector.cpp b/js/src/jit/BaselineInspector.cpp index bcb527516..3b852debf 100644 --- a/js/src/jit/BaselineInspector.cpp +++ b/js/src/jit/BaselineInspector.cpp @@ -104,19 +104,11 @@ AddReceiver(const ReceiverGuard& receiver, static bool GetCacheIRReceiverForNativeReadSlot(ICCacheIR_Monitored* stub, ReceiverGuard* receiver) { - // We match either: + // We match: // // GuardIsObject 0 // GuardShape 0 // LoadFixedSlotResult 0 or LoadDynamicSlotResult 0 - // - // or - // - // GuardIsObject 0 - // GuardGroup 0 - // 1: GuardAndLoadUnboxedExpando 0 - // GuardShape 1 - // LoadFixedSlotResult 1 or LoadDynamicSlotResult 1 *receiver = ReceiverGuard(); CacheIRReader reader(stub->stubInfo()); @@ -125,14 +117,6 @@ GetCacheIRReceiverForNativeReadSlot(ICCacheIR_Monitored* stub, ReceiverGuard* re if (!reader.matchOp(CacheOp::GuardIsObject, objId)) return false; - if (reader.matchOp(CacheOp::GuardGroup, objId)) { - receiver->group = stub->stubInfo()->getStubField(stub, reader.stubOffset()); - - if (!reader.matchOp(CacheOp::GuardAndLoadUnboxedExpando, objId)) - return false; - objId = reader.objOperandId(); - } - if (reader.matchOp(CacheOp::GuardShape, objId)) { receiver->shape = stub->stubInfo()->getStubField(stub, reader.stubOffset()); return reader.matchOpEither(CacheOp::LoadFixedSlotResult, CacheOp::LoadDynamicSlotResult); @@ -141,29 +125,6 @@ GetCacheIRReceiverForNativeReadSlot(ICCacheIR_Monitored* stub, ReceiverGuard* re return false; } -static bool -GetCacheIRReceiverForUnboxedProperty(ICCacheIR_Monitored* stub, ReceiverGuard* receiver) -{ - // We match: - // - // GuardIsObject 0 - // GuardGroup 0 - // LoadUnboxedPropertyResult 0 .. - - *receiver = ReceiverGuard(); - CacheIRReader reader(stub->stubInfo()); - - ObjOperandId objId = ObjOperandId(0); - if (!reader.matchOp(CacheOp::GuardIsObject, objId)) - return false; - - if (!reader.matchOp(CacheOp::GuardGroup, objId)) - return false; - receiver->group = stub->stubInfo()->getStubField(stub, reader.stubOffset()); - - return reader.matchOp(CacheOp::LoadUnboxedPropertyResult, objId); -} - bool BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receivers) { @@ -182,8 +143,7 @@ BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receiv while (stub->next()) { ReceiverGuard receiver; if (stub->isCacheIR_Monitored()) { - if (!GetCacheIRReceiverForNativeReadSlot(stub->toCacheIR_Monitored(), &receiver) && - !GetCacheIRReceiverForUnboxedProperty(stub->toCacheIR_Monitored(), &receiver)) + if (!GetCacheIRReceiverForNativeReadSlot(stub->toCacheIR_Monitored(), &receiver)) { receivers.clear(); return true; @@ -191,8 +151,6 @@ BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receiv } else if (stub->isSetProp_Native()) { receiver = ReceiverGuard(stub->toSetProp_Native()->group(), stub->toSetProp_Native()->shape()); - } else if (stub->isSetProp_Unboxed()) { - receiver = ReceiverGuard(stub->toSetProp_Unboxed()->group(), nullptr); } else { receivers.clear(); return true; diff --git a/js/src/jit/CacheIR.cpp b/js/src/jit/CacheIR.cpp index 6822a70af..d184ea40c 100644 --- a/js/src/jit/CacheIR.cpp +++ b/js/src/jit/CacheIR.cpp @@ -10,8 +10,7 @@ #include "jit/IonCaches.h" #include "jsobjinlines.h" - -#include "vm/UnboxedObject-inl.h" +#include "vm/NativeObject-inl.h" using namespace js; using namespace js::jit; @@ -60,10 +59,6 @@ GetPropIRGenerator::tryAttachStub(Maybe& writer) return false; if (!emitted_ && !tryAttachNative(*writer, obj, objId)) return false; - if (!emitted_ && !tryAttachUnboxed(*writer, obj, objId)) - return false; - if (!emitted_ && !tryAttachUnboxedExpando(*writer, obj, objId)) - return false; if (!emitted_ && !tryAttachTypedObject(*writer, obj, objId)) return false; if (!emitted_ && !tryAttachModuleNamespace(*writer, obj, objId)) @@ -163,19 +158,9 @@ GeneratePrototypeGuards(CacheIRWriter& writer, JSObject* obj, JSObject* holder, } static void -TestMatchingReceiver(CacheIRWriter& writer, JSObject* obj, Shape* shape, ObjOperandId objId, - Maybe* expandoId) +TestMatchingReceiver(CacheIRWriter& writer, JSObject* obj, Shape* shape, ObjOperandId objId) { - if (obj->is()) { - writer.guardGroup(objId, obj->group()); - - if (UnboxedExpandoObject* expando = obj->as().maybeExpando()) { - expandoId->emplace(writer.guardAndLoadUnboxedExpando(objId)); - writer.guardShape(expandoId->ref(), expando->lastProperty()); - } else { - writer.guardNoUnboxedExpando(objId); - } - } else if (obj->is()) { + if (obj->is()) { writer.guardGroup(objId, obj->group()); } else { Shape* shape = obj->maybeShape(); @@ -188,8 +173,7 @@ static void EmitReadSlotResult(CacheIRWriter& writer, JSObject* obj, JSObject* holder, Shape* shape, ObjOperandId objId) { - Maybe expandoId; - TestMatchingReceiver(writer, obj, shape, objId, &expandoId); + TestMatchingReceiver(writer, obj, shape, objId); ObjOperandId holderId; if (obj != holder) { @@ -212,9 +196,6 @@ EmitReadSlotResult(CacheIRWriter& writer, JSObject* obj, JSObject* holder, lastObjId = protoId; } } - } else if (obj->is()) { - holder = obj->as().maybeExpando(); - holderId = *expandoId; } else { holderId = objId; } @@ -265,51 +246,6 @@ GetPropIRGenerator::tryAttachNative(CacheIRWriter& writer, HandleObject obj, Obj return true; } -bool -GetPropIRGenerator::tryAttachUnboxed(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId) -{ - MOZ_ASSERT(!emitted_); - - if (!obj->is()) - return true; - - const UnboxedLayout::Property* property = obj->as().layout().lookup(name_); - if (!property) - return true; - - if (!cx_->runtime()->jitSupportsFloatingPoint) - return true; - - writer.guardGroup(objId, obj->group()); - writer.loadUnboxedPropertyResult(objId, property->type, - UnboxedPlainObject::offsetOfData() + property->offset); - emitted_ = true; - preliminaryObjectAction_ = PreliminaryObjectAction::Unlink; - return true; -} - -bool -GetPropIRGenerator::tryAttachUnboxedExpando(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId) -{ - MOZ_ASSERT(!emitted_); - - if (!obj->is()) - return true; - - UnboxedExpandoObject* expando = obj->as().maybeExpando(); - if (!expando) - return true; - - Shape* shape = expando->lookup(cx_, NameToId(name_)); - if (!shape || !shape->hasDefaultGetter() || !shape->hasSlot()) - return true; - - emitted_ = true; - - EmitReadSlotResult(writer, obj, obj, shape, objId); - return true; -} - bool GetPropIRGenerator::tryAttachTypedObject(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId) { diff --git a/js/src/jit/CacheIR.h b/js/src/jit/CacheIR.h index 4fd8575f0..ae55cfebb 100644 --- a/js/src/jit/CacheIR.h +++ b/js/src/jit/CacheIR.h @@ -87,13 +87,10 @@ class ObjOperandId : public OperandId _(GuardClass) \ _(GuardSpecificObject) \ _(GuardNoDetachedTypedObjects) \ - _(GuardNoUnboxedExpando) \ - _(GuardAndLoadUnboxedExpando) \ _(LoadObject) \ _(LoadProto) \ _(LoadFixedSlotResult) \ _(LoadDynamicSlotResult) \ - _(LoadUnboxedPropertyResult) \ _(LoadTypedObjectResult) \ _(LoadInt32ArrayLengthResult) \ _(LoadArgumentsObjectLengthResult) \ @@ -274,15 +271,6 @@ class MOZ_RAII CacheIRWriter void guardNoDetachedTypedObjects() { writeOp(CacheOp::GuardNoDetachedTypedObjects); } - void guardNoUnboxedExpando(ObjOperandId obj) { - writeOpWithOperandId(CacheOp::GuardNoUnboxedExpando, obj); - } - ObjOperandId guardAndLoadUnboxedExpando(ObjOperandId obj) { - ObjOperandId res(nextOperandId_++); - writeOpWithOperandId(CacheOp::GuardAndLoadUnboxedExpando, obj); - writeOperandId(res); - return res; - } ObjOperandId loadObject(JSObject* obj) { ObjOperandId res(nextOperandId_++); @@ -308,11 +296,6 @@ class MOZ_RAII CacheIRWriter writeOpWithOperandId(CacheOp::LoadDynamicSlotResult, obj); addStubWord(offset, StubField::GCType::NoGCThing); } - void loadUnboxedPropertyResult(ObjOperandId obj, JSValueType type, size_t offset) { - writeOpWithOperandId(CacheOp::LoadUnboxedPropertyResult, obj); - buffer_.writeByte(uint32_t(type)); - addStubWord(offset, StubField::GCType::NoGCThing); - } void loadTypedObjectResult(ObjOperandId obj, uint32_t offset, TypedThingLayout layout, uint32_t typeDescr) { MOZ_ASSERT(uint32_t(layout) <= UINT8_MAX); @@ -406,9 +389,6 @@ class MOZ_RAII GetPropIRGenerator PreliminaryObjectAction preliminaryObjectAction_; MOZ_MUST_USE bool tryAttachNative(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId); - MOZ_MUST_USE bool tryAttachUnboxed(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId); - MOZ_MUST_USE bool tryAttachUnboxedExpando(CacheIRWriter& writer, HandleObject obj, - ObjOperandId objId); MOZ_MUST_USE bool tryAttachTypedObject(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId); MOZ_MUST_USE bool tryAttachObjectLength(CacheIRWriter& writer, HandleObject obj, diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index 81cf9d9bb..1ef25cbd5 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -867,30 +867,6 @@ GenerateReadSlot(JSContext* cx, IonScript* ion, MacroAssembler& masm, attacher.jumpNextStub(masm); } -static void -GenerateReadUnboxed(JSContext* cx, IonScript* ion, MacroAssembler& masm, - IonCache::StubAttacher& attacher, JSObject* obj, - const UnboxedLayout::Property* property, - Register object, TypedOrValueRegister output, - Label* failures = nullptr) -{ - // Guard on the group of the object. - attacher.branchNextStubOrLabel(masm, Assembler::NotEqual, - Address(object, JSObject::offsetOfGroup()), - ImmGCPtr(obj->group()), failures); - - Address address(object, UnboxedPlainObject::offsetOfData() + property->offset); - - masm.loadUnboxedProperty(address, property->type, output); - - attacher.jumpRejoin(masm); - - if (failures) { - masm.bind(failures); - attacher.jumpNextStub(masm); - } -} - static bool EmitGetterCall(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& attacher, JSObject* obj, @@ -1497,67 +1473,6 @@ GetPropertyIC::tryAttachNative(JSContext* cx, HandleScript outerScript, IonScrip return linkAndAttachStub(cx, masm, attacher, ion, attachKind, outcome); } -bool -GetPropertyIC::tryAttachUnboxed(JSContext* cx, HandleScript outerScript, IonScript* ion, - HandleObject obj, HandleId id, void* returnAddr, bool* emitted) -{ - MOZ_ASSERT(canAttachStub()); - MOZ_ASSERT(!*emitted); - MOZ_ASSERT(outerScript->ionScript() == ion); - - if (!obj->is()) - return true; - const UnboxedLayout::Property* property = obj->as().layout().lookup(id); - if (!property) - return true; - - *emitted = true; - - MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_); - - Label failures; - emitIdGuard(masm, id, &failures); - Label* maybeFailures = failures.used() ? &failures : nullptr; - - StubAttacher attacher(*this); - GenerateReadUnboxed(cx, ion, masm, attacher, obj, property, object(), output(), maybeFailures); - return linkAndAttachStub(cx, masm, attacher, ion, "read unboxed", - JS::TrackedOutcome::ICGetPropStub_UnboxedRead); -} - -bool -GetPropertyIC::tryAttachUnboxedExpando(JSContext* cx, HandleScript outerScript, IonScript* ion, - HandleObject obj, HandleId id, void* returnAddr, bool* emitted) -{ - MOZ_ASSERT(canAttachStub()); - MOZ_ASSERT(!*emitted); - MOZ_ASSERT(outerScript->ionScript() == ion); - - if (!obj->is()) - return true; - Rooted expando(cx, obj->as().maybeExpando()); - if (!expando) - return true; - - Shape* shape = expando->lookup(cx, id); - if (!shape || !shape->hasDefaultGetter() || !shape->hasSlot()) - return true; - - *emitted = true; - - MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_); - - Label failures; - emitIdGuard(masm, id, &failures); - Label* maybeFailures = failures.used() ? &failures : nullptr; - - StubAttacher attacher(*this); - GenerateReadSlot(cx, ion, masm, attacher, DontCheckTDZ, obj, obj, - shape, object(), output(), maybeFailures); - return linkAndAttachStub(cx, masm, attacher, ion, "read unboxed expando", - JS::TrackedOutcome::ICGetPropStub_UnboxedReadExpando); -} - bool GetPropertyIC::tryAttachTypedArrayLength(JSContext* cx, HandleScript outerScript, IonScript* ion, HandleObject obj, HandleId id, bool* emitted) @@ -2127,12 +2042,6 @@ GetPropertyIC::tryAttachStub(JSContext* cx, HandleScript outerScript, IonScript* if (!*emitted && !tryAttachNative(cx, outerScript, ion, obj, id, returnAddr, emitted)) return false; - if (!*emitted && !tryAttachUnboxed(cx, outerScript, ion, obj, id, returnAddr, emitted)) - return false; - - if (!*emitted && !tryAttachUnboxedExpando(cx, outerScript, ion, obj, id, returnAddr, emitted)) - return false; - if (!*emitted && !tryAttachTypedArrayLength(cx, outerScript, ion, obj, id, emitted)) return false; } @@ -3298,141 +3207,6 @@ CanAttachNativeSetProp(JSContext* cx, HandleObject obj, HandleId id, const Const return SetPropertyIC::CanAttachNone; } -static void -GenerateSetUnboxed(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& attacher, - JSObject* obj, jsid id, uint32_t unboxedOffset, JSValueType unboxedType, - Register object, Register tempReg, const ConstantOrRegister& value, - bool checkTypeset, Label* failures) -{ - // Guard on the type of the object. - masm.branchPtr(Assembler::NotEqual, - Address(object, JSObject::offsetOfGroup()), - ImmGCPtr(obj->group()), failures); - - if (checkTypeset) - CheckTypeSetForWrite(masm, obj, id, tempReg, value, failures); - - Address address(object, UnboxedPlainObject::offsetOfData() + unboxedOffset); - - if (cx->zone()->needsIncrementalBarrier()) { - if (unboxedType == JSVAL_TYPE_OBJECT) - masm.callPreBarrier(address, MIRType::Object); - else if (unboxedType == JSVAL_TYPE_STRING) - masm.callPreBarrier(address, MIRType::String); - else - MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(unboxedType)); - } - - masm.storeUnboxedProperty(address, unboxedType, value, failures); - - attacher.jumpRejoin(masm); - - masm.bind(failures); - attacher.jumpNextStub(masm); -} - -static bool -CanAttachSetUnboxed(JSContext* cx, HandleObject obj, HandleId id, const ConstantOrRegister& val, - bool needsTypeBarrier, bool* checkTypeset, - uint32_t* unboxedOffset, JSValueType* unboxedType) -{ - if (!obj->is()) - return false; - - const UnboxedLayout::Property* property = obj->as().layout().lookup(id); - if (property) { - *checkTypeset = false; - if (needsTypeBarrier && !CanInlineSetPropTypeCheck(obj, id, val, checkTypeset)) - return false; - *unboxedOffset = property->offset; - *unboxedType = property->type; - return true; - } - - return false; -} - -static bool -CanAttachSetUnboxedExpando(JSContext* cx, HandleObject obj, HandleId id, - const ConstantOrRegister& val, - bool needsTypeBarrier, bool* checkTypeset, Shape** pshape) -{ - if (!obj->is()) - return false; - - Rooted expando(cx, obj->as().maybeExpando()); - if (!expando) - return false; - - Shape* shape = expando->lookupPure(id); - if (!shape || !shape->hasDefaultSetter() || !shape->hasSlot() || !shape->writable()) - return false; - - *checkTypeset = false; - if (needsTypeBarrier && !CanInlineSetPropTypeCheck(obj, id, val, checkTypeset)) - return false; - - *pshape = shape; - return true; -} - -static bool -CanAttachAddUnboxedExpando(JSContext* cx, HandleObject obj, HandleShape oldShape, - HandleId id, const ConstantOrRegister& val, - bool needsTypeBarrier, bool* checkTypeset) -{ - if (!obj->is()) - return false; - - Rooted expando(cx, obj->as().maybeExpando()); - if (!expando || expando->inDictionaryMode()) - return false; - - Shape* newShape = expando->lastProperty(); - if (newShape->isEmptyShape() || newShape->propid() != id || newShape->previous() != oldShape) - return false; - - MOZ_ASSERT(newShape->hasDefaultSetter() && newShape->hasSlot() && newShape->writable()); - - if (PrototypeChainShadowsPropertyAdd(cx, obj, id)) - return false; - - *checkTypeset = false; - if (needsTypeBarrier && !CanInlineSetPropTypeCheck(obj, id, val, checkTypeset)) - return false; - - return true; -} - -bool -SetPropertyIC::tryAttachUnboxed(JSContext* cx, HandleScript outerScript, IonScript* ion, - HandleObject obj, HandleId id, bool* emitted) -{ - MOZ_ASSERT(!*emitted); - - bool checkTypeset = false; - uint32_t unboxedOffset; - JSValueType unboxedType; - if (!CanAttachSetUnboxed(cx, obj, id, value(), needsTypeBarrier(), &checkTypeset, - &unboxedOffset, &unboxedType)) - { - return true; - } - - *emitted = true; - - MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_); - StubAttacher attacher(*this); - - Label failures; - emitIdGuard(masm, id, &failures); - - GenerateSetUnboxed(cx, masm, attacher, obj, id, unboxedOffset, unboxedType, - object(), temp(), value(), checkTypeset, &failures); - return linkAndAttachStub(cx, masm, attacher, ion, "set_unboxed", - JS::TrackedOutcome::ICSetPropStub_SetUnboxed); -} - bool SetPropertyIC::tryAttachProxy(JSContext* cx, HandleScript outerScript, IonScript* ion, HandleObject obj, HandleId id, bool* emitted) @@ -3513,26 +3287,6 @@ SetPropertyIC::tryAttachNative(JSContext* cx, HandleScript outerScript, IonScrip MOZ_CRASH("Unreachable"); } -bool -SetPropertyIC::tryAttachUnboxedExpando(JSContext* cx, HandleScript outerScript, IonScript* ion, - HandleObject obj, HandleId id, bool* emitted) -{ - MOZ_ASSERT(!*emitted); - - RootedShape shape(cx); - bool checkTypeset = false; - if (!CanAttachSetUnboxedExpando(cx, obj, id, value(), needsTypeBarrier(), - &checkTypeset, shape.address())) - { - return true; - } - - if (!attachSetSlot(cx, outerScript, ion, obj, shape, checkTypeset)) - return false; - *emitted = true; - return true; -} - bool SetPropertyIC::tryAttachStub(JSContext* cx, HandleScript outerScript, IonScript* ion, HandleObject obj, HandleValue idval, HandleValue value, @@ -3558,12 +3312,6 @@ SetPropertyIC::tryAttachStub(JSContext* cx, HandleScript outerScript, IonScript* if (!*emitted && !tryAttachNative(cx, outerScript, ion, obj, id, emitted, tryNativeAddSlot)) return false; - - if (!*emitted && !tryAttachUnboxed(cx, outerScript, ion, obj, id, emitted)) - return false; - - if (!*emitted && !tryAttachUnboxedExpando(cx, outerScript, ion, obj, id, emitted)) - return false; } if (idval.isInt32()) { @@ -3615,16 +3363,6 @@ SetPropertyIC::tryAttachAddSlot(JSContext* cx, HandleScript outerScript, IonScri return true; } - checkTypeset = false; - if (CanAttachAddUnboxedExpando(cx, obj, oldShape, id, value(), needsTypeBarrier(), - &checkTypeset)) - { - if (!attachAddSlot(cx, outerScript, ion, obj, id, oldShape, oldGroup, checkTypeset)) - return false; - *emitted = true; - return true; - } - return true; } diff --git a/js/src/jit/IonCaches.h b/js/src/jit/IonCaches.h index 173e06c6b..b00646538 100644 --- a/js/src/jit/IonCaches.h +++ b/js/src/jit/IonCaches.h @@ -529,18 +529,6 @@ class GetPropertyIC : public IonCache HandleObject obj, HandleId id, void* returnAddr, bool* emitted); - MOZ_MUST_USE bool tryAttachUnboxed(JSContext* cx, HandleScript outerScript, IonScript* ion, - HandleObject obj, HandleId id, void* returnAddr, - bool* emitted); - - MOZ_MUST_USE bool tryAttachUnboxedExpando(JSContext* cx, HandleScript outerScript, - IonScript* ion, HandleObject obj, HandleId id, - void* returnAddr, bool* emitted); - - MOZ_MUST_USE bool tryAttachUnboxedArrayLength(JSContext* cx, HandleScript outerScript, - IonScript* ion, HandleObject obj, HandleId id, - void* returnAddr, bool* emitted); - MOZ_MUST_USE bool tryAttachTypedArrayLength(JSContext* cx, HandleScript outerScript, IonScript* ion, HandleObject obj, HandleId id, bool* emitted); diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp index e50f68722..bc04e85cf 100644 --- a/js/src/jit/MacroAssembler.cpp +++ b/js/src/jit/MacroAssembler.cpp @@ -468,243 +468,6 @@ template void MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, const A template void MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, const BaseIndex& src, const ValueOperand& dest, bool allowDouble, Register temp, Label* fail); -template -void -MacroAssembler::loadUnboxedProperty(T address, JSValueType type, TypedOrValueRegister output) -{ - switch (type) { - case JSVAL_TYPE_INT32: { - // Handle loading an int32 into a double reg. - if (output.type() == MIRType::Double) { - convertInt32ToDouble(address, output.typedReg().fpu()); - break; - } - MOZ_FALLTHROUGH; - } - - case JSVAL_TYPE_BOOLEAN: - case JSVAL_TYPE_STRING: { - Register outReg; - if (output.hasValue()) { - outReg = output.valueReg().scratchReg(); - } else { - MOZ_ASSERT(output.type() == MIRTypeFromValueType(type)); - outReg = output.typedReg().gpr(); - } - - switch (type) { - case JSVAL_TYPE_BOOLEAN: - load8ZeroExtend(address, outReg); - break; - case JSVAL_TYPE_INT32: - load32(address, outReg); - break; - case JSVAL_TYPE_STRING: - loadPtr(address, outReg); - break; - default: - MOZ_CRASH(); - } - - if (output.hasValue()) - tagValue(type, outReg, output.valueReg()); - break; - } - - case JSVAL_TYPE_OBJECT: - if (output.hasValue()) { - Register scratch = output.valueReg().scratchReg(); - loadPtr(address, scratch); - - Label notNull, done; - branchPtr(Assembler::NotEqual, scratch, ImmWord(0), ¬Null); - - moveValue(NullValue(), output.valueReg()); - jump(&done); - - bind(¬Null); - tagValue(JSVAL_TYPE_OBJECT, scratch, output.valueReg()); - - bind(&done); - } else { - // Reading null can't be possible here, as otherwise the result - // would be a value (either because null has been read before or - // because there is a barrier). - Register reg = output.typedReg().gpr(); - loadPtr(address, reg); -#ifdef DEBUG - Label ok; - branchTestPtr(Assembler::NonZero, reg, reg, &ok); - assumeUnreachable("Null not possible"); - bind(&ok); -#endif - } - break; - - case JSVAL_TYPE_DOUBLE: - // Note: doubles in unboxed objects are not accessed through other - // views and do not need canonicalization. - if (output.hasValue()) - loadValue(address, output.valueReg()); - else - loadDouble(address, output.typedReg().fpu()); - break; - - default: - MOZ_CRASH(); - } -} - -template void -MacroAssembler::loadUnboxedProperty(Address address, JSValueType type, - TypedOrValueRegister output); - -template void -MacroAssembler::loadUnboxedProperty(BaseIndex address, JSValueType type, - TypedOrValueRegister output); - -static void -StoreUnboxedFailure(MacroAssembler& masm, Label* failure) -{ - // Storing a value to an unboxed property is a fallible operation and - // the caller must provide a failure label if a particular unboxed store - // might fail. Sometimes, however, a store that cannot succeed (such as - // storing a string to an int32 property) will be marked as infallible. - // This can only happen if the code involved is unreachable. - if (failure) - masm.jump(failure); - else - masm.assumeUnreachable("Incompatible write to unboxed property"); -} - -template -void -MacroAssembler::storeUnboxedProperty(T address, JSValueType type, - const ConstantOrRegister& value, Label* failure) -{ - switch (type) { - case JSVAL_TYPE_BOOLEAN: - if (value.constant()) { - if (value.value().isBoolean()) - store8(Imm32(value.value().toBoolean()), address); - else - StoreUnboxedFailure(*this, failure); - } else if (value.reg().hasTyped()) { - if (value.reg().type() == MIRType::Boolean) - store8(value.reg().typedReg().gpr(), address); - else - StoreUnboxedFailure(*this, failure); - } else { - if (failure) - branchTestBoolean(Assembler::NotEqual, value.reg().valueReg(), failure); - storeUnboxedPayload(value.reg().valueReg(), address, /* width = */ 1); - } - break; - - case JSVAL_TYPE_INT32: - if (value.constant()) { - if (value.value().isInt32()) - store32(Imm32(value.value().toInt32()), address); - else - StoreUnboxedFailure(*this, failure); - } else if (value.reg().hasTyped()) { - if (value.reg().type() == MIRType::Int32) - store32(value.reg().typedReg().gpr(), address); - else - StoreUnboxedFailure(*this, failure); - } else { - if (failure) - branchTestInt32(Assembler::NotEqual, value.reg().valueReg(), failure); - storeUnboxedPayload(value.reg().valueReg(), address, /* width = */ 4); - } - break; - - case JSVAL_TYPE_DOUBLE: - if (value.constant()) { - if (value.value().isNumber()) { - loadConstantDouble(value.value().toNumber(), ScratchDoubleReg); - storeDouble(ScratchDoubleReg, address); - } else { - StoreUnboxedFailure(*this, failure); - } - } else if (value.reg().hasTyped()) { - if (value.reg().type() == MIRType::Int32) { - convertInt32ToDouble(value.reg().typedReg().gpr(), ScratchDoubleReg); - storeDouble(ScratchDoubleReg, address); - } else if (value.reg().type() == MIRType::Double) { - storeDouble(value.reg().typedReg().fpu(), address); - } else { - StoreUnboxedFailure(*this, failure); - } - } else { - ValueOperand reg = value.reg().valueReg(); - Label notInt32, end; - branchTestInt32(Assembler::NotEqual, reg, ¬Int32); - int32ValueToDouble(reg, ScratchDoubleReg); - storeDouble(ScratchDoubleReg, address); - jump(&end); - bind(¬Int32); - if (failure) - branchTestDouble(Assembler::NotEqual, reg, failure); - storeValue(reg, address); - bind(&end); - } - break; - - case JSVAL_TYPE_OBJECT: - if (value.constant()) { - if (value.value().isObjectOrNull()) - storePtr(ImmGCPtr(value.value().toObjectOrNull()), address); - else - StoreUnboxedFailure(*this, failure); - } else if (value.reg().hasTyped()) { - MOZ_ASSERT(value.reg().type() != MIRType::Null); - if (value.reg().type() == MIRType::Object) - storePtr(value.reg().typedReg().gpr(), address); - else - StoreUnboxedFailure(*this, failure); - } else { - if (failure) { - Label ok; - branchTestNull(Assembler::Equal, value.reg().valueReg(), &ok); - branchTestObject(Assembler::NotEqual, value.reg().valueReg(), failure); - bind(&ok); - } - storeUnboxedPayload(value.reg().valueReg(), address, /* width = */ sizeof(uintptr_t)); - } - break; - - case JSVAL_TYPE_STRING: - if (value.constant()) { - if (value.value().isString()) - storePtr(ImmGCPtr(value.value().toString()), address); - else - StoreUnboxedFailure(*this, failure); - } else if (value.reg().hasTyped()) { - if (value.reg().type() == MIRType::String) - storePtr(value.reg().typedReg().gpr(), address); - else - StoreUnboxedFailure(*this, failure); - } else { - if (failure) - branchTestString(Assembler::NotEqual, value.reg().valueReg(), failure); - storeUnboxedPayload(value.reg().valueReg(), address, /* width = */ sizeof(uintptr_t)); - } - break; - - default: - MOZ_CRASH(); - } -} - -template void -MacroAssembler::storeUnboxedProperty(Address address, JSValueType type, - const ConstantOrRegister& value, Label* failure); - -template void -MacroAssembler::storeUnboxedProperty(BaseIndex address, JSValueType type, - const ConstantOrRegister& value, Label* failure); - // Inlined version of gc::CheckAllocatorState that checks the bare essentials // and bails for anything that cannot be handled with our jit allocators. void @@ -1252,10 +1015,6 @@ MacroAssembler::initGCThing(Register obj, Register temp, JSObject* templateObj, nbytes = (nbytes < sizeof(uintptr_t)) ? 0 : nbytes - sizeof(uintptr_t); offset += sizeof(uintptr_t); } - } else if (templateObj->is()) { - storePtr(ImmWord(0), Address(obj, UnboxedPlainObject::offsetOfExpando())); - if (initContents) - initUnboxedObjectContents(obj, &templateObj->as()); } else { MOZ_CRASH("Unknown object"); } @@ -1276,29 +1035,6 @@ MacroAssembler::initGCThing(Register obj, Register temp, JSObject* templateObj, #endif } -void -MacroAssembler::initUnboxedObjectContents(Register object, UnboxedPlainObject* templateObject) -{ - const UnboxedLayout& layout = templateObject->layoutDontCheckGeneration(); - - // Initialize reference fields of the object, per UnboxedPlainObject::create. - if (const int32_t* list = layout.traceList()) { - while (*list != -1) { - storePtr(ImmGCPtr(GetJitContext()->runtime->names().empty), - Address(object, UnboxedPlainObject::offsetOfData() + *list)); - list++; - } - list++; - while (*list != -1) { - storePtr(ImmWord(0), - Address(object, UnboxedPlainObject::offsetOfData() + *list)); - list++; - } - // Unboxed objects don't have Values to initialize. - MOZ_ASSERT(*(list + 1) == -1); - } -} - void MacroAssembler::compareStrings(JSOp op, Register left, Register right, Register result, Label* fail) diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index 6ee989463..d5cc95839 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -36,7 +36,6 @@ #include "vm/ProxyObject.h" #include "vm/Shape.h" #include "vm/TypedArrayObject.h" -#include "vm/UnboxedObject.h" using mozilla::FloatingPoint; @@ -1626,17 +1625,6 @@ class MacroAssembler : public MacroAssemblerSpecific void storeToTypedFloatArray(Scalar::Type arrayType, FloatRegister value, const Address& dest, unsigned numElems = 0); - // Load a property from an UnboxedPlainObject. - template - void loadUnboxedProperty(T address, JSValueType type, TypedOrValueRegister output); - - // Store a property to an UnboxedPlainObject, without triggering barriers. - // If failure is null, the value definitely has a type suitable for storing - // in the property. - template - void storeUnboxedProperty(T address, JSValueType type, - const ConstantOrRegister& value, Label* failure); - Register extractString(const Address& address, Register scratch) { return extractObject(address, scratch); } @@ -1713,8 +1701,6 @@ class MacroAssembler : public MacroAssemblerSpecific LiveRegisterSet liveRegs, Label* fail, TypedArrayObject* templateObj, TypedArrayLength lengthKind); - void initUnboxedObjectContents(Register object, UnboxedPlainObject* templateObject); - void newGCString(Register result, Register temp, Label* fail); void newGCFatInlineString(Register result, Register temp, Label* fail); diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp index 806a9db81..a96fb58a8 100644 --- a/js/src/vm/UnboxedObject.cpp +++ b/js/src/vm/UnboxedObject.cpp @@ -67,205 +67,8 @@ static const uintptr_t CLEAR_CONSTRUCTOR_CODE_TOKEN = 0x1; /* static */ bool UnboxedLayout::makeConstructorCode(JSContext* cx, HandleObjectGroup group) { - gc::AutoSuppressGC suppress(cx); - - using namespace jit; - - if (!cx->compartment()->ensureJitCompartmentExists(cx)) - return false; - - UnboxedLayout& layout = group->unboxedLayout(); - MOZ_ASSERT(!layout.constructorCode()); - - UnboxedPlainObject* templateObject = UnboxedPlainObject::create(cx, group, TenuredObject); - if (!templateObject) - return false; - - JitContext jitContext(cx, nullptr); - - MacroAssembler masm; - - Register propertiesReg, newKindReg; -#ifdef JS_CODEGEN_X86 - propertiesReg = eax; - newKindReg = ecx; - masm.loadPtr(Address(masm.getStackPointer(), sizeof(void*)), propertiesReg); - masm.loadPtr(Address(masm.getStackPointer(), 2 * sizeof(void*)), newKindReg); -#else - propertiesReg = IntArgReg0; - newKindReg = IntArgReg1; -#endif - -#ifdef JS_CODEGEN_ARM64 - // ARM64 communicates stack address via sp, but uses a pseudo-sp for addressing. - masm.initStackPtr(); -#endif - - MOZ_ASSERT(propertiesReg.volatile_()); - MOZ_ASSERT(newKindReg.volatile_()); - - AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All()); - regs.take(propertiesReg); - regs.take(newKindReg); - Register object = regs.takeAny(), scratch1 = regs.takeAny(), scratch2 = regs.takeAny(); - - LiveGeneralRegisterSet savedNonVolatileRegisters = SavedNonVolatileRegisters(regs); - masm.PushRegsInMask(savedNonVolatileRegisters); - - // The scratch double register might be used by MacroAssembler methods. - if (ScratchDoubleReg.volatile_()) - masm.push(ScratchDoubleReg); - - Label failure, tenuredObject, allocated; - masm.branch32(Assembler::NotEqual, newKindReg, Imm32(GenericObject), &tenuredObject); - masm.branchTest32(Assembler::NonZero, AbsoluteAddress(group->addressOfFlags()), - Imm32(OBJECT_FLAG_PRE_TENURE), &tenuredObject); - - // Allocate an object in the nursery - masm.createGCObject(object, scratch1, templateObject, gc::DefaultHeap, &failure, - /* initFixedSlots = */ false); - - masm.jump(&allocated); - masm.bind(&tenuredObject); - - // Allocate an object in the tenured heap. - masm.createGCObject(object, scratch1, templateObject, gc::TenuredHeap, &failure, - /* initFixedSlots = */ false); - - // If any of the properties being stored are in the nursery, add a store - // buffer entry for the new object. - Label postBarrier; - for (size_t i = 0; i < layout.properties().length(); i++) { - const UnboxedLayout::Property& property = layout.properties()[i]; - if (property.type == JSVAL_TYPE_OBJECT) { - Address valueAddress(propertiesReg, i * sizeof(IdValuePair) + offsetof(IdValuePair, value)); - Label notObject; - masm.branchTestObject(Assembler::NotEqual, valueAddress, ¬Object); - Register valueObject = masm.extractObject(valueAddress, scratch1); - masm.branchPtrInNurseryChunk(Assembler::Equal, valueObject, scratch2, &postBarrier); - masm.bind(¬Object); - } - } - - masm.jump(&allocated); - masm.bind(&postBarrier); - - LiveGeneralRegisterSet liveVolatileRegisters; - liveVolatileRegisters.add(propertiesReg); - if (object.volatile_()) - liveVolatileRegisters.add(object); - masm.PushRegsInMask(liveVolatileRegisters); - - masm.mov(ImmPtr(cx->runtime()), scratch1); - masm.setupUnalignedABICall(scratch2); - masm.passABIArg(scratch1); - masm.passABIArg(object); - masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, PostWriteBarrier)); - - masm.PopRegsInMask(liveVolatileRegisters); - - masm.bind(&allocated); - - ValueOperand valueOperand; -#ifdef JS_NUNBOX32 - valueOperand = ValueOperand(scratch1, scratch2); -#else - valueOperand = ValueOperand(scratch1); -#endif - - Label failureStoreOther, failureStoreObject; - - for (size_t i = 0; i < layout.properties().length(); i++) { - const UnboxedLayout::Property& property = layout.properties()[i]; - Address valueAddress(propertiesReg, i * sizeof(IdValuePair) + offsetof(IdValuePair, value)); - Address targetAddress(object, UnboxedPlainObject::offsetOfData() + property.offset); - - masm.loadValue(valueAddress, valueOperand); - - if (property.type == JSVAL_TYPE_OBJECT) { - HeapTypeSet* types = group->maybeGetProperty(IdToTypeId(NameToId(property.name))); - - Label notObject; - masm.branchTestObject(Assembler::NotEqual, valueOperand, - types->mightBeMIRType(MIRType::Null) ? ¬Object : &failureStoreObject); - - Register payloadReg = masm.extractObject(valueOperand, scratch1); - - if (!types->hasType(TypeSet::AnyObjectType())) { - Register scratch = (payloadReg == scratch1) ? scratch2 : scratch1; - masm.guardObjectType(payloadReg, types, scratch, &failureStoreObject); - } - - masm.storeUnboxedProperty(targetAddress, JSVAL_TYPE_OBJECT, - TypedOrValueRegister(MIRType::Object, - AnyRegister(payloadReg)), nullptr); - - if (notObject.used()) { - Label done; - masm.jump(&done); - masm.bind(¬Object); - masm.branchTestNull(Assembler::NotEqual, valueOperand, &failureStoreOther); - masm.storeUnboxedProperty(targetAddress, JSVAL_TYPE_OBJECT, NullValue(), nullptr); - masm.bind(&done); - } - } else { - masm.storeUnboxedProperty(targetAddress, property.type, - ConstantOrRegister(valueOperand), &failureStoreOther); - } - } - - Label done; - masm.bind(&done); - - if (object != ReturnReg) - masm.movePtr(object, ReturnReg); - - // Restore non-volatile registers which were saved on entry. - if (ScratchDoubleReg.volatile_()) - masm.pop(ScratchDoubleReg); - masm.PopRegsInMask(savedNonVolatileRegisters); - - masm.abiret(); - - masm.bind(&failureStoreOther); - - // There was a failure while storing a value which cannot be stored at all - // in the unboxed object. Initialize the object so it is safe for GC and - // return null. - masm.initUnboxedObjectContents(object, templateObject); - - masm.bind(&failure); - - masm.movePtr(ImmWord(0), object); - masm.jump(&done); - - masm.bind(&failureStoreObject); - - // There was a failure while storing a value to an object slot of the - // unboxed object. If the value is storable, the failure occurred due to - // incomplete type information in the object, so return a token to trigger - // regeneration of the jitcode after a new object is created in the VM. - { - Label isObject; - masm.branchTestObject(Assembler::Equal, valueOperand, &isObject); - masm.branchTestNull(Assembler::NotEqual, valueOperand, &failureStoreOther); - masm.bind(&isObject); - } - - // Initialize the object so it is safe for GC. - masm.initUnboxedObjectContents(object, templateObject); - - masm.movePtr(ImmWord(CLEAR_CONSTRUCTOR_CODE_TOKEN), object); - masm.jump(&done); - - Linker linker(masm); - AutoFlushICache afc("UnboxedObject"); - JitCode* code = linker.newCode(cx, OTHER_CODE); - if (!code) - return false; - - layout.setConstructorCode(code); - return true; + // *** STUB *** + return false; } void -- cgit v1.2.3 From fd96dac1d27da739cf168395623a962b2f0f1b98 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sun, 23 Jun 2019 19:41:44 +0000 Subject: Fix unified deprot --- js/src/jit/CodeGenerator.cpp | 1 + js/src/jit/VMFunctions.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'js/src') diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index e0b8a7f28..71a8890f3 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -25,6 +25,7 @@ #include "builtin/Eval.h" #include "builtin/TypedObject.h" #include "gc/Nursery.h" +#include "gc/StoreBuffer-inl.h" #include "irregexp/NativeRegExpMacroAssembler.h" #include "jit/AtomicOperations.h" #include "jit/BaselineCompiler.h" diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 297357b1e..402d910b9 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -28,7 +28,7 @@ #include "vm/NativeObject-inl.h" #include "vm/StringObject-inl.h" #include "vm/TypeInference-inl.h" -#include "vm/UnboxedObject-inl.h" +#include "gc/StoreBuffer-inl.h" using namespace js; using namespace js::jit; -- cgit v1.2.3 From ac97104c52c573e25392312d3bb7b3a297f67c44 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sun, 23 Jun 2019 21:30:34 +0000 Subject: Remove Unboxed Object code from jit, Part 3. --- js/src/jit/BaselineIC.cpp | 40 +++---------------------------------- js/src/jit/BaselineIC.h | 10 ++-------- js/src/jit/IonCaches.cpp | 5 ----- js/src/jit/MCallOptimize.cpp | 1 - js/src/jit/OptimizationTracking.cpp | 4 ---- js/src/jit/Recover.cpp | 35 +++++--------------------------- 6 files changed, 10 insertions(+), 85 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index ba855dac9..56049a2a0 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -42,8 +42,8 @@ #include "jit/shared/Lowering-shared-inl.h" #include "vm/EnvironmentObject-inl.h" #include "vm/Interpreter-inl.h" +#include "vm/NativeObject-inl.h" #include "vm/StringObject-inl.h" -#include "vm/UnboxedObject-inl.h" using mozilla::DebugOnly; @@ -732,11 +732,6 @@ LastPropertyForSetProp(JSObject* obj) if (obj->isNative()) return obj->as().lastProperty(); - if (obj->is()) { - UnboxedExpandoObject* expando = obj->as().maybeExpando(); - return expando ? expando->lastProperty() : nullptr; - } - return nullptr; } @@ -2666,18 +2661,6 @@ BaselineScript::noteArrayWriteHole(uint32_t pcOffset) // SetElem_DenseOrUnboxedArray // -template -void -EmitUnboxedPreBarrierForBaseline(MacroAssembler &masm, T address, JSValueType type) -{ - if (type == JSVAL_TYPE_OBJECT) - EmitPreBarrier(masm, address, MIRType::Object); - else if (type == JSVAL_TYPE_STRING) - EmitPreBarrier(masm, address, MIRType::String); - else - MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(type)); -} - bool ICSetElem_DenseOrUnboxedArray::Compiler::generateStubCode(MacroAssembler& masm) { @@ -4124,18 +4107,7 @@ TryAttachSetValuePropStub(JSContext* cx, HandleScript script, jsbytecode* pc, IC return true; if (!obj->isNative()) { - if (obj->is()) { - UnboxedExpandoObject* expando = obj->as().maybeExpando(); - if (expando) { - shape = expando->lookup(cx, name); - if (!shape) - return true; - } else { - return true; - } - } else { - return true; - } + return true; } size_t chainDepth; @@ -4368,12 +4340,6 @@ DoSetPropFallback(JSContext* cx, BaselineFrame* frame, ICSetProp_Fallback* stub_ return false; RootedReceiverGuard oldGuard(cx, ReceiverGuard(obj)); - if (obj->is()) { - MOZ_ASSERT(!oldShape); - if (UnboxedExpandoObject* expando = obj->as().maybeExpando()) - oldShape = expando->lastProperty(); - } - bool attached = false; // There are some reasons we can fail to attach a stub that are temporary. // We want to avoid calling noteUnoptimizableAccess() if the reason we @@ -5538,7 +5504,7 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb if (!thisObject) return false; - if (thisObject->is() || thisObject->is()) + if (thisObject->is()) templateObject = thisObject; } diff --git a/js/src/jit/BaselineIC.h b/js/src/jit/BaselineIC.h index 901fca9cc..98f0e1c59 100644 --- a/js/src/jit/BaselineIC.h +++ b/js/src/jit/BaselineIC.h @@ -22,7 +22,6 @@ #include "jit/SharedICRegisters.h" #include "js/GCVector.h" #include "vm/ArrayObject.h" -#include "vm/UnboxedObject.h" namespace js { namespace jit { @@ -1823,8 +1822,7 @@ class ICSetProp_Native : public ICUpdatedStub virtual int32_t getKey() const { return static_cast(engine_) | (static_cast(kind) << 1) | - (static_cast(isFixedSlot_) << 17) | - (static_cast(obj_->is()) << 18); + (static_cast(isFixedSlot_) << 17); } MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm); @@ -1929,7 +1927,6 @@ class ICSetPropNativeAddCompiler : public ICStubCompiler return static_cast(engine_) | (static_cast(kind) << 1) | (static_cast(isFixedSlot_) << 17) | - (static_cast(obj_->is()) << 18) | (static_cast(protoChainDepth_) << 19); } @@ -1954,10 +1951,7 @@ class ICSetPropNativeAddCompiler : public ICStubCompiler newGroup = nullptr; RootedShape newShape(cx); - if (obj_->isNative()) - newShape = obj_->as().lastProperty(); - else - newShape = obj_->as().maybeExpando()->lastProperty(); + newShape = obj_->as().lastProperty(); return newStub>( space, getStubCode(), oldGroup_, shapes, newShape, newGroup, offset_); diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index 1ef25cbd5..2cd9fa4be 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -3384,11 +3384,6 @@ SetPropertyIC::update(JSContext* cx, HandleScript outerScript, size_t cacheIndex return false; oldShape = obj->maybeShape(); - if (obj->is()) { - MOZ_ASSERT(!oldShape); - if (UnboxedExpandoObject* expando = obj->as().maybeExpando()) - oldShape = expando->lastProperty(); - } } RootedId id(cx); diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index fed5aefe5..359f04639 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -30,7 +30,6 @@ #include "jit/shared/Lowering-shared-inl.h" #include "vm/NativeObject-inl.h" #include "vm/StringObject-inl.h" -#include "vm/UnboxedObject-inl.h" using mozilla::ArrayLength; using mozilla::AssertedCast; diff --git a/js/src/jit/OptimizationTracking.cpp b/js/src/jit/OptimizationTracking.cpp index b42634d43..7d72795a0 100644 --- a/js/src/jit/OptimizationTracking.cpp +++ b/js/src/jit/OptimizationTracking.cpp @@ -15,11 +15,9 @@ #include "jit/JitcodeMap.h" #include "jit/JitSpewer.h" #include "js/TrackedOptimizationInfo.h" -#include "vm/UnboxedObject.h" #include "vm/ObjectGroup-inl.h" #include "vm/TypeInference-inl.h" -#include "vm/UnboxedObject-inl.h" using namespace js; using namespace js::jit; @@ -846,8 +844,6 @@ MaybeConstructorFromType(TypeSet::Type ty) return nullptr; ObjectGroup* obj = ty.group(); TypeNewScript* newScript = obj->newScript(); - if (!newScript && obj->maybeUnboxedLayout()) - newScript = obj->unboxedLayout().newScript(); return newScript ? newScript->function() : nullptr; } diff --git a/js/src/jit/Recover.cpp b/js/src/jit/Recover.cpp index 8fe6ee3fb..3edc6de8b 100644 --- a/js/src/jit/Recover.cpp +++ b/js/src/jit/Recover.cpp @@ -1540,37 +1540,12 @@ RObjectState::recover(JSContext* cx, SnapshotIterator& iter) const RootedObject object(cx, &iter.read().toObject()); RootedValue val(cx); - if (object->is()) { - const UnboxedLayout& layout = object->as().layout(); - - RootedId id(cx); - RootedValue receiver(cx, ObjectValue(*object)); - const UnboxedLayout::PropertyVector& properties = layout.properties(); - for (size_t i = 0; i < properties.length(); i++) { - val = iter.read(); - - // This is the default placeholder value of MObjectState, when no - // properties are defined yet. - if (val.isUndefined()) - continue; - - id = NameToId(properties[i].name); - ObjectOpResult result; - - // SetProperty can only fail due to OOM. - if (!SetProperty(cx, object, id, val, receiver, result)) - return false; - if (!result) - return result.reportError(cx, object, id); - } - } else { - RootedNativeObject nativeObject(cx, &object->as()); - MOZ_ASSERT(nativeObject->slotSpan() == numSlots()); + RootedNativeObject nativeObject(cx, &object->as()); + MOZ_ASSERT(nativeObject->slotSpan() == numSlots()); - for (size_t i = 0; i < numSlots(); i++) { - val = iter.read(); - nativeObject->setSlot(i, val); - } + for (size_t i = 0; i < numSlots(); i++) { + val = iter.read(); + nativeObject->setSlot(i, val); } val.setObject(*object); -- cgit v1.2.3 From e2ab8d5f332cd26a072430fe1d1a4518cad15d1b Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Tue, 25 Jun 2019 11:12:26 +0000 Subject: Remove Unboxed Object code from jit, Part 4. --- js/src/jit/BaselineIC.cpp | 115 +++------------------------ js/src/jit/CodeGenerator.cpp | 15 +--- js/src/jit/IonBuilder.cpp | 183 ------------------------------------------- js/src/jit/IonBuilder.h | 13 --- js/src/jit/IonCaches.cpp | 69 +--------------- js/src/jit/Recover.cpp | 1 - js/src/jit/SharedIC.cpp | 30 +------ 7 files changed, 20 insertions(+), 406 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 56049a2a0..d95d08edc 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -1148,56 +1148,6 @@ TryAttachNativeOrUnboxedGetValueElemStub(JSContext* cx, HandleScript script, jsb ICStub* monitorStub = stub->fallbackMonitorStub()->firstMonitorStub(); - if (obj->is() && holder == obj) { - const UnboxedLayout::Property* property = obj->as().layout().lookup(id); - - // Once unboxed objects support symbol-keys, we need to change the following accordingly - MOZ_ASSERT_IF(!keyVal.isString(), !property); - - if (property) { - if (!cx->runtime()->jitSupportsFloatingPoint) - return true; - - RootedPropertyName name(cx, JSID_TO_ATOM(id)->asPropertyName()); - ICGetElemNativeCompiler compiler(cx, ICStub::GetElem_UnboxedPropertyName, - monitorStub, obj, holder, - name, - ICGetElemNativeStub::UnboxedProperty, - needsAtomize, property->offset + - UnboxedPlainObject::offsetOfData(), - property->type); - ICStub* newStub = compiler.getStub(compiler.getStubSpace(script)); - if (!newStub) - return false; - - stub->addNewStub(newStub); - *attached = true; - return true; - } - - Shape* shape = obj->as().maybeExpando()->lookup(cx, id); - if (!shape->hasDefaultGetter() || !shape->hasSlot()) - return true; - - bool isFixedSlot; - uint32_t offset; - GetFixedOrDynamicSlotOffset(shape, &isFixedSlot, &offset); - - ICGetElemNativeStub::AccessType acctype = - isFixedSlot ? ICGetElemNativeStub::FixedSlot - : ICGetElemNativeStub::DynamicSlot; - ICGetElemNativeCompiler compiler(cx, getGetElemStubKind(ICStub::GetElem_NativeSlotName), - monitorStub, obj, holder, key, - acctype, needsAtomize, offset); - ICStub* newStub = compiler.getStub(compiler.getStubSpace(script)); - if (!newStub) - return false; - - stub->addNewStub(newStub); - *attached = true; - return true; - } - if (!holder->isNative()) return true; @@ -1445,7 +1395,7 @@ TryAttachGetElemStub(JSContext* cx, JSScript* script, jsbytecode* pc, ICGetElem_ } // Check for NativeObject[id] and UnboxedPlainObject[id] shape-optimizable accesses. - if (obj->isNative() || obj->is()) { + if (obj->isNative()) { RootedScript rootedScript(cx, script); if (rhs.isString()) { if (!TryAttachNativeOrUnboxedGetValueElemStub(cx, rootedScript, pc, stub, @@ -1857,14 +1807,6 @@ ICGetElemNativeCompiler::generateStubCode(MacroAssembler& masm) Register holderReg; if (obj_ == holder_) { holderReg = objReg; - - if (obj_->is() && acctype_ != ICGetElemNativeStub::UnboxedProperty) { - // The property will be loaded off the unboxed expando. - masm.push(R1.scratchReg()); - popR1 = true; - holderReg = R1.scratchReg(); - masm.loadPtr(Address(objReg, UnboxedPlainObject::offsetOfExpando()), holderReg); - } } else { // Shape guard holder. if (regs.empty()) { @@ -4494,20 +4436,7 @@ GuardGroupAndShapeMaybeUnboxedExpando(MacroAssembler& masm, JSObject* obj, // Guard against shape or expando shape. masm.loadPtr(Address(ICStubReg, offsetOfShape), scratch); - if (obj->is()) { - Address expandoAddress(object, UnboxedPlainObject::offsetOfExpando()); - masm.branchPtr(Assembler::Equal, expandoAddress, ImmWord(0), failure); - Label done; - masm.push(object); - masm.loadPtr(expandoAddress, object); - masm.branchTestObjShape(Assembler::Equal, object, scratch, &done); - masm.pop(object); - masm.jump(failure); - masm.bind(&done); - masm.pop(object); - } else { - masm.branchTestObjShape(Assembler::NotEqual, object, scratch, failure); - } + masm.branchTestObjShape(Assembler::NotEqual, object, scratch, failure); } bool @@ -4546,13 +4475,7 @@ ICSetProp_Native::Compiler::generateStubCode(MacroAssembler& masm) regs.takeUnchecked(objReg); Register holderReg; - if (obj_->is()) { - // We are loading off the expando object, so use that for the holder. - holderReg = regs.takeAny(); - masm.loadPtr(Address(objReg, UnboxedPlainObject::offsetOfExpando()), holderReg); - if (!isFixedSlot_) - masm.loadPtr(Address(holderReg, NativeObject::offsetOfSlots()), holderReg); - } else if (isFixedSlot_) { + if (isFixedSlot_) { holderReg = objReg; } else { holderReg = regs.takeAny(); @@ -4689,31 +4612,17 @@ ICSetPropNativeAddCompiler::generateStubCode(MacroAssembler& masm) regs.add(R0); regs.takeUnchecked(objReg); - if (obj_->is()) { - holderReg = regs.takeAny(); - masm.loadPtr(Address(objReg, UnboxedPlainObject::offsetOfExpando()), holderReg); - - // Write the expando object's new shape. - Address shapeAddr(holderReg, ShapedObject::offsetOfShape()); - EmitPreBarrier(masm, shapeAddr, MIRType::Shape); - masm.loadPtr(Address(ICStubReg, ICSetProp_NativeAdd::offsetOfNewShape()), scratch); - masm.storePtr(scratch, shapeAddr); + // Write the object's new shape. + Address shapeAddr(objReg, ShapedObject::offsetOfShape()); + EmitPreBarrier(masm, shapeAddr, MIRType::Shape); + masm.loadPtr(Address(ICStubReg, ICSetProp_NativeAdd::offsetOfNewShape()), scratch); + masm.storePtr(scratch, shapeAddr); - if (!isFixedSlot_) - masm.loadPtr(Address(holderReg, NativeObject::offsetOfSlots()), holderReg); + if (isFixedSlot_) { + holderReg = objReg; } else { - // Write the object's new shape. - Address shapeAddr(objReg, ShapedObject::offsetOfShape()); - EmitPreBarrier(masm, shapeAddr, MIRType::Shape); - masm.loadPtr(Address(ICStubReg, ICSetProp_NativeAdd::offsetOfNewShape()), scratch); - masm.storePtr(scratch, shapeAddr); - - if (isFixedSlot_) { - holderReg = objReg; - } else { - holderReg = regs.takeAny(); - masm.loadPtr(Address(objReg, NativeObject::offsetOfSlots()), holderReg); - } + holderReg = regs.takeAny(); + masm.loadPtr(Address(objReg, NativeObject::offsetOfSlots()), holderReg); } // Perform the store. No write barrier required since this is a new diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 71a8890f3..a276ab9af 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -8383,11 +8383,6 @@ CodeGenerator::visitStoreUnboxedPointer(LStoreUnboxedPointer* lir) } } -typedef bool (*ConvertUnboxedObjectToNativeFn)(JSContext*, JSObject*); -static const VMFunction ConvertUnboxedPlainObjectToNativeInfo = - FunctionInfo(UnboxedPlainObject::convertToNative, - "UnboxedPlainObject::convertToNative"); - typedef bool (*ArrayPopShiftFn)(JSContext*, HandleObject, MutableHandleValue); static const VMFunction ArrayPopDenseInfo = FunctionInfo(jit::ArrayPopDense, "ArrayPopDense"); @@ -8680,11 +8675,11 @@ CodeGenerator::visitIteratorStartO(LIteratorStartO* lir) masm.loadPtr(Address(niTemp, offsetof(NativeIterator, guard_array)), temp2); // Compare object with the first receiver guard. The last iterator can only - // match for native objects and unboxed objects. + // match for native objects. { Address groupAddr(temp2, offsetof(ReceiverGuard, group)); Address shapeAddr(temp2, offsetof(ReceiverGuard, shape)); - Label guardDone, shapeMismatch, noExpando; + Label guardDone, shapeMismatch; masm.loadObjShape(obj, temp1); masm.branchPtr(Assembler::NotEqual, shapeAddr, temp1, &shapeMismatch); @@ -8696,12 +8691,6 @@ CodeGenerator::visitIteratorStartO(LIteratorStartO* lir) masm.bind(&shapeMismatch); masm.loadObjGroup(obj, temp1); masm.branchPtr(Assembler::NotEqual, groupAddr, temp1, ool->entry()); - masm.loadPtr(Address(obj, UnboxedPlainObject::offsetOfExpando()), temp1); - masm.branchTestPtr(Assembler::Zero, temp1, temp1, &noExpando); - branchIfNotEmptyObjectElements(temp1, ool->entry()); - masm.loadObjShape(temp1, temp1); - masm.bind(&noExpando); - masm.branchPtr(Assembler::NotEqual, shapeAddr, temp1, ool->entry()); masm.bind(&guardDone); } diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index fc864a197..a54a58add 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -10925,63 +10925,6 @@ IonBuilder::getDefiniteSlot(TemporaryTypeSet* types, PropertyName* name, uint32_ return slot; } -uint32_t -IonBuilder::getUnboxedOffset(TemporaryTypeSet* types, PropertyName* name, JSValueType* punboxedType) -{ - if (!types || types->unknownObject() || !types->objectOrSentinel()) { - trackOptimizationOutcome(TrackedOutcome::NoTypeInfo); - return UINT32_MAX; - } - - uint32_t offset = UINT32_MAX; - - for (size_t i = 0; i < types->getObjectCount(); i++) { - TypeSet::ObjectKey* key = types->getObject(i); - if (!key) - continue; - - if (key->unknownProperties()) { - trackOptimizationOutcome(TrackedOutcome::UnknownProperties); - return UINT32_MAX; - } - - if (key->isSingleton()) { - trackOptimizationOutcome(TrackedOutcome::Singleton); - return UINT32_MAX; - } - - UnboxedLayout* layout = key->group()->maybeUnboxedLayout(); - if (!layout) { - trackOptimizationOutcome(TrackedOutcome::NotUnboxed); - return UINT32_MAX; - } - - const UnboxedLayout::Property* property = layout->lookup(name); - if (!property) { - trackOptimizationOutcome(TrackedOutcome::StructNoField); - return UINT32_MAX; - } - - if (layout->nativeGroup()) { - trackOptimizationOutcome(TrackedOutcome::UnboxedConvertedToNative); - return UINT32_MAX; - } - - if (offset == UINT32_MAX) { - offset = property->offset; - *punboxedType = property->type; - } else if (offset != property->offset) { - trackOptimizationOutcome(TrackedOutcome::InconsistentFieldOffset); - return UINT32_MAX; - } else if (*punboxedType != property->type) { - trackOptimizationOutcome(TrackedOutcome::InconsistentFieldType); - return UINT32_MAX; - } - } - - return offset; -} - bool IonBuilder::jsop_runonce() { @@ -11948,72 +11891,6 @@ IonBuilder::getPropTryModuleNamespace(bool* emitted, MDefinition* obj, PropertyN return true; } -MInstruction* -IonBuilder::loadUnboxedProperty(MDefinition* obj, size_t offset, JSValueType unboxedType, - BarrierKind barrier, TemporaryTypeSet* types) -{ - // loadUnboxedValue is designed to load any value as if it were contained in - // an array. Thus a property offset is converted to an index, when the - // object is reinterpreted as an array of properties of the same size. - size_t index = offset / UnboxedTypeSize(unboxedType); - MInstruction* indexConstant = MConstant::New(alloc(), Int32Value(index)); - current->add(indexConstant); - - return loadUnboxedValue(obj, UnboxedPlainObject::offsetOfData(), - indexConstant, unboxedType, barrier, types); -} - -MInstruction* -IonBuilder::loadUnboxedValue(MDefinition* elements, size_t elementsOffset, - MDefinition* index, JSValueType unboxedType, - BarrierKind barrier, TemporaryTypeSet* types) -{ - MInstruction* load; - switch (unboxedType) { - case JSVAL_TYPE_BOOLEAN: - load = MLoadUnboxedScalar::New(alloc(), elements, index, Scalar::Uint8, - DoesNotRequireMemoryBarrier, elementsOffset); - load->setResultType(MIRType::Boolean); - break; - - case JSVAL_TYPE_INT32: - load = MLoadUnboxedScalar::New(alloc(), elements, index, Scalar::Int32, - DoesNotRequireMemoryBarrier, elementsOffset); - load->setResultType(MIRType::Int32); - break; - - case JSVAL_TYPE_DOUBLE: - load = MLoadUnboxedScalar::New(alloc(), elements, index, Scalar::Float64, - DoesNotRequireMemoryBarrier, elementsOffset, - /* canonicalizeDoubles = */ false); - load->setResultType(MIRType::Double); - break; - - case JSVAL_TYPE_STRING: - load = MLoadUnboxedString::New(alloc(), elements, index, elementsOffset); - break; - - case JSVAL_TYPE_OBJECT: { - MLoadUnboxedObjectOrNull::NullBehavior nullBehavior; - if (types->hasType(TypeSet::NullType())) - nullBehavior = MLoadUnboxedObjectOrNull::HandleNull; - else if (barrier != BarrierKind::NoBarrier) - nullBehavior = MLoadUnboxedObjectOrNull::BailOnNull; - else - nullBehavior = MLoadUnboxedObjectOrNull::NullNotPossible; - load = MLoadUnboxedObjectOrNull::New(alloc(), elements, index, nullBehavior, - elementsOffset); - break; - } - - default: - MOZ_CRASH(); - } - - current->add(load); - return load; -} - MDefinition* IonBuilder::addShapeGuardsForGetterSetter(MDefinition* obj, JSObject* holder, Shape* holderShape, const BaselineInspector::ReceiverVector& receivers, @@ -12835,66 +12712,6 @@ IonBuilder::setPropTryDefiniteSlot(bool* emitted, MDefinition* obj, return true; } -MInstruction* -IonBuilder::storeUnboxedProperty(MDefinition* obj, size_t offset, JSValueType unboxedType, - MDefinition* value) -{ - size_t scaledOffsetConstant = offset / UnboxedTypeSize(unboxedType); - MInstruction* scaledOffset = MConstant::New(alloc(), Int32Value(scaledOffsetConstant)); - current->add(scaledOffset); - - return storeUnboxedValue(obj, obj, UnboxedPlainObject::offsetOfData(), - scaledOffset, unboxedType, value); -} - -MInstruction* -IonBuilder::storeUnboxedValue(MDefinition* obj, MDefinition* elements, int32_t elementsOffset, - MDefinition* scaledOffset, JSValueType unboxedType, - MDefinition* value, bool preBarrier /* = true */) -{ - MInstruction* store; - switch (unboxedType) { - case JSVAL_TYPE_BOOLEAN: - store = MStoreUnboxedScalar::New(alloc(), elements, scaledOffset, value, Scalar::Uint8, - MStoreUnboxedScalar::DontTruncateInput, - DoesNotRequireMemoryBarrier, elementsOffset); - break; - - case JSVAL_TYPE_INT32: - store = MStoreUnboxedScalar::New(alloc(), elements, scaledOffset, value, Scalar::Int32, - MStoreUnboxedScalar::DontTruncateInput, - DoesNotRequireMemoryBarrier, elementsOffset); - break; - - case JSVAL_TYPE_DOUBLE: - store = MStoreUnboxedScalar::New(alloc(), elements, scaledOffset, value, Scalar::Float64, - MStoreUnboxedScalar::DontTruncateInput, - DoesNotRequireMemoryBarrier, elementsOffset); - break; - - case JSVAL_TYPE_STRING: - store = MStoreUnboxedString::New(alloc(), elements, scaledOffset, value, - elementsOffset, preBarrier); - break; - - case JSVAL_TYPE_OBJECT: - MOZ_ASSERT(value->type() == MIRType::Object || - value->type() == MIRType::Null || - value->type() == MIRType::Value); - MOZ_ASSERT(!value->mightBeType(MIRType::Undefined), - "MToObjectOrNull slow path is invalid for unboxed objects"); - store = MStoreUnboxedObjectOrNull::New(alloc(), elements, scaledOffset, value, obj, - elementsOffset, preBarrier); - break; - - default: - MOZ_CRASH(); - } - - current->add(store); - return store; -} - bool IonBuilder::setPropTryInlineAccess(bool* emitted, MDefinition* obj, PropertyName* name, MDefinition* value, diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index 1b97c4743..dd40b4bd6 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -1048,19 +1048,6 @@ class IonBuilder ResultWithOOM testNotDefinedProperty(MDefinition* obj, jsid id); uint32_t getDefiniteSlot(TemporaryTypeSet* types, PropertyName* name, uint32_t* pnfixed); - uint32_t getUnboxedOffset(TemporaryTypeSet* types, PropertyName* name, - JSValueType* punboxedType); - MInstruction* loadUnboxedProperty(MDefinition* obj, size_t offset, JSValueType unboxedType, - BarrierKind barrier, TemporaryTypeSet* types); - MInstruction* loadUnboxedValue(MDefinition* elements, size_t elementsOffset, - MDefinition* scaledOffset, JSValueType unboxedType, - BarrierKind barrier, TemporaryTypeSet* types); - MInstruction* storeUnboxedProperty(MDefinition* obj, size_t offset, JSValueType unboxedType, - MDefinition* value); - MInstruction* storeUnboxedValue(MDefinition* obj, - MDefinition* elements, int32_t elementsOffset, - MDefinition* scaledOffset, JSValueType unboxedType, - MDefinition* value, bool preBarrier = true); MOZ_MUST_USE bool checkPreliminaryGroups(MDefinition *obj); MOZ_MUST_USE bool freezePropTypeSets(TemporaryTypeSet* types, JSObject* foundProto, PropertyName* name); diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index 2cd9fa4be..9901bdd07 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -31,7 +31,6 @@ #include "jit/shared/Lowering-shared-inl.h" #include "vm/Interpreter-inl.h" #include "vm/Shape-inl.h" -#include "vm/UnboxedObject-inl.h" using namespace js; using namespace js::jit; @@ -620,26 +619,7 @@ TestMatchingReceiver(MacroAssembler& masm, IonCache::StubAttacher& attacher, Register object, JSObject* obj, Label* failure, bool alwaysCheckGroup = false) { - if (obj->is()) { - MOZ_ASSERT(failure); - - masm.branchTestObjGroup(Assembler::NotEqual, object, obj->group(), failure); - Address expandoAddress(object, UnboxedPlainObject::offsetOfExpando()); - if (UnboxedExpandoObject* expando = obj->as().maybeExpando()) { - masm.branchPtr(Assembler::Equal, expandoAddress, ImmWord(0), failure); - Label success; - masm.push(object); - masm.loadPtr(expandoAddress, object); - masm.branchTestObjShape(Assembler::Equal, object, expando->lastProperty(), - &success); - masm.pop(object); - masm.jump(failure); - masm.bind(&success); - masm.pop(object); - } else { - masm.branchPtr(Assembler::NotEqual, expandoAddress, ImmWord(0), failure); - } - } else if (obj->is()) { + if (obj->is()) { attacher.branchNextStubOrLabel(masm, Assembler::NotEqual, Address(object, JSObject::offsetOfGroup()), ImmGCPtr(obj->group()), failure); @@ -756,7 +736,6 @@ GenerateReadSlot(JSContext* cx, IonScript* ion, MacroAssembler& masm, // jump directly. Otherwise, jump to the end of the stub, so there's a // common point to patch. bool multipleFailureJumps = (obj != holder) - || obj->is() || (checkTDZ && output.hasValue()) || (failures != nullptr && failures->used()); @@ -775,7 +754,6 @@ GenerateReadSlot(JSContext* cx, IonScript* ion, MacroAssembler& masm, Register scratchReg = Register::FromCode(0); // Quell compiler warning. if (obj != holder || - obj->is() || !holder->as().isFixedSlot(shape->slot())) { if (output.hasValue()) { @@ -836,10 +814,6 @@ GenerateReadSlot(JSContext* cx, IonScript* ion, MacroAssembler& masm, holderReg = InvalidReg; } - } else if (obj->is()) { - holder = obj->as().maybeExpando(); - holderReg = scratchReg; - masm.loadPtr(Address(object, UnboxedPlainObject::offsetOfExpando()), holderReg); } else { holderReg = object; } @@ -2220,12 +2194,6 @@ GenerateSetSlot(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& att NativeObject::slotsSizeMustNotOverflow(); - if (obj->is()) { - obj = obj->as().maybeExpando(); - masm.loadPtr(Address(object, UnboxedPlainObject::offsetOfExpando()), tempReg); - object = tempReg; - } - if (obj->as().isFixedSlot(shape->slot())) { Address addr(object, NativeObject::getFixedSlotOffset(shape->slot())); @@ -2863,23 +2831,13 @@ GenerateAddSlot(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& att masm.branchTestObjGroup(Assembler::NotEqual, object, oldGroup, failures); if (obj->maybeShape()) { masm.branchTestObjShape(Assembler::NotEqual, object, oldShape, failures); - } else { - MOZ_ASSERT(obj->is()); - - Address expandoAddress(object, UnboxedPlainObject::offsetOfExpando()); - masm.branchPtr(Assembler::Equal, expandoAddress, ImmWord(0), failures); - - masm.loadPtr(expandoAddress, tempReg); - masm.branchTestObjShape(Assembler::NotEqual, tempReg, oldShape, failures); } Shape* newShape = obj->maybeShape(); - if (!newShape) - newShape = obj->as().maybeExpando()->lastProperty(); // Guard that the incoming value is in the type set for the property // if a type barrier is required. - if (checkTypeset) + if (newShape && checkTypeset) CheckTypeSetForWrite(masm, obj, newShape->propid(), tempReg, value, failures); // Guard shapes along prototype chain. @@ -2900,9 +2858,7 @@ GenerateAddSlot(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& att } // Call a stub to (re)allocate dynamic slots, if necessary. - uint32_t newNumDynamicSlots = obj->is() - ? obj->as().maybeExpando()->numDynamicSlots() - : obj->as().numDynamicSlots(); + uint32_t newNumDynamicSlots = obj->as().numDynamicSlots(); if (NativeObject::dynamicSlotsCount(oldShape) != newNumDynamicSlots) { AllocatableRegisterSet regs(RegisterSet::Volatile()); LiveRegisterSet save(regs.asLiveSet()); @@ -2913,12 +2869,6 @@ GenerateAddSlot(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& att Register temp1 = regs.takeAnyGeneral(); Register temp2 = regs.takeAnyGeneral(); - if (obj->is()) { - // Pass the expando object to the stub. - masm.Push(object); - masm.loadPtr(Address(object, UnboxedPlainObject::offsetOfExpando()), object); - } - masm.setupUnalignedABICall(temp1); masm.loadJSContext(temp1); masm.passABIArg(temp1); @@ -2935,27 +2885,16 @@ GenerateAddSlot(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& att masm.jump(&allocDone); masm.bind(&allocFailed); - if (obj->is()) - masm.Pop(object); masm.PopRegsInMask(save); masm.jump(failures); masm.bind(&allocDone); masm.setFramePushed(framePushedAfterCall); - if (obj->is()) - masm.Pop(object); masm.PopRegsInMask(save); } bool popObject = false; - if (obj->is()) { - masm.push(object); - popObject = true; - obj = obj->as().maybeExpando(); - masm.loadPtr(Address(object, UnboxedPlainObject::offsetOfExpando()), object); - } - // Write the object or expando object's new shape. Address shapeAddr(object, ShapedObject::offsetOfShape()); if (cx->zone()->needsIncrementalBarrier()) @@ -2963,8 +2902,6 @@ GenerateAddSlot(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& att masm.storePtr(ImmGCPtr(newShape), shapeAddr); if (oldGroup != obj->group()) { - MOZ_ASSERT(!obj->is()); - // Changing object's group from a partially to fully initialized group, // per the acquired properties analysis. Only change the group if the // old group still has a newScript. diff --git a/js/src/jit/Recover.cpp b/js/src/jit/Recover.cpp index 3edc6de8b..793b631df 100644 --- a/js/src/jit/Recover.cpp +++ b/js/src/jit/Recover.cpp @@ -30,7 +30,6 @@ #include "vm/Interpreter-inl.h" #include "vm/NativeObject-inl.h" -#include "vm/UnboxedObject-inl.h" using namespace js; using namespace js::jit; diff --git a/js/src/jit/SharedIC.cpp b/js/src/jit/SharedIC.cpp index 313957462..05a95824f 100644 --- a/js/src/jit/SharedIC.cpp +++ b/js/src/jit/SharedIC.cpp @@ -2244,8 +2244,7 @@ IsCacheableProtoChain(JSObject* obj, JSObject* holder, bool isDOMProxy) if (!isDOMProxy && !obj->isNative()) { if (obj == holder) return false; - if (!obj->is() && - !obj->is()) + if (!obj->is()) { return false; } @@ -2573,9 +2572,6 @@ CheckHasNoSuchProperty(JSContext* cx, JSObject* obj, PropertyName* name, } else if (curObj != obj) { // Non-native objects are only handled as the original receiver. return false; - } else if (curObj->is()) { - if (curObj->as().containsUnboxedOrExpandoProperty(cx, NameToId(name))) - return false; } else if (curObj->is()) { if (curObj->as().typeDescr().hasProperty(cx->names(), NameToId(name))) return false; @@ -2840,34 +2836,15 @@ GuardReceiverObject(MacroAssembler& masm, ReceiverGuard guard, { Address groupAddress(ICStubReg, receiverGuardOffset + HeapReceiverGuard::offsetOfGroup()); Address shapeAddress(ICStubReg, receiverGuardOffset + HeapReceiverGuard::offsetOfShape()); - Address expandoAddress(object, UnboxedPlainObject::offsetOfExpando()); if (guard.group) { masm.loadPtr(groupAddress, scratch); masm.branchTestObjGroup(Assembler::NotEqual, object, scratch, failure); - - if (guard.group->clasp() == &UnboxedPlainObject::class_ && !guard.shape) { - // Guard the unboxed object has no expando object. - masm.branchPtr(Assembler::NotEqual, expandoAddress, ImmWord(0), failure); - } } if (guard.shape) { masm.loadPtr(shapeAddress, scratch); - if (guard.group && guard.group->clasp() == &UnboxedPlainObject::class_) { - // Guard the unboxed object has a matching expando object. - masm.branchPtr(Assembler::Equal, expandoAddress, ImmWord(0), failure); - Label done; - masm.push(object); - masm.loadPtr(expandoAddress, object); - masm.branchTestObjShape(Assembler::Equal, object, scratch, &done); - masm.pop(object); - masm.jump(failure); - masm.bind(&done); - masm.pop(object); - } else { - masm.branchTestObjShape(Assembler::NotEqual, object, scratch, failure); - } + masm.branchTestObjShape(Assembler::NotEqual, object, scratch, failure); } } @@ -4251,8 +4228,7 @@ DoNewObject(JSContext* cx, void* payload, ICNewObject_Fallback* stub, MutableHan return false; if (!stub->invalid() && - (templateObject->is() || - !templateObject->as().hasDynamicSlots())) + !templateObject->as().hasDynamicSlots()) { JitCode* code = GenerateNewObjectWithTemplateCode(cx, templateObject); if (!code) -- cgit v1.2.3 From c5b0e1f5e12f25613c95b0133883b774c22c8449 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Tue, 25 Jun 2019 11:15:11 +0000 Subject: Remove Unboxed Object code from /vm, Part 3. --- js/src/jsarray.cpp | 1 - js/src/jscompartment.h | 3 - js/src/jsfriendapi.cpp | 2 +- js/src/jsobj.cpp | 1 - js/src/jsobjinlines.h | 15 - js/src/moz.build | 1 - js/src/vm/Interpreter.cpp | 5 - js/src/vm/NativeObject.cpp | 27 -- js/src/vm/NativeObject.h | 5 - js/src/vm/ObjectGroup-inl.h | 14 - js/src/vm/ObjectGroup.cpp | 55 +-- js/src/vm/ObjectGroup.h | 28 +- js/src/vm/ReceiverGuard.cpp | 14 +- js/src/vm/TypeInference-inl.h | 5 - js/src/vm/TypeInference.cpp | 142 +------- js/src/vm/UnboxedObject-inl.h | 177 ---------- js/src/vm/UnboxedObject.cpp | 759 ------------------------------------------ js/src/vm/UnboxedObject.h | 319 ------------------ 18 files changed, 13 insertions(+), 1560 deletions(-) delete mode 100644 js/src/vm/UnboxedObject-inl.h delete mode 100644 js/src/vm/UnboxedObject.cpp delete mode 100644 js/src/vm/UnboxedObject.h (limited to 'js/src') diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 5854fda4c..ec65bce64 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -45,7 +45,6 @@ #include "vm/Caches-inl.h" #include "vm/Interpreter-inl.h" #include "vm/NativeObject-inl.h" -#include "vm/UnboxedObject-inl.h" using namespace js; using namespace js::gc; diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index 98c8fe200..83c15da3b 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -529,9 +529,6 @@ struct JSCompartment // table manages references from such typed objects to their buffers. js::ObjectWeakMap* lazyArrayBuffers; - // All unboxed layouts in the compartment. - mozilla::LinkedList unboxedLayouts; - // WebAssembly state for the compartment. js::wasm::Compartment wasm; diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index 1fd9d1d28..5baba0beb 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -269,7 +269,7 @@ js::GetBuiltinClass(JSContext* cx, HandleObject obj, ESClass* cls) if (MOZ_UNLIKELY(obj->is())) return Proxy::getBuiltinClass(cx, obj, cls); - if (obj->is() || obj->is()) + if (obj->is()) *cls = ESClass::Object; else if (obj->is()) *cls = ESClass::Array; diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index deaa1d53e..58988739b 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -54,7 +54,6 @@ #include "vm/RegExpStaticsObject.h" #include "vm/Shape.h" #include "vm/TypedArrayCommon.h" -#include "vm/UnboxedObject-inl.h" #include "jsatominlines.h" #include "jsboolinlines.h" diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 26f9eacce..b1d817bca 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -32,19 +32,6 @@ #include "vm/ShapedObject-inl.h" #include "vm/TypeInference-inl.h" -namespace js { - -// This is needed here for ensureShape() below. -inline bool -MaybeConvertUnboxedObjectToNative(ExclusiveContext* cx, JSObject* obj) -{ - if (obj->is()) - return UnboxedPlainObject::convertToNative(cx->asJSContext(), obj); - return true; -} - -} // namespace js - inline js::Shape* JSObject::maybeShape() const { @@ -57,8 +44,6 @@ JSObject::maybeShape() const inline js::Shape* JSObject::ensureShape(js::ExclusiveContext* cx) { - if (!js::MaybeConvertUnboxedObjectToNative(cx, this)) - return nullptr; js::Shape* shape = maybeShape(); MOZ_ASSERT(shape); return shape; diff --git a/js/src/moz.build b/js/src/moz.build index 888741138..eb30866c8 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -355,7 +355,6 @@ UNIFIED_SOURCES += [ 'vm/UbiNode.cpp', 'vm/UbiNodeCensus.cpp', 'vm/UbiNodeShortestPaths.cpp', - 'vm/UnboxedObject.cpp', 'vm/Unicode.cpp', 'vm/Value.cpp', 'vm/WeakMapPtr.cpp', diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 74a1ef3e9..0f83c3435 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -4970,11 +4970,6 @@ js::NewObjectOperationWithTemplate(JSContext* cx, HandleObject templateObject) NewObjectKind newKind = templateObject->group()->shouldPreTenure() ? TenuredObject : GenericObject; - if (templateObject->group()->maybeUnboxedLayout()) { - RootedObjectGroup group(cx, templateObject->group()); - return UnboxedPlainObject::create(cx, group, newKind); - } - JSObject* obj = CopyInitializerObject(cx, templateObject.as(), newKind); if (!obj) return nullptr; diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp index 21f73f4a9..a3f28653a 100644 --- a/js/src/vm/NativeObject.cpp +++ b/js/src/vm/NativeObject.cpp @@ -390,33 +390,6 @@ NativeObject::setLastPropertyMakeNonNative(Shape* shape) shape_ = shape; } -void -NativeObject::setLastPropertyMakeNative(ExclusiveContext* cx, Shape* shape) -{ - MOZ_ASSERT(getClass()->isNative()); - MOZ_ASSERT(shape->getObjectClass()->isNative()); - MOZ_ASSERT(!shape->inDictionary()); - - // This method is used to convert unboxed objects into native objects. In - // this case, the shape_ field was previously used to store other data and - // this should be treated as an initialization. - shape_.init(shape); - - slots_ = nullptr; - elements_ = emptyObjectElements; - - size_t oldSpan = shape->numFixedSlots(); - size_t newSpan = shape->slotSpan(); - - initializeSlotRange(0, oldSpan); - - // A failure at this point will leave the object as a mutant, and we - // can't recover. - AutoEnterOOMUnsafeRegion oomUnsafe; - if (oldSpan != newSpan && !updateSlotsForSpan(cx, oldSpan, newSpan)) - oomUnsafe.crash("NativeObject::setLastPropertyMakeNative"); -} - bool NativeObject::setSlotSpan(ExclusiveContext* cx, uint32_t span) { diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h index da4f873a6..d9d8b8aec 100644 --- a/js/src/vm/NativeObject.h +++ b/js/src/vm/NativeObject.h @@ -470,11 +470,6 @@ class NativeObject : public ShapedObject // that are (temporarily) inconsistent. void setLastPropertyMakeNonNative(Shape* shape); - // As for setLastProperty(), but changes the class associated with the - // object to a native one. The object's type has already been changed, and - // this brings the shape into sync with it. - void setLastPropertyMakeNative(ExclusiveContext* cx, Shape* shape); - // Newly-created TypedArrays that map a SharedArrayBuffer are // marked as shared by giving them an ObjectElements that has the // ObjectElements::SHARED_MEMORY flag set. diff --git a/js/src/vm/ObjectGroup-inl.h b/js/src/vm/ObjectGroup-inl.h index 9074f4d97..d41343be6 100644 --- a/js/src/vm/ObjectGroup-inl.h +++ b/js/src/vm/ObjectGroup-inl.h @@ -108,20 +108,6 @@ ObjectGroup::maybePreliminaryObjects() return maybePreliminaryObjectsDontCheckGeneration(); } -inline UnboxedLayout* -ObjectGroup::maybeUnboxedLayout() -{ - maybeSweep(nullptr); - return maybeUnboxedLayoutDontCheckGeneration(); -} - -inline UnboxedLayout& -ObjectGroup::unboxedLayout() -{ - maybeSweep(nullptr); - return unboxedLayoutDontCheckGeneration(); -} - } // namespace js #endif /* vm_ObjectGroup_inl_h */ diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp index 63ac33eea..676792379 100644 --- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -18,11 +18,10 @@ #include "vm/ArrayObject.h" #include "vm/Shape.h" #include "vm/TaggedProto.h" -#include "vm/UnboxedObject.h" #include "jsobjinlines.h" -#include "vm/UnboxedObject-inl.h" +#include "vm/NativeObject-inl.h" using namespace js; @@ -56,7 +55,6 @@ ObjectGroup::finalize(FreeOp* fop) if (newScriptDontCheckGeneration()) newScriptDontCheckGeneration()->clear(); fop->delete_(newScriptDontCheckGeneration()); - fop->delete_(maybeUnboxedLayoutDontCheckGeneration()); if (maybePreliminaryObjectsDontCheckGeneration()) maybePreliminaryObjectsDontCheckGeneration()->clear(); fop->delete_(maybePreliminaryObjectsDontCheckGeneration()); @@ -83,8 +81,6 @@ ObjectGroup::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const size_t n = 0; if (TypeNewScript* newScript = newScriptDontCheckGeneration()) n += newScript->sizeOfIncludingThis(mallocSizeOf); - if (UnboxedLayout* layout = maybeUnboxedLayoutDontCheckGeneration()) - n += layout->sizeOfIncludingThis(mallocSizeOf); return n; } @@ -530,8 +526,7 @@ ObjectGroup::defaultNewGroup(ExclusiveContext* cx, const Class* clasp, if (p) { ObjectGroup* group = p->group; MOZ_ASSERT_IF(clasp, group->clasp() == clasp); - MOZ_ASSERT_IF(!clasp, group->clasp() == &PlainObject::class_ || - group->clasp() == &UnboxedPlainObject::class_); + MOZ_ASSERT_IF(!clasp, group->clasp() == &PlainObject::class_); MOZ_ASSERT(group->proto() == proto); return group; } @@ -971,46 +966,6 @@ js::CombinePlainObjectPropertyTypes(ExclusiveContext* cx, JSObject* newObj, } } } - } else if (newObj->is()) { - const UnboxedLayout& layout = newObj->as().layout(); - const int32_t* traceList = layout.traceList(); - if (!traceList) - return true; - - uint8_t* newData = newObj->as().data(); - uint8_t* oldData = oldObj->as().data(); - - for (; *traceList != -1; traceList++) {} - traceList++; - for (; *traceList != -1; traceList++) { - JSObject* newInnerObj = *reinterpret_cast(newData + *traceList); - JSObject* oldInnerObj = *reinterpret_cast(oldData + *traceList); - - if (!newInnerObj || !oldInnerObj || SameGroup(oldInnerObj, newInnerObj)) - continue; - - if (!GiveObjectGroup(cx, newInnerObj, oldInnerObj)) - return false; - - if (SameGroup(oldInnerObj, newInnerObj)) - continue; - - if (!GiveObjectGroup(cx, oldInnerObj, newInnerObj)) - return false; - - if (SameGroup(oldInnerObj, newInnerObj)) { - for (size_t i = 1; i < ncompare; i++) { - if (compare[i].isObject() && SameGroup(&compare[i].toObject(), newObj)) { - uint8_t* otherData = compare[i].toObject().as().data(); - JSObject* otherInnerObj = *reinterpret_cast(otherData + *traceList); - if (otherInnerObj && !SameGroup(otherInnerObj, newInnerObj)) { - if (!GiveObjectGroup(cx, otherInnerObj, newInnerObj)) - return false; - } - } - } - } - } } return true; @@ -1234,12 +1189,6 @@ ObjectGroup::newPlainObject(ExclusiveContext* cx, IdValuePair* properties, size_ RootedObjectGroup group(cx, p->value().group); - // Watch for existing groups which now use an unboxed layout. - if (group->maybeUnboxedLayout()) { - MOZ_ASSERT(group->unboxedLayout().properties().length() == nproperties); - return UnboxedPlainObject::createWithProperties(cx, group, newKind, properties); - } - // Update property types according to the properties we are about to add. // Do this before we do anything which can GC, which might move or remove // this table entry. diff --git a/js/src/vm/ObjectGroup.h b/js/src/vm/ObjectGroup.h index 553cb8366..bf8398742 100644 --- a/js/src/vm/ObjectGroup.h +++ b/js/src/vm/ObjectGroup.h @@ -20,7 +20,6 @@ namespace js { class TypeDescr; -class UnboxedLayout; class PreliminaryObjectArrayWithTemplate; class TypeNewScript; @@ -154,11 +153,6 @@ class ObjectGroup : public gc::TenuredCell // For some plain objects, the addendum stores a PreliminaryObjectArrayWithTemplate. Addendum_PreliminaryObjects, - // When objects in this group have an unboxed representation, the - // addendum stores an UnboxedLayout (which might have a TypeNewScript - // as well, if the group is also constructed using 'new'). - Addendum_UnboxedLayout, - // If this group is used by objects that have been converted from an // unboxed representation and/or have the same allocation kind as such // objects, the addendum points to that unboxed group. @@ -225,24 +219,6 @@ class ObjectGroup : public gc::TenuredCell maybePreliminaryObjectsDontCheckGeneration(); } - inline UnboxedLayout* maybeUnboxedLayout(); - inline UnboxedLayout& unboxedLayout(); - - UnboxedLayout* maybeUnboxedLayoutDontCheckGeneration() const { - if (addendumKind() == Addendum_UnboxedLayout) - return reinterpret_cast(addendum_); - return nullptr; - } - - UnboxedLayout& unboxedLayoutDontCheckGeneration() const { - MOZ_ASSERT(addendumKind() == Addendum_UnboxedLayout); - return *maybeUnboxedLayoutDontCheckGeneration(); - } - - void setUnboxedLayout(UnboxedLayout* layout) { - setAddendum(Addendum_UnboxedLayout, layout); - } - ObjectGroup* maybeOriginalUnboxedGroup() const { if (addendumKind() == Addendum_OriginalUnboxedGroup) return reinterpret_cast(addendum_); @@ -511,8 +487,8 @@ class ObjectGroup : public gc::TenuredCell NewObjectKind newKind, NewArrayKind arrayKind = NewArrayKind::Normal); - // Create a PlainObject or UnboxedPlainObject with the specified properties - // and a group specialized for those properties. + // Create a PlainObject with the specified properties and a group specialized + // for those properties. static JSObject* newPlainObject(ExclusiveContext* cx, IdValuePair* properties, size_t nproperties, NewObjectKind newKind); diff --git a/js/src/vm/ReceiverGuard.cpp b/js/src/vm/ReceiverGuard.cpp index e37bf8ee5..e95e8a208 100644 --- a/js/src/vm/ReceiverGuard.cpp +++ b/js/src/vm/ReceiverGuard.cpp @@ -15,11 +15,7 @@ ReceiverGuard::ReceiverGuard(JSObject* obj) : group(nullptr), shape(nullptr) { if (obj) { - if (obj->is()) { - group = obj->group(); - if (UnboxedExpandoObject* expando = obj->as().maybeExpando()) - shape = expando->lastProperty(); - } else if (obj->is()) { + if (obj->is()) { group = obj->group(); } else { shape = obj->maybeShape(); @@ -32,9 +28,7 @@ ReceiverGuard::ReceiverGuard(ObjectGroup* group, Shape* shape) { if (group) { const Class* clasp = group->clasp(); - if (clasp == &UnboxedPlainObject::class_) { - // Keep both group and shape. - } else if (IsTypedObjectClass(clasp)) { + if (IsTypedObjectClass(clasp)) { this->shape = nullptr; } else { this->group = nullptr; @@ -45,10 +39,6 @@ ReceiverGuard::ReceiverGuard(ObjectGroup* group, Shape* shape) /* static */ int32_t HeapReceiverGuard::keyBits(JSObject* obj) { - if (obj->is()) { - // Both the group and shape need to be guarded for unboxed plain objects. - return obj->as().maybeExpando() ? 0 : 1; - } if (obj->is()) { // Only the group needs to be guarded for typed objects. return 2; diff --git a/js/src/vm/TypeInference-inl.h b/js/src/vm/TypeInference-inl.h index da47fa898..2af252cea 100644 --- a/js/src/vm/TypeInference-inl.h +++ b/js/src/vm/TypeInference-inl.h @@ -23,7 +23,6 @@ #include "vm/SharedArrayObject.h" #include "vm/StringObject.h" #include "vm/TypedArrayObject.h" -#include "vm/UnboxedObject.h" #include "jscntxtinlines.h" @@ -285,10 +284,6 @@ TypeIdString(jsid id) */ struct AutoEnterAnalysis { - // For use when initializing an UnboxedLayout. The UniquePtr's destructor - // must run when GC is not suppressed. - UniquePtr unboxedLayoutToCleanUp; - // Prevent GC activity in the middle of analysis. gc::AutoSuppressGC suppressGC; diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index 0551e2c58..26ade2948 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -35,7 +35,6 @@ #include "vm/Opcodes.h" #include "vm/Shape.h" #include "vm/Time.h" -#include "vm/UnboxedObject.h" #include "jsatominlines.h" #include "jsscriptinlines.h" @@ -297,9 +296,6 @@ js::ObjectGroupHasProperty(JSContext* cx, ObjectGroup* group, jsid id, const Val return true; } } - JSObject* obj = &value.toObject(); - if (!obj->hasLazyGroup() && obj->group()->maybeOriginalUnboxedGroup()) - return true; } if (!types->hasType(type)) { @@ -1944,33 +1940,6 @@ class ConstraintDataFreezeObjectForTypedArrayData } }; -// Constraint which triggers recompilation if an unboxed object in some group -// is converted to a native object. -class ConstraintDataFreezeObjectForUnboxedConvertedToNative -{ - public: - ConstraintDataFreezeObjectForUnboxedConvertedToNative() - {} - - const char* kind() { return "freezeObjectForUnboxedConvertedToNative"; } - - bool invalidateOnNewType(TypeSet::Type type) { return false; } - bool invalidateOnNewPropertyState(TypeSet* property) { return false; } - bool invalidateOnNewObjectState(ObjectGroup* group) { - return group->unboxedLayout().nativeGroup() != nullptr; - } - - bool constraintHolds(JSContext* cx, - const HeapTypeSetKey& property, TemporaryTypeSet* expected) - { - return !invalidateOnNewObjectState(property.object()->maybeGroup()); - } - - bool shouldSweep() { return false; } - - JSCompartment* maybeCompartment() { return nullptr; } -}; - } /* anonymous namespace */ void @@ -2505,8 +2474,6 @@ TemporaryTypeSet::propertyNeedsBarrier(CompilerConstraintList* constraints, jsid bool js::ClassCanHaveExtraProperties(const Class* clasp) { - if (clasp == &UnboxedPlainObject::class_) - return false; return clasp->getResolve() || clasp->getOpsLookupProperty() || clasp->getOpsGetProperty() @@ -2805,15 +2772,6 @@ js::AddTypePropertyId(ExclusiveContext* cx, ObjectGroup* group, JSObject* obj, j // from acquiring the fully initialized group. if (group->newScript() && group->newScript()->initializedGroup()) AddTypePropertyId(cx, group->newScript()->initializedGroup(), nullptr, id, type); - - // Maintain equivalent type information for unboxed object groups and their - // corresponding native group. Since type sets might contain the unboxed - // group but not the native group, this ensures optimizations based on the - // unboxed group are valid for the native group. - if (group->maybeUnboxedLayout() && group->maybeUnboxedLayout()->nativeGroup()) - AddTypePropertyId(cx, group->maybeUnboxedLayout()->nativeGroup(), nullptr, id, type); - if (ObjectGroup* unboxedGroup = group->maybeOriginalUnboxedGroup()) - AddTypePropertyId(cx, unboxedGroup, nullptr, id, type); } void @@ -2885,12 +2843,6 @@ ObjectGroup::setFlags(ExclusiveContext* cx, ObjectGroupFlags flags) // acquired properties analysis. if (newScript() && newScript()->initializedGroup()) newScript()->initializedGroup()->setFlags(cx, flags); - - // Propagate flag changes between unboxed and corresponding native groups. - if (maybeUnboxedLayout() && maybeUnboxedLayout()->nativeGroup()) - maybeUnboxedLayout()->nativeGroup()->setFlags(cx, flags); - if (ObjectGroup* unboxedGroup = maybeOriginalUnboxedGroup()) - unboxedGroup->setFlags(cx, flags); } void @@ -2923,13 +2875,6 @@ ObjectGroup::markUnknown(ExclusiveContext* cx) prop->types.setNonDataProperty(cx); } } - - if (ObjectGroup* unboxedGroup = maybeOriginalUnboxedGroup()) - MarkObjectGroupUnknownProperties(cx, unboxedGroup); - if (maybeUnboxedLayout() && maybeUnboxedLayout()->nativeGroup()) - MarkObjectGroupUnknownProperties(cx, maybeUnboxedLayout()->nativeGroup()); - if (ObjectGroup* unboxedGroup = maybeOriginalUnboxedGroup()) - MarkObjectGroupUnknownProperties(cx, unboxedGroup); } TypeNewScript* @@ -2937,8 +2882,6 @@ ObjectGroup::anyNewScript() { if (newScript()) return newScript(); - if (maybeUnboxedLayout()) - return unboxedLayout().newScript(); return nullptr; } @@ -2968,10 +2911,7 @@ ObjectGroup::detachNewScript(bool writeBarrier, ObjectGroup* replacement) MOZ_ASSERT(!replacement); } - if (this->newScript()) - setAddendum(Addendum_None, nullptr, writeBarrier); - else - unboxedLayout().setNewScript(nullptr, writeBarrier); + setAddendum(Addendum_None, nullptr, writeBarrier); } void @@ -3451,22 +3391,6 @@ PreliminaryObjectArray::sweep() for (size_t i = 0; i < COUNT; i++) { JSObject** ptr = &objects[i]; if (*ptr && IsAboutToBeFinalizedUnbarriered(ptr)) { - // Before we clear this reference, change the object's group to the - // Object.prototype group. This is done to ensure JSObject::finalize - // sees a NativeObject Class even if we change the current group's - // Class to one of the unboxed object classes in the meantime. If - // the compartment's global is dead, we don't do anything as the - // group's Class is not going to change in that case. - JSObject* obj = *ptr; - GlobalObject* global = obj->compartment()->unsafeUnbarrieredMaybeGlobal(); - if (global && !obj->isSingleton()) { - JSObject* objectProto = GetBuiltinPrototypePure(global, JSProto_Object); - obj->setGroup(objectProto->groupRaw()); - MOZ_ASSERT(obj->is()); - MOZ_ASSERT(obj->getClass() == objectProto->getClass()); - MOZ_ASSERT(!obj->getClass()->hasFinalize()); - } - *ptr = nullptr; } } @@ -3566,16 +3490,11 @@ PreliminaryObjectArrayWithTemplate::maybeAnalyze(ExclusiveContext* cx, ObjectGro } } - if (group->maybeUnboxedLayout()) - return; - - if (shape()) { - // We weren't able to use an unboxed layout, but since the preliminary - // objects still reflect the template object's properties, and all - // objects in the future will be created with those properties, the - // properties can be marked as definite for objects in the group. - group->addDefiniteProperties(cx, shape()); - } + // Since the preliminary objects still reflect the template object's + // properties, and all objects in the future will be created with those + // properties, the properties can be marked as definitive for objects in + // the group. + group->addDefiniteProperties(cx, shape()); } ///////////////////////////////////////////////////////////////////// @@ -3589,7 +3508,6 @@ TypeNewScript::make(JSContext* cx, ObjectGroup* group, JSFunction* fun) { MOZ_ASSERT(cx->zone()->types.activeAnalysis); MOZ_ASSERT(!group->newScript()); - MOZ_ASSERT(!group->maybeUnboxedLayout()); // rollbackPartiallyInitializedObjects expects function_ to be // canonicalized. @@ -3852,27 +3770,6 @@ TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate, js_delete(preliminaryObjects); preliminaryObjects = nullptr; - if (group->maybeUnboxedLayout()) { - // An unboxed layout was constructed for the group, and this has already - // been hooked into it. - MOZ_ASSERT(group->unboxedLayout().newScript() == this); - destroyNewScript.group = nullptr; - - // Clear out the template object, which is not used for TypeNewScripts - // with an unboxed layout. Currently it is a mutant object with a - // non-native group and native shape, so make it safe for GC by changing - // its group to the default for its prototype. - AutoEnterOOMUnsafeRegion oomUnsafe; - ObjectGroup* plainGroup = ObjectGroup::defaultNewGroup(cx, &PlainObject::class_, - group->proto()); - if (!plainGroup) - oomUnsafe.crash("TypeNewScript::maybeAnalyze"); - templateObject_->setGroup(plainGroup); - templateObject_ = nullptr; - - return true; - } - if (prefixShape->slotSpan() == templateObject()->slotSpan()) { // The definite properties analysis found exactly the properties that // are held in common by the preliminary objects. No further analysis @@ -3968,12 +3865,6 @@ TypeNewScript::rollbackPartiallyInitializedObjects(JSContext* cx, ObjectGroup* g continue; } - if (thisv.toObject().is()) { - AutoEnterOOMUnsafeRegion oomUnsafe; - if (!UnboxedPlainObject::convertToNative(cx, &thisv.toObject())) - oomUnsafe.crash("rollbackPartiallyInitializedObjects"); - } - // Found a matching frame. RootedPlainObject obj(cx, &thisv.toObject().as()); @@ -4167,12 +4058,6 @@ ConstraintTypeSet::sweep(Zone* zone, AutoClearTypeInferenceStateOnOOM& oom) // Object sets containing objects with unknown properties might // not be complete. Mark the type set as unknown, which it will // be treated as during Ion compilation. - // - // Note that we don't have to do this when the type set might - // be missing the native group corresponding to an unboxed - // object group. In this case, the native group points to the - // unboxed object group via its addendum, so as long as objects - // with either group exist, neither group will be finalized. flags |= TYPE_FLAG_ANYOBJECT; clearObjects(); objectCount = 0; @@ -4256,21 +4141,6 @@ ObjectGroup::sweep(AutoClearTypeInferenceStateOnOOM* oom) Maybe fallbackOOM; EnsureHasAutoClearTypeInferenceStateOnOOM(oom, zone(), fallbackOOM); - if (maybeUnboxedLayout()) { - // Remove unboxed layouts that are about to be finalized from the - // compartment wide list while we are still on the main thread. - ObjectGroup* group = this; - if (IsAboutToBeFinalizedUnbarriered(&group)) - unboxedLayout().detachFromCompartment(); - - if (unboxedLayout().newScript()) - unboxedLayout().newScript()->sweep(); - - // Discard constructor code to avoid holding onto ExecutablePools. - if (zone()->isGCCompacting()) - unboxedLayout().setConstructorCode(nullptr); - } - if (maybePreliminaryObjects()) maybePreliminaryObjects()->sweep(); diff --git a/js/src/vm/UnboxedObject-inl.h b/js/src/vm/UnboxedObject-inl.h deleted file mode 100644 index c1468a5b1..000000000 --- a/js/src/vm/UnboxedObject-inl.h +++ /dev/null @@ -1,177 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * 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/. */ - -#ifndef vm_UnboxedObject_inl_h -#define vm_UnboxedObject_inl_h - -#include "vm/UnboxedObject.h" - -#include "gc/StoreBuffer-inl.h" -#include "vm/ArrayObject-inl.h" -#include "vm/NativeObject-inl.h" - -namespace js { - -static inline Value -GetUnboxedValue(uint8_t* p, JSValueType type, bool maybeUninitialized) -{ - switch (type) { - case JSVAL_TYPE_BOOLEAN: - return BooleanValue(*p != 0); - - case JSVAL_TYPE_INT32: - return Int32Value(*reinterpret_cast(p)); - - case JSVAL_TYPE_DOUBLE: { - // During unboxed plain object creation, non-GC thing properties are - // left uninitialized. This is normally fine, since the properties will - // be filled in shortly, but if they are read before that happens we - // need to make sure that doubles are canonical. - double d = *reinterpret_cast(p); - if (maybeUninitialized) - return DoubleValue(JS::CanonicalizeNaN(d)); - return DoubleValue(d); - } - - case JSVAL_TYPE_STRING: - return StringValue(*reinterpret_cast(p)); - - case JSVAL_TYPE_OBJECT: - return ObjectOrNullValue(*reinterpret_cast(p)); - - default: - MOZ_CRASH("Invalid type for unboxed value"); - } -} - -static inline void -SetUnboxedValueNoTypeChange(JSObject* unboxedObject, - uint8_t* p, JSValueType type, const Value& v, - bool preBarrier) -{ - switch (type) { - case JSVAL_TYPE_BOOLEAN: - *p = v.toBoolean(); - return; - - case JSVAL_TYPE_INT32: - *reinterpret_cast(p) = v.toInt32(); - return; - - case JSVAL_TYPE_DOUBLE: - *reinterpret_cast(p) = v.toNumber(); - return; - - case JSVAL_TYPE_STRING: { - MOZ_ASSERT(!IsInsideNursery(v.toString())); - JSString** np = reinterpret_cast(p); - if (preBarrier) - JSString::writeBarrierPre(*np); - *np = v.toString(); - return; - } - - case JSVAL_TYPE_OBJECT: { - JSObject** np = reinterpret_cast(p); - - // Manually trigger post barriers on the whole object. If we treat - // the pointer as a HeapPtrObject we will get confused later if the - // object is converted to its native representation. - JSObject* obj = v.toObjectOrNull(); - if (IsInsideNursery(obj) && !IsInsideNursery(unboxedObject)) { - JSRuntime* rt = unboxedObject->runtimeFromMainThread(); - rt->gc.storeBuffer.putWholeCell(unboxedObject); - } - - if (preBarrier) - JSObject::writeBarrierPre(*np); - *np = obj; - return; - } - - default: - MOZ_CRASH("Invalid type for unboxed value"); - } -} - -static inline bool -SetUnboxedValue(ExclusiveContext* cx, JSObject* unboxedObject, jsid id, - uint8_t* p, JSValueType type, const Value& v, bool preBarrier) -{ - switch (type) { - case JSVAL_TYPE_BOOLEAN: - if (v.isBoolean()) { - *p = v.toBoolean(); - return true; - } - return false; - - case JSVAL_TYPE_INT32: - if (v.isInt32()) { - *reinterpret_cast(p) = v.toInt32(); - return true; - } - return false; - - case JSVAL_TYPE_DOUBLE: - if (v.isNumber()) { - *reinterpret_cast(p) = v.toNumber(); - return true; - } - return false; - - case JSVAL_TYPE_STRING: - if (v.isString()) { - MOZ_ASSERT(!IsInsideNursery(v.toString())); - JSString** np = reinterpret_cast(p); - if (preBarrier) - JSString::writeBarrierPre(*np); - *np = v.toString(); - return true; - } - return false; - - case JSVAL_TYPE_OBJECT: - if (v.isObjectOrNull()) { - JSObject** np = reinterpret_cast(p); - - // Update property types when writing object properties. Types for - // other properties were captured when the unboxed layout was - // created. - AddTypePropertyId(cx, unboxedObject, id, v); - - // As above, trigger post barriers on the whole object. - JSObject* obj = v.toObjectOrNull(); - if (IsInsideNursery(v.toObjectOrNull()) && !IsInsideNursery(unboxedObject)) { - JSRuntime* rt = unboxedObject->runtimeFromMainThread(); - rt->gc.storeBuffer.putWholeCell(unboxedObject); - } - - if (preBarrier) - JSObject::writeBarrierPre(*np); - *np = obj; - return true; - } - return false; - - default: - MOZ_CRASH("Invalid type for unboxed value"); - } -} - -///////////////////////////////////////////////////////////////////// -// UnboxedPlainObject -///////////////////////////////////////////////////////////////////// - -inline const UnboxedLayout& -UnboxedPlainObject::layout() const -{ - return group()->unboxedLayout(); -} - -} // namespace js - -#endif // vm_UnboxedObject_inl_h diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp deleted file mode 100644 index a96fb58a8..000000000 --- a/js/src/vm/UnboxedObject.cpp +++ /dev/null @@ -1,759 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * 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/. */ - -#include "vm/UnboxedObject-inl.h" - -#include "jit/BaselineIC.h" -#include "jit/ExecutableAllocator.h" -#include "jit/JitCommon.h" -#include "jit/Linker.h" - -#include "jsobjinlines.h" - -#include "gc/Nursery-inl.h" -#include "jit/MacroAssembler-inl.h" -#include "vm/Shape-inl.h" - -using mozilla::ArrayLength; -using mozilla::DebugOnly; -using mozilla::PodCopy; - -using namespace js; - -///////////////////////////////////////////////////////////////////// -// UnboxedLayout -///////////////////////////////////////////////////////////////////// - -void -UnboxedLayout::trace(JSTracer* trc) -{ - for (size_t i = 0; i < properties_.length(); i++) - TraceManuallyBarrieredEdge(trc, &properties_[i].name, "unboxed_layout_name"); - - if (newScript()) - newScript()->trace(trc); - - TraceNullableEdge(trc, &nativeGroup_, "unboxed_layout_nativeGroup"); - TraceNullableEdge(trc, &nativeShape_, "unboxed_layout_nativeShape"); - TraceNullableEdge(trc, &allocationScript_, "unboxed_layout_allocationScript"); - TraceNullableEdge(trc, &replacementGroup_, "unboxed_layout_replacementGroup"); - TraceNullableEdge(trc, &constructorCode_, "unboxed_layout_constructorCode"); -} - -size_t -UnboxedLayout::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) -{ - return mallocSizeOf(this) - + properties_.sizeOfExcludingThis(mallocSizeOf) - + (newScript() ? newScript()->sizeOfIncludingThis(mallocSizeOf) : 0) - + mallocSizeOf(traceList()); -} - -void -UnboxedLayout::setNewScript(TypeNewScript* newScript, bool writeBarrier /* = true */) -{ - if (newScript_ && writeBarrier) - TypeNewScript::writeBarrierPre(newScript_); - newScript_ = newScript; -} - -// Constructor code returns a 0x1 value to indicate the constructor code should -// be cleared. -static const uintptr_t CLEAR_CONSTRUCTOR_CODE_TOKEN = 0x1; - -/* static */ bool -UnboxedLayout::makeConstructorCode(JSContext* cx, HandleObjectGroup group) -{ - // *** STUB *** - return false; -} - -void -UnboxedLayout::detachFromCompartment() -{ - if (isInList()) - remove(); -} - -///////////////////////////////////////////////////////////////////// -// UnboxedPlainObject -///////////////////////////////////////////////////////////////////// - -bool -UnboxedPlainObject::setValue(ExclusiveContext* cx, const UnboxedLayout::Property& property, - const Value& v) -{ - uint8_t* p = &data_[property.offset]; - return SetUnboxedValue(cx, this, NameToId(property.name), p, property.type, v, - /* preBarrier = */ true); -} - -Value -UnboxedPlainObject::getValue(const UnboxedLayout::Property& property, - bool maybeUninitialized /* = false */) -{ - uint8_t* p = &data_[property.offset]; - return GetUnboxedValue(p, property.type, maybeUninitialized); -} - -void -UnboxedPlainObject::trace(JSTracer* trc, JSObject* obj) -{ - if (obj->as().expando_) { - TraceManuallyBarrieredEdge(trc, - reinterpret_cast(&obj->as().expando_), - "unboxed_expando"); - } - - const UnboxedLayout& layout = obj->as().layoutDontCheckGeneration(); - const int32_t* list = layout.traceList(); - if (!list) - return; - - uint8_t* data = obj->as().data(); - while (*list != -1) { - GCPtrString* heap = reinterpret_cast(data + *list); - TraceEdge(trc, heap, "unboxed_string"); - list++; - } - list++; - while (*list != -1) { - GCPtrObject* heap = reinterpret_cast(data + *list); - TraceNullableEdge(trc, heap, "unboxed_object"); - list++; - } - - // Unboxed objects don't have Values to trace. - MOZ_ASSERT(*(list + 1) == -1); -} - -/* static */ UnboxedExpandoObject* -UnboxedPlainObject::ensureExpando(JSContext* cx, Handle obj) -{ - if (obj->expando_) - return obj->expando_; - - UnboxedExpandoObject* expando = - NewObjectWithGivenProto(cx, nullptr, gc::AllocKind::OBJECT4); - if (!expando) - return nullptr; - - // Don't track property types for expando objects. This allows Baseline - // and Ion AddSlot ICs to guard on the unboxed group without guarding on - // the expando group. - MarkObjectGroupUnknownProperties(cx, expando->group()); - - // If the expando is tenured then the original object must also be tenured. - // Otherwise barriers triggered on the original object for writes to the - // expando (as can happen in the JIT) won't see the tenured->nursery edge. - // See WholeCellEdges::mark. - MOZ_ASSERT_IF(!IsInsideNursery(expando), !IsInsideNursery(obj)); - - // As with setValue(), we need to manually trigger post barriers on the - // whole object. If we treat the field as a GCPtrObject and later - // convert the object to its native representation, we will end up with a - // corrupted store buffer entry. - if (IsInsideNursery(expando) && !IsInsideNursery(obj)) - cx->runtime()->gc.storeBuffer.putWholeCell(obj); - - obj->expando_ = expando; - return expando; -} - -bool -UnboxedPlainObject::containsUnboxedOrExpandoProperty(ExclusiveContext* cx, jsid id) const -{ - if (layout().lookup(id)) - return true; - - if (maybeExpando() && maybeExpando()->containsShapeOrElement(cx, id)) - return true; - - return false; -} - -static bool -PropagatePropertyTypes(JSContext* cx, jsid id, ObjectGroup* oldGroup, ObjectGroup* newGroup) -{ - HeapTypeSet* typeProperty = oldGroup->maybeGetProperty(id); - TypeSet::TypeList types; - if (!typeProperty->enumerateTypes(&types)) { - ReportOutOfMemory(cx); - return false; - } - for (size_t j = 0; j < types.length(); j++) - AddTypePropertyId(cx, newGroup, nullptr, id, types[j]); - return true; -} - -static PlainObject* -MakeReplacementTemplateObject(JSContext* cx, HandleObjectGroup group, const UnboxedLayout &layout) -{ - PlainObject* obj = NewObjectWithGroup(cx, group, layout.getAllocKind(), - TenuredObject); - if (!obj) - return nullptr; - - for (size_t i = 0; i < layout.properties().length(); i++) { - const UnboxedLayout::Property& property = layout.properties()[i]; - if (!obj->addDataProperty(cx, NameToId(property.name), i, JSPROP_ENUMERATE)) - return nullptr; - MOZ_ASSERT(obj->slotSpan() == i + 1); - MOZ_ASSERT(!obj->inDictionaryMode()); - } - - return obj; -} - -/* static */ bool -UnboxedLayout::makeNativeGroup(JSContext* cx, ObjectGroup* group) -{ - AutoEnterAnalysis enter(cx); - - UnboxedLayout& layout = group->unboxedLayout(); - Rooted proto(cx, group->proto()); - - MOZ_ASSERT(!layout.nativeGroup()); - - RootedObjectGroup replacementGroup(cx); - - // Immediately clear any new script on the group. This is done by replacing - // the existing new script with one for a replacement default new group. - // This is done so that the size of the replacment group's objects is the - // same as that for the unboxed group, so that we do not see polymorphic - // slot accesses later on for sites that see converted objects from this - // group and objects that were allocated using the replacement new group. - if (layout.newScript()) { - replacementGroup = ObjectGroupCompartment::makeGroup(cx, &PlainObject::class_, proto); - if (!replacementGroup) - return false; - - PlainObject* templateObject = MakeReplacementTemplateObject(cx, replacementGroup, layout); - if (!templateObject) - return false; - - TypeNewScript* replacementNewScript = - TypeNewScript::makeNativeVersion(cx, layout.newScript(), templateObject); - if (!replacementNewScript) - return false; - - replacementGroup->setNewScript(replacementNewScript); - gc::TraceTypeNewScript(replacementGroup); - - group->clearNewScript(cx, replacementGroup); - } - - // Similarly, if this group is keyed to an allocation site, replace its - // entry with a new group that has no unboxed layout. - if (layout.allocationScript()) { - RootedScript script(cx, layout.allocationScript()); - jsbytecode* pc = layout.allocationPc(); - - replacementGroup = ObjectGroupCompartment::makeGroup(cx, &PlainObject::class_, proto); - if (!replacementGroup) - return false; - - PlainObject* templateObject = &script->getObject(pc)->as(); - replacementGroup->addDefiniteProperties(cx, templateObject->lastProperty()); - - cx->compartment()->objectGroups.replaceAllocationSiteGroup(script, pc, JSProto_Object, - replacementGroup); - - // Clear any baseline information at this opcode which might use the old group. - if (script->hasBaselineScript()) { - jit::ICEntry& entry = script->baselineScript()->icEntryFromPCOffset(script->pcToOffset(pc)); - jit::ICFallbackStub* fallback = entry.fallbackStub(); - for (jit::ICStubIterator iter = fallback->beginChain(); !iter.atEnd(); iter++) - iter.unlink(cx); - if (fallback->isNewObject_Fallback()) - fallback->toNewObject_Fallback()->setTemplateObject(nullptr); - else if (fallback->isNewArray_Fallback()) - fallback->toNewArray_Fallback()->setTemplateGroup(replacementGroup); - } - } - - size_t nfixed = gc::GetGCKindSlots(layout.getAllocKind()); - - RootedShape shape(cx, EmptyShape::getInitialShape(cx, &PlainObject::class_, proto, nfixed, 0)); - if (!shape) - return false; - - // Add shapes for each property, if this is for a plain object. - for (size_t i = 0; i < layout.properties().length(); i++) { - const UnboxedLayout::Property& property = layout.properties()[i]; - - Rooted child(cx, StackShape(shape->base()->unowned(), NameToId(property.name), - i, JSPROP_ENUMERATE, 0)); - shape = cx->zone()->propertyTree.getChild(cx, shape, child); - if (!shape) - return false; - } - - ObjectGroup* nativeGroup = - ObjectGroupCompartment::makeGroup(cx, &PlainObject::class_, proto, - group->flags() & OBJECT_FLAG_DYNAMIC_MASK); - if (!nativeGroup) - return false; - - // No sense propagating if we don't know what we started with. - if (!group->unknownProperties()) { - // Propagate all property types from the old group to the new group. - for (size_t i = 0; i < layout.properties().length(); i++) { - const UnboxedLayout::Property& property = layout.properties()[i]; - jsid id = NameToId(property.name); - if (!PropagatePropertyTypes(cx, id, group, nativeGroup)) - return false; - - // If we are OOM we may not be able to propagate properties. - if (nativeGroup->unknownProperties()) - break; - - HeapTypeSet* nativeProperty = nativeGroup->maybeGetProperty(id); - if (nativeProperty && nativeProperty->canSetDefinite(i)) - nativeProperty->setDefinite(i); - } - } else { - // If we skip, though, the new group had better agree. - MOZ_ASSERT(nativeGroup->unknownProperties()); - } - - layout.nativeGroup_ = nativeGroup; - layout.nativeShape_ = shape; - layout.replacementGroup_ = replacementGroup; - - nativeGroup->setOriginalUnboxedGroup(group); - - group->markStateChange(cx); - - return true; -} - -/* static */ bool -UnboxedPlainObject::convertToNative(JSContext* cx, JSObject* obj) -{ - const UnboxedLayout& layout = obj->as().layout(); - UnboxedExpandoObject* expando = obj->as().maybeExpando(); - - if (!layout.nativeGroup()) { - if (!UnboxedLayout::makeNativeGroup(cx, obj->group())) - return false; - - // makeNativeGroup can reentrantly invoke this method. - if (obj->is()) - return true; - } - - AutoValueVector values(cx); - for (size_t i = 0; i < layout.properties().length(); i++) { - // We might be reading properties off the object which have not been - // initialized yet. Make sure any double values we read here are - // canonicalized. - if (!values.append(obj->as().getValue(layout.properties()[i], true))) - return false; - } - - // We are eliminating the expando edge with the conversion, so trigger a - // pre barrier. - JSObject::writeBarrierPre(expando); - - // Additionally trigger a post barrier on the expando itself. Whole cell - // store buffer entries can be added on the original unboxed object for - // writes to the expando (see WholeCellEdges::trace), so after conversion - // we need to make sure the expando itself will still be traced. - if (expando && !IsInsideNursery(expando)) - cx->runtime()->gc.storeBuffer.putWholeCell(expando); - - obj->setGroup(layout.nativeGroup()); - obj->as().setLastPropertyMakeNative(cx, layout.nativeShape()); - - for (size_t i = 0; i < values.length(); i++) - obj->as().initSlotUnchecked(i, values[i]); - - if (expando) { - // Add properties from the expando object to the object, in order. - // Suppress GC here, so that callers don't need to worry about this - // method collecting. The stuff below can only fail due to OOM, in - // which case the object will not have been completely filled back in. - gc::AutoSuppressGC suppress(cx); - - Vector ids(cx); - for (Shape::Range r(expando->lastProperty()); !r.empty(); r.popFront()) { - if (!ids.append(r.front().propid())) - return false; - } - for (size_t i = 0; i < expando->getDenseInitializedLength(); i++) { - if (!expando->getDenseElement(i).isMagic(JS_ELEMENTS_HOLE)) { - if (!ids.append(INT_TO_JSID(i))) - return false; - } - } - ::Reverse(ids.begin(), ids.end()); - - RootedPlainObject nobj(cx, &obj->as()); - Rooted nexpando(cx, expando); - RootedId id(cx); - Rooted desc(cx); - for (size_t i = 0; i < ids.length(); i++) { - id = ids[i]; - if (!GetOwnPropertyDescriptor(cx, nexpando, id, &desc)) - return false; - ObjectOpResult result; - if (!DefineProperty(cx, nobj, id, desc, result)) - return false; - MOZ_ASSERT(result.ok()); - } - } - - return true; -} - -/* static */ -UnboxedPlainObject* -UnboxedPlainObject::create(ExclusiveContext* cx, HandleObjectGroup group, NewObjectKind newKind) -{ - AutoSetNewObjectMetadata metadata(cx); - - MOZ_ASSERT(group->clasp() == &class_); - gc::AllocKind allocKind = group->unboxedLayout().getAllocKind(); - - UnboxedPlainObject* res = - NewObjectWithGroup(cx, group, allocKind, newKind); - if (!res) - return nullptr; - - // Overwrite the dummy shape which was written to the object's expando field. - res->initExpando(); - - // Initialize reference fields of the object. All fields in the object will - // be overwritten shortly, but references need to be safe for the GC. - const int32_t* list = res->layout().traceList(); - if (list) { - uint8_t* data = res->data(); - while (*list != -1) { - GCPtrString* heap = reinterpret_cast(data + *list); - heap->init(cx->names().empty); - list++; - } - list++; - while (*list != -1) { - GCPtrObject* heap = reinterpret_cast(data + *list); - heap->init(nullptr); - list++; - } - // Unboxed objects don't have Values to initialize. - MOZ_ASSERT(*(list + 1) == -1); - } - - return res; -} - -/* static */ JSObject* -UnboxedPlainObject::createWithProperties(ExclusiveContext* cx, HandleObjectGroup group, - NewObjectKind newKind, IdValuePair* properties) -{ - MOZ_ASSERT(newKind == GenericObject || newKind == TenuredObject); - - UnboxedLayout& layout = group->unboxedLayout(); - - if (layout.constructorCode()) { - MOZ_ASSERT(cx->isJSContext()); - - typedef JSObject* (*ConstructorCodeSignature)(IdValuePair*, NewObjectKind); - ConstructorCodeSignature function = - reinterpret_cast(layout.constructorCode()->raw()); - - JSObject* obj; - { - JS::AutoSuppressGCAnalysis nogc; - obj = reinterpret_cast(CALL_GENERATED_2(function, properties, newKind)); - } - if (obj > reinterpret_cast(CLEAR_CONSTRUCTOR_CODE_TOKEN)) - return obj; - - if (obj == reinterpret_cast(CLEAR_CONSTRUCTOR_CODE_TOKEN)) - layout.setConstructorCode(nullptr); - } - - UnboxedPlainObject* obj = UnboxedPlainObject::create(cx, group, newKind); - if (!obj) - return nullptr; - - for (size_t i = 0; i < layout.properties().length(); i++) { - if (!obj->setValue(cx, layout.properties()[i], properties[i].value)) - return NewPlainObjectWithProperties(cx, properties, layout.properties().length(), newKind); - } - -#ifndef JS_CODEGEN_NONE - if (cx->isJSContext() && - !group->unknownProperties() && - !layout.constructorCode() && - cx->asJSContext()->runtime()->jitSupportsFloatingPoint && - jit::CanLikelyAllocateMoreExecutableMemory()) - { - if (!UnboxedLayout::makeConstructorCode(cx->asJSContext(), group)) - return nullptr; - } -#endif - - return obj; -} - -/* static */ bool -UnboxedPlainObject::obj_lookupProperty(JSContext* cx, HandleObject obj, - HandleId id, MutableHandleObject objp, - MutableHandleShape propp) -{ - if (obj->as().containsUnboxedOrExpandoProperty(cx, id)) { - MarkNonNativePropertyFound(propp); - objp.set(obj); - return true; - } - - RootedObject proto(cx, obj->staticPrototype()); - if (!proto) { - objp.set(nullptr); - propp.set(nullptr); - return true; - } - - return LookupProperty(cx, proto, id, objp, propp); -} - -/* static */ bool -UnboxedPlainObject::obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id, - Handle desc, - ObjectOpResult& result) -{ - const UnboxedLayout& layout = obj->as().layout(); - - if (const UnboxedLayout::Property* property = layout.lookup(id)) { - if (!desc.getter() && !desc.setter() && desc.attributes() == JSPROP_ENUMERATE) { - // This define is equivalent to setting an existing property. - if (obj->as().setValue(cx, *property, desc.value())) - return result.succeed(); - } - - // Trying to incompatibly redefine an existing property requires the - // object to be converted to a native object. - if (!convertToNative(cx, obj)) - return false; - - return DefineProperty(cx, obj, id, desc, result); - } - - // Define the property on the expando object. - Rooted expando(cx, ensureExpando(cx, obj.as())); - if (!expando) - return false; - - // Update property types on the unboxed object as well. - AddTypePropertyId(cx, obj, id, desc.value()); - - return DefineProperty(cx, expando, id, desc, result); -} - -/* static */ bool -UnboxedPlainObject::obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp) -{ - if (obj->as().containsUnboxedOrExpandoProperty(cx, id)) { - *foundp = true; - return true; - } - - RootedObject proto(cx, obj->staticPrototype()); - if (!proto) { - *foundp = false; - return true; - } - - return HasProperty(cx, proto, id, foundp); -} - -/* static */ bool -UnboxedPlainObject::obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver, - HandleId id, MutableHandleValue vp) -{ - const UnboxedLayout& layout = obj->as().layout(); - - if (const UnboxedLayout::Property* property = layout.lookup(id)) { - vp.set(obj->as().getValue(*property)); - return true; - } - - if (UnboxedExpandoObject* expando = obj->as().maybeExpando()) { - if (expando->containsShapeOrElement(cx, id)) { - RootedObject nexpando(cx, expando); - return GetProperty(cx, nexpando, receiver, id, vp); - } - } - - RootedObject proto(cx, obj->staticPrototype()); - if (!proto) { - vp.setUndefined(); - return true; - } - - return GetProperty(cx, proto, receiver, id, vp); -} - -/* static */ bool -UnboxedPlainObject::obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v, - HandleValue receiver, ObjectOpResult& result) -{ - const UnboxedLayout& layout = obj->as().layout(); - - if (const UnboxedLayout::Property* property = layout.lookup(id)) { - if (receiver.isObject() && obj == &receiver.toObject()) { - if (obj->as().setValue(cx, *property, v)) - return result.succeed(); - - if (!convertToNative(cx, obj)) - return false; - return SetProperty(cx, obj, id, v, receiver, result); - } - - return SetPropertyByDefining(cx, id, v, receiver, result); - } - - if (UnboxedExpandoObject* expando = obj->as().maybeExpando()) { - if (expando->containsShapeOrElement(cx, id)) { - // Update property types on the unboxed object as well. - AddTypePropertyId(cx, obj, id, v); - - RootedObject nexpando(cx, expando); - return SetProperty(cx, nexpando, id, v, receiver, result); - } - } - - return SetPropertyOnProto(cx, obj, id, v, receiver, result); -} - -/* static */ bool -UnboxedPlainObject::obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id, - MutableHandle desc) -{ - const UnboxedLayout& layout = obj->as().layout(); - - if (const UnboxedLayout::Property* property = layout.lookup(id)) { - desc.value().set(obj->as().getValue(*property)); - desc.setAttributes(JSPROP_ENUMERATE); - desc.object().set(obj); - return true; - } - - if (UnboxedExpandoObject* expando = obj->as().maybeExpando()) { - if (expando->containsShapeOrElement(cx, id)) { - RootedObject nexpando(cx, expando); - if (!GetOwnPropertyDescriptor(cx, nexpando, id, desc)) - return false; - if (desc.object() == nexpando) - desc.object().set(obj); - return true; - } - } - - desc.object().set(nullptr); - return true; -} - -/* static */ bool -UnboxedPlainObject::obj_deleteProperty(JSContext* cx, HandleObject obj, HandleId id, - ObjectOpResult& result) -{ - if (!convertToNative(cx, obj)) - return false; - return DeleteProperty(cx, obj, id, result); -} - -/* static */ bool -UnboxedPlainObject::obj_watch(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable) -{ - if (!convertToNative(cx, obj)) - return false; - return WatchProperty(cx, obj, id, callable); -} - -/* static */ bool -UnboxedPlainObject::obj_enumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties, - bool enumerableOnly) -{ - // Ignore expando properties here, they are special-cased by the property - // enumeration code. - - const UnboxedLayout::PropertyVector& unboxed = obj->as().layout().properties(); - for (size_t i = 0; i < unboxed.length(); i++) { - if (!properties.append(NameToId(unboxed[i].name))) - return false; - } - - return true; -} - -const Class UnboxedExpandoObject::class_ = { - "UnboxedExpandoObject", - 0 -}; - -static const ClassOps UnboxedPlainObjectClassOps = { - nullptr, /* addProperty */ - nullptr, /* delProperty */ - nullptr, /* getProperty */ - nullptr, /* setProperty */ - nullptr, /* enumerate */ - nullptr, /* resolve */ - nullptr, /* mayResolve */ - nullptr, /* finalize */ - nullptr, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - UnboxedPlainObject::trace, -}; - -static const ObjectOps UnboxedPlainObjectObjectOps = { - UnboxedPlainObject::obj_lookupProperty, - UnboxedPlainObject::obj_defineProperty, - UnboxedPlainObject::obj_hasProperty, - UnboxedPlainObject::obj_getProperty, - UnboxedPlainObject::obj_setProperty, - UnboxedPlainObject::obj_getOwnPropertyDescriptor, - UnboxedPlainObject::obj_deleteProperty, - UnboxedPlainObject::obj_watch, - nullptr, /* No unwatch needed, as watch() converts the object to native */ - nullptr, /* getElements */ - UnboxedPlainObject::obj_enumerate, - nullptr /* funToString */ -}; - -const Class UnboxedPlainObject::class_ = { - js_Object_str, - Class::NON_NATIVE | - JSCLASS_HAS_CACHED_PROTO(JSProto_Object) | - JSCLASS_DELAY_METADATA_BUILDER, - &UnboxedPlainObjectClassOps, - JS_NULL_CLASS_SPEC, - JS_NULL_CLASS_EXT, - &UnboxedPlainObjectObjectOps -}; - -///////////////////////////////////////////////////////////////////// -// API -///////////////////////////////////////////////////////////////////// - -static inline Value -NextValue(Handle> values, size_t* valueCursor) -{ - return values[(*valueCursor)++]; -} - -void -UnboxedPlainObject::fillAfterConvert(ExclusiveContext* cx, - Handle> values, size_t* valueCursor) -{ - initExpando(); - memset(data(), 0, layout().size()); - for (size_t i = 0; i < layout().properties().length(); i++) - JS_ALWAYS_TRUE(setValue(cx, layout().properties()[i], NextValue(values, valueCursor))); -} diff --git a/js/src/vm/UnboxedObject.h b/js/src/vm/UnboxedObject.h deleted file mode 100644 index ba66434bc..000000000 --- a/js/src/vm/UnboxedObject.h +++ /dev/null @@ -1,319 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * 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/. */ - -#ifndef vm_UnboxedObject_h -#define vm_UnboxedObject_h - -#include "jsgc.h" -#include "jsobj.h" - -#include "vm/Runtime.h" -#include "vm/TypeInference.h" - -namespace js { - -// Memory required for an unboxed value of a given type. Returns zero for types -// which can't be used for unboxed objects. -static inline size_t -UnboxedTypeSize(JSValueType type) -{ - switch (type) { - case JSVAL_TYPE_BOOLEAN: return 1; - case JSVAL_TYPE_INT32: return 4; - case JSVAL_TYPE_DOUBLE: return 8; - case JSVAL_TYPE_STRING: return sizeof(void*); - case JSVAL_TYPE_OBJECT: return sizeof(void*); - default: return 0; - } -} - -static inline bool -UnboxedTypeNeedsPreBarrier(JSValueType type) -{ - return type == JSVAL_TYPE_STRING || type == JSVAL_TYPE_OBJECT; -} - -static inline bool -UnboxedTypeNeedsPostBarrier(JSValueType type) -{ - return type == JSVAL_TYPE_OBJECT; -} - -// Class tracking information specific to unboxed objects. -class UnboxedLayout : public mozilla::LinkedListElement -{ - public: - struct Property { - PropertyName* name; - uint32_t offset; - JSValueType type; - - Property() - : name(nullptr), offset(UINT32_MAX), type(JSVAL_TYPE_MAGIC) - {} - }; - - typedef Vector PropertyVector; - - private: - // If objects in this group have ever been converted to native objects, - // these store the corresponding native group and initial shape for such - // objects. Type information for this object is reflected in nativeGroup. - GCPtrObjectGroup nativeGroup_; - GCPtrShape nativeShape_; - - // Any script/pc which the associated group is created for. - GCPtrScript allocationScript_; - jsbytecode* allocationPc_; - - // If nativeGroup is set and this object originally had a TypeNewScript or - // was keyed to an allocation site, this points to the group which replaced - // this one. This link is only needed to keep the replacement group from - // being GC'ed. If it were GC'ed and a new one regenerated later, that new - // group might have a different allocation kind from this group. - GCPtrObjectGroup replacementGroup_; - - // The following members are only used for unboxed plain objects. - - // All properties on objects with this layout, in enumeration order. - PropertyVector properties_; - - // Byte size of the data for objects with this layout. - size_t size_; - - // Any 'new' script information associated with this layout. - TypeNewScript* newScript_; - - // List for use in tracing objects with this layout. This has the same - // structure as the trace list on a TypeDescr. - int32_t* traceList_; - - // If this layout has been used to construct script or JSON constant - // objects, this code might be filled in to more quickly fill in objects - // from an array of values. - GCPtrJitCode constructorCode_; - - public: - UnboxedLayout() - : nativeGroup_(nullptr), nativeShape_(nullptr), - allocationScript_(nullptr), allocationPc_(nullptr), replacementGroup_(nullptr), - size_(0), newScript_(nullptr), traceList_(nullptr), constructorCode_(nullptr) - {} - - bool initProperties(const PropertyVector& properties, size_t size) { - size_ = size; - return properties_.appendAll(properties); - } - - ~UnboxedLayout() { - if (newScript_) - newScript_->clear(); - js_delete(newScript_); - js_free(traceList_); - - nativeGroup_.init(nullptr); - nativeShape_.init(nullptr); - replacementGroup_.init(nullptr); - constructorCode_.init(nullptr); - } - - void detachFromCompartment(); - - const PropertyVector& properties() const { - return properties_; - } - - TypeNewScript* newScript() const { - return newScript_; - } - - void setNewScript(TypeNewScript* newScript, bool writeBarrier = true); - - JSScript* allocationScript() const { - return allocationScript_; - } - - jsbytecode* allocationPc() const { - return allocationPc_; - } - - void setAllocationSite(JSScript* script, jsbytecode* pc) { - allocationScript_ = script; - allocationPc_ = pc; - } - - const int32_t* traceList() const { - return traceList_; - } - - void setTraceList(int32_t* traceList) { - traceList_ = traceList; - } - - const Property* lookup(JSAtom* atom) const { - for (size_t i = 0; i < properties_.length(); i++) { - if (properties_[i].name == atom) - return &properties_[i]; - } - return nullptr; - } - - const Property* lookup(jsid id) const { - if (JSID_IS_STRING(id)) - return lookup(JSID_TO_ATOM(id)); - return nullptr; - } - - size_t size() const { - return size_; - } - - ObjectGroup* nativeGroup() const { - return nativeGroup_; - } - - Shape* nativeShape() const { - return nativeShape_; - } - - jit::JitCode* constructorCode() const { - return constructorCode_; - } - - void setConstructorCode(jit::JitCode* code) { - constructorCode_ = code; - } - - inline gc::AllocKind getAllocKind() const; - - void trace(JSTracer* trc); - - size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf); - - static bool makeNativeGroup(JSContext* cx, ObjectGroup* group); - static bool makeConstructorCode(JSContext* cx, HandleObjectGroup group); -}; - -// Class for expando objects holding extra properties given to an unboxed plain -// object. These objects behave identically to normal native plain objects, and -// have a separate Class to distinguish them for memory usage reporting. -class UnboxedExpandoObject : public NativeObject -{ - public: - static const Class class_; -}; - -// Class for a plain object using an unboxed representation. The physical -// layout of these objects is identical to that of an InlineTypedObject, though -// these objects use an UnboxedLayout instead of a TypeDescr to keep track of -// how their properties are stored. -class UnboxedPlainObject : public JSObject -{ - // Optional object which stores extra properties on this object. This is - // not automatically barriered to avoid problems if the object is converted - // to a native. See ensureExpando(). - UnboxedExpandoObject* expando_; - - // Start of the inline data, which immediately follows the group and extra properties. - uint8_t data_[1]; - - public: - static const Class class_; - - static bool obj_lookupProperty(JSContext* cx, HandleObject obj, - HandleId id, MutableHandleObject objp, - MutableHandleShape propp); - - static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id, - Handle desc, - ObjectOpResult& result); - - static bool obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp); - - static bool obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver, - HandleId id, MutableHandleValue vp); - - static bool obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v, - HandleValue receiver, ObjectOpResult& result); - - static bool obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id, - MutableHandle desc); - - static bool obj_deleteProperty(JSContext* cx, HandleObject obj, HandleId id, - ObjectOpResult& result); - - static bool obj_enumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties, - bool enumerableOnly); - static bool obj_watch(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable); - - inline const UnboxedLayout& layout() const; - - const UnboxedLayout& layoutDontCheckGeneration() const { - return group()->unboxedLayoutDontCheckGeneration(); - } - - uint8_t* data() { - return &data_[0]; - } - - UnboxedExpandoObject* maybeExpando() const { - return expando_; - } - - void initExpando() { - expando_ = nullptr; - } - - // For use during GC. - JSObject** addressOfExpando() { - return reinterpret_cast(&expando_); - } - - bool containsUnboxedOrExpandoProperty(ExclusiveContext* cx, jsid id) const; - - static UnboxedExpandoObject* ensureExpando(JSContext* cx, Handle obj); - - bool setValue(ExclusiveContext* cx, const UnboxedLayout::Property& property, const Value& v); - Value getValue(const UnboxedLayout::Property& property, bool maybeUninitialized = false); - - static bool convertToNative(JSContext* cx, JSObject* obj); - static UnboxedPlainObject* create(ExclusiveContext* cx, HandleObjectGroup group, - NewObjectKind newKind); - static JSObject* createWithProperties(ExclusiveContext* cx, HandleObjectGroup group, - NewObjectKind newKind, IdValuePair* properties); - - void fillAfterConvert(ExclusiveContext* cx, - Handle> values, size_t* valueCursor); - - static void trace(JSTracer* trc, JSObject* object); - - static size_t offsetOfExpando() { - return offsetof(UnboxedPlainObject, expando_); - } - - static size_t offsetOfData() { - return offsetof(UnboxedPlainObject, data_[0]); - } -}; - -inline gc::AllocKind -UnboxedLayout::getAllocKind() const -{ - MOZ_ASSERT(size()); - return gc::GetGCObjectKindForBytes(UnboxedPlainObject::offsetOfData() + size()); -} - -} // namespace js - -namespace JS { - -template <> -struct DeletePolicy : public js::GCManagedDeletePolicy -{}; - -} /* namespace JS */ - -#endif /* vm_UnboxedObject_h */ -- cgit v1.2.3 From 1cf7e63d993b0f41aecc3af7e0cd759c8b067df4 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Tue, 25 Jun 2019 20:13:11 +0000 Subject: Remove Unboxed Objects Option Code --- js/src/jit/JitOptions.cpp | 3 --- js/src/jit/JitOptions.h | 3 --- js/src/shell/js.cpp | 2 -- 3 files changed, 8 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/JitOptions.cpp b/js/src/jit/JitOptions.cpp index b9a7c7b27..3f9d9db88 100644 --- a/js/src/jit/JitOptions.cpp +++ b/js/src/jit/JitOptions.cpp @@ -221,9 +221,6 @@ DefaultJitOptions::DefaultJitOptions() Warn(forcedRegisterAllocatorEnv, env); } - // Toggles whether unboxed plain objects can be created by the VM. - SET_DEFAULT(disableUnboxedObjects, true); - // Test whether Atomics are allowed in asm.js code. SET_DEFAULT(asmJSAtomicsEnable, false); diff --git a/js/src/jit/JitOptions.h b/js/src/jit/JitOptions.h index 076980b4e..719ee14d9 100644 --- a/js/src/jit/JitOptions.h +++ b/js/src/jit/JitOptions.h @@ -91,9 +91,6 @@ struct DefaultJitOptions mozilla::Maybe forcedDefaultIonSmallFunctionWarmUpThreshold; mozilla::Maybe forcedRegisterAllocator; - // The options below affect the rest of the VM, and not just the JIT. - bool disableUnboxedObjects; - DefaultJitOptions(); bool isSmallFunction(JSScript* script) const; void setEagerCompilation(); diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 29cbd9762..617b5e902 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -7536,7 +7536,6 @@ SetWorkerContextOptions(JSContext* cx) .setWasm(enableWasm) .setWasmAlwaysBaseline(enableWasmAlwaysBaseline) .setNativeRegExp(enableNativeRegExp) - .setUnboxedArrays(enableUnboxedArrays) .setArrayProtoValues(enableArrayProtoValues); cx->setOffthreadIonCompilationEnabled(offthreadCompilation); cx->profilingScripts = enableCodeCoverage || enableDisassemblyDumps; @@ -7706,7 +7705,6 @@ main(int argc, char** argv, char** envp) || !op.addBoolOption('\0', "no-asmjs", "Disable asm.js compilation") || !op.addBoolOption('\0', "no-wasm", "Disable WebAssembly compilation") || !op.addBoolOption('\0', "no-native-regexp", "Disable native regexp compilation") - || !op.addBoolOption('\0', "no-unboxed-objects", "Disable creating unboxed plain objects") || !op.addBoolOption('\0', "wasm-always-baseline", "Enable wasm baseline compiler when possible") || !op.addBoolOption('\0', "wasm-check-bce", "Always generate wasm bounds check, even redundant ones.") || !op.addBoolOption('\0', "no-array-proto-values", "Remove Array.prototype.values") -- cgit v1.2.3 From 083d840f32e6cee08c709408160dcbc802b600fc Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Tue, 25 Jun 2019 20:18:14 +0000 Subject: Remove unboxed object tests. --- .../tests/basic/unboxed-object-clear-new-script.js | 49 ---------------------- .../basic/unboxed-object-convert-to-native.js | 47 --------------------- .../jit-test/tests/basic/unboxed-object-getelem.js | 20 --------- .../tests/basic/unboxed-object-set-property.js | 31 -------------- .../tests/basic/unboxed-property-enumeration.js | 24 ----------- .../tests/ion/unboxed-objects-invalidate.js | 16 ------- 6 files changed, 187 deletions(-) delete mode 100644 js/src/jit-test/tests/basic/unboxed-object-clear-new-script.js delete mode 100644 js/src/jit-test/tests/basic/unboxed-object-convert-to-native.js delete mode 100644 js/src/jit-test/tests/basic/unboxed-object-getelem.js delete mode 100644 js/src/jit-test/tests/basic/unboxed-object-set-property.js delete mode 100644 js/src/jit-test/tests/basic/unboxed-property-enumeration.js delete mode 100644 js/src/jit-test/tests/ion/unboxed-objects-invalidate.js (limited to 'js/src') diff --git a/js/src/jit-test/tests/basic/unboxed-object-clear-new-script.js b/js/src/jit-test/tests/basic/unboxed-object-clear-new-script.js deleted file mode 100644 index f55456222..000000000 --- a/js/src/jit-test/tests/basic/unboxed-object-clear-new-script.js +++ /dev/null @@ -1,49 +0,0 @@ - -function Foo(a, b) { - this.a = a; - this.b = b; -} - -function invalidate_foo() { - var a = []; - var counter = 0; - for (var i = 0; i < 50; i++) - a.push(new Foo(i, i + 1)); - Object.defineProperty(Foo.prototype, "a", {configurable: true, set: function() { counter++; }}); - for (var i = 0; i < 50; i++) - a.push(new Foo(i, i + 1)); - delete Foo.prototype.a; - var total = 0; - for (var i = 0; i < a.length; i++) { - assertEq('a' in a[i], i < 50); - total += a[i].b; - } - assertEq(total, 2550); - assertEq(counter, 50); -} -invalidate_foo(); - -function Bar(a, b, fn) { - this.a = a; - if (b == 30) - Object.defineProperty(Bar.prototype, "b", {configurable: true, set: fn}); - this.b = b; -} - -function invalidate_bar() { - var a = []; - var counter = 0; - function fn() { counter++; } - for (var i = 0; i < 50; i++) - a.push(new Bar(i, i + 1, fn)); - delete Bar.prototype.b; - var total = 0; - for (var i = 0; i < a.length; i++) { - assertEq('a' in a[i], true); - assertEq('b' in a[i], i < 29); - total += a[i].a; - } - assertEq(total, 1225); - assertEq(counter, 21); -} -invalidate_bar(); diff --git a/js/src/jit-test/tests/basic/unboxed-object-convert-to-native.js b/js/src/jit-test/tests/basic/unboxed-object-convert-to-native.js deleted file mode 100644 index 691fe166c..000000000 --- a/js/src/jit-test/tests/basic/unboxed-object-convert-to-native.js +++ /dev/null @@ -1,47 +0,0 @@ - -// Test various ways of converting an unboxed object to native. - -function Foo(a, b) { - this.a = a; - this.b = b; -} - -var proxyObj = { - get: function(recipient, name) { - return recipient[name] + 2; - } -}; - -function f() { - var a = []; - for (var i = 0; i < 50; i++) - a.push(new Foo(i, i + 1)); - - var prop = "a"; - - i = 0; - for (; i < 5; i++) - a[i].c = i; - for (; i < 10; i++) - Object.defineProperty(a[i], 'c', {value: i}); - for (; i < 15; i++) - a[i] = new Proxy(a[i], proxyObj); - for (; i < 20; i++) - a[i].a = 3.5; - for (; i < 25; i++) - delete a[i].b; - for (; i < 30; i++) - a[prop] = 4; - - var total = 0; - for (i = 0; i < a.length; i++) { - if ('a' in a[i]) - total += a[i].a; - if ('b' in a[i]) - total += a[i].b; - if ('c' in a[i]) - total += a[i].c; - } - assertEq(total, 2382.5); -} -f(); diff --git a/js/src/jit-test/tests/basic/unboxed-object-getelem.js b/js/src/jit-test/tests/basic/unboxed-object-getelem.js deleted file mode 100644 index b30b8325a..000000000 --- a/js/src/jit-test/tests/basic/unboxed-object-getelem.js +++ /dev/null @@ -1,20 +0,0 @@ - -function f() { - var propNames = ["a","b","c","d","e","f","g","h","i","j","x","y"]; - var arr = []; - for (var i=0; i<64; i++) - arr.push({x:1, y:2}); - for (var i=0; i<64; i++) { - // Make sure there are expandos with dynamic slots for each object. - for (var j = 0; j < propNames.length; j++) - arr[i][propNames[j]] = j; - } - var res = 0; - for (var i=0; i<100000; i++) { - var o = arr[i % 64]; - var p = propNames[i % propNames.length]; - res += o[p]; - } - assertEq(res, 549984); -} -f(); diff --git a/js/src/jit-test/tests/basic/unboxed-object-set-property.js b/js/src/jit-test/tests/basic/unboxed-object-set-property.js deleted file mode 100644 index fdcfcf6b2..000000000 --- a/js/src/jit-test/tests/basic/unboxed-object-set-property.js +++ /dev/null @@ -1,31 +0,0 @@ - -// Use the correct receiver when non-native objects are prototypes of other objects. - -function Thing(a, b) { - this.a = a; - this.b = b; -} - -function foo() { - var array = []; - for (var i = 0; i < 10000; i++) - array.push(new Thing(i, i + 1)); - - var proto = new Thing(1, 2); - var obj = Object.create(proto); - - Object.defineProperty(Thing.prototype, "c", {set:function() { this.d = 0; }}); - obj.c = 3; - assertEq(obj.c, undefined); - assertEq(obj.d, 0); - assertEq(obj.hasOwnProperty("d"), true); - assertEq(proto.d, undefined); - assertEq(proto.hasOwnProperty("d"), false); - - obj.a = 3; - assertEq(obj.a, 3); - assertEq(proto.a, 1); - assertEq(obj.hasOwnProperty("a"), true); -} - -foo(); diff --git a/js/src/jit-test/tests/basic/unboxed-property-enumeration.js b/js/src/jit-test/tests/basic/unboxed-property-enumeration.js deleted file mode 100644 index 142d932dd..000000000 --- a/js/src/jit-test/tests/basic/unboxed-property-enumeration.js +++ /dev/null @@ -1,24 +0,0 @@ -function O() { - this.x = 1; - this.y = 2; -} -function testUnboxed() { - var arr = []; - for (var i=0; i<100; i++) - arr.push(new O); - - var o = arr[arr.length-1]; - o[0] = 0; - o[2] = 2; - var sym = Symbol(); - o[sym] = 1; - o.z = 3; - Object.defineProperty(o, '3', {value:1,enumerable:false,configurable:false,writable:false}); - o[4] = 4; - - var props = Reflect.ownKeys(o); - assertEq(props[props.length-1], sym); - - assertEq(Object.getOwnPropertyNames(o).join(""), "0234xyz"); -} -testUnboxed(); diff --git a/js/src/jit-test/tests/ion/unboxed-objects-invalidate.js b/js/src/jit-test/tests/ion/unboxed-objects-invalidate.js deleted file mode 100644 index 02e27614f..000000000 --- a/js/src/jit-test/tests/ion/unboxed-objects-invalidate.js +++ /dev/null @@ -1,16 +0,0 @@ - -var a = []; -for (var i = 0; i < 2000; i++) - a.push({f:i}); - -function f() { - var total = 0; - for (var i = 0; i < a.length; i++) - total += a[i].f; - return total; -} -assertEq(f(), 1999000); - -var sub = Object.create(a[0]); - -assertEq(f(), 1999000); -- cgit v1.2.3 From 636901a4f56c0039fc922debbc48920b19ec0a71 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Tue, 25 Jun 2019 20:24:34 +0000 Subject: Remove UnboxedObjects ObjectGroup addendum --- js/src/jit/MacroAssembler.cpp | 10 ++-------- js/src/vm/ObjectGroup.h | 33 +++++---------------------------- 2 files changed, 7 insertions(+), 36 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp index bc04e85cf..a739b9325 100644 --- a/js/src/jit/MacroAssembler.cpp +++ b/js/src/jit/MacroAssembler.cpp @@ -126,20 +126,14 @@ MacroAssembler::guardTypeSetMightBeIncomplete(TypeSet* types, Register obj, Regi { // Type set guards might miss when an object's group changes. In this case // either its old group's properties will become unknown, or it will change - // to a native object with an original unboxed group. Jump to label if this - // might have happened for the input object. + // to a native object. Jump to label if this might have happened for the + // input object. if (types->unknownObject()) { jump(label); return; } - loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch); - load32(Address(scratch, ObjectGroup::offsetOfFlags()), scratch); - and32(Imm32(OBJECT_FLAG_ADDENDUM_MASK), scratch); - branch32(Assembler::Equal, - scratch, Imm32(ObjectGroup::addendumOriginalUnboxedGroupValue()), label); - for (size_t i = 0; i < types->getObjectCount(); i++) { if (JSObject* singleton = types->getSingletonNoBarrier(i)) { movePtr(ImmGCPtr(singleton), scratch); diff --git a/js/src/vm/ObjectGroup.h b/js/src/vm/ObjectGroup.h index bf8398742..0439b4c21 100644 --- a/js/src/vm/ObjectGroup.h +++ b/js/src/vm/ObjectGroup.h @@ -153,11 +153,6 @@ class ObjectGroup : public gc::TenuredCell // For some plain objects, the addendum stores a PreliminaryObjectArrayWithTemplate. Addendum_PreliminaryObjects, - // If this group is used by objects that have been converted from an - // unboxed representation and/or have the same allocation kind as such - // objects, the addendum points to that unboxed group. - Addendum_OriginalUnboxedGroup, - // When used by typed objects, the addendum stores a TypeDescr. Addendum_TypeDescr }; @@ -219,16 +214,6 @@ class ObjectGroup : public gc::TenuredCell maybePreliminaryObjectsDontCheckGeneration(); } - ObjectGroup* maybeOriginalUnboxedGroup() const { - if (addendumKind() == Addendum_OriginalUnboxedGroup) - return reinterpret_cast(addendum_); - return nullptr; - } - - void setOriginalUnboxedGroup(ObjectGroup* group) { - setAddendum(Addendum_OriginalUnboxedGroup, group); - } - TypeDescr* maybeTypeDescr() { // Note: there is no need to sweep when accessing the type descriptor // of an object, as it is strongly held and immutable. @@ -289,9 +274,8 @@ class ObjectGroup : public gc::TenuredCell * that can be read out of that property in actual JS objects. In native * objects, property types account for plain data properties (those with a * slot and no getter or setter hook) and dense elements. In typed objects - * and unboxed objects, property types account for object and value - * properties and elements in the object, and expando properties in unboxed - * objects. + * property types account for object and value properties and elements in + * the object. * * For accesses on these properties, the correspondence is as follows: * @@ -314,10 +298,9 @@ class ObjectGroup : public gc::TenuredCell * 2. Array lengths are special cased by the compiler and VM and are not * reflected in property types. * - * 3. In typed objects (but not unboxed objects), the initial values of - * properties (null pointers and undefined values) are not reflected in - * the property types. These values are always possible when reading the - * property. + * 3. In typed objects, the initial values of properties (null pointers and + * undefined values) are not reflected in the property types. These + * values are always possible when reading the property. * * We establish these by using write barriers on calls to setProperty and * defineProperty which are on native properties, and on any jitcode which @@ -431,12 +414,6 @@ class ObjectGroup : public gc::TenuredCell return &flags_; } - // Get the bit pattern stored in an object's addendum when it has an - // original unboxed group. - static inline int32_t addendumOriginalUnboxedGroupValue() { - return Addendum_OriginalUnboxedGroup << OBJECT_FLAG_ADDENDUM_SHIFT; - } - inline uint32_t basePropertyCount(); private: -- cgit v1.2.3 From 3264f3b73802f016777d090d0372749356f3a291 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Wed, 26 Jun 2019 09:19:13 +0000 Subject: Remove now-unused parameter (prev. used for unboxed objects). --- js/src/jit/CodeGenerator.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index a276ab9af..fcb711237 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -3028,7 +3028,7 @@ CodeGenerator::visitStoreSlotV(LStoreSlotV* lir) static void GuardReceiver(MacroAssembler& masm, const ReceiverGuard& guard, - Register obj, Register scratch, Label* miss, bool checkNullExpando) + Register obj, Register scratch, Label* miss) { if (guard.group) { masm.branchTestObjGroup(Assembler::NotEqual, obj, guard.group, miss); @@ -3050,13 +3050,11 @@ CodeGenerator::emitGetPropertyPolymorphic(LInstruction* ins, Register obj, Regis Label next; masm.comment("GuardReceiver"); - GuardReceiver(masm, receiver, obj, scratch, &next, /* checkNullExpando = */ false); + GuardReceiver(masm, receiver, obj, scratch, &next); if (receiver.shape) { masm.comment("loadTypedOrValue"); - // If this is an unboxed expando access, GuardReceiver loaded the - // expando object into scratch. - Register target = receiver.group ? scratch : obj; + Register target = obj; Shape* shape = mir->shape(i); if (shape->slot() < shape->numFixedSlots()) { @@ -3122,12 +3120,10 @@ CodeGenerator::emitSetPropertyPolymorphic(LInstruction* ins, Register obj, Regis ReceiverGuard receiver = mir->receiver(i); Label next; - GuardReceiver(masm, receiver, obj, scratch, &next, /* checkNullExpando = */ false); + GuardReceiver(masm, receiver, obj, scratch, &next); if (receiver.shape) { - // If this is an unboxed expando access, GuardReceiver loaded the - // expando object into scratch. - Register target = receiver.group ? scratch : obj; + Register target = obj; Shape* shape = mir->shape(i); if (shape->slot() < shape->numFixedSlots()) { @@ -3293,7 +3289,7 @@ CodeGenerator::visitGuardReceiverPolymorphic(LGuardReceiverPolymorphic* lir) const ReceiverGuard& receiver = mir->receiver(i); Label next; - GuardReceiver(masm, receiver, obj, temp, &next, /* checkNullExpando = */ true); + GuardReceiver(masm, receiver, obj, temp, &next); if (i == mir->numReceivers() - 1) { bailoutFrom(&next, lir->snapshot()); -- cgit v1.2.3 From 06bf5d769f33d72441825fa39e00baf9eaaac179 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Wed, 26 Jun 2019 11:44:03 +0000 Subject: Clean up MObjectState --- js/src/jit/MIR.cpp | 9 +++------ js/src/jit/MIR.h | 23 +++-------------------- js/src/jit/ScalarReplacement.cpp | 33 --------------------------------- 3 files changed, 6 insertions(+), 59 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 190b40bb2..fa9cc3019 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -4817,15 +4817,14 @@ MCreateThisWithTemplate::canRecoverOnBailout() const MObjectState::MObjectState(MObjectState* state) : numSlots_(state->numSlots_), - numFixedSlots_(state->numFixedSlots_), - operandIndex_(state->operandIndex_) + numFixedSlots_(state->numFixedSlots_) { // This instruction is only used as a summary for bailout paths. setResultType(MIRType::Object); setRecoveredOnBailout(); } -MObjectState::MObjectState(JSObject *templateObject, OperandIndexMap* operandIndex) +MObjectState::MObjectState(JSObject* templateObject) { // This instruction is only used as a summary for bailout paths. setResultType(MIRType::Object); @@ -4836,8 +4835,6 @@ MObjectState::MObjectState(JSObject *templateObject, OperandIndexMap* operandInd NativeObject* nativeObject = &templateObject->as(); numSlots_ = nativeObject->slotSpan(); numFixedSlots_ = nativeObject->numFixedSlots(); - - operandIndex_ = operandIndex; } JSObject* @@ -4897,7 +4894,7 @@ MObjectState::New(TempAllocator& alloc, MDefinition* obj) JSObject* templateObject = templateObjectOf(obj); MOZ_ASSERT(templateObject, "Unexpected object creation."); - MObjectState* res = new(alloc) MObjectState(templateObject, nullptr); + MObjectState* res = new(alloc) MObjectState(templateObject); if (!res || !res->init(alloc, obj)) return nullptr; return res; diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 6526e0931..0992768bf 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -375,7 +375,7 @@ class AliasSet { Element = 1 << 1, // A Value member of obj->elements or // a typed object. UnboxedElement = 1 << 2, // An unboxed scalar or reference member of - // typed object or unboxed object. + // typed object. DynamicSlot = 1 << 3, // A Value member of obj->slots. FixedSlot = 1 << 4, // A Value member of obj->fixedSlots(). DOMProperty = 1 << 5, // A DOM property @@ -3758,14 +3758,9 @@ class MObjectState { private: uint32_t numSlots_; - uint32_t numFixedSlots_; // valid if isUnboxed() == false. - OperandIndexMap* operandIndex_; // valid if isUnboxed() == true. + uint32_t numFixedSlots_; - bool isUnboxed() const { - return operandIndex_ != nullptr; - } - - MObjectState(JSObject *templateObject, OperandIndexMap* operandIndex); + MObjectState(JSObject *templateObject); explicit MObjectState(MObjectState* state); MOZ_MUST_USE bool init(TempAllocator& alloc, MDefinition* obj); @@ -3826,18 +3821,6 @@ class MObjectState setSlot(slot + numFixedSlots(), def); } - // Interface reserved for unboxed objects. - bool hasOffset(uint32_t offset) const { - MOZ_ASSERT(isUnboxed()); - return offset < operandIndex_->map.length() && operandIndex_->map[offset] != 0; - } - MDefinition* getOffset(uint32_t offset) const { - return getOperand(operandIndex_->map[offset]); - } - void setOffset(uint32_t offset, MDefinition* def) { - replaceOperand(operandIndex_->map[offset], def); - } - MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override; bool canRecoverOnBailout() const override { return true; diff --git a/js/src/jit/ScalarReplacement.cpp b/js/src/jit/ScalarReplacement.cpp index be9ceee2e..97ba52349 100644 --- a/js/src/jit/ScalarReplacement.cpp +++ b/js/src/jit/ScalarReplacement.cpp @@ -285,10 +285,6 @@ class ObjectMemoryView : public MDefinitionVisitorDefaultNoop void visitGuardShape(MGuardShape* ins); void visitFunctionEnvironment(MFunctionEnvironment* ins); void visitLambda(MLambda* ins); - - private: - void storeOffset(MInstruction* ins, size_t offset, MDefinition* value); - void loadOffset(MInstruction* ins, size_t offset); }; const char* ObjectMemoryView::phaseName = "Scalar Replacement of Object"; @@ -630,35 +626,6 @@ ObjectMemoryView::visitLambda(MLambda* ins) ins->setIncompleteObject(); } -void -ObjectMemoryView::storeOffset(MInstruction* ins, size_t offset, MDefinition* value) -{ - // Clone the state and update the slot value. - MOZ_ASSERT(state_->hasOffset(offset)); - state_ = BlockState::Copy(alloc_, state_); - if (!state_) { - oom_ = true; - return; - } - - state_->setOffset(offset, value); - ins->block()->insertBefore(ins, state_); - - // Remove original instruction. - ins->block()->discard(ins); -} - -void -ObjectMemoryView::loadOffset(MInstruction* ins, size_t offset) -{ - // Replace load by the slot value. - MOZ_ASSERT(state_->hasOffset(offset)); - ins->replaceAllUsesWith(state_->getOffset(offset)); - - // Remove original instruction. - ins->block()->discard(ins); -} - static bool IndexOf(MDefinition* ins, int32_t* res) { -- cgit v1.2.3 From e4ae95acc6dcf60e4dae488df5b3b293d3759c8b Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Wed, 26 Jun 2019 12:00:26 +0000 Subject: Remove anyNewScript() --- js/src/vm/ObjectGroup.h | 1 - js/src/vm/TypeInference.cpp | 14 +++----------- 2 files changed, 3 insertions(+), 12 deletions(-) (limited to 'js/src') diff --git a/js/src/vm/ObjectGroup.h b/js/src/vm/ObjectGroup.h index 0439b4c21..0b6eaee51 100644 --- a/js/src/vm/ObjectGroup.h +++ b/js/src/vm/ObjectGroup.h @@ -174,7 +174,6 @@ class ObjectGroup : public gc::TenuredCell return nullptr; } - TypeNewScript* anyNewScript(); void detachNewScript(bool writeBarrier, ObjectGroup* replacement); ObjectGroupFlags flagsDontCheckGeneration() const { diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index 26ade2948..ba809fc4e 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -2877,14 +2877,6 @@ ObjectGroup::markUnknown(ExclusiveContext* cx) } } -TypeNewScript* -ObjectGroup::anyNewScript() -{ - if (newScript()) - return newScript(); - return nullptr; -} - void ObjectGroup::detachNewScript(bool writeBarrier, ObjectGroup* replacement) { @@ -2892,7 +2884,7 @@ ObjectGroup::detachNewScript(bool writeBarrier, ObjectGroup* replacement) // analyzed, remove it from the newObjectGroups table so that it will not be // produced by calling 'new' on the associated function anymore. // The TypeNewScript is not actually destroyed. - TypeNewScript* newScript = anyNewScript(); + TypeNewScript* newScript = this->newScript(); MOZ_ASSERT(newScript); if (newScript->analyzed()) { @@ -2922,7 +2914,7 @@ ObjectGroup::maybeClearNewScriptOnOOM() if (!isMarked()) return; - TypeNewScript* newScript = anyNewScript(); + TypeNewScript* newScript = this->newScript(); if (!newScript) return; @@ -2937,7 +2929,7 @@ ObjectGroup::maybeClearNewScriptOnOOM() void ObjectGroup::clearNewScript(ExclusiveContext* cx, ObjectGroup* replacement /* = nullptr*/) { - TypeNewScript* newScript = anyNewScript(); + TypeNewScript* newScript = this->newScript(); if (!newScript) return; -- cgit v1.2.3 From b8ff1df2c96270c481a645947390c4cdae93e3cc Mon Sep 17 00:00:00 2001 From: Travis W Date: Thu, 27 Jun 2019 17:57:07 -0500 Subject: Add StoreBuffer-inl.h header to jsobj.cpp This should fix deprot on the Linux and Macintosh --- js/src/jsobj.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'js/src') diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 58988739b..2364f707e 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -43,6 +43,7 @@ #include "frontend/BytecodeCompiler.h" #include "gc/Marking.h" #include "gc/Policy.h" +#include "gc/StoreBuffer-inl.h" #include "jit/BaselineJIT.h" #include "js/MemoryMetrics.h" #include "js/Proxy.h" -- cgit v1.2.3 From 01e1fcf522219bf1b2d7d2dcc6209db3d270a182 Mon Sep 17 00:00:00 2001 From: g4jc Date: Fri, 28 Jun 2019 21:35:05 -0400 Subject: Issue #1142 - Remove uneeded assertion (#1145) Since unboxed objects were removed, isUnboxed is undefined. This causes a build failure when debuging is enabled. This patch fixes the issue by removing the uneeeded assertion. --- js/src/jit/MIR.h | 1 - 1 file changed, 1 deletion(-) (limited to 'js/src') diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 0992768bf..9076339f1 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -3785,7 +3785,6 @@ class MObjectState MOZ_MUST_USE bool initFromTemplateObject(TempAllocator& alloc, MDefinition* undefinedVal); size_t numFixedSlots() const { - MOZ_ASSERT(!isUnboxed()); return numFixedSlots_; } size_t numSlots() const { -- cgit v1.2.3 From 35d29c05c59057fc84be41ec94f2e3bc31ddef44 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Fri, 28 Jun 2019 23:02:15 -0400 Subject: Issue #1142 - Cleanup unused debug code for unboxed objects Also fixes an assertion during compile if debug is enabled since unboxed objects have been removed. --- js/src/jit/BaselineIC.cpp | 2 +- js/src/jscompartment.cpp | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index d95d08edc..2f20ffa4f 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -289,7 +289,7 @@ DoTypeUpdateFallback(JSContext* cx, BaselineFrame* frame, ICUpdatedStub* stub, H case ICStub::SetProp_Native: case ICStub::SetProp_NativeAdd: case ICStub::SetProp_Unboxed: { - MOZ_ASSERT(obj->isNative() || obj->is()); + MOZ_ASSERT(obj->isNative()); jsbytecode* pc = stub->getChainFallback()->icEntry()->pc(script); if (*pc == JSOP_SETALIASEDVAR || *pc == JSOP_INITALIASEDLEXICAL) id = NameToId(EnvironmentCoordinateName(cx->caches.envCoordinateNameCache, script, pc)); diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index a48bb0ffe..6024a1768 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -112,13 +112,6 @@ JSCompartment::~JSCompartment() js_delete(nonSyntacticLexicalEnvironments_), js_free(enumerators); -#ifdef DEBUG - // Avoid assertion destroying the unboxed layouts list if the embedding - // leaked GC things. - if (!rt->gc.shutdownCollectedEverything()) - unboxedLayouts.clear(); -#endif - runtime_->numCompartments--; } -- cgit v1.2.3 From 20e3587ef5a97f190da7a4e674e988d7189c795c Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Mon, 8 Jul 2019 02:17:07 +0200 Subject: Avoid type confusion in ArrayJoinDenseKernel --- js/src/jsarray.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'js/src') diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index ec65bce64..ff581beec 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -1048,7 +1048,7 @@ struct StringSeparatorOp template static bool -ArrayJoinDenseKernel(JSContext* cx, SeparatorOp sepOp, HandleNativeObject obj, uint64_t length, +ArrayJoinDenseKernel(JSContext* cx, SeparatorOp sepOp, HandleNativeObject obj, uint32_t length, StringBuffer& sb, uint32_t* numProcessed) { // This loop handles all elements up to initializedLength. If -- cgit v1.2.3 From 5e76f72c539cd0e2fc0d38e4475f494868b5e859 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 13:02:16 -0400 Subject: 1315815 - Don't treat async or await as a keyword when they contain escapes. --- js/src/frontend/FullParseHandler.h | 20 ++--- js/src/frontend/Parser.cpp | 95 +++++++++++++--------- js/src/frontend/SyntaxParseHandler.h | 29 +++---- .../async-contains-unicode-escape.js | 54 ++++++++++++ 4 files changed, 134 insertions(+), 64 deletions(-) create mode 100644 js/src/tests/ecma_7/AsyncFunctions/async-contains-unicode-escape.js (limited to 'js/src') diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index b619cf24c..3938d9743 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -10,6 +10,8 @@ #include "mozilla/Attributes.h" #include "mozilla/PodOperations.h" +#include + #include "frontend/ParseNode.h" #include "frontend/SharedContext.h" @@ -870,29 +872,25 @@ class FullParseHandler return node->isKind(PNK_NAME); } - bool nameIsEvalAnyParentheses(ParseNode* node, ExclusiveContext* cx) { - MOZ_ASSERT(isNameAnyParentheses(node), - "must only call this function on known names"); - - return node->pn_atom == cx->names().eval; + bool isEvalAnyParentheses(ParseNode* node, ExclusiveContext* cx) { + return node->isKind(PNK_NAME) && node->pn_atom == cx->names().eval; } const char* nameIsArgumentsEvalAnyParentheses(ParseNode* node, ExclusiveContext* cx) { MOZ_ASSERT(isNameAnyParentheses(node), "must only call this function on known names"); - if (nameIsEvalAnyParentheses(node, cx)) + if (isEvalAnyParentheses(node, cx)) return js_eval_str; if (node->pn_atom == cx->names().arguments) return js_arguments_str; return nullptr; } - bool nameIsUnparenthesizedAsync(ParseNode* node, ExclusiveContext* cx) { - MOZ_ASSERT(isNameAnyParentheses(node), - "must only call this function on known names"); - - return node->pn_atom == cx->names().async; + bool isAsyncKeyword(ParseNode* node, ExclusiveContext* cx) { + return node->isKind(PNK_NAME) && + node->pn_pos.begin + strlen("async") == node->pn_pos.end && + node->pn_atom == cx->names().async; } bool isCall(ParseNode* pn) { diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 3b7a0e612..7d923420a 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -5147,7 +5147,10 @@ Parser::exportDeclaration() return null(); break; default: { - if (tt == TOK_NAME && tokenStream.currentName() == context->names().async) { + if (tt == TOK_NAME && + tokenStream.currentName() == context->names().async && + !tokenStream.currentToken().nameContainsEscape()) + { TokenKind nextSameLine = TOK_EOF; if (!tokenStream.peekTokenSameLine(&nextSameLine)) return null(); @@ -7045,21 +7048,23 @@ Parser::statementListItem(YieldHandling yieldHandling, if (!tokenStream.peekToken(&next)) return null(); - if (!tokenStream.currentToken().nameContainsEscape() && - tokenStream.currentName() == context->names().let && - nextTokenContinuesLetDeclaration(next, yieldHandling)) - { - return lexicalDeclaration(yieldHandling, /* isConst = */ false); - } + if (!tokenStream.currentToken().nameContainsEscape()) { + if (tokenStream.currentName() == context->names().let && + nextTokenContinuesLetDeclaration(next, yieldHandling)) + { + return lexicalDeclaration(yieldHandling, /* isConst = */ false); + } - if (tokenStream.currentName() == context->names().async) { - TokenKind nextSameLine = TOK_EOF; - if (!tokenStream.peekTokenSameLine(&nextSameLine)) - return null(); - if (nextSameLine == TOK_FUNCTION) { - uint32_t preludeStart = pos().begin; - tokenStream.consumeKnownToken(TOK_FUNCTION); - return functionStmt(preludeStart, yieldHandling, NameRequired, AsyncFunction); + if (tokenStream.currentName() == context->names().async) { + TokenKind nextSameLine = TOK_EOF; + if (!tokenStream.peekTokenSameLine(&nextSameLine)) { + return null(); + } + if (nextSameLine == TOK_FUNCTION) { + uint32_t preludeStart = pos().begin; + tokenStream.consumeKnownToken(TOK_FUNCTION); + return functionStmt(preludeStart, yieldHandling, NameRequired, AsyncFunction); + } } } @@ -7516,7 +7521,10 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl return yieldExpression(inHandling); bool maybeAsyncArrow = false; - if (tt == TOK_NAME && tokenStream.currentName() == context->names().async) { + if (tt == TOK_NAME && + tokenStream.currentName() == context->names().async && + !tokenStream.currentToken().nameContainsEscape()) + { TokenKind nextSameLine = TOK_EOF; if (!tokenStream.peekTokenSameLine(&nextSameLine)) return null(); @@ -7537,6 +7545,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl if (maybeAsyncArrow) { tokenStream.consumeKnownToken(TOK_NAME, TokenStream::Operand); MOZ_ASSERT(tokenStream.currentName() == context->names().async); + MOZ_ASSERT(!tokenStream.currentToken().nameContainsEscape()); TokenKind tt; if (!tokenStream.getToken(&tt)) @@ -7613,7 +7622,9 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl if (next == TOK_NAME) { tokenStream.consumeKnownToken(next, TokenStream::Operand); - if (tokenStream.currentName() == context->names().async) { + if (tokenStream.currentName() == context->names().async && + !tokenStream.currentToken().nameContainsEscape()) + { TokenKind nextSameLine = TOK_EOF; if (!tokenStream.peekTokenSameLine(&nextSameLine)) return null(); @@ -8448,8 +8459,27 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling JSOp op = JSOP_CALL; bool maybeAsyncArrow = false; - if (tt == TOK_LP && handler.isNameAnyParentheses(lhs)) { - if (handler.nameIsEvalAnyParentheses(lhs, context)) { + if (PropertyName* prop = handler.maybeDottedProperty(lhs)) { + // Use the JSOP_FUN{APPLY,CALL} optimizations given the + // right syntax. + if (prop == context->names().apply) { + op = JSOP_FUNAPPLY; + if (pc->isFunctionBox()) { + pc->functionBox()->usesApply = true; + } + } else if (prop == context->names().call) { + op = JSOP_FUNCALL; + } + } else if (tt == TOK_LP) { + if (handler.isAsyncKeyword(lhs, context)) { + // |async (| can be the start of an async arrow + // function, so we need to defer reporting possible + // errors from destructuring syntax. To give better + // error messages, we only allow the AsyncArrowHead + // part of the CoverCallExpressionAndAsyncArrowHead + // syntax when the initial name is "async". + maybeAsyncArrow = true; + } else if (handler.isEvalAnyParentheses(lhs, context)) { // Select the right EVAL op and flag pc as having a // direct eval. op = pc->sc()->strict() ? JSOP_STRICTEVAL : JSOP_EVAL; @@ -8466,24 +8496,6 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling // it. (If we're not in a method, that's fine, so // ignore the return value.) checkAndMarkSuperScope(); - } else if (handler.nameIsUnparenthesizedAsync(lhs, context)) { - // |async (| can be the start of an async arrow - // function, so we need to defer reporting possible - // errors from destructuring syntax. To give better - // error messages, we only allow the AsyncArrowHead - // part of the CoverCallExpressionAndAsyncArrowHead - // syntax when the initial name is "async". - maybeAsyncArrow = true; - } - } else if (PropertyName* prop = handler.maybeDottedProperty(lhs)) { - // Use the JSOP_FUN{APPLY,CALL} optimizations given the - // right syntax. - if (prop == context->names().apply) { - op = JSOP_FUNAPPLY; - if (pc->isFunctionBox()) - pc->functionBox()->usesApply = true; - } else if (prop == context->names().call) { - op = JSOP_FUNCALL; } } @@ -8816,7 +8828,10 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, return null(); } - if (ltok == TOK_NAME && tokenStream.currentName() == context->names().async) { + if (ltok == TOK_NAME && + tokenStream.currentName() == context->names().async && + !tokenStream.currentToken().nameContainsEscape()) + { // AsyncMethod[Yield, Await]: // async [no LineTerminator here] PropertyName[?Yield, ?Await] ... // @@ -9404,7 +9419,9 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling case TOK_YIELD: case TOK_NAME: { - if (tokenStream.currentName() == context->names().async) { + if (tokenStream.currentName() == context->names().async && + !tokenStream.currentToken().nameContainsEscape()) + { TokenKind nextSameLine = TOK_EOF; if (!tokenStream.peekTokenSameLine(&nextSameLine)) return null(); diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index 00ea9d35d..9dc3c1072 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -9,6 +9,8 @@ #include "mozilla/Attributes.h" +#include + #include "frontend/ParseNode.h" #include "frontend/TokenStream.h" @@ -94,10 +96,13 @@ class SyntaxParseHandler // Nodes representing unparenthesized names. NodeUnparenthesizedArgumentsName, - NodeUnparenthesizedAsyncName, NodeUnparenthesizedEvalName, NodeUnparenthesizedName, + // Node representing the "async" name, which may actually be a + // contextual keyword. + NodePotentialAsyncKeyword, + // Valuable for recognizing potential destructuring patterns. NodeUnparenthesizedArray, NodeUnparenthesizedObject, @@ -183,8 +188,8 @@ class SyntaxParseHandler lastAtom = name; if (name == cx->names().arguments) return NodeUnparenthesizedArgumentsName; - if (name == cx->names().async) - return NodeUnparenthesizedAsyncName; + if (pos.begin + strlen("async") == pos.end && name == cx->names().async) + return NodePotentialAsyncKeyword; if (name == cx->names().eval) return NodeUnparenthesizedEvalName; return NodeUnparenthesizedName; @@ -497,7 +502,7 @@ class SyntaxParseHandler return NodeParenthesizedArgumentsName; if (node == NodeUnparenthesizedEvalName) return NodeParenthesizedEvalName; - if (node == NodeUnparenthesizedName || node == NodeUnparenthesizedAsyncName) + if (node == NodeUnparenthesizedName || node == NodePotentialAsyncKeyword) return NodeParenthesizedName; if (node == NodeUnparenthesizedArray) @@ -528,9 +533,9 @@ class SyntaxParseHandler bool isUnparenthesizedName(Node node) { return node == NodeUnparenthesizedArgumentsName || - node == NodeUnparenthesizedAsyncName || node == NodeUnparenthesizedEvalName || - node == NodeUnparenthesizedName; + node == NodeUnparenthesizedName || + node == NodePotentialAsyncKeyword; } bool isNameAnyParentheses(Node node) { @@ -541,9 +546,7 @@ class SyntaxParseHandler node == NodeParenthesizedName; } - bool nameIsEvalAnyParentheses(Node node, ExclusiveContext* cx) { - MOZ_ASSERT(isNameAnyParentheses(node), - "must only call this function on known names"); + bool isEvalAnyParentheses(Node node, ExclusiveContext* cx) { return node == NodeUnparenthesizedEvalName || node == NodeParenthesizedEvalName; } @@ -551,17 +554,15 @@ class SyntaxParseHandler MOZ_ASSERT(isNameAnyParentheses(node), "must only call this method on known names"); - if (nameIsEvalAnyParentheses(node, cx)) + if (isEvalAnyParentheses(node, cx)) return js_eval_str; if (node == NodeUnparenthesizedArgumentsName || node == NodeParenthesizedArgumentsName) return js_arguments_str; return nullptr; } - bool nameIsUnparenthesizedAsync(Node node, ExclusiveContext* cx) { - MOZ_ASSERT(isNameAnyParentheses(node), - "must only call this function on known names"); - return node == NodeUnparenthesizedAsyncName; + bool isAsyncKeyword(Node node, ExclusiveContext* cx) { + return node == NodePotentialAsyncKeyword; } PropertyName* maybeDottedProperty(Node node) { diff --git a/js/src/tests/ecma_7/AsyncFunctions/async-contains-unicode-escape.js b/js/src/tests/ecma_7/AsyncFunctions/async-contains-unicode-escape.js new file mode 100644 index 000000000..d53dff696 --- /dev/null +++ b/js/src/tests/ecma_7/AsyncFunctions/async-contains-unicode-escape.js @@ -0,0 +1,54 @@ +var BUGNUMBER = 1315815; +var summary = "async/await containing escapes"; + +print(BUGNUMBER + ": " + summary); + +// Using "eval" as the argument name is fugly, but it means evals below are +// *direct* evals, and so their effects in the unescaped case won't extend +// past each separate |test| call (as would happen if we used a different name +// that made each eval into an indirect eval, affecting code in the global +// scope). +function test(code, eval) +{ + var unescaped = code.replace("###", "async"); + var escaped = code.replace("###", "\\u0061"); + + assertThrowsInstanceOf(() => eval(escaped), SyntaxError); + eval(unescaped); +} + +test("### function f() {}", eval); +test("var x = ### function f() {}", eval); +test("### x => {};", eval); +test("var x = ### x => {}", eval); +test("### () => {};", eval); +test("var x = ### () => {}", eval); +test("### (y) => {};", eval); +test("var x = ### (y) => {}", eval); +test("({ ### x() {} })", eval); +test("var x = ### function f() {}", eval); + +if (typeof parseModule === "function") + test("export default ### function f() {}", parseModule); + +assertThrowsInstanceOf(() => eval("async await => 1;"), + SyntaxError); +assertThrowsInstanceOf(() => eval("async aw\\u0061it => 1;"), + SyntaxError); + +var async = 0; +assertEq(\u0061sync, 0); + +var obj = { \u0061sync() { return 1; } }; +assertEq(obj.async(), 1); + +async = function() { return 42; }; + +var z = async(obj); +assertEq(z, 42); + +var w = async(obj)=>{}; +assertEq(typeof w, "function"); + +if (typeof reportCompare === "function") + reportCompare(true, true); -- cgit v1.2.3 From dcb43bda93f1f2cbe3da5ba1b7d3f783f1c8ad1c Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 13:04:58 -0400 Subject: 1317090: Remove js::FindBody; --- js/src/jsfun.cpp | 70 -------------------------------------------------------- js/src/jsfun.h | 4 ---- 2 files changed, 74 deletions(-) (limited to 'js/src') diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index e624aa415..3cba3434d 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -886,76 +886,6 @@ const Class JSFunction::class_ = { const Class* const js::FunctionClassPtr = &JSFunction::class_; -/* Find the body of a function (not including braces). */ -bool -js::FindBody(JSContext* cx, HandleFunction fun, HandleLinearString src, size_t* bodyStart, - size_t* bodyEnd) -{ - // We don't need principals, since those are only used for error reporting. - CompileOptions options(cx); - options.setFileAndLine("internal-findBody", 0); - - // For asm.js/wasm modules, there's no script. - if (fun->hasScript()) - options.setVersion(fun->nonLazyScript()->getVersion()); - - AutoKeepAtoms keepAtoms(cx->perThreadData); - - AutoStableStringChars stableChars(cx); - if (!stableChars.initTwoByte(cx, src)) - return false; - - const mozilla::Range srcChars = stableChars.twoByteRange(); - TokenStream ts(cx, options, srcChars.begin().get(), srcChars.length(), nullptr); - int nest = 0; - bool onward = true; - // Skip arguments list. - do { - TokenKind tt; - if (!ts.getToken(&tt)) - return false; - switch (tt) { - case TOK_NAME: - case TOK_YIELD: - if (nest == 0) - onward = false; - break; - case TOK_LP: - nest++; - break; - case TOK_RP: - if (--nest == 0) - onward = false; - break; - default: - break; - } - } while (onward); - TokenKind tt; - if (!ts.getToken(&tt)) - return false; - if (tt == TOK_ARROW) { - if (!ts.getToken(&tt)) - return false; - } - bool braced = tt == TOK_LC; - MOZ_ASSERT_IF(fun->isExprBody(), !braced); - *bodyStart = ts.currentToken().pos.begin; - if (braced) - *bodyStart += 1; - mozilla::RangedPtr end = srcChars.end(); - if (end[-1] == '}') { - end--; - } else { - MOZ_ASSERT(!braced); - for (; unicode::IsSpaceOrBOM2(end[-1]); end--) - ; - } - *bodyEnd = end - srcChars.begin(); - MOZ_ASSERT(*bodyStart <= *bodyEnd); - return true; -} - JSString* js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint) { diff --git a/js/src/jsfun.h b/js/src/jsfun.h index 1c7da57ec..62b285806 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -802,10 +802,6 @@ CloneFunctionAndScript(JSContext* cx, HandleFunction fun, HandleObject parent, gc::AllocKind kind = gc::AllocKind::FUNCTION, HandleObject proto = nullptr); -extern bool -FindBody(JSContext* cx, HandleFunction fun, HandleLinearString src, size_t* bodyStart, - size_t* bodyEnd); - } // namespace js inline js::FunctionExtended* -- cgit v1.2.3 From f319f49a5280a7ba37cb551a7236505e496ae34a Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 13:34:41 -0400 Subject: 1317153 - Provide better error message when errornous syntax possibly match "await SOMETHING" outside async function. --- js/src/frontend/Parser.cpp | 89 ++++++++++++++-------- js/src/frontend/Parser.h | 4 + js/src/js.msg | 1 + .../tests/ecma_2017/AsyncFunctions/await-error.js | 16 ++++ 4 files changed, 77 insertions(+), 33 deletions(-) create mode 100644 js/src/tests/ecma_2017/AsyncFunctions/await-error.js (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 7d923420a..3c509465f 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -2631,39 +2631,62 @@ Parser::newFunction(HandleAtom atom, FunctionSyntaxKind kind, /* * WARNING: Do not call this function directly. - * Call either MatchOrInsertSemicolonAfterExpression or - * MatchOrInsertSemicolonAfterNonExpression instead, depending on context. + * Call either matchOrInsertSemicolonAfterExpression or + * matchOrInsertSemicolonAfterNonExpression instead, depending on context. */ -static bool -MatchOrInsertSemicolonHelper(TokenStream& ts, TokenStream::Modifier modifier) +template +bool +Parser::matchOrInsertSemicolonHelper(TokenStream::Modifier modifier) { TokenKind tt = TOK_EOF; - if (!ts.peekTokenSameLine(&tt, modifier)) + if (!tokenStream.peekTokenSameLine(&tt, modifier)) return false; if (tt != TOK_EOF && tt != TOK_EOL && tt != TOK_SEMI && tt != TOK_RC) { + /* + * When current token is `await` and it's outside of async function, + * it's possibly intended to be an await expression. + * + * await f(); + * ^ + * | + * tried to insert semicolon here + * + * Detect this situation and throw an understandable error. Otherwise + * we'd throw a confusing "missing ; before statement" error. + */ + if (!pc->isAsync() && + tokenStream.currentToken().type == TOK_NAME && + tokenStream.currentName() == context->names().await) + { + error(JSMSG_AWAIT_OUTSIDE_ASYNC); + return false; + } + /* Advance the scanner for proper error location reporting. */ - ts.consumeKnownToken(tt, modifier); - ts.reportError(JSMSG_SEMI_BEFORE_STMNT); + tokenStream.consumeKnownToken(tt, modifier); + error(JSMSG_SEMI_BEFORE_STMNT); return false; } bool matched; - if (!ts.matchToken(&matched, TOK_SEMI, modifier)) + if (!tokenStream.matchToken(&matched, TOK_SEMI, modifier)) return false; if (!matched && modifier == TokenStream::None) - ts.addModifierException(TokenStream::OperandIsNone); + tokenStream.addModifierException(TokenStream::OperandIsNone); return true; } -static bool -MatchOrInsertSemicolonAfterExpression(TokenStream& ts) +template +bool +Parser::matchOrInsertSemicolonAfterExpression() { - return MatchOrInsertSemicolonHelper(ts, TokenStream::None); + return matchOrInsertSemicolonHelper(TokenStream::None); } -static bool -MatchOrInsertSemicolonAfterNonExpression(TokenStream& ts) +template +bool +Parser::matchOrInsertSemicolonAfterNonExpression() { - return MatchOrInsertSemicolonHelper(ts, TokenStream::Operand); + return matchOrInsertSemicolonHelper(TokenStream::Operand); } template @@ -3020,7 +3043,7 @@ Parser::skipLazyInnerFunction(ParseNode* pn, uint32_t preludeS return false; if (kind == Statement && fun->isExprBody()) { - if (!MatchOrInsertSemicolonAfterExpression(tokenStream)) + if (!matchOrInsertSemicolonAfterExpression()) return false; } @@ -3503,7 +3526,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if (tokenStream.hadError()) return false; funbox->bufEnd = pos().end; - if (kind == Statement && !MatchOrInsertSemicolonAfterExpression(tokenStream)) + if (kind == Statement && !matchOrInsertSemicolonAfterExpression()) return false; } @@ -4639,7 +4662,7 @@ Parser::lexicalDeclaration(YieldHandling yieldHandling, bool isCon * See 8.1.1.1.6 and the note in 13.2.1. */ Node decl = declarationList(yieldHandling, isConst ? PNK_CONST : PNK_LET); - if (!decl || !MatchOrInsertSemicolonAfterExpression(tokenStream)) + if (!decl || !matchOrInsertSemicolonAfterExpression()) return null(); return decl; @@ -4880,7 +4903,7 @@ Parser::importDeclaration() if (!moduleSpec) return null(); - if (!MatchOrInsertSemicolonAfterNonExpression(tokenStream)) + if (!matchOrInsertSemicolonAfterNonExpression()) return null(); ParseNode* node = @@ -5023,7 +5046,7 @@ Parser::exportDeclaration() // export { x } // ExportDeclaration, terminated by ASI // fro\u006D // ExpressionStatement, the name "from" // - // In that case let MatchOrInsertSemicolonAfterNonExpression sort out + // In that case let matchOrInsertSemicolonAfterNonExpression sort out // ASI or any necessary error. TokenKind tt; if (!tokenStream.getToken(&tt, TokenStream::Operand)) @@ -5039,7 +5062,7 @@ Parser::exportDeclaration() if (!moduleSpec) return null(); - if (!MatchOrInsertSemicolonAfterNonExpression(tokenStream)) + if (!matchOrInsertSemicolonAfterNonExpression()) return null(); ParseNode* node = handler.newExportFromDeclaration(begin, kid, moduleSpec); @@ -5051,7 +5074,7 @@ Parser::exportDeclaration() tokenStream.ungetToken(); - if (!MatchOrInsertSemicolonAfterNonExpression(tokenStream)) + if (!matchOrInsertSemicolonAfterNonExpression()) return null(); break; } @@ -5085,7 +5108,7 @@ Parser::exportDeclaration() if (!moduleSpec) return null(); - if (!MatchOrInsertSemicolonAfterNonExpression(tokenStream)) + if (!matchOrInsertSemicolonAfterNonExpression()) return null(); ParseNode* node = handler.newExportFromDeclaration(begin, kid, moduleSpec); @@ -5121,7 +5144,7 @@ Parser::exportDeclaration() kid = declarationList(YieldIsName, PNK_VAR); if (!kid) return null(); - if (!MatchOrInsertSemicolonAfterExpression(tokenStream)) + if (!matchOrInsertSemicolonAfterExpression()) return null(); if (!checkExportedNamesForDeclaration(kid)) return null(); @@ -5174,7 +5197,7 @@ Parser::exportDeclaration() kid = assignExpr(InAllowed, YieldIsKeyword, TripledotProhibited); if (!kid) return null(); - if (!MatchOrInsertSemicolonAfterExpression(tokenStream)) + if (!matchOrInsertSemicolonAfterExpression()) return null(); break; } @@ -5239,7 +5262,7 @@ Parser::expressionStatement(YieldHandling yieldHandling, InvokedPr /* possibleError = */ nullptr, invoked); if (!pnexpr) return null(); - if (!MatchOrInsertSemicolonAfterExpression(tokenStream)) + if (!matchOrInsertSemicolonAfterExpression()) return null(); return handler.newExprStatement(pnexpr, pos().end); } @@ -5870,7 +5893,7 @@ Parser::continueStatement(YieldHandling yieldHandling) return null(); } - if (!MatchOrInsertSemicolonAfterNonExpression(tokenStream)) + if (!matchOrInsertSemicolonAfterNonExpression()) return null(); return handler.newContinueStatement(label, TokenPos(begin, pos().end)); @@ -5910,7 +5933,7 @@ Parser::breakStatement(YieldHandling yieldHandling) } } - if (!MatchOrInsertSemicolonAfterNonExpression(tokenStream)) + if (!matchOrInsertSemicolonAfterNonExpression()) return null(); return handler.newBreakStatement(label, TokenPos(begin, pos().end)); @@ -5950,10 +5973,10 @@ Parser::returnStatement(YieldHandling yieldHandling) } if (exprNode) { - if (!MatchOrInsertSemicolonAfterExpression(tokenStream)) + if (!matchOrInsertSemicolonAfterExpression()) return null(); } else { - if (!MatchOrInsertSemicolonAfterNonExpression(tokenStream)) + if (!matchOrInsertSemicolonAfterNonExpression()) return null(); } @@ -6250,7 +6273,7 @@ Parser::throwStatement(YieldHandling yieldHandling) if (!throwExpr) return null(); - if (!MatchOrInsertSemicolonAfterExpression(tokenStream)) + if (!matchOrInsertSemicolonAfterExpression()) return null(); return handler.newThrowStatement(throwExpr, TokenPos(begin, pos().end)); @@ -6477,7 +6500,7 @@ Parser::debuggerStatement() { TokenPos p; p.begin = pos().begin; - if (!MatchOrInsertSemicolonAfterNonExpression(tokenStream)) + if (!matchOrInsertSemicolonAfterNonExpression()) return null(); p.end = pos().end; @@ -6784,7 +6807,7 @@ Parser::variableStatement(YieldHandling yieldHandling) Node vars = declarationList(yieldHandling, PNK_VAR); if (!vars) return null(); - if (!MatchOrInsertSemicolonAfterExpression(tokenStream)) + if (!matchOrInsertSemicolonAfterExpression()) return null(); return vars; } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 156a1c1b0..41abb6d76 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1354,6 +1354,10 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool finishFunction(); bool leaveInnerFunction(ParseContext* outerpc); + bool matchOrInsertSemicolonHelper(TokenStream::Modifier modifier); + bool matchOrInsertSemicolonAfterExpression(); + bool matchOrInsertSemicolonAfterNonExpression(); + public: enum FunctionCallBehavior { PermitAssignmentToFunctionCalls, diff --git a/js/src/js.msg b/js/src/js.msg index 4ded69a25..50817f50f 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -186,6 +186,7 @@ MSG_DEF(JSMSG_AS_AFTER_IMPORT_STAR, 0, JSEXN_SYNTAXERR, "missing keyword 'as' MSG_DEF(JSMSG_AS_AFTER_RESERVED_WORD, 1, JSEXN_SYNTAXERR, "missing keyword 'as' after reserved word '{0}'") MSG_DEF(JSMSG_ASYNC_GENERATOR, 0, JSEXN_SYNTAXERR, "generator function or method can't be async") MSG_DEF(JSMSG_AWAIT_IN_DEFAULT, 0, JSEXN_SYNTAXERR, "await can't be used in default expression") +MSG_DEF(JSMSG_AWAIT_OUTSIDE_ASYNC, 0, JSEXN_SYNTAXERR, "await is only valid in async functions") MSG_DEF(JSMSG_BAD_ARROW_ARGS, 0, JSEXN_SYNTAXERR, "invalid arrow-function arguments (parentheses around the arrow-function may help)") MSG_DEF(JSMSG_BAD_BINDING, 1, JSEXN_SYNTAXERR, "redefining {0} is deprecated") MSG_DEF(JSMSG_BAD_CONST_DECL, 0, JSEXN_SYNTAXERR, "missing = in const declaration") diff --git a/js/src/tests/ecma_2017/AsyncFunctions/await-error.js b/js/src/tests/ecma_2017/AsyncFunctions/await-error.js new file mode 100644 index 000000000..1f40ea8a0 --- /dev/null +++ b/js/src/tests/ecma_2017/AsyncFunctions/await-error.js @@ -0,0 +1,16 @@ +var BUGNUMBER = 1317153; +var summary = "await outside of async function should provide better error"; + +print(BUGNUMBER + ": " + summary); + +let caught = false; +try { + eval("await 10"); +} catch(e) { + assertEq(e.message, "await is only valid in async functions"); + caught = true; +} +assertEq(caught, true); + +if (typeof reportCompare === "function") + reportCompare(true, true); -- cgit v1.2.3 From 987d6726f3c64d1cc510acba1de08deb5e0a7702 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 14:34:29 -0400 Subject: 1296814 - Move FunctionDeclaration-as-consequent/alternative handling out of Parser::functionStmt into Parser::consequentOrAlternative. --- js/src/frontend/Parser.cpp | 56 ++++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 32 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 3c509465f..8f52f1d27 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -3550,21 +3550,6 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION)); - // Annex B.3.4 says we can parse function declarations unbraced under if - // or else as if it were braced. That is, |if (x) function f() {}| is - // parsed as |if (x) { function f() {} }|. - Maybe synthesizedStmtForAnnexB; - Maybe synthesizedScopeForAnnexB; - if (!pc->sc()->strict()) { - ParseContext::Statement* stmt = pc->innermostStatement(); - if (stmt && stmt->kind() == StatementKind::If) { - synthesizedStmtForAnnexB.emplace(pc, StatementKind::Block); - synthesizedScopeForAnnexB.emplace(this); - if (!synthesizedScopeForAnnexB->init(pc)) - return null(); - } - } - // In sloppy mode, Annex B.3.2 allows labelled function declarations. // Otherwise it's a parse error. ParseContext::Statement* declaredInStmt = pc->innermostStatement(); @@ -3645,20 +3630,8 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan return null(); YieldHandling newYieldHandling = GetYieldHandling(generatorKind, asyncKind); - Node fun = functionDefinition(preludeStart, pn, InAllowed, newYieldHandling, + return functionDefinition(preludeStart, pn, InAllowed, newYieldHandling, name, Statement, generatorKind, asyncKind, tryAnnexB); - if (!fun) - return null(); - - if (synthesizedStmtForAnnexB) { - Node synthesizedStmtList = handler.newStatementList(handler.getPosition(fun)); - if (!synthesizedStmtList) - return null(); - handler.addStatementToList(synthesizedStmtList, fun); - return finishLexicalScope(*synthesizedScopeForAnnexB, synthesizedStmtList); - } - - return fun; } template @@ -5276,13 +5249,32 @@ Parser::consequentOrAlternative(YieldHandling yieldHandling) return null(); if (next == TOK_FUNCTION) { - // Apply Annex B.3.4 in non-strict code to allow FunctionDeclaration as - // the consequent/alternative of an |if| or |else|. Parser::statement - // will report the strict mode error. + // Annex B.3.4 says that unbraced function declarations under if/else + // in non-strict code act as if they were braced. That is, + // |if (x) function f() {}| is parsed as |if (x) { function f() {} }|. if (!pc->sc()->strict()) { tokenStream.consumeKnownToken(next, TokenStream::Operand); - return functionStmt(pos().begin, yieldHandling, NameRequired); + + ParseContext::Statement stmt(pc, StatementKind::Block); + ParseContext::Scope scope(this); + if (!scope.init(pc)) + return null(); + + TokenPos funcPos = pos(); + Node fun = functionStmt(pos().begin, yieldHandling, NameRequired); + if (!fun) + return null(); + + Node block = handler.newStatementList(funcPos); + if (!block) + return null(); + + handler.addStatementToList(block, fun); + return finishLexicalScope(scope, block); } + + // Function declarations are a syntax error in strict mode code. + // Parser::statement reports that error. } return statement(yieldHandling); -- cgit v1.2.3 From 7ecc50d90d13690d610f26d0056a326e52bc834c Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 14:51:46 -0400 Subject: 1317379 - Disallow generator functions and async functions as direct children of if/else. --- js/src/frontend/Parser.cpp | 83 ++++++++++++++++------ .../AsyncFunctions/forbidden-as-consequent.js | 14 ++++ .../ecma_6/Generators/forbidden-as-consequent.js | 11 +++ 3 files changed, 87 insertions(+), 21 deletions(-) create mode 100644 js/src/tests/ecma_2017/AsyncFunctions/forbidden-as-consequent.js create mode 100644 js/src/tests/ecma_6/Generators/forbidden-as-consequent.js (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 8f52f1d27..a7b1f3a14 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -5248,33 +5248,74 @@ Parser::consequentOrAlternative(YieldHandling yieldHandling) if (!tokenStream.peekToken(&next, TokenStream::Operand)) return null(); - if (next == TOK_FUNCTION) { - // Annex B.3.4 says that unbraced function declarations under if/else - // in non-strict code act as if they were braced. That is, - // |if (x) function f() {}| is parsed as |if (x) { function f() {} }|. - if (!pc->sc()->strict()) { - tokenStream.consumeKnownToken(next, TokenStream::Operand); + // Annex B.3.4 says that unbraced FunctionDeclarations under if/else in + // non-strict code act as if they were braced: |if (x) function f() {}| + // parses as |if (x) { function f() {} }|. + // + // Careful! FunctionDeclaration doesn't include generators or async + // functions. + if (next == TOK_NAME && + !tokenStream.nextNameContainsEscape() && + tokenStream.nextName() == context->names().async) + { + tokenStream.consumeKnownToken(next, TokenStream::Operand); - ParseContext::Statement stmt(pc, StatementKind::Block); - ParseContext::Scope scope(this); - if (!scope.init(pc)) - return null(); + // Peek only on the same line: ExpressionStatement's lookahead + // restriction is phrased as + // + // [lookahead ∉ { {, function, async [no LineTerminator here] function, class, let [ }] + // + // meaning that code like this is valid: + // + // if (true) + // async // ASI opportunity + // function clownshoes() {} + TokenKind maybeFunction; + if (!tokenStream.peekTokenSameLine(&maybeFunction)) + return null(); - TokenPos funcPos = pos(); - Node fun = functionStmt(pos().begin, yieldHandling, NameRequired); - if (!fun) - return null(); + if (maybeFunction == TOK_FUNCTION) { + error(JSMSG_FORBIDDEN_AS_STATEMENT, "async function declarations"); + return null(); + } - Node block = handler.newStatementList(funcPos); - if (!block) - return null(); + // Otherwise this |async| begins an ExpressionStatement. + tokenStream.ungetToken(); + } else if (next == TOK_FUNCTION) { + tokenStream.consumeKnownToken(next, TokenStream::Operand); - handler.addStatementToList(block, fun); - return finishLexicalScope(scope, block); + // Parser::statement would handle this, but as this function handles + // every other error case, it seems best to handle this. + if (pc->sc()->strict()) { + error(JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations"); + return null(); + } + + TokenKind maybeStar; + if (!tokenStream.peekToken(&maybeStar)) + return null(); + + if (maybeStar == TOK_MUL) { + error(JSMSG_FORBIDDEN_AS_STATEMENT, "generator declarations"); + return null(); } - // Function declarations are a syntax error in strict mode code. - // Parser::statement reports that error. + ParseContext::Statement stmt(pc, StatementKind::Block); + ParseContext::Scope scope(this); + if (!scope.init(pc)) + return null(); + + TokenPos funcPos = pos(); + Node fun = functionStmt(pos().begin, yieldHandling, NameRequired); + if (!fun) + return null(); + + Node block = handler.newStatementList(funcPos); + if (!block) + return null(); + + handler.addStatementToList(block, fun); + return finishLexicalScope(scope, block); } return statement(yieldHandling); diff --git a/js/src/tests/ecma_2017/AsyncFunctions/forbidden-as-consequent.js b/js/src/tests/ecma_2017/AsyncFunctions/forbidden-as-consequent.js new file mode 100644 index 000000000..656ed46de --- /dev/null +++ b/js/src/tests/ecma_2017/AsyncFunctions/forbidden-as-consequent.js @@ -0,0 +1,14 @@ +/* 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/. */ + +assertThrowsInstanceOf(() => eval("if (1) async function foo() {}"), + SyntaxError); +assertThrowsInstanceOf(() => eval("'use strict'; if (1) async function foo() {}"), + SyntaxError); + +var async = 42; +assertEq(eval("if (1) async \n function foo() {}"), 42); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Generators/forbidden-as-consequent.js b/js/src/tests/ecma_6/Generators/forbidden-as-consequent.js new file mode 100644 index 000000000..13647e154 --- /dev/null +++ b/js/src/tests/ecma_6/Generators/forbidden-as-consequent.js @@ -0,0 +1,11 @@ +/* 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/. */ + +assertThrowsInstanceOf(() => eval("if (1) function* foo() {}"), + SyntaxError); +assertThrowsInstanceOf(() => eval("'use strict'; if (1) function* foo() {}"), + SyntaxError); + +if (typeof reportCompare === "function") + reportCompare(true, true); -- cgit v1.2.3 From 986ae6266566447f22be68caf6371cbf98cafd52 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 15:03:53 -0400 Subject: 636635 - Do not create named lambda binding for a function created by Function constructor. --- js/src/frontend/Parser.cpp | 21 ++++---- js/src/frontend/Parser.h | 7 +-- js/src/jsapi-tests/moz.build | 1 + js/src/jsapi-tests/testFunctionBinding.cpp | 58 ++++++++++++++++++++++ .../tests/ecma_6/Function/constructor-binding.js | 11 ++++ 5 files changed, 85 insertions(+), 13 deletions(-) create mode 100644 js/src/jsapi-tests/testFunctionBinding.cpp create mode 100644 js/src/tests/ecma_6/Function/constructor-binding.js (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index a7b1f3a14..c86d9ca7b 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -2173,7 +2173,7 @@ Parser::declareDotGeneratorName() template bool -Parser::finishFunctionScopes() +Parser::finishFunctionScopes(bool isStandaloneFunction) { FunctionBox* funbox = pc->functionBox(); @@ -2182,7 +2182,7 @@ Parser::finishFunctionScopes() return false; } - if (funbox->function()->isNamedLambda()) { + if (funbox->function()->isNamedLambda() && !isStandaloneFunction) { if (!propagateFreeNamesAndMarkClosedOverBindings(pc->namedLambdaScope())) return false; } @@ -2192,9 +2192,9 @@ Parser::finishFunctionScopes() template <> bool -Parser::finishFunction() +Parser::finishFunction(bool isStandaloneFunction /* = false */) { - if (!finishFunctionScopes()) + if (!finishFunctionScopes(isStandaloneFunction)) return false; FunctionBox* funbox = pc->functionBox(); @@ -2215,7 +2215,7 @@ Parser::finishFunction() funbox->functionScopeBindings().set(*bindings); } - if (funbox->function()->isNamedLambda()) { + if (funbox->function()->isNamedLambda() && !isStandaloneFunction) { Maybe bindings = newLexicalScopeData(pc->namedLambdaScope()); if (!bindings) return false; @@ -2227,14 +2227,14 @@ Parser::finishFunction() template <> bool -Parser::finishFunction() +Parser::finishFunction(bool isStandaloneFunction /* = false */) { // The LazyScript for a lazily parsed function needs to know its set of // free variables and inner functions so that when it is fully parsed, we // can skip over any already syntax parsed inner functions and still // retain correct scope information. - if (!finishFunctionScopes()) + if (!finishFunctionScopes(isStandaloneFunction)) return false; // There are too many bindings or inner functions to be saved into the @@ -2354,7 +2354,7 @@ Parser::standaloneFunction(HandleFunction fun, YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind); AutoAwaitIsKeyword awaitIsKeyword(&tokenStream, asyncKind == AsyncFunction); if (!functionFormalParametersAndBody(InAllowed, yieldHandling, fn, Statement, - parameterListEnd)) + parameterListEnd, /* isStandaloneFunction = */ true)) { return null(); } @@ -3425,7 +3425,8 @@ bool Parser::functionFormalParametersAndBody(InHandling inHandling, YieldHandling yieldHandling, Node pn, FunctionSyntaxKind kind, - Maybe parameterListEnd /* = Nothing() */) + Maybe parameterListEnd /* = Nothing() */, + bool isStandaloneFunction /* = false */) { // Given a properly initialized parse context, try to parse an actual // function without concern for conversion to strict mode, use of lazy @@ -3533,7 +3534,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if (IsMethodDefinitionKind(kind) && pc->superScopeNeedsHomeObject()) funbox->setNeedsHomeObject(); - if (!finishFunction()) + if (!finishFunction(isStandaloneFunction)) return false; handler.setEndPosition(body, pos().begin); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 41abb6d76..f6cff8a6c 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1070,7 +1070,8 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter // ParseContext is already on the stack. bool functionFormalParametersAndBody(InHandling inHandling, YieldHandling yieldHandling, Node pn, FunctionSyntaxKind kind, - mozilla::Maybe parameterListEnd = mozilla::Nothing()); + mozilla::Maybe parameterListEnd = mozilla::Nothing(), + bool isStandaloneFunction = false); // Determine whether |yield| is a valid name in the current context, or @@ -1350,8 +1351,8 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB, Directives inheritedDirectives, Directives* newDirectives); - bool finishFunctionScopes(); - bool finishFunction(); + bool finishFunctionScopes(bool isStandaloneFunction); + bool finishFunction(bool isStandaloneFunction = false); bool leaveInnerFunction(ParseContext* outerpc); bool matchOrInsertSemicolonHelper(TokenStream::Modifier modifier); diff --git a/js/src/jsapi-tests/moz.build b/js/src/jsapi-tests/moz.build index 277a145b0..c176fbf0a 100644 --- a/js/src/jsapi-tests/moz.build +++ b/js/src/jsapi-tests/moz.build @@ -37,6 +37,7 @@ UNIFIED_SOURCES += [ 'testForOfIterator.cpp', 'testForwardSetProperty.cpp', 'testFreshGlobalEvalRedefinition.cpp', + 'testFunctionBinding.cpp', 'testFunctionProperties.cpp', 'testGCAllocator.cpp', 'testGCCellPtr.cpp', diff --git a/js/src/jsapi-tests/testFunctionBinding.cpp b/js/src/jsapi-tests/testFunctionBinding.cpp new file mode 100644 index 000000000..33632db14 --- /dev/null +++ b/js/src/jsapi-tests/testFunctionBinding.cpp @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * + * Test function name binding. + */ +/* 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/. */ + +#include "jsfriendapi.h" + +#include "jsapi-tests/tests.h" + +using namespace js; + +BEGIN_TEST(test_functionBinding) +{ + RootedFunction fun(cx); + + JS::CompileOptions options(cx); + options.setFileAndLine(__FILE__, __LINE__); + + // Named function shouldn't have it's binding. + const char s1chars[] = "return (typeof s1) == 'undefined';"; + JS::AutoObjectVector emptyScopeChain(cx); + CHECK(JS::CompileFunction(cx, emptyScopeChain, options, "s1", 0, nullptr, s1chars, + strlen(s1chars), &fun)); + CHECK(fun); + + JS::AutoValueVector args(cx); + RootedValue rval(cx); + CHECK(JS::Call(cx, UndefinedHandleValue, fun, args, &rval)); + CHECK(rval.isBoolean()); + CHECK(rval.toBoolean()); + + // Named function shouldn't have `anonymous` binding. + const char s2chars[] = "return (typeof anonymous) == 'undefined';"; + CHECK(JS::CompileFunction(cx, emptyScopeChain, options, "s2", 0, nullptr, s2chars, + strlen(s2chars), &fun)); + CHECK(fun); + + CHECK(JS::Call(cx, UndefinedHandleValue, fun, args, &rval)); + CHECK(rval.isBoolean()); + CHECK(rval.toBoolean()); + + // Anonymous function shouldn't have `anonymous` binding. + const char s3chars[] = "return (typeof anonymous) == 'undefined';"; + CHECK(JS::CompileFunction(cx, emptyScopeChain, options, nullptr, 0, nullptr, s3chars, + strlen(s3chars), &fun)); + CHECK(fun); + + CHECK(JS::Call(cx, UndefinedHandleValue, fun, args, &rval)); + CHECK(rval.isBoolean()); + CHECK(rval.toBoolean()); + + return true; +} +END_TEST(test_functionBinding) diff --git a/js/src/tests/ecma_6/Function/constructor-binding.js b/js/src/tests/ecma_6/Function/constructor-binding.js new file mode 100644 index 000000000..e82274d27 --- /dev/null +++ b/js/src/tests/ecma_6/Function/constructor-binding.js @@ -0,0 +1,11 @@ +var BUGNUMBER = 636635; +var summary = "A function created by Function constructor shouldn't have anonymous binding"; + +print(BUGNUMBER + ": " + summary); + +assertEq(new Function("return typeof anonymous")(), "undefined"); +assertEq(new Function("return function() { return typeof anonymous; }")()(), "undefined"); +assertEq(new Function("return function() { eval(''); return typeof anonymous; }")()(), "undefined"); + +if (typeof reportCompare === "function") + reportCompare(true, true); -- cgit v1.2.3 From 90d999c59a08bfc3145317aa4f0a92db0597632e Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 15:12:00 -0400 Subject: 1320403 - Move JSFunction::EXPR_BODY to JSScript, LazyScript, and FunctionBox. --- js/src/builtin/ReflectParse.cpp | 7 +------ js/src/frontend/Parser.cpp | 18 +++++++++++++----- js/src/frontend/SharedContext.h | 8 ++++++++ js/src/jsfun.cpp | 2 -- js/src/jsfun.h | 10 +--------- js/src/jsscript.cpp | 9 +++++++++ js/src/jsscript.h | 22 +++++++++++++++++++++- js/src/shell/js.cpp | 2 +- js/src/wasm/AsmJS.cpp | 3 +-- 9 files changed, 55 insertions(+), 26 deletions(-) (limited to 'js/src') diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp index beff58e13..2a0a08a5d 100644 --- a/js/src/builtin/ReflectParse.cpp +++ b/js/src/builtin/ReflectParse.cpp @@ -3407,12 +3407,7 @@ ASTSerializer::function(ParseNode* pn, ASTType type, MutableHandleValue dst) : GeneratorStyle::None; bool isAsync = pn->pn_funbox->isAsync(); - bool isExpression = -#if JS_HAS_EXPR_CLOSURES - func->isExprBody(); -#else - false; -#endif + bool isExpression = pn->pn_funbox->isExprBody(); RootedValue id(cx); RootedAtom funcAtom(cx, func->explicitName()); diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index c86d9ca7b..2a80afbf1 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -474,6 +474,7 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* trac usesThis(false), usesReturn(false), hasRest_(false), + isExprBody_(false), funCxFlags() { // Functions created at parse time may be set singleton after parsing and @@ -2264,6 +2265,8 @@ Parser::finishFunction(bool isStandaloneFunction /* = false lazy->setAsyncKind(funbox->asyncKind()); if (funbox->hasRest()) lazy->setHasRest(); + if (funbox->isExprBody()) + lazy->setIsExprBody(); if (funbox->isLikelyConstructorWrapper()) lazy->setLikelyConstructorWrapper(); if (funbox->isDerivedClassConstructor()) @@ -3030,6 +3033,8 @@ Parser::skipLazyInnerFunction(ParseNode* pn, uint32_t preludeS LazyScript* lazy = fun->lazyScript(); if (lazy->needsHomeObject()) funbox->setNeedsHomeObject(); + if (lazy->isExprBody()) + funbox->setIsExprBody(); PropagateTransitiveParseFlags(lazy, pc->sc()); @@ -3042,10 +3047,15 @@ Parser::skipLazyInnerFunction(ParseNode* pn, uint32_t preludeS if (!tokenStream.advance(fun->lazyScript()->end() - userbufBase)) return false; - if (kind == Statement && fun->isExprBody()) { +#if JS_HAS_EXPR_CLOSURES + // Only expression closure can be Statement kind. + // If we remove expression closure, we can remove isExprBody flag from + // LazyScript and JSScript. + if (kind == Statement && funbox->isExprBody()) { if (!matchOrInsertSemicolonAfterExpression()) return false; } +#endif return true; } @@ -3490,9 +3500,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, tokenStream.ungetToken(); bodyType = ExpressionBody; -#if JS_HAS_EXPR_CLOSURES - fun->setIsExprBody(); -#endif + funbox->setIsExprBody(); } // Arrow function parameters inherit yieldHandling from the enclosing @@ -6130,7 +6138,7 @@ Parser::yieldExpression(InHandling inHandling) if (pc->funHasReturnExpr #if JS_HAS_EXPR_CLOSURES - || pc->functionBox()->function()->isExprBody() + || pc->functionBox()->isExprBody() #endif ) { diff --git a/js/src/frontend/SharedContext.h b/js/src/frontend/SharedContext.h index b20417d5d..f5a74e18c 100644 --- a/js/src/frontend/SharedContext.h +++ b/js/src/frontend/SharedContext.h @@ -473,6 +473,9 @@ class FunctionBox : public ObjectBox, public SharedContext bool usesThis:1; /* contains 'this' */ bool usesReturn:1; /* contains a 'return' statement */ bool hasRest_:1; /* has rest parameter */ + bool isExprBody_:1; /* arrow function with expression + * body or expression closure: + * function(x) x*x */ FunctionContextFlags funCxFlags; @@ -546,6 +549,11 @@ class FunctionBox : public ObjectBox, public SharedContext hasRest_ = true; } + bool isExprBody() const { return isExprBody_; } + void setIsExprBody() { + isExprBody_ = true; + } + void setGeneratorKind(GeneratorKind kind) { // A generator kind can be set at initialization, or when "yield" is // first seen. In both cases the transition can only happen from diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 3cba3434d..304700da2 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -980,8 +980,6 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint) return nullptr; } } else { - MOZ_ASSERT(!fun->isExprBody()); - bool derived = fun->infallibleIsDefaultClassConstructor(cx); if (derived && fun->isDerivedClassConstructor()) { if (!AppendPrelude() || diff --git a/js/src/jsfun.h b/js/src/jsfun.h index 62b285806..b91c69d33 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -58,8 +58,6 @@ class JSFunction : public js::NativeObject CONSTRUCTOR = 0x0002, /* function that can be called as a constructor */ EXTENDED = 0x0004, /* structure is FunctionExtended */ 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 name was guessed for it anyway */ LAMBDA = 0x0040, /* function comes from a FunctionExpression, ArrowFunction, or @@ -102,7 +100,7 @@ class JSFunction : public js::NativeObject INTERPRETED_GENERATOR = INTERPRETED, NO_XDR_FLAGS = RESOLVED_LENGTH | RESOLVED_NAME, - STABLE_ACROSS_CLONES = CONSTRUCTOR | EXPR_BODY | HAS_GUESSED_ATOM | LAMBDA | + STABLE_ACROSS_CLONES = CONSTRUCTOR | HAS_GUESSED_ATOM | LAMBDA | SELF_HOSTED | HAS_COMPILE_TIME_NAME | FUNCTION_KIND_MASK }; @@ -187,7 +185,6 @@ class JSFunction : public js::NativeObject bool isAsmJSNative() const { return kind() == AsmJS; } /* Possible attributes of an interpreted function: */ - bool isExprBody() const { return flags() & EXPR_BODY; } bool hasCompileTimeName() const { return flags() & HAS_COMPILE_TIME_NAME; } bool hasGuessedAtom() const { return flags() & HAS_GUESSED_ATOM; } bool isLambda() const { return flags() & LAMBDA; } @@ -290,11 +287,6 @@ class JSFunction : public js::NativeObject flags_ |= SELF_HOSTED; } - // Can be called multiple times by the parser. - void setIsExprBody() { - flags_ |= EXPR_BODY; - } - void setArrow() { setKind(Arrow); } diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 33ae56d6f..899820a0d 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -319,6 +319,7 @@ js::XDRScript(XDRState* xdr, HandleScope scriptEnclosingScope, HandleScrip IsStarGenerator, IsAsync, HasRest, + IsExprBody, OwnSource, ExplicitUseStrict, SelfHosted, @@ -436,6 +437,8 @@ js::XDRScript(XDRState* xdr, HandleScope scriptEnclosingScope, HandleScrip scriptBits |= (1 << IsAsync); if (script->hasRest()) scriptBits |= (1 << HasRest); + if (script->isExprBody()) + scriptBits |= (1 << IsExprBody); if (script->hasSingletons()) scriptBits |= (1 << HasSingleton); if (script->treatAsRunOnce()) @@ -589,6 +592,8 @@ js::XDRScript(XDRState* xdr, HandleScope scriptEnclosingScope, HandleScrip script->setAsyncKind(AsyncFunction); if (scriptBits & (1 << HasRest)) script->setHasRest(); + if (scriptBits & (1 << IsExprBody)) + script->setIsExprBody(); } JS_STATIC_ASSERT(sizeof(jsbytecode) == 1); @@ -2660,6 +2665,8 @@ JSScript::initFromFunctionBox(ExclusiveContext* cx, HandleScript script, script->setAsyncKind(funbox->asyncKind()); if (funbox->hasRest()) script->setHasRest(); + if (funbox->isExprBody()) + script->setIsExprBody(); PositionalFormalParameterIter fi(script); while (fi && !fi.closedOver()) @@ -3320,6 +3327,7 @@ js::detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst, dst->isDefaultClassConstructor_ = src->isDefaultClassConstructor(); dst->isAsync_ = src->asyncKind() == AsyncFunction; dst->hasRest_ = src->hasRest_; + dst->isExprBody_ = src->isExprBody_; if (nconsts != 0) { GCPtrValue* vector = Rebase(dst, src, src->consts()->vector); @@ -4059,6 +4067,7 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun, p.hasThisBinding = false; p.isAsync = false; p.hasRest = false; + p.isExprBody = false; p.numClosedOverBindings = closedOverBindings.length(); p.numInnerFunctions = innerFunctions.length(); p.generatorKindBits = GeneratorKindAsBits(NotGenerator); diff --git a/js/src/jsscript.h b/js/src/jsscript.h index bb8635581..c3298a884 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -1021,6 +1021,7 @@ class JSScript : public js::gc::TenuredCell bool isAsync_:1; bool hasRest_:1; + bool isExprBody_:1; // Add padding so JSScript is gc::Cell aligned. Make padding protected // instead of private to suppress -Wunused-private-field compiler warnings. @@ -1329,6 +1330,13 @@ class JSScript : public js::gc::TenuredCell hasRest_ = true; } + bool isExprBody() const { + return isExprBody_; + } + void setIsExprBody() { + isExprBody_ = true; + } + void setNeedsHomeObject() { needsHomeObject_ = true; } @@ -1936,7 +1944,7 @@ class LazyScript : public gc::TenuredCell #endif private: - static const uint32_t NumClosedOverBindingsBits = 21; + static const uint32_t NumClosedOverBindingsBits = 20; static const uint32_t NumInnerFunctionsBits = 20; struct PackedView { @@ -1946,7 +1954,12 @@ class LazyScript : public gc::TenuredCell uint32_t shouldDeclareArguments : 1; uint32_t hasThisBinding : 1; uint32_t isAsync : 1; + uint32_t isExprBody : 1; + uint32_t numClosedOverBindings : NumClosedOverBindingsBits; + + // -- 32bit boundary -- + uint32_t numInnerFunctions : NumInnerFunctionsBits; uint32_t generatorKindBits : 2; @@ -2104,6 +2117,13 @@ class LazyScript : public gc::TenuredCell p_.hasRest = true; } + bool isExprBody() const { + return p_.isExprBody; + } + void setIsExprBody() { + p_.isExprBody = true; + } + bool strict() const { return p_.strict; } diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 617b5e902..f6a13623c 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -2689,7 +2689,7 @@ DisassembleScript(JSContext* cx, HandleScript script, HandleFunction fun, if (sp->put(" CONSTRUCTOR") < 0) return false; } - if (fun->isExprBody()) { + if (script->isExprBody()) { if (sp->put(" EXPRESSION_CLOSURE") < 0) return false; } diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp index a318d67a9..6483d6ec3 100644 --- a/js/src/wasm/AsmJS.cpp +++ b/js/src/wasm/AsmJS.cpp @@ -3250,10 +3250,9 @@ CheckModuleLevelName(ModuleValidator& m, ParseNode* usepn, PropertyName* name) static bool CheckFunctionHead(ModuleValidator& m, ParseNode* fn) { - JSFunction* fun = FunctionObject(fn); if (fn->pn_funbox->hasRest()) return m.fail(fn, "rest args not allowed"); - if (fun->isExprBody()) + if (fn->pn_funbox->isExprBody()) return m.fail(fn, "expression closures not allowed"); if (fn->pn_funbox->hasDestructuringArgs) return m.fail(fn, "destructuring args not allowed"); -- cgit v1.2.3 From 7535217e1b164417d9aa05c38e5c23048c8d47ce Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 15:15:05 -0400 Subject: 1325473 - A TypeError should be thrown when accessing 'arguments' or 'caller' on any of the new function types. --- js/src/jsfun.cpp | 13 ++++++- .../newer-type-functions-caller-arguments.js | 43 ++++++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 js/src/tests/ecma_6/extensions/newer-type-functions-caller-arguments.js (limited to 'js/src') diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 304700da2..ef5aea768 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -129,6 +129,11 @@ IsFunctionInStrictMode(JSFunction* fun) return IsAsmJSStrictModeModuleOrFunction(fun); } +static bool +IsNewerTypeFunction(JSFunction* fun) { + return fun->isArrow() || fun->isGenerator() || fun->isAsync() || fun->isMethod(); +} + // Beware: this function can be invoked on *any* function! That includes // natives, strict mode functions, bound functions, arrow functions, // self-hosted functions and constructors, asm.js functions, functions with @@ -142,7 +147,9 @@ ArgumentsRestrictions(JSContext* cx, HandleFunction fun) // a strict mode function, or a bound function. // TODO (bug 1057208): ensure semantics are correct for all possible // pairings of callee/caller. - if (fun->isBuiltin() || IsFunctionInStrictMode(fun) || fun->isBoundFunction()) { + if (fun->isBuiltin() || IsFunctionInStrictMode(fun) || + fun->isBoundFunction() || IsNewerTypeFunction(fun)) + { ThrowTypeErrorBehavior(cx); return false; } @@ -229,7 +236,9 @@ CallerRestrictions(JSContext* cx, HandleFunction fun) // a strict mode function, or a bound function. // TODO (bug 1057208): ensure semantics are correct for all possible // pairings of callee/caller. - if (fun->isBuiltin() || IsFunctionInStrictMode(fun) || fun->isBoundFunction()) { + if (fun->isBuiltin() || IsFunctionInStrictMode(fun) || + fun->isBoundFunction() || IsNewerTypeFunction(fun)) + { ThrowTypeErrorBehavior(cx); return false; } diff --git a/js/src/tests/ecma_6/extensions/newer-type-functions-caller-arguments.js b/js/src/tests/ecma_6/extensions/newer-type-functions-caller-arguments.js new file mode 100644 index 000000000..7fed18037 --- /dev/null +++ b/js/src/tests/ecma_6/extensions/newer-type-functions-caller-arguments.js @@ -0,0 +1,43 @@ +// Tests that newer-type functions (i.e. anything not defined by regular function declarations and +// expressions) throw when accessing their 'arguments' and 'caller' properties. + +// 9.2.7 (AddRestrictedFunctionProperties) defines accessors on Function.prototype which throw on +// every 'get' and 'set' of 'caller' and 'arguments'. +// Additionally, 16.2 (Forbidden Extensions) forbids adding properties to all non-"legacy" function +// declarations and expressions. This creates the effect that all newer-style functions act like +// strict-mode functions when accessing their 'caller' and 'arguments' properties. + +const container = { + async asyncMethod() {}, + *genMethod() {}, + method() {} +}; + +[ + async function(){}, + function*(){}, + () => {}, + async () => {}, + + container.asyncMethod, + container.genMethod, + container.method +].forEach(f => { + checkArgumentsAccess(f); + checkCallerAccess(f); +}); + +function checkArgumentsAccess(f) { + assertThrowsInstanceOf(() => f.arguments, TypeError, + `Expected 'arguments' property access to throw on ${f}`); +} + +function checkCallerAccess(f) { + assertThrowsInstanceOf(() => f.caller, TypeError, + `Expected 'caller' property access to throw on ${f}`); +} + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); -- cgit v1.2.3 From c3e3a917d634ee1e550b2a19096ee99dc2024139 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 15:29:37 -0400 Subject: 1325157 - Implement a ParserBase class that holds functionality that's identical between syntax parsing and full parsing. --- js/src/frontend/Parser.cpp | 100 +++++++++--------- js/src/frontend/Parser.h | 251 +++++++++++++++++++++++---------------------- 2 files changed, 181 insertions(+), 170 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 2a80afbf1..79b5d70f4 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -571,9 +571,8 @@ FunctionBox::initWithEnclosingScope(Scope* enclosingScope) computeInWith(enclosingScope); } -template void -Parser::error(unsigned errorNumber, ...) +ParserBase::error(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); @@ -585,9 +584,8 @@ Parser::error(unsigned errorNumber, ...) va_end(args); } -template void -Parser::errorAt(uint32_t offset, unsigned errorNumber, ...) +ParserBase::errorAt(uint32_t offset, unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); @@ -599,9 +597,8 @@ Parser::errorAt(uint32_t offset, unsigned errorNumber, ...) va_end(args); } -template bool -Parser::warning(unsigned errorNumber, ...) +ParserBase::warning(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); @@ -611,9 +608,8 @@ Parser::warning(unsigned errorNumber, ...) return result; } -template bool -Parser::warningAt(uint32_t offset, unsigned errorNumber, ...) +ParserBase::warningAt(uint32_t offset, unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); @@ -623,9 +619,8 @@ Parser::warningAt(uint32_t offset, unsigned errorNumber, ...) return result; } -template bool -Parser::extraWarning(unsigned errorNumber, ...) +ParserBase::extraWarning(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); @@ -634,9 +629,8 @@ Parser::extraWarning(unsigned errorNumber, ...) return result; } -template bool -Parser::strictModeError(unsigned errorNumber, ...) +ParserBase::strictModeError(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); @@ -647,9 +641,8 @@ Parser::strictModeError(unsigned errorNumber, ...) return res; } -template bool -Parser::strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...) +ParserBase::strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); @@ -659,9 +652,8 @@ Parser::strictModeErrorAt(uint32_t offset, unsigned errorNumber, . return res; } -template bool -Parser::reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...) +ParserBase::reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); @@ -702,16 +694,14 @@ Parser::abortIfSyntaxParser() return false; } -template -Parser::Parser(ExclusiveContext* cx, LifoAlloc& alloc, - const ReadOnlyCompileOptions& options, - const char16_t* chars, size_t length, - bool foldConstants, - UsedNameTracker& usedNames, - Parser* syntaxParser, - LazyScript* lazyOuterFunction) - : AutoGCRooter(cx, PARSER), - context(cx), +ParserBase::ParserBase(ExclusiveContext* cx, LifoAlloc& alloc, + const ReadOnlyCompileOptions& options, + const char16_t* chars, size_t length, + bool foldConstants, + UsedNameTracker& usedNames, + Parser* syntaxParser, + LazyScript* lazyOuterFunction) + : context(cx), alloc(alloc), tokenStream(cx, options, chars, length, thisForCtor()), traceListHead(nullptr), @@ -725,18 +715,44 @@ Parser::Parser(ExclusiveContext* cx, LifoAlloc& alloc, checkOptionsCalled(false), #endif abortedSyntaxParse(false), - isUnexpectedEOF_(false), - handler(cx, alloc, tokenStream, syntaxParser, lazyOuterFunction) + isUnexpectedEOF_(false) { cx->perThreadData->frontendCollectionPool.addActiveCompilation(); + tempPoolMark = alloc.mark(); +} + +ParserBase::~ParserBase() +{ + alloc.release(tempPoolMark); + + /* + * The parser can allocate enormous amounts of memory for large functions. + * Eagerly free the memory now (which otherwise won't be freed until the + * next GC) to avoid unnecessary OOMs. + */ + alloc.freeAllIfHugeAndUnused(); + + context->perThreadData->frontendCollectionPool.removeActiveCompilation(); +} +template +Parser::Parser(ExclusiveContext* cx, LifoAlloc& alloc, + const ReadOnlyCompileOptions& options, + const char16_t* chars, size_t length, + bool foldConstants, + UsedNameTracker& usedNames, + Parser* syntaxParser, + LazyScript* lazyOuterFunction) + : ParserBase(cx, alloc, options, chars, length, foldConstants, usedNames, syntaxParser, + lazyOuterFunction), + AutoGCRooter(cx, PARSER), + handler(cx, alloc, tokenStream, syntaxParser, lazyOuterFunction) +{ // The Mozilla specific JSOPTION_EXTRA_WARNINGS option adds extra warnings // which are not generated if functions are parsed lazily. Note that the // standard "use strict" does not inhibit lazy parsing. if (options.extraWarningsOption) handler.disableSyntaxParser(); - - tempPoolMark = alloc.mark(); } template @@ -747,26 +763,13 @@ Parser::checkOptions() checkOptionsCalled = true; #endif - if (!tokenStream.checkOptions()) - return false; - - return true; + return tokenStream.checkOptions(); } template Parser::~Parser() { MOZ_ASSERT(checkOptionsCalled); - alloc.release(tempPoolMark); - - /* - * The parser can allocate enormous amounts of memory for large functions. - * Eagerly free the memory now (which otherwise won't be freed until the - * next GC) to avoid unnecessary OOMs. - */ - alloc.freeAllIfHugeAndUnused(); - - context->perThreadData->frontendCollectionPool.removeActiveCompilation(); } template @@ -897,9 +900,8 @@ Parser::parse() * Strict mode forbids introducing new definitions for 'eval', 'arguments', or * for any strict mode reserved keyword. */ -template bool -Parser::isValidStrictBinding(PropertyName* name) +ParserBase::isValidStrictBinding(PropertyName* name) { return name != context->names().eval && name != context->names().arguments && @@ -9602,9 +9604,8 @@ Parser::exprInParens(InHandling inHandling, YieldHandling yieldHan return expr(inHandling, yieldHandling, tripledotHandling, possibleError, PredictInvoked); } -template bool -Parser::warnOnceAboutExprClosure() +ParserBase::warnOnceAboutExprClosure() { #ifndef RELEASE_OR_BETA JSContext* cx = context->maybeJSContext(); @@ -9620,9 +9621,8 @@ Parser::warnOnceAboutExprClosure() return true; } -template bool -Parser::warnOnceAboutForEach() +ParserBase::warnOnceAboutForEach() { JSContext* cx = context->maybeJSContext(); if (!cx) diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index f6cff8a6c..e36a6e8b2 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -734,8 +734,138 @@ class UsedNameTracker } }; +class ParserBase : public StrictModeGetter +{ + private: + ParserBase* thisForCtor() { return this; } + + public: + ExclusiveContext* const context; + + LifoAlloc& alloc; + + TokenStream tokenStream; + LifoAlloc::Mark tempPoolMark; + + /* list of parsed objects for GC tracing */ + ObjectBox* traceListHead; + + /* innermost parse context (stack-allocated) */ + ParseContext* pc; + + // For tracking used names in this parsing session. + UsedNameTracker& usedNames; + + /* Compression token for aborting. */ + SourceCompressionTask* sct; + + ScriptSource* ss; + + /* Root atoms and objects allocated for the parsed tree. */ + AutoKeepAtoms keepAtoms; + + /* Perform constant-folding; must be true when interfacing with the emitter. */ + const bool foldConstants:1; + + protected: +#if DEBUG + /* Our fallible 'checkOptions' member function has been called. */ + bool checkOptionsCalled:1; +#endif + + /* + * Not all language constructs can be handled during syntax parsing. If it + * is not known whether the parse succeeds or fails, this bit is set and + * the parse will return false. + */ + bool abortedSyntaxParse:1; + + /* Unexpected end of input, i.e. TOK_EOF not at top-level. */ + bool isUnexpectedEOF_:1; + + public: + ParserBase(ExclusiveContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options, + const char16_t* chars, size_t length, bool foldConstants, + UsedNameTracker& usedNames, Parser* syntaxParser, + LazyScript* lazyOuterFunction); + ~ParserBase(); + + const char* getFilename() const { return tokenStream.getFilename(); } + JSVersion versionNumber() const { return tokenStream.versionNumber(); } + TokenPos pos() const { return tokenStream.currentToken().pos; } + + // Determine whether |yield| is a valid name in the current context, or + // whether it's prohibited due to strictness, JS version, or occurrence + // inside a star generator. + bool yieldExpressionsSupported() { + return (versionNumber() >= JSVERSION_1_7 || pc->isGenerator()) && !pc->isAsync(); + } + + virtual bool strictMode() { return pc->sc()->strict(); } + bool setLocalStrictMode(bool strict) { + MOZ_ASSERT(tokenStream.debugHasNoLookahead()); + return pc->sc()->setLocalStrictMode(strict); + } + + const ReadOnlyCompileOptions& options() const { + return tokenStream.options(); + } + + bool hadAbortedSyntaxParse() { + return abortedSyntaxParse; + } + void clearAbortedSyntaxParse() { + abortedSyntaxParse = false; + } + + bool isUnexpectedEOF() const { return isUnexpectedEOF_; } + + bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...); + + /* Report the given error at the current offset. */ + void error(unsigned errorNumber, ...); + + /* Report the given error at the given offset. */ + void errorAt(uint32_t offset, unsigned errorNumber, ...); + + /* + * Handle a strict mode error at the current offset. Report an error if in + * strict mode code, or warn if not, using the given error number and + * arguments. + */ + MOZ_MUST_USE bool strictModeError(unsigned errorNumber, ...); + + /* + * Handle a strict mode error at the given offset. Report an error if in + * strict mode code, or warn if not, using the given error number and + * arguments. + */ + MOZ_MUST_USE bool strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...); + + /* Report the given warning at the current offset. */ + MOZ_MUST_USE bool warning(unsigned errorNumber, ...); + + /* Report the given warning at the given offset. */ + MOZ_MUST_USE bool warningAt(uint32_t offset, unsigned errorNumber, ...); + + /* + * If extra warnings are enabled, report the given warning at the current + * offset. + */ + MOZ_MUST_USE bool extraWarning(unsigned errorNumber, ...); + + bool isValidStrictBinding(PropertyName* name); + + bool warnOnceAboutExprClosure(); + bool warnOnceAboutForEach(); + + protected: + enum InvokedPrediction { PredictUninvoked = false, PredictInvoked = true }; + enum ForInitLocation { InForInit, NotInForInit }; +}; + template -class Parser final : private JS::AutoGCRooter, public StrictModeGetter +class Parser final : public ParserBase, private JS::AutoGCRooter { private: using Node = typename ParseHandler::Node; @@ -852,50 +982,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter void transferErrorsTo(PossibleError* other); }; - public: - ExclusiveContext* const context; - - LifoAlloc& alloc; - - TokenStream tokenStream; - LifoAlloc::Mark tempPoolMark; - - /* list of parsed objects for GC tracing */ - ObjectBox* traceListHead; - - /* innermost parse context (stack-allocated) */ - ParseContext* pc; - - // For tracking used names in this parsing session. - UsedNameTracker& usedNames; - - /* Compression token for aborting. */ - SourceCompressionTask* sct; - - ScriptSource* ss; - - /* Root atoms and objects allocated for the parsed tree. */ - AutoKeepAtoms keepAtoms; - - /* Perform constant-folding; must be true when interfacing with the emitter. */ - const bool foldConstants:1; - - private: -#if DEBUG - /* Our fallible 'checkOptions' member function has been called. */ - bool checkOptionsCalled:1; -#endif - - /* - * Not all language constructs can be handled during syntax parsing. If it - * is not known whether the parse succeeds or fails, this bit is set and - * the parse will return false. - */ - bool abortedSyntaxParse:1; - - /* Unexpected end of input, i.e. TOK_EOF not at top-level. */ - bool isUnexpectedEOF_:1; - public: /* State specific to the kind of parse being performed. */ ParseHandler handler; @@ -904,40 +990,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter void freeTree(Node node) { handler.freeTree(node); } public: - bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...); - - /* Report the given error at the current offset. */ - void error(unsigned errorNumber, ...); - - /* Report the given error at the given offset. */ - void errorAt(uint32_t offset, unsigned errorNumber, ...); - - /* - * Handle a strict mode error at the current offset. Report an error if in - * strict mode code, or warn if not, using the given error number and - * arguments. - */ - MOZ_MUST_USE bool strictModeError(unsigned errorNumber, ...); - - /* - * Handle a strict mode error at the given offset. Report an error if in - * strict mode code, or warn if not, using the given error number and - * arguments. - */ - MOZ_MUST_USE bool strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...); - - /* Report the given warning at the current offset. */ - MOZ_MUST_USE bool warning(unsigned errorNumber, ...); - - /* Report the given warning at the given offset. */ - MOZ_MUST_USE bool warningAt(uint32_t offset, unsigned errorNumber, ...); - - /* - * If extra warnings are enabled, report the given warning at the current - * offset. - */ - MOZ_MUST_USE bool extraWarning(unsigned errorNumber, ...); - Parser(ExclusiveContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options, const char16_t* chars, size_t length, bool foldConstants, UsedNameTracker& usedNames, Parser* syntaxParser, LazyScript* lazyOuterFunction); @@ -967,9 +1019,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter friend void js::frontend::MarkParser(JSTracer* trc, JS::AutoGCRooter* parser); - const char* getFilename() const { return tokenStream.getFilename(); } - JSVersion versionNumber() const { return tokenStream.versionNumber(); } - /* * Parse a top-level JS script. */ @@ -995,15 +1044,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter void trace(JSTracer* trc); - bool hadAbortedSyntaxParse() { - return abortedSyntaxParse; - } - void clearAbortedSyntaxParse() { - abortedSyntaxParse = false; - } - - bool isUnexpectedEOF() const { return isUnexpectedEOF_; } - bool checkUnescapedName(); private: @@ -1072,34 +1112,12 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter Node pn, FunctionSyntaxKind kind, mozilla::Maybe parameterListEnd = mozilla::Nothing(), bool isStandaloneFunction = false); - - - // Determine whether |yield| is a valid name in the current context, or - // whether it's prohibited due to strictness, JS version, or occurrence - // inside a star generator. - bool yieldExpressionsSupported() { - return (versionNumber() >= JSVERSION_1_7 || pc->isGenerator()) && !pc->isAsync(); - } // Match the current token against the BindingIdentifier production with // the given Yield parameter. If there is no match, report a syntax // error. PropertyName* bindingIdentifier(YieldHandling yieldHandling); - virtual bool strictMode() { return pc->sc()->strict(); } - bool setLocalStrictMode(bool strict) { - MOZ_ASSERT(tokenStream.debugHasNoLookahead()); - return pc->sc()->setLocalStrictMode(strict); - } - - const ReadOnlyCompileOptions& options() const { - return tokenStream.options(); - } - - private: - enum InvokedPrediction { PredictUninvoked = false, PredictInvoked = true }; - enum ForInitLocation { InForInit, NotInForInit }; - private: /* * JS parsers, from lowest to highest precedence. @@ -1375,8 +1393,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool hasValidSimpleStrictParameterNames(); - bool isValidStrictBinding(PropertyName* name); - void reportRedeclaration(HandlePropertyName name, DeclarationKind kind, TokenPos pos); bool notePositionalFormalParameter(Node fn, HandlePropertyName name, bool disallowDuplicateParams, bool* duplicatedParam); @@ -1432,12 +1448,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter JSAtom* prefixAccessorName(PropertyType propType, HandleAtom propAtom); - TokenPos pos() const { return tokenStream.currentToken().pos; } - bool asmJS(Node list); - - bool warnOnceAboutExprClosure(); - bool warnOnceAboutForEach(); }; } /* namespace frontend */ -- cgit v1.2.3 From f6193fd0f4689643f47c6ac9aa5aac3b8cc10213 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 15:37:06 -0400 Subject: 1326454 - Introduce TokenStream::error that reports an error at the current offset. --- js/src/frontend/TokenStream.cpp | 37 +++++++++++++++++++++++++++---------- js/src/frontend/TokenStream.h | 3 +++ 2 files changed, 30 insertions(+), 10 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index 8438ff7c5..9becaf55e 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -554,8 +554,10 @@ TokenStream::advance(size_t position) MOZ_MAKE_MEM_UNDEFINED(&cur->type, sizeof(cur->type)); lookahead = 0; - if (flags.hitOOM) - return reportError(JSMSG_OUT_OF_MEMORY); + if (flags.hitOOM) { + error(JSMSG_OUT_OF_MEMORY); + return false; + } return true; } @@ -806,6 +808,19 @@ TokenStream::reportAsmJSError(uint32_t offset, unsigned errorNumber, ...) va_end(args); } +void +TokenStream::error(unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); +#ifdef DEBUG + bool result = +#endif + reportCompileErrorNumberVA(currentToken().pos.begin, JSREPORT_ERROR, errorNumber, args); + MOZ_ASSERT(!result, "reporting an error returned true?"); + va_end(args); +} + // We have encountered a '\': check for a Unicode escape sequence after it. // Return the length of the escape sequence and the character code point (by // value) if we found a Unicode escape sequence. Otherwise, return 0. In both @@ -1119,8 +1134,10 @@ TokenStream::checkForKeyword(const KeywordInfo* kw, TokenKind* ttp) return true; } - if (kw->tokentype == TOK_RESERVED) - return reportError(JSMSG_RESERVED_ID, kw->chars); + if (kw->tokentype == TOK_RESERVED) { + error(JSMSG_RESERVED_ID, kw->chars); + return false; + } if (kw->tokentype == TOK_STRICT_RESERVED) return reportStrictModeError(JSMSG_RESERVED_ID, kw->chars); @@ -1897,7 +1914,7 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp) while ((c = getCharIgnoreEOL()) != untilChar) { if (c == EOF) { ungetCharIgnoreEOL(c); - reportError(JSMSG_UNTERMINATED_STRING); + error(JSMSG_UNTERMINATED_STRING); return false; } @@ -1920,7 +1937,7 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp) if (peekChar() == '{') { uint32_t code; if (!getBracedUnicode(&code)) { - reportError(JSMSG_MALFORMED_ESCAPE, "Unicode"); + error(JSMSG_MALFORMED_ESCAPE, "Unicode"); return false; } @@ -1945,7 +1962,7 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp) c = (c << 4) + JS7_UNHEX(cp[3]); skipChars(4); } else { - reportError(JSMSG_MALFORMED_ESCAPE, "Unicode"); + error(JSMSG_MALFORMED_ESCAPE, "Unicode"); return false; } break; @@ -1958,7 +1975,7 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp) c = (JS7_UNHEX(cp[0]) << 4) + JS7_UNHEX(cp[1]); skipChars(2); } else { - reportError(JSMSG_MALFORMED_ESCAPE, "hexadecimal"); + error(JSMSG_MALFORMED_ESCAPE, "hexadecimal"); return false; } break; @@ -1974,7 +1991,7 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp) // Strict mode code allows only \0, then a non-digit. if (val != 0 || JS7_ISDEC(c)) { if (parsingTemplate) { - reportError(JSMSG_DEPRECATED_OCTAL); + error(JSMSG_DEPRECATED_OCTAL); return false; } if (!reportStrictModeError(JSMSG_DEPRECATED_OCTAL)) @@ -2003,7 +2020,7 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp) } else if (TokenBuf::isRawEOLChar(c)) { if (!parsingTemplate) { ungetCharIgnoreEOL(c); - reportError(JSMSG_UNTERMINATED_STRING); + error(JSMSG_UNTERMINATED_STRING); return false; } if (c == '\r') { diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index 6ba9fba5a..f08d317ba 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -366,6 +366,9 @@ class MOZ_STACK_CLASS TokenStream bool reportErrorNoOffset(unsigned errorNumber, ...); bool reportWarning(unsigned errorNumber, ...); + // Report the given error at the current offset. + void error(unsigned errorNumber, ...); + static const uint32_t NoOffset = UINT32_MAX; // General-purpose error reporters. You should avoid calling these -- cgit v1.2.3 From 068916b59a847bede7c6c788e803442c1833fe67 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 15:40:56 -0400 Subject: 1326454 - Introduce TokenStream::warning that warns at the current offset. --- js/src/frontend/TokenStream.cpp | 16 +++++++++------- js/src/frontend/TokenStream.h | 8 +++++--- 2 files changed, 14 insertions(+), 10 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index 9becaf55e..e8d622d38 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -777,7 +777,7 @@ TokenStream::reportErrorNoOffset(unsigned errorNumber, ...) } bool -TokenStream::reportWarning(unsigned errorNumber, ...) +TokenStream::warning(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); @@ -958,9 +958,10 @@ TokenStream::getDirective(bool isMultiline, bool shouldWarnDeprecated, int32_t c; if (peekChars(directiveLength, peeked) && CharsMatch(peeked, directive)) { - if (shouldWarnDeprecated && - !reportWarning(JSMSG_DEPRECATED_PRAGMA, errorMsgPragma)) - return false; + if (shouldWarnDeprecated) { + if (!warning(JSMSG_DEPRECATED_PRAGMA, errorMsgPragma)) + return false; + } skipChars(directiveLength); tokenbuf.clear(); @@ -1555,10 +1556,11 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier) // grammar. We might not always be so permissive, so we warn // about it. if (c >= '8') { - if (!reportWarning(JSMSG_BAD_OCTAL, c == '8' ? "08" : "09")) { + if (!warning(JSMSG_BAD_OCTAL, c == '8' ? "08" : "09")) goto error; - } - goto decimal; // use the decimal scanner for the rest of the number + + // Use the decimal scanner for the rest of the number. + goto decimal; } c = getCharIgnoreEOL(); } diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index f08d317ba..18e9cb3ca 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -364,16 +364,18 @@ class MOZ_STACK_CLASS TokenStream // TokenStream-specific error reporters. bool reportError(unsigned errorNumber, ...); bool reportErrorNoOffset(unsigned errorNumber, ...); - bool reportWarning(unsigned errorNumber, ...); // Report the given error at the current offset. void error(unsigned errorNumber, ...); + // Warn at the current offset. + MOZ_MUST_USE bool warning(unsigned errorNumber, ...); + static const uint32_t NoOffset = UINT32_MAX; // General-purpose error reporters. You should avoid calling these - // directly, and instead use the more succinct alternatives (e.g. - // reportError()) in TokenStream, Parser, and BytecodeEmitter. + // directly, and instead use the more succinct alternatives (error(), + // warning(), &c.) in TokenStream, Parser, and BytecodeEmitter. bool reportCompileErrorNumberVA(uint32_t offset, unsigned flags, unsigned errorNumber, va_list args); bool reportStrictModeErrorNumberVA(uint32_t offset, bool strictMode, unsigned errorNumber, -- cgit v1.2.3 From b41de8683d8d28d08a6e2b79511610a268342a0e Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 15:48:25 -0400 Subject: 1326454 - Rename TokenStream::getBracedUnicode to TokenStream::matchBracedUnicode and make its signature fallible. --- js/src/frontend/TokenStream.cpp | 57 +++++++++++++++++++++++++++++----------- js/src/frontend/TokenStream.h | 5 +++- js/src/irregexp/RegExpParser.cpp | 6 ++--- js/src/irregexp/RegExpParser.h | 2 +- js/src/js.msg | 2 +- 5 files changed, 51 insertions(+), 21 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index e8d622d38..abb7228eb 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -821,6 +821,19 @@ TokenStream::error(unsigned errorNumber, ...) va_end(args); } +void +TokenStream::errorAt(uint32_t offset, unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); +#ifdef DEBUG + bool result = +#endif + reportCompileErrorNumberVA(offset, JSREPORT_ERROR, errorNumber, args); + MOZ_ASSERT(!result, "reporting an error returned true?"); + va_end(args); +} + // We have encountered a '\': check for a Unicode escape sequence after it. // Return the length of the escape sequence and the character code point (by // value) if we found a Unicode escape sequence. Otherwise, return 0. In both @@ -1869,32 +1882,47 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier) } bool -TokenStream::getBracedUnicode(uint32_t* cp) +TokenStream::matchBracedUnicode(bool* matched, uint32_t* cp) { + if (peekChar() != '{') { + *matched = false; + return true; + } + consumeKnownChar('{'); + uint32_t start = userbuf.offset(); + bool first = true; - int32_t c; uint32_t code = 0; - while (true) { - c = getCharIgnoreEOL(); - if (c == EOF) + do { + int32_t c = getCharIgnoreEOL(); + if (c == EOF) { + error(JSMSG_MALFORMED_ESCAPE, "Unicode"); return false; + } if (c == '}') { - if (first) + if (first) { + error(JSMSG_MALFORMED_ESCAPE, "Unicode"); return false; + } break; } - if (!JS7_ISHEX(c)) + if (!JS7_ISHEX(c)) { + error(JSMSG_MALFORMED_ESCAPE, "Unicode"); return false; + } code = (code << 4) | JS7_UNHEX(c); - if (code > unicode::NonBMPMax) + if (code > unicode::NonBMPMax) { + errorAt(start, JSMSG_UNICODE_OVERFLOW, "escape sequence"); return false; + } first = false; - } + } while (true); + *matched = true; *cp = code; return true; } @@ -1936,12 +1964,11 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp) // Unicode character specification. case 'u': { - if (peekChar() == '{') { - uint32_t code; - if (!getBracedUnicode(&code)) { - error(JSMSG_MALFORMED_ESCAPE, "Unicode"); - return false; - } + bool matched; + uint32_t code; + if (!matchBracedUnicode(&matched, &code)) + return false; + if (matched) { MOZ_ASSERT(code <= unicode::NonBMPMax); if (code < unicode::NonBMPMin) { diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index 18e9cb3ca..19385b499 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -368,6 +368,9 @@ class MOZ_STACK_CLASS TokenStream // Report the given error at the current offset. void error(unsigned errorNumber, ...); + // Report the given error at the given offset. + void errorAt(uint32_t offset, unsigned errorNumber, ...); + // Warn at the current offset. MOZ_MUST_USE bool warning(unsigned errorNumber, ...); @@ -952,7 +955,7 @@ class MOZ_STACK_CLASS TokenStream MOZ_MUST_USE bool getTokenInternal(TokenKind* ttp, Modifier modifier); - MOZ_MUST_USE bool getBracedUnicode(uint32_t* code); + MOZ_MUST_USE bool matchBracedUnicode(bool* matched, uint32_t* code); MOZ_MUST_USE bool getStringOrTemplateToken(int untilChar, Token** tp); int32_t getChar(); diff --git a/js/src/irregexp/RegExpParser.cpp b/js/src/irregexp/RegExpParser.cpp index ccc6ae3eb..8bd88047a 100644 --- a/js/src/irregexp/RegExpParser.cpp +++ b/js/src/irregexp/RegExpParser.cpp @@ -243,10 +243,10 @@ RegExpParser::RegExpParser(frontend::TokenStream& ts, LifoAlloc* alloc, template RegExpTree* -RegExpParser::ReportError(unsigned errorNumber) +RegExpParser::ReportError(unsigned errorNumber, const char* param /* = nullptr */) { gc::AutoSuppressGC suppressGC(ts.context()); - ts.reportError(errorNumber); + ts.reportError(errorNumber, param); return nullptr; } @@ -350,7 +350,7 @@ RegExpParser::ParseBracedHexEscape(widechar* value) } code = (code << 4) | d; if (code > unicode::NonBMPMax) { - ReportError(JSMSG_UNICODE_OVERFLOW); + ReportError(JSMSG_UNICODE_OVERFLOW, "regular expression"); return false; } Advance(); diff --git a/js/src/irregexp/RegExpParser.h b/js/src/irregexp/RegExpParser.h index b5228a86f..0a7e61858 100644 --- a/js/src/irregexp/RegExpParser.h +++ b/js/src/irregexp/RegExpParser.h @@ -211,7 +211,7 @@ class RegExpParser bool ParseBackReferenceIndex(int* index_out); bool ParseClassAtom(char16_t* char_class, widechar *value); - RegExpTree* ReportError(unsigned errorNumber); + RegExpTree* ReportError(unsigned errorNumber, const char* param = nullptr); void Advance(); void Advance(int dist) { next_pos_ += dist - 1; diff --git a/js/src/js.msg b/js/src/js.msg index 50817f50f..495e3bfad 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -502,7 +502,7 @@ MSG_DEF(JSMSG_RANGE_WITH_CLASS_ESCAPE, 0, JSEXN_SYNTAXERR, "character class esca MSG_DEF(JSMSG_RAW_BRACE_IN_REGEP, 0, JSEXN_SYNTAXERR, "raw brace is not allowed in regular expression with unicode flag") MSG_DEF(JSMSG_RAW_BRACKET_IN_REGEP, 0, JSEXN_SYNTAXERR, "raw bracket is not allowed in regular expression with unicode flag") MSG_DEF(JSMSG_TOO_MANY_PARENS, 0, JSEXN_INTERNALERR, "too many parentheses in regular expression") -MSG_DEF(JSMSG_UNICODE_OVERFLOW, 0, JSEXN_SYNTAXERR, "unicode codepoint should not be greater than 0x10FFFF in regular expression") +MSG_DEF(JSMSG_UNICODE_OVERFLOW, 1, JSEXN_SYNTAXERR, "Unicode codepoint must not be greater than 0x10FFFF in {0}") MSG_DEF(JSMSG_UNMATCHED_RIGHT_PAREN, 0, JSEXN_SYNTAXERR, "unmatched ) in regular expression") MSG_DEF(JSMSG_UNTERM_CLASS, 0, JSEXN_SYNTAXERR, "unterminated character class") -- cgit v1.2.3 From d400e9491c0be93f34f368227d6a3e4d056d9061 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 15:52:17 -0400 Subject: 1326454 - Make TokenStream::peekChar's signature fallible. --- js/src/frontend/TokenStream.cpp | 55 ++++++++++++++++++++++++++++++----------- js/src/frontend/TokenStream.h | 8 +++--- 2 files changed, 45 insertions(+), 18 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index abb7228eb..6c5ea8fe9 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -968,7 +968,6 @@ TokenStream::getDirective(bool isMultiline, bool shouldWarnDeprecated, { MOZ_ASSERT(directiveLength <= 18); char16_t peeked[18]; - int32_t c; if (peekChars(directiveLength, peeked) && CharsMatch(peeked, directive)) { if (shouldWarnDeprecated) { @@ -979,18 +978,33 @@ TokenStream::getDirective(bool isMultiline, bool shouldWarnDeprecated, skipChars(directiveLength); tokenbuf.clear(); - while ((c = peekChar()) && c != EOF && !unicode::IsSpaceOrBOM2(c)) { - getChar(); + do { + int32_t c; + if (!peekChar(&c)) + return false; + + if (c == EOF || unicode::IsSpaceOrBOM2(c)) + break; + + consumeKnownChar(c); + // Debugging directives can occur in both single- and multi-line // comments. If we're currently inside a multi-line comment, we also // need to recognize multi-line comment terminators. - if (isMultiline && c == '*' && peekChar() == '/') { - ungetChar('*'); - break; + if (isMultiline && c == '*') { + int32_t c2; + if (!peekChar(&c2)) + return false; + + if (c2 == '/') { + ungetChar('*'); + break; + } } + if (!tokenbuf.append(c)) return false; - } + } while (true); if (tokenbuf.empty()) { // The directive's URL was missing, but this is not quite an @@ -1722,7 +1736,8 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier) case '/': // Look for a single-line comment. if (matchChar('/')) { - c = peekChar(); + if (!peekChar(&c)) + goto error; if (c == '@' || c == '#') { bool shouldWarn = getChar() == '@'; if (!getDirectives(false, shouldWarn)) @@ -1789,7 +1804,8 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier) RegExpFlag reflags = NoFlags; unsigned length = tokenbuf.length() + 1; while (true) { - c = peekChar(); + if (!peekChar(&c)) + goto error; if (c == 'g' && !(reflags & GlobalFlag)) reflags = RegExpFlag(reflags | GlobalFlag); else if (c == 'i' && !(reflags & IgnoreCaseFlag)) @@ -1806,7 +1822,8 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier) length++; } - c = peekChar(); + if (!peekChar(&c)) + goto error; if (JS7_ISLET(c)) { char buf[2] = { '\0', '\0' }; tp->pos.begin += length + 1; @@ -1829,8 +1846,13 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier) case '-': if (matchChar('-')) { - if (peekChar() == '>' && !flags.isDirtyLine) + int32_t c2; + if (!peekChar(&c2)) + goto error; + + if (c2 == '>' && !flags.isDirtyLine) goto skipline; + tp->type = TOK_DEC; } else { tp->type = matchChar('=') ? TOK_SUBASSIGN : TOK_SUB; @@ -1884,7 +1906,10 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier) bool TokenStream::matchBracedUnicode(bool* matched, uint32_t* cp) { - if (peekChar() != '{') { + int32_t c; + if (!peekChar(&c)) + return false; + if (c != '{') { *matched = false; return true; } @@ -2015,7 +2040,8 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp) if (JS7_ISOCT(c)) { int32_t val = JS7_UNOCT(c); - c = peekChar(); + if (!peekChar(&c)) + return false; // Strict mode code allows only \0, then a non-digit. if (val != 0 || JS7_ISDEC(c)) { @@ -2031,7 +2057,8 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp) if (JS7_ISOCT(c)) { val = 8 * val + JS7_UNOCT(c); getChar(); - c = peekChar(); + if (!peekChar(&c)) + return false; if (JS7_ISOCT(c)) { int32_t save = val; val = 8 * val + JS7_UNOCT(c); diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index 19385b499..e0e4b959e 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -990,10 +990,10 @@ class MOZ_STACK_CLASS TokenStream MOZ_ASSERT(c == expect); } - int32_t peekChar() { - int32_t c = getChar(); - ungetChar(c); - return c; + MOZ_MUST_USE bool peekChar(int32_t* c) { + *c = getChar(); + ungetChar(*c); + return true; } void skipChars(int n) { -- cgit v1.2.3 From 0ed4cf321f276d88f80d13daf2644f9bc51b0957 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 15:54:42 -0400 Subject: 1326454 - Make TokenStream::skipChars{,IgnoreEOL} accept an unsigned integral number of chars to skip. --- js/src/frontend/TokenStream.cpp | 14 +++++++++++--- js/src/frontend/TokenStream.h | 10 +++++----- 2 files changed, 16 insertions(+), 8 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index 6c5ea8fe9..619285090 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -8,6 +8,7 @@ #include "frontend/TokenStream.h" +#include "mozilla/ArrayUtils.h" #include "mozilla/IntegerTypeTraits.h" #include "mozilla/PodOperations.h" @@ -33,6 +34,7 @@ using namespace js; using namespace js::frontend; +using mozilla::ArrayLength; using mozilla::Maybe; using mozilla::PodAssign; using mozilla::PodCopy; @@ -962,7 +964,7 @@ TokenStream::getDirectives(bool isMultiline, bool shouldWarnDeprecated) bool TokenStream::getDirective(bool isMultiline, bool shouldWarnDeprecated, - const char* directive, int directiveLength, + const char* directive, uint8_t directiveLength, const char* errorMsgPragma, UniqueTwoByteChars* destination) { @@ -1036,7 +1038,10 @@ TokenStream::getDisplayURL(bool isMultiline, bool shouldWarnDeprecated) // developer would like to refer to the source as from the source's actual // URL. - return getDirective(isMultiline, shouldWarnDeprecated, " sourceURL=", 11, + static const char sourceURLDirective[] = " sourceURL="; + constexpr uint8_t sourceURLDirectiveLength = ArrayLength(sourceURLDirective) - 1; + return getDirective(isMultiline, shouldWarnDeprecated, + sourceURLDirective, sourceURLDirectiveLength, "sourceURL", &displayURL_); } @@ -1046,7 +1051,10 @@ TokenStream::getSourceMappingURL(bool isMultiline, bool shouldWarnDeprecated) // Match comments of the form "//# sourceMappingURL=" or // "/\* //# sourceMappingURL= *\/" - return getDirective(isMultiline, shouldWarnDeprecated, " sourceMappingURL=", 18, + static const char sourceMappingURLDirective[] = " sourceMappingURL="; + constexpr uint8_t sourceMappingURLDirectiveLength = ArrayLength(sourceMappingURLDirective) - 1; + return getDirective(isMultiline, shouldWarnDeprecated, + sourceMappingURLDirective, sourceMappingURLDirectiveLength, "sourceMappingURL", &sourceMapURL_); } diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index e0e4b959e..a058759c6 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -972,7 +972,7 @@ class MOZ_STACK_CLASS TokenStream MOZ_MUST_USE bool getDirectives(bool isMultiline, bool shouldWarnDeprecated); MOZ_MUST_USE bool getDirective(bool isMultiline, bool shouldWarnDeprecated, - const char* directive, int directiveLength, + const char* directive, uint8_t directiveLength, const char* errorMsgPragma, UniquePtr* destination); MOZ_MUST_USE bool getDisplayURL(bool isMultiline, bool shouldWarnDeprecated); @@ -996,13 +996,13 @@ class MOZ_STACK_CLASS TokenStream return true; } - void skipChars(int n) { - while (--n >= 0) + void skipChars(uint8_t n) { + while (n-- > 0) getChar(); } - void skipCharsIgnoreEOL(int n) { - while (--n >= 0) + void skipCharsIgnoreEOL(uint8_t n) { + while (n-- > 0) getCharIgnoreEOL(); } -- cgit v1.2.3 From aa2decd154dbbd17e0eac9c570841eb445c63a3f Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 15:55:51 -0400 Subject: 1326454 - Add assertions to TokenStream::skipChars{,IgnoreEOL} verifying EOF isn't yet hit and that newlines aren't skipped, if appropriate. --- js/src/frontend/TokenStream.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index a058759c6..4efc31446 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -997,13 +997,18 @@ class MOZ_STACK_CLASS TokenStream } void skipChars(uint8_t n) { - while (n-- > 0) - getChar(); + while (n-- > 0) { + MOZ_ASSERT(userbuf.hasRawChars()); + mozilla::DebugOnly c = getCharIgnoreEOL(); + MOZ_ASSERT(c != '\n'); + } } void skipCharsIgnoreEOL(uint8_t n) { - while (n-- > 0) + while (n-- > 0) { + MOZ_ASSERT(userbuf.hasRawChars()); getCharIgnoreEOL(); + } } void updateLineInfoForEOL(); -- cgit v1.2.3 From c6fe42095040b0be2ee85bc750bd905bfe396fbd Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 15:57:27 -0400 Subject: 1326454 - Don't report an error when SourceCoords::add fails, because it fails only when an underlying Vector::append fails, and that vector handles OOM reporting itself. --- js/src/frontend/TokenStream.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index 619285090..186b7a8ab 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -225,8 +225,13 @@ TokenStream::SourceCoords::add(uint32_t lineNum, uint32_t lineStartOffset) // only if lineStartOffsets_.append succeeds, to keep sentinel. // Otherwise return false to tell TokenStream about OOM. uint32_t maxPtr = MAX_PTR; - if (!lineStartOffsets_.append(maxPtr)) + if (!lineStartOffsets_.append(maxPtr)) { + static_assert(mozilla::IsSame::value, + "this function's caller depends on it reporting an " + "error on failure, as TempAllocPolicy ensures"); return false; + } lineStartOffsets_[lineIndex] = lineStartOffset; } else { @@ -557,7 +562,6 @@ TokenStream::advance(size_t position) lookahead = 0; if (flags.hitOOM) { - error(JSMSG_OUT_OF_MEMORY); return false; } @@ -1876,8 +1880,9 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier) MOZ_CRASH("should have jumped to |out| or |error|"); out: - if (flags.hitOOM) - return reportError(JSMSG_OUT_OF_MEMORY); + if (flags.hitOOM) { + return false; + } flags.isDirtyLine = true; tp->pos.end = userbuf.offset(); @@ -1893,8 +1898,9 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier) return true; error: - if (flags.hitOOM) - return reportError(JSMSG_OUT_OF_MEMORY); + if (flags.hitOOM) { + return false; + } flags.isDirtyLine = true; tp->pos.end = userbuf.offset(); -- cgit v1.2.3 From af32c8553e54455ef8cbfe70a13f79f84c2163a4 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 16:16:14 -0400 Subject: 1325606 - Return wrapped async function from caller property. --- js/src/jsfun.cpp | 4 ++++ .../tests/ecma_2017/AsyncFunctions/inner-caller.js | 26 ++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 js/src/tests/ecma_2017/AsyncFunctions/inner-caller.js (limited to 'js/src') diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index ef5aea768..06d5cced7 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -284,6 +284,8 @@ CallerGetterImpl(JSContext* cx, const CallArgs& args) } RootedObject caller(cx, iter.callee(cx)); + if (caller->is() && caller->as().isAsync()) + caller = GetWrappedAsyncFunction(&caller->as()); if (!cx->compartment()->wrap(cx, &caller)) return false; @@ -304,6 +306,8 @@ CallerGetterImpl(JSContext* cx, const CallArgs& args) } JSFunction* callerFun = &callerObj->as(); + if (IsWrappedAsyncFunction(callerFun)) + callerFun = GetUnwrappedAsyncFunction(callerFun); MOZ_ASSERT(!callerFun->isBuiltin(), "non-builtin iterator returned a builtin?"); if (callerFun->strict()) { diff --git a/js/src/tests/ecma_2017/AsyncFunctions/inner-caller.js b/js/src/tests/ecma_2017/AsyncFunctions/inner-caller.js new file mode 100644 index 000000000..523eb79ea --- /dev/null +++ b/js/src/tests/ecma_2017/AsyncFunctions/inner-caller.js @@ -0,0 +1,26 @@ +var BUGNUMBER = 1185106; +var summary = "caller property of function inside async function should return wrapped async function"; + +print(BUGNUMBER + ": " + summary); + +(async function f() { + var inner = (function g() { + return g.caller; + })(); + assertEq(inner, f); +})(); + +(async function f() { + "use strict"; + try { + (function g() { + return g.caller; + })(); + assertEq(true, false); + } catch (e) { + assertEq(e instanceof TypeError, true); + } +})(); + +if (typeof reportCompare === "function") + reportCompare(true, true); -- cgit v1.2.3 From 52e22e231b065cc7d5975d5f6f8a9231c4f18f6e Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 29 Jun 2019 22:19:56 -0400 Subject: 1323324 - Part 1: Make Promise::unforgeable{Resolve,Reject} spec-compliant. --- js/src/builtin/Promise.cpp | 100 +++++++++++++++++++-------------------------- js/src/jsapi.cpp | 4 +- 2 files changed, 44 insertions(+), 60 deletions(-) (limited to 'js/src') diff --git a/js/src/builtin/Promise.cpp b/js/src/builtin/Promise.cpp index c781a336d..9941c6f57 100644 --- a/js/src/builtin/Promise.cpp +++ b/js/src/builtin/Promise.cpp @@ -1947,26 +1947,23 @@ PerformPromiseRace(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C, } // ES2016, Sub-steps of 25.4.4.4 and 25.4.4.5. -static MOZ_MUST_USE bool -CommonStaticResolveRejectImpl(JSContext* cx, unsigned argc, Value* vp, ResolutionMode mode) +static MOZ_MUST_USE JSObject* +CommonStaticResolveRejectImpl(JSContext* cx, HandleValue thisVal, HandleValue argVal, + ResolutionMode mode) { - CallArgs args = CallArgsFromVp(argc, vp); - RootedValue x(cx, args.get(0)); - // Steps 1-2. - if (!args.thisv().isObject()) { + if (!thisVal.isObject()) { const char* msg = mode == ResolveMode ? "Receiver of Promise.resolve call" : "Receiver of Promise.reject call"; JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, msg); - return false; + return nullptr; } - RootedValue cVal(cx, args.thisv()); - RootedObject C(cx, &cVal.toObject()); + RootedObject C(cx, &thisVal.toObject()); // Step 3 of Resolve. - if (mode == ResolveMode && x.isObject()) { - RootedObject xObj(cx, &x.toObject()); + if (mode == ResolveMode && argVal.isObject()) { + RootedObject xObj(cx, &argVal.toObject()); bool isPromise = false; if (xObj->is()) { isPromise = true; @@ -1985,11 +1982,9 @@ CommonStaticResolveRejectImpl(JSContext* cx, unsigned argc, Value* vp, Resolutio if (isPromise) { RootedValue ctorVal(cx); if (!GetProperty(cx, xObj, xObj, cx->names().constructor, &ctorVal)) - return false; - if (ctorVal == cVal) { - args.rval().set(x); - return true; - } + return nullptr; + if (ctorVal == thisVal) + return xObj; } } @@ -1998,15 +1993,17 @@ CommonStaticResolveRejectImpl(JSContext* cx, unsigned argc, Value* vp, Resolutio RootedObject resolveFun(cx); RootedObject rejectFun(cx); if (!NewPromiseCapability(cx, C, &promise, &resolveFun, &rejectFun, true)) - return false; + return nullptr; // Step 5 of Resolve, 4 of Reject. - if (!RunResolutionFunction(cx, mode == ResolveMode ? resolveFun : rejectFun, x, mode, promise)) - return false; + if (!RunResolutionFunction(cx, mode == ResolveMode ? resolveFun : rejectFun, argVal, mode, + promise)) + { + return nullptr; + } // Step 6 of Resolve, 4 of Reject. - args.rval().setObject(*promise); - return true; + return promise; } /** @@ -2015,7 +2012,14 @@ CommonStaticResolveRejectImpl(JSContext* cx, unsigned argc, Value* vp, Resolutio bool js::Promise_reject(JSContext* cx, unsigned argc, Value* vp) { - return CommonStaticResolveRejectImpl(cx, argc, vp, RejectMode); + CallArgs args = CallArgsFromVp(argc, vp); + RootedValue thisVal(cx, args.thisv()); + RootedValue argVal(cx, args.get(0)); + JSObject* result = CommonStaticResolveRejectImpl(cx, thisVal, argVal, RejectMode); + if (!result) + return false; + args.rval().setObject(*result); + return true; } /** @@ -2024,19 +2028,11 @@ js::Promise_reject(JSContext* cx, unsigned argc, Value* vp) /* static */ JSObject* PromiseObject::unforgeableReject(JSContext* cx, HandleValue value) { - // Steps 1-2 (omitted). - - // Roughly step 3. - Rooted promise(cx, CreatePromiseObjectInternal(cx)); - if (!promise) - return nullptr; - - // Roughly step 4. - if (!ResolvePromise(cx, promise, value, JS::PromiseState::Rejected)) + RootedObject promiseCtor(cx, JS::GetPromiseConstructor(cx)); + if (!promiseCtor) return nullptr; - - // Step 5. - return promise; + RootedValue cVal(cx, ObjectValue(*promiseCtor)); + return CommonStaticResolveRejectImpl(cx, cVal, value, RejectMode); } /** @@ -2045,7 +2041,14 @@ PromiseObject::unforgeableReject(JSContext* cx, HandleValue value) bool js::Promise_static_resolve(JSContext* cx, unsigned argc, Value* vp) { - return CommonStaticResolveRejectImpl(cx, argc, vp, ResolveMode); + CallArgs args = CallArgsFromVp(argc, vp); + RootedValue thisVal(cx, args.thisv()); + RootedValue argVal(cx, args.get(0)); + JSObject* result = CommonStaticResolveRejectImpl(cx, thisVal, argVal, ResolveMode); + if (!result) + return false; + args.rval().setObject(*result); + return true; } /** @@ -2054,30 +2057,11 @@ js::Promise_static_resolve(JSContext* cx, unsigned argc, Value* vp) /* static */ JSObject* PromiseObject::unforgeableResolve(JSContext* cx, HandleValue value) { - // Steps 1-2 (omitted). - - // Step 3. - if (value.isObject()) { - JSObject* obj = &value.toObject(); - if (IsWrapper(obj)) - obj = CheckedUnwrap(obj); - // Instead of getting the `constructor` property, do an unforgeable - // check. - if (obj && obj->is()) - return obj; - } - - // Step 4. - Rooted promise(cx, CreatePromiseObjectInternal(cx)); - if (!promise) + RootedObject promiseCtor(cx, JS::GetPromiseConstructor(cx)); + if (!promiseCtor) return nullptr; - - // Steps 5. - if (!ResolvePromiseInternal(cx, promise, value)) - return nullptr; - - // Step 6. - return promise; + RootedValue cVal(cx, ObjectValue(*promiseCtor)); + return CommonStaticResolveRejectImpl(cx, cVal, value, ResolveMode); } // ES2016, 25.4.4.6, implemented in Promise.js. diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 9ee29ffe4..ac7b78581 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -4884,7 +4884,7 @@ JS::CallOriginalPromiseResolve(JSContext* cx, JS::HandleValue resolutionValue) assertSameCompartment(cx, resolutionValue); RootedObject promise(cx, PromiseObject::unforgeableResolve(cx, resolutionValue)); - MOZ_ASSERT_IF(promise, promise->is()); + MOZ_ASSERT_IF(promise, CheckedUnwrap(promise)->is()); return promise; } @@ -4896,7 +4896,7 @@ JS::CallOriginalPromiseReject(JSContext* cx, JS::HandleValue rejectionValue) assertSameCompartment(cx, rejectionValue); RootedObject promise(cx, PromiseObject::unforgeableReject(cx, rejectionValue)); - MOZ_ASSERT_IF(promise, promise->is()); + MOZ_ASSERT_IF(promise, CheckedUnwrap(promise)->is()); return promise; } -- cgit v1.2.3 From adc81d634d12d58a64e0d2a1e95998b766cf6e96 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 16:37:10 -0400 Subject: 1317374 - Don't do Annex B lexical function behavior when redeclaring a parameter name. --- js/src/frontend/Parser.cpp | 6 ++++++ .../tests/basic/testFunctionStatementAliasLocals.js | 4 +++- .../block-scoped-functions-annex-b-parameter.js | 16 ++++++++++++++++ js/src/tests/js1_8/regress/regress-467495-05.js | 2 +- js/src/tests/js1_8/regress/regress-467495-06.js | 2 +- 5 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b-parameter.js (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 79b5d70f4..66ada79f2 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -1183,6 +1183,12 @@ Parser::tryDeclareVar(HandlePropertyName name, DeclarationKind kin *redeclaredKind = Some(declaredKind); return true; } + } else if (kind == DeclarationKind::VarForAnnexBLexicalFunction) { + MOZ_ASSERT(DeclarationKindIsParameter(declaredKind)); + + // Annex B.3.3.1 disallows redeclaring parameter names. + *redeclaredKind = Some(declaredKind); + return true; } } else { if (!scope->addDeclaredName(pc, p, name, kind)) diff --git a/js/src/jit-test/tests/basic/testFunctionStatementAliasLocals.js b/js/src/jit-test/tests/basic/testFunctionStatementAliasLocals.js index 7be49b7f3..be7f528b9 100644 --- a/js/src/jit-test/tests/basic/testFunctionStatementAliasLocals.js +++ b/js/src/jit-test/tests/basic/testFunctionStatementAliasLocals.js @@ -8,9 +8,11 @@ assertEq(typeof f1(true), "function"); assertEq(f1(false), 3); function f2(b, w) { + // Annex B doesn't apply to functions in blocks with the same name as a + // parameter. if (b) function w() {} return w; } -assertEq(typeof f2(true, 3), "function"); +assertEq(typeof f2(true, 3), "number"); assertEq(f2(false, 3), 3); diff --git a/js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b-parameter.js b/js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b-parameter.js new file mode 100644 index 000000000..f0adedf7d --- /dev/null +++ b/js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b-parameter.js @@ -0,0 +1,16 @@ +// Annex B.3.3.1 disallows Annex B lexical function behavior when redeclaring a +// parameter. + +(function(f) { + if (true) function f() { } + assertEq(f, 123); +}(123)); + +(function(f) { + { function f() { } } + assertEq(f, 123); +}(123)); + + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/js1_8/regress/regress-467495-05.js b/js/src/tests/js1_8/regress/regress-467495-05.js index 505fb6bd6..ecf47b8fe 100644 --- a/js/src/tests/js1_8/regress/regress-467495-05.js +++ b/js/src/tests/js1_8/regress/regress-467495-05.js @@ -20,7 +20,7 @@ function test() printBugNumber(BUGNUMBER); printStatus (summary); - expect = 'function x() {}'; + expect = '1'; function g(x) { if (1) function x() {} return x; } print(actual = g(1) + ''); diff --git a/js/src/tests/js1_8/regress/regress-467495-06.js b/js/src/tests/js1_8/regress/regress-467495-06.js index d8bc81c83..72adeee9e 100644 --- a/js/src/tests/js1_8/regress/regress-467495-06.js +++ b/js/src/tests/js1_8/regress/regress-467495-06.js @@ -32,7 +32,7 @@ function test() var r = f(0); - if (typeof(r[0]) != "function") + if (typeof(r[0]) != "number") actual += "Bad r[0]"; if (typeof(r[1]) != "function") -- cgit v1.2.3 From afb28a43d481075a244b0e18faa8447dfadacf8f Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 16:51:29 -0400 Subject: 1317375 - Implement "Template Literals Revision / Lifting Template Literal Restriction" ECMAScript proposal --- js/src/builtin/ReflectParse.cpp | 12 +- js/src/frontend/BytecodeEmitter.cpp | 5 + js/src/frontend/FoldConstants.cpp | 4 + js/src/frontend/FullParseHandler.h | 4 + js/src/frontend/NameFunctions.cpp | 6 +- js/src/frontend/ParseNode.cpp | 2 + js/src/frontend/ParseNode.h | 18 ++- js/src/frontend/Parser.cpp | 25 ++- js/src/frontend/Parser.h | 3 +- js/src/frontend/SyntaxParseHandler.h | 1 + js/src/frontend/TokenStream.cpp | 140 ++++++++++------- js/src/frontend/TokenStream.h | 62 +++++++- js/src/tests/ecma_6/TemplateStrings/tagTempl.js | 171 +++++++++++++++++++++ .../tests/js1_8_5/reflect-parse/templateStrings.js | 2 + 14 files changed, 386 insertions(+), 69 deletions(-) (limited to 'js/src') diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp index 2a0a08a5d..3495ede2f 100644 --- a/js/src/builtin/ReflectParse.cpp +++ b/js/src/builtin/ReflectParse.cpp @@ -3044,7 +3044,12 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos)); RootedValue expr(cx); - expr.setString(next->pn_atom); + if (next->isKind(PNK_RAW_UNDEFINED)) { + expr.setUndefined(); + } else { + MOZ_ASSERT(next->isKind(PNK_TEMPLATE_STRING)); + expr.setString(next->pn_atom); + } cooked.infallibleAppend(expr); } @@ -3136,6 +3141,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) case PNK_TRUE: case PNK_FALSE: case PNK_NULL: + case PNK_RAW_UNDEFINED: return literal(pn, dst); case PNK_YIELD_STAR: @@ -3276,6 +3282,10 @@ ASTSerializer::literal(ParseNode* pn, MutableHandleValue dst) val.setNull(); break; + case PNK_RAW_UNDEFINED: + val.setUndefined(); + break; + case PNK_TRUE: val.setBoolean(true); break; diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 7f9fa8a5d..44787dc52 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -3069,6 +3069,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer) case PNK_TRUE: case PNK_FALSE: case PNK_NULL: + case PNK_RAW_UNDEFINED: case PNK_ELISION: case PNK_GENERATOR: case PNK_NUMBER: @@ -6242,6 +6243,9 @@ ParseNode::getConstantValue(ExclusiveContext* cx, AllowConstantObjects allowObje case PNK_NULL: vp.setNull(); return true; + case PNK_RAW_UNDEFINED: + vp.setUndefined(); + return true; case PNK_CALLSITEOBJ: case PNK_ARRAY: { unsigned count; @@ -10636,6 +10640,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote) case PNK_TRUE: case PNK_FALSE: case PNK_NULL: + case PNK_RAW_UNDEFINED: if (!emit1(pn->getOp())) return false; break; diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.cpp index 6f62ffac6..441a72a45 100644 --- a/js/src/frontend/FoldConstants.cpp +++ b/js/src/frontend/FoldConstants.cpp @@ -378,6 +378,7 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result) case PNK_TRUE: case PNK_FALSE: case PNK_NULL: + case PNK_RAW_UNDEFINED: case PNK_THIS: case PNK_ELISION: case PNK_NUMBER: @@ -468,6 +469,7 @@ IsEffectless(ParseNode* node) node->isKind(PNK_TEMPLATE_STRING) || node->isKind(PNK_NUMBER) || node->isKind(PNK_NULL) || + node->isKind(PNK_RAW_UNDEFINED) || node->isKind(PNK_FUNCTION) || node->isKind(PNK_GENEXP); } @@ -492,6 +494,7 @@ Boolish(ParseNode* pn) case PNK_FALSE: case PNK_NULL: + case PNK_RAW_UNDEFINED: return Falsy; case PNK_VOID: { @@ -1643,6 +1646,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser& parser, bo case PNK_TRUE: case PNK_FALSE: case PNK_NULL: + case PNK_RAW_UNDEFINED: case PNK_ELISION: case PNK_NUMBER: case PNK_DEBUGGER: diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index 3938d9743..f0fc7700d 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -183,6 +183,10 @@ class FullParseHandler return new_(pos); } + ParseNode* newRawUndefinedLiteral(const TokenPos& pos) { + return new_(pos); + } + // The Boxer object here is any object that can allocate ObjectBoxes. // Specifically, a Boxer has a .newObjectBox(T) method that accepts a // Rooted argument and returns an ObjectBox*. diff --git a/js/src/frontend/NameFunctions.cpp b/js/src/frontend/NameFunctions.cpp index ce1318f0b..dc54d0a88 100644 --- a/js/src/frontend/NameFunctions.cpp +++ b/js/src/frontend/NameFunctions.cpp @@ -316,7 +316,8 @@ class NameResolver return false; // Next is the callsite object node. This node only contains - // internal strings and an array -- no user-controlled expressions. + // internal strings or undefined and an array -- no user-controlled + // expressions. element = element->pn_next; #ifdef DEBUG { @@ -326,7 +327,7 @@ class NameResolver for (ParseNode* kid = array->pn_head; kid; kid = kid->pn_next) MOZ_ASSERT(kid->isKind(PNK_TEMPLATE_STRING)); for (ParseNode* next = array->pn_next; next; next = next->pn_next) - MOZ_ASSERT(next->isKind(PNK_TEMPLATE_STRING)); + MOZ_ASSERT(next->isKind(PNK_TEMPLATE_STRING) || next->isKind(PNK_RAW_UNDEFINED)); } #endif @@ -382,6 +383,7 @@ class NameResolver case PNK_TRUE: case PNK_FALSE: case PNK_NULL: + case PNK_RAW_UNDEFINED: case PNK_ELISION: case PNK_GENERATOR: case PNK_NUMBER: diff --git a/js/src/frontend/ParseNode.cpp b/js/src/frontend/ParseNode.cpp index 91f17625c..5fe64e3d3 100644 --- a/js/src/frontend/ParseNode.cpp +++ b/js/src/frontend/ParseNode.cpp @@ -190,6 +190,7 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack) case PNK_TRUE: case PNK_FALSE: case PNK_NULL: + case PNK_RAW_UNDEFINED: case PNK_ELISION: case PNK_GENERATOR: case PNK_NUMBER: @@ -685,6 +686,7 @@ NullaryNode::dump() case PNK_TRUE: fprintf(stderr, "#true"); break; case PNK_FALSE: fprintf(stderr, "#false"); break; case PNK_NULL: fprintf(stderr, "#null"); break; + case PNK_RAW_UNDEFINED: fprintf(stderr, "#undefined"); break; case PNK_NUMBER: { ToCStringBuf cbuf; diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index c3523afe4..c0669d85e 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -54,6 +54,7 @@ class ObjectBox; F(TRUE) \ F(FALSE) \ F(NULL) \ + F(RAW_UNDEFINED) \ F(THIS) \ F(FUNCTION) \ F(MODULE) \ @@ -406,7 +407,8 @@ IsTypeofKind(ParseNodeKind kind) * PNK_NUMBER dval pn_dval: double value of numeric literal * PNK_TRUE, nullary pn_op: JSOp bytecode * PNK_FALSE, - * PNK_NULL + * PNK_NULL, + * PNK_RAW_UNDEFINED * * PNK_THIS, unary pn_kid: '.this' Name if function `this`, else nullptr * PNK_SUPERBASE unary pn_kid: '.this' Name @@ -686,7 +688,8 @@ class ParseNode isKind(PNK_STRING) || isKind(PNK_TRUE) || isKind(PNK_FALSE) || - isKind(PNK_NULL); + isKind(PNK_NULL) || + isKind(PNK_RAW_UNDEFINED); } /* Return true if this node appears in a Directive Prologue. */ @@ -1141,6 +1144,16 @@ class NullLiteral : public ParseNode explicit NullLiteral(const TokenPos& pos) : ParseNode(PNK_NULL, JSOP_NULL, PN_NULLARY, pos) { } }; +// This is only used internally, currently just for tagged templates. +// It represents the value 'undefined' (aka `void 0`), like NullLiteral +// represents the value 'null'. +class RawUndefinedLiteral : public ParseNode +{ + public: + explicit RawUndefinedLiteral(const TokenPos& pos) + : ParseNode(PNK_RAW_UNDEFINED, JSOP_UNDEFINED, PN_NULLARY, pos) { } +}; + class BooleanLiteral : public ParseNode { public: @@ -1361,6 +1374,7 @@ ParseNode::isConstant() case PNK_STRING: case PNK_TEMPLATE_STRING: case PNK_NULL: + case PNK_RAW_UNDEFINED: case PNK_FALSE: case PNK_TRUE: return true; diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 66ada79f2..0ff10f73f 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -3123,7 +3123,7 @@ template typename ParseHandler::Node Parser::templateLiteral(YieldHandling yieldHandling) { - Node pn = noSubstitutionTemplate(); + Node pn = noSubstitutionUntaggedTemplate(); if (!pn) return null(); @@ -3136,7 +3136,7 @@ Parser::templateLiteral(YieldHandling yieldHandling) if (!addExprAndGetNextTemplStrToken(yieldHandling, nodeList, &tt)) return null(); - pn = noSubstitutionTemplate(); + pn = noSubstitutionUntaggedTemplate(); if (!pn) return null(); @@ -3365,7 +3365,7 @@ template bool Parser::appendToCallSiteObj(Node callSiteObj) { - Node cookedNode = noSubstitutionTemplate(); + Node cookedNode = noSubstitutionTaggedTemplate(); if (!cookedNode) return false; @@ -8753,8 +8753,23 @@ Parser::stringLiteral() template typename ParseHandler::Node -Parser::noSubstitutionTemplate() +Parser::noSubstitutionTaggedTemplate() { + if (tokenStream.hasInvalidTemplateEscape()) { + tokenStream.clearInvalidTemplateEscape(); + return handler.newRawUndefinedLiteral(pos()); + } + + return handler.newTemplateStringLiteral(stopStringCompression(), pos()); +} + +template +typename ParseHandler::Node +Parser::noSubstitutionUntaggedTemplate() +{ + if (!tokenStream.checkForInvalidTemplateEscapeError()) + return null(); + return handler.newTemplateStringLiteral(stopStringCompression(), pos()); } @@ -9485,7 +9500,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling return templateLiteral(yieldHandling); case TOK_NO_SUBS_TEMPLATE: - return noSubstitutionTemplate(); + return noSubstitutionUntaggedTemplate(); case TOK_STRING: return stringLiteral(); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index e36a6e8b2..b850dc00b 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1052,7 +1052,8 @@ class Parser final : public ParserBase, private JS::AutoGCRooter JSAtom* stopStringCompression(); Node stringLiteral(); - Node noSubstitutionTemplate(); + Node noSubstitutionTaggedTemplate(); + Node noSubstitutionUntaggedTemplate(); Node templateLiteral(YieldHandling yieldHandling); bool taggedTemplate(YieldHandling yieldHandling, Node nodeList, TokenKind tt); bool appendToCallSiteObj(Node callSiteObj); diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index 9dc3c1072..aa85a631e 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -224,6 +224,7 @@ class SyntaxParseHandler Node newThisLiteral(const TokenPos& pos, Node thisName) { return NodeGeneric; } Node newNullLiteral(const TokenPos& pos) { return NodeGeneric; } + Node newRawUndefinedLiteral(const TokenPos& pos) { return NodeGeneric; } template Node newRegExp(RegExpObject* reobj, const TokenPos& pos, Boxer& boxer) { return NodeGeneric; } diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index 186b7a8ab..6a7934e8f 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -1917,55 +1917,6 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier) return false; } -bool -TokenStream::matchBracedUnicode(bool* matched, uint32_t* cp) -{ - int32_t c; - if (!peekChar(&c)) - return false; - if (c != '{') { - *matched = false; - return true; - } - - consumeKnownChar('{'); - - uint32_t start = userbuf.offset(); - - bool first = true; - uint32_t code = 0; - do { - int32_t c = getCharIgnoreEOL(); - if (c == EOF) { - error(JSMSG_MALFORMED_ESCAPE, "Unicode"); - return false; - } - if (c == '}') { - if (first) { - error(JSMSG_MALFORMED_ESCAPE, "Unicode"); - return false; - } - break; - } - - if (!JS7_ISHEX(c)) { - error(JSMSG_MALFORMED_ESCAPE, "Unicode"); - return false; - } - - code = (code << 4) | JS7_UNHEX(c); - if (code > unicode::NonBMPMax) { - errorAt(start, JSMSG_UNICODE_OVERFLOW, "escape sequence"); - return false; - } - first = false; - } while (true); - - *matched = true; - *cp = code; - return true; -} - bool TokenStream::getStringOrTemplateToken(int untilChar, Token** tp) { @@ -1988,6 +1939,10 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp) } if (c == '\\') { + // When parsing templates, we don't immediately report errors for + // invalid escapes; these are handled by the parser. + // In those cases we don't append to tokenbuf, since it won't be + // read. switch (c = getChar()) { case 'b': c = '\b'; break; case 'f': c = '\f'; break; @@ -2003,11 +1958,73 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp) // Unicode character specification. case 'u': { - bool matched; - uint32_t code; - if (!matchBracedUnicode(&matched, &code)) + uint32_t code = 0; + + int32_t c2; + if (!peekChar(&c2)) return false; - if (matched) { + + uint32_t start = userbuf.offset() - 2; + + if (c2 == '{') { + consumeKnownChar('{'); + + bool first = true; + bool valid = true; + do { + int32_t c = getCharIgnoreEOL(); + if (c == EOF) { + if (parsingTemplate) { + setInvalidTemplateEscape(start, InvalidEscapeType::Unicode); + valid = false; + break; + } + reportInvalidEscapeError(start, InvalidEscapeType::Unicode); + return false; + } + if (c == '}') { + if (first) { + if (parsingTemplate) { + setInvalidTemplateEscape(start, InvalidEscapeType::Unicode); + valid = false; + break; + } + reportInvalidEscapeError(start, InvalidEscapeType::Unicode); + return false; + } + break; + } + + if (!JS7_ISHEX(c)) { + if (parsingTemplate) { + // We put the character back so that we read + // it on the next pass, which matters if it + // was '`' or '\'. + ungetCharIgnoreEOL(c); + setInvalidTemplateEscape(start, InvalidEscapeType::Unicode); + valid = false; + break; + } + reportInvalidEscapeError(start, InvalidEscapeType::Unicode); + return false; + } + + code = (code << 4) | JS7_UNHEX(c); + if (code > unicode::NonBMPMax) { + if (parsingTemplate) { + setInvalidTemplateEscape(start + 3, InvalidEscapeType::UnicodeOverflow); + valid = false; + break; + } + reportInvalidEscapeError(start + 3, InvalidEscapeType::UnicodeOverflow); + return false; + } + + first = false; + } while (true); + + if (!valid) + continue; MOZ_ASSERT(code <= unicode::NonBMPMax); if (code < unicode::NonBMPMin) { @@ -2030,7 +2047,11 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp) c = (c << 4) + JS7_UNHEX(cp[3]); skipChars(4); } else { - error(JSMSG_MALFORMED_ESCAPE, "Unicode"); + if (parsingTemplate) { + setInvalidTemplateEscape(start, InvalidEscapeType::Unicode); + continue; + } + reportInvalidEscapeError(start, InvalidEscapeType::Unicode); return false; } break; @@ -2043,7 +2064,12 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp) c = (JS7_UNHEX(cp[0]) << 4) + JS7_UNHEX(cp[1]); skipChars(2); } else { - error(JSMSG_MALFORMED_ESCAPE, "hexadecimal"); + uint32_t start = userbuf.offset() - 2; + if (parsingTemplate) { + setInvalidTemplateEscape(start, InvalidEscapeType::Hexadecimal); + continue; + } + reportInvalidEscapeError(start, InvalidEscapeType::Hexadecimal); return false; } break; @@ -2060,8 +2086,8 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp) // Strict mode code allows only \0, then a non-digit. if (val != 0 || JS7_ISDEC(c)) { if (parsingTemplate) { - error(JSMSG_DEPRECATED_OCTAL); - return false; + setInvalidTemplateEscape(userbuf.offset() - 2, InvalidEscapeType::Octal); + continue; } if (!reportStrictModeError(JSMSG_DEPRECATED_OCTAL)) return false; diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index 4efc31446..fbfefbfe1 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -80,6 +80,20 @@ struct TokenPos { enum DecimalPoint { NoDecimal = false, HasDecimal = true }; +enum class InvalidEscapeType { + // No invalid character escapes. + None, + // A malformed \x escape. + Hexadecimal, + // A malformed \u escape. + Unicode, + // An otherwise well-formed \u escape which represents a + // codepoint > 10FFFF. + UnicodeOverflow, + // An octal escape in a template token. + Octal +}; + class TokenStream; struct Token @@ -361,6 +375,23 @@ class MOZ_STACK_CLASS TokenStream bool hadError() const { return flags.hadError; } void clearSawOctalEscape() { flags.sawOctalEscape = false; } + bool hasInvalidTemplateEscape() const { + return invalidTemplateEscapeType != InvalidEscapeType::None; + } + void clearInvalidTemplateEscape() { + invalidTemplateEscapeType = InvalidEscapeType::None; + } + + // If there is an invalid escape in a template, report it and return false, + // otherwise return true. + bool checkForInvalidTemplateEscapeError() { + if (invalidTemplateEscapeType == InvalidEscapeType::None) + return true; + + reportInvalidEscapeError(invalidTemplateEscapeOffset, invalidTemplateEscapeType); + return false; + } + // TokenStream-specific error reporters. bool reportError(unsigned errorNumber, ...); bool reportErrorNoOffset(unsigned errorNumber, ...); @@ -422,6 +453,33 @@ class MOZ_STACK_CLASS TokenStream bool reportStrictModeError(unsigned errorNumber, ...); bool strictMode() const { return strictModeGetter && strictModeGetter->strictMode(); } + void setInvalidTemplateEscape(uint32_t offset, InvalidEscapeType type) { + MOZ_ASSERT(type != InvalidEscapeType::None); + if (invalidTemplateEscapeType != InvalidEscapeType::None) + return; + invalidTemplateEscapeOffset = offset; + invalidTemplateEscapeType = type; + } + void reportInvalidEscapeError(uint32_t offset, InvalidEscapeType type) { + switch (type) { + case InvalidEscapeType::None: + MOZ_ASSERT_UNREACHABLE("unexpected InvalidEscapeType"); + return; + case InvalidEscapeType::Hexadecimal: + errorAt(offset, JSMSG_MALFORMED_ESCAPE, "hexadecimal"); + return; + case InvalidEscapeType::Unicode: + errorAt(offset, JSMSG_MALFORMED_ESCAPE, "Unicode"); + return; + case InvalidEscapeType::UnicodeOverflow: + errorAt(offset, JSMSG_UNICODE_OVERFLOW, "escape sequence"); + return; + case InvalidEscapeType::Octal: + errorAt(offset, JSMSG_DEPRECATED_OCTAL); + return; + } + } + static JSAtom* atomize(ExclusiveContext* cx, CharBuffer& cb); MOZ_MUST_USE bool putIdentInTokenbuf(const char16_t* identStart); @@ -442,6 +500,9 @@ class MOZ_STACK_CLASS TokenStream bool awaitIsKeyword = false; friend class AutoAwaitIsKeyword; + uint32_t invalidTemplateEscapeOffset = 0; + InvalidEscapeType invalidTemplateEscapeType = InvalidEscapeType::None; + public: typedef Token::Modifier Modifier; static constexpr Modifier None = Token::None; @@ -955,7 +1016,6 @@ class MOZ_STACK_CLASS TokenStream MOZ_MUST_USE bool getTokenInternal(TokenKind* ttp, Modifier modifier); - MOZ_MUST_USE bool matchBracedUnicode(bool* matched, uint32_t* code); MOZ_MUST_USE bool getStringOrTemplateToken(int untilChar, Token** tp); int32_t getChar(); diff --git a/js/src/tests/ecma_6/TemplateStrings/tagTempl.js b/js/src/tests/ecma_6/TemplateStrings/tagTempl.js index 1e3f52bfb..99c2098dc 100644 --- a/js/src/tests/ecma_6/TemplateStrings/tagTempl.js +++ b/js/src/tests/ecma_6/TemplateStrings/tagTempl.js @@ -287,5 +287,176 @@ assertEq(String.raw`h\r\ney${4}there\n`, "h\\r\\ney4there\\n"); assertEq(String.raw`hey`, "hey"); assertEq(String.raw``, ""); +// Invalid escape sequences +check(raw`\01`, ["\\01"]); +check(raw`\01${0}right`, ["\\01","right"]); +check(raw`left${0}\01`, ["left","\\01"]); +check(raw`left${0}\01${1}right`, ["left","\\01","right"]); +check(raw`\1`, ["\\1"]); +check(raw`\1${0}right`, ["\\1","right"]); +check(raw`left${0}\1`, ["left","\\1"]); +check(raw`left${0}\1${1}right`, ["left","\\1","right"]); +check(raw`\xg`, ["\\xg"]); +check(raw`\xg${0}right`, ["\\xg","right"]); +check(raw`left${0}\xg`, ["left","\\xg"]); +check(raw`left${0}\xg${1}right`, ["left","\\xg","right"]); +check(raw`\xAg`, ["\\xAg"]); +check(raw`\xAg${0}right`, ["\\xAg","right"]); +check(raw`left${0}\xAg`, ["left","\\xAg"]); +check(raw`left${0}\xAg${1}right`, ["left","\\xAg","right"]); +check(raw`\u0`, ["\\u0"]); +check(raw`\u0${0}right`, ["\\u0","right"]); +check(raw`left${0}\u0`, ["left","\\u0"]); +check(raw`left${0}\u0${1}right`, ["left","\\u0","right"]); +check(raw`\u0g`, ["\\u0g"]); +check(raw`\u0g${0}right`, ["\\u0g","right"]); +check(raw`left${0}\u0g`, ["left","\\u0g"]); +check(raw`left${0}\u0g${1}right`, ["left","\\u0g","right"]); +check(raw`\u00g`, ["\\u00g"]); +check(raw`\u00g${0}right`, ["\\u00g","right"]); +check(raw`left${0}\u00g`, ["left","\\u00g"]); +check(raw`left${0}\u00g${1}right`, ["left","\\u00g","right"]); +check(raw`\u000g`, ["\\u000g"]); +check(raw`\u000g${0}right`, ["\\u000g","right"]); +check(raw`left${0}\u000g`, ["left","\\u000g"]); +check(raw`left${0}\u000g${1}right`, ["left","\\u000g","right"]); +check(raw`\u{}`, ["\\u{}"]); +check(raw`\u{}${0}right`, ["\\u{}","right"]); +check(raw`left${0}\u{}`, ["left","\\u{}"]); +check(raw`left${0}\u{}${1}right`, ["left","\\u{}","right"]); +check(raw`\u{-0}`, ["\\u{-0}"]); +check(raw`\u{-0}${0}right`, ["\\u{-0}","right"]); +check(raw`left${0}\u{-0}`, ["left","\\u{-0}"]); +check(raw`left${0}\u{-0}${1}right`, ["left","\\u{-0}","right"]); +check(raw`\u{g}`, ["\\u{g}"]); +check(raw`\u{g}${0}right`, ["\\u{g}","right"]); +check(raw`left${0}\u{g}`, ["left","\\u{g}"]); +check(raw`left${0}\u{g}${1}right`, ["left","\\u{g}","right"]); +check(raw`\u{0`, ["\\u{0"]); +check(raw`\u{0${0}right`, ["\\u{0","right"]); +check(raw`left${0}\u{0`, ["left","\\u{0"]); +check(raw`left${0}\u{0${1}right`, ["left","\\u{0","right"]); +check(raw`\u{\u{0}`, ["\\u{\\u{0}"]); +check(raw`\u{\u{0}${0}right`, ["\\u{\\u{0}","right"]); +check(raw`left${0}\u{\u{0}`, ["left","\\u{\\u{0}"]); +check(raw`left${0}\u{\u{0}${1}right`, ["left","\\u{\\u{0}","right"]); +check(raw`\u{110000}`, ["\\u{110000}"]); +check(raw`\u{110000}${0}right`, ["\\u{110000}","right"]); +check(raw`left${0}\u{110000}`, ["left","\\u{110000}"]); +check(raw`left${0}\u{110000}${1}right`, ["left","\\u{110000}","right"]); + +check(cooked`\01`, [void 0]); +check(cooked`\01${0}right`, [void 0,"right"]); +check(cooked`left${0}\01`, ["left",void 0]); +check(cooked`left${0}\01${1}right`, ["left",void 0,"right"]); +check(cooked`\1`, [void 0]); +check(cooked`\1${0}right`, [void 0,"right"]); +check(cooked`left${0}\1`, ["left",void 0]); +check(cooked`left${0}\1${1}right`, ["left",void 0,"right"]); +check(cooked`\xg`, [void 0]); +check(cooked`\xg${0}right`, [void 0,"right"]); +check(cooked`left${0}\xg`, ["left",void 0]); +check(cooked`left${0}\xg${1}right`, ["left",void 0,"right"]); +check(cooked`\xAg`, [void 0]); +check(cooked`\xAg${0}right`, [void 0,"right"]); +check(cooked`left${0}\xAg`, ["left",void 0]); +check(cooked`left${0}\xAg${1}right`, ["left",void 0,"right"]); +check(cooked`\u0`, [void 0]); +check(cooked`\u0${0}right`, [void 0,"right"]); +check(cooked`left${0}\u0`, ["left",void 0]); +check(cooked`left${0}\u0${1}right`, ["left",void 0,"right"]); +check(cooked`\u0g`, [void 0]); +check(cooked`\u0g${0}right`, [void 0,"right"]); +check(cooked`left${0}\u0g`, ["left",void 0]); +check(cooked`left${0}\u0g${1}right`, ["left",void 0,"right"]); +check(cooked`\u00g`, [void 0]); +check(cooked`\u00g${0}right`, [void 0,"right"]); +check(cooked`left${0}\u00g`, ["left",void 0]); +check(cooked`left${0}\u00g${1}right`, ["left",void 0,"right"]); +check(cooked`\u000g`, [void 0]); +check(cooked`\u000g${0}right`, [void 0,"right"]); +check(cooked`left${0}\u000g`, ["left",void 0]); +check(cooked`left${0}\u000g${1}right`, ["left",void 0,"right"]); +check(cooked`\u{}`, [void 0]); +check(cooked`\u{}${0}right`, [void 0,"right"]); +check(cooked`left${0}\u{}`, ["left",void 0]); +check(cooked`left${0}\u{}${1}right`, ["left",void 0,"right"]); +check(cooked`\u{-0}`, [void 0]); +check(cooked`\u{-0}${0}right`, [void 0,"right"]); +check(cooked`left${0}\u{-0}`, ["left",void 0]); +check(cooked`left${0}\u{-0}${1}right`, ["left",void 0,"right"]); +check(cooked`\u{g}`, [void 0]); +check(cooked`\u{g}${0}right`, [void 0,"right"]); +check(cooked`left${0}\u{g}`, ["left",void 0]); +check(cooked`left${0}\u{g}${1}right`, ["left",void 0,"right"]); +check(cooked`\u{0`, [void 0]); +check(cooked`\u{0${0}right`, [void 0,"right"]); +check(cooked`left${0}\u{0`, ["left",void 0]); +check(cooked`left${0}\u{0${1}right`, ["left",void 0,"right"]); +check(cooked`\u{\u{0}`, [void 0]); +check(cooked`\u{\u{0}${0}right`, [void 0,"right"]); +check(cooked`left${0}\u{\u{0}`, ["left",void 0]); +check(cooked`left${0}\u{\u{0}${1}right`, ["left",void 0,"right"]); +check(cooked`\u{110000}`, [void 0]); +check(cooked`\u{110000}${0}right`, [void 0,"right"]); +check(cooked`left${0}\u{110000}`, ["left",void 0]); +check(cooked`left${0}\u{110000}${1}right`, ["left",void 0,"right"]); + +syntaxError("`\\01`"); +syntaxError("`\\01${0}right`"); +syntaxError("`left${0}\\01`"); +syntaxError("`left${0}\\01${1}right`"); +syntaxError("`\\1`"); +syntaxError("`\\1${0}right`"); +syntaxError("`left${0}\\1`"); +syntaxError("`left${0}\\1${1}right`"); +syntaxError("`\\xg`"); +syntaxError("`\\xg${0}right`"); +syntaxError("`left${0}\\xg`"); +syntaxError("`left${0}\\xg${1}right`"); +syntaxError("`\\xAg`"); +syntaxError("`\\xAg${0}right`"); +syntaxError("`left${0}\\xAg`"); +syntaxError("`left${0}\\xAg${1}right`"); +syntaxError("`\\u0`"); +syntaxError("`\\u0${0}right`"); +syntaxError("`left${0}\\u0`"); +syntaxError("`left${0}\\u0${1}right`"); +syntaxError("`\\u0g`"); +syntaxError("`\\u0g${0}right`"); +syntaxError("`left${0}\\u0g`"); +syntaxError("`left${0}\\u0g${1}right`"); +syntaxError("`\\u00g`"); +syntaxError("`\\u00g${0}right`"); +syntaxError("`left${0}\\u00g`"); +syntaxError("`left${0}\\u00g${1}right`"); +syntaxError("`\\u000g`"); +syntaxError("`\\u000g${0}right`"); +syntaxError("`left${0}\\u000g`"); +syntaxError("`left${0}\\u000g${1}right`"); +syntaxError("`\\u{}`"); +syntaxError("`\\u{}${0}right`"); +syntaxError("`left${0}\\u{}`"); +syntaxError("`left${0}\\u{}${1}right`"); +syntaxError("`\\u{-0}`"); +syntaxError("`\\u{-0}${0}right`"); +syntaxError("`left${0}\\u{-0}`"); +syntaxError("`left${0}\\u{-0}${1}right`"); +syntaxError("`\\u{g}`"); +syntaxError("`\\u{g}${0}right`"); +syntaxError("`left${0}\\u{g}`"); +syntaxError("`left${0}\\u{g}${1}right`"); +syntaxError("`\\u{0`"); +syntaxError("`\\u{0${0}right`"); +syntaxError("`left${0}\\u{0`"); +syntaxError("`left${0}\\u{0${1}right`"); +syntaxError("`\\u{\\u{0}`"); +syntaxError("`\\u{\\u{0}${0}right`"); +syntaxError("`left${0}\\u{\\u{0}`"); +syntaxError("`left${0}\\u{\\u{0}${1}right`"); +syntaxError("`\\u{110000}`"); +syntaxError("`\\u{110000}${0}right`"); +syntaxError("`left${0}\\u{110000}`"); +syntaxError("`left${0}\\u{110000}${1}right`"); reportCompare(0, 0, "ok"); diff --git a/js/src/tests/js1_8_5/reflect-parse/templateStrings.js b/js/src/tests/js1_8_5/reflect-parse/templateStrings.js index c87ba96b8..fb12afd00 100644 --- a/js/src/tests/js1_8_5/reflect-parse/templateStrings.js +++ b/js/src/tests/js1_8_5/reflect-parse/templateStrings.js @@ -7,6 +7,8 @@ assertStringExpr("`hey\nthere`", literal("hey\nthere")); assertExpr("`hey${\"there\"}`", templateLit([lit("hey"), lit("there"), lit("")])); assertExpr("`hey${\"there\"}mine`", templateLit([lit("hey"), lit("there"), lit("mine")])); assertExpr("`hey${a == 5}mine`", templateLit([lit("hey"), binExpr("==", ident("a"), lit(5)), lit("mine")])); +assertExpr("func`hey\\x`", taggedTemplate(ident("func"), template(["hey\\x"], [void 0]))); +assertExpr("func`hey${4}\\x`", taggedTemplate(ident("func"), template(["hey","\\x"], ["hey",void 0], lit(4)))); assertExpr("`hey${`there${\"how\"}`}mine`", templateLit([lit("hey"), templateLit([lit("there"), lit("how"), lit("")]), lit("mine")])); assertExpr("func`hey`", taggedTemplate(ident("func"), template(["hey"], ["hey"]))); -- cgit v1.2.3 From 668254e2b2a7b4f1d6da703275b89f3753096f71 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 17:11:49 -0400 Subject: 903389 - Fix uses of ClassMethodIsNative. --- js/src/builtin/RegExp.cpp | 2 +- .../tests/asm.js/import-function-toPrimitive.js | 26 +++++++++++++ .../basic/hasnativemethodpure-optimization.js | 21 +++++++++++ js/src/jsobj.cpp | 24 ++---------- js/src/jsobjinlines.h | 44 +++++++--------------- js/src/jsstr.cpp | 8 +++- js/src/vm/NativeObject.h | 13 ------- js/src/wasm/AsmJS.cpp | 6 +-- 8 files changed, 73 insertions(+), 71 deletions(-) create mode 100644 js/src/jit-test/tests/asm.js/import-function-toPrimitive.js create mode 100644 js/src/jit-test/tests/basic/hasnativemethodpure-optimization.js (limited to 'js/src') diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp index b20f41c53..d71cee75e 100644 --- a/js/src/builtin/RegExp.cpp +++ b/js/src/builtin/RegExp.cpp @@ -1800,7 +1800,7 @@ js::intrinsic_GetStringDataProperty(JSContext* cx, unsigned argc, Value* vp) return false; RootedValue v(cx); - if (HasDataProperty(cx, nobj, AtomToId(atom), v.address()) && v.isString()) + if (GetPropertyPure(cx, nobj, AtomToId(atom), v.address()) && v.isString()) args.rval().set(v); else args.rval().setUndefined(); diff --git a/js/src/jit-test/tests/asm.js/import-function-toPrimitive.js b/js/src/jit-test/tests/asm.js/import-function-toPrimitive.js new file mode 100644 index 000000000..aa529b465 --- /dev/null +++ b/js/src/jit-test/tests/asm.js/import-function-toPrimitive.js @@ -0,0 +1,26 @@ +var counter = 0; + +function f(stdlib, foreign) +{ + "use asm"; + var a = +foreign.a; + var b = +foreign.b; + function g() {} + return g; +} + +var foreign = + { + a: function() {}, + b: /value that doesn't coerce purely/, + }; + +foreign.a[Symbol.toPrimitive] = + function() + { + counter++; + return 0; + }; + +f(null, foreign); +assertEq(counter, 1); diff --git a/js/src/jit-test/tests/basic/hasnativemethodpure-optimization.js b/js/src/jit-test/tests/basic/hasnativemethodpure-optimization.js new file mode 100644 index 000000000..2f5e99186 --- /dev/null +++ b/js/src/jit-test/tests/basic/hasnativemethodpure-optimization.js @@ -0,0 +1,21 @@ +load(libdir + "asserts.js"); + +let string = Object.defineProperty(new String("123"), "valueOf", { + get: function() { throw "get-valueOf"; } +}); +assertThrowsValue(() => "" + string, "get-valueOf"); + +string = Object.defineProperty(new String("123"), "toString", { + get: function() { throw "get-toString"; } +}); +assertThrowsValue(() => string.toLowerCase(), "get-toString"); + +string = Object.defineProperty(new String("123"), Symbol.toPrimitive, { + get: function() { throw "get-toPrimitive"; } +}); +assertThrowsValue(() => string.toLowerCase(), "get-toPrimitive"); + +let number = Object.defineProperty(new Number(123), "valueOf", { + get: function() { throw "get-valueOf"; } +}); +assertThrowsValue(() => +number, "get-valueOf"); \ No newline at end of file diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 2364f707e..418e08dad 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -2852,24 +2852,6 @@ js::GetObjectClassName(JSContext* cx, HandleObject obj) /* * */ -bool -js::HasDataProperty(JSContext* cx, NativeObject* obj, jsid id, Value* vp) -{ - if (JSID_IS_INT(id) && obj->containsDenseElement(JSID_TO_INT(id))) { - *vp = obj->getDenseElement(JSID_TO_INT(id)); - return true; - } - - if (Shape* shape = obj->lookup(cx, id)) { - if (shape->hasDefaultGetter() && shape->hasSlot()) { - *vp = obj->getSlot(shape->slot()); - return true; - } - } - - return false; -} - extern bool PropertySpecNameToId(JSContext* cx, const char* name, MutableHandleId id, js::PinningBehavior pin = js::DoNotPinAtom); @@ -2985,7 +2967,7 @@ JS::OrdinaryToPrimitive(JSContext* cx, HandleObject obj, JSType hint, MutableHan /* Optimize (new String(...)).toString(). */ if (clasp == &StringObject::class_) { StringObject* nobj = &obj->as(); - if (ClassMethodIsNative(cx, nobj, &StringObject::class_, id, str_toString)) { + if (HasNativeMethodPure(nobj, cx->names().toString, str_toString, cx)) { vp.setString(nobj->unbox()); return true; } @@ -3007,7 +2989,7 @@ JS::OrdinaryToPrimitive(JSContext* cx, HandleObject obj, JSType hint, MutableHan /* Optimize new String(...).valueOf(). */ if (clasp == &StringObject::class_) { StringObject* nobj = &obj->as(); - if (ClassMethodIsNative(cx, nobj, &StringObject::class_, id, str_toString)) { + if (HasNativeMethodPure(nobj, cx->names().valueOf, str_toString, cx)) { vp.setString(nobj->unbox()); return true; } @@ -3016,7 +2998,7 @@ JS::OrdinaryToPrimitive(JSContext* cx, HandleObject obj, JSType hint, MutableHan /* Optimize new Number(...).valueOf(). */ if (clasp == &NumberObject::class_) { NumberObject* nobj = &obj->as(); - if (ClassMethodIsNative(cx, nobj, &NumberObject::class_, id, num_valueOf)) { + if (HasNativeMethodPure(nobj, cx->names().valueOf, num_valueOf, cx)) { vp.setNumber(nobj->unbox()); return true; } diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index b1d817bca..7028310ce 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -557,48 +557,30 @@ IsNativeFunction(const js::Value& v, JSNative native) return IsFunctionObject(v, &fun) && fun->maybeNative() == native; } -/* - * When we have an object of a builtin class, we don't quite know what its - * valueOf/toString methods are, since these methods may have been overwritten - * or shadowed. However, we can still do better than the general case by - * hard-coding the necessary properties for us to find the native we expect. - * - * TODO: a per-thread shape-based cache would be faster and simpler. - */ +// Return whether looking up a method on 'obj' definitely resolves to the +// original specified native function. The method may conservatively return +// 'false' in the case of proxies or other non-native objects. static MOZ_ALWAYS_INLINE bool -ClassMethodIsNative(JSContext* cx, NativeObject* obj, const Class* clasp, jsid methodid, JSNative native) +HasNativeMethodPure(JSObject* obj, PropertyName* name, JSNative native, JSContext* cx) { - MOZ_ASSERT(obj->getClass() == clasp); - Value v; - if (!HasDataProperty(cx, obj, methodid, &v)) { - JSObject* proto = obj->staticPrototype(); - if (!proto || proto->getClass() != clasp || !HasDataProperty(cx, &proto->as(), methodid, &v)) - return false; - } + if (!GetPropertyPure(cx, obj, NameToId(name), &v)) + return false; return IsNativeFunction(v, native); } -// Return whether looking up 'valueOf' on 'obj' definitely resolves to the -// original Object.prototype.valueOf. The method may conservatively return -// 'false' in the case of proxies or other non-native objects. +// Return whether 'obj' definitely has no @@toPrimitive method. static MOZ_ALWAYS_INLINE bool -HasObjectValueOf(JSObject* obj, JSContext* cx) +HasNoToPrimitiveMethodPure(JSObject* obj, JSContext* cx) { - if (obj->is() || !obj->isNative()) + jsid id = SYMBOL_TO_JSID(cx->wellKnownSymbols().toPrimitive); + JSObject* pobj; + Shape* shape; + if (!LookupPropertyPure(cx, obj, id, &pobj, &shape)) return false; - jsid valueOf = NameToId(cx->names().valueOf); - - Value v; - while (!HasDataProperty(cx, &obj->as(), valueOf, &v)) { - obj = obj->staticPrototype(); - if (!obj || obj->is() || !obj->isNative()) - return false; - } - - return IsNativeFunction(v, obj_valueOf); + return !shape; } /* ES6 draft rev 28 (2014 Oct 14) 7.1.14 */ diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index d7db5129d..3fecb463d 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -461,9 +461,13 @@ ToStringForStringFunction(JSContext* cx, HandleValue thisv) RootedObject obj(cx, &thisv.toObject()); if (obj->is()) { StringObject* nobj = &obj->as(); - Rooted id(cx, NameToId(cx->names().toString)); - if (ClassMethodIsNative(cx, nobj, &StringObject::class_, id, str_toString)) + // We have to make sure that the ToPrimitive call from ToString + // would be unobservable. + if (HasNoToPrimitiveMethodPure(nobj, cx) && + HasNativeMethodPure(nobj, cx->names().toString, str_toString, cx)) + { return nobj->unbox(); + } } } else if (thisv.isNullOrUndefined()) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_CONVERT_TO, diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h index d9d8b8aec..832a701dd 100644 --- a/js/src/vm/NativeObject.h +++ b/js/src/vm/NativeObject.h @@ -1470,19 +1470,6 @@ NativeGetExistingProperty(JSContext* cx, HandleObject receiver, HandleNativeObje /* * */ -/* - * If obj has an already-resolved data property for id, return true and - * store the property value in *vp. - */ -extern bool -HasDataProperty(JSContext* cx, NativeObject* obj, jsid id, Value* vp); - -inline bool -HasDataProperty(JSContext* cx, NativeObject* obj, PropertyName* name, Value* vp) -{ - return HasDataProperty(cx, obj, NameToId(name), vp); -} - extern bool GetPropertyForNameLookup(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp); diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp index 6483d6ec3..f906d4bf1 100644 --- a/js/src/wasm/AsmJS.cpp +++ b/js/src/wasm/AsmJS.cpp @@ -7478,10 +7478,10 @@ HasPureCoercion(JSContext* cx, HandleValue v) // coercions are not observable and coercion via ToNumber/ToInt32 // definitely produces NaN/0. We should remove this special case later once // most apps have been built with newer Emscripten. - jsid toString = NameToId(cx->names().toString); if (v.toObject().is() && - HasObjectValueOf(&v.toObject(), cx) && - ClassMethodIsNative(cx, &v.toObject().as(), &JSFunction::class_, toString, fun_toString)) + HasNoToPrimitiveMethodPure(&v.toObject(), cx) && + HasNativeMethodPure(&v.toObject(), cx->names().valueOf, obj_valueOf, cx) && + HasNativeMethodPure(&v.toObject(), cx->names().toString, fun_toString, cx)) { return true; } -- cgit v1.2.3 From d074844a4e758209dcfd8ce12720680edd957b42 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 17:13:01 -0400 Subject: 903389 - Make Make NativeGet[Getter]PureInline handle dense/typed array shapes. --- js/src/jsobj.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'js/src') diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 418e08dad..5f6331ac8 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -2326,9 +2326,18 @@ js::LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Shape** } static inline bool -NativeGetPureInline(NativeObject* pobj, Shape* shape, Value* vp) +NativeGetPureInline(NativeObject* pobj, jsid id, Shape* shape, Value* vp) { - /* Fail if we have a custom getter. */ + if (IsImplicitDenseOrTypedArrayElement(shape)) { + // For simplicity we ignore the TypedArray with string index case. + if (!JSID_IS_INT(id)) + return false; + + *vp = pobj->getDenseOrTypedArrayElement(JSID_TO_INT(id)); + return true; + } + + // Fail if we have a custom getter. if (!shape->hasDefaultGetter()) return false; @@ -2355,13 +2364,13 @@ js::GetPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Value* vp) return true; } - return pobj->isNative() && NativeGetPureInline(&pobj->as(), shape, vp); + return pobj->isNative() && NativeGetPureInline(&pobj->as(), id, shape, vp); } static inline bool NativeGetGetterPureInline(Shape* shape, JSFunction** fp) { - if (shape->hasGetterObject()) { + if (!IsImplicitDenseOrTypedArrayElement(shape) && shape->hasGetterObject()) { if (shape->getterObject()->is()) { *fp = &shape->getterObject()->as(); return true; -- cgit v1.2.3 From cefee262b7059d035667b148d56ebc7af5120d37 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 17:19:11 -0400 Subject: 1333143 - Self-host Object.prototype.valueOf. --- js/src/builtin/Object.cpp | 14 +------------- js/src/builtin/Object.h | 3 --- js/src/builtin/Object.js | 6 ++++++ js/src/jit-test/tests/basic/bug713226.js | 2 +- js/src/jit-test/tests/profiler/AutoEntryMonitor-01.js | 2 +- js/src/vm/CommonPropertyNames.h | 1 + js/src/wasm/AsmJS.cpp | 17 ++++++++++++++++- 7 files changed, 26 insertions(+), 19 deletions(-) (limited to 'js/src') diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp index 389bb57db..e4bee5457 100644 --- a/js/src/builtin/Object.cpp +++ b/js/src/builtin/Object.cpp @@ -525,18 +525,6 @@ js::obj_toString(JSContext* cx, unsigned argc, Value* vp) return true; } - -bool -js::obj_valueOf(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - RootedObject obj(cx, ToObject(cx, args.thisv())); - if (!obj) - return false; - args.rval().setObject(*obj); - return true; -} - static bool obj_setPrototypeOf(JSContext* cx, unsigned argc, Value* vp) { @@ -1301,7 +1289,7 @@ static const JSFunctionSpec object_methods[] = { #endif JS_FN(js_toString_str, obj_toString, 0,0), JS_SELF_HOSTED_FN(js_toLocaleString_str, "Object_toLocaleString", 0, 0), - JS_FN(js_valueOf_str, obj_valueOf, 0,0), + JS_SELF_HOSTED_FN(js_valueOf_str, "Object_valueOf", 0,0), #if JS_HAS_OBJ_WATCHPOINT JS_FN(js_watch_str, obj_watch, 2,0), JS_FN(js_unwatch_str, obj_unwatch, 1,0), diff --git a/js/src/builtin/Object.h b/js/src/builtin/Object.h index 09512be36..8231888b1 100644 --- a/js/src/builtin/Object.h +++ b/js/src/builtin/Object.h @@ -25,9 +25,6 @@ obj_construct(JSContext* cx, unsigned argc, JS::Value* vp); MOZ_MUST_USE bool obj_propertyIsEnumerable(JSContext* cx, unsigned argc, Value* vp); -MOZ_MUST_USE bool -obj_valueOf(JSContext* cx, unsigned argc, JS::Value* vp); - PlainObject* ObjectCreateImpl(JSContext* cx, HandleObject proto, NewObjectKind newKind = GenericObject, HandleObjectGroup group = nullptr); diff --git a/js/src/builtin/Object.js b/js/src/builtin/Object.js index a7440aec7..9ed1be0e1 100644 --- a/js/src/builtin/Object.js +++ b/js/src/builtin/Object.js @@ -87,6 +87,12 @@ function Object_toLocaleString() { return callContentFunction(O.toString, O); } +// ES 2017 draft bb96899bb0d9ef9be08164a26efae2ee5f25e875 19.1.3.7 +function Object_valueOf() { + // Step 1. + return ToObject(this); +} + // ES7 draft (2016 March 8) B.2.2.3 function ObjectDefineSetter(name, setter) { // Step 1. diff --git a/js/src/jit-test/tests/basic/bug713226.js b/js/src/jit-test/tests/basic/bug713226.js index 3ae991f43..36858b86c 100644 --- a/js/src/jit-test/tests/basic/bug713226.js +++ b/js/src/jit-test/tests/basic/bug713226.js @@ -8,7 +8,7 @@ function addDebug(g, id) {\ var debuggerGlobal = newGlobal();\ debuggerGlobal.debuggee = g;\ debuggerGlobal.id = id;\ - debuggerGlobal.print = function (s) { (g) += s; };\ + debuggerGlobal.print = function (s) { print(s); };\ debuggerGlobal.eval('var dbg = new Debugger(debuggee);dbg.onDebuggerStatement = function () { print(id); debugger; };');\ return debuggerGlobal;\ }\ diff --git a/js/src/jit-test/tests/profiler/AutoEntryMonitor-01.js b/js/src/jit-test/tests/profiler/AutoEntryMonitor-01.js index d66548680..e9dd5d526 100644 --- a/js/src/jit-test/tests/profiler/AutoEntryMonitor-01.js +++ b/js/src/jit-test/tests/profiler/AutoEntryMonitor-01.js @@ -31,7 +31,7 @@ cold_and_warm(Object.prototype.toString, { ToString: {} }, []); var toS = { toString: function myToString() { return "string"; } }; cold_and_warm(toS.toString, { ToString: toS }, [ "myToString" ]); -cold_and_warm(undefined, { ToNumber: {} }, []); +cold_and_warm(undefined, { ToNumber: 5 }, []); var vOf = { valueOf: function myValueOf() { return 42; } }; cold_and_warm(vOf.valueOf, { ToNumber: vOf }, [ "myValueOf" ]); diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h index 8a36df083..e7a4f1222 100644 --- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -238,6 +238,7 @@ macro(other, other, "other") \ macro(outOfMemory, outOfMemory, "out of memory") \ macro(ownKeys, ownKeys, "ownKeys") \ + macro(Object_valueOf, Object_valueOf, "Object_valueOf") \ macro(parseFloat, parseFloat, "parseFloat") \ macro(parseInt, parseInt, "parseInt") \ macro(pattern, pattern, "pattern") \ diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp index f906d4bf1..81795b47d 100644 --- a/js/src/wasm/AsmJS.cpp +++ b/js/src/wasm/AsmJS.cpp @@ -34,6 +34,7 @@ #include "frontend/Parser.h" #include "gc/Policy.h" #include "js/MemoryMetrics.h" +#include "vm/SelfHosting.h" #include "vm/StringBuffer.h" #include "vm/Time.h" #include "vm/TypedArrayObject.h" @@ -7464,6 +7465,20 @@ GetDataProperty(JSContext* cx, HandleValue objVal, ImmutablePropertyNamePtr fiel return GetDataProperty(cx, objVal, fieldHandle, v); } +static bool +HasObjectValueOfMethodPure(JSObject* obj, JSContext* cx) +{ + Value v; + if (!GetPropertyPure(cx, obj, NameToId(cx->names().valueOf), &v)) + return false; + + JSFunction* fun; + if (!IsFunctionObject(v, &fun)) + return false; + + return IsSelfHostedFunctionWithName(fun, cx->names().Object_valueOf); +} + static bool HasPureCoercion(JSContext* cx, HandleValue v) { @@ -7480,7 +7495,7 @@ HasPureCoercion(JSContext* cx, HandleValue v) // most apps have been built with newer Emscripten. if (v.toObject().is() && HasNoToPrimitiveMethodPure(&v.toObject(), cx) && - HasNativeMethodPure(&v.toObject(), cx->names().valueOf, obj_valueOf, cx) && + HasObjectValueOfMethodPure(&v.toObject(), cx) && HasNativeMethodPure(&v.toObject(), cx->names().toString, fun_toString, cx)) { return true; -- cgit v1.2.3 From 2ea840b045e7db434d6960f72f5313b9621ffd03 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 18:43:21 -0400 Subject: 1175823 - Implement [[DefineOwnProperty]] for mapped arguments object. --- js/src/jsobj.cpp | 2 +- js/src/vm/ArgumentsObject.cpp | 68 ++++++++++++++++++++++++++++++++++++++++++- js/src/vm/ArgumentsObject.h | 3 ++ 3 files changed, 71 insertions(+), 2 deletions(-) (limited to 'js/src') diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 5f6331ac8..bea01daf4 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -471,7 +471,7 @@ js::SetIntegrityLevel(JSContext* cx, HandleObject obj, IntegrityLevel level) // Steps 8-9, loosely interpreted. if (obj->isNative() && !obj->as().inDictionaryMode() && - !obj->is()) + !obj->is() && !obj->is()) { HandleNativeObject nobj = obj.as(); diff --git a/js/src/vm/ArgumentsObject.cpp b/js/src/vm/ArgumentsObject.cpp index 717aa1050..f9a939e6e 100644 --- a/js/src/vm/ArgumentsObject.cpp +++ b/js/src/vm/ArgumentsObject.cpp @@ -590,6 +590,64 @@ MappedArgumentsObject::obj_enumerate(JSContext* cx, HandleObject obj) return true; } +// ES 2017 draft 9.4.4.2 +/* static */ bool +MappedArgumentsObject::obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id, + Handle desc, ObjectOpResult& result) +{ + // Step 1. + Rooted argsobj(cx, &obj->as()); + + // Steps 2-3. + bool isMapped = false; + if (JSID_IS_INT(id)) { + unsigned arg = unsigned(JSID_TO_INT(id)); + isMapped = arg < argsobj->initialLength() && !argsobj->isElementDeleted(arg); + } + + // Step 4. + Rooted newArgDesc(cx, desc); + if (!desc.isAccessorDescriptor() && isMapped) { + // In this case the live mapping is supposed to keep working, + // we have to pass along the Getter/Setter otherwise they are overwritten. + newArgDesc.setGetter(MappedArgGetter); + newArgDesc.setSetter(MappedArgSetter); + } + + // Steps 5-6. NativeDefineProperty will lookup [[Value]] for us. + if (!NativeDefineProperty(cx, obj.as(), id, newArgDesc, result)) + return false; + // Step 7. + if (!result.ok()) + return true; + + // Step 8. + if (isMapped) { + unsigned arg = unsigned(JSID_TO_INT(id)); + if (desc.isAccessorDescriptor()) { + if (!argsobj->markElementDeleted(cx, arg)) + return false; + } else { + if (desc.hasValue()) { + RootedFunction callee(cx, &argsobj->callee()); + RootedScript script(cx, callee->getOrCreateScript(cx)); + if (!script) + return false; + argsobj->setElement(cx, arg, desc.value()); + if (arg < script->functionNonDelazifying()->nargs()) + TypeScript::SetArgument(cx, script, arg, desc.value()); + } + if (desc.hasWritable() && !desc.writable()) { + if (!argsobj->markElementDeleted(cx, arg)) + return false; + } + } + } + + // Step 9. + return result.succeed(); +} + static bool UnmappedArgGetter(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp) { @@ -804,6 +862,11 @@ const ClassOps MappedArgumentsObject::classOps_ = { ArgumentsObject::trace }; +const ObjectOps MappedArgumentsObject::objectOps_ = { + nullptr, /* lookupProperty */ + MappedArgumentsObject::obj_defineProperty +}; + const Class MappedArgumentsObject::class_ = { "Arguments", JSCLASS_DELAY_METADATA_BUILDER | @@ -811,7 +874,10 @@ const Class MappedArgumentsObject::class_ = { JSCLASS_HAS_CACHED_PROTO(JSProto_Object) | JSCLASS_SKIP_NURSERY_FINALIZE | JSCLASS_BACKGROUND_FINALIZE, - &MappedArgumentsObject::classOps_ + &MappedArgumentsObject::classOps_, + nullptr, + nullptr, + &MappedArgumentsObject::objectOps_ }; /* diff --git a/js/src/vm/ArgumentsObject.h b/js/src/vm/ArgumentsObject.h index 247c7cd94..988e41951 100644 --- a/js/src/vm/ArgumentsObject.h +++ b/js/src/vm/ArgumentsObject.h @@ -389,6 +389,7 @@ class ArgumentsObject : public NativeObject class MappedArgumentsObject : public ArgumentsObject { static const ClassOps classOps_; + static const ObjectOps objectOps_; public: static const Class class_; @@ -410,6 +411,8 @@ class MappedArgumentsObject : public ArgumentsObject private: static bool obj_enumerate(JSContext* cx, HandleObject obj); static bool obj_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp); + static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id, + Handle desc, ObjectOpResult& result); }; class UnmappedArgumentsObject : public ArgumentsObject -- cgit v1.2.3 From 9476f2e018856139f92e96e8e738bbbab615e67d Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 18:45:02 -0400 Subject: 1175823 - Import test262 mapped arguments tests. --- .../Object/getOwnPropertyDescriptors/shell.js | 27 --------------------- .../mapped/mapped-arguments-nonconfigurable-1.js | 17 +++++++++++++ .../mapped/mapped-arguments-nonconfigurable-2.js | 19 +++++++++++++++ .../mapped/mapped-arguments-nonconfigurable-3.js | 19 +++++++++++++++ .../mapped/mapped-arguments-nonconfigurable-4.js | 19 +++++++++++++++ .../mapped-arguments-nonconfigurable-delete-1.js | 19 +++++++++++++++ .../mapped-arguments-nonconfigurable-delete-2.js | 24 +++++++++++++++++++ .../mapped-arguments-nonconfigurable-delete-3.js | 25 +++++++++++++++++++ .../mapped-arguments-nonconfigurable-delete-4.js | 25 +++++++++++++++++++ ...pped-arguments-nonconfigurable-nonwritable-1.js | 24 +++++++++++++++++++ ...pped-arguments-nonconfigurable-nonwritable-2.js | 25 +++++++++++++++++++ ...pped-arguments-nonconfigurable-nonwritable-3.js | 28 ++++++++++++++++++++++ ...pped-arguments-nonconfigurable-nonwritable-4.js | 25 +++++++++++++++++++ ...pped-arguments-nonconfigurable-nonwritable-5.js | 26 ++++++++++++++++++++ ...ed-arguments-nonconfigurable-strict-delete-1.js | 21 ++++++++++++++++ ...ed-arguments-nonconfigurable-strict-delete-2.js | 26 ++++++++++++++++++++ ...ed-arguments-nonconfigurable-strict-delete-3.js | 27 +++++++++++++++++++++ ...ed-arguments-nonconfigurable-strict-delete-4.js | 26 ++++++++++++++++++++ ...pped-arguments-nonwritable-nonconfigurable-1.js | 25 +++++++++++++++++++ ...pped-arguments-nonwritable-nonconfigurable-2.js | 26 ++++++++++++++++++++ ...pped-arguments-nonwritable-nonconfigurable-3.js | 25 +++++++++++++++++++ ...pped-arguments-nonwritable-nonconfigurable-4.js | 26 ++++++++++++++++++++ .../language/arguments-object/mapped/shell.js | 0 .../test262/language/arguments-object/shell.js | 0 js/src/tests/test262/language/shell.js | 0 js/src/tests/test262/shell.js | 28 ++++++++++++++++++++++ 26 files changed, 525 insertions(+), 27 deletions(-) create mode 100755 js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-1.js create mode 100755 js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-2.js create mode 100755 js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-3.js create mode 100755 js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-4.js create mode 100755 js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-1.js create mode 100755 js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-2.js create mode 100755 js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-3.js create mode 100755 js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-4.js create mode 100755 js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-1.js create mode 100755 js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-2.js create mode 100755 js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-3.js create mode 100755 js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-4.js create mode 100755 js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-5.js create mode 100755 js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-1.js create mode 100755 js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-2.js create mode 100755 js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-3.js create mode 100755 js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-4.js create mode 100755 js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-1.js create mode 100755 js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-2.js create mode 100755 js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-3.js create mode 100755 js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-4.js create mode 100644 js/src/tests/test262/language/arguments-object/mapped/shell.js create mode 100644 js/src/tests/test262/language/arguments-object/shell.js create mode 100644 js/src/tests/test262/language/shell.js (limited to 'js/src') diff --git a/js/src/tests/test262/built-ins/Object/getOwnPropertyDescriptors/shell.js b/js/src/tests/test262/built-ins/Object/getOwnPropertyDescriptors/shell.js index 6ed766e94..e69de29bb 100644 --- a/js/src/tests/test262/built-ins/Object/getOwnPropertyDescriptors/shell.js +++ b/js/src/tests/test262/built-ins/Object/getOwnPropertyDescriptors/shell.js @@ -1,27 +0,0 @@ -var assert = { - sameValue: assertEq, - notSameValue(a, b, msg) { - try { - assertEq(a, b); - throw "equal" - } catch (e) { - if (e === "equal") - throw new Error("Assertion failed: expected different values, got " + a); - } - }, - throws(ctor, f) { - var fullmsg; - try { - f(); - } catch (exc) { - if (exc instanceof ctor) - return; - fullmsg = "Assertion failed: expected exception " + ctor.name + ", got " + exc; - } - if (fullmsg === undefined) - fullmsg = "Assertion failed: expected exception " + ctor.name + ", no exception thrown"; - if (msg !== undefined) - fullmsg += " - " + msg; - throw new Error(fullmsg); - } -} diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-1.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-1.js new file mode 100755 index 000000000..08925e079 --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-1.js @@ -0,0 +1,17 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapped value is not changed when property was made non-configurable. +flags: [noStrict] +---*/ + +function argumentsNonConfigurable(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + + assert.sameValue(a, 1); + assert.sameValue(arguments[0], 1); +} +argumentsNonConfigurable(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-2.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-2.js new file mode 100755 index 000000000..265481e01 --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-2.js @@ -0,0 +1,19 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapping works when property is non-configurable, variable is + changed with SetMutableBinding. +flags: [noStrict] +---*/ + +function argumentsAndSetMutableBinding(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + + a = 2; + assert.sameValue(a, 2); + assert.sameValue(arguments[0], 2); +} +argumentsAndSetMutableBinding(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-3.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-3.js new file mode 100755 index 000000000..6877a0c9d --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-3.js @@ -0,0 +1,19 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapping works when property is non-configurable, arguments property + is changed with [[DefineOwnProperty]]. +flags: [noStrict] +---*/ + +function argumentsAndDefineOwnProperty(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + + Object.defineProperty(arguments, "0", {value: 2}); + assert.sameValue(a, 2); + assert.sameValue(arguments[0], 2); +} +argumentsAndDefineOwnProperty(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-4.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-4.js new file mode 100755 index 000000000..d2ac4d376 --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-4.js @@ -0,0 +1,19 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapping works when property is non-configurable, arguments property + is changed with [[Set]]. +flags: [noStrict] +---*/ + +function argumentsAndSet(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + + arguments[0] = 2; + assert.sameValue(a, 2); + assert.sameValue(arguments[0], 2); +} +argumentsAndSet(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-1.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-1.js new file mode 100755 index 000000000..67f971369 --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-1.js @@ -0,0 +1,19 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapping works when property is non-configurable, arguments property + was not deleted. [[Delete]] operation returns false. +flags: [noStrict] +---*/ + +function argumentsAndDelete(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + + assert.sameValue(delete arguments[0], false); + assert.sameValue(a, 1); + assert.sameValue(arguments[0], 1); +} +argumentsAndDelete(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-2.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-2.js new file mode 100755 index 000000000..9a089eaac --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-2.js @@ -0,0 +1,24 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapping works when property is non-configurable, arguments property + was not deleted. Variable is changed with SetMutableBinding. +flags: [noStrict] +---*/ + +function argumentsAndDeleteSetMutableBinding(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + + // Precondition: Delete is unsuccessful and doesn't affect mapping. + assert.sameValue(delete arguments[0], false); + assert.sameValue(a, 1); + assert.sameValue(arguments[0], 1); + + a = 2; + assert.sameValue(a, 2); + assert.sameValue(arguments[0], 2); +} +argumentsAndDeleteSetMutableBinding(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-3.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-3.js new file mode 100755 index 000000000..26676a4ee --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-3.js @@ -0,0 +1,25 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapping works when property is non-configurable, arguments property + was not deleted. Arguments property is changed with + [[DefineOwnProperty]]. +flags: [noStrict] +---*/ + +function argumentsAndDeleteDefineOwnProperty(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + + // Precondition: Delete is unsuccessful and doesn't affect mapping. + assert.sameValue(delete arguments[0], false); + assert.sameValue(a, 1); + assert.sameValue(arguments[0], 1); + + Object.defineProperty(arguments, "0", {value: 2}); + assert.sameValue(a, 2); + assert.sameValue(arguments[0], 2); +} +argumentsAndDeleteDefineOwnProperty(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-4.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-4.js new file mode 100755 index 000000000..ed96a0e67 --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-4.js @@ -0,0 +1,25 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapping works when property is non-configurable, arguments property + was not deleted. Arguments property is changed with + [[Set]]. +flags: [noStrict] +---*/ + +function argumentsAndDeleteSet(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + + // Precondition: Delete is unsuccessful and doesn't affect mapping. + assert.sameValue(delete arguments[0], false); + assert.sameValue(a, 1); + assert.sameValue(arguments[0], 1); + + arguments[0] = 2; + assert.sameValue(a, 2); + assert.sameValue(arguments[0], 2); +} +argumentsAndDeleteSet(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-1.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-1.js new file mode 100755 index 000000000..cfeba05c4 --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-1.js @@ -0,0 +1,24 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapped arguments property is changed to non-configurable and + non-writable. Perform property attribute changes with a single + [[DefineOwnProperty]] call. Mapped values are unchanged, mapping + itself is removed. +flags: [noStrict] +---*/ + +function argumentsNonConfigurableAndNonWritable(a) { + Object.defineProperty(arguments, "0", {configurable: false, writable: false}); + assert.sameValue(a, 1); + assert.sameValue(arguments[0], 1); + + // Postcondition: Arguments mapping is removed. + a = 2; + assert.sameValue(a, 2); + assert.sameValue(arguments[0], 1); +} +argumentsNonConfigurableAndNonWritable(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-2.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-2.js new file mode 100755 index 000000000..69c0e125b --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-2.js @@ -0,0 +1,25 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapped arguments property is changed to non-configurable and + non-writable. Perform property attribute changes with two + consecutive [[DefineOwnProperty]] calls. Mapped values are + unchanged, mapping itself is removed. +flags: [noStrict] +---*/ + +function argumentsNonConfigurableThenNonWritable(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + Object.defineProperty(arguments, "0", {writable: false}); + assert.sameValue(a, 1); + assert.sameValue(arguments[0], 1); + + // Postcondition: Arguments mapping is removed. + a = 2; + assert.sameValue(a, 2); + assert.sameValue(arguments[0], 1); +} +argumentsNonConfigurableThenNonWritable(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-3.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-3.js new file mode 100755 index 000000000..dca0adcd2 --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-3.js @@ -0,0 +1,28 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapped arguments property is changed to non-configurable and + non-writable. Perform property attribute changes with two + [[DefineOwnProperty]] calls. Add intervening call to + SetMutableBinding. +flags: [noStrict] +---*/ + +function argumentsNonConfigurableThenNonWritableWithInterveningSetMutableBinding(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + a = 2; + Object.defineProperty(arguments, "0", {writable: false}); + assert.sameValue(a, 2); + // `arguments[0] === 1` per ES2015, Rev 38, April 14, 2015 Final Draft. + // Specification bug: https://bugs.ecmascript.org/show_bug.cgi?id=4371 + assert.sameValue(arguments[0], 2); + + // Postcondition: Arguments mapping is removed. + a = 3; + assert.sameValue(a, 3); + assert.sameValue(arguments[0], 2); +} +argumentsNonConfigurableThenNonWritableWithInterveningSetMutableBinding(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-4.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-4.js new file mode 100755 index 000000000..80d56fe1c --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-4.js @@ -0,0 +1,25 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapped arguments property is changed to non-configurable and + non-writable. Perform property attribute changes with two + [[DefineOwnProperty]] calls. Add intervening call to [[Set]]. +flags: [noStrict] +---*/ + +function argumentsNonConfigurableThenNonWritableWithInterveningSet(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + arguments[0] = 2; + Object.defineProperty(arguments, "0", {writable: false}); + assert.sameValue(a, 2); + assert.sameValue(arguments[0], 2); + + // Postcondition: Arguments mapping is removed. + a = 3; + assert.sameValue(a, 3); + assert.sameValue(arguments[0], 2); +} +argumentsNonConfigurableThenNonWritableWithInterveningSet(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-5.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-5.js new file mode 100755 index 000000000..bbb951502 --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-5.js @@ -0,0 +1,26 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapped arguments property is changed to non-configurable and + non-writable. Perform property attribute changes with two + [[DefineOwnProperty]] calls. Add intervening call to + [[DefineOwnProperty]]. +flags: [noStrict] +---*/ + +function argumentsNonConfigurableThenNonWritableWithDefineOwnProperty(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + Object.defineProperty(arguments, "0", {value: 2}); + Object.defineProperty(arguments, "0", {writable: false}); + assert.sameValue(a, 2); + assert.sameValue(arguments[0], 2); + + // Postcondition: Arguments mapping is removed. + a = 3; + assert.sameValue(a, 3); + assert.sameValue(arguments[0], 2); +} +argumentsNonConfigurableThenNonWritableWithDefineOwnProperty(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-1.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-1.js new file mode 100755 index 000000000..b918f75a1 --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-1.js @@ -0,0 +1,21 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapping works when property is non-configurable, arguments property + was not deleted. [[Delete]] operations throws TypeError if called + from strict-mode code. +flags: [noStrict] +---*/ + +function argumentsAndStrictDelete(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + + var args = arguments; + assert.throws(TypeError, function() { "use strict"; delete args[0]; }); + assert.sameValue(a, 1); + assert.sameValue(arguments[0], 1); +} +argumentsAndStrictDelete(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-2.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-2.js new file mode 100755 index 000000000..01afbe4de --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-2.js @@ -0,0 +1,26 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapping works when property is non-configurable, arguments property + was not deleted. [[Delete]] operations throws TypeError if called + from strict-mode code. Variable is changed with SetMutableBinding. +flags: [noStrict] +---*/ + +function argumentsAndStrictDeleteSetMutableBinding(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + + // Precondition: Delete is unsuccessful and doesn't affect mapping. + var args = arguments; + assert.throws(TypeError, function() { "use strict"; delete args[0]; }); + assert.sameValue(a, 1); + assert.sameValue(arguments[0], 1); + + a = 2; + assert.sameValue(a, 2); + assert.sameValue(arguments[0], 2); +} +argumentsAndStrictDeleteSetMutableBinding(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-3.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-3.js new file mode 100755 index 000000000..9aa2a2ed2 --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-3.js @@ -0,0 +1,27 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapping works when property is non-configurable, arguments property + was not deleted. [[Delete]] operations throws TypeError if called + from strict-mode code. Arguments property is changed with + [[DefineOwnProperty]]. +flags: [noStrict] +---*/ + +function argumentsAndStrictDeleteDefineOwnProperty(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + + // Precondition: Delete is unsuccessful and doesn't affect mapping. + var args = arguments; + assert.throws(TypeError, function() { "use strict"; delete args[0]; }); + assert.sameValue(a, 1); + assert.sameValue(arguments[0], 1); + + Object.defineProperty(arguments, "0", {value: 2}); + assert.sameValue(a, 2); + assert.sameValue(arguments[0], 2); +} +argumentsAndStrictDeleteDefineOwnProperty(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-4.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-4.js new file mode 100755 index 000000000..b48018843 --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-4.js @@ -0,0 +1,26 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapping works when property is non-configurable, arguments property + was not deleted. [[Delete]] operations throws TypeError if called + from strict-mode code. Arguments property is changed with [[Set]]. +flags: [noStrict] +---*/ + +function argumentsAndStrictDeleteSet(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + + // Precondition: Delete is unsuccessful and doesn't affect mapping. + var args = arguments; + assert.throws(TypeError, function() { "use strict"; delete args[0]; }); + assert.sameValue(a, 1); + assert.sameValue(arguments[0], 1); + + arguments[0] = 2; + assert.sameValue(a, 2); + assert.sameValue(arguments[0], 2); +} +argumentsAndStrictDeleteSet(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-1.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-1.js new file mode 100755 index 000000000..2dae07678 --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-1.js @@ -0,0 +1,25 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapped arguments property is changed to non-writable and + non-configurable. Perform property attribute changes with two + consecutive [[DefineOwnProperty]] calls. Mapped values are + unchanged, mapping itself is removed. +flags: [noStrict] +---*/ + +function argumentsNonWritableThenNonConfigurable(a) { + Object.defineProperty(arguments, "0", {writable: false}); + Object.defineProperty(arguments, "0", {configurable: false}); + assert.sameValue(a, 1); + assert.sameValue(arguments[0], 1); + + // Postcondition: Arguments mapping is removed. + a = 2; + assert.sameValue(a, 2); + assert.sameValue(arguments[0], 1); +} +argumentsNonWritableThenNonConfigurable(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-2.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-2.js new file mode 100755 index 000000000..63585b437 --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-2.js @@ -0,0 +1,26 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapped arguments property is changed to non-writable and + non-configurable. Perform property attribute changes with two + [[DefineOwnProperty]] calls. Add intervening call to + SetMutableBinding. +flags: [noStrict] +---*/ + +function argumentsNonWritableThenNonConfigurableWithInterveningSetMutableBinding(a) { + Object.defineProperty(arguments, "0", {writable: false}); + a = 2; + Object.defineProperty(arguments, "0", {configurable: false}); + assert.sameValue(a, 2); + assert.sameValue(arguments[0], 1); + + // Postcondition: Arguments mapping is removed. + a = 3; + assert.sameValue(a, 3); + assert.sameValue(arguments[0], 1); +} +argumentsNonWritableThenNonConfigurableWithInterveningSetMutableBinding(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-3.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-3.js new file mode 100755 index 000000000..2bd1bc9c1 --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-3.js @@ -0,0 +1,25 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapped arguments property is changed to non-writable and + non-configurable. Perform property attribute changes with two + [[DefineOwnProperty]] calls. Add intervening call to [[Set]]. +flags: [noStrict] +---*/ + +function argumentsNonWritableThenNonConfigurableWithInterveningSet(a) { + Object.defineProperty(arguments, "0", {writable: false}); + arguments[0] = 2; + Object.defineProperty(arguments, "0", {configurable: false}); + assert.sameValue(a, 1); + assert.sameValue(arguments[0], 1); + + // Postcondition: Arguments mapping is removed. + a = 3; + assert.sameValue(a, 3); + assert.sameValue(arguments[0], 1); +} +argumentsNonWritableThenNonConfigurableWithInterveningSet(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-4.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-4.js new file mode 100755 index 000000000..ea40a49a8 --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-4.js @@ -0,0 +1,26 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapped arguments property is changed to non-writable and + non-configurable. Perform property attribute changes with two + [[DefineOwnProperty]] calls. Add intervening call to + [[DefineOwnProperty]]. +flags: [noStrict] +---*/ + +function argumentsNonWritableThenNonConfigurableWithInterveningDefineOwnProperty(a) { + Object.defineProperty(arguments, "0", {writable: false}); + Object.defineProperty(arguments, "0", {value: 2}); + Object.defineProperty(arguments, "0", {configurable: false}); + assert.sameValue(a, 1); + assert.sameValue(arguments[0], 2); + + // Postcondition: Arguments mapping is removed. + a = 3; + assert.sameValue(a, 3); + assert.sameValue(arguments[0], 2); +} +argumentsNonWritableThenNonConfigurableWithInterveningDefineOwnProperty(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/shell.js b/js/src/tests/test262/language/arguments-object/mapped/shell.js new file mode 100644 index 000000000..e69de29bb diff --git a/js/src/tests/test262/language/arguments-object/shell.js b/js/src/tests/test262/language/arguments-object/shell.js new file mode 100644 index 000000000..e69de29bb diff --git a/js/src/tests/test262/language/shell.js b/js/src/tests/test262/language/shell.js new file mode 100644 index 000000000..e69de29bb diff --git a/js/src/tests/test262/shell.js b/js/src/tests/test262/shell.js index b70bb5dbb..462ec9cf8 100644 --- a/js/src/tests/test262/shell.js +++ b/js/src/tests/test262/shell.js @@ -938,3 +938,31 @@ var fnGlobalObject = (function() var global = Function("return this")(); return function fnGlobalObject() { return global; }; })(); + +var assert = { + sameValue: assertEq, + notSameValue(a, b, msg) { + try { + assertEq(a, b); + throw "equal" + } catch (e) { + if (e === "equal") + throw new Error("Assertion failed: expected different values, got " + a); + } + }, + throws(ctor, f) { + var fullmsg; + try { + f(); + } catch (exc) { + if (exc instanceof ctor) + return; + fullmsg = "Assertion failed: expected exception " + ctor.name + ", got " + exc; + } + if (fullmsg === undefined) + fullmsg = "Assertion failed: expected exception " + ctor.name + ", no exception thrown"; + if (msg !== undefined) + fullmsg += " - " + msg; + throw new Error(fullmsg); + } +} -- cgit v1.2.3 From e5019fd4cf2142b7fe2cbfedaefcea300390393e Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 18:45:53 -0400 Subject: 1320408 - Part 1: Change JSFunction::getLength and JSFunction::getUnresolvedLength to static method. --- js/src/jsfun.cpp | 29 ++++++++++++++--------------- js/src/jsfun.h | 5 +++-- js/src/vm/AsyncFunction.cpp | 2 +- js/src/vm/SelfHosting.cpp | 2 +- 4 files changed, 19 insertions(+), 19 deletions(-) (limited to 'js/src') diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 06d5cced7..18ff875da 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -476,7 +476,7 @@ fun_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp) if (fun->hasResolvedLength()) return true; - if (!fun->getUnresolvedLength(cx, &v)) + if (!JSFunction::getUnresolvedLength(cx, fun, &v)) return false; } else { if (fun->hasResolvedName()) @@ -1242,34 +1242,33 @@ JSFunction::isDerivedClassConstructor() return derived; } -bool -JSFunction::getLength(JSContext* cx, uint16_t* length) +/* static */ bool +JSFunction::getLength(JSContext* cx, HandleFunction fun, uint16_t* length) { - JS::RootedFunction self(cx, this); - MOZ_ASSERT(!self->isBoundFunction()); - if (self->isInterpretedLazy() && !self->getOrCreateScript(cx)) + MOZ_ASSERT(!fun->isBoundFunction()); + if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx)) return false; - *length = self->isNative() ? self->nargs() : self->nonLazyScript()->funLength(); + *length = fun->isNative() ? fun->nargs() : fun->nonLazyScript()->funLength(); return true; } -bool -JSFunction::getUnresolvedLength(JSContext* cx, MutableHandleValue v) +/* static */ bool +JSFunction::getUnresolvedLength(JSContext* cx, HandleFunction fun, MutableHandleValue v) { - MOZ_ASSERT(!IsInternalFunctionObject(*this)); - MOZ_ASSERT(!hasResolvedLength()); + MOZ_ASSERT(!IsInternalFunctionObject(*fun)); + MOZ_ASSERT(!fun->hasResolvedLength()); // Bound functions' length can have values up to MAX_SAFE_INTEGER, so // they're handled differently from other functions. - if (isBoundFunction()) { - MOZ_ASSERT(getExtendedSlot(BOUND_FUN_LENGTH_SLOT).isNumber()); - v.set(getExtendedSlot(BOUND_FUN_LENGTH_SLOT)); + if (fun->isBoundFunction()) { + MOZ_ASSERT(fun->getExtendedSlot(BOUND_FUN_LENGTH_SLOT).isNumber()); + v.set(fun->getExtendedSlot(BOUND_FUN_LENGTH_SLOT)); return true; } uint16_t length; - if (!getLength(cx, &length)) + if (!JSFunction::getLength(cx, fun, &length)) return false; v.setInt32(length); diff --git a/js/src/jsfun.h b/js/src/jsfun.h index b91c69d33..65fe542c4 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -306,7 +306,8 @@ class JSFunction : public js::NativeObject nonLazyScript()->setAsyncKind(asyncKind); } - bool getUnresolvedLength(JSContext* cx, js::MutableHandleValue v); + static bool getUnresolvedLength(JSContext* cx, js::HandleFunction fun, + js::MutableHandleValue v); JSAtom* getUnresolvedName(JSContext* cx); @@ -478,7 +479,7 @@ class JSFunction : public js::NativeObject return u.i.s.script_; } - bool getLength(JSContext* cx, uint16_t* length); + static bool getLength(JSContext* cx, js::HandleFunction fun, uint16_t* length); js::LazyScript* lazyScript() const { MOZ_ASSERT(isInterpretedLazy() && u.i.s.lazy_); diff --git a/js/src/vm/AsyncFunction.cpp b/js/src/vm/AsyncFunction.cpp index f50c87114..e14b77424 100644 --- a/js/src/vm/AsyncFunction.cpp +++ b/js/src/vm/AsyncFunction.cpp @@ -118,7 +118,7 @@ js::WrapAsyncFunctionWithProto(JSContext* cx, HandleFunction unwrapped, HandleOb RootedAtom funName(cx, unwrapped->explicitName()); uint16_t length; - if (!unwrapped->getLength(cx, &length)) + if (!JSFunction::getLength(cx, unwrapped, &length)) return nullptr; // Steps 3 (partially). diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index ccd4cc8d7..dfec47cf2 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -477,7 +477,7 @@ intrinsic_FinishBoundFunctionInit(JSContext* cx, unsigned argc, Value* vp) // Try to avoid invoking the resolve hook. if (targetObj->is() && !targetObj->as().hasResolvedLength()) { RootedValue targetLength(cx); - if (!targetObj->as().getUnresolvedLength(cx, &targetLength)) + if (!JSFunction::getUnresolvedLength(cx, targetObj.as(), &targetLength)) return false; length = Max(0.0, targetLength.toNumber() - argCount); -- cgit v1.2.3 From 739a81958035410ddd9b230354a56c909cc5c816 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 18:54:17 -0400 Subject: 1320408 - Part 2: Change JSFunction::getOrCreateScript to static method. --- js/src/builtin/RegExp.cpp | 2 +- js/src/builtin/TestingFunctions.cpp | 4 ++-- js/src/frontend/BytecodeCompiler.cpp | 3 ++- js/src/jit/IonAnalysis.cpp | 4 ++-- js/src/jit/IonAnalysis.h | 2 +- js/src/jit/IonBuilder.cpp | 3 ++- js/src/jit/VMFunctions.cpp | 2 +- js/src/jsapi-tests/testUbiNode.cpp | 2 +- js/src/jsapi.cpp | 6 +++--- js/src/jsarray.cpp | 4 ++-- js/src/jscompartment.cpp | 8 ++++---- js/src/jsfun.cpp | 4 ++-- js/src/jsfun.h | 13 ++++++------- js/src/jsfuninlines.h | 2 +- js/src/jsobj.cpp | 2 +- js/src/jsopcode.cpp | 7 ++++--- js/src/jsscript.cpp | 4 ++-- js/src/jsscriptinlines.h | 3 ++- js/src/shell/js.cpp | 6 +++--- js/src/vm/ArgumentsObject.cpp | 4 ++-- js/src/vm/Debugger.cpp | 2 +- js/src/vm/EnvironmentObject.cpp | 23 +++++++++++++++-------- js/src/vm/Interpreter-inl.h | 2 +- js/src/vm/Interpreter.cpp | 6 +++--- js/src/vm/ObjectGroup.cpp | 2 +- js/src/vm/SelfHosting.cpp | 2 +- js/src/vm/Stack-inl.h | 2 +- js/src/vm/TypeInference.cpp | 3 ++- 28 files changed, 69 insertions(+), 58 deletions(-) (limited to 'js/src') diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp index d71cee75e..231c58a5d 100644 --- a/js/src/builtin/RegExp.cpp +++ b/js/src/builtin/RegExp.cpp @@ -1725,7 +1725,7 @@ js::intrinsic_GetElemBaseForLambda(JSContext* cx, unsigned argc, Value* vp) if (!fun->isInterpreted() || fun->isClassConstructor()) return true; - JSScript* script = fun->getOrCreateScript(cx); + JSScript* script = JSFunction::getOrCreateScript(cx, fun); if (!script) return false; diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index c896ce5d1..89e3b1793 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -3218,13 +3218,13 @@ ByteSizeOfScript(JSContext*cx, unsigned argc, Value* vp) return false; } - JSFunction* fun = &args[0].toObject().as(); + RootedFunction fun(cx, &args[0].toObject().as()); if (fun->isNative()) { JS_ReportErrorASCII(cx, "Argument must be a scripted function"); return false; } - RootedScript script(cx, fun->getOrCreateScript(cx)); + RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun)); if (!script) return false; diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index b5be5f5ac..a4b7dba6b 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -287,7 +287,8 @@ BytecodeCompiler::deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObj RootedObject env(cx, environment); while (env->is() || env->is()) { if (env->is()) { - RootedScript script(cx, env->as().callee().getOrCreateScript(cx)); + RootedFunction fun(cx, &env->as().callee()); + RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun)); if (!script) return false; if (script->argumentsHasVarBinding()) { diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index 41c71c9c3..90fa1864a 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -4132,7 +4132,7 @@ CmpInstructions(const void* a, const void* b) } bool -jit::AnalyzeNewScriptDefiniteProperties(JSContext* cx, JSFunction* fun, +jit::AnalyzeNewScriptDefiniteProperties(JSContext* cx, HandleFunction fun, ObjectGroup* group, HandlePlainObject baseobj, Vector* initializerList) { @@ -4142,7 +4142,7 @@ jit::AnalyzeNewScriptDefiniteProperties(JSContext* cx, JSFunction* fun, // which will definitely be added to the created object before it has a // chance to escape and be accessed elsewhere. - RootedScript script(cx, fun->getOrCreateScript(cx)); + RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun)); if (!script) return false; diff --git a/js/src/jit/IonAnalysis.h b/js/src/jit/IonAnalysis.h index 1ce8edc80..efd31415b 100644 --- a/js/src/jit/IonAnalysis.h +++ b/js/src/jit/IonAnalysis.h @@ -196,7 +196,7 @@ MCompare* ConvertLinearInequality(TempAllocator& alloc, MBasicBlock* block, const LinearSum& sum); MOZ_MUST_USE bool -AnalyzeNewScriptDefiniteProperties(JSContext* cx, JSFunction* fun, +AnalyzeNewScriptDefiniteProperties(JSContext* cx, HandleFunction fun, ObjectGroup* group, HandlePlainObject baseobj, Vector* initializerList); diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index a54a58add..e98a4056e 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -466,7 +466,8 @@ IonBuilder::canInlineTarget(JSFunction* target, CallInfo& callInfo) // Allow constructing lazy scripts when performing the definite properties // analysis, as baseline has not been used to warm the caller up yet. if (target->isInterpreted() && info().analysisMode() == Analysis_DefiniteProperties) { - RootedScript script(analysisContext, target->getOrCreateScript(analysisContext)); + RootedFunction fun(analysisContext, target); + RootedScript script(analysisContext, JSFunction::getOrCreateScript(analysisContext, fun)); if (!script) return InliningDecision_Error; diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 402d910b9..5bcd36ba0 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -555,7 +555,7 @@ CreateThis(JSContext* cx, HandleObject callee, HandleObject newTarget, MutableHa if (callee->is()) { RootedFunction fun(cx, &callee->as()); if (fun->isInterpreted() && fun->isConstructor()) { - JSScript* script = fun->getOrCreateScript(cx); + JSScript* script = JSFunction::getOrCreateScript(cx, fun); if (!script || !script->ensureHasTypes(cx)) return false; if (fun->isBoundFunction() || script->isDerivedClassConstructor()) { diff --git a/js/src/jsapi-tests/testUbiNode.cpp b/js/src/jsapi-tests/testUbiNode.cpp index 075e777d6..00b1253e7 100644 --- a/js/src/jsapi-tests/testUbiNode.cpp +++ b/js/src/jsapi-tests/testUbiNode.cpp @@ -646,7 +646,7 @@ BEGIN_TEST(test_JS_ubi_Node_scriptFilename) CHECK(obj->is()); JS::RootedFunction func(cx, &obj->as()); - JS::RootedScript script(cx, func->getOrCreateScript(cx)); + JS::RootedScript script(cx, JSFunction::getOrCreateScript(cx, func)); CHECK(script); CHECK(script->filename()); diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index ac7b78581..949e4796b 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -3549,7 +3549,7 @@ CloneFunctionObject(JSContext* cx, HandleObject funobj, HandleObject env, Handle RootedFunction fun(cx, &funobj->as()); if (fun->isInterpretedLazy()) { AutoCompartment ac(cx, funobj); - if (!fun->getOrCreateScript(cx)) + if (!JSFunction::getOrCreateScript(cx, fun)) return nullptr; } @@ -3581,7 +3581,7 @@ CloneFunctionObject(JSContext* cx, HandleObject funobj, HandleObject env, Handle // Fail here if we OOM during debug asserting. // CloneFunctionReuseScript will delazify the script anyways, so we // are not creating an extra failure condition for DEBUG builds. - if (!fun->getOrCreateScript(cx)) + if (!JSFunction::getOrCreateScript(cx, fun)) return nullptr; MOZ_ASSERT(scope->as().isSyntactic() || fun->nonLazyScript()->hasNonSyntacticScope()); @@ -4234,7 +4234,7 @@ JS_GetFunctionScript(JSContext* cx, HandleFunction fun) return nullptr; if (fun->isInterpretedLazy()) { AutoCompartment funCompartment(cx, fun); - JSScript* script = fun->getOrCreateScript(cx); + JSScript* script = JSFunction::getOrCreateScript(cx, fun); if (!script) MOZ_CRASH(); return script; diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index ff581beec..d28f5cb8e 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -1662,11 +1662,11 @@ MatchNumericComparator(JSContext* cx, const Value& v) if (!obj.is()) return Match_None; - JSFunction* fun = &obj.as(); + RootedFunction fun(cx, &obj.as()); if (!fun->isInterpreted() || fun->isClassConstructor()) return Match_None; - JSScript* script = fun->getOrCreateScript(cx); + JSScript* script = JSFunction::getOrCreateScript(cx, fun); if (!script) return Match_Failure; diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index 6024a1768..d0caeb558 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -1075,18 +1075,18 @@ CreateLazyScriptsForCompartment(JSContext* cx) // Create scripts for each lazy function, updating the list of functions to // process with any newly exposed inner functions in created scripts. // A function cannot be delazified until its outer script exists. + RootedFunction fun(cx); for (size_t i = 0; i < lazyFunctions.length(); i++) { - JSFunction* fun = &lazyFunctions[i]->as(); + fun = &lazyFunctions[i]->as(); // lazyFunctions may have been populated with multiple functions for // a lazy script. if (!fun->isInterpretedLazy()) continue; - LazyScript* lazy = fun->lazyScript(); - bool lazyScriptHadNoScript = !lazy->maybeScript(); + bool lazyScriptHadNoScript = !fun->lazyScript()->maybeScript(); - JSScript* script = fun->getOrCreateScript(cx); + JSScript* script = JSFunction::getOrCreateScript(cx, fun); if (!script) return false; if (lazyScriptHadNoScript && !AddInnerLazyFunctionsFromScript(script, lazyFunctions)) diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 18ff875da..41f935080 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -902,7 +902,7 @@ const Class* const js::FunctionClassPtr = &JSFunction::class_; JSString* js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint) { - if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx)) + if (fun->isInterpretedLazy() && !JSFunction::getOrCreateScript(cx, fun)) return nullptr; if (IsAsmJSModule(fun)) @@ -1246,7 +1246,7 @@ JSFunction::isDerivedClassConstructor() JSFunction::getLength(JSContext* cx, HandleFunction fun, uint16_t* length) { MOZ_ASSERT(!fun->isBoundFunction()); - if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx)) + if (fun->isInterpretedLazy() && !getOrCreateScript(cx, fun)) return false; *length = fun->isNative() ? fun->nargs() : fun->nonLazyScript()->funLength(); diff --git a/js/src/jsfun.h b/js/src/jsfun.h index 65fe542c4..781ca6223 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -412,16 +412,15 @@ class JSFunction : public js::NativeObject // // - For functions known to have a JSScript, nonLazyScript() will get it. - JSScript* getOrCreateScript(JSContext* cx) { - MOZ_ASSERT(isInterpreted()); + static JSScript* getOrCreateScript(JSContext* cx, js::HandleFunction fun) { + MOZ_ASSERT(fun->isInterpreted()); MOZ_ASSERT(cx); - if (isInterpretedLazy()) { - JS::RootedFunction self(cx, this); - if (!createScriptForLazilyInterpretedFunction(cx, self)) + if (fun->isInterpretedLazy()) { + if (!createScriptForLazilyInterpretedFunction(cx, fun)) return nullptr; - return self->nonLazyScript(); + return fun->nonLazyScript(); } - return nonLazyScript(); + return fun->nonLazyScript(); } JSScript* existingScriptNonDelazifying() const { diff --git a/js/src/jsfuninlines.h b/js/src/jsfuninlines.h index e134def61..13fe51e26 100644 --- a/js/src/jsfuninlines.h +++ b/js/src/jsfuninlines.h @@ -88,7 +88,7 @@ CloneFunctionObjectIfNotSingleton(JSContext* cx, HandleFunction fun, HandleObjec if (CanReuseScriptForClone(cx->compartment(), fun, parent)) return CloneFunctionReuseScript(cx, fun, parent, kind, newKind, proto); - RootedScript script(cx, fun->getOrCreateScript(cx)); + RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun)); if (!script) return nullptr; RootedScope enclosingScope(cx, script->enclosingScope()); diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index bea01daf4..afaf24abd 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -952,7 +952,7 @@ js::CreateThisForFunctionWithProto(JSContext* cx, HandleObject callee, HandleObj } if (res) { - JSScript* script = callee->as().getOrCreateScript(cx); + JSScript* script = JSFunction::getOrCreateScript(cx, callee.as()); if (!script) return nullptr; TypeScript::SetThis(cx, script, TypeSet::ObjectType(res)); diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index 6adb5401e..b6897908b 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -2214,6 +2214,7 @@ GenerateLcovInfo(JSContext* cx, JSCompartment* comp, GenericPrinter& out) return false; RootedScript script(cx); + RootedFunction fun(cx); do { script = queue.popCopy(); compCover.collectCodeCoverageInfo(comp, script->sourceObject(), script); @@ -2231,15 +2232,15 @@ GenerateLcovInfo(JSContext* cx, JSCompartment* comp, GenericPrinter& out) // Only continue on JSFunction objects. if (!obj->is()) continue; - JSFunction& fun = obj->as(); + fun = &obj->as(); // Let's skip wasm for now. - if (!fun.isInterpreted()) + if (!fun->isInterpreted()) continue; // Queue the script in the list of script associated to the // current source. - JSScript* childScript = fun.getOrCreateScript(cx); + JSScript* childScript = JSFunction::getOrCreateScript(cx, fun); if (!childScript || !queue.append(childScript)) return false; } diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 899820a0d..28fb3636c 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -3268,7 +3268,7 @@ js::detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst, } else { if (innerFun->isInterpretedLazy()) { AutoCompartment ac(cx, innerFun); - if (!innerFun->getOrCreateScript(cx)) + if (!JSFunction::getOrCreateScript(cx, innerFun)) return false; } @@ -4296,7 +4296,7 @@ JSScript::AutoDelazify::holdScript(JS::HandleFunction fun) script_ = fun->nonLazyScript(); } else { JSAutoCompartment ac(cx_, fun); - script_ = fun->getOrCreateScript(cx_); + script_ = JSFunction::getOrCreateScript(cx_, fun); if (script_) { oldDoNotRelazify_ = script_->doNotRelazify_; script_->setDoNotRelazify(true); diff --git a/js/src/jsscriptinlines.h b/js/src/jsscriptinlines.h index da23804ac..65abb5cb7 100644 --- a/js/src/jsscriptinlines.h +++ b/js/src/jsscriptinlines.h @@ -78,7 +78,8 @@ inline JSFunction* LazyScript::functionDelazifying(JSContext* cx) const { Rooted self(cx, this); - if (self->function_ && !self->function_->getOrCreateScript(cx)) + RootedFunction fun(cx, self->function_); + if (self->function_ && !JSFunction::getOrCreateScript(cx, fun)) return nullptr; return self->function_; } diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index f6a13623c..f8b10285a 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -2310,7 +2310,7 @@ ValueToScript(JSContext* cx, HandleValue v, JSFunction** funp = nullptr) return nullptr; } - JSScript* script = fun->getOrCreateScript(cx); + JSScript* script = JSFunction::getOrCreateScript(cx, fun); if (!script) return nullptr; @@ -2726,7 +2726,7 @@ DisassembleScript(JSContext* cx, HandleScript script, HandleFunction fun, RootedFunction fun(cx, &obj->as()); if (fun->isInterpreted()) { - RootedScript script(cx, fun->getOrCreateScript(cx)); + RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun)); if (script) { if (!DisassembleScript(cx, script, fun, lines, recursive, sourceNotes, sp)) return false; @@ -5403,7 +5403,7 @@ DumpScopeChain(JSContext* cx, unsigned argc, Value* vp) ReportUsageErrorASCII(cx, callee, "Argument must be an interpreted function"); return false; } - script = fun->getOrCreateScript(cx); + script = JSFunction::getOrCreateScript(cx, fun); } else { script = obj->as().script(); } diff --git a/js/src/vm/ArgumentsObject.cpp b/js/src/vm/ArgumentsObject.cpp index f9a939e6e..73a9c1ac4 100644 --- a/js/src/vm/ArgumentsObject.cpp +++ b/js/src/vm/ArgumentsObject.cpp @@ -475,7 +475,7 @@ MappedArgSetter(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue attrs &= (JSPROP_ENUMERATE | JSPROP_PERMANENT); /* only valid attributes */ RootedFunction callee(cx, &argsobj->callee()); - RootedScript script(cx, callee->getOrCreateScript(cx)); + RootedScript script(cx, JSFunction::getOrCreateScript(cx, callee)); if (!script) return false; @@ -630,7 +630,7 @@ MappedArgumentsObject::obj_defineProperty(JSContext* cx, HandleObject obj, Handl } else { if (desc.hasValue()) { RootedFunction callee(cx, &argsobj->callee()); - RootedScript script(cx, callee->getOrCreateScript(cx)); + RootedScript script(cx, JSFunction::getOrCreateScript(cx, callee)); if (!script) return false; argsobj->setElement(cx, arg, desc.value()); diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index d16781326..988ae413b 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -224,7 +224,7 @@ EnsureFunctionHasScript(JSContext* cx, HandleFunction fun) { if (fun->isInterpretedLazy()) { AutoCompartment ac(cx, fun); - return !!fun->getOrCreateScript(cx); + return !!JSFunction::getOrCreateScript(cx, fun); } return true; } diff --git a/js/src/vm/EnvironmentObject.cpp b/js/src/vm/EnvironmentObject.cpp index 34c39eabf..3125aa41c 100644 --- a/js/src/vm/EnvironmentObject.cpp +++ b/js/src/vm/EnvironmentObject.cpp @@ -1425,7 +1425,8 @@ class DebugEnvironmentProxyHandler : public BaseProxyHandler /* Handle unaliased formals, vars, lets, and consts at function scope. */ if (env->is()) { CallObject& callobj = env->as(); - RootedScript script(cx, callobj.callee().getOrCreateScript(cx)); + RootedFunction fun(cx, &callobj.callee()); + RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun)); if (!script->ensureHasTypes(cx) || !script->ensureHasAnalyzedArgsUsage(cx)) return false; @@ -2960,7 +2961,7 @@ js::GetDebugEnvironmentForFunction(JSContext* cx, HandleFunction fun) MOZ_ASSERT(CanUseDebugEnvironmentMaps(cx)); if (!DebugEnvironments::updateLiveEnvironments(cx)) return nullptr; - JSScript* script = fun->getOrCreateScript(cx); + JSScript* script = JSFunction::getOrCreateScript(cx, fun); if (!script) return nullptr; EnvironmentIter ei(cx, fun->environment(), script->enclosingScope()); @@ -3468,11 +3469,13 @@ RemoveReferencedNames(JSContext* cx, HandleScript script, PropertyNameSet& remai if (script->hasObjects()) { ObjectArray* objects = script->objects(); + RootedFunction fun(cx); + RootedScript innerScript(cx); for (size_t i = 0; i < objects->length; i++) { JSObject* obj = objects->vector[i]; if (obj->is() && obj->as().isInterpreted()) { - JSFunction* fun = &obj->as(); - RootedScript innerScript(cx, fun->getOrCreateScript(cx)); + fun = &obj->as(); + innerScript = JSFunction::getOrCreateScript(cx, fun); if (!innerScript) return false; @@ -3535,11 +3538,13 @@ AnalyzeEntrainedVariablesInScript(JSContext* cx, HandleScript script, HandleScri if (innerScript->hasObjects()) { ObjectArray* objects = innerScript->objects(); + RootedFunction fun(cx); + RootedScript innerInnerScript(cx); for (size_t i = 0; i < objects->length; i++) { JSObject* obj = objects->vector[i]; if (obj->is() && obj->as().isInterpreted()) { - JSFunction* fun = &obj->as(); - RootedScript innerInnerScript(cx, fun->getOrCreateScript(cx)); + fun = &obj->as(); + innerInnerScript = JSFunction::getOrCreateScript(cx, fun); if (!innerInnerScript || !AnalyzeEntrainedVariablesInScript(cx, script, innerInnerScript)) { @@ -3570,11 +3575,13 @@ js::AnalyzeEntrainedVariables(JSContext* cx, HandleScript script) return true; ObjectArray* objects = script->objects(); + RootedFunction fun(cx); + RootedScript innerScript(cx); for (size_t i = 0; i < objects->length; i++) { JSObject* obj = objects->vector[i]; if (obj->is() && obj->as().isInterpreted()) { - JSFunction* fun = &obj->as(); - RootedScript innerScript(cx, fun->getOrCreateScript(cx)); + fun = &obj->as(); + innerScript = JSFunction::getOrCreateScript(cx, fun); if (!innerScript) return false; diff --git a/js/src/vm/Interpreter-inl.h b/js/src/vm/Interpreter-inl.h index a2c8e220a..acfa8f74b 100644 --- a/js/src/vm/Interpreter-inl.h +++ b/js/src/vm/Interpreter-inl.h @@ -830,7 +830,7 @@ class FastCallGuard if (useIon_ && fun_) { if (!script_) { - script_ = fun_->getOrCreateScript(cx); + script_ = JSFunction::getOrCreateScript(cx, fun_); if (!script_) return false; } diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 0f83c3435..35ab2ff26 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -446,7 +446,7 @@ js::InternalCallOrConstruct(JSContext* cx, const CallArgs& args, MaybeConstruct } /* Invoke native functions. */ - JSFunction* fun = &args.callee().as(); + RootedFunction fun(cx, &args.callee().as()); if (construct != CONSTRUCT && fun->isClassConstructor()) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_CALL_CLASS_CONSTRUCTOR); return false; @@ -457,7 +457,7 @@ js::InternalCallOrConstruct(JSContext* cx, const CallArgs& args, MaybeConstruct return CallJSNative(cx, fun->native(), args); } - if (!fun->getOrCreateScript(cx)) + if (!JSFunction::getOrCreateScript(cx, fun)) return false; /* Run function until JSOP_RETRVAL, JSOP_RETURN or error. */ @@ -3000,7 +3000,7 @@ CASE(JSOP_FUNCALL) { MOZ_ASSERT(maybeFun); ReservedRooted fun(&rootFunction0, maybeFun); - ReservedRooted funScript(&rootScript0, fun->getOrCreateScript(cx)); + ReservedRooted funScript(&rootScript0, JSFunction::getOrCreateScript(cx, fun)); if (!funScript) goto error; diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp index 676792379..f3e748a1d 100644 --- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -307,7 +307,7 @@ JSObject::makeLazyGroup(JSContext* cx, HandleObject obj) /* De-lazification of functions can GC, so we need to do it up here. */ if (obj->is() && obj->as().isInterpretedLazy()) { RootedFunction fun(cx, &obj->as()); - if (!fun->getOrCreateScript(cx)) + if (!JSFunction::getOrCreateScript(cx, fun)) return nullptr; } diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index dfec47cf2..2ff20cfea 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -3008,7 +3008,7 @@ JSRuntime::cloneSelfHostedFunctionScript(JSContext* cx, HandlePropertyName name, MOZ_ASSERT(targetFun->isInterpretedLazy()); MOZ_ASSERT(targetFun->isSelfHostedBuiltin()); - RootedScript sourceScript(cx, sourceFun->getOrCreateScript(cx)); + RootedScript sourceScript(cx, JSFunction::getOrCreateScript(cx, sourceFun)); if (!sourceScript) return false; diff --git a/js/src/vm/Stack-inl.h b/js/src/vm/Stack-inl.h index a51c0aa14..9adea9af5 100644 --- a/js/src/vm/Stack-inl.h +++ b/js/src/vm/Stack-inl.h @@ -336,7 +336,7 @@ InterpreterStack::resumeGeneratorCallFrame(JSContext* cx, InterpreterRegs& regs, HandleObject envChain) { MOZ_ASSERT(callee->isGenerator()); - RootedScript script(cx, callee->getOrCreateScript(cx)); + RootedScript script(cx, JSFunction::getOrCreateScript(cx, callee)); InterpreterFrame* prev = regs.fp(); jsbytecode* prevpc = regs.pc; Value* prevsp = regs.sp; diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index ba809fc4e..63daec36e 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -3712,7 +3712,8 @@ TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate, Vector initializerVector(cx); RootedPlainObject templateRoot(cx, templateObject()); - if (!jit::AnalyzeNewScriptDefiniteProperties(cx, function(), group, templateRoot, &initializerVector)) + RootedFunction fun(cx, function()); + if (!jit::AnalyzeNewScriptDefiniteProperties(cx, fun, group, templateRoot, &initializerVector)) return false; if (!group->newScript()) -- cgit v1.2.3 From c2b1e70b763660da2a41a826b4049360090ff373 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 19:05:28 -0400 Subject: 1320408 - Part 3: Remove JSContext* parameter from JSFunction::getBoundFunctionArgument. --- js/src/jsfun.cpp | 6 ++---- js/src/jsfun.h | 2 +- js/src/vm/Debugger.cpp | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) (limited to 'js/src') diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 41f935080..f032b822f 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -1325,13 +1325,11 @@ GetBoundFunctionArguments(const JSFunction* boundFun) } const js::Value& -JSFunction::getBoundFunctionArgument(JSContext* cx, unsigned which) const +JSFunction::getBoundFunctionArgument(unsigned which) const { MOZ_ASSERT(which < getBoundFunctionArgumentCount()); - RootedArrayObject boundArgs(cx, GetBoundFunctionArguments(this)); - RootedValue res(cx); - return boundArgs->getDenseElement(which); + return GetBoundFunctionArguments(this)->getDenseElement(which); } size_t diff --git a/js/src/jsfun.h b/js/src/jsfun.h index 781ca6223..f3643f1e6 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -591,7 +591,7 @@ class JSFunction : public js::NativeObject JSObject* getBoundFunctionTarget() const; const js::Value& getBoundFunctionThis() const; - const js::Value& getBoundFunctionArgument(JSContext* cx, unsigned which) const; + const js::Value& getBoundFunctionArgument(unsigned which) const; size_t getBoundFunctionArgumentCount() const; private: diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 988ae413b..5cc054308 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -9611,7 +9611,7 @@ DebuggerObject::getBoundArguments(JSContext* cx, HandleDebuggerObject object, if (!result.resize(length)) return false; for (size_t i = 0; i < length; i++) { - result[i].set(referent->getBoundFunctionArgument(cx, i)); + result[i].set(referent->getBoundFunctionArgument(i)); if (!dbg->wrapDebuggeeValue(cx, result[i])) return false; } -- cgit v1.2.3 From af6768fb1f2e44b0bfe4136c79d8031028d073b1 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 19:20:00 -0400 Subject: 1320408 - Part 4: Change JSObject::getGroup to static method. --- js/src/jit/BaselineIC.cpp | 23 ++++++++++++++--------- js/src/jit/BaselineIC.h | 2 +- js/src/jit/IonCaches.cpp | 2 +- js/src/jsarray.cpp | 16 ++++++++-------- js/src/jsarray.h | 4 ++-- js/src/jsfun.cpp | 2 +- js/src/jsobj.cpp | 7 ++++--- js/src/jsobj.h | 2 +- js/src/jsobjinlines.h | 15 +++++++-------- js/src/shell/js.cpp | 4 ++-- js/src/vm/ArrayBufferObject.cpp | 2 +- js/src/vm/Interpreter.cpp | 3 ++- js/src/vm/ObjectGroup.cpp | 5 +++-- js/src/vm/TypeInference.cpp | 14 +++++++++----- 14 files changed, 56 insertions(+), 45 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 2f20ffa4f..506cbf1d2 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -2253,14 +2253,20 @@ DenseOrUnboxedArraySetElemStubExists(JSContext* cx, ICStub::Kind kind, for (ICStubConstIterator iter = stub->beginChainConst(); !iter.atEnd(); iter++) { if (kind == ICStub::SetElem_DenseOrUnboxedArray && iter->isSetElem_DenseOrUnboxedArray()) { ICSetElem_DenseOrUnboxedArray* nstub = iter->toSetElem_DenseOrUnboxedArray(); - if (obj->maybeShape() == nstub->shape() && obj->getGroup(cx) == nstub->group()) + if (obj->maybeShape() == nstub->shape() && + JSObject::getGroup(cx, obj) == nstub->group()) + { return true; + } } if (kind == ICStub::SetElem_DenseOrUnboxedArrayAdd && iter->isSetElem_DenseOrUnboxedArrayAdd()) { ICSetElem_DenseOrUnboxedArrayAdd* nstub = iter->toSetElem_DenseOrUnboxedArrayAdd(); - if (obj->getGroup(cx) == nstub->group() && SetElemAddHasSameShapes(nstub, obj)) + if (JSObject::getGroup(cx, obj) == nstub->group() && + SetElemAddHasSameShapes(nstub, obj)) + { return true; + } } } return false; @@ -2446,7 +2452,7 @@ DoSetElemFallback(JSContext* cx, BaselineFrame* frame, ICSetElem_Fallback* stub_ &addingCase, &protoDepth)) { RootedShape shape(cx, obj->maybeShape()); - RootedObjectGroup group(cx, obj->getGroup(cx)); + RootedObjectGroup group(cx, JSObject::getGroup(cx, obj)); if (!group) return false; @@ -4277,7 +4283,7 @@ DoSetPropFallback(JSContext* cx, BaselineFrame* frame, ICSetProp_Fallback* stub_ if (!obj) return false; RootedShape oldShape(cx, obj->maybeShape()); - RootedObjectGroup oldGroup(cx, obj->getGroup(cx)); + RootedObjectGroup oldGroup(cx, JSObject::getGroup(cx, obj)); if (!oldGroup) return false; RootedReceiverGuard oldGuard(cx, ReceiverGuard(obj)); @@ -5175,14 +5181,13 @@ GetTemplateObjectForNative(JSContext* cx, HandleFunction target, const CallArgs& if (native == js::array_slice) { if (args.thisv().isObject()) { - JSObject* obj = &args.thisv().toObject(); + RootedObject obj(cx, &args.thisv().toObject()); if (!obj->isSingleton()) { if (obj->group()->maybePreliminaryObjects()) { *skipAttach = true; return true; } - res.set(NewFullyAllocatedArrayTryReuseGroup(cx, &args.thisv().toObject(), 0, - TenuredObject)); + res.set(NewFullyAllocatedArrayTryReuseGroup(cx, obj, 0, TenuredObject)); return !!res; } } @@ -7961,7 +7966,7 @@ ICUpdatedStub* ICSetElemDenseOrUnboxedArrayAddCompiler::getStubSpecific(ICStubSpace* space, Handle shapes) { - RootedObjectGroup group(cx, obj_->getGroup(cx)); + RootedObjectGroup group(cx, JSObject::getGroup(cx, obj_)); if (!group) return nullptr; Rooted stubCode(cx, getStubCode()); @@ -8098,7 +8103,7 @@ ICSetProp_Native::ICSetProp_Native(JitCode* stubCode, ObjectGroup* group, Shape* ICSetProp_Native* ICSetProp_Native::Compiler::getStub(ICStubSpace* space) { - RootedObjectGroup group(cx, obj_->getGroup(cx)); + RootedObjectGroup group(cx, JSObject::getGroup(cx, obj_)); if (!group) return nullptr; diff --git a/js/src/jit/BaselineIC.h b/js/src/jit/BaselineIC.h index 98f0e1c59..9941cc93d 100644 --- a/js/src/jit/BaselineIC.h +++ b/js/src/jit/BaselineIC.h @@ -1940,7 +1940,7 @@ class ICSetPropNativeAddCompiler : public ICStubCompiler template ICUpdatedStub* getStubSpecific(ICStubSpace* space, Handle shapes) { - RootedObjectGroup newGroup(cx, obj_->getGroup(cx)); + RootedObjectGroup newGroup(cx, JSObject::getGroup(cx, obj_)); if (!newGroup) return nullptr; diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index 9901bdd07..48e0792bb 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -3316,7 +3316,7 @@ SetPropertyIC::update(JSContext* cx, HandleScript outerScript, size_t cacheIndex RootedObjectGroup oldGroup(cx); RootedShape oldShape(cx); if (cache.canAttachStub()) { - oldGroup = obj->getGroup(cx); + oldGroup = JSObject::getGroup(cx, obj); if (!oldGroup) return false; diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index d28f5cb8e..c1a6dcfab 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -602,7 +602,7 @@ js::ArraySetLength(JSContext* cx, Handle arr, HandleId id, // for..in iteration over the array. Keys deleted before being reached // during the iteration must not be visited, and suppressing them here // would be too costly. - ObjectGroup* arrGroup = arr->getGroup(cx); + ObjectGroup* arrGroup = JSObject::getGroup(cx, arr); if (MOZ_UNLIKELY(!arrGroup)) return false; if (!arr->isIndexed() && !MOZ_UNLIKELY(arrGroup->hasAllFlags(OBJECT_FLAG_ITERATED))) { @@ -1285,7 +1285,7 @@ InitArrayElements(JSContext* cx, HandleObject obj, uint32_t start, if (count == 0) return true; - ObjectGroup* group = obj->getGroup(cx); + ObjectGroup* group = JSObject::getGroup(cx, obj); if (!group) return false; @@ -2144,7 +2144,7 @@ ArrayShiftDenseKernel(JSContext* cx, HandleObject obj, MutableHandleValue rval) if (ObjectMayHaveExtraIndexedProperties(obj)) return DenseElementResult::Incomplete; - RootedObjectGroup group(cx, obj->getGroup(cx)); + RootedObjectGroup group(cx, JSObject::getGroup(cx, obj)); if (MOZ_UNLIKELY(!group)) return DenseElementResult::Failure; @@ -2340,7 +2340,7 @@ CanOptimizeForDenseStorage(HandleObject arr, uint32_t startingIndex, uint32_t co * deleted if a hole is moved from one location to another location not yet * visited. See bug 690622. */ - ObjectGroup* arrGroup = arr->getGroup(cx); + ObjectGroup* arrGroup = JSObject::getGroup(cx, arr); if (!arrGroup) { cx->recoverFromOutOfMemory(); return false; @@ -3586,7 +3586,7 @@ js::NewPartlyAllocatedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup g // will have unknown property types. template static inline ArrayObject* -NewArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length, +NewArrayTryReuseGroup(JSContext* cx, HandleObject obj, size_t length, NewObjectKind newKind = GenericObject) { if (!obj->is()) @@ -3595,7 +3595,7 @@ NewArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length, if (obj->staticPrototype() != cx->global()->maybeGetArrayPrototype()) return NewArray(cx, length, nullptr, newKind); - RootedObjectGroup group(cx, obj->getGroup(cx)); + RootedObjectGroup group(cx, JSObject::getGroup(cx, obj)); if (!group) return nullptr; @@ -3603,14 +3603,14 @@ NewArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length, } ArrayObject* -js::NewFullyAllocatedArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length, +js::NewFullyAllocatedArrayTryReuseGroup(JSContext* cx, HandleObject obj, size_t length, NewObjectKind newKind) { return NewArrayTryReuseGroup(cx, obj, length, newKind); } ArrayObject* -js::NewPartlyAllocatedArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length) +js::NewPartlyAllocatedArrayTryReuseGroup(JSContext* cx, HandleObject obj, size_t length) { return NewArrayTryReuseGroup(cx, obj, length); } diff --git a/js/src/jsarray.h b/js/src/jsarray.h index ec2e4f514..00b475a8e 100644 --- a/js/src/jsarray.h +++ b/js/src/jsarray.h @@ -83,11 +83,11 @@ extern ArrayObject* NewPartlyAllocatedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length); extern ArrayObject* -NewFullyAllocatedArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length, +NewFullyAllocatedArrayTryReuseGroup(JSContext* cx, HandleObject obj, size_t length, NewObjectKind newKind = GenericObject); extern ArrayObject* -NewPartlyAllocatedArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length); +NewPartlyAllocatedArrayTryReuseGroup(JSContext* cx, HandleObject obj, size_t length); extern ArrayObject* NewFullyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length, diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index f032b822f..5a253217b 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -826,7 +826,7 @@ CreateFunctionPrototype(JSContext* cx, JSProtoKey key) return nullptr; functionProto->initScript(script); - ObjectGroup* protoGroup = functionProto->getGroup(cx); + ObjectGroup* protoGroup = JSObject::getGroup(cx, functionProto); if (!protoGroup) return nullptr; diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index afaf24abd..0c7c9bc32 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -1489,9 +1489,9 @@ JSObject::swap(JSContext* cx, HandleObject a, HandleObject b) AutoCompartment ac(cx, a); - if (!a->getGroup(cx)) + if (!JSObject::getGroup(cx, a)) oomUnsafe.crash("JSObject::swap"); - if (!b->getGroup(cx)) + if (!JSObject::getGroup(cx, b)) oomUnsafe.crash("JSObject::swap"); /* @@ -3852,7 +3852,8 @@ displayAtomFromObjectGroup(ObjectGroup& group) bool JSObject::constructorDisplayAtom(JSContext* cx, js::MutableHandleAtom name) { - ObjectGroup *g = getGroup(cx); + RootedObject self(cx, this); // Temporary change. + ObjectGroup *g = JSObject::getGroup(cx, self); if (!g) return false; diff --git a/js/src/jsobj.h b/js/src/jsobj.h index af79131af..aa4070556 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -348,7 +348,7 @@ class JSObject : public js::gc::Cell // Change an existing object to have a singleton group. static bool changeToSingleton(JSContext* cx, js::HandleObject obj); - inline js::ObjectGroup* getGroup(JSContext* cx); + static inline js::ObjectGroup* getGroup(JSContext* cx, js::HandleObject obj); const js::GCPtrObjectGroup& groupFromGC() const { /* Direct field access for use by GC. */ diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 7028310ce..c132ee6b2 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -117,17 +117,16 @@ JSObject::setSingleton(js::ExclusiveContext* cx, js::HandleObject obj) return true; } -inline js::ObjectGroup* -JSObject::getGroup(JSContext* cx) +/* static */ inline js::ObjectGroup* +JSObject::getGroup(JSContext* cx, js::HandleObject obj) { - MOZ_ASSERT(cx->compartment() == compartment()); - if (hasLazyGroup()) { - JS::RootedObject self(cx, this); - if (cx->compartment() != compartment()) + MOZ_ASSERT(cx->compartment() == obj->compartment()); + if (obj->hasLazyGroup()) { + if (cx->compartment() != obj->compartment()) MOZ_CRASH(); - return makeLazyGroup(cx, self); + return makeLazyGroup(cx, obj); } - return group_; + return obj->group_; } inline void diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index f8b10285a..19bb6b84a 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -3488,8 +3488,8 @@ GroupOf(JSContext* cx, unsigned argc, JS::Value* vp) JS_ReportErrorASCII(cx, "groupOf: object expected"); return false; } - JSObject* obj = &args[0].toObject(); - ObjectGroup* group = obj->getGroup(cx); + RootedObject obj(cx, &args[0].toObject()); + ObjectGroup* group = JSObject::getGroup(cx, obj); if (!group) return false; args.rval().set(JS_NumberValue(double(uintptr_t(group) >> 3))); diff --git a/js/src/vm/ArrayBufferObject.cpp b/js/src/vm/ArrayBufferObject.cpp index 1053fa99d..2c5e2dd25 100644 --- a/js/src/vm/ArrayBufferObject.cpp +++ b/js/src/vm/ArrayBufferObject.cpp @@ -344,7 +344,7 @@ ArrayBufferObject::detach(JSContext* cx, Handle buffer, // Make sure the global object's group has been instantiated, so the // flag change will be observed. AutoEnterOOMUnsafeRegion oomUnsafe; - if (!cx->global()->getGroup(cx)) + if (!JSObject::getGroup(cx, cx->global())) oomUnsafe.crash("ArrayBufferObject::detach"); MarkObjectGroupFlags(cx, cx->global(), OBJECT_FLAG_TYPED_OBJECT_HAS_DETACHED_BUFFER); cx->compartment()->detachedTypedObjects = 1; diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 35ab2ff26..77637aab8 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -4725,7 +4725,8 @@ js::RunOnceScriptPrologue(JSContext* cx, HandleScript script) // Force instantiation of the script's function's group to ensure the flag // is preserved in type information. - if (!script->functionNonDelazifying()->getGroup(cx)) + RootedFunction fun(cx, script->functionNonDelazifying()); + if (!JSObject::getGroup(cx, fun)) return false; MarkObjectGroupFlags(cx, script->functionNonDelazifying(), OBJECT_FLAG_RUNONCE_INVALIDATED); diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp index f3e748a1d..6e9000894 100644 --- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -283,12 +283,13 @@ JSObject::splicePrototype(JSContext* cx, const Class* clasp, Handle return false; // Force type instantiation when splicing lazy group. - RootedObjectGroup group(cx, self->getGroup(cx)); + RootedObjectGroup group(cx, JSObject::getGroup(cx, self)); if (!group) return false; RootedObjectGroup protoGroup(cx, nullptr); if (proto.isObject()) { - protoGroup = proto.toObject()->getGroup(cx); + RootedObject protoObj(cx, proto.toObject()); + protoGroup = JSObject::getGroup(cx, protoObj); if (!protoGroup) return false; } diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index 63daec36e..60d9e183a 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -1319,7 +1319,8 @@ js::EnsureTrackPropertyTypes(JSContext* cx, JSObject* obj, jsid id) AutoEnterAnalysis enter(cx); if (obj->hasLazyGroup()) { AutoEnterOOMUnsafeRegion oomUnsafe; - if (!obj->getGroup(cx)) { + RootedObject objRoot(cx, obj); + if (!JSObject::getGroup(cx, objRoot)) { oomUnsafe.crash("Could not allocate ObjectGroup in EnsureTrackPropertyTypes"); return; } @@ -1338,9 +1339,12 @@ HeapTypeSetKey::instantiate(JSContext* cx) { if (maybeTypes()) return true; - if (object()->isSingleton() && !object()->singleton()->getGroup(cx)) { - cx->clearPendingException(); - return false; + if (object()->isSingleton()) { + RootedObject obj(cx, object()->singleton()); + if (!JSObject::getGroup(cx, obj)) { + cx->clearPendingException(); + return false; + } } JSObject* obj = object()->isSingleton() ? object()->singleton() : nullptr; maybeTypes_ = object()->maybeGroup()->getProperty(cx, obj, id()); @@ -3088,7 +3092,7 @@ js::AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx, ObjectGroup* gr */ RootedObject proto(cx, group->proto().toObjectOrNull()); while (proto) { - ObjectGroup* protoGroup = proto->getGroup(cx); + ObjectGroup* protoGroup = JSObject::getGroup(cx, proto); if (!protoGroup) { cx->recoverFromOutOfMemory(); return false; -- cgit v1.2.3 From 2d1d2cefbbaff4b0380bfbcdab4631a1dcf142af Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 19:23:13 -0400 Subject: 1320408 - Part 5: Change JSObject::constructorDisplayAtom to static method. --- js/src/builtin/TestingFunctions.cpp | 3 ++- js/src/jsobj.cpp | 7 +++---- js/src/jsobj.h | 3 ++- js/src/vm/Debugger.cpp | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) (limited to 'js/src') diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 89e3b1793..f9e4674c8 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -3319,7 +3319,8 @@ GetConstructorName(JSContext* cx, unsigned argc, Value* vp) } RootedAtom name(cx); - if (!args[0].toObject().constructorDisplayAtom(cx, &name)) + RootedObject obj(cx, &args[0].toObject()); + if (!JSObject::constructorDisplayAtom(cx, obj, &name)) return false; if (name) { diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 0c7c9bc32..ce2f9a614 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -3849,11 +3849,10 @@ displayAtomFromObjectGroup(ObjectGroup& group) return script->function()->displayAtom(); } -bool -JSObject::constructorDisplayAtom(JSContext* cx, js::MutableHandleAtom name) +/* static */ bool +JSObject::constructorDisplayAtom(JSContext* cx, js::HandleObject obj, js::MutableHandleAtom name) { - RootedObject self(cx, this); // Temporary change. - ObjectGroup *g = JSObject::getGroup(cx, self); + ObjectGroup *g = JSObject::getGroup(cx, obj); if (!g) return false; diff --git a/js/src/jsobj.h b/js/src/jsobj.h index aa4070556..49b7c5e8e 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -288,7 +288,8 @@ class JSObject : public js::gc::Cell * If this object was instantiated with `new Ctor`, return the constructor's * display atom. Otherwise, return nullptr. */ - bool constructorDisplayAtom(JSContext* cx, js::MutableHandleAtom name); + static bool constructorDisplayAtom(JSContext* cx, js::HandleObject obj, + js::MutableHandleAtom name); /* * The same as constructorDisplayAtom above, however if this object has a diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 5cc054308..a4f1f3032 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -2234,7 +2234,7 @@ Debugger::appendAllocationSite(JSContext* cx, HandleObject obj, HandleSavedFrame RootedAtom ctorName(cx); { AutoCompartment ac(cx, obj); - if (!obj->constructorDisplayAtom(cx, &ctorName)) + if (!JSObject::constructorDisplayAtom(cx, obj, &ctorName)) return false; } -- cgit v1.2.3 From 6bbc8d66646f49a1aa8a02765c1111bb3a92ee80 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 19:26:40 -0400 Subject: 1320408 - Part 6: Change JSObject::splicePrototype to static method. --- js/src/builtin/Object.cpp | 2 +- js/src/jsfriendapi.cpp | 2 +- js/src/jsobj.cpp | 6 +++--- js/src/jsobj.h | 3 ++- js/src/vm/ObjectGroup.cpp | 13 ++++++------- 5 files changed, 13 insertions(+), 13 deletions(-) (limited to 'js/src') diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp index e4bee5457..a6dcab099 100644 --- a/js/src/builtin/Object.cpp +++ b/js/src/builtin/Object.cpp @@ -1409,7 +1409,7 @@ FinishObjectClassInit(JSContext* cx, JS::HandleObject ctor, JS::HandleObject pro */ Rooted tagged(cx, TaggedProto(proto)); if (global->shouldSplicePrototype(cx)) { - if (!global->splicePrototype(cx, global->getClass(), tagged)) + if (!JSObject::splicePrototype(cx, global, global->getClass(), tagged)) return false; } return true; diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index 5baba0beb..f7622cb44 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -113,7 +113,7 @@ JS_SplicePrototype(JSContext* cx, HandleObject obj, HandleObject proto) } Rooted tagged(cx, TaggedProto(proto)); - return obj->splicePrototype(cx, obj->getClass(), tagged); + return JSObject::splicePrototype(cx, obj, obj->getClass(), tagged); } JS_FRIEND_API(JSObject*) diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index ce2f9a614..f4a524d44 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -884,7 +884,7 @@ CreateThisForFunctionWithGroup(JSContext* cx, HandleObjectGroup group, if (newKind == SingletonObject) { Rooted proto(cx, TaggedProto(templateObject->staticPrototype())); - if (!res->splicePrototype(cx, &PlainObject::class_, proto)) + if (!JSObject::splicePrototype(cx, res, &PlainObject::class_, proto)) return nullptr; } else { res->setGroup(group); @@ -1722,7 +1722,7 @@ DefineConstructorAndPrototype(JSContext* cx, HandleObject obj, JSProtoKey key, H /* Bootstrap Function.prototype (see also JS_InitStandardClasses). */ Rooted tagged(cx, TaggedProto(proto)); - if (ctor->getClass() == clasp && !ctor->splicePrototype(cx, clasp, tagged)) + if (ctor->getClass() == clasp && !JSObject::splicePrototype(cx, ctor, clasp, tagged)) goto bad; } @@ -1862,7 +1862,7 @@ js::SetClassAndProto(JSContext* cx, HandleObject obj, * Just splice the prototype, but mark the properties as unknown for * consistent behavior. */ - if (!obj->splicePrototype(cx, clasp, proto)) + if (!JSObject::splicePrototype(cx, obj, clasp, proto)) return false; MarkObjectGroupUnknownProperties(cx, obj->group()); return true; diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 49b7c5e8e..bdfe75b92 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -439,7 +439,8 @@ class JSObject : public js::gc::Cell } /* Set a new prototype for an object with a singleton type. */ - bool splicePrototype(JSContext* cx, const js::Class* clasp, js::Handle proto); + static bool splicePrototype(JSContext* cx, js::HandleObject obj, const js::Class* clasp, + js::Handle proto); /* * For bootstrapping, whether to splice a prototype for Function.prototype diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp index 6e9000894..fbad85e57 100644 --- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -262,19 +262,18 @@ JSObject::shouldSplicePrototype(JSContext* cx) return isSingleton(); } -bool -JSObject::splicePrototype(JSContext* cx, const Class* clasp, Handle proto) +/* static */ bool +JSObject::splicePrototype(JSContext* cx, HandleObject obj, const Class* clasp, + Handle proto) { - MOZ_ASSERT(cx->compartment() == compartment()); - - RootedObject self(cx, this); + MOZ_ASSERT(cx->compartment() == obj->compartment()); /* * For singleton groups representing only a single JSObject, the proto * can be rearranged as needed without destroying type information for * the old or new types. */ - MOZ_ASSERT(self->isSingleton()); + MOZ_ASSERT(obj->isSingleton()); // Windows may not appear on prototype chains. MOZ_ASSERT_IF(proto.isObject(), !IsWindow(proto.toObject())); @@ -283,7 +282,7 @@ JSObject::splicePrototype(JSContext* cx, const Class* clasp, Handle return false; // Force type instantiation when splicing lazy group. - RootedObjectGroup group(cx, JSObject::getGroup(cx, self)); + RootedObjectGroup group(cx, JSObject::getGroup(cx, obj)); if (!group) return false; RootedObjectGroup protoGroup(cx, nullptr); -- cgit v1.2.3 From 549bab83d1d7fa7bb0a15f7852ccffc708d70ab0 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 19:28:18 -0400 Subject: 1320408 - Part 7: Remove JSContext* parameter from JSObject::shouldSplicePrototype. --- js/src/builtin/Object.cpp | 2 +- js/src/jsobj.h | 2 +- js/src/vm/ObjectGroup.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'js/src') diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp index a6dcab099..56c77f304 100644 --- a/js/src/builtin/Object.cpp +++ b/js/src/builtin/Object.cpp @@ -1408,7 +1408,7 @@ FinishObjectClassInit(JSContext* cx, JS::HandleObject ctor, JS::HandleObject pro * only set the [[Prototype]] if it hasn't already been set. */ Rooted tagged(cx, TaggedProto(proto)); - if (global->shouldSplicePrototype(cx)) { + if (global->shouldSplicePrototype()) { if (!JSObject::splicePrototype(cx, global, global->getClass(), tagged)) return false; } diff --git a/js/src/jsobj.h b/js/src/jsobj.h index bdfe75b92..bdd08cf96 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -446,7 +446,7 @@ class JSObject : public js::gc::Cell * For bootstrapping, whether to splice a prototype for Function.prototype * or the global object. */ - bool shouldSplicePrototype(JSContext* cx); + bool shouldSplicePrototype(); /* * Environment chains. diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp index fbad85e57..bbbac743d 100644 --- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -249,7 +249,7 @@ ObjectGroup::useSingletonForAllocationSite(JSScript* script, jsbytecode* pc, con ///////////////////////////////////////////////////////////////////// bool -JSObject::shouldSplicePrototype(JSContext* cx) +JSObject::shouldSplicePrototype() { /* * During bootstrapping, if inference is enabled we need to make sure not -- cgit v1.2.3 From fe20cd26491f8db4e7304d509a2639cfccf26c7e Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 19:30:53 -0400 Subject: 1320408 - Part 8: Change JSObject::reportNotConfigurable and JSObject::reportNotExtensible to static method. --- js/src/jsobj.cpp | 10 +++++----- js/src/jsobj.h | 5 +++-- js/src/vm/Shape.cpp | 6 +++--- 3 files changed, 11 insertions(+), 10 deletions(-) (limited to 'js/src') diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index f4a524d44..b08e8a619 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -2451,7 +2451,7 @@ js::HasOwnDataPropertyPure(JSContext* cx, JSObject* obj, jsid id, bool* result) return true; } -bool +/* static */ bool JSObject::reportReadOnly(JSContext* cx, jsid id, unsigned report) { RootedValue val(cx, IdToValue(id)); @@ -2460,7 +2460,7 @@ JSObject::reportReadOnly(JSContext* cx, jsid id, unsigned report) nullptr, nullptr); } -bool +/* static */ bool JSObject::reportNotConfigurable(JSContext* cx, jsid id, unsigned report) { RootedValue val(cx, IdToValue(id)); @@ -2469,10 +2469,10 @@ JSObject::reportNotConfigurable(JSContext* cx, jsid id, unsigned report) nullptr, nullptr); } -bool -JSObject::reportNotExtensible(JSContext* cx, unsigned report) +/* static */ bool +JSObject::reportNotExtensible(JSContext* cx, HandleObject obj, unsigned report) { - RootedValue val(cx, ObjectValue(*this)); + RootedValue val(cx, ObjectValue(*obj)); return ReportValueErrorFlags(cx, report, JSMSG_OBJECT_NOT_EXTENSIBLE, JSDVG_IGNORE_STACK, val, nullptr, nullptr, nullptr); diff --git a/js/src/jsobj.h b/js/src/jsobj.h index bdd08cf96..3eabf448a 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -520,8 +520,9 @@ class JSObject : public js::gc::Cell public: static bool reportReadOnly(JSContext* cx, jsid id, unsigned report = JSREPORT_ERROR); - bool reportNotConfigurable(JSContext* cx, jsid id, unsigned report = JSREPORT_ERROR); - bool reportNotExtensible(JSContext* cx, unsigned report = JSREPORT_ERROR); + static bool reportNotConfigurable(JSContext* cx, jsid id, unsigned report = JSREPORT_ERROR); + static bool reportNotExtensible(JSContext* cx, js::HandleObject obj, + unsigned report = JSREPORT_ERROR); static bool nonNativeSetProperty(JSContext* cx, js::HandleObject obj, js::HandleId id, js::HandleValue v, js::HandleValue receiver, diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index 306a2c540..15fb71343 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -534,7 +534,7 @@ NativeObject::addProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId return nullptr; if (!extensible) { if (cx->isJSContext()) - obj->reportNotExtensible(cx->asJSContext()); + JSObject::reportNotExtensible(cx->asJSContext(), obj); return nullptr; } @@ -727,7 +727,7 @@ CheckCanChangeAttrs(ExclusiveContext* cx, JSObject* obj, Shape* shape, unsigned* (*attrsp & (JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED))) { if (cx->isJSContext()) - obj->reportNotConfigurable(cx->asJSContext(), shape->propid()); + JSObject::reportNotConfigurable(cx->asJSContext(), shape->propid()); return false; } @@ -785,7 +785,7 @@ NativeObject::putProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId if (!extensible) { if (cx->isJSContext()) - obj->reportNotExtensible(cx->asJSContext()); + JSObject::reportNotExtensible(cx->asJSContext(), obj); return nullptr; } -- cgit v1.2.3 From 1d0ab1c752c583c153b850af339edb86d23f6cc8 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 19:49:29 -0400 Subject: 1320408 - Part 9: Change JSObject::setFlags and depending methods to static method. --- js/src/jsapi.cpp | 2 +- js/src/jsarray.cpp | 2 +- js/src/jsiter.cpp | 4 ++-- js/src/jsobj.cpp | 13 +++++++----- js/src/jsobj.h | 34 ++++++++++++++++---------------- js/src/jswatchpoint.cpp | 2 +- js/src/proxy/CrossCompartmentWrapper.cpp | 4 ++-- js/src/vm/EnvironmentObject.cpp | 4 ++-- js/src/vm/GeneratorObject.cpp | 4 ++-- js/src/vm/GlobalObject.cpp | 6 +++--- js/src/vm/Interpreter.cpp | 2 +- js/src/vm/ObjectGroup.cpp | 11 +++++++---- js/src/vm/Shape.cpp | 25 +++++++++++------------ js/src/vm/TypeInference.cpp | 3 ++- 14 files changed, 61 insertions(+), 55 deletions(-) (limited to 'js/src') diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 949e4796b..e2d572598 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -3489,7 +3489,7 @@ CreateNonSyntacticEnvironmentChain(JSContext* cx, AutoObjectVector& envChain, // declaration was qualified by "var". There is only sadness. // // See JSObject::isQualifiedVarObj. - if (!env->setQualifiedVarObj(cx)) + if (!JSObject::setQualifiedVarObj(cx, env)) return false; // Also get a non-syntactic lexical environment to capture 'let' and diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index c1a6dcfab..aef98cc60 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -3266,7 +3266,7 @@ CreateArrayPrototype(JSContext* cx, JSProtoKey key) metadata)); if (!arrayProto || !JSObject::setSingleton(cx, arrayProto) || - !arrayProto->setDelegate(cx) || + !JSObject::setDelegate(cx, arrayProto) || !AddLengthProperty(cx, arrayProto)) { return nullptr; diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index 004c7fc0d..84d9a45c3 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -654,7 +654,7 @@ VectorToKeyIterator(JSContext* cx, HandleObject obj, unsigned flags, AutoIdVecto { MOZ_ASSERT(!(flags & JSITER_FOREACH)); - if (obj->isSingleton() && !obj->setIteratedSingleton(cx)) + if (obj->isSingleton() && !JSObject::setIteratedSingleton(cx, obj)) return false; MarkObjectGroupFlags(cx, obj, OBJECT_FLAG_ITERATED); @@ -698,7 +698,7 @@ VectorToValueIterator(JSContext* cx, HandleObject obj, unsigned flags, AutoIdVec { MOZ_ASSERT(flags & JSITER_FOREACH); - if (obj->isSingleton() && !obj->setIteratedSingleton(cx)) + if (obj->isSingleton() && !JSObject::setIteratedSingleton(cx, obj)) return false; MarkObjectGroupFlags(cx, obj, OBJECT_FLAG_ITERATED); diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index b08e8a619..78efca8de 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -1842,7 +1842,7 @@ js::SetClassAndProto(JSContext* cx, HandleObject obj, if (!oldproto->as().generateOwnShape(cx)) return false; } else { - if (!oldproto->setUncacheableProto(cx)) + if (!JSObject::setUncacheableProto(cx, oldproto)) return false; } if (!obj->isDelegate()) { @@ -1854,8 +1854,11 @@ js::SetClassAndProto(JSContext* cx, HandleObject obj, oldproto = oldproto->staticPrototype(); } - if (proto.isObject() && !proto.toObject()->setDelegate(cx)) - return false; + if (proto.isObject()) { + RootedObject protoObj(cx, proto.toObject()); + if (!JSObject::setDelegate(cx, protoObj)) + return false; + } if (obj->isSingleton()) { /* @@ -2611,7 +2614,7 @@ js::PreventExtensions(JSContext* cx, HandleObject obj, ObjectOpResult& result, I } } - if (!obj->setFlags(cx, BaseShape::NOT_EXTENSIBLE, JSObject::GENERATE_SHAPE)) { + if (!JSObject::setFlags(cx, obj, BaseShape::NOT_EXTENSIBLE, JSObject::GENERATE_SHAPE)) { // We failed to mark the object non-extensible, so reset the frozen // flag on the elements. MOZ_ASSERT(obj->nonProxyIsExtensible()); @@ -2751,7 +2754,7 @@ js::SetImmutablePrototype(ExclusiveContext* cx, HandleObject obj, bool* succeede return Proxy::setImmutablePrototype(cx->asJSContext(), obj, succeeded); } - if (!obj->setFlags(cx, BaseShape::IMMUTABLE_PROTOTYPE)) + if (!JSObject::setFlags(cx, obj, BaseShape::IMMUTABLE_PROTOTYPE)) return false; *succeeded = true; return true; diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 3eabf448a..db2c22b76 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -200,8 +200,8 @@ class JSObject : public js::gc::Cell GENERATE_SHAPE }; - bool setFlags(js::ExclusiveContext* cx, js::BaseShape::Flag flags, - GenerateShape generateShape = GENERATE_NONE); + static bool setFlags(js::ExclusiveContext* cx, JS::HandleObject obj, js::BaseShape::Flag flags, + GenerateShape generateShape = GENERATE_NONE); inline bool hasAllFlags(js::BaseShape::Flag flags) const; /* @@ -214,16 +214,16 @@ class JSObject : public js::gc::Cell * (see Purge{Scope,Proto}Chain in jsobj.cpp). */ inline bool isDelegate() const; - bool setDelegate(js::ExclusiveContext* cx) { - return setFlags(cx, js::BaseShape::DELEGATE, GENERATE_SHAPE); + static bool setDelegate(js::ExclusiveContext* cx, JS::HandleObject obj) { + return setFlags(cx, obj, js::BaseShape::DELEGATE, GENERATE_SHAPE); } inline bool isBoundFunction() const; inline bool hasSpecialEquality() const; inline bool watched() const; - bool setWatched(js::ExclusiveContext* cx) { - return setFlags(cx, js::BaseShape::WATCHED, GENERATE_SHAPE); + static bool setWatched(js::ExclusiveContext* cx, JS::HandleObject obj) { + return setFlags(cx, obj, js::BaseShape::WATCHED, GENERATE_SHAPE); } // A "qualified" varobj is the object on which "qualified" variable @@ -247,8 +247,8 @@ class JSObject : public js::gc::Cell // (e.g., Gecko and XPConnect), as they often wish to run scripts under a // scope that captures var bindings. inline bool isQualifiedVarObj() const; - bool setQualifiedVarObj(js::ExclusiveContext* cx) { - return setFlags(cx, js::BaseShape::QUALIFIED_VAROBJ); + static bool setQualifiedVarObj(js::ExclusiveContext* cx, JS::HandleObject obj) { + return setFlags(cx, obj, js::BaseShape::QUALIFIED_VAROBJ); } // An "unqualified" varobj is the object on which "unqualified" @@ -262,11 +262,11 @@ class JSObject : public js::gc::Cell // generate a new shape when their prototype changes, regardless of this // hasUncacheableProto flag. inline bool hasUncacheableProto() const; - bool setUncacheableProto(js::ExclusiveContext* cx) { - MOZ_ASSERT(hasStaticPrototype(), + static bool setUncacheableProto(js::ExclusiveContext* cx, JS::HandleObject obj) { + MOZ_ASSERT(obj->hasStaticPrototype(), "uncacheability as a concept is only applicable to static " "(not dynamically-computed) prototypes"); - return setFlags(cx, js::BaseShape::UNCACHEABLE_PROTO, GENERATE_SHAPE); + return setFlags(cx, obj, js::BaseShape::UNCACHEABLE_PROTO, GENERATE_SHAPE); } /* @@ -274,8 +274,8 @@ class JSObject : public js::gc::Cell * PropertyTree::MAX_HEIGHT. */ inline bool hadElementsAccess() const; - bool setHadElementsAccess(js::ExclusiveContext* cx) { - return setFlags(cx, js::BaseShape::HAD_ELEMENTS_ACCESS); + static bool setHadElementsAccess(js::ExclusiveContext* cx, JS::HandleObject obj) { + return setFlags(cx, obj, js::BaseShape::HAD_ELEMENTS_ACCESS); } /* @@ -421,8 +421,8 @@ class JSObject : public js::gc::Cell * is purged on GC. */ inline bool isIteratedSingleton() const; - bool setIteratedSingleton(js::ExclusiveContext* cx) { - return setFlags(cx, js::BaseShape::ITERATED_SINGLETON); + static bool setIteratedSingleton(js::ExclusiveContext* cx, JS::HandleObject obj) { + return setFlags(cx, obj, js::BaseShape::ITERATED_SINGLETON); } /* @@ -434,8 +434,8 @@ class JSObject : public js::gc::Cell // Mark an object as having its 'new' script information cleared. inline bool wasNewScriptCleared() const; - bool setNewScriptCleared(js::ExclusiveContext* cx) { - return setFlags(cx, js::BaseShape::NEW_SCRIPT_CLEARED); + static bool setNewScriptCleared(js::ExclusiveContext* cx, JS::HandleObject obj) { + return setFlags(cx, obj, js::BaseShape::NEW_SCRIPT_CLEARED); } /* Set a new prototype for an object with a singleton type. */ diff --git a/js/src/jswatchpoint.cpp b/js/src/jswatchpoint.cpp index e37323555..34479a990 100644 --- a/js/src/jswatchpoint.cpp +++ b/js/src/jswatchpoint.cpp @@ -64,7 +64,7 @@ WatchpointMap::watch(JSContext* cx, HandleObject obj, HandleId id, { MOZ_ASSERT(JSID_IS_STRING(id) || JSID_IS_INT(id) || JSID_IS_SYMBOL(id)); - if (!obj->setWatched(cx)) + if (!JSObject::setWatched(cx, obj)) return false; Watchpoint w(handler, closure, false); diff --git a/js/src/proxy/CrossCompartmentWrapper.cpp b/js/src/proxy/CrossCompartmentWrapper.cpp index 2a6cb5400..246639956 100644 --- a/js/src/proxy/CrossCompartmentWrapper.cpp +++ b/js/src/proxy/CrossCompartmentWrapper.cpp @@ -89,7 +89,7 @@ CrossCompartmentWrapper::getPrototype(JSContext* cx, HandleObject wrapper, if (!GetPrototype(cx, wrapped, protop)) return false; if (protop) { - if (!protop->setDelegate(cx)) + if (!JSObject::setDelegate(cx, protop)) return false; } } @@ -122,7 +122,7 @@ CrossCompartmentWrapper::getPrototypeIfOrdinary(JSContext* cx, HandleObject wrap return true; if (protop) { - if (!protop->setDelegate(cx)) + if (!JSObject::setDelegate(cx, protop)) return false; } } diff --git a/js/src/vm/EnvironmentObject.cpp b/js/src/vm/EnvironmentObject.cpp index 3125aa41c..611f0e194 100644 --- a/js/src/vm/EnvironmentObject.cpp +++ b/js/src/vm/EnvironmentObject.cpp @@ -816,7 +816,7 @@ NonSyntacticVariablesObject::create(JSContext* cx) return nullptr; MOZ_ASSERT(obj->isUnqualifiedVarObj()); - if (!obj->setQualifiedVarObj(cx)) + if (!JSObject::setQualifiedVarObj(cx, obj)) return nullptr; obj->initEnclosingEnvironment(&cx->global()->lexicalEnvironment()); @@ -957,7 +957,7 @@ LexicalEnvironmentObject::createHollowForDebug(JSContext* cx, HandlesetFlags(cx, BaseShape::NOT_EXTENSIBLE, JSObject::GENERATE_SHAPE)) + if (!JSObject::setFlags(cx, env, BaseShape::NOT_EXTENSIBLE, JSObject::GENERATE_SHAPE)) return nullptr; env->initScopeUnchecked(scope); diff --git a/js/src/vm/GeneratorObject.cpp b/js/src/vm/GeneratorObject.cpp index 690c0bf48..82b774a35 100644 --- a/js/src/vm/GeneratorObject.cpp +++ b/js/src/vm/GeneratorObject.cpp @@ -278,7 +278,7 @@ GlobalObject::initLegacyGeneratorProto(JSContext* cx, Handle glob return true; RootedObject proto(cx, NewSingletonObjectWithObjectPrototype(cx, global)); - if (!proto || !proto->setDelegate(cx)) + if (!proto || !JSObject::setDelegate(cx, proto)) return false; if (!DefinePropertiesAndFunctions(cx, proto, nullptr, legacy_generator_methods)) return false; @@ -309,7 +309,7 @@ GlobalObject::initStarGenerators(JSContext* cx, Handle global) } RootedObject genFunctionProto(cx, NewSingletonObjectWithFunctionPrototype(cx, global)); - if (!genFunctionProto || !genFunctionProto->setDelegate(cx)) + if (!genFunctionProto || !JSObject::setDelegate(cx, genFunctionProto)) return false; if (!LinkConstructorAndPrototype(cx, genFunctionProto, genObjectProto) || !DefineToStringTag(cx, genFunctionProto, cx->names().GeneratorFunction)) diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index c90b6b85f..c431b5f1d 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -329,9 +329,9 @@ GlobalObject::createInternal(JSContext* cx, const Class* clasp) cx->compartment()->initGlobal(*global); - if (!global->setQualifiedVarObj(cx)) + if (!JSObject::setQualifiedVarObj(cx, global)) return nullptr; - if (!global->setDelegate(cx)) + if (!JSObject::setDelegate(cx, global)) return nullptr; return global; @@ -595,7 +595,7 @@ CreateBlankProto(JSContext* cx, const Class* clasp, HandleObject proto, HandleOb RootedNativeObject blankProto(cx, NewNativeObjectWithGivenProto(cx, clasp, proto, SingletonObject)); - if (!blankProto || !blankProto->setDelegate(cx)) + if (!blankProto || !JSObject::setDelegate(cx, blankProto)) return nullptr; return blankProto; diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 77637aab8..097b7b0f3 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -1543,7 +1543,7 @@ SetObjectElementOperation(JSContext* cx, HandleObject obj, HandleId id, HandleVa } } - if (obj->isNative() && !JSID_IS_INT(id) && !obj->setHadElementsAccess(cx)) + if (obj->isNative() && !JSID_IS_INT(id) && !JSObject::setHadElementsAccess(cx, obj)) return false; ObjectOpResult result; diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp index bbbac743d..ec0a7aec1 100644 --- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -278,8 +278,11 @@ JSObject::splicePrototype(JSContext* cx, HandleObject obj, const Class* clasp, // Windows may not appear on prototype chains. MOZ_ASSERT_IF(proto.isObject(), !IsWindow(proto.toObject())); - if (proto.isObject() && !proto.toObject()->setDelegate(cx)) - return false; + if (proto.isObject()) { + RootedObject protoObj(cx, proto.toObject()); + if (!JSObject::setDelegate(cx, protoObj)) + return false; + } // Force type instantiation when splicing lazy group. RootedObjectGroup group(cx, JSObject::getGroup(cx, obj)); @@ -346,7 +349,7 @@ JSObject::makeLazyGroup(JSContext* cx, HandleObject obj) JSObject::setNewGroupUnknown(JSContext* cx, const js::Class* clasp, JS::HandleObject obj) { ObjectGroup::setDefaultNewGroupUnknown(cx, clasp, obj); - return obj->setFlags(cx, BaseShape::NEW_GROUP_UNKNOWN); + return JSObject::setFlags(cx, obj, BaseShape::NEW_GROUP_UNKNOWN); } ///////////////////////////////////////////////////////////////////// @@ -508,7 +511,7 @@ ObjectGroup::defaultNewGroup(ExclusiveContext* cx, const Class* clasp, if (proto.isObject() && !proto.toObject()->isDelegate()) { RootedObject protoObj(cx, proto.toObject()); - if (!protoObj->setDelegate(cx)) + if (!JSObject::setDelegate(cx, protoObj)) return nullptr; // Objects which are prototypes of one another should be singletons, so diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index 15fb71343..065a96337 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -1206,38 +1206,37 @@ NativeObject::shadowingShapeChange(ExclusiveContext* cx, const Shape& shape) return generateOwnShape(cx); } -bool -JSObject::setFlags(ExclusiveContext* cx, BaseShape::Flag flags, GenerateShape generateShape) +/* static */ bool +JSObject::setFlags(ExclusiveContext* cx, HandleObject obj, BaseShape::Flag flags, + GenerateShape generateShape) { - if (hasAllFlags(flags)) + if (obj->hasAllFlags(flags)) return true; - RootedObject self(cx, this); - - Shape* existingShape = self->ensureShape(cx); + Shape* existingShape = obj->ensureShape(cx); if (!existingShape) return false; - if (isNative() && as().inDictionaryMode()) { - if (generateShape == GENERATE_SHAPE && !as().generateOwnShape(cx)) + if (obj->isNative() && obj->as().inDictionaryMode()) { + if (generateShape == GENERATE_SHAPE && !obj->as().generateOwnShape(cx)) return false; - StackBaseShape base(self->as().lastProperty()); + StackBaseShape base(obj->as().lastProperty()); base.flags |= flags; UnownedBaseShape* nbase = BaseShape::getUnowned(cx, base); if (!nbase) return false; - self->as().lastProperty()->base()->adoptUnowned(nbase); + obj->as().lastProperty()->base()->adoptUnowned(nbase); return true; } - Shape* newShape = Shape::setObjectFlags(cx, flags, self->taggedProto(), existingShape); + Shape* newShape = Shape::setObjectFlags(cx, flags, obj->taggedProto(), existingShape); if (!newShape) return false; - // The success of the |JSObject::ensureShape| call above means that |self| + // The success of the |JSObject::ensureShape| call above means that |obj| // can be assumed to have a shape. - self->as().setShape(newShape); + obj->as().setShape(newShape); return true; } diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index 60d9e183a..7c2c0194e 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -2945,7 +2945,8 @@ ObjectGroup::clearNewScript(ExclusiveContext* cx, ObjectGroup* replacement /* = // Mark the constructing function as having its 'new' script cleared, so we // will not try to construct another one later. - if (!newScript->function()->setNewScriptCleared(cx)) + RootedFunction fun(cx, newScript->function()); + if (!JSObject::setNewScriptCleared(cx, fun)) cx->recoverFromOutOfMemory(); } -- cgit v1.2.3 From 4d88f48fdb51a29fd66001e87a74e2d6a130fe1f Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 19:52:00 -0400 Subject: 1320408 - Part 10: Change LazyScript::functionDelazifying to static method. --- js/src/jsfun.cpp | 2 +- js/src/jsscript.h | 2 +- js/src/jsscriptinlines.h | 11 +++++------ 3 files changed, 7 insertions(+), 8 deletions(-) (limited to 'js/src') diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 5a253217b..ea64aabe2 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -1366,7 +1366,7 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext* cx, HandleFuncti } if (fun != lazy->functionNonDelazifying()) { - if (!lazy->functionDelazifying(cx)) + if (!LazyScript::functionDelazifying(cx, lazy)) return false; script = lazy->functionNonDelazifying()->nonLazyScript(); if (!script) diff --git a/js/src/jsscript.h b/js/src/jsscript.h index c3298a884..2f962ab94 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -2034,7 +2034,7 @@ class LazyScript : public gc::TenuredCell void initRuntimeFields(uint64_t packedFields); - inline JSFunction* functionDelazifying(JSContext* cx) const; + static inline JSFunction* functionDelazifying(JSContext* cx, Handle); JSFunction* functionNonDelazifying() const { return function_; } diff --git a/js/src/jsscriptinlines.h b/js/src/jsscriptinlines.h index 65abb5cb7..205a37f24 100644 --- a/js/src/jsscriptinlines.h +++ b/js/src/jsscriptinlines.h @@ -74,14 +74,13 @@ void SetFrameArgumentsObject(JSContext* cx, AbstractFramePtr frame, HandleScript script, JSObject* argsobj); -inline JSFunction* -LazyScript::functionDelazifying(JSContext* cx) const +/* static */ inline JSFunction* +LazyScript::functionDelazifying(JSContext* cx, Handle script) { - Rooted self(cx, this); - RootedFunction fun(cx, self->function_); - if (self->function_ && !JSFunction::getOrCreateScript(cx, fun)) + RootedFunction fun(cx, script->function_); + if (script->function_ && !JSFunction::getOrCreateScript(cx, fun)) return nullptr; - return self->function_; + return script->function_; } } // namespace js -- cgit v1.2.3 From 93335c3120968fac165a95978ef0dbdffe7900b4 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 21:10:15 -0400 Subject: 1320408 - Part 12: Change JSScript::sourceData to static method. --- js/src/jit/BaselineJIT.cpp | 2 +- js/src/jit/Ion.cpp | 2 +- js/src/jsapi.cpp | 5 +++-- js/src/jsfun.cpp | 2 +- js/src/jsscript.cpp | 8 ++++---- js/src/jsscript.h | 4 ++-- js/src/jsscriptinlines.h | 2 +- js/src/vm/Interpreter.cpp | 2 +- js/src/vm/Stack-inl.h | 4 ++-- 9 files changed, 16 insertions(+), 15 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/BaselineJIT.cpp b/js/src/jit/BaselineJIT.cpp index d0e297c2d..5c21926b5 100644 --- a/js/src/jit/BaselineJIT.cpp +++ b/js/src/jit/BaselineJIT.cpp @@ -273,7 +273,7 @@ jit::BaselineCompile(JSContext* cx, JSScript* script, bool forceDebugInstrumenta MOZ_ASSERT(script->canBaselineCompile()); MOZ_ASSERT(IsBaselineEnabled(cx)); - script->ensureNonLazyCanonicalFunction(cx); + script->ensureNonLazyCanonicalFunction(); LifoAlloc alloc(TempAllocator::PreferredLifoChunkSize); TempAllocator* temp = alloc.new_(&alloc); diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index c61b414e0..b8a2d2fba 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -2153,7 +2153,7 @@ IonCompile(JSContext* cx, JSScript* script, // Make sure the script's canonical function isn't lazy. We can't de-lazify // it in a helper thread. - script->ensureNonLazyCanonicalFunction(cx); + script->ensureNonLazyCanonicalFunction(); TrackPropertiesForSingletonScopes(cx, script, baselineFrame); diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index e2d572598..4e094adff 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -4405,14 +4405,15 @@ JS_DecompileScript(JSContext* cx, HandleScript script, const char* name, unsigne AssertHeapIsIdle(cx); CHECK_REQUEST(cx); - script->ensureNonLazyCanonicalFunction(cx); + script->ensureNonLazyCanonicalFunction(); RootedFunction fun(cx, script->functionNonDelazifying()); if (fun) return JS_DecompileFunction(cx, fun, indent); bool haveSource = script->scriptSource()->hasSourceData(); if (!haveSource && !JSScript::loadSource(cx, script->scriptSource(), &haveSource)) return nullptr; - return haveSource ? script->sourceData(cx) : NewStringCopyZ(cx, "[no source]"); + return haveSource ? JSScript::sourceData(cx, script) + : NewStringCopyZ(cx, "[no source]"); } JS_PUBLIC_API(JSString*) diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index ea64aabe2..954fd47a0 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -973,7 +973,7 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint) }; if (haveSource) { - Rooted src(cx, script->sourceDataWithPrelude(cx)); + Rooted src(cx, JSScript::sourceDataWithPrelude(cx, script)); if (!src) return nullptr; diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 28fb3636c..36060e4c0 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -1435,11 +1435,11 @@ JSScript::loadSource(JSContext* cx, ScriptSource* ss, bool* worked) return true; } -JSFlatString* -JSScript::sourceData(JSContext* cx) +/* static */ JSFlatString* +JSScript::sourceData(JSContext* cx, HandleScript script) { - MOZ_ASSERT(scriptSource()->hasSourceData()); - return scriptSource()->substring(cx, sourceStart(), sourceEnd()); + MOZ_ASSERT(script->scriptSource()->hasSourceData()); + return script->scriptSource()->substring(cx, script->sourceStart(), script->sourceEnd()); } JSFlatString* diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 2f962ab94..74cefea07 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -1499,7 +1499,7 @@ class JSScript : public js::gc::TenuredCell * De-lazifies the canonical function. Must be called before entering code * that expects the function to be non-lazy. */ - inline void ensureNonLazyCanonicalFunction(JSContext* cx); + inline void ensureNonLazyCanonicalFunction(); js::ModuleObject* module() const { if (bodyScope()->is()) @@ -1518,7 +1518,7 @@ class JSScript : public js::gc::TenuredCell // directly, via lazy arguments or a rest parameter. bool mayReadFrameArgsDirectly(); - JSFlatString* sourceData(JSContext* cx); + static JSFlatString* sourceData(JSContext* cx, JS::HandleScript script); JSFlatString* sourceDataWithPrelude(JSContext* cx); static bool loadSource(JSContext* cx, js::ScriptSource* ss, bool* worked); diff --git a/js/src/jsscriptinlines.h b/js/src/jsscriptinlines.h index 205a37f24..e1052111b 100644 --- a/js/src/jsscriptinlines.h +++ b/js/src/jsscriptinlines.h @@ -100,7 +100,7 @@ JSScript::functionDelazifying() const } inline void -JSScript::ensureNonLazyCanonicalFunction(JSContext* cx) +JSScript::ensureNonLazyCanonicalFunction() { // Infallibly delazify the canonical script. JSFunction* fun = function(); diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 097b7b0f3..23a1ad2a5 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -373,7 +373,7 @@ js::RunScript(JSContext* cx, RunState& state) SPSEntryMarker marker(cx->runtime(), state.script()); - state.script()->ensureNonLazyCanonicalFunction(cx); + state.script()->ensureNonLazyCanonicalFunction(); if (jit::IsIonEnabled(cx)) { jit::MethodStatus status = jit::CanEnter(cx, state); diff --git a/js/src/vm/Stack-inl.h b/js/src/vm/Stack-inl.h index 9adea9af5..11a19d175 100644 --- a/js/src/vm/Stack-inl.h +++ b/js/src/vm/Stack-inl.h @@ -306,7 +306,7 @@ InterpreterStack::pushInlineFrame(JSContext* cx, InterpreterRegs& regs, const Ca MOZ_ASSERT(regs.sp == args.end()); MOZ_ASSERT(callee->nonLazyScript() == script); - script->ensureNonLazyCanonicalFunction(cx); + script->ensureNonLazyCanonicalFunction(); InterpreterFrame* prev = regs.fp(); jsbytecode* prevpc = regs.pc; @@ -342,7 +342,7 @@ InterpreterStack::resumeGeneratorCallFrame(JSContext* cx, InterpreterRegs& regs, Value* prevsp = regs.sp; MOZ_ASSERT(prev); - script->ensureNonLazyCanonicalFunction(cx); + script->ensureNonLazyCanonicalFunction(); LifoAlloc::Mark mark = allocator_.mark(); -- cgit v1.2.3 From fcfaa4fbee917f821806a70b2000a91a97948c11 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 21:29:59 -0400 Subject: 1320408 - Change JSScript::sourceDataWithPrelude to static method UXP Interdiff --- js/src/jsscript.cpp | 8 ++++---- js/src/jsscript.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'js/src') diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 36060e4c0..ddc98ef3f 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -1442,11 +1442,11 @@ JSScript::sourceData(JSContext* cx, HandleScript script) return script->scriptSource()->substring(cx, script->sourceStart(), script->sourceEnd()); } -JSFlatString* -JSScript::sourceDataWithPrelude(JSContext* cx) +/* static */ JSFlatString* +JSScript::sourceDataWithPrelude(JSContext* cx, HandleScript script) { - MOZ_ASSERT(scriptSource()->hasSourceData()); - return scriptSource()->substring(cx, preludeStart(), sourceEnd()); + MOZ_ASSERT(script->scriptSource()->hasSourceData()); + return script->scriptSource()->substring(cx, script->preludeStart(), script->sourceEnd()); } UncompressedSourceCache::AutoHoldEntry::AutoHoldEntry() diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 74cefea07..62502a3c7 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -1519,7 +1519,7 @@ class JSScript : public js::gc::TenuredCell bool mayReadFrameArgsDirectly(); static JSFlatString* sourceData(JSContext* cx, JS::HandleScript script); - JSFlatString* sourceDataWithPrelude(JSContext* cx); + static JSFlatString* sourceDataWithPrelude(JSContext* cx, JS::HandleScript script); static bool loadSource(JSContext* cx, js::ScriptSource* ss, bool* worked); -- cgit v1.2.3 From 7757e03ccc550b030fb4d342f160ee30a940f23d Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 21:33:39 -0400 Subject: 1320408 - Part 13: Change DebugEnvironmentProxy::getMaybeSentinelValue to static method. --- js/src/jsobj.cpp | 3 ++- js/src/vm/Debugger.cpp | 3 ++- js/src/vm/EnvironmentObject.cpp | 8 ++++---- js/src/vm/EnvironmentObject.h | 3 ++- 4 files changed, 10 insertions(+), 7 deletions(-) (limited to 'js/src') diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 78efca8de..58be1a283 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -2198,7 +2198,8 @@ js::LookupNameUnqualified(JSContext* cx, HandlePropertyName name, HandleObject e // environments. if (env->is()) { RootedValue v(cx); - if (!env->as().getMaybeSentinelValue(cx, id, &v)) + Rooted envProxy(cx, &env->as()); + if (!DebugEnvironmentProxy::getMaybeSentinelValue(cx, envProxy, id, &v)) return false; isTDZ = IsUninitializedLexical(v); } else { diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index a4f1f3032..b959740ac 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -10774,7 +10774,8 @@ DebuggerEnvironment::getVariable(JSContext* cx, HandleDebuggerEnvironment enviro // // See wrapDebuggeeValue for how the sentinel values are wrapped. if (referent->is()) { - if (!referent->as().getMaybeSentinelValue(cx, id, result)) + Rooted env(cx, &referent->as()); + if (!DebugEnvironmentProxy::getMaybeSentinelValue(cx, env, id, result)) return false; } else { if (!GetProperty(cx, referent, referent, id, result)) diff --git a/js/src/vm/EnvironmentObject.cpp b/js/src/vm/EnvironmentObject.cpp index 611f0e194..a5aac2ab4 100644 --- a/js/src/vm/EnvironmentObject.cpp +++ b/js/src/vm/EnvironmentObject.cpp @@ -2234,11 +2234,11 @@ DebugEnvironmentProxy::isForDeclarative() const e.is(); } -bool -DebugEnvironmentProxy::getMaybeSentinelValue(JSContext* cx, HandleId id, MutableHandleValue vp) +/* static */ bool +DebugEnvironmentProxy::getMaybeSentinelValue(JSContext* cx, Handle env, + HandleId id, MutableHandleValue vp) { - Rooted self(cx, this); - return DebugEnvironmentProxyHandler::singleton.getMaybeSentinelValue(cx, self, id, vp); + return DebugEnvironmentProxyHandler::singleton.getMaybeSentinelValue(cx, env, id, vp); } bool diff --git a/js/src/vm/EnvironmentObject.h b/js/src/vm/EnvironmentObject.h index 032286116..c527cd1b0 100644 --- a/js/src/vm/EnvironmentObject.h +++ b/js/src/vm/EnvironmentObject.h @@ -872,7 +872,8 @@ class DebugEnvironmentProxy : public ProxyObject // Get a property by 'id', but returns sentinel values instead of throwing // on exceptional cases. - bool getMaybeSentinelValue(JSContext* cx, HandleId id, MutableHandleValue vp); + static bool getMaybeSentinelValue(JSContext* cx, Handle env, + HandleId id, MutableHandleValue vp); // Returns true iff this is a function environment with its own this-binding // (all functions except arrow functions and generator expression lambdas). -- cgit v1.2.3 From 3a5176f4b25a2b90cefe14eb2c2de57113dc21ac Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 23:28:04 -0400 Subject: 1320408 - Part 14: Change some GlobalObject methods to static method. --- js/src/builtin/AtomicsObject.cpp | 2 +- js/src/builtin/Intl.cpp | 31 ++--- js/src/builtin/MapObject.cpp | 4 +- js/src/builtin/ModuleObject.cpp | 6 +- js/src/builtin/Promise.cpp | 2 +- js/src/builtin/Reflect.cpp | 3 +- js/src/builtin/RegExp.cpp | 8 +- js/src/builtin/SIMD.cpp | 22 ++-- js/src/builtin/SymbolObject.cpp | 8 +- js/src/builtin/TypedObject.cpp | 19 ++- js/src/builtin/WeakMapObject.cpp | 6 +- js/src/builtin/WeakSetObject.cpp | 7 +- js/src/builtin/WeakSetObject.h | 2 +- js/src/jit/CodeGenerator.cpp | 2 +- js/src/jsapi.cpp | 25 ++-- js/src/jsarray.cpp | 2 +- js/src/jsbool.cpp | 6 +- js/src/jsdate.cpp | 2 +- js/src/jsexn.cpp | 9 +- js/src/jsfun.cpp | 2 +- js/src/jsiter.cpp | 18 +-- js/src/jsmath.cpp | 3 +- js/src/jsnum.cpp | 7 +- js/src/jsobj.cpp | 5 +- js/src/json.cpp | 4 +- js/src/jsstr.cpp | 8 +- js/src/proxy/Proxy.cpp | 4 +- js/src/vm/ArgumentsObject.cpp | 2 +- js/src/vm/ArrayBufferObject.cpp | 2 +- js/src/vm/Debugger.cpp | 16 +-- js/src/vm/GeneratorObject.cpp | 10 +- js/src/vm/GlobalObject.cpp | 40 +++---- js/src/vm/GlobalObject.h | 241 +++++++++++++++++++++------------------ js/src/vm/RegExpObject.cpp | 2 +- js/src/vm/SharedArrayObject.cpp | 3 +- js/src/vm/TypedArrayObject.cpp | 11 +- js/src/wasm/WasmJS.cpp | 2 +- 37 files changed, 287 insertions(+), 259 deletions(-) (limited to 'js/src') diff --git a/js/src/builtin/AtomicsObject.cpp b/js/src/builtin/AtomicsObject.cpp index 3de3f5f4c..ceee83349 100644 --- a/js/src/builtin/AtomicsObject.cpp +++ b/js/src/builtin/AtomicsObject.cpp @@ -1117,7 +1117,7 @@ JSObject* AtomicsObject::initClass(JSContext* cx, Handle global) { // Create Atomics Object. - RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx)); + RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!objProto) return nullptr; RootedObject Atomics(cx, NewObjectWithGivenProto(cx, &AtomicsObject::class_, objProto, diff --git a/js/src/builtin/Intl.cpp b/js/src/builtin/Intl.cpp index 71f7b58d4..0cd0c62dd 100644 --- a/js/src/builtin/Intl.cpp +++ b/js/src/builtin/Intl.cpp @@ -270,7 +270,7 @@ Collator(JSContext* cx, const CallArgs& args, bool construct) // See https://github.com/tc39/ecma402/issues/57 if (!construct) { // ES Intl 1st ed., 10.1.2.1 step 3 - JSObject* intl = cx->global()->getOrCreateIntlObject(cx); + JSObject* intl = GlobalObject::getOrCreateIntlObject(cx, cx->global()); if (!intl) return false; RootedValue self(cx, args.thisv()); @@ -298,7 +298,7 @@ Collator(JSContext* cx, const CallArgs& args, bool construct) return false; if (!proto) { - proto = cx->global()->getOrCreateCollatorPrototype(cx); + proto = GlobalObject::getOrCreateCollatorPrototype(cx, cx->global()); if (!proto) return false; } @@ -358,11 +358,12 @@ collator_finalize(FreeOp* fop, JSObject* obj) static JSObject* CreateCollatorPrototype(JSContext* cx, HandleObject Intl, Handle global) { - RootedFunction ctor(cx, global->createConstructor(cx, &Collator, cx->names().Collator, 0)); + RootedFunction ctor(cx, GlobalObject::createConstructor(cx, &Collator, cx->names().Collator, + 0)); if (!ctor) return nullptr; - RootedNativeObject proto(cx, global->createBlankPrototype(cx, &CollatorClass)); + RootedNativeObject proto(cx, GlobalObject::createBlankPrototype(cx, global, &CollatorClass)); if (!proto) return nullptr; proto->setReservedSlot(UCOLLATOR_SLOT, PrivateValue(nullptr)); @@ -772,7 +773,7 @@ NumberFormat(JSContext* cx, const CallArgs& args, bool construct) // See https://github.com/tc39/ecma402/issues/57 if (!construct) { // ES Intl 1st ed., 11.1.2.1 step 3 - JSObject* intl = cx->global()->getOrCreateIntlObject(cx); + JSObject* intl = GlobalObject::getOrCreateIntlObject(cx, cx->global()); if (!intl) return false; RootedValue self(cx, args.thisv()); @@ -800,7 +801,7 @@ NumberFormat(JSContext* cx, const CallArgs& args, bool construct) return false; if (!proto) { - proto = cx->global()->getOrCreateNumberFormatPrototype(cx); + proto = GlobalObject::getOrCreateNumberFormatPrototype(cx, cx->global()); if (!proto) return false; } @@ -862,11 +863,12 @@ static JSObject* CreateNumberFormatPrototype(JSContext* cx, HandleObject Intl, Handle global) { RootedFunction ctor(cx); - ctor = global->createConstructor(cx, &NumberFormat, cx->names().NumberFormat, 0); + ctor = GlobalObject::createConstructor(cx, &NumberFormat, cx->names().NumberFormat, 0); if (!ctor) return nullptr; - RootedNativeObject proto(cx, global->createBlankPrototype(cx, &NumberFormatClass)); + RootedNativeObject proto(cx, GlobalObject::createBlankPrototype(cx, global, + &NumberFormatClass)); if (!proto) return nullptr; proto->setReservedSlot(UNUMBER_FORMAT_SLOT, PrivateValue(nullptr)); @@ -1250,7 +1252,7 @@ DateTimeFormat(JSContext* cx, const CallArgs& args, bool construct) // See https://github.com/tc39/ecma402/issues/57 if (!construct) { // ES Intl 1st ed., 12.1.2.1 step 3 - JSObject* intl = cx->global()->getOrCreateIntlObject(cx); + JSObject* intl = GlobalObject::getOrCreateIntlObject(cx, cx->global()); if (!intl) return false; RootedValue self(cx, args.thisv()); @@ -1278,7 +1280,7 @@ DateTimeFormat(JSContext* cx, const CallArgs& args, bool construct) return false; if (!proto) { - proto = cx->global()->getOrCreateDateTimeFormatPrototype(cx); + proto = GlobalObject::getOrCreateDateTimeFormatPrototype(cx, cx->global()); if (!proto) return false; } @@ -1340,11 +1342,12 @@ static JSObject* CreateDateTimeFormatPrototype(JSContext* cx, HandleObject Intl, Handle global) { RootedFunction ctor(cx); - ctor = global->createConstructor(cx, &DateTimeFormat, cx->names().DateTimeFormat, 0); + ctor = GlobalObject::createConstructor(cx, &DateTimeFormat, cx->names().DateTimeFormat, 0); if (!ctor) return nullptr; - RootedNativeObject proto(cx, global->createBlankPrototype(cx, &DateTimeFormatClass)); + RootedNativeObject proto(cx, GlobalObject::createBlankPrototype(cx, global, + &DateTimeFormatClass)); if (!proto) return nullptr; proto->setReservedSlot(UDATE_FORMAT_SLOT, PrivateValue(nullptr)); @@ -2731,10 +2734,10 @@ static const JSFunctionSpec intl_static_methods[] = { * Initializes the Intl Object and its standard built-in properties. * Spec: ECMAScript Internationalization API Specification, 8.0, 8.1 */ -bool +/* static */ bool GlobalObject::initIntlObject(JSContext* cx, Handle global) { - RootedObject proto(cx, global->getOrCreateObjectPrototype(cx)); + RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!proto) return false; diff --git a/js/src/builtin/MapObject.cpp b/js/src/builtin/MapObject.cpp index c496cfb77..34e2e566d 100644 --- a/js/src/builtin/MapObject.cpp +++ b/js/src/builtin/MapObject.cpp @@ -164,7 +164,7 @@ MapIteratorObject::kind() const return MapObject::IteratorKind(i); } -bool +/* static */ bool GlobalObject::initMapIteratorProto(JSContext* cx, Handle global) { Rooted base(cx, GlobalObject::getOrCreateIteratorPrototype(cx, global)); @@ -924,7 +924,7 @@ SetIteratorObject::kind() const return SetObject::IteratorKind(i); } -bool +/* static */ bool GlobalObject::initSetIteratorProto(JSContext* cx, Handle global) { Rooted base(cx, GlobalObject::getOrCreateIteratorPrototype(cx, global)); diff --git a/js/src/builtin/ModuleObject.cpp b/js/src/builtin/ModuleObject.cpp index c6bd2d300..3888ad4d3 100644 --- a/js/src/builtin/ModuleObject.cpp +++ b/js/src/builtin/ModuleObject.cpp @@ -103,7 +103,7 @@ GlobalObject::initImportEntryProto(JSContext* cx, Handle global) JS_PS_END }; - RootedObject proto(cx, global->createBlankPrototype(cx)); + RootedObject proto(cx, GlobalObject::createBlankPrototype(cx, global)); if (!proto) return false; @@ -169,7 +169,7 @@ GlobalObject::initExportEntryProto(JSContext* cx, Handle global) JS_PS_END }; - RootedObject proto(cx, global->createBlankPrototype(cx)); + RootedObject proto(cx, GlobalObject::createBlankPrototype(cx, global)); if (!proto) return false; @@ -1020,7 +1020,7 @@ GlobalObject::initModuleProto(JSContext* cx, Handle global) JS_FS_END }; - RootedObject proto(cx, global->createBlankPrototype(cx)); + RootedObject proto(cx, GlobalObject::createBlankPrototype(cx, global)); if (!proto) return false; diff --git a/js/src/builtin/Promise.cpp b/js/src/builtin/Promise.cpp index 9941c6f57..346b2ebc2 100644 --- a/js/src/builtin/Promise.cpp +++ b/js/src/builtin/Promise.cpp @@ -2734,7 +2734,7 @@ PromiseTask::executeAndFinish(JSContext* cx) static JSObject* CreatePromisePrototype(JSContext* cx, JSProtoKey key) { - return cx->global()->createBlankPrototype(cx, &PromiseObject::protoClass_); + return GlobalObject::createBlankPrototype(cx, cx->global(), &PromiseObject::protoClass_); } static const JSFunctionSpec promise_methods[] = { diff --git a/js/src/builtin/Reflect.cpp b/js/src/builtin/Reflect.cpp index 2f509a226..4e7fae78c 100644 --- a/js/src/builtin/Reflect.cpp +++ b/js/src/builtin/Reflect.cpp @@ -268,7 +268,8 @@ static const JSFunctionSpec methods[] = { JSObject* js::InitReflect(JSContext* cx, HandleObject obj) { - RootedObject proto(cx, obj->as().getOrCreateObjectPrototype(cx)); + Handle global = obj.as(); + RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!proto) return nullptr; diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp index 231c58a5d..392046ef1 100644 --- a/js/src/builtin/RegExp.cpp +++ b/js/src/builtin/RegExp.cpp @@ -801,7 +801,7 @@ const JSFunctionSpec js::regexp_methods[] = { name(JSContext* cx, unsigned argc, Value* vp) \ { \ CallArgs args = CallArgsFromVp(argc, vp); \ - RegExpStatics* res = cx->global()->getRegExpStatics(cx); \ + RegExpStatics* res = GlobalObject::getRegExpStatics(cx, cx->global()); \ if (!res) \ return false; \ code; \ @@ -827,7 +827,7 @@ DEFINE_STATIC_GETTER(static_paren9_getter, STATIC_PAREN_GETTER_CODE(9)) static bool \ name(JSContext* cx, unsigned argc, Value* vp) \ { \ - RegExpStatics* res = cx->global()->getRegExpStatics(cx); \ + RegExpStatics* res = GlobalObject::getRegExpStatics(cx, cx->global()); \ if (!res) \ return false; \ code; \ @@ -838,7 +838,7 @@ static bool static_input_setter(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); - RegExpStatics* res = cx->global()->getRegExpStatics(cx); + RegExpStatics* res = GlobalObject::getRegExpStatics(cx, cx->global()); if (!res) return false; @@ -923,7 +923,7 @@ ExecuteRegExp(JSContext* cx, HandleObject regexp, HandleString string, RegExpStatics* res; if (staticsUpdate == UpdateRegExpStatics) { - res = cx->global()->getRegExpStatics(cx); + res = GlobalObject::getRegExpStatics(cx, cx->global()); if (!res) return RegExpRunStatus_Error; } else { diff --git a/js/src/builtin/SIMD.cpp b/js/src/builtin/SIMD.cpp index 2383922db..5fe691152 100644 --- a/js/src/builtin/SIMD.cpp +++ b/js/src/builtin/SIMD.cpp @@ -475,7 +475,7 @@ const Class SimdObject::class_ = { &SimdObjectClassOps }; -bool +/* static */ bool GlobalObject::initSimdObject(JSContext* cx, Handle global) { // SIMD relies on the TypedObject module being initialized. @@ -483,11 +483,11 @@ GlobalObject::initSimdObject(JSContext* cx, Handle global) // to be able to call GetTypedObjectModule(). It is NOT necessary // to install the TypedObjectModule global, but at the moment // those two things are not separable. - if (!global->getOrCreateTypedObjectModule(cx)) + if (!GlobalObject::getOrCreateTypedObjectModule(cx, global)) return false; RootedObject globalSimdObject(cx); - RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx)); + RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!objProto) return false; @@ -510,7 +510,7 @@ static bool CreateSimdType(JSContext* cx, Handle global, HandlePropertyName stringRepr, SimdType simdType, const JSFunctionSpec* methods) { - RootedObject funcProto(cx, global->getOrCreateFunctionPrototype(cx)); + RootedObject funcProto(cx, GlobalObject::getOrCreateFunctionPrototype(cx, global)); if (!funcProto) return false; @@ -531,7 +531,7 @@ CreateSimdType(JSContext* cx, Handle global, HandlePropertyName s return false; // Create prototype property, which inherits from Object.prototype. - RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx)); + RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!objProto) return false; Rooted proto(cx); @@ -551,7 +551,7 @@ CreateSimdType(JSContext* cx, Handle global, HandlePropertyName s } // Bind type descriptor to the global SIMD object - RootedObject globalSimdObject(cx, global->getOrCreateSimdGlobalObject(cx)); + RootedObject globalSimdObject(cx, GlobalObject::getOrCreateSimdGlobalObject(cx, global)); MOZ_ASSERT(globalSimdObject); RootedValue typeValue(cx, ObjectValue(*typeDescr)); @@ -568,7 +568,7 @@ CreateSimdType(JSContext* cx, Handle global, HandlePropertyName s return !!typeDescr; } -bool +/* static */ bool GlobalObject::initSimdType(JSContext* cx, Handle global, SimdType simdType) { #define CREATE_(Type) \ @@ -584,13 +584,13 @@ GlobalObject::initSimdType(JSContext* cx, Handle global, SimdType #undef CREATE_ } -SimdTypeDescr* +/* static */ SimdTypeDescr* GlobalObject::getOrCreateSimdTypeDescr(JSContext* cx, Handle global, SimdType simdType) { MOZ_ASSERT(unsigned(simdType) < unsigned(SimdType::Count), "Invalid SIMD type"); - RootedObject globalSimdObject(cx, global->getOrCreateSimdGlobalObject(cx)); + RootedObject globalSimdObject(cx, GlobalObject::getOrCreateSimdGlobalObject(cx, global)); if (!globalSimdObject) return nullptr; @@ -628,8 +628,8 @@ SimdObject::resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* JSObject* js::InitSimdClass(JSContext* cx, HandleObject obj) { - Rooted global(cx, &obj->as()); - return global->getOrCreateSimdGlobalObject(cx); + Handle global = obj.as(); + return GlobalObject::getOrCreateSimdGlobalObject(cx, global); } template diff --git a/js/src/builtin/SymbolObject.cpp b/js/src/builtin/SymbolObject.cpp index ae38d5371..8fa860ef3 100644 --- a/js/src/builtin/SymbolObject.cpp +++ b/js/src/builtin/SymbolObject.cpp @@ -53,17 +53,17 @@ const JSFunctionSpec SymbolObject::staticMethods[] = { JSObject* SymbolObject::initClass(JSContext* cx, HandleObject obj) { - Rooted global(cx, &obj->as()); + Handle global = obj.as(); // This uses &JSObject::class_ because: "The Symbol prototype object is an // ordinary object. It is not a Symbol instance and does not have a // [[SymbolData]] internal slot." (ES6 rev 24, 19.4.3) - RootedObject proto(cx, global->createBlankPrototype(cx)); + RootedObject proto(cx, GlobalObject::createBlankPrototype(cx, global)); if (!proto) return nullptr; - RootedFunction ctor(cx, global->createConstructor(cx, construct, - ClassName(JSProto_Symbol, cx), 0)); + RootedFunction ctor(cx, GlobalObject::createConstructor(cx, construct, + ClassName(JSProto_Symbol, cx), 0)); if (!ctor) return nullptr; diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index 0dfc1123a..ff3680774 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -1124,11 +1124,11 @@ DefineSimpleTypeDescr(JSContext* cx, typename T::Type type, HandlePropertyName className) { - RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx)); + RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!objProto) return false; - RootedObject funcProto(cx, global->getOrCreateFunctionPrototype(cx)); + RootedObject funcProto(cx, GlobalObject::getOrCreateFunctionPrototype(cx, global)); if (!funcProto) return false; @@ -1185,7 +1185,7 @@ DefineMetaTypeDescr(JSContext* cx, if (!className) return nullptr; - RootedObject funcProto(cx, global->getOrCreateFunctionPrototype(cx)); + RootedObject funcProto(cx, GlobalObject::getOrCreateFunctionPrototype(cx, global)); if (!funcProto) return nullptr; @@ -1197,7 +1197,7 @@ DefineMetaTypeDescr(JSContext* cx, // Create ctor.prototype.prototype, which inherits from Object.__proto__ - RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx)); + RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!objProto) return nullptr; RootedObject protoProto(cx); @@ -1216,7 +1216,7 @@ DefineMetaTypeDescr(JSContext* cx, const int constructorLength = 2; RootedFunction ctor(cx); - ctor = global->createConstructor(cx, T::construct, className, constructorLength); + ctor = GlobalObject::createConstructor(cx, T::construct, className, constructorLength); if (!ctor || !LinkConstructorAndPrototype(cx, ctor, proto) || !DefinePropertiesAndFunctions(cx, proto, @@ -1240,10 +1240,10 @@ DefineMetaTypeDescr(JSContext* cx, * initializer for the `TypedObject` class populate the * `TypedObject` global (which is referred to as "module" herein). */ -bool +/* static */ bool GlobalObject::initTypedObjectModule(JSContext* cx, Handle global) { - RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx)); + RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!objProto) return false; @@ -1317,9 +1317,8 @@ GlobalObject::initTypedObjectModule(JSContext* cx, Handle global) JSObject* js::InitTypedObjectModuleObject(JSContext* cx, HandleObject obj) { - MOZ_ASSERT(obj->is()); - Rooted global(cx, &obj->as()); - return global->getOrCreateTypedObjectModule(cx); + Handle global = obj.as(); + return GlobalObject::getOrCreateTypedObjectModule(cx, global); } /****************************************************************************** diff --git a/js/src/builtin/WeakMapObject.cpp b/js/src/builtin/WeakMapObject.cpp index 555b9e03a..dcfa19776 100644 --- a/js/src/builtin/WeakMapObject.cpp +++ b/js/src/builtin/WeakMapObject.cpp @@ -350,14 +350,14 @@ InitWeakMapClass(JSContext* cx, HandleObject obj, bool defineMembers) { MOZ_ASSERT(obj->isNative()); - Rooted global(cx, &obj->as()); + Handle global = obj.as(); RootedPlainObject proto(cx, NewBuiltinClassInstance(cx)); if (!proto) return nullptr; - RootedFunction ctor(cx, global->createConstructor(cx, WeakMap_construct, - cx->names().WeakMap, 0)); + RootedFunction ctor(cx, GlobalObject::createConstructor(cx, WeakMap_construct, + cx->names().WeakMap, 0)); if (!ctor) return nullptr; diff --git a/js/src/builtin/WeakSetObject.cpp b/js/src/builtin/WeakSetObject.cpp index 7ea3f2fef..fbe5e418c 100644 --- a/js/src/builtin/WeakSetObject.cpp +++ b/js/src/builtin/WeakSetObject.cpp @@ -41,14 +41,15 @@ const JSFunctionSpec WeakSetObject::methods[] = { }; JSObject* -WeakSetObject::initClass(JSContext* cx, JSObject* obj) +WeakSetObject::initClass(JSContext* cx, HandleObject obj) { - Rooted global(cx, &obj->as()); + Handle global = obj.as(); RootedPlainObject proto(cx, NewBuiltinClassInstance(cx)); if (!proto) return nullptr; - Rooted ctor(cx, global->createConstructor(cx, construct, ClassName(JSProto_WeakSet, cx), 0)); + Rooted ctor(cx, GlobalObject::createConstructor(cx, construct, + ClassName(JSProto_WeakSet, cx), 0)); if (!ctor || !LinkConstructorAndPrototype(cx, ctor, proto) || !DefinePropertiesAndFunctions(cx, proto, properties, methods) || diff --git a/js/src/builtin/WeakSetObject.h b/js/src/builtin/WeakSetObject.h index 0a6ff33f3..50e54c182 100644 --- a/js/src/builtin/WeakSetObject.h +++ b/js/src/builtin/WeakSetObject.h @@ -16,7 +16,7 @@ class WeakSetObject : public NativeObject public: static const unsigned RESERVED_SLOTS = 1; - static JSObject* initClass(JSContext* cx, JSObject* obj); + static JSObject* initClass(JSContext* cx, HandleObject obj); static const Class class_; private: diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index fcb711237..573993d5e 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -1053,7 +1053,7 @@ PrepareAndExecuteRegExp(JSContext* cx, MacroAssembler& masm, Register regexp, Re Address pairsVectorAddress(masm.getStackPointer(), pairsVectorStartOffset); - RegExpStatics* res = cx->global()->getRegExpStatics(cx); + RegExpStatics* res = GlobalObject::getRegExpStatics(cx, cx->global()); if (!res) return false; #ifdef JS_USE_LINK_REGISTER diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 4e094adff..28282e384 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -1022,7 +1022,7 @@ JS_ResolveStandardClass(JSContext* cx, HandleObject obj, HandleId id, bool* reso CHECK_REQUEST(cx); assertSameCompartment(cx, obj, id); - Rooted global(cx, &obj->as()); + Handle global = obj.as(); *resolved = false; if (!JSID_IS_ATOM(id)) @@ -1066,10 +1066,7 @@ JS_ResolveStandardClass(JSContext* cx, HandleObject obj, HandleId id, bool* reso // more way: its prototype chain is lazily initialized. That is, // global->getProto() might be null right now because we haven't created // Object.prototype yet. Force it now. - if (!global->getOrCreateObjectPrototype(cx)) - return false; - - return true; + return GlobalObject::getOrCreateObjectPrototype(cx, global); } JS_PUBLIC_API(bool) @@ -1102,8 +1099,7 @@ JS_EnumerateStandardClasses(JSContext* cx, HandleObject obj) AssertHeapIsIdle(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, obj); - MOZ_ASSERT(obj->is()); - Rooted global(cx, &obj->as()); + Handle global = obj.as(); return GlobalObject::initStandardClasses(cx, global); } @@ -1159,7 +1155,8 @@ JS_GetObjectPrototype(JSContext* cx, HandleObject forObj) { CHECK_REQUEST(cx); assertSameCompartment(cx, forObj); - return forObj->global().getOrCreateObjectPrototype(cx); + Rooted global(cx, &forObj->global()); + return GlobalObject::getOrCreateObjectPrototype(cx, global); } JS_PUBLIC_API(JSObject*) @@ -1167,7 +1164,8 @@ JS_GetFunctionPrototype(JSContext* cx, HandleObject forObj) { CHECK_REQUEST(cx); assertSameCompartment(cx, forObj); - return forObj->global().getOrCreateFunctionPrototype(cx); + Rooted global(cx, &forObj->global()); + return GlobalObject::getOrCreateFunctionPrototype(cx, global); } JS_PUBLIC_API(JSObject*) @@ -6015,7 +6013,8 @@ JS_SetRegExpInput(JSContext* cx, HandleObject obj, HandleString input) CHECK_REQUEST(cx); assertSameCompartment(cx, input); - RegExpStatics* res = obj->as().getRegExpStatics(cx); + Handle global = obj.as(); + RegExpStatics* res = GlobalObject::getRegExpStatics(cx, global); if (!res) return false; @@ -6030,7 +6029,8 @@ JS_ClearRegExpStatics(JSContext* cx, HandleObject obj) CHECK_REQUEST(cx); MOZ_ASSERT(obj); - RegExpStatics* res = obj->as().getRegExpStatics(cx); + Handle global = obj.as(); + RegExpStatics* res = GlobalObject::getRegExpStatics(cx, global); if (!res) return false; @@ -6045,7 +6045,8 @@ JS_ExecuteRegExp(JSContext* cx, HandleObject obj, HandleObject reobj, char16_t* AssertHeapIsIdle(cx); CHECK_REQUEST(cx); - RegExpStatics* res = obj->as().getRegExpStatics(cx); + Handle global = obj.as(); + RegExpStatics* res = GlobalObject::getRegExpStatics(cx, global); if (!res) return false; diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index aef98cc60..8bbcac320 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -3246,7 +3246,7 @@ static JSObject* CreateArrayPrototype(JSContext* cx, JSProtoKey key) { MOZ_ASSERT(key == JSProto_Array); - RootedObject proto(cx, cx->global()->getOrCreateObjectPrototype(cx)); + RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, cx->global())); if (!proto) return nullptr; diff --git a/js/src/jsbool.cpp b/js/src/jsbool.cpp index c8109b02c..b2d07c628 100644 --- a/js/src/jsbool.cpp +++ b/js/src/jsbool.cpp @@ -137,14 +137,14 @@ js::InitBooleanClass(JSContext* cx, HandleObject obj) { MOZ_ASSERT(obj->isNative()); - Rooted global(cx, &obj->as()); + Handle global = obj.as(); - Rooted booleanProto(cx, global->createBlankPrototype(cx)); + Rooted booleanProto(cx, GlobalObject::createBlankPrototype(cx, global)); if (!booleanProto) return nullptr; booleanProto->setFixedSlot(BooleanObject::PRIMITIVE_VALUE_SLOT, BooleanValue(false)); - RootedFunction ctor(cx, global->createConstructor(cx, Boolean, cx->names().Boolean, 1)); + RootedFunction ctor(cx, GlobalObject::createConstructor(cx, Boolean, cx->names().Boolean, 1)); if (!ctor) return nullptr; diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp index 52294a5df..c6a369e2d 100755 --- a/js/src/jsdate.cpp +++ b/js/src/jsdate.cpp @@ -3163,7 +3163,7 @@ js::DateConstructor(JSContext* cx, unsigned argc, Value* vp) static JSObject* CreateDatePrototype(JSContext* cx, JSProtoKey key) { - return cx->global()->createBlankPrototype(cx, &DateObject::protoClass_); + return GlobalObject::createBlankPrototype(cx, cx->global(), &DateObject::protoClass_); } static bool diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index 1e70a3890..102e6fb34 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -512,14 +512,17 @@ ErrorObject::createProto(JSContext* cx, JSProtoKey key) { JSExnType type = ExnTypeFromProtoKey(key); - if (type == JSEXN_ERR) - return cx->global()->createBlankPrototype(cx, &ErrorObject::protoClasses[JSEXN_ERR]); + if (type == JSEXN_ERR) { + return GlobalObject::createBlankPrototype(cx, cx->global(), + &ErrorObject::protoClasses[JSEXN_ERR]); + } RootedObject protoProto(cx, GlobalObject::getOrCreateErrorPrototype(cx, cx->global())); if (!protoProto) return nullptr; - return cx->global()->createBlankPrototypeInheriting(cx, &ErrorObject::protoClasses[type], + return GlobalObject::createBlankPrototypeInheriting(cx, cx->global(), + &ErrorObject::protoClasses[type], protoProto); } diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 954fd47a0..3453a59e1 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -379,7 +379,7 @@ ResolveInterpretedFunctionPrototype(JSContext* cx, HandleFunction fun, HandleId if (isStarGenerator) objProto = GlobalObject::getOrCreateStarGeneratorObjectPrototype(cx, global); else - objProto = fun->global().getOrCreateObjectPrototype(cx); + objProto = GlobalObject::getOrCreateObjectPrototype(cx, global); if (!objProto) return false; diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index 84d9a45c3..749e15d27 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -921,7 +921,7 @@ js::CreateItrResultObject(JSContext* cx, HandleValue value, bool done) // FIXME: We can cache the iterator result object shape somewhere. AssertHeapIsIdle(cx); - RootedObject proto(cx, cx->global()->getOrCreateObjectPrototype(cx)); + RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, cx->global())); if (!proto) return nullptr; @@ -1497,7 +1497,7 @@ GlobalObject::initIteratorProto(JSContext* cx, Handle global) if (global->getReservedSlot(ITERATOR_PROTO).isObject()) return true; - RootedObject proto(cx, global->createBlankPrototype(cx)); + RootedObject proto(cx, GlobalObject::createBlankPrototype(cx, global)); if (!proto || !DefinePropertiesAndFunctions(cx, proto, nullptr, iterator_proto_methods)) return false; @@ -1516,7 +1516,8 @@ GlobalObject::initArrayIteratorProto(JSContext* cx, Handle global return false; const Class* cls = &ArrayIteratorPrototypeClass; - RootedObject proto(cx, global->createBlankPrototypeInheriting(cx, cls, iteratorProto)); + RootedObject proto(cx, GlobalObject::createBlankPrototypeInheriting(cx, global, cls, + iteratorProto)); if (!proto || !DefinePropertiesAndFunctions(cx, proto, nullptr, array_iterator_methods) || !DefineToStringTag(cx, proto, cx->names().ArrayIterator)) @@ -1539,7 +1540,8 @@ GlobalObject::initStringIteratorProto(JSContext* cx, Handle globa return false; const Class* cls = &StringIteratorPrototypeClass; - RootedObject proto(cx, global->createBlankPrototypeInheriting(cx, cls, iteratorProto)); + RootedObject proto(cx, GlobalObject::createBlankPrototypeInheriting(cx, global, cls, + iteratorProto)); if (!proto || !DefinePropertiesAndFunctions(cx, proto, nullptr, string_iterator_methods) || !DefineToStringTag(cx, proto, cx->names().StringIterator)) @@ -1560,7 +1562,8 @@ js::InitLegacyIteratorClass(JSContext* cx, HandleObject obj) return &global->getPrototype(JSProto_Iterator).toObject(); RootedObject iteratorProto(cx); - iteratorProto = global->createBlankPrototype(cx, &PropertyIteratorObject::class_); + iteratorProto = GlobalObject::createBlankPrototype(cx, global, + &PropertyIteratorObject::class_); if (!iteratorProto) return nullptr; @@ -1572,7 +1575,7 @@ js::InitLegacyIteratorClass(JSContext* cx, HandleObject obj) ni->init(nullptr, nullptr, 0 /* flags */, 0, 0); Rooted ctor(cx); - ctor = global->createConstructor(cx, IteratorConstructor, cx->names().Iterator, 2); + ctor = GlobalObject::createConstructor(cx, IteratorConstructor, cx->names().Iterator, 2); if (!ctor) return nullptr; if (!LinkConstructorAndPrototype(cx, ctor, iteratorProto)) @@ -1593,7 +1596,8 @@ js::InitStopIterationClass(JSContext* cx, HandleObject obj) { Handle global = obj.as(); if (!global->getPrototype(JSProto_StopIteration).isObject()) { - RootedObject proto(cx, global->createBlankPrototype(cx, &StopIterationObject::class_)); + RootedObject proto(cx, GlobalObject::createBlankPrototype(cx, global, + &StopIterationObject::class_)); if (!proto || !FreezeObject(cx, proto)) return nullptr; diff --git a/js/src/jsmath.cpp b/js/src/jsmath.cpp index 08fbe048c..78a231003 100644 --- a/js/src/jsmath.cpp +++ b/js/src/jsmath.cpp @@ -1417,7 +1417,8 @@ static const JSFunctionSpec math_static_methods[] = { JSObject* js::InitMathClass(JSContext* cx, HandleObject obj) { - RootedObject proto(cx, obj->as().getOrCreateObjectPrototype(cx)); + Handle global = obj.as(); + RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!proto) return nullptr; RootedObject Math(cx, NewObjectWithGivenProto(cx, &MathClass, proto, SingletonObject)); diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp index 28ed15159..bde1f918e 100644 --- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -1005,15 +1005,16 @@ js::InitNumberClass(JSContext* cx, HandleObject obj) /* XXX must do at least once per new thread, so do it per JSContext... */ FIX_FPU(); - Rooted global(cx, &obj->as()); + Handle global = obj.as(); - RootedObject numberProto(cx, global->createBlankPrototype(cx, &NumberObject::class_)); + RootedObject numberProto(cx, GlobalObject::createBlankPrototype(cx, global, + &NumberObject::class_)); if (!numberProto) return nullptr; numberProto->as().setPrimitiveValue(0); RootedFunction ctor(cx); - ctor = global->createConstructor(cx, Number, cx->names().Number, 1); + ctor = GlobalObject::createConstructor(cx, Number, cx->names().Number, 1); if (!ctor) return nullptr; diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 58be1a283..4957b4d39 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -1985,7 +1985,8 @@ js::GetObjectFromIncumbentGlobal(JSContext* cx, MutableHandleObject obj) { AutoCompartment ac(cx, globalObj); - obj.set(globalObj->as().getOrCreateObjectPrototype(cx)); + Handle global = globalObj.as(); + obj.set(GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!obj) return false; } @@ -2548,7 +2549,7 @@ js::SetPrototype(JSContext* cx, HandleObject obj, HandleObject proto, JS::Object // [[Prototype]] chain is always properly immutable, even in the presence // of lazy standard classes. if (obj->is()) { - Rooted global(cx, &obj->as()); + Handle global = obj.as(); if (!GlobalObject::ensureConstructor(cx, global, JSProto_Object)) return false; } diff --git a/js/src/json.cpp b/js/src/json.cpp index 425a2f117..08382b97b 100644 --- a/js/src/json.cpp +++ b/js/src/json.cpp @@ -971,9 +971,9 @@ static const JSFunctionSpec json_static_methods[] = { JSObject* js::InitJSONClass(JSContext* cx, HandleObject obj) { - Rooted global(cx, &obj->as()); + Handle global = obj.as(); - RootedObject proto(cx, global->getOrCreateObjectPrototype(cx)); + RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!proto) return nullptr; RootedObject JSON(cx, NewObjectWithGivenProto(cx, &JSONClass, proto, SingletonObject)); diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 3fecb463d..850db71fe 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -2914,17 +2914,17 @@ js::InitStringClass(JSContext* cx, HandleObject obj) { MOZ_ASSERT(obj->isNative()); - Rooted global(cx, &obj->as()); + Handle global = obj.as(); Rooted empty(cx, cx->runtime()->emptyString); - RootedObject proto(cx, global->createBlankPrototype(cx, &StringObject::class_)); + RootedObject proto(cx, GlobalObject::createBlankPrototype(cx, global, &StringObject::class_)); if (!proto || !proto->as().init(cx, empty)) return nullptr; /* Now create the String function. */ RootedFunction ctor(cx); - ctor = global->createConstructor(cx, StringConstructor, cx->names().String, 1, - AllocKind::FUNCTION, &jit::JitInfo_String); + ctor = GlobalObject::createConstructor(cx, StringConstructor, cx->names().String, 1, + AllocKind::FUNCTION, &jit::JitInfo_String); if (!ctor) return nullptr; diff --git a/js/src/proxy/Proxy.cpp b/js/src/proxy/Proxy.cpp index b43fd02d2..026b40c7b 100644 --- a/js/src/proxy/Proxy.cpp +++ b/js/src/proxy/Proxy.cpp @@ -796,9 +796,9 @@ js::InitProxyClass(JSContext* cx, HandleObject obj) JS_FS_END }; - Rooted global(cx, &obj->as()); + Handle global = obj.as(); RootedFunction ctor(cx); - ctor = global->createConstructor(cx, proxy, cx->names().Proxy, 2); + ctor = GlobalObject::createConstructor(cx, proxy, cx->names().Proxy, 2); if (!ctor) return nullptr; diff --git a/js/src/vm/ArgumentsObject.cpp b/js/src/vm/ArgumentsObject.cpp index 73a9c1ac4..66e0f40a2 100644 --- a/js/src/vm/ArgumentsObject.cpp +++ b/js/src/vm/ArgumentsObject.cpp @@ -214,7 +214,7 @@ ArgumentsObject::createTemplateObject(JSContext* cx, bool mapped) ? &MappedArgumentsObject::class_ : &UnmappedArgumentsObject::class_; - RootedObject proto(cx, cx->global()->getOrCreateObjectPrototype(cx)); + RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, cx->global())); if (!proto) return nullptr; diff --git a/js/src/vm/ArrayBufferObject.cpp b/js/src/vm/ArrayBufferObject.cpp index 2c5e2dd25..392724b21 100644 --- a/js/src/vm/ArrayBufferObject.cpp +++ b/js/src/vm/ArrayBufferObject.cpp @@ -140,7 +140,7 @@ static const Class ArrayBufferObjectProtoClass = { static JSObject* CreateArrayBufferPrototype(JSContext* cx, JSProtoKey key) { - return cx->global()->createBlankPrototype(cx, &ArrayBufferObjectProtoClass); + return GlobalObject::createBlankPrototype(cx, cx->global(), &ArrayBufferObjectProtoClass); } static const ClassOps ArrayBufferObjectClassOps = { diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index b959740ac..63797be38 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -7227,8 +7227,8 @@ static const JSFunctionSpec DebuggerSource_methods[] = { /* static */ NativeObject* DebuggerFrame::initClass(JSContext* cx, HandleObject dbgCtor, HandleObject obj) { - Rooted global(cx, &obj->as()); - RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx)); + Handle global = obj.as(); + RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); return InitClass(cx, dbgCtor, objProto, &class_, construct, 0, properties_, methods_, nullptr, nullptr); @@ -9376,8 +9376,8 @@ const JSFunctionSpec DebuggerObject::methods_[] = { /* static */ NativeObject* DebuggerObject::initClass(JSContext* cx, HandleObject obj, HandleObject debugCtor) { - Rooted global(cx, &obj->as()); - RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx)); + Handle global = obj.as(); + RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); RootedNativeObject objectProto(cx, InitClass(cx, debugCtor, objProto, &class_, construct, 0, properties_, @@ -10577,8 +10577,8 @@ const JSFunctionSpec DebuggerEnvironment::methods_[] = { /* static */ NativeObject* DebuggerEnvironment::initClass(JSContext* cx, HandleObject dbgCtor, HandleObject obj) { - Rooted global(cx, &obj->as()); - RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx)); + Handle global = obj.as(); + RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); return InitClass(cx, dbgCtor, objProto, &DebuggerEnvironment::class_, construct, 0, properties_, methods_, nullptr, nullptr); @@ -10943,9 +10943,9 @@ JS_DefineDebuggerObject(JSContext* cx, HandleObject obj) memoryProto(cx); RootedObject debuggeeWouldRunProto(cx); RootedValue debuggeeWouldRunCtor(cx); - Rooted global(cx, &obj->as()); + Handle global = obj.as(); - objProto = global->getOrCreateObjectPrototype(cx); + objProto = GlobalObject::getOrCreateObjectPrototype(cx, global); if (!objProto) return false; debugProto = InitClass(cx, obj, diff --git a/js/src/vm/GeneratorObject.cpp b/js/src/vm/GeneratorObject.cpp index 82b774a35..ba28501e6 100644 --- a/js/src/vm/GeneratorObject.cpp +++ b/js/src/vm/GeneratorObject.cpp @@ -256,7 +256,7 @@ static const JSFunctionSpec legacy_generator_methods[] = { static JSObject* NewSingletonObjectWithObjectPrototype(JSContext* cx, Handle global) { - RootedObject proto(cx, global->getOrCreateObjectPrototype(cx)); + RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!proto) return nullptr; return NewObjectWithGivenProto(cx, proto, SingletonObject); @@ -265,7 +265,7 @@ NewSingletonObjectWithObjectPrototype(JSContext* cx, Handle globa JSObject* js::NewSingletonObjectWithFunctionPrototype(JSContext* cx, Handle global) { - RootedObject proto(cx, global->getOrCreateFunctionPrototype(cx)); + RootedObject proto(cx, GlobalObject::getOrCreateFunctionPrototype(cx, global)); if (!proto) return nullptr; return NewObjectWithGivenProto(cx, proto, SingletonObject); @@ -297,9 +297,9 @@ GlobalObject::initStarGenerators(JSContext* cx, Handle global) if (!iteratorProto) return false; - RootedObject genObjectProto(cx, global->createBlankPrototypeInheriting(cx, - &PlainObject::class_, - iteratorProto)); + RootedObject genObjectProto(cx, GlobalObject::createBlankPrototypeInheriting(cx, global, + &PlainObject::class_, + iteratorProto)); if (!genObjectProto) return false; if (!DefinePropertiesAndFunctions(cx, genObjectProto, nullptr, star_generator_methods) || diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index c431b5f1d..85707e1c6 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -337,7 +337,7 @@ GlobalObject::createInternal(JSContext* cx, const Class* clasp) return global; } -GlobalObject* +/* static */ GlobalObject* GlobalObject::new_(JSContext* cx, const Class* clasp, JSPrincipals* principals, JS::OnNewGlobalHookOption hookOption, const JS::CompartmentOptions& options) @@ -398,7 +398,7 @@ GlobalObject::emptyGlobalScope() const GlobalObject::getOrCreateEval(JSContext* cx, Handle global, MutableHandleObject eval) { - if (!global->getOrCreateObjectPrototype(cx)) + if (!getOrCreateObjectPrototype(cx, global)) return false; eval.set(&global->getSlot(EVAL).toObject()); return true; @@ -573,7 +573,7 @@ GlobalObject::warnOnceAbout(JSContext* cx, HandleObject obj, WarnOnceFlag flag, return true; } -JSFunction* +/* static */ JSFunction* GlobalObject::createConstructor(JSContext* cx, Native ctor, JSAtom* nameArg, unsigned length, gc::AllocKind kind, const JSJitInfo* jitInfo) { @@ -601,22 +601,21 @@ CreateBlankProto(JSContext* cx, const Class* clasp, HandleObject proto, HandleOb return blankProto; } -NativeObject* -GlobalObject::createBlankPrototype(JSContext* cx, const Class* clasp) +/* static */ NativeObject* +GlobalObject::createBlankPrototype(JSContext* cx, Handle global, const Class* clasp) { - Rooted self(cx, this); - RootedObject objectProto(cx, getOrCreateObjectPrototype(cx)); + RootedObject objectProto(cx, getOrCreateObjectPrototype(cx, global)); if (!objectProto) return nullptr; - return CreateBlankProto(cx, clasp, objectProto, self); + return CreateBlankProto(cx, clasp, objectProto, global); } -NativeObject* -GlobalObject::createBlankPrototypeInheriting(JSContext* cx, const Class* clasp, HandleObject proto) +/* static */ NativeObject* +GlobalObject::createBlankPrototypeInheriting(JSContext* cx, Handle global, + const Class* clasp, HandleObject proto) { - Rooted self(cx, this); - return CreateBlankProto(cx, clasp, proto, self); + return CreateBlankProto(cx, clasp, proto, global); } bool @@ -729,21 +728,20 @@ GlobalObject::hasRegExpStatics() const return !getSlot(REGEXP_STATICS).isUndefined(); } -RegExpStatics* -GlobalObject::getRegExpStatics(ExclusiveContext* cx) const +/* static */ RegExpStatics* +GlobalObject::getRegExpStatics(ExclusiveContext* cx, Handle global) { MOZ_ASSERT(cx); - Rooted self(cx, const_cast(this)); RegExpStaticsObject* resObj = nullptr; - const Value& val = this->getSlot(REGEXP_STATICS); + const Value& val = global->getSlot(REGEXP_STATICS); if (!val.isObject()) { MOZ_ASSERT(val.isUndefined()); - resObj = RegExpStatics::create(cx, self); + resObj = RegExpStatics::create(cx, global); if (!resObj) return nullptr; - self->initSlot(REGEXP_STATICS, ObjectValue(*resObj)); + global->initSlot(REGEXP_STATICS, ObjectValue(*resObj)); } else { resObj = &val.toObject().as(); } @@ -866,7 +864,7 @@ GlobalObject::addIntrinsicValue(JSContext* cx, Handle global, /* static */ bool GlobalObject::ensureModulePrototypesCreated(JSContext *cx, Handle global) { - return global->getOrCreateObject(cx, MODULE_PROTO, initModuleProto) && - global->getOrCreateObject(cx, IMPORT_ENTRY_PROTO, initImportEntryProto) && - global->getOrCreateObject(cx, EXPORT_ENTRY_PROTO, initExportEntryProto); + return getOrCreateObject(cx, global, MODULE_PROTO, initModuleProto) && + getOrCreateObject(cx, global, IMPORT_ENTRY_PROTO, initImportEntryProto) && + getOrCreateObject(cx, global, EXPORT_ENTRY_PROTO, initExportEntryProto); } diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index 3534ef2f6..5aacfc5dc 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -290,8 +290,8 @@ class GlobalObject : public NativeObject * Create a constructor function with the specified name and length using * ctor, a method which creates objects with the given class. */ - JSFunction* - createConstructor(JSContext* cx, JSNative ctor, JSAtom* name, unsigned length, + static JSFunction* + createConstructor(JSContext* cx, JSNative ctor, JSAtom* name, unsigned length, gc::AllocKind kind = gc::AllocKind::FUNCTION, const JSJitInfo* jitInfo = nullptr); @@ -303,48 +303,44 @@ class GlobalObject : public NativeObject * complete the minimal initialization to make the returned object safe to * touch. */ - NativeObject* createBlankPrototype(JSContext* cx, const js::Class* clasp); + static NativeObject* + createBlankPrototype(JSContext* cx, Handle global, const js::Class* clasp); /* * Identical to createBlankPrototype, but uses proto as the [[Prototype]] * of the returned blank prototype. */ - NativeObject* createBlankPrototypeInheriting(JSContext* cx, const js::Class* clasp, - HandleObject proto); + static NativeObject* + createBlankPrototypeInheriting(JSContext* cx, Handle global, + const js::Class* clasp, HandleObject proto); template - T* createBlankPrototype(JSContext* cx) { - NativeObject* res = createBlankPrototype(cx, &T::class_); + static T* + createBlankPrototype(JSContext* cx, Handle global) { + NativeObject* res = createBlankPrototype(cx, global, &T::class_); return res ? &res->template as() : nullptr; } - NativeObject* getOrCreateObjectPrototype(JSContext* cx) { - if (functionObjectClassesInitialized()) - return &getPrototype(JSProto_Object).toObject().as(); - RootedGlobalObject self(cx, this); - if (!ensureConstructor(cx, self, JSProto_Object)) + static NativeObject* + getOrCreateObjectPrototype(JSContext* cx, Handle global) { + if (global->functionObjectClassesInitialized()) + return &global->getPrototype(JSProto_Object).toObject().as(); + if (!ensureConstructor(cx, global, JSProto_Object)) return nullptr; - return &self->getPrototype(JSProto_Object).toObject().as(); - } - - static NativeObject* getOrCreateObjectPrototype(JSContext* cx, Handle global) { - return global->getOrCreateObjectPrototype(cx); + return &global->getPrototype(JSProto_Object).toObject().as(); } - NativeObject* getOrCreateFunctionPrototype(JSContext* cx) { - if (functionObjectClassesInitialized()) - return &getPrototype(JSProto_Function).toObject().as(); - RootedGlobalObject self(cx, this); - if (!ensureConstructor(cx, self, JSProto_Object)) + static NativeObject* + getOrCreateFunctionPrototype(JSContext* cx, Handle global) { + if (global->functionObjectClassesInitialized()) + return &global->getPrototype(JSProto_Function).toObject().as(); + if (!ensureConstructor(cx, global, JSProto_Object)) return nullptr; - return &self->getPrototype(JSProto_Function).toObject().as(); - } - - static NativeObject* getOrCreateFunctionPrototype(JSContext* cx, Handle global) { - return global->getOrCreateFunctionPrototype(cx); + return &global->getPrototype(JSProto_Function).toObject().as(); } - static NativeObject* getOrCreateArrayPrototype(JSContext* cx, Handle global) { + static NativeObject* + getOrCreateArrayPrototype(JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_Array)) return nullptr; return &global->getPrototype(JSProto_Array).toObject().as(); @@ -356,37 +352,43 @@ class GlobalObject : public NativeObject return nullptr; } - static NativeObject* getOrCreateBooleanPrototype(JSContext* cx, Handle global) { + static NativeObject* + getOrCreateBooleanPrototype(JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_Boolean)) return nullptr; return &global->getPrototype(JSProto_Boolean).toObject().as(); } - static NativeObject* getOrCreateNumberPrototype(JSContext* cx, Handle global) { + static NativeObject* + getOrCreateNumberPrototype(JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_Number)) return nullptr; return &global->getPrototype(JSProto_Number).toObject().as(); } - static NativeObject* getOrCreateStringPrototype(JSContext* cx, Handle global) { + static NativeObject* + getOrCreateStringPrototype(JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_String)) return nullptr; return &global->getPrototype(JSProto_String).toObject().as(); } - static NativeObject* getOrCreateSymbolPrototype(JSContext* cx, Handle global) { + static NativeObject* + getOrCreateSymbolPrototype(JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_Symbol)) return nullptr; return &global->getPrototype(JSProto_Symbol).toObject().as(); } - static NativeObject* getOrCreatePromisePrototype(JSContext* cx, Handle global) { + static NativeObject* + getOrCreatePromisePrototype(JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_Promise)) return nullptr; return &global->getPrototype(JSProto_Promise).toObject().as(); } - static NativeObject* getOrCreateRegExpPrototype(JSContext* cx, Handle global) { + static NativeObject* + getOrCreateRegExpPrototype(JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_RegExp)) return nullptr; return &global->getPrototype(JSProto_RegExp).toObject().as(); @@ -398,28 +400,30 @@ class GlobalObject : public NativeObject return nullptr; } - static NativeObject* getOrCreateSavedFramePrototype(JSContext* cx, - Handle global) { + static NativeObject* + getOrCreateSavedFramePrototype(JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_SavedFrame)) return nullptr; return &global->getPrototype(JSProto_SavedFrame).toObject().as(); } - static JSObject* getOrCreateArrayBufferPrototype(JSContext* cx, Handle global) { + static JSObject* + getOrCreateArrayBufferPrototype(JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_ArrayBuffer)) return nullptr; return &global->getPrototype(JSProto_ArrayBuffer).toObject(); } - JSObject* getOrCreateSharedArrayBufferPrototype(JSContext* cx, Handle global) { + static JSObject* + getOrCreateSharedArrayBufferPrototype(JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_SharedArrayBuffer)) return nullptr; return &global->getPrototype(JSProto_SharedArrayBuffer).toObject(); } - static JSObject* getOrCreateCustomErrorPrototype(JSContext* cx, - Handle global, - JSExnType exnType) + static JSObject* + getOrCreateCustomErrorPrototype(JSContext* cx, Handle global, + JSExnType exnType) { JSProtoKey key = GetExceptionProtoKey(exnType); if (!ensureConstructor(cx, global, key)) @@ -439,35 +443,41 @@ class GlobalObject : public NativeObject return getOrCreateCustomErrorPrototype(cx, global, JSEXN_ERR); } - static NativeObject* getOrCreateSetPrototype(JSContext* cx, Handle global) { + static NativeObject* + getOrCreateSetPrototype(JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_Set)) return nullptr; return &global->getPrototype(JSProto_Set).toObject().as(); } - static NativeObject* getOrCreateWeakSetPrototype(JSContext* cx, Handle global) { + static NativeObject* + getOrCreateWeakSetPrototype(JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_WeakSet)) return nullptr; return &global->getPrototype(JSProto_WeakSet).toObject().as(); } - JSObject* getOrCreateIntlObject(JSContext* cx) { - return getOrCreateObject(cx, APPLICATION_SLOTS + JSProto_Intl, initIntlObject); + static JSObject* + getOrCreateIntlObject(JSContext* cx, Handle global) { + return getOrCreateObject(cx, global, APPLICATION_SLOTS + JSProto_Intl, initIntlObject); } - JSObject* getOrCreateTypedObjectModule(JSContext* cx) { - return getOrCreateObject(cx, APPLICATION_SLOTS + JSProto_TypedObject, initTypedObjectModule); + static JSObject* + getOrCreateTypedObjectModule(JSContext* cx, Handle global) { + return getOrCreateObject(cx, global, APPLICATION_SLOTS + JSProto_TypedObject, + initTypedObjectModule); } - JSObject* getOrCreateSimdGlobalObject(JSContext* cx) { - return getOrCreateObject(cx, APPLICATION_SLOTS + JSProto_SIMD, initSimdObject); + static JSObject* + getOrCreateSimdGlobalObject(JSContext* cx, Handle global) { + return getOrCreateObject(cx, global, APPLICATION_SLOTS + JSProto_SIMD, initSimdObject); } // Get the type descriptor for one of the SIMD types. // simdType is one of the JS_SIMDTYPEREPR_* constants. // Implemented in builtin/SIMD.cpp. - static SimdTypeDescr* getOrCreateSimdTypeDescr(JSContext* cx, Handle global, - SimdType simdType); + static SimdTypeDescr* + getOrCreateSimdTypeDescr(JSContext* cx, Handle global, SimdType simdType); TypedObjectModuleObject& getTypedObjectModule() const; @@ -475,16 +485,19 @@ class GlobalObject : public NativeObject return &getPrototype(JSProto_Iterator).toObject(); } - JSObject* getOrCreateCollatorPrototype(JSContext* cx) { - return getOrCreateObject(cx, COLLATOR_PROTO, initIntlObject); + static JSObject* + getOrCreateCollatorPrototype(JSContext* cx, Handle global) { + return getOrCreateObject(cx, global, COLLATOR_PROTO, initIntlObject); } - JSObject* getOrCreateNumberFormatPrototype(JSContext* cx) { - return getOrCreateObject(cx, NUMBER_FORMAT_PROTO, initIntlObject); + static JSObject* + getOrCreateNumberFormatPrototype(JSContext* cx, Handle global) { + return getOrCreateObject(cx, global, NUMBER_FORMAT_PROTO, initIntlObject); } - JSObject* getOrCreateDateTimeFormatPrototype(JSContext* cx) { - return getOrCreateObject(cx, DATE_TIME_FORMAT_PROTO, initIntlObject); + static JSObject* + getOrCreateDateTimeFormatPrototype(JSContext* cx, Handle global) { + return getOrCreateObject(cx, global, DATE_TIME_FORMAT_PROTO, initIntlObject); } static bool ensureModulePrototypesCreated(JSContext *cx, Handle global); @@ -539,88 +552,86 @@ class GlobalObject : public NativeObject private: typedef bool (*ObjectInitOp)(JSContext* cx, Handle global); - JSObject* getOrCreateObject(JSContext* cx, unsigned slot, ObjectInitOp init) { - Value v = getSlotRef(slot); + static JSObject* + getOrCreateObject(JSContext* cx, Handle global, unsigned slot, + ObjectInitOp init) + { + Value v = global->getSlotRef(slot); if (v.isObject()) return &v.toObject(); - RootedGlobalObject self(cx, this); - if (!init(cx, self)) + if (!init(cx, global)) return nullptr; - return &self->getSlot(slot).toObject(); + return &global->getSlot(slot).toObject(); } public: - static NativeObject* getOrCreateIteratorPrototype(JSContext* cx, Handle global) - { - return MaybeNativeObject(global->getOrCreateObject(cx, ITERATOR_PROTO, initIteratorProto)); + static NativeObject* + getOrCreateIteratorPrototype(JSContext* cx, Handle global) { + return MaybeNativeObject(getOrCreateObject(cx, global, ITERATOR_PROTO, initIteratorProto)); } - static NativeObject* getOrCreateArrayIteratorPrototype(JSContext* cx, Handle global) - { - return MaybeNativeObject(global->getOrCreateObject(cx, ARRAY_ITERATOR_PROTO, initArrayIteratorProto)); + static NativeObject* + getOrCreateArrayIteratorPrototype(JSContext* cx, Handle global) { + return MaybeNativeObject(getOrCreateObject(cx, global, ARRAY_ITERATOR_PROTO, + initArrayIteratorProto)); } - static NativeObject* getOrCreateStringIteratorPrototype(JSContext* cx, - Handle global) - { - return MaybeNativeObject(global->getOrCreateObject(cx, STRING_ITERATOR_PROTO, initStringIteratorProto)); + static NativeObject* + getOrCreateStringIteratorPrototype(JSContext* cx, Handle global) { + return MaybeNativeObject(getOrCreateObject(cx, global, STRING_ITERATOR_PROTO, + initStringIteratorProto)); } - static NativeObject* getOrCreateLegacyGeneratorObjectPrototype(JSContext* cx, - Handle global) - { - return MaybeNativeObject(global->getOrCreateObject(cx, LEGACY_GENERATOR_OBJECT_PROTO, - initLegacyGeneratorProto)); + static NativeObject* + getOrCreateLegacyGeneratorObjectPrototype(JSContext* cx, Handle global) { + return MaybeNativeObject(getOrCreateObject(cx, global, LEGACY_GENERATOR_OBJECT_PROTO, + initLegacyGeneratorProto)); } - static NativeObject* getOrCreateStarGeneratorObjectPrototype(JSContext* cx, - Handle global) + static NativeObject* + getOrCreateStarGeneratorObjectPrototype(JSContext* cx, Handle global) { - return MaybeNativeObject(global->getOrCreateObject(cx, STAR_GENERATOR_OBJECT_PROTO, initStarGenerators)); + return MaybeNativeObject(getOrCreateObject(cx, global, STAR_GENERATOR_OBJECT_PROTO, + initStarGenerators)); } - static NativeObject* getOrCreateStarGeneratorFunctionPrototype(JSContext* cx, - Handle global) - { - return MaybeNativeObject(global->getOrCreateObject(cx, STAR_GENERATOR_FUNCTION_PROTO, initStarGenerators)); + static NativeObject* + getOrCreateStarGeneratorFunctionPrototype(JSContext* cx, Handle global) { + return MaybeNativeObject(getOrCreateObject(cx, global, STAR_GENERATOR_FUNCTION_PROTO, + initStarGenerators)); } - static JSObject* getOrCreateStarGeneratorFunction(JSContext* cx, - Handle global) - { - return global->getOrCreateObject(cx, STAR_GENERATOR_FUNCTION, initStarGenerators); + static JSObject* + getOrCreateStarGeneratorFunction(JSContext* cx, Handle global) { + return getOrCreateObject(cx, global, STAR_GENERATOR_FUNCTION, initStarGenerators); } - static NativeObject* getOrCreateAsyncFunctionPrototype(JSContext* cx, - Handle global) - { - return MaybeNativeObject(global->getOrCreateObject(cx, ASYNC_FUNCTION_PROTO, - initAsyncFunction)); + static NativeObject* + getOrCreateAsyncFunctionPrototype(JSContext* cx, Handle global) { + return MaybeNativeObject(getOrCreateObject(cx, global, ASYNC_FUNCTION_PROTO, + initAsyncFunction)); } - static JSObject* getOrCreateAsyncFunction(JSContext* cx, - Handle global) - { - return global->getOrCreateObject(cx, ASYNC_FUNCTION, initAsyncFunction); + static JSObject* + getOrCreateAsyncFunction(JSContext* cx, Handle global) { + return getOrCreateObject(cx, global, ASYNC_FUNCTION, initAsyncFunction); } - static JSObject* getOrCreateMapIteratorPrototype(JSContext* cx, - Handle global) - { - return global->getOrCreateObject(cx, MAP_ITERATOR_PROTO, initMapIteratorProto); + static JSObject* + getOrCreateMapIteratorPrototype(JSContext* cx, Handle global) { + return getOrCreateObject(cx, global, MAP_ITERATOR_PROTO, initMapIteratorProto); } - static JSObject* getOrCreateSetIteratorPrototype(JSContext* cx, - Handle global) - { - return global->getOrCreateObject(cx, SET_ITERATOR_PROTO, initSetIteratorProto); + static JSObject* + getOrCreateSetIteratorPrototype(JSContext* cx, Handle global) { + return getOrCreateObject(cx, global, SET_ITERATOR_PROTO, initSetIteratorProto); } - JSObject* getOrCreateDataViewPrototype(JSContext* cx) { - RootedGlobalObject self(cx, this); - if (!ensureConstructor(cx, self, JSProto_DataView)) + static JSObject* + getOrCreateDataViewPrototype(JSContext* cx, Handle global) { + if (!ensureConstructor(cx, global, JSProto_DataView)) return nullptr; - return &self->getPrototype(JSProto_DataView).toObject(); + return &global->getPrototype(JSProto_DataView).toObject(); } static JSFunction* @@ -678,8 +689,9 @@ class GlobalObject : public NativeObject return true; } - static bool getIntrinsicValue(JSContext* cx, Handle global, - HandlePropertyName name, MutableHandleValue value) + static bool + getIntrinsicValue(JSContext* cx, Handle global, + HandlePropertyName name, MutableHandleValue value) { bool exists = false; if (!GlobalObject::maybeGetIntrinsicValue(cx, global, name, value, &exists)) @@ -709,7 +721,8 @@ class GlobalObject : public NativeObject unsigned nargs, MutableHandleValue funVal); bool hasRegExpStatics() const; - RegExpStatics* getRegExpStatics(ExclusiveContext* cx) const; + static RegExpStatics* getRegExpStatics(ExclusiveContext* cx, + Handle global); RegExpStatics* getAlreadyCreatedRegExpStatics() const; JSObject* getThrowTypeError() const { @@ -996,7 +1009,7 @@ GenericCreateConstructor(JSContext* cx, JSProtoKey key) // Note - We duplicate the trick from ClassName() so that we don't need to // include jsatominlines.h here. PropertyName* name = (&cx->names().Null)[key]; - return cx->global()->createConstructor(cx, ctor, name, length, kind, jitInfo); + return GlobalObject::createConstructor(cx, ctor, name, length, kind, jitInfo); } inline JSObject* @@ -1009,7 +1022,7 @@ GenericCreatePrototype(JSContext* cx, JSProtoKey key) if (!GlobalObject::ensureConstructor(cx, cx->global(), protoKey)) return nullptr; RootedObject parentProto(cx, &cx->global()->getPrototype(protoKey).toObject()); - return cx->global()->createBlankPrototypeInheriting(cx, clasp, parentProto); + return GlobalObject::createBlankPrototypeInheriting(cx, cx->global(), clasp, parentProto); } inline JSProtoKey diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp index e0b44e1eb..6bd7de301 100644 --- a/js/src/vm/RegExpObject.cpp +++ b/js/src/vm/RegExpObject.cpp @@ -199,7 +199,7 @@ RegExpObject::trace(JSTracer* trc, JSObject* obj) static JSObject* CreateRegExpPrototype(JSContext* cx, JSProtoKey key) { - return cx->global()->createBlankPrototype(cx, &RegExpObject::protoClass_); + return GlobalObject::createBlankPrototype(cx, cx->global(), &RegExpObject::protoClass_); } static const ClassOps RegExpObjectClassOps = { diff --git a/js/src/vm/SharedArrayObject.cpp b/js/src/vm/SharedArrayObject.cpp index c69306aac..0dff41201 100644 --- a/js/src/vm/SharedArrayObject.cpp +++ b/js/src/vm/SharedArrayObject.cpp @@ -366,7 +366,8 @@ static const Class SharedArrayBufferObjectProtoClass = { static JSObject* CreateSharedArrayBufferPrototype(JSContext* cx, JSProtoKey key) { - return cx->global()->createBlankPrototype(cx, &SharedArrayBufferObjectProtoClass); + return GlobalObject::createBlankPrototype(cx, cx->global(), + &SharedArrayBufferObjectProtoClass); } static const ClassOps SharedArrayBufferObjectClassOps = { diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp index ae97be0de..8b0302917 100644 --- a/js/src/vm/TypedArrayObject.cpp +++ b/js/src/vm/TypedArrayObject.cpp @@ -361,7 +361,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject return nullptr; const Class* clasp = TypedArrayObject::protoClassForType(ArrayTypeID()); - return global->createBlankPrototypeInheriting(cx, clasp, typedArrayProto); + return GlobalObject::createBlankPrototypeInheriting(cx, global, clasp, typedArrayProto); } static JSObject* @@ -1892,7 +1892,7 @@ DataViewObject::constructWrapped(JSContext* cx, HandleObject bufobj, const CallA Rooted global(cx, cx->compartment()->maybeGlobal()); if (!proto) { - proto = global->getOrCreateDataViewPrototype(cx); + proto = GlobalObject::getOrCreateDataViewPrototype(cx, global); if (!proto) return false; } @@ -2892,12 +2892,13 @@ DataViewObject::initClass(JSContext* cx) if (global->isStandardClassResolved(JSProto_DataView)) return true; - RootedNativeObject proto(cx, global->createBlankPrototype(cx, &DataViewObject::protoClass)); + RootedNativeObject proto(cx, GlobalObject::createBlankPrototype(cx, global, + &DataViewObject::protoClass)); if (!proto) return false; - RootedFunction ctor(cx, global->createConstructor(cx, DataViewObject::class_constructor, - cx->names().DataView, 3)); + RootedFunction ctor(cx, GlobalObject::createConstructor(cx, DataViewObject::class_constructor, + cx->names().DataView, 3)); if (!ctor) return false; diff --git a/js/src/wasm/WasmJS.cpp b/js/src/wasm/WasmJS.cpp index 0b030c844..3fbc81ac5 100644 --- a/js/src/wasm/WasmJS.cpp +++ b/js/src/wasm/WasmJS.cpp @@ -2018,7 +2018,7 @@ js::InitWebAssemblyClass(JSContext* cx, HandleObject obj) Handle global = obj.as(); MOZ_ASSERT(!global->isStandardClassResolved(JSProto_WebAssembly)); - RootedObject proto(cx, global->getOrCreateObjectPrototype(cx)); + RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!proto) return nullptr; -- cgit v1.2.3 From caf39feeeb457ffb143110826a0220211c00afb6 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 23:29:58 -0400 Subject: 1320408 - Part 15: Change NativeObject::addDataProperty to static method. --- js/src/jit/IonAnalysis.cpp | 2 +- js/src/jsstr.cpp | 4 ++-- js/src/vm/ErrorObject.cpp | 8 ++++---- js/src/vm/NativeObject.cpp | 17 ++++++++--------- js/src/vm/NativeObject.h | 8 ++++---- js/src/vm/RegExpObject.cpp | 3 ++- 6 files changed, 21 insertions(+), 21 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index 90fa1864a..5fc624fb1 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -4055,7 +4055,7 @@ AnalyzePoppedThis(JSContext* cx, ObjectGroup* group, // Add the property to the object, being careful not to update type information. DebugOnly slotSpan = baseobj->slotSpan(); MOZ_ASSERT(!baseobj->containsPure(id)); - if (!baseobj->addDataProperty(cx, id, baseobj->slotSpan(), JSPROP_ENUMERATE)) + if (!NativeObject::addDataProperty(cx, baseobj, id, baseobj->slotSpan(), JSPROP_ENUMERATE)) return false; MOZ_ASSERT(baseobj->slotSpan() != slotSpan); MOZ_ASSERT(!baseobj->inDictionaryMode()); diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 850db71fe..fdb62a679 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -2905,8 +2905,8 @@ StringObject::assignInitialShape(ExclusiveContext* cx, Handle obj { MOZ_ASSERT(obj->empty()); - return obj->addDataProperty(cx, cx->names().length, LENGTH_SLOT, - JSPROP_PERMANENT | JSPROP_READONLY); + return NativeObject::addDataProperty(cx, obj, cx->names().length, LENGTH_SLOT, + JSPROP_PERMANENT | JSPROP_READONLY); } JSObject* diff --git a/js/src/vm/ErrorObject.cpp b/js/src/vm/ErrorObject.cpp index d8d29830b..271132801 100644 --- a/js/src/vm/ErrorObject.cpp +++ b/js/src/vm/ErrorObject.cpp @@ -29,11 +29,11 @@ js::ErrorObject::assignInitialShape(ExclusiveContext* cx, Handle o { MOZ_ASSERT(obj->empty()); - if (!obj->addDataProperty(cx, cx->names().fileName, FILENAME_SLOT, 0)) + if (!NativeObject::addDataProperty(cx, obj, cx->names().fileName, FILENAME_SLOT, 0)) return nullptr; - if (!obj->addDataProperty(cx, cx->names().lineNumber, LINENUMBER_SLOT, 0)) + if (!NativeObject::addDataProperty(cx, obj, cx->names().lineNumber, LINENUMBER_SLOT, 0)) return nullptr; - return obj->addDataProperty(cx, cx->names().columnNumber, COLUMNNUMBER_SLOT, 0); + return NativeObject::addDataProperty(cx, obj, cx->names().columnNumber, COLUMNNUMBER_SLOT, 0); } /* static */ bool @@ -57,7 +57,7 @@ js::ErrorObject::init(JSContext* cx, Handle obj, JSExnType type, // |new Error()|. RootedShape messageShape(cx); if (message) { - messageShape = obj->addDataProperty(cx, cx->names().message, MESSAGE_SLOT, 0); + messageShape = NativeObject::addDataProperty(cx, obj, cx->names().message, MESSAGE_SLOT, 0); if (!messageShape) return false; MOZ_ASSERT(messageShape->slot() == MESSAGE_SLOT); diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp index a3f28653a..8940f93c4 100644 --- a/js/src/vm/NativeObject.cpp +++ b/js/src/vm/NativeObject.cpp @@ -996,23 +996,22 @@ NativeObject::freeSlot(ExclusiveContext* cx, uint32_t slot) setSlot(slot, UndefinedValue()); } -Shape* -NativeObject::addDataProperty(ExclusiveContext* cx, jsid idArg, uint32_t slot, unsigned attrs) +/* static */ Shape* +NativeObject::addDataProperty(ExclusiveContext* cx, HandleNativeObject obj, + jsid idArg, uint32_t slot, unsigned attrs) { MOZ_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER))); - RootedNativeObject self(cx, this); RootedId id(cx, idArg); - return addProperty(cx, self, id, nullptr, nullptr, slot, attrs, 0); + return addProperty(cx, obj, id, nullptr, nullptr, slot, attrs, 0); } -Shape* -NativeObject::addDataProperty(ExclusiveContext* cx, HandlePropertyName name, - uint32_t slot, unsigned attrs) +/* static */ Shape* +NativeObject::addDataProperty(ExclusiveContext* cx, HandleNativeObject obj, + HandlePropertyName name, uint32_t slot, unsigned attrs) { MOZ_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER))); - RootedNativeObject self(cx, this); RootedId id(cx, NameToId(name)); - return addProperty(cx, self, id, nullptr, nullptr, slot, attrs, 0); + return addProperty(cx, obj, id, nullptr, nullptr, slot, attrs, 0); } template diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h index 832a701dd..7b240db34 100644 --- a/js/src/vm/NativeObject.h +++ b/js/src/vm/NativeObject.h @@ -741,10 +741,10 @@ class NativeObject : public ShapedObject bool allowDictionary = true); /* Add a data property whose id is not yet in this scope. */ - Shape* addDataProperty(ExclusiveContext* cx, - jsid id_, uint32_t slot, unsigned attrs); - Shape* addDataProperty(ExclusiveContext* cx, HandlePropertyName name, - uint32_t slot, unsigned attrs); + static Shape* addDataProperty(ExclusiveContext* cx, HandleNativeObject obj, + jsid id_, uint32_t slot, unsigned attrs); + static Shape* addDataProperty(ExclusiveContext* cx, HandleNativeObject obj, + HandlePropertyName name, uint32_t slot, unsigned attrs); /* Add or overwrite a property for id in this scope. */ static Shape* diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp index 6bd7de301..1ea67d0bd 100644 --- a/js/src/vm/RegExpObject.cpp +++ b/js/src/vm/RegExpObject.cpp @@ -300,7 +300,8 @@ RegExpObject::assignInitialShape(ExclusiveContext* cx, Handle sel JS_STATIC_ASSERT(LAST_INDEX_SLOT == 0); /* The lastIndex property alone is writable but non-configurable. */ - return self->addDataProperty(cx, cx->names().lastIndex, LAST_INDEX_SLOT, JSPROP_PERMANENT); + return NativeObject::addDataProperty(cx, self, cx->names().lastIndex, LAST_INDEX_SLOT, + JSPROP_PERMANENT); } void -- cgit v1.2.3 From 4c56c51c89a3229e52f4c735d236e956c6b1ab2c Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 23:42:05 -0400 Subject: 1320408 - Part 16: Change NativeObject::removeProperty to static method. --- js/src/vm/NativeObject.cpp | 8 ++++---- js/src/vm/NativeObject.h | 2 +- js/src/vm/Shape.cpp | 47 +++++++++++++++++++++++----------------------- 3 files changed, 28 insertions(+), 29 deletions(-) (limited to 'js/src') diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp index 8940f93c4..eaa47d20a 100644 --- a/js/src/vm/NativeObject.cpp +++ b/js/src/vm/NativeObject.cpp @@ -672,10 +672,10 @@ NativeObject::maybeDensifySparseElements(js::ExclusiveContext* cx, HandleNativeO */ if (shape != obj->lastProperty()) { shape = shape->previous(); - if (!obj->removeProperty(cx, id)) + if (!NativeObject::removeProperty(cx, obj, id)) return DenseElementResult::Failure; } else { - if (!obj->removeProperty(cx, id)) + if (!NativeObject::removeProperty(cx, obj, id)) return DenseElementResult::Failure; shape = obj->lastProperty(); } @@ -1045,7 +1045,7 @@ CallAddPropertyHook(ExclusiveContext* cx, HandleNativeObject obj, HandleShape sh RootedId id(cx, shape->propid()); if (!CallJSAddPropertyOp(cx->asJSContext(), addProperty, obj, id, value)) { - obj->removeProperty(cx, shape->propid()); + NativeObject::removeProperty(cx, obj, shape->propid()); return false; } } @@ -2528,7 +2528,7 @@ js::NativeDeleteProperty(JSContext* cx, HandleNativeObject obj, HandleId id, obj->setDenseElementHole(cx, JSID_TO_INT(id)); } else { - if (!obj->removeProperty(cx, id)) + if (!NativeObject::removeProperty(cx, obj, id)) return false; } diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h index 7b240db34..ea0bf9ab3 100644 --- a/js/src/vm/NativeObject.h +++ b/js/src/vm/NativeObject.h @@ -764,7 +764,7 @@ class NativeObject : public ShapedObject unsigned attrs, JSGetterOp getter, JSSetterOp setter); /* Remove the property named by id from this object. */ - bool removeProperty(ExclusiveContext* cx, jsid id); + static bool removeProperty(ExclusiveContext* cx, HandleNativeObject obj, jsid id); /* Clear the scope, making it empty. */ static void clear(ExclusiveContext* cx, HandleNativeObject obj); diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index 065a96337..a574ac3b5 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -968,16 +968,15 @@ NativeObject::changeProperty(ExclusiveContext* cx, HandleNativeObject obj, Handl return newShape; } -bool -NativeObject::removeProperty(ExclusiveContext* cx, jsid id_) +/* static */ bool +NativeObject::removeProperty(ExclusiveContext* cx, HandleNativeObject obj, jsid id_) { RootedId id(cx, id_); - RootedNativeObject self(cx, this); AutoKeepShapeTables keep(cx); ShapeTable::Entry* entry; RootedShape shape(cx); - if (!Shape::search(cx, lastProperty(), id, keep, shape.address(), &entry)) + if (!Shape::search(cx, obj->lastProperty(), id, keep, shape.address(), &entry)) return false; if (!shape) @@ -987,10 +986,10 @@ NativeObject::removeProperty(ExclusiveContext* cx, jsid id_) * If shape is not the last property added, or the last property cannot * be removed, switch to dictionary mode. */ - if (!self->inDictionaryMode() && (shape != self->lastProperty() || !self->canRemoveLastProperty())) { - if (!self->toDictionaryMode(cx)) + if (!obj->inDictionaryMode() && (shape != obj->lastProperty() || !obj->canRemoveLastProperty())) { + if (!obj->toDictionaryMode(cx)) return false; - ShapeTable* table = self->lastProperty()->maybeTable(keep); + ShapeTable* table = obj->lastProperty()->maybeTable(keep); MOZ_ASSERT(table); entry = &table->search(shape->propid(), keep); shape = entry->shape(); @@ -1004,21 +1003,21 @@ NativeObject::removeProperty(ExclusiveContext* cx, jsid id_) * the object or table, so the remaining removal is infallible. */ RootedShape spare(cx); - if (self->inDictionaryMode()) { + if (obj->inDictionaryMode()) { /* For simplicity, always allocate an accessor shape for now. */ spare = Allocate(cx); if (!spare) return false; new (spare) Shape(shape->base()->unowned(), 0); - if (shape == self->lastProperty()) { + if (shape == obj->lastProperty()) { /* * Get an up to date unowned base shape for the new last property * when removing the dictionary's last property. Information in * base shapes for non-last properties may be out of sync with the * object's state. */ - RootedShape previous(cx, self->lastProperty()->parent); - StackBaseShape base(self->lastProperty()->base()); + RootedShape previous(cx, obj->lastProperty()->parent); + StackBaseShape base(obj->lastProperty()->base()); BaseShape* nbase = BaseShape::getUnowned(cx, base); if (!nbase) return false; @@ -1028,7 +1027,7 @@ NativeObject::removeProperty(ExclusiveContext* cx, jsid id_) /* If shape has a slot, free its slot number. */ if (shape->hasSlot()) { - self->freeSlot(cx, shape->slot()); + obj->freeSlot(cx, shape->slot()); if (cx->isJSContext()) ++cx->asJSContext()->runtime()->propertyRemovals; } @@ -1038,8 +1037,8 @@ NativeObject::removeProperty(ExclusiveContext* cx, jsid id_) * doubly linked list, hashed by lastProperty()->table. So we can edit the * list and hash in place. */ - if (self->inDictionaryMode()) { - ShapeTable* table = self->lastProperty()->maybeTable(keep); + if (obj->inDictionaryMode()) { + ShapeTable* table = obj->lastProperty()->maybeTable(keep); MOZ_ASSERT(table); if (entry->hadCollision()) { @@ -1056,23 +1055,23 @@ NativeObject::removeProperty(ExclusiveContext* cx, jsid id_) * checks not to alter significantly the complexity of the * delete in debug builds, see bug 534493. */ - Shape* aprop = self->lastProperty(); + Shape* aprop = obj->lastProperty(); for (int n = 50; --n >= 0 && aprop->parent; aprop = aprop->parent) - MOZ_ASSERT_IF(aprop != shape, self->contains(cx, aprop)); + MOZ_ASSERT_IF(aprop != shape, obj->contains(cx, aprop)); #endif } { /* Remove shape from its non-circular doubly linked list. */ - Shape* oldLastProp = self->lastProperty(); - shape->removeFromDictionary(self); + Shape* oldLastProp = obj->lastProperty(); + shape->removeFromDictionary(obj); /* Hand off table from the old to new last property. */ - oldLastProp->handoffTableTo(self->lastProperty()); + oldLastProp->handoffTableTo(obj->lastProperty()); } /* Generate a new shape for the object, infallibly. */ - JS_ALWAYS_TRUE(self->generateOwnShape(cx, spare)); + JS_ALWAYS_TRUE(obj->generateOwnShape(cx, spare)); /* Consider shrinking table if its load factor is <= .25. */ uint32_t size = table->capacity(); @@ -1085,11 +1084,11 @@ NativeObject::removeProperty(ExclusiveContext* cx, jsid id_) * lazily make via a later hashify the exact table for the new property * lineage. */ - MOZ_ASSERT(shape == self->lastProperty()); - self->removeLastProperty(cx); + MOZ_ASSERT(shape == obj->lastProperty()); + obj->removeLastProperty(cx); } - self->checkShapeConsistency(); + obj->checkShapeConsistency(); return true; } @@ -1133,7 +1132,7 @@ NativeObject::rollbackProperties(ExclusiveContext* cx, HandleNativeObject obj, u if (slot < slotSpan) break; } - if (!obj->removeProperty(cx, obj->lastProperty()->propid())) + if (!NativeObject::removeProperty(cx, obj, obj->lastProperty()->propid())) return false; } -- cgit v1.2.3 From 08aee2f9d9948c9a4540706d40ea4abf01f452a5 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 23:44:08 -0400 Subject: 1320408 - Part 17: Change NativeObject::clearFlag to static method. --- js/src/vm/NativeObject.cpp | 2 +- js/src/vm/NativeObject.h | 2 +- js/src/vm/Shape.cpp | 13 ++++++------- 3 files changed, 8 insertions(+), 9 deletions(-) (limited to 'js/src') diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp index eaa47d20a..190a19e56 100644 --- a/js/src/vm/NativeObject.cpp +++ b/js/src/vm/NativeObject.cpp @@ -691,7 +691,7 @@ NativeObject::maybeDensifySparseElements(js::ExclusiveContext* cx, HandleNativeO * flag so that we will not start using sparse indexes again if we need * to grow the object. */ - if (!obj->clearFlag(cx, BaseShape::INDEXED)) + if (!NativeObject::clearFlag(cx, obj, BaseShape::INDEXED)) return DenseElementResult::Failure; return DenseElementResult::Success; diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h index ea0bf9ab3..9b8fe4721 100644 --- a/js/src/vm/NativeObject.h +++ b/js/src/vm/NativeObject.h @@ -614,7 +614,7 @@ class NativeObject : public ShapedObject } bool shadowingShapeChange(ExclusiveContext* cx, const Shape& shape); - bool clearFlag(ExclusiveContext* cx, BaseShape::Flag flag); + static bool clearFlag(ExclusiveContext* cx, HandleNativeObject obj, BaseShape::Flag flag); // The maximum number of slots in an object. // |MAX_SLOTS_COUNT * sizeof(JS::Value)| shouldn't overflow diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index a574ac3b5..31cfe382c 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -1240,21 +1240,20 @@ JSObject::setFlags(ExclusiveContext* cx, HandleObject obj, BaseShape::Flag flags return true; } -bool -NativeObject::clearFlag(ExclusiveContext* cx, BaseShape::Flag flag) +/* static */ bool +NativeObject::clearFlag(ExclusiveContext* cx, HandleNativeObject obj, BaseShape::Flag flag) { - MOZ_ASSERT(inDictionaryMode()); + MOZ_ASSERT(obj->inDictionaryMode()); - RootedNativeObject self(cx, &as()); - MOZ_ASSERT(self->lastProperty()->getObjectFlags() & flag); + MOZ_ASSERT(obj->lastProperty()->getObjectFlags() & flag); - StackBaseShape base(self->lastProperty()); + StackBaseShape base(obj->lastProperty()); base.flags &= ~flag; UnownedBaseShape* nbase = BaseShape::getUnowned(cx, base); if (!nbase) return false; - self->lastProperty()->base()->adoptUnowned(nbase); + obj->lastProperty()->base()->adoptUnowned(nbase); return true; } -- cgit v1.2.3 From 761b3afca59ba1c24337ff3afe0c91d005f7718b Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 23:46:41 -0400 Subject: 1320408 - Part 18: Change StringObject::init to static method. --- js/src/jsstr.cpp | 5 ++++- js/src/vm/StringObject-inl.h | 18 ++++++++---------- js/src/vm/StringObject.h | 2 +- 3 files changed, 13 insertions(+), 12 deletions(-) (limited to 'js/src') diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index fdb62a679..74f61b87d 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -2918,7 +2918,10 @@ js::InitStringClass(JSContext* cx, HandleObject obj) Rooted empty(cx, cx->runtime()->emptyString); RootedObject proto(cx, GlobalObject::createBlankPrototype(cx, global, &StringObject::class_)); - if (!proto || !proto->as().init(cx, empty)) + if (!proto) + return nullptr; + Handle protoObj = proto.as(); + if (!StringObject::init(cx, protoObj, empty)) return nullptr; /* Now create the String function. */ diff --git a/js/src/vm/StringObject-inl.h b/js/src/vm/StringObject-inl.h index 5fc1656f6..38191fc7a 100644 --- a/js/src/vm/StringObject-inl.h +++ b/js/src/vm/StringObject-inl.h @@ -15,31 +15,29 @@ namespace js { -inline bool -StringObject::init(JSContext* cx, HandleString str) +/* static */ inline bool +StringObject::init(JSContext* cx, Handle obj, HandleString str) { - MOZ_ASSERT(numFixedSlots() == 2); + MOZ_ASSERT(obj->numFixedSlots() == 2); - Rooted self(cx, this); - - if (!EmptyShape::ensureInitialCustomShape(cx, self)) + if (!EmptyShape::ensureInitialCustomShape(cx, obj)) return false; - MOZ_ASSERT(self->lookup(cx, NameToId(cx->names().length))->slot() == LENGTH_SLOT); + MOZ_ASSERT(obj->lookup(cx, NameToId(cx->names().length))->slot() == LENGTH_SLOT); - self->setStringThis(str); + obj->setStringThis(str); return true; } -inline StringObject* +/* static */ inline StringObject* StringObject::create(JSContext* cx, HandleString str, HandleObject proto, NewObjectKind newKind) { JSObject* obj = NewObjectWithClassProto(cx, &class_, proto, newKind); if (!obj) return nullptr; Rooted strobj(cx, &obj->as()); - if (!strobj->init(cx, str)) + if (!StringObject::init(cx, strobj, str)) return nullptr; return strobj; } diff --git a/js/src/vm/StringObject.h b/js/src/vm/StringObject.h index 119e3d9fa..561e0478a 100644 --- a/js/src/vm/StringObject.h +++ b/js/src/vm/StringObject.h @@ -56,7 +56,7 @@ class StringObject : public NativeObject } private: - inline bool init(JSContext* cx, HandleString str); + static inline bool init(JSContext* cx, Handle obj, HandleString str); void setStringThis(JSString* str) { MOZ_ASSERT(getReservedSlot(PRIMITIVE_VALUE_SLOT).isUndefined()); -- cgit v1.2.3 From 31c0c2f9cc71f8ff1d8c183d38449693ec7ca502 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 8 Jun 2019 23:52:23 -0400 Subject: 1320408 - Part 19: Remove JSContext* parameter from ModuleObject::fixEnvironmentsAfterCompartmentMerge. --- js/src/builtin/ModuleObject.cpp | 2 +- js/src/builtin/ModuleObject.h | 2 +- js/src/vm/HelperThreads.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'js/src') diff --git a/js/src/builtin/ModuleObject.cpp b/js/src/builtin/ModuleObject.cpp index 3888ad4d3..798ef46e1 100644 --- a/js/src/builtin/ModuleObject.cpp +++ b/js/src/builtin/ModuleObject.cpp @@ -788,7 +788,7 @@ AssertModuleScopesMatch(ModuleObject* module) } void -ModuleObject::fixEnvironmentsAfterCompartmentMerge(JSContext* cx) +ModuleObject::fixEnvironmentsAfterCompartmentMerge() { AssertModuleScopesMatch(this); initialEnvironment().fixEnclosingEnvironmentAfterCompartmentMerge(script()->global()); diff --git a/js/src/builtin/ModuleObject.h b/js/src/builtin/ModuleObject.h index d0ed8ed08..e83520ebe 100644 --- a/js/src/builtin/ModuleObject.h +++ b/js/src/builtin/ModuleObject.h @@ -244,7 +244,7 @@ class ModuleObject : public NativeObject #ifdef DEBUG static bool IsFrozen(JSContext* cx, HandleModuleObject self); #endif - void fixEnvironmentsAfterCompartmentMerge(JSContext* cx); + void fixEnvironmentsAfterCompartmentMerge(); JSScript* script() const; Scope* enclosingScope() const; diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp index bd29d0c79..44915521f 100644 --- a/js/src/vm/HelperThreads.cpp +++ b/js/src/vm/HelperThreads.cpp @@ -1291,7 +1291,7 @@ GlobalHelperThreadState::finishModuleParseTask(JSContext* cx, void* token) MOZ_ASSERT(script->module()); RootedModuleObject module(cx, script->module()); - module->fixEnvironmentsAfterCompartmentMerge(cx); + module->fixEnvironmentsAfterCompartmentMerge(); if (!ModuleObject::Freeze(cx, module)) return nullptr; -- cgit v1.2.3 From e1e313f3b6905c39a4b78a2e6cc918238540aeb2 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 9 Jun 2019 00:19:45 -0400 Subject: 1320408 - Part 20: Change PromiseObject::resolve and PromiseObject::reject to static method. --- js/src/builtin/Promise.cpp | 20 ++++++++++---------- js/src/builtin/Promise.h | 6 ++++-- js/src/jsapi.cpp | 4 ++-- js/src/wasm/WasmJS.cpp | 12 ++++++------ 4 files changed, 22 insertions(+), 20 deletions(-) (limited to 'js/src') diff --git a/js/src/builtin/Promise.cpp b/js/src/builtin/Promise.cpp index 346b2ebc2..4210b9cd2 100644 --- a/js/src/builtin/Promise.cpp +++ b/js/src/builtin/Promise.cpp @@ -2631,14 +2631,14 @@ PromiseObject::dependentPromises(JSContext* cx, MutableHandle> v return true; } -bool -PromiseObject::resolve(JSContext* cx, HandleValue resolutionValue) +/* static */ bool +PromiseObject::resolve(JSContext* cx, Handle promise, HandleValue resolutionValue) { - MOZ_ASSERT(!PromiseHasAnyFlag(*this, PROMISE_FLAG_ASYNC)); - if (state() != JS::PromiseState::Pending) + MOZ_ASSERT(!PromiseHasAnyFlag(*promise, PROMISE_FLAG_ASYNC)); + if (promise->state() != JS::PromiseState::Pending) return true; - RootedObject resolveFun(cx, GetResolveFunctionFromPromise(this)); + RootedObject resolveFun(cx, GetResolveFunctionFromPromise(promise)); RootedValue funVal(cx, ObjectValue(*resolveFun)); // For xray'd Promises, the resolve fun may have been created in another @@ -2654,14 +2654,14 @@ PromiseObject::resolve(JSContext* cx, HandleValue resolutionValue) return Call(cx, funVal, UndefinedHandleValue, args, &dummy); } -bool -PromiseObject::reject(JSContext* cx, HandleValue rejectionValue) +/* static */ bool +PromiseObject::reject(JSContext* cx, Handle promise, HandleValue rejectionValue) { - MOZ_ASSERT(!PromiseHasAnyFlag(*this, PROMISE_FLAG_ASYNC)); - if (state() != JS::PromiseState::Pending) + MOZ_ASSERT(!PromiseHasAnyFlag(*promise, PROMISE_FLAG_ASYNC)); + if (promise->state() != JS::PromiseState::Pending) return true; - RootedValue funVal(cx, this->getFixedSlot(PromiseSlot_RejectFunction)); + RootedValue funVal(cx, promise->getFixedSlot(PromiseSlot_RejectFunction)); MOZ_ASSERT(IsCallable(funVal)); FixedInvokeArgs<1> args(cx); diff --git a/js/src/builtin/Promise.h b/js/src/builtin/Promise.h index bb4778631..87d95f154 100644 --- a/js/src/builtin/Promise.h +++ b/js/src/builtin/Promise.h @@ -66,8 +66,10 @@ class PromiseObject : public NativeObject return getFixedSlot(PromiseSlot_ReactionsOrResult); } - MOZ_MUST_USE bool resolve(JSContext* cx, HandleValue resolutionValue); - MOZ_MUST_USE bool reject(JSContext* cx, HandleValue rejectionValue); + static MOZ_MUST_USE bool resolve(JSContext* cx, Handle promise, + HandleValue resolutionValue); + static MOZ_MUST_USE bool reject(JSContext* cx, Handle promise, + HandleValue rejectionValue); void onSettled(JSContext* cx); diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 28282e384..e73865265 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -4925,8 +4925,8 @@ ResolveOrRejectPromise(JSContext* cx, JS::HandleObject promiseObj, JS::HandleVal } return reject - ? promise->reject(cx, resultOrReason) - : promise->resolve(cx, resultOrReason); + ? PromiseObject::reject(cx, promise, resultOrReason) + : PromiseObject::resolve(cx, promise, resultOrReason); } JS_PUBLIC_API(bool) diff --git a/js/src/wasm/WasmJS.cpp b/js/src/wasm/WasmJS.cpp index 3fbc81ac5..8d4f575b2 100644 --- a/js/src/wasm/WasmJS.cpp +++ b/js/src/wasm/WasmJS.cpp @@ -1659,7 +1659,7 @@ Reject(JSContext* cx, const CompileArgs& args, UniqueChars error, HandlegetPendingException(&rejectionValue)) return false; - return promise->reject(cx, rejectionValue); + return PromiseObject::reject(cx, promise, rejectionValue); } RootedObject stack(cx, promise->allocationSite()); @@ -1687,7 +1687,7 @@ Reject(JSContext* cx, const CompileArgs& args, UniqueChars error, Handlereject(cx, rejectionValue); + return PromiseObject::reject(cx, promise, rejectionValue); } static bool @@ -1699,7 +1699,7 @@ ResolveCompilation(JSContext* cx, Module& module, Handle promise return false; RootedValue resolutionValue(cx, ObjectValue(*moduleObj)); - return promise->resolve(cx, resolutionValue); + return PromiseObject::resolve(cx, promise, resolutionValue); } struct CompileTask : PromiseTask @@ -1734,7 +1734,7 @@ RejectWithPendingException(JSContext* cx, Handle promise) if (!GetAndClearException(cx, &rejectionValue)) return false; - return promise->reject(cx, rejectionValue); + return PromiseObject::reject(cx, promise, rejectionValue); } static bool @@ -1822,7 +1822,7 @@ ResolveInstantiation(JSContext* cx, Module& module, HandleObject importObj, return false; val = ObjectValue(*resultObj); - return promise->resolve(cx, val); + return PromiseObject::resolve(cx, promise, val); } struct InstantiateTask : CompileTask @@ -1894,7 +1894,7 @@ WebAssembly_instantiate(JSContext* cx, unsigned argc, Value* vp) return RejectWithPendingException(cx, promise, callArgs); RootedValue resolutionValue(cx, ObjectValue(*instanceObj)); - if (!promise->resolve(cx, resolutionValue)) + if (!PromiseObject::resolve(cx, promise, resolutionValue)) return false; } else { auto task = cx->make_unique(cx, promise, importObj); -- cgit v1.2.3 From bd6819820961aaed4c57949341fedc57feab7403 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 9 Jun 2019 00:37:55 -0400 Subject: 1320408 - Part 21: Change PromiseObject::onSettled to static method. --- js/src/builtin/Promise.cpp | 7 +++---- js/src/builtin/Promise.h | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'js/src') diff --git a/js/src/builtin/Promise.cpp b/js/src/builtin/Promise.cpp index 4210b9cd2..ec7845e89 100644 --- a/js/src/builtin/Promise.cpp +++ b/js/src/builtin/Promise.cpp @@ -603,7 +603,7 @@ ResolvePromise(JSContext* cx, Handle promise, HandleValue valueO // Now that everything else is done, do the things the debugger needs. // Step 7 of RejectPromise implemented in onSettled. - promise->onSettled(cx); + PromiseObject::onSettled(cx, promise); // Step 7 of FulfillPromise. // Step 8 of RejectPromise. @@ -2671,10 +2671,9 @@ PromiseObject::reject(JSContext* cx, Handle promise, HandleValue return Call(cx, funVal, UndefinedHandleValue, args, &dummy); } -void -PromiseObject::onSettled(JSContext* cx) +/* static */ void +PromiseObject::onSettled(JSContext* cx, Handle promise) { - Rooted promise(cx, this); RootedObject stack(cx); if (cx->options().asyncStack() || cx->compartment()->isDebuggee()) { if (!JS::CaptureCurrentStack(cx, &stack, JS::StackCapture(JS::AllFrames()))) { diff --git a/js/src/builtin/Promise.h b/js/src/builtin/Promise.h index 87d95f154..c76dc358c 100644 --- a/js/src/builtin/Promise.h +++ b/js/src/builtin/Promise.h @@ -71,7 +71,7 @@ class PromiseObject : public NativeObject static MOZ_MUST_USE bool reject(JSContext* cx, Handle promise, HandleValue rejectionValue); - void onSettled(JSContext* cx); + static void onSettled(JSContext* cx, Handle promise); double allocationTime() { return getFixedSlot(PromiseSlot_AllocationTime).toNumber(); } double resolutionTime() { return getFixedSlot(PromiseSlot_ResolutionTime).toNumber(); } -- cgit v1.2.3 From 2b0c3663441e51e7ec1fa32411e2339cf81e19b9 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 9 Jun 2019 00:39:54 -0400 Subject: 1320408 - Part 22: Remove JSContext* parameter from ProxyObject::renew and Wrapper::Renew. --- js/src/jswrapper.h | 2 +- js/src/proxy/Proxy.cpp | 2 +- js/src/proxy/Wrapper.cpp | 4 ++-- js/src/vm/ProxyObject.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'js/src') diff --git a/js/src/jswrapper.h b/js/src/jswrapper.h index 84ebe2732..5f3704e32 100644 --- a/js/src/jswrapper.h +++ b/js/src/jswrapper.h @@ -136,7 +136,7 @@ class JS_FRIEND_API(Wrapper) : public BaseProxyHandler static JSObject* New(JSContext* cx, JSObject* obj, const Wrapper* handler, const WrapperOptions& options = WrapperOptions()); - static JSObject* Renew(JSContext* cx, JSObject* existing, JSObject* obj, const Wrapper* handler); + static JSObject* Renew(JSObject* existing, JSObject* obj, const Wrapper* handler); static const Wrapper* wrapperHandler(JSObject* wrapper); diff --git a/js/src/proxy/Proxy.cpp b/js/src/proxy/Proxy.cpp index 026b40c7b..2c1cffb77 100644 --- a/js/src/proxy/Proxy.cpp +++ b/js/src/proxy/Proxy.cpp @@ -774,7 +774,7 @@ js::NewProxyObject(JSContext* cx, const BaseProxyHandler* handler, HandleValue p } void -ProxyObject::renew(JSContext* cx, const BaseProxyHandler* handler, const Value& priv) +ProxyObject::renew(const BaseProxyHandler* handler, const Value& priv) { MOZ_ASSERT(!IsInsideNursery(this)); MOZ_ASSERT_IF(IsCrossCompartmentWrapper(this), IsDeadProxyObject(this)); diff --git a/js/src/proxy/Wrapper.cpp b/js/src/proxy/Wrapper.cpp index 43d559ff3..67f437262 100644 --- a/js/src/proxy/Wrapper.cpp +++ b/js/src/proxy/Wrapper.cpp @@ -312,9 +312,9 @@ Wrapper::New(JSContext* cx, JSObject* obj, const Wrapper* handler, } JSObject* -Wrapper::Renew(JSContext* cx, JSObject* existing, JSObject* obj, const Wrapper* handler) +Wrapper::Renew(JSObject* existing, JSObject* obj, const Wrapper* handler) { - existing->as().renew(cx, handler, ObjectValue(*obj)); + existing->as().renew(handler, ObjectValue(*obj)); return existing; } diff --git a/js/src/vm/ProxyObject.h b/js/src/vm/ProxyObject.h index a0a929b20..d86d72cc9 100644 --- a/js/src/vm/ProxyObject.h +++ b/js/src/vm/ProxyObject.h @@ -104,7 +104,7 @@ class ProxyObject : public ShapedObject public: static unsigned grayLinkExtraSlot(JSObject* obj); - void renew(JSContext* cx, const BaseProxyHandler* handler, const Value& priv); + void renew(const BaseProxyHandler* handler, const Value& priv); static void trace(JSTracer* trc, JSObject* obj); -- cgit v1.2.3 From 72f723f391e5bfb18649d3c26e781c2b0e28e328 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 9 Jun 2019 00:47:09 -0400 Subject: 1320408 - Part 23: Change RegExpObject::{getShared,createShared,dumpBytecode} to static method. --- js/src/builtin/RegExp.cpp | 6 +++--- js/src/builtin/RegExp.h | 2 +- js/src/builtin/TestingFunctions.cpp | 2 +- js/src/jsapi.cpp | 4 ++-- js/src/vm/RegExpObject.cpp | 29 ++++++++++++++--------------- js/src/vm/RegExpObject.h | 11 +++++++---- 6 files changed, 28 insertions(+), 26 deletions(-) (limited to 'js/src') diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp index 392046ef1..7cf20d23c 100644 --- a/js/src/builtin/RegExp.cpp +++ b/js/src/builtin/RegExp.cpp @@ -140,12 +140,12 @@ ExecuteRegExpImpl(JSContext* cx, RegExpStatics* res, RegExpShared& re, HandleLin /* Legacy ExecuteRegExp behavior is baked into the JSAPI. */ bool -js::ExecuteRegExpLegacy(JSContext* cx, RegExpStatics* res, RegExpObject& reobj, +js::ExecuteRegExpLegacy(JSContext* cx, RegExpStatics* res, Handle reobj, HandleLinearString input, size_t* lastIndex, bool test, MutableHandleValue rval) { RegExpGuard shared(cx); - if (!reobj.getShared(cx, &shared)) + if (!RegExpObject::getShared(cx, reobj, &shared)) return false; ScopedMatchPairs matches(&cx->tempLifoAlloc()); @@ -918,7 +918,7 @@ ExecuteRegExp(JSContext* cx, HandleObject regexp, HandleString string, Rooted reobj(cx, ®exp->as()); RegExpGuard re(cx); - if (!reobj->getShared(cx, &re)) + if (!RegExpObject::getShared(cx, reobj, &re)) return RegExpRunStatus_Error; RegExpStatics* res; diff --git a/js/src/builtin/RegExp.h b/js/src/builtin/RegExp.h index 715656f40..4e0ff6948 100644 --- a/js/src/builtin/RegExp.h +++ b/js/src/builtin/RegExp.h @@ -31,7 +31,7 @@ enum RegExpStaticsUpdate { UpdateRegExpStatics, DontUpdateRegExpStatics }; * |chars| and |length|. */ MOZ_MUST_USE bool -ExecuteRegExpLegacy(JSContext* cx, RegExpStatics* res, RegExpObject& reobj, +ExecuteRegExpLegacy(JSContext* cx, RegExpStatics* res, Handle reobj, HandleLinearString input, size_t* lastIndex, bool test, MutableHandleValue rval); diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index f9e4674c8..982c9e386 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -4024,7 +4024,7 @@ DisRegExp(JSContext* cx, unsigned argc, Value* vp) return false; } - if (!reobj->dumpBytecode(cx, match_only, input)) + if (!RegExpObject::dumpBytecode(cx, reobj, match_only, input)) return false; args.rval().setUndefined(); diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index e73865265..6d6eacec2 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -6054,7 +6054,7 @@ JS_ExecuteRegExp(JSContext* cx, HandleObject obj, HandleObject reobj, char16_t* if (!input) return false; - return ExecuteRegExpLegacy(cx, res, reobj->as(), input, indexp, test, rval); + return ExecuteRegExpLegacy(cx, res, reobj.as(), input, indexp, test, rval); } JS_PUBLIC_API(bool) @@ -6068,7 +6068,7 @@ JS_ExecuteRegExpNoStatics(JSContext* cx, HandleObject obj, char16_t* chars, size if (!input) return false; - return ExecuteRegExpLegacy(cx, nullptr, obj->as(), input, indexp, test, + return ExecuteRegExpLegacy(cx, nullptr, obj.as(), input, indexp, test, rval); } diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp index 1ea67d0bd..ef97ed816 100644 --- a/js/src/vm/RegExpObject.cpp +++ b/js/src/vm/RegExpObject.cpp @@ -129,10 +129,10 @@ RegExpSharedReadBarrier(JSContext* cx, RegExpShared* shared) shared->unmarkGray(); } -bool -RegExpObject::getShared(JSContext* cx, RegExpGuard* g) +/* static */ bool +RegExpObject::getShared(JSContext* cx, Handle regexp, RegExpGuard* g) { - if (RegExpShared* shared = maybeShared()) { + if (RegExpShared* shared = regexp->maybeShared()) { // Fetching a RegExpShared from an object requires a read // barrier, as the shared pointer might be weak. RegExpSharedReadBarrier(cx, shared); @@ -141,7 +141,7 @@ RegExpObject::getShared(JSContext* cx, RegExpGuard* g) return true; } - return createShared(cx, g); + return createShared(cx, regexp, g); } /* static */ bool @@ -279,16 +279,14 @@ RegExpObject::create(ExclusiveContext* cx, HandleAtom source, RegExpFlag flags, return regexp; } -bool -RegExpObject::createShared(JSContext* cx, RegExpGuard* g) +/* static */ bool +RegExpObject::createShared(JSContext* cx, Handle regexp, RegExpGuard* g) { - Rooted self(cx, this); - - MOZ_ASSERT(!maybeShared()); - if (!cx->compartment()->regExps.get(cx, getSource(), getFlags(), g)) + MOZ_ASSERT(!regexp->maybeShared()); + if (!cx->compartment()->regExps.get(cx, regexp->getSource(), regexp->getFlags(), g)) return false; - self->setShared(**g); + regexp->setShared(**g); return true; } @@ -892,11 +890,12 @@ RegExpShared::dumpBytecode(JSContext* cx, bool match_only, HandleLinearString in return true; } -bool -RegExpObject::dumpBytecode(JSContext* cx, bool match_only, HandleLinearString input) +/* static */ bool +RegExpObject::dumpBytecode(JSContext* cx, Handle regexp, + bool match_only, HandleLinearString input) { RegExpGuard g(cx); - if (!getShared(cx, &g)) + if (!getShared(cx, regexp, &g)) return false; return g.re()->dumpBytecode(cx, match_only, input); @@ -1431,7 +1430,7 @@ js::CloneRegExpObject(JSContext* cx, JSObject* obj_) Rooted source(cx, regex->getSource()); RegExpGuard g(cx); - if (!regex->getShared(cx, &g)) + if (!RegExpObject::getShared(cx, regex, &g)) return nullptr; clone->initAndZeroLastIndex(source, g->getFlags(), cx); diff --git a/js/src/vm/RegExpObject.h b/js/src/vm/RegExpObject.h index dc428a973..f1ea101ed 100644 --- a/js/src/vm/RegExpObject.h +++ b/js/src/vm/RegExpObject.h @@ -483,7 +483,8 @@ class RegExpObject : public NativeObject static bool isOriginalFlagGetter(JSNative native, RegExpFlag* mask); - bool getShared(JSContext* cx, RegExpGuard* g); + static MOZ_MUST_USE bool getShared(JSContext* cx, Handle regexp, + RegExpGuard* g); void setShared(RegExpShared& shared) { MOZ_ASSERT(!maybeShared()); @@ -500,7 +501,8 @@ class RegExpObject : public NativeObject void initAndZeroLastIndex(HandleAtom source, RegExpFlag flags, ExclusiveContext* cx); #ifdef DEBUG - bool dumpBytecode(JSContext* cx, bool match_only, HandleLinearString input); + static MOZ_MUST_USE bool dumpBytecode(JSContext* cx, Handle regexp, + bool match_only, HandleLinearString input); #endif private: @@ -508,7 +510,8 @@ class RegExpObject : public NativeObject * Precondition: the syntax for |source| has already been validated. * Side effect: sets the private field. */ - bool createShared(JSContext* cx, RegExpGuard* g); + static MOZ_MUST_USE bool createShared(JSContext* cx, Handle regexp, + RegExpGuard* g); RegExpShared* maybeShared() const { return static_cast(NativeObject::getPrivate(PRIVATE_SLOT)); } @@ -531,7 +534,7 @@ inline bool RegExpToShared(JSContext* cx, HandleObject obj, RegExpGuard* g) { if (obj->is()) - return obj->as().getShared(cx, g); + return RegExpObject::getShared(cx, obj.as(), g); return Proxy::regexp_toShared(cx, obj, g); } -- cgit v1.2.3 From fe760880b72f08b75a9adacdcad51d71eac5dfa9 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 9 Jun 2019 00:58:44 -0400 Subject: 1320408 - Part 24: Change NativeObject::{fillInAfterSwap,replaceWithNewEquivalentShape,generateOwnShape,shadowingShapeChange} to static method. --- js/src/jsobj.cpp | 49 +++++++++++++++++++++++++--------------------- js/src/vm/NativeObject.cpp | 2 +- js/src/vm/NativeObject.h | 16 +++++++++------ js/src/vm/Shape.cpp | 49 ++++++++++++++++++++++------------------------ 4 files changed, 61 insertions(+), 55 deletions(-) (limited to 'js/src') diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 4957b4d39..6f9596924 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -1430,40 +1430,41 @@ js::XDRObjectLiteral(XDRState* xdr, MutableHandleObject obj); template bool js::XDRObjectLiteral(XDRState* xdr, MutableHandleObject obj); -bool -NativeObject::fillInAfterSwap(JSContext* cx, const Vector& values, void* priv) +/* static */ bool +NativeObject::fillInAfterSwap(JSContext* cx, HandleNativeObject obj, + const Vector& values, void* priv) { // This object has just been swapped with some other object, and its shape // no longer reflects its allocated size. Correct this information and // fill the slots in with the specified values. - MOZ_ASSERT(slotSpan() == values.length()); + MOZ_ASSERT(obj->slotSpan() == values.length()); // Make sure the shape's numFixedSlots() is correct. - size_t nfixed = gc::GetGCKindSlots(asTenured().getAllocKind(), getClass()); - if (nfixed != shape_->numFixedSlots()) { - if (!generateOwnShape(cx)) + size_t nfixed = gc::GetGCKindSlots(obj->asTenured().getAllocKind(), obj->getClass()); + if (nfixed != obj->shape_->numFixedSlots()) { + if (!NativeObject::generateOwnShape(cx, obj)) return false; - shape_->setNumFixedSlots(nfixed); + obj->shape_->setNumFixedSlots(nfixed); } - if (hasPrivate()) - setPrivate(priv); + if (obj->hasPrivate()) + obj->setPrivate(priv); else MOZ_ASSERT(!priv); - if (slots_) { - js_free(slots_); - slots_ = nullptr; + if (obj->slots_) { + js_free(obj->slots_); + obj->slots_ = nullptr; } - if (size_t ndynamic = dynamicSlotsCount(nfixed, values.length(), getClass())) { - slots_ = cx->zone()->pod_malloc(ndynamic); - if (!slots_) + if (size_t ndynamic = dynamicSlotsCount(nfixed, values.length(), obj->getClass())) { + obj->slots_ = cx->zone()->pod_malloc(ndynamic); + if (!obj->slots_) return false; - Debug_SetSlotRangeToCrashOnTouch(slots_, ndynamic); + Debug_SetSlotRangeToCrashOnTouch(obj->slots_, ndynamic); } - initSlotRange(0, values.begin(), values.length()); + obj->initSlotRange(0, values.begin(), values.length()); return true; } @@ -1573,10 +1574,14 @@ JSObject::swap(JSContext* cx, HandleObject a, HandleObject b) a->fixDictionaryShapeAfterSwap(); b->fixDictionaryShapeAfterSwap(); - if (na && !b->as().fillInAfterSwap(cx, avals, apriv)) - oomUnsafe.crash("fillInAfterSwap"); - if (nb && !a->as().fillInAfterSwap(cx, bvals, bpriv)) - oomUnsafe.crash("fillInAfterSwap"); + if (na) { + if (!NativeObject::fillInAfterSwap(cx, b.as(), avals, apriv)) + oomUnsafe.crash("fillInAfterSwap"); + } + if (nb) { + if (!NativeObject::fillInAfterSwap(cx, a.as(), bvals, bpriv)) + oomUnsafe.crash("fillInAfterSwap"); + } } // Swapping the contents of two objects invalidates type sets which contain @@ -1839,7 +1844,7 @@ js::SetClassAndProto(JSContext* cx, HandleObject obj, // We always generate a new shape if the object is a singleton, // regardless of the uncacheable-proto flag. ICs may rely on // this. - if (!oldproto->as().generateOwnShape(cx)) + if (!NativeObject::generateOwnShape(cx, oldproto.as())) return false; } else { if (!JSObject::setUncacheableProto(cx, oldproto)) diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp index 190a19e56..da0f59fe2 100644 --- a/js/src/vm/NativeObject.cpp +++ b/js/src/vm/NativeObject.cpp @@ -1117,7 +1117,7 @@ PurgeProtoChain(ExclusiveContext* cx, JSObject* objArg, HandleId id) shape = obj->as().lookup(cx, id); if (shape) - return obj->as().shadowingShapeChange(cx, *shape); + return NativeObject::shadowingShapeChange(cx, obj.as(), *shape); obj = obj->staticPrototype(); } diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h index 9b8fe4721..656542100 100644 --- a/js/src/vm/NativeObject.h +++ b/js/src/vm/NativeObject.h @@ -491,8 +491,8 @@ class NativeObject : public ShapedObject void checkShapeConsistency() { } #endif - Shape* - replaceWithNewEquivalentShape(ExclusiveContext* cx, + static Shape* + replaceWithNewEquivalentShape(ExclusiveContext* cx, HandleNativeObject obj, Shape* existingShape, Shape* newShape = nullptr, bool accessorShape = false); @@ -609,11 +609,14 @@ class NativeObject : public ShapedObject } public: - bool generateOwnShape(ExclusiveContext* cx, Shape* newShape = nullptr) { - return replaceWithNewEquivalentShape(cx, lastProperty(), newShape); + static MOZ_MUST_USE bool generateOwnShape(ExclusiveContext* cx, HandleNativeObject obj, + Shape* newShape = nullptr) + { + return replaceWithNewEquivalentShape(cx, obj, obj->lastProperty(), newShape); } - bool shadowingShapeChange(ExclusiveContext* cx, const Shape& shape); + static MOZ_MUST_USE bool shadowingShapeChange(ExclusiveContext* cx, HandleNativeObject obj, + const Shape& shape); static bool clearFlag(ExclusiveContext* cx, HandleNativeObject obj, BaseShape::Flag flag); // The maximum number of slots in an object. @@ -783,7 +786,8 @@ class NativeObject : public ShapedObject unsigned flags, ShapeTable::Entry* entry, bool allowDictionary, const AutoKeepShapeTables& keep); - bool fillInAfterSwap(JSContext* cx, const Vector& values, void* priv); + static MOZ_MUST_USE bool fillInAfterSwap(JSContext* cx, HandleNativeObject obj, + const Vector& values, void* priv); public: // Return true if this object has been converted from shared-immutable diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index 31cfe382c..448502805 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -853,10 +853,11 @@ NativeObject::putProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId */ bool updateLast = (shape == obj->lastProperty()); bool accessorShape = getter || setter || (attrs & (JSPROP_GETTER | JSPROP_SETTER)); - shape = obj->replaceWithNewEquivalentShape(cx, shape, nullptr, accessorShape); + shape = NativeObject::replaceWithNewEquivalentShape(cx, obj, shape, nullptr, + accessorShape); if (!shape) return nullptr; - if (!updateLast && !obj->generateOwnShape(cx)) + if (!updateLast && !NativeObject::generateOwnShape(cx, obj)) return nullptr; /* @@ -1071,7 +1072,7 @@ NativeObject::removeProperty(ExclusiveContext* cx, HandleNativeObject obj, jsid } /* Generate a new shape for the object, infallibly. */ - JS_ALWAYS_TRUE(obj->generateOwnShape(cx, spare)); + JS_ALWAYS_TRUE(NativeObject::generateOwnShape(cx, obj, spare)); /* Consider shrinking table if its load factor is <= .25. */ uint32_t size = table->capacity(); @@ -1139,28 +1140,23 @@ NativeObject::rollbackProperties(ExclusiveContext* cx, HandleNativeObject obj, u return true; } -Shape* -NativeObject::replaceWithNewEquivalentShape(ExclusiveContext* cx, Shape* oldShape, Shape* newShape, - bool accessorShape) +/* static */ Shape* +NativeObject::replaceWithNewEquivalentShape(ExclusiveContext* cx, HandleNativeObject obj, + Shape* oldShape, Shape* newShape, bool accessorShape) { MOZ_ASSERT(cx->isInsideCurrentZone(oldShape)); - MOZ_ASSERT_IF(oldShape != lastProperty(), - inDictionaryMode() && lookup(cx, oldShape->propidRef()) == oldShape); - - NativeObject* self = this; + MOZ_ASSERT_IF(oldShape != obj->lastProperty(), + obj->inDictionaryMode() && obj->lookup(cx, oldShape->propidRef()) == oldShape); - if (!inDictionaryMode()) { - RootedNativeObject selfRoot(cx, self); + if (!obj->inDictionaryMode()) { RootedShape newRoot(cx, newShape); - if (!toDictionaryMode(cx)) + if (!obj->toDictionaryMode(cx)) return nullptr; - oldShape = selfRoot->lastProperty(); - self = selfRoot; + oldShape = obj->lastProperty(); newShape = newRoot; } if (!newShape) { - RootedNativeObject selfRoot(cx, self); RootedShape oldRoot(cx, oldShape); newShape = (oldShape->isAccessorShape() || accessorShape) ? Allocate(cx) @@ -1168,12 +1164,11 @@ NativeObject::replaceWithNewEquivalentShape(ExclusiveContext* cx, Shape* oldShap if (!newShape) return nullptr; new (newShape) Shape(oldRoot->base()->unowned(), 0); - self = selfRoot; oldShape = oldRoot; } AutoCheckCannotGC nogc; - ShapeTable* table = self->lastProperty()->ensureTableForDictionary(cx, nogc); + ShapeTable* table = obj->lastProperty()->ensureTableForDictionary(cx, nogc); if (!table) return nullptr; @@ -1186,12 +1181,12 @@ NativeObject::replaceWithNewEquivalentShape(ExclusiveContext* cx, Shape* oldShap * enumeration order (see bug 601399). */ StackShape nshape(oldShape); - newShape->initDictionaryShape(nshape, self->numFixedSlots(), oldShape->listp); + newShape->initDictionaryShape(nshape, obj->numFixedSlots(), oldShape->listp); MOZ_ASSERT(newShape->parent == oldShape); - oldShape->removeFromDictionary(self); + oldShape->removeFromDictionary(obj); - if (newShape == self->lastProperty()) + if (newShape == obj->lastProperty()) oldShape->handoffTableTo(newShape); if (entry) @@ -1199,10 +1194,10 @@ NativeObject::replaceWithNewEquivalentShape(ExclusiveContext* cx, Shape* oldShap return newShape; } -bool -NativeObject::shadowingShapeChange(ExclusiveContext* cx, const Shape& shape) +/* static */ bool +NativeObject::shadowingShapeChange(ExclusiveContext* cx, HandleNativeObject obj, const Shape& shape) { - return generateOwnShape(cx); + return generateOwnShape(cx, obj); } /* static */ bool @@ -1217,8 +1212,10 @@ JSObject::setFlags(ExclusiveContext* cx, HandleObject obj, BaseShape::Flag flags return false; if (obj->isNative() && obj->as().inDictionaryMode()) { - if (generateShape == GENERATE_SHAPE && !obj->as().generateOwnShape(cx)) - return false; + if (generateShape == GENERATE_SHAPE) { + if (!NativeObject::generateOwnShape(cx, obj.as())) + return false; + } StackBaseShape base(obj->as().lastProperty()); base.flags |= flags; UnownedBaseShape* nbase = BaseShape::getUnowned(cx, base); -- cgit v1.2.3 From eb6c9ea6bb78bbcbc9c4a74830649527f4df980a Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 9 Jun 2019 01:02:39 -0400 Subject: 1320408 - Part 25: Change NativeObject::toDictionaryMode to static method. --- js/src/vm/NativeObject.h | 2 +- js/src/vm/Shape.cpp | 34 ++++++++++++++++------------------ 2 files changed, 17 insertions(+), 19 deletions(-) (limited to 'js/src') diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h index 656542100..d0279556d 100644 --- a/js/src/vm/NativeObject.h +++ b/js/src/vm/NativeObject.h @@ -510,7 +510,7 @@ class NativeObject : public ShapedObject */ bool setSlotSpan(ExclusiveContext* cx, uint32_t span); - bool toDictionaryMode(ExclusiveContext* cx); + static MOZ_MUST_USE bool toDictionaryMode(ExclusiveContext* cx, HandleNativeObject obj); private: friend class TenuringTracer; diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index 448502805..8fe2145e5 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -460,15 +460,13 @@ NativeObject::getChildProperty(ExclusiveContext* cx, return shape; } -bool -js::NativeObject::toDictionaryMode(ExclusiveContext* cx) +/* static */ bool +js::NativeObject::toDictionaryMode(ExclusiveContext* cx, HandleNativeObject obj) { - MOZ_ASSERT(!inDictionaryMode()); - MOZ_ASSERT(cx->isInsideCurrentCompartment(this)); + MOZ_ASSERT(!obj->inDictionaryMode()); + MOZ_ASSERT(cx->isInsideCurrentCompartment(obj)); - uint32_t span = slotSpan(); - - Rooted self(cx, this); + uint32_t span = obj->slotSpan(); // Clone the shapes into a new dictionary list. Don't update the last // property of this object until done, otherwise a GC triggered while @@ -476,7 +474,7 @@ js::NativeObject::toDictionaryMode(ExclusiveContext* cx) RootedShape root(cx); RootedShape dictionaryShape(cx); - RootedShape shape(cx, lastProperty()); + RootedShape shape(cx, obj->lastProperty()); while (shape) { MOZ_ASSERT(!shape->inDictionary()); @@ -488,7 +486,7 @@ js::NativeObject::toDictionaryMode(ExclusiveContext* cx) GCPtrShape* listp = dictionaryShape ? &dictionaryShape->parent : nullptr; StackShape child(shape); - dprop->initDictionaryShape(child, self->numFixedSlots(), listp); + dprop->initDictionaryShape(child, obj->numFixedSlots(), listp); if (!dictionaryShape) root = dprop; @@ -503,18 +501,18 @@ js::NativeObject::toDictionaryMode(ExclusiveContext* cx) return false; } - if (IsInsideNursery(self) && - !cx->asJSContext()->gc.nursery.queueDictionaryModeObjectToSweep(self)) + if (IsInsideNursery(obj) && + !cx->asJSContext()->gc.nursery.queueDictionaryModeObjectToSweep(obj)) { ReportOutOfMemory(cx); return false; } MOZ_ASSERT(root->listp == nullptr); - root->listp = &self->shape_; - self->shape_ = root; + root->listp = &obj->shape_; + obj->shape_ = root; - MOZ_ASSERT(self->inDictionaryMode()); + MOZ_ASSERT(obj->inDictionaryMode()); root->base()->setSlotSpan(span); return true; @@ -592,7 +590,7 @@ NativeObject::addPropertyInternal(ExclusiveContext* cx, if (allowDictionary && (!stableSlot || ShouldConvertToDictionary(obj))) { - if (!obj->toDictionaryMode(cx)) + if (!toDictionaryMode(cx, obj)) return nullptr; table = obj->lastProperty()->maybeTable(keep); entry = &table->search(id, keep); @@ -834,7 +832,7 @@ NativeObject::putProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId * addPropertyInternal because a failure under add would lose data. */ if (shape != obj->lastProperty() && !obj->inDictionaryMode()) { - if (!obj->toDictionaryMode(cx)) + if (!toDictionaryMode(cx, obj)) return nullptr; ShapeTable* table = obj->lastProperty()->maybeTable(keep); MOZ_ASSERT(table); @@ -988,7 +986,7 @@ NativeObject::removeProperty(ExclusiveContext* cx, HandleNativeObject obj, jsid * be removed, switch to dictionary mode. */ if (!obj->inDictionaryMode() && (shape != obj->lastProperty() || !obj->canRemoveLastProperty())) { - if (!obj->toDictionaryMode(cx)) + if (!toDictionaryMode(cx, obj)) return false; ShapeTable* table = obj->lastProperty()->maybeTable(keep); MOZ_ASSERT(table); @@ -1150,7 +1148,7 @@ NativeObject::replaceWithNewEquivalentShape(ExclusiveContext* cx, HandleNativeOb if (!obj->inDictionaryMode()) { RootedShape newRoot(cx, newShape); - if (!obj->toDictionaryMode(cx)) + if (!toDictionaryMode(cx, obj)) return nullptr; oldShape = obj->lastProperty(); newShape = newRoot; -- cgit v1.2.3 From 3f8364e4a0342be52555adf9ae13999dc8244d1b Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 9 Jun 2019 01:03:19 -0400 Subject: 1320408 - Part 26: Remove Shape::set declaration. --- js/src/vm/Shape.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'js/src') diff --git a/js/src/vm/Shape.h b/js/src/vm/Shape.h index 978798aaa..fd6d843e0 100644 --- a/js/src/vm/Shape.h +++ b/js/src/vm/Shape.h @@ -905,9 +905,6 @@ class Shape : public gc::TenuredCell setter() == rawSetter; } - bool set(JSContext* cx, HandleNativeObject obj, HandleObject receiver, MutableHandleValue vp, - ObjectOpResult& result); - BaseShape* base() const { return base_.get(); } bool hasSlot() const { -- cgit v1.2.3 From c75bd3037aa32d4a2a574feda15f43635bc0c01c Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 9 Jun 2019 01:33:48 -0400 Subject: 1337143 - Tweak NamedImports parsing to eliminate a complexifying peekToken where getToken could be used. --- js/src/frontend/Parser.cpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 0ff10f73f..abb2d51ad 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -4663,12 +4663,11 @@ bool Parser::namedImportsOrNamespaceImport(TokenKind tt, Node importSpecSet) { if (tt == TOK_LC) { - TokenStream::Modifier modifier = TokenStream::KeywordIsName; while (true) { // Handle the forms |import {} from 'a'| and // |import { ..., } from 'a'| (where ... is non empty), by // escaping the loop early if the next token is }. - if (!tokenStream.peekToken(&tt, TokenStream::KeywordIsName)) + if (!tokenStream.getToken(&tt, TokenStream::KeywordIsName)) return false; if (tt == TOK_RC) @@ -4677,7 +4676,11 @@ Parser::namedImportsOrNamespaceImport(TokenKind tt, Node impor // If the next token is a keyword, the previous call to // peekToken matched it as a TOK_NAME, and put it in the // lookahead buffer, so this call will match keywords as well. - MUST_MATCH_TOKEN_MOD(TOK_NAME, TokenStream::KeywordIsName, JSMSG_NO_IMPORT_NAME); + if (tt != TOK_NAME) { + error(JSMSG_NO_IMPORT_NAME); + return false; + } + Rooted importName(context, tokenStream.currentName()); TokenPos importNamePos = pos(); @@ -4735,17 +4738,18 @@ Parser::namedImportsOrNamespaceImport(TokenKind tt, Node impor handler.addList(importSpecSet, importSpec); - bool matched; - if (!tokenStream.matchToken(&matched, TOK_COMMA)) + TokenKind next; + if (!tokenStream.getToken(&next)) return false; - if (!matched) { - modifier = TokenStream::None; + if (next == TOK_RC) break; + + if (next != TOK_COMMA) { + error(JSMSG_RC_AFTER_IMPORT_SPEC_LIST); + return false; } } - - MUST_MATCH_TOKEN_MOD(TOK_RC, modifier, JSMSG_RC_AFTER_IMPORT_SPEC_LIST); } else { MOZ_ASSERT(tt == TOK_MUL); if (!tokenStream.getToken(&tt)) -- cgit v1.2.3 From d200a2b02e50b33511ff2ea26a2968301f06b170 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 9 Jun 2019 01:35:28 -0400 Subject: 1337143 - Tweak ExportClause parsing to eliminate a peekToken where a simpler consuming getToken could be performed. --- js/src/frontend/Parser.cpp | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index abb2d51ad..7e43bc3b5 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -4990,12 +4990,17 @@ Parser::exportDeclaration() // Handle the forms |export {}| and |export { ..., }| (where ... // is non empty), by escaping the loop early if the next token // is }. - if (!tokenStream.peekToken(&tt)) + if (!tokenStream.getToken(&tt)) return null(); + if (tt == TOK_RC) break; - MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_BINDING_NAME); + if (tt != TOK_NAME) { + error(JSMSG_NO_BINDING_NAME); + return null(); + } + Node bindingName = newName(tokenStream.currentName()); if (!bindingName) return null(); @@ -5019,14 +5024,18 @@ Parser::exportDeclaration() handler.addList(kid, exportSpec); - bool matched; - if (!tokenStream.matchToken(&matched, TOK_COMMA)) + TokenKind next; + if (!tokenStream.getToken(&next)) return null(); - if (!matched) + + if (next == TOK_RC) break; - } - MUST_MATCH_TOKEN(TOK_RC, JSMSG_RC_AFTER_EXPORT_SPEC_LIST); + if (next != TOK_COMMA) { + error(JSMSG_RC_AFTER_EXPORT_SPEC_LIST); + return null(); + } + } // Careful! If |from| follows, even on a new line, it must start a // FromClause: -- cgit v1.2.3 From d27591806950034d8d3763a13db6f2c201311991 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 9 Jun 2019 01:48:29 -0400 Subject: 1339137 - Don't do Annex B lexical function behavior when redeclaring a parameter name in a function with parameter expressions. --- js/src/frontend/Parser.cpp | 26 +++++++++++++++++----- .../block-scoped-functions-annex-b-parameter.js | 5 +++++ js/src/vm/Scope.cpp | 8 +++++++ js/src/vm/Scope.h | 11 +++++---- 4 files changed, 41 insertions(+), 9 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 7e43bc3b5..2e13910df 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -1211,6 +1211,25 @@ Parser::tryDeclareVarForAnnexBLexicalFunction(HandlePropertyName n if (!tryDeclareVar(name, DeclarationKind::VarForAnnexBLexicalFunction, &redeclaredKind)) return false; + if (!redeclaredKind && pc->isFunctionBox()) { + ParseContext::Scope& funScope = pc->functionScope(); + ParseContext::Scope& varScope = pc->varScope(); + if (&funScope != &varScope) { + // Annex B.3.3.1 disallows redeclaring parameter names. In the + // presence of parameter expressions, parameter names are on the + // function scope, which encloses the var scope. This means + // tryDeclareVar call above would not catch this case, so test it + // manually. + if (AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(name)) { + DeclarationKind declaredKind = p->value()->kind(); + if (DeclarationKindIsParameter(declaredKind)) + redeclaredKind = Some(declaredKind); + else + MOZ_ASSERT(FunctionScope::isSpecialName(context, name)); + } + } + } + if (redeclaredKind) { // If an early error would have occurred, undo all the // VarForAnnexBLexicalFunction declarations. @@ -1751,11 +1770,8 @@ Parser::newFunctionScopeData(ParseContext::Scope& scope, bool case BindingKind::Var: // The only vars in the function scope when there are parameter // exprs, which induces a separate var environment, should be the - // special internal bindings. - MOZ_ASSERT_IF(hasParameterExprs, - bi.name() == context->names().arguments || - bi.name() == context->names().dotThis || - bi.name() == context->names().dotGenerator); + // special bindings. + MOZ_ASSERT_IF(hasParameterExprs, FunctionScope::isSpecialName(context, bi.name())); if (!vars.append(binding)) return Nothing(); break; diff --git a/js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b-parameter.js b/js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b-parameter.js index f0adedf7d..ae7fbe879 100644 --- a/js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b-parameter.js +++ b/js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b-parameter.js @@ -11,6 +11,11 @@ assertEq(f, 123); }(123)); +(function(f = 123) { + assertEq(f, 123); + { function f() { } } + assertEq(f, 123); +}()); if (typeof reportCompare === "function") reportCompare(true, true); diff --git a/js/src/vm/Scope.cpp b/js/src/vm/Scope.cpp index a71c03695..0f80d7b69 100644 --- a/js/src/vm/Scope.cpp +++ b/js/src/vm/Scope.cpp @@ -669,6 +669,14 @@ FunctionScope::script() const return canonicalFunction()->nonLazyScript(); } +/* static */ bool +FunctionScope::isSpecialName(ExclusiveContext* cx, JSAtom* name) +{ + return name == cx->names().arguments || + name == cx->names().dotThis || + name == cx->names().dotGenerator; +} + /* static */ Shape* FunctionScope::getEmptyEnvironmentShape(ExclusiveContext* cx, bool hasParameterExprs) { diff --git a/js/src/vm/Scope.h b/js/src/vm/Scope.h index 1d04fd9f6..4a4ae8090 100644 --- a/js/src/vm/Scope.h +++ b/js/src/vm/Scope.h @@ -446,10 +446,11 @@ Scope::is() const } // -// Scope corresponding to a function. Holds formal parameter names and, if the -// function parameters contain no expressions that might possibly be -// evaluated, the function's var bindings. For example, in these functions, -// the FunctionScope will store a/b/c bindings but not d/e/f bindings: +// Scope corresponding to a function. Holds formal parameter names, special +// internal names (see FunctionScope::isSpecialName), and, if the function +// parameters contain no expressions that might possibly be evaluated, the +// function's var bindings. For example, in these functions, the FunctionScope +// will store a/b/c bindings but not d/e/f bindings: // // function f1(a, b) { // var c; @@ -562,6 +563,8 @@ class FunctionScope : public Scope return data().nonPositionalFormalStart; } + static bool isSpecialName(ExclusiveContext* cx, JSAtom* name); + static Shape* getEmptyEnvironmentShape(ExclusiveContext* cx, bool hasParameterExprs); }; -- cgit v1.2.3 From 9a7113f7c8d89d27558942f42603c4edee779d20 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 9 Jun 2019 11:27:16 -0400 Subject: 1283712 - Part 1: Add JSErrorBase, JSErrorNotes, JSErrorNotes::Note, and JSErrorReport.{notes,freeNotes}. --- js/src/jsapi.cpp | 131 +++++++++++++++++++++++++++++++++++++++- js/src/jsapi.h | 174 ++++++++++++++++++++++++++++++++++++++++++----------- js/src/jscntxt.cpp | 41 ++++++++++++- js/src/jscntxt.h | 7 +++ js/src/jsexn.cpp | 114 ++++++++++++++++++++++++++--------- js/src/jsexn.h | 3 + 6 files changed, 401 insertions(+), 69 deletions(-) (limited to 'js/src') diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 6d6eacec2..8cb3e5802 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -69,7 +69,6 @@ #include "js/Proxy.h" #include "js/SliceBudget.h" #include "js/StructuredClone.h" -#include "js/UniquePtr.h" #include "js/Utility.h" #include "vm/AsyncFunction.h" #include "vm/DateObject.h" @@ -6300,7 +6299,7 @@ JSErrorReport::freeLinebuf() } JSString* -JSErrorReport::newMessageString(JSContext* cx) +JSErrorBase::newMessageString(JSContext* cx) { if (!message_) return cx->runtime()->emptyString; @@ -6309,7 +6308,7 @@ JSErrorReport::newMessageString(JSContext* cx) } void -JSErrorReport::freeMessage() +JSErrorBase::freeMessage() { if (ownsMessage_) { js_free((void*)message_.get()); @@ -6318,6 +6317,132 @@ JSErrorReport::freeMessage() message_ = JS::ConstUTF8CharsZ(); } +JSErrorNotes::JSErrorNotes() + : notes_() +{} + +JSErrorNotes::~JSErrorNotes() +{ +} + +static UniquePtr +CreateErrorNoteVA(JSContext* cx, + const char* filename, unsigned lineno, unsigned column, + JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, + ErrorArgumentsType argumentsType, va_list ap) +{ + auto note = MakeUnique(); + if (!note) + return nullptr; + + note->errorNumber = errorNumber; + note->filename = filename; + note->lineno = lineno; + note->column = column; + + if (!ExpandErrorArgumentsVA(cx, errorCallback, userRef, errorNumber, + nullptr, argumentsType, note.get(), ap)) { + return nullptr; + } + + return note; +} + +bool +JSErrorNotes::addNoteASCII(JSContext* cx, + const char* filename, unsigned lineno, unsigned column, + JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, ...) +{ + va_list ap; + va_start(ap, errorNumber); + auto note = CreateErrorNoteVA(cx, filename, lineno, column, errorCallback, userRef, + errorNumber, ArgumentsAreASCII, ap); + va_end(ap); + + if (!note) + return false; + if (!notes_.append(Move(note))) + return false; + return true; +} + +bool +JSErrorNotes::addNoteLatin1(JSContext* cx, + const char* filename, unsigned lineno, unsigned column, + JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, ...) +{ + va_list ap; + va_start(ap, errorNumber); + auto note = CreateErrorNoteVA(cx, filename, lineno, column, errorCallback, userRef, + errorNumber, ArgumentsAreLatin1, ap); + va_end(ap); + + if (!note) + return false; + if (!notes_.append(Move(note))) + return false; + return true; +} + +bool +JSErrorNotes::addNoteUTF8(JSContext* cx, + const char* filename, unsigned lineno, unsigned column, + JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, ...) +{ + va_list ap; + va_start(ap, errorNumber); + auto note = CreateErrorNoteVA(cx, filename, lineno, column, errorCallback, userRef, + errorNumber, ArgumentsAreUTF8, ap); + va_end(ap); + + if (!note) + return false; + if (!notes_.append(Move(note))) + return false; + return true; +} + +size_t +JSErrorNotes::length() +{ + return notes_.length(); +} + +UniquePtr +JSErrorNotes::copy(JSContext* cx) +{ + auto copiedNotes = MakeUnique(); + if (!copiedNotes) + return nullptr; + + for (auto&& note : *this) { + js::UniquePtr copied(CopyErrorNote(cx, note.get())); + if (!copied) + return nullptr; + + if (!copiedNotes->notes_.append(Move(copied))) + return nullptr; + } + + return copiedNotes; +} + +JSErrorNotes::iterator +JSErrorNotes::begin() +{ + return iterator(notes_.begin()); +} + +JSErrorNotes::iterator +JSErrorNotes::end() +{ + return iterator(notes_.end()); +} + JS_PUBLIC_API(bool) JS_ThrowStopIteration(JSContext* cx) { diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 3f65dad34..99100620a 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -18,6 +18,7 @@ #include "mozilla/RefPtr.h" #include "mozilla/Variant.h" +#include #include #include #include @@ -36,6 +37,7 @@ #include "js/Realm.h" #include "js/RootingAPI.h" #include "js/TracingAPI.h" +#include "js/UniquePtr.h" #include "js/Utility.h" #include "js/Value.h" #include "js/Vector.h" @@ -5362,14 +5364,130 @@ JS_ReportOutOfMemory(JSContext* cx); extern JS_PUBLIC_API(void) JS_ReportAllocationOverflow(JSContext* cx); -class JSErrorReport +/** + * Base class that implements parts shared by JSErrorReport and + * JSErrorNotes::Note. + */ +class JSErrorBase { // The (default) error message. // If ownsMessage_ is true, the it is freed in destructor. JS::ConstUTF8CharsZ message_; + public: + JSErrorBase() + : filename(nullptr), lineno(0), column(0), + errorNumber(0), + ownsMessage_(false) + {} + + ~JSErrorBase() { + freeMessage(); + } + + // Source file name, URL, etc., or null. + const char* filename; + + // Source line number. + unsigned lineno; + + // Zero-based column index in line. + unsigned column; + + // the error number, e.g. see js.msg. + unsigned errorNumber; + + private: + bool ownsMessage_ : 1; + + public: + const JS::ConstUTF8CharsZ message() const { + return message_; + } + + void initOwnedMessage(const char* messageArg) { + initBorrowedMessage(messageArg); + ownsMessage_ = true; + } + void initBorrowedMessage(const char* messageArg) { + MOZ_ASSERT(!message_); + message_ = JS::ConstUTF8CharsZ(messageArg, strlen(messageArg)); + } + + JSString* newMessageString(JSContext* cx); + + private: + void freeMessage(); +}; + +/** + * Notes associated with JSErrorReport. + */ +class JSErrorNotes +{ + public: + class Note : public JSErrorBase + {}; + + private: + // Stores pointers to each note. + js::Vector, 1, js::SystemAllocPolicy> notes_; + + public: + JSErrorNotes(); + ~JSErrorNotes(); + + // Add an note to the given position. + bool addNoteASCII(JSContext* cx, + const char* filename, unsigned lineno, unsigned column, + JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, ...); + bool addNoteLatin1(JSContext* cx, + const char* filename, unsigned lineno, unsigned column, + JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, ...); + bool addNoteUTF8(JSContext* cx, + const char* filename, unsigned lineno, unsigned column, + JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, ...); + + size_t length(); + + // Create a deep copy of notes. + js::UniquePtr copy(JSContext* cx); + + class iterator : public std::iterator> + { + js::UniquePtr* note_; + public: + explicit iterator(js::UniquePtr* note = nullptr) : note_(note) + {} + + bool operator==(iterator other) const { + return note_ == other.note_; + } + bool operator!=(iterator other) const { + return !(*this == other); + } + iterator& operator++() { + note_++; + return *this; + } + reference operator*() { + return *note_; + } + }; + iterator begin(); + iterator end(); +}; + +/** + * Describes a single error or warning that occurs in the execution of script. + */ +class JSErrorReport : public JSErrorBase +{ // Offending source line without final '\n'. - // If ownsLinebuf__ is true, the buffer is freed in destructor. + // If ownsLinebuf_ is true, the buffer is freed in destructor. const char16_t* linebuf_; // Number of chars in linebuf_. Does not include trailing '\0'. @@ -5381,28 +5499,29 @@ class JSErrorReport public: JSErrorReport() : linebuf_(nullptr), linebufLength_(0), tokenOffset_(0), - filename(nullptr), lineno(0), column(0), - flags(0), errorNumber(0), - exnType(0), isMuted(false), - ownsLinebuf_(false), ownsMessage_(false) + notes(nullptr), + flags(0), exnType(0), isMuted(false), + ownsLinebuf_(false) {} ~JSErrorReport() { freeLinebuf(); - freeMessage(); } - const char* filename; /* source file name, URL, etc., or null */ - unsigned lineno; /* source line number */ - unsigned column; /* zero-based column index in line */ - unsigned flags; /* error/warning, etc. */ - unsigned errorNumber; /* the error number, e.g. see js.msg */ - int16_t exnType; /* One of the JSExnType constants */ - bool isMuted : 1; /* See the comment in ReadOnlyCompileOptions. */ + // Associated notes, or nullptr if there's no note. + js::UniquePtr notes; + + // error/warning, etc. + unsigned flags; + + // One of the JSExnType constants. + int16_t exnType; + + // See the comment in ReadOnlyCompileOptions. + bool isMuted : 1; private: bool ownsLinebuf_ : 1; - bool ownsMessage_ : 1; public: const char16_t* linebuf() const { @@ -5414,29 +5533,16 @@ class JSErrorReport size_t tokenOffset() const { return tokenOffset_; } - void initOwnedLinebuf(const char16_t* linebufArg, size_t linebufLengthArg, size_t tokenOffsetArg) { + void initOwnedLinebuf(const char16_t* linebufArg, size_t linebufLengthArg, + size_t tokenOffsetArg) { initBorrowedLinebuf(linebufArg, linebufLengthArg, tokenOffsetArg); ownsLinebuf_ = true; } - void initBorrowedLinebuf(const char16_t* linebufArg, size_t linebufLengthArg, size_t tokenOffsetArg); - void freeLinebuf(); - - const JS::ConstUTF8CharsZ message() const { - return message_; - } - - void initOwnedMessage(const char* messageArg) { - initBorrowedMessage(messageArg); - ownsMessage_ = true; - } - void initBorrowedMessage(const char* messageArg) { - MOZ_ASSERT(!message_); - message_ = JS::ConstUTF8CharsZ(messageArg, strlen(messageArg)); - } + void initBorrowedLinebuf(const char16_t* linebufArg, size_t linebufLengthArg, + size_t tokenOffsetArg); - JSString* newMessageString(JSContext* cx); - - void freeMessage(); + private: + void freeLinebuf(); }; /* diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 31d62332d..4e34c0e48 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -557,6 +557,18 @@ class MOZ_RAII AutoMessageArgs } }; +static void +SetExnType(JSErrorReport* reportp, int16_t exnType) +{ + reportp->exnType = exnType; +} + +static void +SetExnType(JSErrorNotes::Note* notep, int16_t exnType) +{ + // Do nothing for JSErrorNotes::Note. +} + /* * The arguments from ap need to be packaged up into an array and stored * into the report struct. @@ -568,12 +580,13 @@ class MOZ_RAII AutoMessageArgs * * Returns true if the expansion succeeds (can fail if out of memory). */ +template bool -js::ExpandErrorArgumentsVA(ExclusiveContext* cx, JSErrorCallback callback, +ExpandErrorArgumentsHelper(ExclusiveContext* cx, JSErrorCallback callback, void* userRef, const unsigned errorNumber, const char16_t** messageArgs, ErrorArgumentsType argumentsType, - JSErrorReport* reportp, va_list ap) + T* reportp, va_list ap) { const JSErrorFormatString* efs; @@ -586,7 +599,7 @@ js::ExpandErrorArgumentsVA(ExclusiveContext* cx, JSErrorCallback callback, } if (efs) { - reportp->exnType = efs->exnType; + SetExnType(reportp, efs->exnType); MOZ_ASSERT_IF(argumentsType == ArgumentsAreASCII, JS::StringIsASCII(efs->format)); @@ -669,6 +682,28 @@ js::ExpandErrorArgumentsVA(ExclusiveContext* cx, JSErrorCallback callback, return true; } +bool +js::ExpandErrorArgumentsVA(ExclusiveContext* cx, JSErrorCallback callback, + void* userRef, const unsigned errorNumber, + const char16_t** messageArgs, + ErrorArgumentsType argumentsType, + JSErrorReport* reportp, va_list ap) +{ + return ExpandErrorArgumentsHelper(cx, callback, userRef, errorNumber, + messageArgs, argumentsType, reportp, ap); +} + +bool +js::ExpandErrorArgumentsVA(JSContext* cx, JSErrorCallback callback, + void* userRef, const unsigned errorNumber, + const char16_t** messageArgs, + ErrorArgumentsType argumentsType, + JSErrorNotes::Note* notep, va_list ap) +{ + return ExpandErrorArgumentsHelper(cx, callback, userRef, errorNumber, + messageArgs, argumentsType, notep, ap); +} + bool js::ReportErrorNumberVA(JSContext* cx, unsigned flags, JSErrorCallback callback, void* userRef, const unsigned errorNumber, diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 0a2841242..c1e676f68 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -621,6 +621,13 @@ ExpandErrorArgumentsVA(ExclusiveContext* cx, JSErrorCallback callback, ErrorArgumentsType argumentsType, JSErrorReport* reportp, va_list ap); +extern bool +ExpandErrorArgumentsVA(JSContext* cx, JSErrorCallback callback, + void* userRef, const unsigned errorNumber, + const char16_t** messageArgs, + ErrorArgumentsType argumentsType, + JSErrorNotes::Note* notep, va_list ap); + /* |callee| requires a usage string provided by JS_DefineFunctionsWithHelp. */ extern void ReportUsageErrorASCII(JSContext* cx, HandleObject callee, const char* msg); diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index 102e6fb34..b07d118b9 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -201,28 +201,77 @@ ErrorObject::classes[JSEXN_ERROR_LIMIT] = { IMPLEMENT_ERROR_CLASS(RuntimeError) }; -JSErrorReport* -js::CopyErrorReport(JSContext* cx, JSErrorReport* report) +size_t +ExtraMallocSize(JSErrorReport* report) +{ + if (report->linebuf()) + return (report->linebufLength() + 1) * sizeof(char16_t); + + return 0; +} + +size_t +ExtraMallocSize(JSErrorNotes::Note* note) +{ + return 0; +} + +bool +CopyExtraData(JSContext* cx, uint8_t** cursor, JSErrorReport* copy, JSErrorReport* report) +{ + if (report->linebuf()) { + size_t linebufSize = (report->linebufLength() + 1) * sizeof(char16_t); + const char16_t* linebufCopy = (const char16_t*)(*cursor); + js_memcpy(*cursor, report->linebuf(), linebufSize); + *cursor += linebufSize; + copy->initBorrowedLinebuf(linebufCopy, report->linebufLength(), report->tokenOffset()); + } + + /* Copy non-pointer members. */ + copy->isMuted = report->isMuted; + copy->exnType = report->exnType; + + /* Note that this is before it gets flagged with JSREPORT_EXCEPTION */ + copy->flags = report->flags; + + /* Deep copy notes. */ + if (report->notes) { + auto copiedNotes = report->notes->copy(cx); + if (!copiedNotes) + return false; + copy->notes = Move(copiedNotes); + } else { + copy->notes.reset(nullptr); + } + + return true; +} + +bool +CopyExtraData(JSContext* cx, uint8_t** cursor, JSErrorNotes::Note* copy, JSErrorNotes::Note* report) +{ + return true; +} + +template +static T* +CopyErrorHelper(JSContext* cx, T* report) { /* - * We use a single malloc block to make a deep copy of JSErrorReport with + * We use a single malloc block to make a deep copy of JSErrorReport or + * JSErrorNotes::Note, except JSErrorNotes linked from JSErrorReport with * the following layout: - * JSErrorReport + * JSErrorReport or JSErrorNotes::Note * char array with characters for message_ - * char16_t array with characters for linebuf * char array with characters for filename + * char16_t array with characters for linebuf (only for JSErrorReport) * Such layout together with the properties enforced by the following * asserts does not need any extra alignment padding. */ - JS_STATIC_ASSERT(sizeof(JSErrorReport) % sizeof(const char*) == 0); + JS_STATIC_ASSERT(sizeof(T) % sizeof(const char*) == 0); JS_STATIC_ASSERT(sizeof(const char*) % sizeof(char16_t) == 0); -#define JS_CHARS_SIZE(chars) ((js_strlen(chars) + 1) * sizeof(char16_t)) - size_t filenameSize = report->filename ? strlen(report->filename) + 1 : 0; - size_t linebufSize = 0; - if (report->linebuf()) - linebufSize = (report->linebufLength() + 1) * sizeof(char16_t); size_t messageSize = 0; if (report->message()) messageSize = strlen(report->message().c_str()) + 1; @@ -231,13 +280,13 @@ js::CopyErrorReport(JSContext* cx, JSErrorReport* report) * The mallocSize can not overflow since it represents the sum of the * sizes of already allocated objects. */ - size_t mallocSize = sizeof(JSErrorReport) + messageSize + linebufSize + filenameSize; + size_t mallocSize = sizeof(T) + messageSize + filenameSize + ExtraMallocSize(report); uint8_t* cursor = cx->pod_calloc(mallocSize); if (!cursor) return nullptr; - JSErrorReport* copy = (JSErrorReport*)cursor; - cursor += sizeof(JSErrorReport); + T* copy = new (cursor) T(); + cursor += sizeof(T); if (report->message()) { copy->initBorrowedMessage((const char*)cursor); @@ -245,33 +294,40 @@ js::CopyErrorReport(JSContext* cx, JSErrorReport* report) cursor += messageSize; } - if (report->linebuf()) { - const char16_t* linebufCopy = (const char16_t*)cursor; - js_memcpy(cursor, report->linebuf(), linebufSize); - cursor += linebufSize; - copy->initBorrowedLinebuf(linebufCopy, report->linebufLength(), report->tokenOffset()); - } - if (report->filename) { copy->filename = (const char*)cursor; js_memcpy(cursor, report->filename, filenameSize); + cursor += filenameSize; + } + + if (!CopyExtraData(cx, &cursor, copy, report)) { + /* js_delete calls destructor for T and js_free for pod_calloc. */ + js_delete(copy); + return nullptr; } - MOZ_ASSERT(cursor + filenameSize == (uint8_t*)copy + mallocSize); + + MOZ_ASSERT(cursor == (uint8_t*)copy + mallocSize); /* Copy non-pointer members. */ - copy->isMuted = report->isMuted; copy->lineno = report->lineno; copy->column = report->column; copy->errorNumber = report->errorNumber; - copy->exnType = report->exnType; - /* Note that this is before it gets flagged with JSREPORT_EXCEPTION */ - copy->flags = report->flags; - -#undef JS_CHARS_SIZE return copy; } +JSErrorNotes::Note* +js::CopyErrorNote(JSContext* cx, JSErrorNotes::Note* note) +{ + return CopyErrorHelper(cx, note); +} + +JSErrorReport* +js::CopyErrorReport(JSContext* cx, JSErrorReport* report) +{ + return CopyErrorHelper(cx, report); +} + struct SuppressErrorsGuard { JSContext* cx; @@ -322,7 +378,7 @@ exn_finalize(FreeOp* fop, JSObject* obj) { MOZ_ASSERT(fop->maybeOffMainThread()); if (JSErrorReport* report = obj->as().getErrorReport()) - fop->free_(report); + fop->delete_(report); } JSErrorReport* diff --git a/js/src/jsexn.h b/js/src/jsexn.h index ae6335209..1698bb2e9 100644 --- a/js/src/jsexn.h +++ b/js/src/jsexn.h @@ -18,6 +18,9 @@ namespace js { class ErrorObject; +JSErrorNotes::Note* +CopyErrorNote(JSContext* cx, JSErrorNotes::Note* note); + JSErrorReport* CopyErrorReport(JSContext* cx, JSErrorReport* report); -- cgit v1.2.3 From 3765f057896718bfca3056728a485448bfb411cb Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 7 Jul 2019 14:41:27 -0400 Subject: Make JSErrorNotes Single Threaded --- js/src/jsapi.cpp | 12 ++++++------ js/src/jsapi.h | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'js/src') diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 8cb3e5802..7cc7bd035 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -6350,14 +6350,14 @@ CreateErrorNoteVA(JSContext* cx, } bool -JSErrorNotes::addNoteASCII(JSContext* cx, +JSErrorNotes::addNoteASCII(ExclusiveContext* cx, const char* filename, unsigned lineno, unsigned column, JSErrorCallback errorCallback, void* userRef, const unsigned errorNumber, ...) { va_list ap; va_start(ap, errorNumber); - auto note = CreateErrorNoteVA(cx, filename, lineno, column, errorCallback, userRef, + auto note = CreateErrorNoteVA(cx->asJSContext(), filename, lineno, column, errorCallback, userRef, errorNumber, ArgumentsAreASCII, ap); va_end(ap); @@ -6369,14 +6369,14 @@ JSErrorNotes::addNoteASCII(JSContext* cx, } bool -JSErrorNotes::addNoteLatin1(JSContext* cx, +JSErrorNotes::addNoteLatin1(ExclusiveContext* cx, const char* filename, unsigned lineno, unsigned column, JSErrorCallback errorCallback, void* userRef, const unsigned errorNumber, ...) { va_list ap; va_start(ap, errorNumber); - auto note = CreateErrorNoteVA(cx, filename, lineno, column, errorCallback, userRef, + auto note = CreateErrorNoteVA(cx->asJSContext(), filename, lineno, column, errorCallback, userRef, errorNumber, ArgumentsAreLatin1, ap); va_end(ap); @@ -6388,14 +6388,14 @@ JSErrorNotes::addNoteLatin1(JSContext* cx, } bool -JSErrorNotes::addNoteUTF8(JSContext* cx, +JSErrorNotes::addNoteUTF8(ExclusiveContext* cx, const char* filename, unsigned lineno, unsigned column, JSErrorCallback errorCallback, void* userRef, const unsigned errorNumber, ...) { va_list ap; va_start(ap, errorNumber); - auto note = CreateErrorNoteVA(cx, filename, lineno, column, errorCallback, userRef, + auto note = CreateErrorNoteVA(cx->asJSContext(), filename, lineno, column, errorCallback, userRef, errorNumber, ArgumentsAreUTF8, ap); va_end(ap); diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 99100620a..d00562588 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -5438,15 +5438,15 @@ class JSErrorNotes ~JSErrorNotes(); // Add an note to the given position. - bool addNoteASCII(JSContext* cx, + bool addNoteASCII(js::ExclusiveContext* cx, const char* filename, unsigned lineno, unsigned column, JSErrorCallback errorCallback, void* userRef, const unsigned errorNumber, ...); - bool addNoteLatin1(JSContext* cx, + bool addNoteLatin1(js::ExclusiveContext* cx, const char* filename, unsigned lineno, unsigned column, JSErrorCallback errorCallback, void* userRef, const unsigned errorNumber, ...); - bool addNoteUTF8(JSContext* cx, + bool addNoteUTF8(js::ExclusiveContext* cx, const char* filename, unsigned lineno, unsigned column, JSErrorCallback errorCallback, void* userRef, const unsigned errorNumber, ...); -- cgit v1.2.3 From c185c2fe7230c30b3da9bf1b943a6efe3ad4f55c Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 9 Jun 2019 13:32:19 -0400 Subject: 1283712 - Part 2: Add JSEXN_NOTE. --- js/src/jsapi.h | 1 + js/src/jsexn.cpp | 3 ++- js/src/jsexn.h | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) (limited to 'js/src') diff --git a/js/src/jsapi.h b/js/src/jsapi.h index d00562588..67b3d4267 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -654,6 +654,7 @@ typedef enum JSExnType { JSEXN_WASMRUNTIMEERROR, JSEXN_ERROR_LIMIT, JSEXN_WARN = JSEXN_ERROR_LIMIT, + JSEXN_NOTE, JSEXN_LIMIT } JSExnType; diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index b07d118b9..65cc81a1a 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -645,6 +645,7 @@ js::ErrorToException(JSContext* cx, JSErrorReport* reportp, const JSErrorFormatString* errorString = callback(userRef, errorNumber); JSExnType exnType = errorString ? static_cast(errorString->exnType) : JSEXN_ERR; MOZ_ASSERT(exnType < JSEXN_LIMIT); + MOZ_ASSERT(exnType != JSEXN_NOTE); if (exnType == JSEXN_WARN) { // werror must be enabled, so we use JSEXN_ERR. @@ -728,7 +729,7 @@ ErrorReportToString(JSContext* cx, JSErrorReport* reportp) */ JSExnType type = static_cast(reportp->exnType); RootedString str(cx); - if (type != JSEXN_WARN) + if (type != JSEXN_WARN && type != JSEXN_NOTE) str = ClassName(GetExceptionProtoKey(type), cx); /* diff --git a/js/src/jsexn.h b/js/src/jsexn.h index 1698bb2e9..00120d89c 100644 --- a/js/src/jsexn.h +++ b/js/src/jsexn.h @@ -70,7 +70,8 @@ static_assert(JSEXN_ERR == 0 && JSProto_Error + JSEXN_WASMCOMPILEERROR == JSProto_CompileError && JSProto_Error + JSEXN_WASMRUNTIMEERROR == JSProto_RuntimeError && JSEXN_WASMRUNTIMEERROR + 1 == JSEXN_WARN && - JSEXN_WARN + 1 == JSEXN_LIMIT, + JSEXN_WARN + 1 == JSEXN_NOTE && + JSEXN_NOTE + 1 == JSEXN_LIMIT, "GetExceptionProtoKey and ExnTypeFromProtoKey require that " "each corresponding JSExnType and JSProtoKey value be separated " "by the same constant value"); -- cgit v1.2.3 From 412f15de44cee51e2443bc4846fe9679dca7e1b4 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 9 Jun 2019 14:23:16 -0400 Subject: 1283712 - Part 3: Add Parser::errorWithNotes and Parser::errorWithNotesAt. --- js/src/frontend/BytecodeEmitter.cpp | 7 +++-- js/src/frontend/Parser.cpp | 60 ++++++++++++++++++++++++++++++------- js/src/frontend/Parser.h | 3 ++ js/src/frontend/TokenStream.cpp | 36 ++++++++++++---------- js/src/frontend/TokenStream.h | 11 +++---- 5 files changed, 82 insertions(+), 35 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 44787dc52..7b8b41727 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -3604,7 +3604,7 @@ BytecodeEmitter::reportError(ParseNode* pn, unsigned errorNumber, ...) va_list args; va_start(args, errorNumber); - bool result = tokenStream()->reportCompileErrorNumberVA(pos.begin, JSREPORT_ERROR, + bool result = tokenStream()->reportCompileErrorNumberVA(nullptr, pos.begin, JSREPORT_ERROR, errorNumber, args); va_end(args); return result; @@ -3617,7 +3617,8 @@ BytecodeEmitter::reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...) va_list args; va_start(args, errorNumber); - bool result = tokenStream()->reportExtraWarningErrorNumberVA(pos.begin, errorNumber, args); + bool result = tokenStream()->reportExtraWarningErrorNumberVA(nullptr, pos.begin, + errorNumber, args); va_end(args); return result; } @@ -3629,7 +3630,7 @@ BytecodeEmitter::reportStrictModeError(ParseNode* pn, unsigned errorNumber, ...) va_list args; va_start(args, errorNumber); - bool result = tokenStream()->reportStrictModeErrorNumberVA(pos.begin, sc->strict(), + bool result = tokenStream()->reportStrictModeErrorNumberVA(nullptr, pos.begin, sc->strict(), errorNumber, args); va_end(args); return result; diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 2e13910df..923b42870 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -579,7 +579,22 @@ ParserBase::error(unsigned errorNumber, ...) #ifdef DEBUG bool result = #endif - tokenStream.reportCompileErrorNumberVA(pos().begin, JSREPORT_ERROR, errorNumber, args); + tokenStream.reportCompileErrorNumberVA(nullptr, pos().begin, JSREPORT_ERROR, + errorNumber, args); + MOZ_ASSERT(!result, "reporting an error returned true?"); + va_end(args); +} + +void +ParserBase::errorWithNotes(UniquePtr notes, unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); +#ifdef DEBUG + bool result = +#endif + tokenStream.reportCompileErrorNumberVA(Move(notes), pos().begin, JSREPORT_ERROR, + errorNumber, args); MOZ_ASSERT(!result, "reporting an error returned true?"); va_end(args); } @@ -592,7 +607,22 @@ ParserBase::errorAt(uint32_t offset, unsigned errorNumber, ...) #ifdef DEBUG bool result = #endif - tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_ERROR, errorNumber, args); + tokenStream.reportCompileErrorNumberVA(nullptr, offset, JSREPORT_ERROR, errorNumber, args); + MOZ_ASSERT(!result, "reporting an error returned true?"); + va_end(args); +} + +void +ParserBase::errorWithNotesAt(UniquePtr notes, uint32_t offset, + unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); +#ifdef DEBUG + bool result = +#endif + tokenStream.reportCompileErrorNumberVA(Move(notes), offset, JSREPORT_ERROR, + errorNumber, args); MOZ_ASSERT(!result, "reporting an error returned true?"); va_end(args); } @@ -603,7 +633,8 @@ ParserBase::warning(unsigned errorNumber, ...) va_list args; va_start(args, errorNumber); bool result = - tokenStream.reportCompileErrorNumberVA(pos().begin, JSREPORT_WARNING, errorNumber, args); + tokenStream.reportCompileErrorNumberVA(nullptr, pos().begin, JSREPORT_WARNING, + errorNumber, args); va_end(args); return result; } @@ -614,7 +645,8 @@ ParserBase::warningAt(uint32_t offset, unsigned errorNumber, ...) va_list args; va_start(args, errorNumber); bool result = - tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_WARNING, errorNumber, args); + tokenStream.reportCompileErrorNumberVA(nullptr, offset, JSREPORT_WARNING, + errorNumber, args); va_end(args); return result; } @@ -624,7 +656,8 @@ ParserBase::extraWarning(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool result = tokenStream.reportExtraWarningErrorNumberVA(pos().begin, errorNumber, args); + bool result = tokenStream.reportExtraWarningErrorNumberVA(nullptr, pos().begin, + errorNumber, args); va_end(args); return result; } @@ -635,7 +668,7 @@ ParserBase::strictModeError(unsigned errorNumber, ...) va_list args; va_start(args, errorNumber); bool res = - tokenStream.reportStrictModeErrorNumberVA(pos().begin, pc->sc()->strict(), + tokenStream.reportStrictModeErrorNumberVA(nullptr, pos().begin, pc->sc()->strict(), errorNumber, args); va_end(args); return res; @@ -647,7 +680,8 @@ ParserBase::strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...) va_list args; va_start(args, errorNumber); bool res = - tokenStream.reportStrictModeErrorNumberVA(offset, pc->sc()->strict(), errorNumber, args); + tokenStream.reportStrictModeErrorNumberVA(nullptr, offset, pc->sc()->strict(), + errorNumber, args); va_end(args); return res; } @@ -661,17 +695,21 @@ ParserBase::reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumb uint32_t offset = TokenStream::NoOffset; switch (kind) { case ParseError: - result = tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_ERROR, errorNumber, args); + result = tokenStream.reportCompileErrorNumberVA(nullptr, offset, JSREPORT_ERROR, + errorNumber, args); break; case ParseWarning: result = - tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_WARNING, errorNumber, args); + tokenStream.reportCompileErrorNumberVA(nullptr, offset, JSREPORT_WARNING, + errorNumber, args); break; case ParseExtraWarning: - result = tokenStream.reportExtraWarningErrorNumberVA(offset, errorNumber, args); + result = tokenStream.reportExtraWarningErrorNumberVA(nullptr, offset, + errorNumber, args); break; case ParseStrictError: - result = tokenStream.reportStrictModeErrorNumberVA(offset, strict, errorNumber, args); + result = tokenStream.reportStrictModeErrorNumberVA(nullptr, offset, strict, + errorNumber, args); break; } va_end(args); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index b850dc00b..35b9384a8 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -824,9 +824,12 @@ class ParserBase : public StrictModeGetter /* Report the given error at the current offset. */ void error(unsigned errorNumber, ...); + void errorWithNotes(UniquePtr notes, unsigned errorNumber, ...); /* Report the given error at the given offset. */ void errorAt(uint32_t offset, unsigned errorNumber, ...); + void errorWithNotesAt(UniquePtr notes, uint32_t offset, + unsigned errorNumber, ...); /* * Handle a strict mode error at the current offset. Report an error if in diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index 6a7934e8f..76ea7e821 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -607,8 +607,8 @@ TokenStream::seek(const Position& pos, const TokenStream& other) } bool -TokenStream::reportStrictModeErrorNumberVA(uint32_t offset, bool strictMode, unsigned errorNumber, - va_list args) +TokenStream::reportStrictModeErrorNumberVA(UniquePtr notes, uint32_t offset, + bool strictMode, unsigned errorNumber, va_list args) { // In strict mode code, this is an error, not merely a warning. unsigned flags; @@ -619,7 +619,7 @@ TokenStream::reportStrictModeErrorNumberVA(uint32_t offset, bool strictMode, uns else return true; - return reportCompileErrorNumberVA(offset, flags, errorNumber, args); + return reportCompileErrorNumberVA(Move(notes), offset, flags, errorNumber, args); } void @@ -645,8 +645,8 @@ CompileError::throwError(JSContext* cx) } bool -TokenStream::reportCompileErrorNumberVA(uint32_t offset, unsigned flags, unsigned errorNumber, - va_list args) +TokenStream::reportCompileErrorNumberVA(UniquePtr notes, uint32_t offset, + unsigned flags, unsigned errorNumber, va_list args) { bool warning = JSREPORT_IS_WARNING(flags); @@ -663,6 +663,7 @@ TokenStream::reportCompileErrorNumberVA(uint32_t offset, unsigned flags, unsigne return false; CompileError& err = *tempErrPtr; + err.notes = Move(notes); err.flags = flags; err.errorNumber = errorNumber; err.filename = filename; @@ -754,7 +755,7 @@ TokenStream::reportStrictModeError(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool result = reportStrictModeErrorNumberVA(currentToken().pos.begin, strictMode(), + bool result = reportStrictModeErrorNumberVA(nullptr, currentToken().pos.begin, strictMode(), errorNumber, args); va_end(args); return result; @@ -765,8 +766,8 @@ TokenStream::reportError(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool result = reportCompileErrorNumberVA(currentToken().pos.begin, JSREPORT_ERROR, errorNumber, - args); + bool result = reportCompileErrorNumberVA(nullptr, currentToken().pos.begin, JSREPORT_ERROR, + errorNumber, args); va_end(args); return result; } @@ -776,8 +777,8 @@ TokenStream::reportErrorNoOffset(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool result = reportCompileErrorNumberVA(NoOffset, JSREPORT_ERROR, errorNumber, - args); + bool result = reportCompileErrorNumberVA(nullptr, NoOffset, JSREPORT_ERROR, + errorNumber, args); va_end(args); return result; } @@ -787,19 +788,21 @@ TokenStream::warning(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool result = reportCompileErrorNumberVA(currentToken().pos.begin, JSREPORT_WARNING, + bool result = reportCompileErrorNumberVA(nullptr, currentToken().pos.begin, JSREPORT_WARNING, errorNumber, args); va_end(args); return result; } bool -TokenStream::reportExtraWarningErrorNumberVA(uint32_t offset, unsigned errorNumber, va_list args) +TokenStream::reportExtraWarningErrorNumberVA(UniquePtr notes, uint32_t offset, + unsigned errorNumber, va_list args) { if (!options().extraWarningsOption) return true; - return reportCompileErrorNumberVA(offset, JSREPORT_STRICT|JSREPORT_WARNING, errorNumber, args); + return reportCompileErrorNumberVA(Move(notes), offset, JSREPORT_STRICT|JSREPORT_WARNING, + errorNumber, args); } void @@ -810,7 +813,7 @@ TokenStream::reportAsmJSError(uint32_t offset, unsigned errorNumber, ...) unsigned flags = options().throwOnAsmJSValidationFailureOption ? JSREPORT_ERROR : JSREPORT_WARNING; - reportCompileErrorNumberVA(offset, flags, errorNumber, args); + reportCompileErrorNumberVA(nullptr, offset, flags, errorNumber, args); va_end(args); } @@ -822,7 +825,8 @@ TokenStream::error(unsigned errorNumber, ...) #ifdef DEBUG bool result = #endif - reportCompileErrorNumberVA(currentToken().pos.begin, JSREPORT_ERROR, errorNumber, args); + reportCompileErrorNumberVA(nullptr, currentToken().pos.begin, JSREPORT_ERROR, + errorNumber, args); MOZ_ASSERT(!result, "reporting an error returned true?"); va_end(args); } @@ -835,7 +839,7 @@ TokenStream::errorAt(uint32_t offset, unsigned errorNumber, ...) #ifdef DEBUG bool result = #endif - reportCompileErrorNumberVA(offset, JSREPORT_ERROR, errorNumber, args); + reportCompileErrorNumberVA(nullptr, offset, JSREPORT_ERROR, errorNumber, args); MOZ_ASSERT(!result, "reporting an error returned true?"); va_end(args); } diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index fbfefbfe1..e0119c83d 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -410,11 +410,12 @@ class MOZ_STACK_CLASS TokenStream // General-purpose error reporters. You should avoid calling these // directly, and instead use the more succinct alternatives (error(), // warning(), &c.) in TokenStream, Parser, and BytecodeEmitter. - bool reportCompileErrorNumberVA(uint32_t offset, unsigned flags, unsigned errorNumber, - va_list args); - bool reportStrictModeErrorNumberVA(uint32_t offset, bool strictMode, unsigned errorNumber, - va_list args); - bool reportExtraWarningErrorNumberVA(uint32_t offset, unsigned errorNumber, va_list args); + bool reportCompileErrorNumberVA(UniquePtr notes, uint32_t offset, unsigned flags, + unsigned errorNumber, va_list args); + bool reportStrictModeErrorNumberVA(UniquePtr notes, uint32_t offset, + bool strictMode, unsigned errorNumber, va_list args); + bool reportExtraWarningErrorNumberVA(UniquePtr notes, uint32_t offset, + unsigned errorNumber, va_list args); // asm.js reporter void reportAsmJSError(uint32_t offset, unsigned errorNumber, ...); -- cgit v1.2.3 From da77e2c04cf4d408a3d0dca153c8a27ec3de2951 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 9 Jun 2019 14:24:06 -0400 Subject: 1283712 - Part 4: Print error note in js::PrintError. --- js/src/jscntxt.cpp | 140 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 97 insertions(+), 43 deletions(-) (limited to 'js/src') diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 4e34c0e48..b113a0e1f 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -381,49 +381,16 @@ js::ReportUsageErrorASCII(JSContext* cx, HandleObject callee, const char* msg) } } -bool -js::PrintError(JSContext* cx, FILE* file, JS::ConstUTF8CharsZ toStringResult, - JSErrorReport* report, bool reportWarnings) -{ - MOZ_ASSERT(report); - - /* Conditionally ignore reported warnings. */ - if (JSREPORT_IS_WARNING(report->flags) && !reportWarnings) - return false; - - char* prefix = nullptr; - if (report->filename) - prefix = JS_smprintf("%s:", report->filename); - if (report->lineno) { - char* tmp = prefix; - prefix = JS_smprintf("%s%u:%u ", tmp ? tmp : "", report->lineno, report->column); - JS_free(cx, tmp); - } - if (JSREPORT_IS_WARNING(report->flags)) { - char* tmp = prefix; - prefix = JS_smprintf("%s%swarning: ", - tmp ? tmp : "", - JSREPORT_IS_STRICT(report->flags) ? "strict " : ""); - JS_free(cx, tmp); - } - - const char* message = toStringResult ? toStringResult.c_str() : report->message().c_str(); - - /* embedded newlines -- argh! */ - const char* ctmp; - while ((ctmp = strchr(message, '\n')) != 0) { - ctmp++; - if (prefix) - fputs(prefix, file); - fwrite(message, 1, ctmp - message, file); - message = ctmp; - } - - /* If there were no filename or lineno, the prefix might be empty */ - if (prefix) - fputs(prefix, file); - fputs(message, file); +enum class PrintErrorKind { + Error, + Warning, + StrictWarning, + Note +}; +static void +PrintErrorLine(JSContext* cx, FILE* file, const char* prefix, JSErrorReport* report) +{ if (const char16_t* linebuf = report->linebuf()) { size_t n = report->linebufLength(); @@ -453,9 +420,96 @@ js::PrintError(JSContext* cx, FILE* file, JS::ConstUTF8CharsZ toStringResult, } fputc('^', file); } +} + +static void +PrintErrorLine(JSContext* cx, FILE* file, const char* prefix, JSErrorNotes::Note* note) +{ +} + +template +static bool +PrintSingleError(JSContext* cx, FILE* file, JS::ConstUTF8CharsZ toStringResult, + T* report, PrintErrorKind kind) +{ + UniquePtr prefix; + if (report->filename) + prefix.reset(JS_smprintf("%s:", report->filename)); + + if (report->lineno) { + UniquePtr tmp(JS_smprintf("%s%u:%u ", prefix ? prefix.get() : "", report->lineno, + report->column)); + prefix = Move(tmp); + } + + if (kind != PrintErrorKind::Error) { + const char* kindPrefix = nullptr; + switch (kind) { + case PrintErrorKind::Error: + break; + case PrintErrorKind::Warning: + kindPrefix = "warning"; + break; + case PrintErrorKind::StrictWarning: + kindPrefix = "strict warning"; + break; + case PrintErrorKind::Note: + kindPrefix = "note"; + break; + } + + UniquePtr tmp(JS_smprintf("%s%s: ", prefix ? prefix.get() : "", kindPrefix)); + prefix = Move(tmp); + } + + const char* message = toStringResult ? toStringResult.c_str() : report->message().c_str(); + + /* embedded newlines -- argh! */ + const char* ctmp; + while ((ctmp = strchr(message, '\n')) != 0) { + ctmp++; + if (prefix) + fputs(prefix.get(), file); + fwrite(message, 1, ctmp - message, file); + message = ctmp; + } + + /* If there were no filename or lineno, the prefix might be empty */ + if (prefix) + fputs(prefix.get(), file); + fputs(message, file); + + PrintErrorLine(cx, file, prefix.get(), report); fputc('\n', file); + fflush(file); - JS_free(cx, prefix); + return true; +} + +bool +js::PrintError(JSContext* cx, FILE* file, JS::ConstUTF8CharsZ toStringResult, + JSErrorReport* report, bool reportWarnings) +{ + MOZ_ASSERT(report); + + /* Conditionally ignore reported warnings. */ + if (JSREPORT_IS_WARNING(report->flags) && !reportWarnings) + return false; + + PrintErrorKind kind = PrintErrorKind::Error; + if (JSREPORT_IS_WARNING(report->flags)) { + if (JSREPORT_IS_STRICT(report->flags)) + kind = PrintErrorKind::StrictWarning; + else + kind = PrintErrorKind::Warning; + } + PrintSingleError(cx, file, toStringResult, report, kind); + + if (report->notes) { + for (auto&& note : *report->notes) + PrintSingleError(cx, file, JS::ConstUTF8CharsZ(), note.get(), PrintErrorKind::Note); + } + return true; } -- cgit v1.2.3 From f4552af8bc9419c5f2860385de14e28a6805ea7e Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 9 Jun 2019 14:38:36 -0400 Subject: 1283712 - Part 5: Support notes in Debugger. --- js/src/jscntxt.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++++++ js/src/jscntxt.h | 3 +++ js/src/vm/Debugger.cpp | 33 +++++++++++++++++++++++++++++++++ js/src/vm/Debugger.h | 3 +++ 4 files changed, 85 insertions(+) (limited to 'js/src') diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index b113a0e1f..441b006d6 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -921,6 +921,52 @@ js::ReportValueErrorFlags(JSContext* cx, unsigned flags, const unsigned errorNum return ok; } +JSObject* +js::CreateErrorNotesArray(JSContext* cx, JSErrorReport* report) +{ + RootedArrayObject notesArray(cx, NewDenseEmptyArray(cx)); + if (!notesArray) + return nullptr; + + if (!report->notes) + return notesArray; + + for (auto&& note : *report->notes) { + RootedPlainObject noteObj(cx, NewBuiltinClassInstance(cx)); + if (!noteObj) + return nullptr; + + RootedString messageStr(cx, note->newMessageString(cx)); + if (!messageStr) + return nullptr; + RootedValue messageVal(cx, StringValue(messageStr)); + if (!DefineProperty(cx, noteObj, cx->names().message, messageVal)) + return nullptr; + + RootedValue filenameVal(cx); + if (note->filename) { + RootedString filenameStr(cx, NewStringCopyZ(cx, note->filename)); + if (!filenameStr) + return nullptr; + filenameVal = StringValue(filenameStr); + } + if (!DefineProperty(cx, noteObj, cx->names().fileName, filenameVal)) + return nullptr; + + RootedValue linenoVal(cx, Int32Value(note->lineno)); + if (!DefineProperty(cx, noteObj, cx->names().lineNumber, linenoVal)) + return nullptr; + RootedValue columnVal(cx, Int32Value(note->column)); + if (!DefineProperty(cx, noteObj, cx->names().columnNumber, columnVal)) + return nullptr; + + if (!NewbornArrayPush(cx, notesArray, ObjectValue(*noteObj))) + return nullptr; + } + + return notesArray; +} + const JSErrorFormatString js_ErrorFormatString[JSErr_Limit] = { #define MSG_DEF(name, count, exception, format) \ { #name, format, count, exception } , diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index c1e676f68..c949d18fd 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -685,6 +685,9 @@ ReportValueErrorFlags(JSContext* cx, unsigned flags, const unsigned errorNumber, ((void)ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber, \ spindex, v, fallback, arg1, arg2)) +JSObject* +CreateErrorNotesArray(JSContext* cx, JSErrorReport* report); + } /* namespace js */ extern const JSErrorFormatString js_ErrorFormatString[JSErr_Limit]; diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 63797be38..d68d1b75e 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -8665,6 +8665,14 @@ DebuggerObject::errorMessageNameGetter(JSContext *cx, unsigned argc, Value* vp) return true; } +/* static */ bool +DebuggerObject::errorNotesGetter(JSContext *cx, unsigned argc, Value* vp) +{ + THIS_DEBUGOBJECT(cx, argc, vp, "get errorNotes", args, object) + + return DebuggerObject::getErrorNotes(cx, object, args.rval()); +} + /* static */ bool DebuggerObject::errorLineNumberGetter(JSContext *cx, unsigned argc, Value* vp) { @@ -9324,6 +9332,7 @@ const JSPropertySpec DebuggerObject::properties_[] = { JS_PSG("global", DebuggerObject::globalGetter, 0), JS_PSG("allocationSite", DebuggerObject::allocationSiteGetter, 0), JS_PSG("errorMessageName", DebuggerObject::errorMessageNameGetter, 0), + JS_PSG("errorNotes", DebuggerObject::errorNotesGetter, 0), JS_PSG("errorLineNumber", DebuggerObject::errorLineNumberGetter, 0), JS_PSG("errorColumnNumber", DebuggerObject::errorColumnNumberGetter, 0), JS_PSG("isProxy", DebuggerObject::isProxyGetter, 0), @@ -9694,6 +9703,30 @@ DebuggerObject::getErrorMessageName(JSContext* cx, HandleDebuggerObject object, return true; } +/* static */ bool +DebuggerObject::getErrorNotes(JSContext* cx, HandleDebuggerObject object, + MutableHandleValue result) +{ + RootedObject referent(cx, object->referent()); + JSErrorReport* report; + if (!getErrorReport(cx, referent, report)) + return false; + + if (!report) { + result.setUndefined(); + return true; + } + + RootedObject errorNotesArray(cx, CreateErrorNotesArray(cx, report)); + if (!errorNotesArray) + return false; + + if (!cx->compartment()->wrap(cx, &errorNotesArray)) + return false; + result.setObject(*errorNotesArray); + return true; +} + /* static */ bool DebuggerObject::getErrorLineNumber(JSContext* cx, HandleDebuggerObject object, MutableHandleValue result) diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h index 3239ade6d..cdcf2d67f 100644 --- a/js/src/vm/Debugger.h +++ b/js/src/vm/Debugger.h @@ -1246,6 +1246,8 @@ class DebuggerObject : public NativeObject MutableHandleObject result); static MOZ_MUST_USE bool getErrorMessageName(JSContext* cx, HandleDebuggerObject object, MutableHandleString result); + static MOZ_MUST_USE bool getErrorNotes(JSContext* cx, HandleDebuggerObject object, + MutableHandleValue result); static MOZ_MUST_USE bool getErrorLineNumber(JSContext* cx, HandleDebuggerObject object, MutableHandleValue result); static MOZ_MUST_USE bool getErrorColumnNumber(JSContext* cx, HandleDebuggerObject object, @@ -1371,6 +1373,7 @@ class DebuggerObject : public NativeObject static MOZ_MUST_USE bool globalGetter(JSContext* cx, unsigned argc, Value* vp); static MOZ_MUST_USE bool allocationSiteGetter(JSContext* cx, unsigned argc, Value* vp); static MOZ_MUST_USE bool errorMessageNameGetter(JSContext* cx, unsigned argc, Value* vp); + static MOZ_MUST_USE bool errorNotesGetter(JSContext* cx, unsigned argc, Value* vp); static MOZ_MUST_USE bool errorLineNumberGetter(JSContext* cx, unsigned argc, Value* vp); static MOZ_MUST_USE bool errorColumnNumberGetter(JSContext* cx, unsigned argc, Value* vp); static MOZ_MUST_USE bool isProxyGetter(JSContext* cx, unsigned argc, Value* vp); -- cgit v1.2.3 From 4a82fdad87107d369df20da0a4a0987b1bd821fd Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 16 Jun 2019 09:48:07 -0400 Subject: 1332245 - Move nsScriptError from js/xpconnect to dom/bindings. --- js/src/vm/ErrorReporting.cpp | 124 +++++++++++++++++++++++++++++++++++++++++++ js/src/vm/ErrorReporting.h | 91 +++++++++++++++++++++++++++++++ 2 files changed, 215 insertions(+) create mode 100644 js/src/vm/ErrorReporting.cpp create mode 100644 js/src/vm/ErrorReporting.h (limited to 'js/src') diff --git a/js/src/vm/ErrorReporting.cpp b/js/src/vm/ErrorReporting.cpp new file mode 100644 index 000000000..5877f3a4b --- /dev/null +++ b/js/src/vm/ErrorReporting.cpp @@ -0,0 +1,124 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * 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/. */ + +#include "vm/ErrorReporting.h" + +#include "mozilla/Move.h" + +#include + +#include "jscntxt.h" +#include "jsexn.h" + +using mozilla::Move; + +using JS::UniqueTwoByteChars; + +void +CallWarningReporter(JSContext* cx, JSErrorReport* reportp) +{ + MOZ_ASSERT(reportp); + MOZ_ASSERT(JSREPORT_IS_WARNING(reportp->flags)); + + if (JS::WarningReporter warningReporter = cx->runtime()->warningReporter) + warningReporter(cx, reportp); +} + +void +CompileError::throwError(JSContext* cx) +{ + if (JSREPORT_IS_WARNING(flags)) { + CallWarningReporter(cx, this); + return; + } + + // If there's a runtime exception type associated with this error + // number, set that as the pending exception. For errors occuring at + // compile time, this is very likely to be a JSEXN_SYNTAXERR. + // + // If an exception is thrown but not caught, the JSREPORT_EXCEPTION + // flag will be set in report.flags. Proper behavior for an error + // reporter is to ignore a report with this flag for all but top-level + // compilation errors. The exception will remain pending, and so long + // as the non-top-level "load", "eval", or "compile" native function + // returns false, the top-level reporter will eventually receive the + // uncaught exception report. + ErrorToException(cx, this, nullptr, nullptr); +} + +bool +ReportCompileWarning(JSContext* cx, ErrorMetadata&& metadata, UniquePtr notes, + unsigned flags, unsigned errorNumber, va_list args) +{ + // On the main thread, report the error immediately. When compiling off + // thread, save the error so that the thread finishing the parse can report + // it later. + CompileError tempErr; + CompileError* err = &tempErr; + if (!cx->isJSContext() && !cx->addPendingCompileError(&err)) { + return false; + } + + err->notes = Move(notes); + err->flags = flags; + err->errorNumber = errorNumber; + + err->filename = metadata.filename; + err->lineno = metadata.lineNumber; + err->column = metadata.columnNumber; + err->isMuted = metadata.isMuted; + + if (UniqueTwoByteChars lineOfContext = Move(metadata.lineOfContext)) + err->initOwnedLinebuf(lineOfContext.release(), metadata.lineLength, metadata.tokenOffset); + + if (!ExpandErrorArgumentsVA(cx, GetErrorMessage, nullptr, errorNumber, + nullptr, ArgumentsAreLatin1, err, args)) + { + return false; + } + + if (cx->isJSContext()) { + err->throwError(cx->asJSContext()); + } + + return true; +} + +void +ReportCompileError(JSContext* cx, ErrorMetadata&& metadata, UniquePtr notes, + unsigned flags, unsigned errorNumber, va_list args) +{ + // On the main thread, report the error immediately. When compiling off + // thread, save the error so that the thread finishing the parse can report + // it later. + CompileError tempErr; + CompileError* err = &tempErr; + if (!cx->isJSContext() && !cx->addPendingCompileError(&err)) { + return; + } + + err->notes = Move(notes); + err->flags = flags; + err->errorNumber = errorNumber; + + err->filename = metadata.filename; + err->lineno = metadata.lineNumber; + err->column = metadata.columnNumber; + err->isMuted = metadata.isMuted; + + if (UniqueTwoByteChars lineOfContext = Move(metadata.lineOfContext)) + err->initOwnedLinebuf(lineOfContext.release(), metadata.lineLength, metadata.tokenOffset); + + if (!ExpandErrorArgumentsVA(cx, GetErrorMessage, nullptr, errorNumber, + nullptr, ArgumentsAreLatin1, err, args)) + { + return; + } + + if (cx->isJSContext()) { + err->throwError(cx->asJSContext()); + } +} diff --git a/js/src/vm/ErrorReporting.h b/js/src/vm/ErrorReporting.h new file mode 100644 index 000000000..02bbe2c63 --- /dev/null +++ b/js/src/vm/ErrorReporting.h @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * 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/. */ + +#ifndef vm_ErrorReporting_h +#define vm_ErrorReporting_h + +#include "mozilla/Move.h" + +#include + +#include "jsapi.h" // for JSErrorNotes, JSErrorReport + +#include "js/UniquePtr.h" // for UniquePtr +#include "js/Utility.h" // for UniqueTwoByteChars + +struct JSContext; + +namespace js { + +/** + * Metadata for a compilation error (or warning) at a particular offset, or at + * no offset (i.e. with respect to a script overall). + */ +struct ErrorMetadata +{ + // The file/URL where the error occurred. + const char* filename; + + // The line and column numbers where the error occurred. If the error + // is with respect to the entire script and not with respect to a + // particular location, these will both be zero. + uint32_t lineNumber; + uint32_t columnNumber; + + // If the error occurs at a particular location, context surrounding the + // location of the error: the line that contained the error, or a small + // portion of it if the line is long. + // + // This information is provided on a best-effort basis: code populating + // ErrorMetadata instances isn't obligated to supply this. + JS::UniqueTwoByteChars lineOfContext; + + // If |lineOfContext| is non-null, its length. + size_t lineLength; + + // If |lineOfContext| is non-null, the offset within it of the token that + // triggered the error. + size_t tokenOffset; + + // Whether the error is "muted" because it derives from a cross-origin + // load. See the comment in TransitiveCompileOptions in jsapi.h for + // details. + bool isMuted; +}; + +class CompileError : public JSErrorReport +{ + public: + void throwError(JSContext* cx); +}; + +/** Send a JSErrorReport to the warningReporter callback. */ +extern void +CallWarningReporter(JSContext* cx, JSErrorReport* report); + +/** + * Report a compile error during script processing prior to execution of the + * script. + */ +extern void +ReportCompileError(ErrorMetadata&& metadata, UniquePtr notes, + unsigned flags, unsigned errorNumber, va_list args); + +/** + * Report a compile warning during script processing prior to execution of the + * script. Returns true if the warning was successfully reported, false if an + * error occurred. + * + * This function DOES NOT respect an existing werror option. If the caller + * wishes such option to be respected, it must do so itself. + */ +extern MOZ_MUST_USE bool +ReportCompileWarning(JSContext* cx, ErrorMetadata&& metadata, UniquePtr notes, + unsigned flags, unsigned errorNumber, va_list args); + +} // namespace js + +#endif /* vm_ErrorReporting_h */ -- cgit v1.2.3 From a781578b416c502e642ab465da3344abd419475f Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 16 Jun 2019 11:30:20 -0400 Subject: 1283712 - Part 9: Add getErrorNotes testing function to extract error notes from exception. --- js/src/builtin/TestingFunctions.cpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'js/src') diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 982c9e386..992fe2c97 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -4043,6 +4043,32 @@ IsConstructor(JSContext* cx, unsigned argc, Value* vp) return true; } +static bool +GetErrorNotes(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + if (!args.requireAtLeast(cx, "getErrorNotes", 1)) + return false; + + if (!args[0].isObject() || !args[0].toObject().is()) { + args.rval().setNull(); + return true; + } + + JSErrorReport* report = args[0].toObject().as().getErrorReport(); + if (!report) { + args.rval().setNull(); + return true; + } + + RootedObject notesArray(cx, CreateErrorNotesArray(cx, report)); + if (!notesArray) + return false; + + args.rval().setObject(*notesArray); + return true; +} + static const JSFunctionSpecWithHelp TestingFunctions[] = { JS_FN_HELP("gc", ::GC, 0, 0, "gc([obj] | 'zone' [, 'shrinking'])", @@ -4577,6 +4603,10 @@ static const JSFunctionSpecWithHelp FuzzingUnsafeTestingFunctions[] = { " Dumps RegExp bytecode."), #endif + JS_FN_HELP("getErrorNotes", GetErrorNotes, 1, 0, +"getErrorNotes(error)", +" Returns an array of error notes."), + JS_FS_HELP_END }; -- cgit v1.2.3 From 8e932efef46c70fd0c165ee432893f9898267f08 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 16 Jun 2019 11:32:41 -0400 Subject: 1283712 - Part 10: Support notes in getLastWarning shell-only testing function. --- js/src/shell/js.cpp | 8 ++++++++ js/src/vm/CommonPropertyNames.h | 1 + 2 files changed, 9 insertions(+) (limited to 'js/src') diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 19bb6b84a..1e2435955 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -6419,6 +6419,14 @@ CreateLastWarningObject(JSContext* cx, JSErrorReport* report) if (!DefineProperty(cx, warningObj, cx->names().columnNumber, columnVal)) return false; + RootedObject notesArray(cx, CreateErrorNotesArray(cx, report)); + if (!notesArray) + return false; + + RootedValue notesArrayVal(cx, ObjectValue(*notesArray)); + if (!DefineProperty(cx, warningObj, cx->names().notes, notesArrayVal)) + return false; + GetShellContext(cx)->lastWarning.setObject(*warningObj); return true; } diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h index e7a4f1222..eaeea84b9 100644 --- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -217,6 +217,7 @@ macro(noFilename, noFilename, "noFilename") \ macro(nonincrementalReason, nonincrementalReason, "nonincrementalReason") \ macro(noStack, noStack, "noStack") \ + macro(notes, notes, "notes") \ macro(NumberFormat, NumberFormat, "NumberFormat") \ macro(NumberFormatFormatGet, NumberFormatFormatGet, "Intl_NumberFormat_format_get") \ macro(numeric, numeric, "numeric") \ -- cgit v1.2.3 From 05c9c752a34ce4c9d246b63e2fbb46eaa946f8b6 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 9 Jun 2019 16:14:01 -0400 Subject: 1336783 - Part 1: Rework on reserved word and remove TokenStream::KeywordIsName. --- js/src/frontend/GenerateReservedWords.py | 213 ++++++ js/src/frontend/Parser.cpp | 716 +++++++++------------ js/src/frontend/Parser.h | 48 +- js/src/frontend/ReservedWords.h | 81 +++ js/src/frontend/TokenKind.h | 99 ++- js/src/frontend/TokenStream.cpp | 191 +++--- js/src/frontend/TokenStream.h | 135 +--- .../jit-test/tests/modules/export-declaration.js | 4 +- js/src/js.msg | 1 + js/src/jsatom.cpp | 32 - js/src/jsatom.h | 35 - js/src/moz.build | 10 +- js/src/vm/CommonPropertyNames.h | 34 +- js/src/vm/Keywords.h | 66 -- js/src/wasm/AsmJS.cpp | 2 +- 15 files changed, 898 insertions(+), 769 deletions(-) create mode 100644 js/src/frontend/GenerateReservedWords.py create mode 100644 js/src/frontend/ReservedWords.h delete mode 100644 js/src/vm/Keywords.h (limited to 'js/src') diff --git a/js/src/frontend/GenerateReservedWords.py b/js/src/frontend/GenerateReservedWords.py new file mode 100644 index 000000000..bd698cc5f --- /dev/null +++ b/js/src/frontend/GenerateReservedWords.py @@ -0,0 +1,213 @@ +# 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/. + +import re +import sys + +def read_reserved_word_list(filename): + macro_pat = re.compile(r"^\s*macro\(([^,]+), *[^,]+, *[^\)]+\)\s*\\?$") + + reserved_word_list = [] + index = 0 + with open(filename, 'r') as f: + for line in f: + m = macro_pat.search(line) + if m: + reserved_word_list.append((index, m.group(1))) + index += 1 + + assert(len(reserved_word_list) != 0) + + return reserved_word_list + +def line(opt, s): + opt['output'].write('{}{}\n'.format(' ' * opt['indent_level'], s)) + +def indent(opt): + opt['indent_level'] += 1 + +def dedent(opt): + opt['indent_level'] -= 1 + +def span_and_count_at(reserved_word_list, column): + assert(len(reserved_word_list) != 0); + + chars_dict = {} + for index, word in reserved_word_list: + chars_dict[ord(word[column])] = True + + chars = sorted(chars_dict.keys()) + return chars[-1] - chars[0] + 1, len(chars) + +def optimal_switch_column(opt, reserved_word_list, columns, unprocessed_columns): + assert(len(reserved_word_list) != 0); + assert(unprocessed_columns != 0); + + min_count = 0 + min_span = 0 + min_count_index = 0 + min_span_index = 0 + + for index in range(0, unprocessed_columns): + span, count = span_and_count_at(reserved_word_list, columns[index]) + assert(span != 0) + + if span == 1: + assert(count == 1) + return 1, True + + assert(count != 1) + if index == 0 or min_span > span: + min_span = span + min_span_index = index + + if index == 0 or min_count > count: + min_count = count + min_count_index = index + + if min_count <= opt['use_if_threshold']: + return min_count_index, True + + return min_span_index, False + +def split_list_per_column(reserved_word_list, column): + assert(len(reserved_word_list) != 0); + + column_dict = {} + for item in reserved_word_list: + index, word = item + per_column = column_dict.setdefault(word[column], []) + per_column.append(item) + + return sorted(column_dict.items(), key=lambda (char, word): ord(char)) + +def generate_letter_switch(opt, unprocessed_columns, reserved_word_list, + columns=None): + assert(len(reserved_word_list) != 0); + + if not columns: + columns = range(0, unprocessed_columns) + + if len(reserved_word_list) == 1: + index, word = reserved_word_list[0] + + if unprocessed_columns == 0: + line(opt, 'JSRW_GOT_MATCH({}) /* {} */'.format(index, word)) + return + + if unprocessed_columns > opt['char_tail_test_threshold']: + line(opt, 'JSRW_TEST_GUESS({}) /* {} */'.format(index, word)) + return + + conds = [] + for column in columns[0:unprocessed_columns]: + quoted = repr(word[column]) + conds.append('JSRW_AT({})=={}'.format(column, quoted)) + + line(opt, 'if ({}) {{'.format(' && '.join(conds))) + + indent(opt) + line(opt, 'JSRW_GOT_MATCH({}) /* {} */'.format(index, word)) + dedent(opt) + + line(opt, '}') + line(opt, 'JSRW_NO_MATCH()') + return + + assert(unprocessed_columns != 0); + + optimal_column_index, use_if = optimal_switch_column(opt, reserved_word_list, + columns, + unprocessed_columns) + optimal_column = columns[optimal_column_index] + + # Make a copy to avoid breaking passed list. + columns = columns[:] + columns[optimal_column_index] = columns[unprocessed_columns - 1] + + list_per_column = split_list_per_column(reserved_word_list, optimal_column) + + if not use_if: + line(opt, 'switch (JSRW_AT({})) {{'.format(optimal_column)) + + for char, reserved_word_list_per_column in list_per_column: + quoted = repr(char) + if use_if: + line(opt, 'if (JSRW_AT({}) == {}) {{'.format(optimal_column, + quoted)) + else: + line(opt, ' case {}:'.format(quoted)) + + indent(opt) + generate_letter_switch(opt, unprocessed_columns - 1, + reserved_word_list_per_column, columns) + dedent(opt) + + if use_if: + line(opt, '}') + + if not use_if: + line(opt, '}') + + line(opt, 'JSRW_NO_MATCH()') + +def split_list_per_length(reserved_word_list): + assert(len(reserved_word_list) != 0); + + length_dict = {} + for item in reserved_word_list: + index, word = item + per_length = length_dict.setdefault(len(word), []) + per_length.append(item) + + return sorted(length_dict.items(), key=lambda (length, word): length) + +def generate_switch(opt, reserved_word_list): + assert(len(reserved_word_list) != 0); + + line(opt, '/*') + line(opt, ' * Generating switch for the list of {} entries:'.format(len(reserved_word_list))) + for index, word in reserved_word_list: + line(opt, ' * {}'.format(word)) + line(opt, ' */') + + list_per_length = split_list_per_length(reserved_word_list) + + use_if = False + if len(list_per_length) < opt['use_if_threshold']: + use_if = True + + if not use_if: + line(opt, 'switch (JSRW_LENGTH()) {') + + for length, reserved_word_list_per_length in list_per_length: + if use_if: + line(opt, 'if (JSRW_LENGTH() == {}) {{'.format(length)) + else: + line(opt, ' case {}:'.format(length)) + + indent(opt) + generate_letter_switch(opt, length, reserved_word_list_per_length) + dedent(opt) + + if use_if: + line(opt, '}') + + if not use_if: + line(opt, '}') + line(opt, 'JSRW_NO_MATCH()') + +def main(output, reserved_words_h): + reserved_word_list = read_reserved_word_list(reserved_words_h) + + opt = { + 'indent_level': 1, + 'use_if_threshold': 3, + 'char_tail_test_threshold': 4, + 'output': output + } + generate_switch(opt, reserved_word_list) + +if __name__ == '__main__': + main(sys.stdout, *sys.argv[1:]) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 923b42870..9b057fb72 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -62,19 +62,27 @@ using AddDeclaredNamePtr = ParseContext::Scope::AddDeclaredNamePtr; using BindingIter = ParseContext::Scope::BindingIter; using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr; -/* Read a token. Report an error and return null() if that token isn't of type tt. */ -#define MUST_MATCH_TOKEN_MOD(tt, modifier, errorNumber) \ +// Read a token. Report an error and return null() if that token doesn't match +// to the given func's condition. +#define MUST_MATCH_TOKEN_FUNC_MOD(func, modifier, errorNumber) \ JS_BEGIN_MACRO \ TokenKind token; \ if (!tokenStream.getToken(&token, modifier)) \ return null(); \ - if (token != tt) { \ + if (!(func)(token)) { \ error(errorNumber); \ return null(); \ } \ JS_END_MACRO -#define MUST_MATCH_TOKEN(tt, errno) MUST_MATCH_TOKEN_MOD(tt, TokenStream::None, errno) +#define MUST_MATCH_TOKEN_MOD(tt, modifier, errorNumber) \ + MUST_MATCH_TOKEN_FUNC_MOD([](TokenKind tok) { return tok == tt; }, modifier, errorNumber) + +#define MUST_MATCH_TOKEN(tt, errorNumber) \ + MUST_MATCH_TOKEN_MOD(tt, TokenStream::None, errorNumber) + +#define MUST_MATCH_TOKEN_FUNC(func, errorNumber) \ + MUST_MATCH_TOKEN_FUNC_MOD(func, TokenStream::None, errorNumber) template static inline void @@ -753,7 +761,8 @@ ParserBase::ParserBase(ExclusiveContext* cx, LifoAlloc& alloc, checkOptionsCalled(false), #endif abortedSyntaxParse(false), - isUnexpectedEOF_(false) + isUnexpectedEOF_(false), + awaitIsKeyword_(false) { cx->perThreadData->frontendCollectionPool.addActiveCompilation(); tempPoolMark = alloc.mark(); @@ -810,6 +819,22 @@ Parser::~Parser() MOZ_ASSERT(checkOptionsCalled); } +template <> +void +Parser::setAwaitIsKeyword(bool isKeyword) +{ + awaitIsKeyword_ = isKeyword; +} + +template <> +void +Parser::setAwaitIsKeyword(bool isKeyword) +{ + awaitIsKeyword_ = isKeyword; + if (Parser* parser = handler.syntaxParser) + parser->setAwaitIsKeyword(isKeyword); +} + template ObjectBox* Parser::newObjectBox(JSObject* obj) @@ -936,7 +961,7 @@ Parser::parse() /* * Strict mode forbids introducing new definitions for 'eval', 'arguments', or - * for any strict mode reserved keyword. + * for any strict mode reserved word. */ bool ParserBase::isValidStrictBinding(PropertyName* name) @@ -945,7 +970,8 @@ ParserBase::isValidStrictBinding(PropertyName* name) name != context->names().arguments && name != context->names().let && name != context->names().static_ && - !(IsKeyword(name) && name != context->names().await); + name != context->names().yield && + !IsStrictReservedWord(name); } /* @@ -959,13 +985,30 @@ Parser::checkStrictBinding(PropertyName* name, TokenPos pos) if (!pc->sc()->needStrictChecks()) return true; - if (!isValidStrictBinding(name)) { - JSAutoByteString bytes; - if (!AtomToPrintableString(context, name, &bytes)) - return false; - return strictModeErrorAt(pos.begin, JSMSG_BAD_BINDING, bytes.ptr()); + if (name == context->names().arguments) + return strictModeErrorAt(pos.begin, JSMSG_BAD_BINDING, "arguments"); + + if (name == context->names().eval) + return strictModeErrorAt(pos.begin, JSMSG_BAD_BINDING, "eval"); + + if (name == context->names().let) { + errorAt(pos.begin, JSMSG_RESERVED_ID, "let"); + return false; } + if (name == context->names().static_) { + errorAt(pos.begin, JSMSG_RESERVED_ID, "static"); + return false; + } + + if (name == context->names().yield) { + errorAt(pos.begin, JSMSG_RESERVED_ID, "yield"); + return false; + } + + if (IsStrictReservedWord(name)) + return strictModeErrorAt(pos.begin, JSMSG_RESERVED_ID, ReservedWordToCharZ(name)); + return true; } @@ -2094,7 +2137,7 @@ Parser::moduleBody(ModuleSharedContext* modulesc) if (!mn) return null(); - AutoAwaitIsKeyword awaitIsKeyword(&tokenStream, true); + AutoAwaitIsKeyword awaitIsKeyword(this, true); ParseNode* pn = statementList(YieldIsKeyword); if (!pn) return null(); @@ -2417,7 +2460,7 @@ Parser::standaloneFunction(HandleFunction fun, funpc.setIsStandaloneFunctionBody(); YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind); - AutoAwaitIsKeyword awaitIsKeyword(&tokenStream, asyncKind == AsyncFunction); + AutoAwaitIsKeyword awaitIsKeyword(this, asyncKind == AsyncFunction); if (!functionFormalParametersAndBody(InAllowed, yieldHandling, fn, Statement, parameterListEnd, /* isStandaloneFunction = */ true)) { @@ -2719,10 +2762,7 @@ Parser::matchOrInsertSemicolonHelper(TokenStream::Modifier modifie * Detect this situation and throw an understandable error. Otherwise * we'd throw a confusing "missing ; before statement" error. */ - if (!pc->isAsync() && - tokenStream.currentToken().type == TOK_NAME && - tokenStream.currentName() == context->names().await) - { + if (!pc->isAsync() && tokenStream.currentToken().type == TOK_AWAIT) { error(JSMSG_AWAIT_OUTSIDE_ASYNC); return false; } @@ -2845,7 +2885,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn firstTokenModifier = funbox->isAsync() ? TokenStream::None : TokenStream::Operand; if (!tokenStream.peekToken(&tt, firstTokenModifier)) return false; - if (tt == TOK_NAME || tt == TOK_YIELD) { + if (TokenKindIsPossibleIdentifier(tt)) { parenFreeArrow = true; argModifier = firstTokenModifier; } @@ -2901,7 +2941,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn if (!tokenStream.getToken(&tt, argModifier)) return false; argModifier = TokenStream::Operand; - MOZ_ASSERT_IF(parenFreeArrow, tt == TOK_NAME || tt == TOK_YIELD); + MOZ_ASSERT_IF(parenFreeArrow, TokenKindIsPossibleIdentifier(tt)); if (tt == TOK_TRIPLEDOT) { if (IsSetterKind(kind)) { @@ -2922,7 +2962,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn if (!tokenStream.getToken(&tt)) return false; - if (tt != TOK_NAME && tt != TOK_YIELD && tt != TOK_LB && tt != TOK_LC) { + if (!TokenKindIsPossibleIdentifier(tt) && tt != TOK_LB && tt != TOK_LC) { error(JSMSG_NO_REST_NAME); return false; } @@ -2952,20 +2992,15 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn break; } - case TOK_NAME: - case TOK_YIELD: { - if (parenFreeArrow) - funbox->setStart(tokenStream); - - if (funbox->isAsync() && tokenStream.currentName() == context->names().await) { - // `await` is already gotten as TOK_NAME for the following - // case: - // - // async await => 1 - error(JSMSG_RESERVED_ID, "await"); + default: { + if (!TokenKindIsPossibleIdentifier(tt)) { + error(JSMSG_MISSING_FORMAL); return false; } + if (parenFreeArrow) + funbox->setStart(tokenStream); + RootedPropertyName name(context, bindingIdentifier(yieldHandling)); if (!name) return false; @@ -2980,10 +3015,6 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn break; } - - default: - error(JSMSG_MISSING_FORMAL); - return false; } if (positionalFormals.length() >= ARGNO_LIMIT) { @@ -3507,7 +3538,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, FunctionBox* funbox = pc->functionBox(); RootedFunction fun(context, funbox->function()); - AutoAwaitIsKeyword awaitIsKeyword(&tokenStream, funbox->isAsync()); + AutoAwaitIsKeyword awaitIsKeyword(this, funbox->isAsync()); if (!functionArguments(yieldHandling, kind, pn)) return false; @@ -3656,7 +3687,7 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan } RootedPropertyName name(context); - if (tt == TOK_NAME || tt == TOK_YIELD) { + if (TokenKindIsPossibleIdentifier(tt)) { name = bindingIdentifier(yieldHandling); if (!name) return null(); @@ -3712,7 +3743,7 @@ Parser::functionExpr(uint32_t preludeStart, InvokedPrediction invo { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION)); - AutoAwaitIsKeyword awaitIsKeyword(&tokenStream, asyncKind == AsyncFunction); + AutoAwaitIsKeyword awaitIsKeyword(this, asyncKind == AsyncFunction); GeneratorKind generatorKind = asyncKind == AsyncFunction ? StarGenerator : NotGenerator; TokenKind tt; if (!tokenStream.getToken(&tt)) @@ -3731,7 +3762,7 @@ Parser::functionExpr(uint32_t preludeStart, InvokedPrediction invo YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind); RootedPropertyName name(context); - if (tt == TOK_NAME || tt == TOK_YIELD) { + if (TokenKindIsPossibleIdentifier(tt)) { name = bindingIdentifier(yieldHandling); if (!name) return null(); @@ -3768,18 +3799,6 @@ IsEscapeFreeStringLiteral(const TokenPos& pos, JSAtom* str) return pos.begin + str->length() + 2 == pos.end; } -template -bool -Parser::checkUnescapedName() -{ - const Token& token = tokenStream.currentToken(); - if (!token.nameContainsEscape()) - return true; - - errorAt(token.pos.begin, JSMSG_ESCAPED_KEYWORD); - return false; -} - template <> bool Parser::asmJS(Node list) @@ -3998,7 +4017,7 @@ Parser::matchLabel(YieldHandling yieldHandling, MutableHandle::declarationName(Node decl, DeclarationKind declKind, Token ParseNodeKind* forHeadKind, Node* forInOrOfExpression) { // Anything other than TOK_YIELD or TOK_NAME is an error. - if (tt != TOK_NAME && tt != TOK_YIELD) { + // Anything other than possible identifier is an error. + if (!TokenKindIsPossibleIdentifier(tt)) { error(JSMSG_NO_VARIABLE_NAME); return null(); } @@ -4721,16 +4741,13 @@ Parser::namedImportsOrNamespaceImport(TokenKind tt, Node impor // Handle the forms |import {} from 'a'| and // |import { ..., } from 'a'| (where ... is non empty), by // escaping the loop early if the next token is }. - if (!tokenStream.getToken(&tt, TokenStream::KeywordIsName)) + if (!tokenStream.getToken(&tt)) return false; if (tt == TOK_RC) break; - // If the next token is a keyword, the previous call to - // peekToken matched it as a TOK_NAME, and put it in the - // lookahead buffer, so this call will match keywords as well. - if (tt != TOK_NAME) { + if (!TokenKindIsPossibleIdentifierName(tt)) { error(JSMSG_NO_IMPORT_NAME); return false; } @@ -4738,23 +4755,16 @@ Parser::namedImportsOrNamespaceImport(TokenKind tt, Node impor Rooted importName(context, tokenStream.currentName()); TokenPos importNamePos = pos(); - TokenKind maybeAs; - if (!tokenStream.peekToken(&maybeAs)) + bool matched; + if (!tokenStream.matchToken(&matched, TOK_AS)) return null(); - if (maybeAs == TOK_NAME && - tokenStream.nextName() == context->names().as) - { - tokenStream.consumeKnownToken(TOK_NAME); - - if (!checkUnescapedName()) - return false; - + if (matched) { TokenKind afterAs; if (!tokenStream.getToken(&afterAs)) return false; - if (afterAs != TOK_NAME && afterAs != TOK_YIELD) { + if (!TokenKindIsPossibleIdentifierName(afterAs)) { error(JSMSG_NO_BINDING_NAME); return false; } @@ -4764,10 +4774,7 @@ Parser::namedImportsOrNamespaceImport(TokenKind tt, Node impor // by the keyword 'as'. // See the ImportSpecifier production in ES6 section 15.2.2. if (IsKeyword(importName)) { - JSAutoByteString bytes; - if (!AtomToPrintableString(context, importName, &bytes)) - return false; - error(JSMSG_AS_AFTER_RESERVED_WORD, bytes.ptr()); + error(JSMSG_AS_AFTER_RESERVED_WORD, ReservedWordToCharZ(importName)); return false; } } @@ -4806,18 +4813,10 @@ Parser::namedImportsOrNamespaceImport(TokenKind tt, Node impor } } else { MOZ_ASSERT(tt == TOK_MUL); - if (!tokenStream.getToken(&tt)) - return false; - if (tt != TOK_NAME || tokenStream.currentName() != context->names().as) { - error(JSMSG_AS_AFTER_IMPORT_STAR); - return false; - } + MUST_MATCH_TOKEN(TOK_AS, JSMSG_AS_AFTER_IMPORT_STAR); - if (!checkUnescapedName()) - return false; - - MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_BINDING_NAME); + MUST_MATCH_TOKEN_FUNC(TokenKindIsPossibleIdentifierName, JSMSG_NO_BINDING_NAME); Node importName = newName(context->names().star); if (!importName) @@ -4878,8 +4877,15 @@ Parser::importDeclaration() if (!importSpecSet) return null(); - if (tt == TOK_NAME || tt == TOK_LC || tt == TOK_MUL) { - if (tt == TOK_NAME) { + if (tt == TOK_STRING) { + // Handle the form |import 'a'| by leaving the list empty. This is + // equivalent to |import {} from 'a'|. + importSpecSet->pn_pos.end = importSpecSet->pn_pos.begin; + } else { + if (tt == TOK_LC || tt == TOK_MUL) { + if (!namedImportsOrNamespaceImport(tt, importSpecSet)) + return null(); + } else if (TokenKindIsPossibleIdentifierName(tt)) { // Handle the form |import a from 'b'|, by adding a single import // specifier to the list, with 'default' as the import name and // 'a' as the binding name. This is equivalent to @@ -4922,29 +4928,19 @@ Parser::importDeclaration() return null(); } } else { - if (!namedImportsOrNamespaceImport(tt, importSpecSet)) - return null(); + error(JSMSG_DECLARATION_AFTER_IMPORT); + return null(); } if (!tokenStream.getToken(&tt)) return null(); - if (tt != TOK_NAME || tokenStream.currentName() != context->names().from) { + if (tt != TOK_FROM) { error(JSMSG_FROM_AFTER_IMPORT_CLAUSE); return null(); } - if (!checkUnescapedName()) - return null(); - MUST_MATCH_TOKEN(TOK_STRING, JSMSG_MODULE_SPEC_AFTER_FROM); - } else if (tt == TOK_STRING) { - // Handle the form |import 'a'| by leaving the list empty. This is - // equivalent to |import {} from 'a'|. - importSpecSet->pn_pos.end = importSpecSet->pn_pos.begin; - } else { - error(JSMSG_DECLARATION_AFTER_IMPORT); - return null(); } Node moduleSpec = stringLiteral(); @@ -5050,7 +5046,7 @@ Parser::exportDeclaration() if (tt == TOK_RC) break; - if (tt != TOK_NAME) { + if (!TokenKindIsPossibleIdentifierName(tt)) { error(JSMSG_NO_BINDING_NAME); return null(); } @@ -5060,10 +5056,10 @@ Parser::exportDeclaration() return null(); bool foundAs; - if (!tokenStream.matchContextualKeyword(&foundAs, context->names().as)) + if (!tokenStream.matchToken(&foundAs, TOK_AS)) return null(); if (foundAs) - MUST_MATCH_TOKEN_MOD(TOK_NAME, TokenStream::KeywordIsName, JSMSG_NO_EXPORT_NAME); + MUST_MATCH_TOKEN_FUNC(TokenKindIsPossibleIdentifierName, JSMSG_NO_EXPORT_NAME); Node exportName = newName(tokenStream.currentName()); if (!exportName) @@ -5098,21 +5094,18 @@ Parser::exportDeclaration() // from "foo"; // a single ExportDeclaration // // But if it doesn't, we might have an ASI opportunity in Operand - // context, so simply matching a contextual keyword won't work: + // context: // // export { x } // ExportDeclaration, terminated by ASI // fro\u006D // ExpressionStatement, the name "from" // // In that case let matchOrInsertSemicolonAfterNonExpression sort out // ASI or any necessary error. - TokenKind tt; - if (!tokenStream.getToken(&tt, TokenStream::Operand)) + bool matched; + if (!tokenStream.matchToken(&matched, TOK_FROM, TokenStream::Operand)) return null(); - if (tt == TOK_NAME && - tokenStream.currentToken().name() == context->names().from && - !tokenStream.currentToken().nameContainsEscape()) - { + if (matched) { MUST_MATCH_TOKEN(TOK_STRING, JSMSG_MODULE_SPEC_AFTER_FROM); Node moduleSpec = stringLiteral(); @@ -5129,8 +5122,6 @@ Parser::exportDeclaration() return node; } - tokenStream.ungetToken(); - if (!matchOrInsertSemicolonAfterNonExpression()) return null(); break; @@ -5151,14 +5142,11 @@ Parser::exportDeclaration() if (!tokenStream.getToken(&tt)) return null(); - if (tt != TOK_NAME || tokenStream.currentName() != context->names().from) { + if (tt != TOK_FROM) { error(JSMSG_FROM_AFTER_EXPORT_STAR); return null(); } - if (!checkUnescapedName()) - return null(); - MUST_MATCH_TOKEN(TOK_STRING, JSMSG_MODULE_SPEC_AFTER_FROM); Node moduleSpec = stringLiteral(); @@ -5227,10 +5215,7 @@ Parser::exportDeclaration() return null(); break; default: { - if (tt == TOK_NAME && - tokenStream.currentName() == context->names().async && - !tokenStream.currentToken().nameContainsEscape()) - { + if (tt == TOK_ASYNC) { TokenKind nextSameLine = TOK_EOF; if (!tokenStream.peekTokenSameLine(&nextSameLine)) return null(); @@ -5276,19 +5261,13 @@ Parser::exportDeclaration() return null(); break; - case TOK_NAME: - if (tokenStream.currentName() == context->names().let) { - if (!checkUnescapedName()) - return null(); - - kid = lexicalDeclaration(YieldIsName, /* isConst = */ false); - if (!kid) - return null(); - if (!checkExportedNamesForDeclaration(kid)) - return null(); - break; - } - MOZ_FALLTHROUGH; + case TOK_LET: + kid = lexicalDeclaration(YieldIsName, /* isConst = */ false); + if (!kid) + return null(); + if (!checkExportedNamesForDeclaration(kid)) + return null(); + break; default: error(JSMSG_DECLARATION_AFTER_EXPORT); @@ -5338,10 +5317,7 @@ Parser::consequentOrAlternative(YieldHandling yieldHandling) // // Careful! FunctionDeclaration doesn't include generators or async // functions. - if (next == TOK_NAME && - !tokenStream.nextNameContainsEscape() && - tokenStream.nextName() == context->names().async) - { + if (next == TOK_ASYNC) { tokenStream.consumeKnownToken(next, TokenStream::Operand); // Peek only on the same line: ExpressionStatement's lookahead @@ -5514,13 +5490,9 @@ Parser::matchInOrOf(bool* isForInp, bool* isForOfp) return false; *isForInp = tt == TOK_IN; - *isForOfp = tt == TOK_NAME && tokenStream.currentToken().name() == context->names().of; - if (!*isForInp && !*isForOfp) { + *isForOfp = tt == TOK_OF; + if (!*isForInp && !*isForOfp) tokenStream.ungetToken(); - } else { - if (tt == TOK_NAME && !checkUnescapedName()) - return false; - } MOZ_ASSERT_IF(*isForInp || *isForOfp, *isForInp != *isForOfp); return true; @@ -5570,15 +5542,12 @@ Parser::forHeadStart(YieldHandling yieldHandling, if (tt == TOK_CONST) { parsingLexicalDeclaration = true; tokenStream.consumeKnownToken(tt, TokenStream::Operand); - } else if (tt == TOK_NAME && - tokenStream.nextName() == context->names().let && - !tokenStream.nextNameContainsEscape()) - { + } else if (tt == TOK_LET) { // We could have a {For,Lexical}Declaration, or we could have a // LeftHandSideExpression with lookahead restrictions so it's not // ambiguous with the former. Check for a continuation of the former // to decide which we have. - tokenStream.consumeKnownToken(TOK_NAME, TokenStream::Operand); + tokenStream.consumeKnownToken(TOK_LET, TokenStream::Operand); TokenKind next; if (!tokenStream.peekToken(&next)) @@ -5699,7 +5668,7 @@ Parser::forStatement(YieldHandling yieldHandling) if (allowsForEachIn()) { bool matched; - if (!tokenStream.matchContextualKeyword(&matched, context->names().each)) + if (!tokenStream.matchToken(&matched, TOK_EACH)) return null(); if (matched) { iflags = JSITER_FOREACH; @@ -6410,12 +6379,12 @@ Parser::tryStatement(YieldHandling yieldHandling) * kid3 is the finally statement * * catch nodes are ternary. - * kid1 is the lvalue (TOK_NAME, TOK_LB, or TOK_LC) + * kid1 is the lvalue (possible identifier, TOK_LB, or TOK_LC) * kid2 is the catch guard or null if no guard * kid3 is the catch block * * catch lvalue nodes are either: - * TOK_NAME for a single identifier + * a single identifier * TOK_RB or TOK_RC for a destructuring left-hand side * * finally nodes are TOK_LC statement lists. @@ -6490,8 +6459,12 @@ Parser::tryStatement(YieldHandling yieldHandling) return null(); break; - case TOK_NAME: - case TOK_YIELD: { + default: { + if (!TokenKindIsPossibleIdentifierName(tt)) { + error(JSMSG_CATCH_IDENTIFIER); + return null(); + } + RootedPropertyName param(context, bindingIdentifier(yieldHandling)); if (!param) return null(); @@ -6502,10 +6475,6 @@ Parser::tryStatement(YieldHandling yieldHandling) return null(); break; } - - default: - error(JSMSG_CATCH_IDENTIFIER); - return null(); } Node catchGuard = null(); @@ -6664,7 +6633,7 @@ Parser::classDefinition(YieldHandling yieldHandling, return null(); RootedPropertyName name(context); - if (tt == TOK_NAME || tt == TOK_YIELD) { + if (TokenKindIsPossibleIdentifier(tt)) { name = bindingIdentifier(yieldHandling); if (!name) return null(); @@ -6721,7 +6690,7 @@ Parser::classDefinition(YieldHandling yieldHandling, bool seenConstructor = false; for (;;) { TokenKind tt; - if (!tokenStream.getToken(&tt, TokenStream::KeywordIsName)) + if (!tokenStream.getToken(&tt)) return null(); if (tt == TOK_RC) break; @@ -6730,22 +6699,18 @@ Parser::classDefinition(YieldHandling yieldHandling, continue; bool isStatic = false; - if (tt == TOK_NAME && tokenStream.currentName() == context->names().static_) { - if (!tokenStream.peekToken(&tt, TokenStream::KeywordIsName)) + if (tt == TOK_STATIC) { + if (!tokenStream.peekToken(&tt)) return null(); if (tt == TOK_RC) { - tokenStream.consumeKnownToken(tt, TokenStream::KeywordIsName); + tokenStream.consumeKnownToken(tt); error(JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(tt)); return null(); } if (tt != TOK_LP) { - if (!checkUnescapedName()) - return null(); - isStatic = true; } else { - tokenStream.addModifierException(TokenStream::NoneIsKeywordIsName); tokenStream.ungetToken(); } } else { @@ -6865,9 +6830,7 @@ template bool Parser::nextTokenContinuesLetDeclaration(TokenKind next, YieldHandling yieldHandling) { - MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_NAME)); - MOZ_ASSERT(tokenStream.currentName() == context->names().let); - MOZ_ASSERT(!tokenStream.currentToken().nameContainsEscape()); + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LET)); #ifdef DEBUG TokenKind verify; @@ -6879,18 +6842,19 @@ Parser::nextTokenContinuesLetDeclaration(TokenKind next, YieldHand if (next == TOK_LB || next == TOK_LC) return true; - // Otherwise a let declaration must have a name. - if (next == TOK_NAME) { - if (tokenStream.nextName() == context->names().yield) { - MOZ_ASSERT(tokenStream.nextNameContainsEscape(), - "token stream should interpret unescaped 'yield' as TOK_YIELD"); - - // Same as |next == TOK_YIELD|. - return yieldHandling == YieldIsName; - } + // If we have the name "yield", the grammar parameter exactly states + // whether this is okay. (This wasn't true for SpiderMonkey's ancient + // legacy generator syntax, but that's dead now.) If YieldIsName, + // declaration-parsing code will (if necessary) enforce a strict mode + // restriction on defining "yield". If YieldIsKeyword, consider this the + // end of the declaration, in case ASI induces a semicolon that makes the + // "yield" valid. + if (next == TOK_YIELD) + return yieldHandling == YieldIsName; - // One non-"yield" TOK_NAME edge case deserves special comment. - // Consider this: + // Otherwise a let declaration must have a name. + if (TokenKindIsPossibleIdentifier(next)) { + // A "let" edge case deserves special comment. Consider this: // // let // not an ASI opportunity // let; @@ -6903,16 +6867,6 @@ Parser::nextTokenContinuesLetDeclaration(TokenKind next, YieldHand return true; } - // If we have the name "yield", the grammar parameter exactly states - // whether this is okay. (This wasn't true for SpiderMonkey's ancient - // legacy generator syntax, but that's dead now.) If YieldIsName, - // declaration-parsing code will (if necessary) enforce a strict mode - // restriction on defining "yield". If YieldIsKeyword, consider this the - // end of the declaration, in case ASI induces a semicolon that makes the - // "yield" valid. - if (next == TOK_YIELD) - return yieldHandling == YieldIsName; - // Otherwise not a let declaration. return false; } @@ -6975,16 +6929,21 @@ Parser::statement(YieldHandling yieldHandling) return expressionStatement(yieldHandling); } - case TOK_NAME: { + default: { + // Avoid getting next token with None. + if (tt == TOK_AWAIT && pc->isAsync()) + return expressionStatement(yieldHandling); + + if (!TokenKindIsPossibleIdentifier(tt)) + return expressionStatement(yieldHandling); + TokenKind next; if (!tokenStream.peekToken(&next)) return null(); // |let| here can only be an Identifier, not a declaration. Give nicer // errors for declaration-looking typos. - if (!tokenStream.currentToken().nameContainsEscape() && - tokenStream.currentName() == context->names().let) - { + if (tt == TOK_LET) { bool forbiddenLetDeclaration = false; if (pc->sc()->strict() || versionNumber() >= JSVERSION_1_7) { @@ -6994,7 +6953,7 @@ Parser::statement(YieldHandling yieldHandling) } else if (next == TOK_LB) { // Enforce ExpressionStatement's 'let [' lookahead restriction. forbiddenLetDeclaration = true; - } else if (next == TOK_LC || next == TOK_NAME) { + } else if (next == TOK_LC || TokenKindIsPossibleIdentifier(next)) { // 'let {' and 'let foo' aren't completely forbidden, if ASI // causes 'let' to be the entire Statement. But if they're // same-line, we can aggressively give a better error message. @@ -7005,7 +6964,7 @@ Parser::statement(YieldHandling yieldHandling) if (!tokenStream.peekTokenSameLine(&nextSameLine)) return null(); - MOZ_ASSERT(nextSameLine == TOK_NAME || + MOZ_ASSERT(TokenKindIsPossibleIdentifier(nextSameLine) || nextSameLine == TOK_LC || nextSameLine == TOK_EOL); @@ -7029,9 +6988,6 @@ Parser::statement(YieldHandling yieldHandling) case TOK_NEW: return expressionStatement(yieldHandling, PredictInvoked); - default: - return expressionStatement(yieldHandling); - // IfStatement[?Yield, ?Return] case TOK_IF: return ifStatement(yieldHandling); @@ -7077,7 +7033,7 @@ Parser::statement(YieldHandling yieldHandling) return withStatement(yieldHandling); // LabelledStatement[?Yield, ?Return] - // This is really handled by TOK_NAME and TOK_YIELD cases above. + // This is really handled by default and TOK_YIELD cases above. // ThrowStatement[?Yield] case TOK_THROW: @@ -7183,28 +7139,29 @@ Parser::statementListItem(YieldHandling yieldHandling, return expressionStatement(yieldHandling); } - case TOK_NAME: { + default: { + // Avoid getting next token with None. + if (tt == TOK_AWAIT && pc->isAsync()) + return expressionStatement(yieldHandling); + + if (!TokenKindIsPossibleIdentifier(tt)) + return expressionStatement(yieldHandling); + TokenKind next; if (!tokenStream.peekToken(&next)) return null(); - if (!tokenStream.currentToken().nameContainsEscape()) { - if (tokenStream.currentName() == context->names().let && - nextTokenContinuesLetDeclaration(next, yieldHandling)) - { - return lexicalDeclaration(yieldHandling, /* isConst = */ false); - } + if (tt == TOK_LET && nextTokenContinuesLetDeclaration(next, yieldHandling)) + return lexicalDeclaration(yieldHandling, /* isConst = */ false); - if (tokenStream.currentName() == context->names().async) { - TokenKind nextSameLine = TOK_EOF; - if (!tokenStream.peekTokenSameLine(&nextSameLine)) { - return null(); - } - if (nextSameLine == TOK_FUNCTION) { - uint32_t preludeStart = pos().begin; - tokenStream.consumeKnownToken(TOK_FUNCTION); - return functionStmt(preludeStart, yieldHandling, NameRequired, AsyncFunction); - } + if (tt == TOK_ASYNC) { + TokenKind nextSameLine = TOK_EOF; + if (!tokenStream.peekTokenSameLine(&nextSameLine)) + return null(); + if (nextSameLine == TOK_FUNCTION) { + uint32_t preludeStart = pos().begin; + tokenStream.consumeKnownToken(TOK_FUNCTION); + return functionStmt(preludeStart, yieldHandling, NameRequired, AsyncFunction); } } @@ -7217,9 +7174,6 @@ Parser::statementListItem(YieldHandling yieldHandling, case TOK_NEW: return expressionStatement(yieldHandling, PredictInvoked); - default: - return expressionStatement(yieldHandling); - // IfStatement[?Yield, ?Return] case TOK_IF: return ifStatement(yieldHandling); @@ -7265,7 +7219,7 @@ Parser::statementListItem(YieldHandling yieldHandling, return withStatement(yieldHandling); // LabelledStatement[?Yield, ?Return] - // This is really handled by TOK_NAME and TOK_YIELD cases above. + // This is really handled by default and TOK_YIELD cases above. // ThrowStatement[?Yield] case TOK_THROW: @@ -7631,6 +7585,9 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl bool endsExpr; + // This only handles identifiers that *never* have special meaning anywhere + // in the language. Contextual keywords, reserved words in strict mode, + // and other hard cases are handled outside this fast path. if (tt == TOK_NAME) { if (!tokenStream.nextTokenEndsExpr(&endsExpr)) return null(); @@ -7661,15 +7618,12 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl return yieldExpression(inHandling); bool maybeAsyncArrow = false; - if (tt == TOK_NAME && - tokenStream.currentName() == context->names().async && - !tokenStream.currentToken().nameContainsEscape()) - { + if (tt == TOK_ASYNC) { TokenKind nextSameLine = TOK_EOF; if (!tokenStream.peekTokenSameLine(&nextSameLine)) return null(); - if (nextSameLine == TOK_NAME || nextSameLine == TOK_YIELD) + if (TokenKindIsPossibleIdentifier(nextSameLine)) maybeAsyncArrow = true; } @@ -7683,14 +7637,12 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl PossibleError possibleErrorInner(*this); Node lhs; if (maybeAsyncArrow) { - tokenStream.consumeKnownToken(TOK_NAME, TokenStream::Operand); - MOZ_ASSERT(tokenStream.currentName() == context->names().async); - MOZ_ASSERT(!tokenStream.currentToken().nameContainsEscape()); + tokenStream.consumeKnownToken(TOK_ASYNC, TokenStream::Operand); TokenKind tt; if (!tokenStream.getToken(&tt)) return null(); - MOZ_ASSERT(tt == TOK_NAME || tt == TOK_YIELD); + MOZ_ASSERT(TokenKindIsPossibleIdentifier(tt)); // Check yield validity here. RootedPropertyName name(context, bindingIdentifier(yieldHandling)); @@ -7759,24 +7711,18 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl GeneratorKind generatorKind = NotGenerator; FunctionAsyncKind asyncKind = SyncFunction; - if (next == TOK_NAME) { + if (next == TOK_ASYNC) { tokenStream.consumeKnownToken(next, TokenStream::Operand); - if (tokenStream.currentName() == context->names().async && - !tokenStream.currentToken().nameContainsEscape()) - { - TokenKind nextSameLine = TOK_EOF; - if (!tokenStream.peekTokenSameLine(&nextSameLine)) - return null(); + TokenKind nextSameLine = TOK_EOF; + if (!tokenStream.peekTokenSameLine(&nextSameLine)) + return null(); - if (nextSameLine == TOK_ARROW) { - tokenStream.ungetToken(); - } else { - generatorKind = StarGenerator; - asyncKind = AsyncFunction; - } - } else { + if (nextSameLine == TOK_ARROW) { tokenStream.ungetToken(); + } else { + generatorKind = StarGenerator; + asyncKind = AsyncFunction; } } @@ -8025,20 +7971,17 @@ Parser::unaryExpr(YieldHandling yieldHandling, TripledotHandling t } case TOK_AWAIT: { - if (!pc->isAsync()) { - // TOK_AWAIT can be returned in module, even if it's not inside - // async function. - error(JSMSG_RESERVED_ID, "await"); - return null(); + if (pc->isAsync()) { + Node kid = unaryExpr(yieldHandling, tripledotHandling, possibleError, invoked); + if (!kid) + return null(); + pc->lastAwaitOffset = begin; + return newAwaitExpression(begin, kid); } - - Node kid = unaryExpr(yieldHandling, tripledotHandling, possibleError, invoked); - if (!kid) - return null(); - pc->lastAwaitOffset = begin; - return newAwaitExpression(begin, kid); } + MOZ_FALLTHROUGH; + default: { Node expr = memberExpr(yieldHandling, tripledotHandling, tt, /* allowCallSyntax = */ true, possibleError, invoked); @@ -8176,7 +8119,7 @@ Parser::comprehensionFor(GeneratorKind comprehensionKind) // FIXME: Destructuring binding (bug 980828). - MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_VARIABLE_NAME); + MUST_MATCH_TOKEN_FUNC(TokenKindIsPossibleIdentifier, JSMSG_NO_VARIABLE_NAME); RootedPropertyName name(context, tokenStream.currentName()); if (name == context->names().let) { error(JSMSG_LET_COMP_BINDING); @@ -8187,7 +8130,7 @@ Parser::comprehensionFor(GeneratorKind comprehensionKind) if (!lhs) return null(); bool matched; - if (!tokenStream.matchContextualKeyword(&matched, context->names().of)) + if (!tokenStream.matchToken(&matched, TOK_OF)) return null(); if (!matched) { error(JSMSG_OF_AFTER_FOR_NAME); @@ -8522,9 +8465,9 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling Node nextMember; if (tt == TOK_DOT) { - if (!tokenStream.getToken(&tt, TokenStream::KeywordIsName)) + if (!tokenStream.getToken(&tt)) return null(); - if (tt == TOK_NAME) { + if (TokenKindIsPossibleIdentifierName(tt)) { PropertyName* field = tokenStream.currentName(); if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) { error(JSMSG_BAD_SUPERPROP, "property"); @@ -8695,46 +8638,52 @@ Parser::newName(PropertyName* name, TokenPos pos) template PropertyName* -Parser::labelOrIdentifierReference(YieldHandling yieldHandling, - bool yieldTokenizedAsName) -{ - PropertyName* ident; - bool isYield; - const Token& tok = tokenStream.currentToken(); - if (tok.type == TOK_NAME) { - MOZ_ASSERT(tok.name() != context->names().yield || - tok.nameContainsEscape() || - yieldTokenizedAsName, - "tokenizer should have treated unescaped 'yield' as TOK_YIELD"); - MOZ_ASSERT_IF(yieldTokenizedAsName, tok.name() == context->names().yield); - - ident = tok.name(); - isYield = ident == context->names().yield; - } else { - MOZ_ASSERT(tok.type == TOK_YIELD && !yieldTokenizedAsName); - - ident = context->names().yield; - isYield = true; - } - - if (!isYield) { - if (pc->sc()->strict()) { - const char* badName = ident == context->names().let - ? "let" - : ident == context->names().static_ - ? "static" - : nullptr; - if (badName) { - error(JSMSG_RESERVED_ID, badName); - return nullptr; - } - } - } else { +Parser::checkLabelOrIdentifierReference(PropertyName* ident, + uint32_t offset, + YieldHandling yieldHandling) +{ + if (ident == context->names().yield) { if (yieldHandling == YieldIsKeyword || pc->sc()->strict() || versionNumber() >= JSVERSION_1_7) { - error(JSMSG_RESERVED_ID, "yield"); + errorAt(offset, JSMSG_RESERVED_ID, "yield"); + return nullptr; + } + return ident; + } + + if (ident == context->names().await) { + if (awaitIsKeyword()) { + errorAt(offset, JSMSG_RESERVED_ID, "await"); + return nullptr; + } + return ident; + } + + if (IsKeyword(ident) || IsReservedWordLiteral(ident)) { + errorAt(offset, JSMSG_INVALID_ID, ReservedWordToCharZ(ident)); + return nullptr; + } + + if (IsFutureReservedWord(ident)) { + errorAt(offset, JSMSG_RESERVED_ID, ReservedWordToCharZ(ident)); + return nullptr; + } + + if (pc->sc()->strict()) { + if (IsStrictReservedWord(ident)) { + errorAt(offset, JSMSG_RESERVED_ID, ReservedWordToCharZ(ident)); + return nullptr; + } + + if (ident == context->names().let) { + errorAt(offset, JSMSG_RESERVED_ID, "let"); + return nullptr; + } + + if (ident == context->names().static_) { + errorAt(offset, JSMSG_RESERVED_ID, "static"); return nullptr; } } @@ -8744,52 +8693,34 @@ Parser::labelOrIdentifierReference(YieldHandling yieldHandling, template PropertyName* -Parser::bindingIdentifier(YieldHandling yieldHandling) +Parser::labelOrIdentifierReference(YieldHandling yieldHandling) { - PropertyName* ident; - bool isYield; - const Token& tok = tokenStream.currentToken(); - if (tok.type == TOK_NAME) { - MOZ_ASSERT(tok.name() != context->names().yield || tok.nameContainsEscape(), - "tokenizer should have treated unescaped 'yield' as TOK_YIELD"); - - ident = tok.name(); - isYield = ident == context->names().yield; - } else { - MOZ_ASSERT(tok.type == TOK_YIELD); + // ES 2017 draft 12.1.1. + // StringValue of IdentifierName normalizes any Unicode escape sequences + // in IdentifierName hence such escapes cannot be used to write an + // Identifier whose code point sequence is the same as a ReservedWord. + // + // Use PropertyName* instead of TokenKind to reflect the normalization. - ident = context->names().yield; - isYield = true; - } + return checkLabelOrIdentifierReference(tokenStream.currentName(), pos().begin, yieldHandling); +} - if (!isYield) { - if (pc->sc()->strict()) { - const char* badName = ident == context->names().arguments - ? "arguments" - : ident == context->names().eval - ? "eval" - : nullptr; - if (badName) { - error(JSMSG_BAD_STRICT_ASSIGN, badName); - return nullptr; - } +template +PropertyName* +Parser::bindingIdentifier(YieldHandling yieldHandling) +{ + PropertyName* ident = labelOrIdentifierReference(yieldHandling); + if (!ident) + return nullptr; - badName = ident == context->names().let - ? "let" - : ident == context->names().static_ - ? "static" - : nullptr; - if (badName) { - error(JSMSG_RESERVED_ID, badName); - return nullptr; - } + if (pc->sc()->strict()) { + if (ident == context->names().arguments) { + error(JSMSG_BAD_STRICT_ASSIGN, "arguments"); + return nullptr; } - } else { - if (yieldHandling == YieldIsKeyword || - pc->sc()->strict() || - versionNumber() >= JSVERSION_1_7) - { - error(JSMSG_RESERVED_ID, "yield"); + + if (ident == context->names().eval) { + error(JSMSG_BAD_STRICT_ASSIGN, "eval"); return nullptr; } } @@ -8970,7 +8901,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, PropertyType* propType, MutableHandleAtom propAtom) { TokenKind ltok; - if (!tokenStream.getToken(<ok, TokenStream::KeywordIsName)) + if (!tokenStream.getToken(<ok)) return null(); MOZ_ASSERT(ltok != TOK_RC, "caller should have handled TOK_RC"); @@ -8979,14 +8910,11 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, bool isAsync = false; if (ltok == TOK_MUL) { isGenerator = true; - if (!tokenStream.getToken(<ok, TokenStream::KeywordIsName)) + if (!tokenStream.getToken(<ok)) return null(); } - if (ltok == TOK_NAME && - tokenStream.currentName() == context->names().async && - !tokenStream.currentToken().nameContainsEscape()) - { + if (ltok == TOK_ASYNC) { // AsyncMethod[Yield, Await]: // async [no LineTerminator here] PropertyName[?Yield, ?Await] ... // @@ -9002,16 +8930,13 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, // ComputedPropertyName[Yield, Await]: // [ ... TokenKind tt = TOK_EOF; - if (!tokenStream.peekTokenSameLine(&tt, TokenStream::KeywordIsName)) + if (!tokenStream.getToken(&tt)) return null(); - if (tt == TOK_STRING || tt == TOK_NUMBER || tt == TOK_LB || - tt == TOK_NAME || tt == TOK_YIELD) - { + if (tt != TOK_LP && tt != TOK_COLON && tt != TOK_RC && tt != TOK_ASSIGN) { isAsync = true; - tokenStream.consumeKnownToken(tt, TokenStream::KeywordIsName); ltok = tt; } else { - tokenStream.addModifierException(TokenStream::NoneIsKeywordIsName); + tokenStream.ungetToken(); } } @@ -9038,41 +8963,36 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, return null(); break; - case TOK_NAME: { + default: { + if (!TokenKindIsPossibleIdentifierName(ltok)) { + error(JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(ltok)); + return null(); + } + propAtom.set(tokenStream.currentName()); // Do not look for accessor syntax on generators - if (isGenerator || isAsync || - !(propAtom.get() == context->names().get || - propAtom.get() == context->names().set)) - { + if (isGenerator || isAsync || !(ltok == TOK_GET || ltok == TOK_SET)) { propName = handler.newObjectLiteralPropertyName(propAtom, pos()); if (!propName) return null(); break; } - *propType = propAtom.get() == context->names().get ? PropertyType::Getter - : PropertyType::Setter; + *propType = ltok == TOK_GET ? PropertyType::Getter : PropertyType::Setter; // We have parsed |get| or |set|. Look for an accessor property // name next. TokenKind tt; - if (!tokenStream.peekToken(&tt, TokenStream::KeywordIsName)) + if (!tokenStream.peekToken(&tt)) return null(); - if (tt == TOK_NAME) { - if (!checkUnescapedName()) - return null(); - - tokenStream.consumeKnownToken(TOK_NAME, TokenStream::KeywordIsName); + if (TokenKindIsPossibleIdentifierName(tt)) { + tokenStream.consumeKnownToken(tt); propAtom.set(tokenStream.currentName()); return handler.newObjectLiteralPropertyName(propAtom, pos()); } if (tt == TOK_STRING) { - if (!checkUnescapedName()) - return null(); - - tokenStream.consumeKnownToken(TOK_STRING, TokenStream::KeywordIsName); + tokenStream.consumeKnownToken(TOK_STRING); propAtom.set(tokenStream.currentToken().atom()); @@ -9086,10 +9006,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, return stringLiteral(); } if (tt == TOK_NUMBER) { - if (!checkUnescapedName()) - return null(); - - tokenStream.consumeKnownToken(TOK_NUMBER, TokenStream::KeywordIsName); + tokenStream.consumeKnownToken(TOK_NUMBER); propAtom.set(DoubleToAtom(context, tokenStream.currentToken().number())); if (!propAtom.get()) @@ -9097,10 +9014,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, return newNumber(tokenStream.currentToken()); } if (tt == TOK_LB) { - if (!checkUnescapedName()) - return null(); - - tokenStream.consumeKnownToken(TOK_LB, TokenStream::KeywordIsName); + tokenStream.consumeKnownToken(TOK_LB); return computedPropertyName(yieldHandling, propList); } @@ -9109,7 +9023,6 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, propName = handler.newObjectLiteralPropertyName(propAtom.get(), pos()); if (!propName) return null(); - tokenStream.addModifierException(TokenStream::NoneIsKeywordIsName); break; } @@ -9127,10 +9040,6 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, return null(); break; } - - default: - error(JSMSG_BAD_PROP_ID); - return null(); } TokenKind tt; @@ -9146,7 +9055,9 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, return propName; } - if (ltok == TOK_NAME && (tt == TOK_COMMA || tt == TOK_RC || tt == TOK_ASSIGN)) { + if (TokenKindIsPossibleIdentifierName(ltok) && + (tt == TOK_COMMA || tt == TOK_RC || tt == TOK_ASSIGN)) + { if (isGenerator) { error(JSMSG_BAD_PROP_ID); return null(); @@ -9214,7 +9125,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* RootedAtom propAtom(context); for (;;) { TokenKind tt; - if (!tokenStream.getToken(&tt, TokenStream::KeywordIsName)) + if (!tokenStream.getToken(&tt)) return null(); if (tt == TOK_RC) break; @@ -9274,17 +9185,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* * for |var {x: x, y: y} = o|, and |var o = {x, y}| as initializer * shorthand for |var o = {x: x, y: y}|. */ - TokenKind propToken = TOK_NAME; - if (!tokenStream.checkForKeyword(propAtom, &propToken)) - return null(); - - if (propToken != TOK_NAME && propToken != TOK_YIELD) { - error(JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); - return null(); - } - - Rooted name(context, - identifierReference(yieldHandling, propToken == TOK_YIELD)); + Rooted name(context, identifierReference(yieldHandling)); if (!name) return null(); @@ -9299,17 +9200,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* * Support, e.g., |var {x=1, y=2} = o| as destructuring shorthand * with default values, as per ES6 12.14.5 */ - TokenKind propToken = TOK_NAME; - if (!tokenStream.checkForKeyword(propAtom, &propToken)) - return null(); - - if (propToken != TOK_NAME && propToken != TOK_YIELD) { - error(JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); - return null(); - } - - Rooted name(context, - identifierReference(yieldHandling, propToken == TOK_YIELD)); + Rooted name(context, identifierReference(yieldHandling)); if (!name) return null(); @@ -9482,14 +9373,11 @@ Parser::tryNewTarget(Node &newTarget) if (!tokenStream.getToken(&next)) return false; - if (next != TOK_NAME || tokenStream.currentName() != context->names().target) { + if (next != TOK_TARGET) { error(JSMSG_UNEXPECTED_TOKEN, "target", TokenKindToDesc(next)); return false; } - if (!checkUnescapedName()) - return false; - if (!pc->sc()->allowNewTarget()) { errorAt(begin, JSMSG_BAD_NEWTARGET); return false; @@ -9572,11 +9460,13 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling case TOK_STRING: return stringLiteral(); - case TOK_YIELD: - case TOK_NAME: { - if (tokenStream.currentName() == context->names().async && - !tokenStream.currentToken().nameContainsEscape()) - { + default: { + if (!TokenKindIsPossibleIdentifier(tt)) { + error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); + return null(); + } + + if (tt == TOK_ASYNC) { TokenKind nextSameLine = TOK_EOF; if (!tokenStream.peekTokenSameLine(&nextSameLine)) return null(); @@ -9648,7 +9538,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling // the enclosing code is strict mode code, any of "let", "yield", // or "arguments" should be prohibited. Argument-parsing code // handles that. - if (next != TOK_NAME && next != TOK_YIELD) { + if (!TokenKindIsPossibleIdentifier(next)) { error(JSMSG_UNEXPECTED_TOKEN, "rest argument name", TokenKindToDesc(next)); return null(); } @@ -9675,10 +9565,6 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling // Return an arbitrary expression node. See case TOK_RP above. return handler.newNullLiteral(pos()); } - - default: - error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); - return null(); } } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 35b9384a8..9ec862d92 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -734,6 +734,9 @@ class UsedNameTracker } }; +template +class AutoAwaitIsKeyword; + class ParserBase : public StrictModeGetter { private: @@ -783,7 +786,13 @@ class ParserBase : public StrictModeGetter /* Unexpected end of input, i.e. TOK_EOF not at top-level. */ bool isUnexpectedEOF_:1; + bool awaitIsKeyword_:1; + public: + bool awaitIsKeyword() const { + return awaitIsKeyword_; + } + ParserBase(ExclusiveContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options, const char16_t* chars, size_t length, bool foldConstants, UsedNameTracker& usedNames, Parser* syntaxParser, @@ -998,6 +1007,9 @@ class Parser final : public ParserBase, private JS::AutoGCRooter Parser* syntaxParser, LazyScript* lazyOuterFunction); ~Parser(); + friend class AutoAwaitIsKeyword; + void setAwaitIsKeyword(bool isKeyword); + bool checkOptions(); // A Parser::Mark is the extension of the LifoAlloc::Mark to the entire @@ -1047,8 +1059,6 @@ class Parser final : public ParserBase, private JS::AutoGCRooter void trace(JSTracer* trc); - bool checkUnescapedName(); - private: Parser* thisForCtor() { return this; } @@ -1321,17 +1331,18 @@ class Parser final : public ParserBase, private JS::AutoGCRooter Node classDefinition(YieldHandling yieldHandling, ClassContext classContext, DefaultHandling defaultHandling); - PropertyName* labelOrIdentifierReference(YieldHandling yieldHandling, - bool yieldTokenizedAsName); + PropertyName* checkLabelOrIdentifierReference(PropertyName* ident, + uint32_t offset, + YieldHandling yieldHandling); + + PropertyName* labelOrIdentifierReference(YieldHandling yieldHandling); PropertyName* labelIdentifier(YieldHandling yieldHandling) { - return labelOrIdentifierReference(yieldHandling, false); + return labelOrIdentifierReference(yieldHandling); } - PropertyName* identifierReference(YieldHandling yieldHandling, - bool yieldTokenizedAsName = false) - { - return labelOrIdentifierReference(yieldHandling, yieldTokenizedAsName); + PropertyName* identifierReference(YieldHandling yieldHandling) { + return labelOrIdentifierReference(yieldHandling); } PropertyName* importedBinding() { @@ -1455,6 +1466,25 @@ class Parser final : public ParserBase, private JS::AutoGCRooter bool asmJS(Node list); }; +template +class MOZ_STACK_CLASS AutoAwaitIsKeyword +{ + private: + Parser* parser_; + bool oldAwaitIsKeyword_; + + public: + AutoAwaitIsKeyword(Parser* parser, bool awaitIsKeyword) { + parser_ = parser; + oldAwaitIsKeyword_ = parser_->awaitIsKeyword_; + parser_->setAwaitIsKeyword(awaitIsKeyword); + } + + ~AutoAwaitIsKeyword() { + parser_->setAwaitIsKeyword(oldAwaitIsKeyword_); + } +}; + } /* namespace frontend */ } /* namespace js */ diff --git a/js/src/frontend/ReservedWords.h b/js/src/frontend/ReservedWords.h new file mode 100644 index 000000000..27f5b11c1 --- /dev/null +++ b/js/src/frontend/ReservedWords.h @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * 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/. */ + +/* A higher-order macro for enumerating reserved word tokens. */ + +#ifndef vm_ReservedWords_h +#define vm_ReservedWords_h + +#define FOR_EACH_JAVASCRIPT_RESERVED_WORD(macro) \ + macro(false, false_, TOK_FALSE) \ + macro(true, true_, TOK_TRUE) \ + macro(null, null, TOK_NULL) \ + \ + /* Keywords. */ \ + macro(break, break_, TOK_BREAK) \ + macro(case, case_, TOK_CASE) \ + macro(catch, catch_, TOK_CATCH) \ + macro(const, const_, TOK_CONST) \ + macro(continue, continue_, TOK_CONTINUE) \ + macro(debugger, debugger, TOK_DEBUGGER) \ + macro(default, default_, TOK_DEFAULT) \ + macro(delete, delete_, TOK_DELETE) \ + macro(do, do_, TOK_DO) \ + macro(else, else_, TOK_ELSE) \ + macro(finally, finally_, TOK_FINALLY) \ + macro(for, for_, TOK_FOR) \ + macro(function, function, TOK_FUNCTION) \ + macro(if, if_, TOK_IF) \ + macro(in, in, TOK_IN) \ + macro(instanceof, instanceof, TOK_INSTANCEOF) \ + macro(new, new_, TOK_NEW) \ + macro(return, return_, TOK_RETURN) \ + macro(switch, switch_, TOK_SWITCH) \ + macro(this, this_, TOK_THIS) \ + macro(throw, throw_, TOK_THROW) \ + macro(try, try_, TOK_TRY) \ + macro(typeof, typeof_, TOK_TYPEOF) \ + macro(var, var, TOK_VAR) \ + macro(void, void_, TOK_VOID) \ + macro(while, while_, TOK_WHILE) \ + macro(with, with, TOK_WITH) \ + macro(import, import, TOK_IMPORT) \ + macro(export, export_, TOK_EXPORT) \ + macro(class, class_, TOK_CLASS) \ + macro(extends, extends, TOK_EXTENDS) \ + macro(super, super, TOK_SUPER) \ + \ + /* Future reserved words. */ \ + macro(enum, enum_, TOK_ENUM) \ + \ + /* Future reserved words, but only in strict mode. */ \ + macro(implements, implements, TOK_IMPLEMENTS) \ + macro(interface, interface, TOK_INTERFACE) \ + macro(package, package, TOK_PACKAGE) \ + macro(private, private_, TOK_PRIVATE) \ + macro(protected, protected_, TOK_PROTECTED) \ + macro(public, public_, TOK_PUBLIC) \ + \ + /* Contextual keywords. */ \ + macro(as, as, TOK_AS) \ + macro(async, async, TOK_ASYNC) \ + macro(await, await, TOK_AWAIT) \ + macro(each, each, TOK_EACH) \ + macro(from, from, TOK_FROM) \ + macro(get, get, TOK_GET) \ + macro(let, let, TOK_LET) \ + macro(of, of, TOK_OF) \ + macro(set, set, TOK_SET) \ + macro(static, static_, TOK_STATIC) \ + macro(target, target, TOK_TARGET) \ + /* \ + * Yield is a token inside function*. Outside of a function*, it is a \ + * future reserved word in strict mode, but a keyword in JS1.7 even \ + * when strict. Punt logic to parser. \ + */ \ + macro(yield, yield, TOK_YIELD) + +#endif /* vm_ReservedWords_h */ diff --git a/js/src/frontend/TokenKind.h b/js/src/frontend/TokenKind.h index 6f22d78e5..98f23fec8 100644 --- a/js/src/frontend/TokenKind.h +++ b/js/src/frontend/TokenKind.h @@ -81,9 +81,12 @@ \ macro(REGEXP, "regular expression literal") \ macro(TRUE, "boolean literal 'true'") \ + range(RESERVED_WORD_LITERAL_FIRST, TRUE) \ macro(FALSE, "boolean literal 'false'") \ macro(NULL, "null literal") \ + range(RESERVED_WORD_LITERAL_LAST, NULL) \ macro(THIS, "keyword 'this'") \ + range(KEYWORD_FIRST, THIS) \ macro(FUNCTION, "keyword 'function'") \ macro(IF, "keyword 'if'") \ macro(ELSE, "keyword 'else'") \ @@ -106,16 +109,43 @@ macro(FINALLY, "keyword 'finally'") \ macro(THROW, "keyword 'throw'") \ macro(DEBUGGER, "keyword 'debugger'") \ - macro(YIELD, "keyword 'yield'") \ - macro(AWAIT, "keyword 'await'") \ macro(EXPORT, "keyword 'export'") \ macro(IMPORT, "keyword 'import'") \ macro(CLASS, "keyword 'class'") \ macro(EXTENDS, "keyword 'extends'") \ macro(SUPER, "keyword 'super'") \ - macro(RESERVED, "reserved keyword") \ - /* reserved keywords in strict mode */ \ - macro(STRICT_RESERVED, "reserved keyword") \ + range(KEYWORD_LAST, SUPER) \ + \ + /* contextual keywords */ \ + macro(AS, "'as'") \ + range(CONTEXTUAL_KEYWORD_FIRST, AS) \ + macro(ASYNC, "'async'") \ + macro(AWAIT, "'await'") \ + macro(EACH, "'each'") \ + macro(FROM, "'from'") \ + macro(GET, "'get'") \ + macro(LET, "'let'") \ + macro(OF, "'of'") \ + macro(SET, "'set'") \ + macro(STATIC, "'static'") \ + macro(TARGET, "'target'") \ + macro(YIELD, "'yield'") \ + range(CONTEXTUAL_KEYWORD_LAST, YIELD) \ + \ + /* future reserved words */ \ + macro(ENUM, "reserved word 'enum'") \ + range(FUTURE_RESERVED_KEYWORD_FIRST, ENUM) \ + range(FUTURE_RESERVED_KEYWORD_LAST, ENUM) \ + \ + /* reserved words in strict mode */ \ + macro(IMPLEMENTS, "reserved word 'implements'") \ + range(STRICT_RESERVED_KEYWORD_FIRST, IMPLEMENTS) \ + macro(INTERFACE, "reserved word 'interface'") \ + macro(PACKAGE, "reserved word 'package'") \ + macro(PRIVATE, "reserved word 'private'") \ + macro(PROTECTED, "reserved word 'protected'") \ + macro(PUBLIC, "reserved word 'public'") \ + range(STRICT_RESERVED_KEYWORD_LAST, PUBLIC) \ \ /* \ * The following token types occupy contiguous ranges to enable easy \ @@ -149,7 +179,9 @@ range(RELOP_LAST, GE) \ \ macro(INSTANCEOF, "keyword 'instanceof'") \ + range(KEYWORD_BINOP_FIRST, INSTANCEOF) \ macro(IN, "keyword 'in'") \ + range(KEYWORD_BINOP_LAST, IN) \ \ /* Shift ops, per TokenKindIsShift. */ \ macro(LSH, "'<<'") \ @@ -168,7 +200,9 @@ \ /* Unary operation tokens. */ \ macro(TYPEOF, "keyword 'typeof'") \ + range(KEYWORD_UNOP_FIRST, TYPEOF) \ macro(VOID, "keyword 'void'") \ + range(KEYWORD_UNOP_LAST, VOID) \ macro(NOT, "'!'") \ macro(BITNOT, "'~'") \ \ @@ -239,6 +273,61 @@ TokenKindIsAssignment(TokenKind tt) return TOK_ASSIGNMENT_START <= tt && tt <= TOK_ASSIGNMENT_LAST; } +inline MOZ_MUST_USE bool +TokenKindIsKeyword(TokenKind tt) +{ + return (TOK_KEYWORD_FIRST <= tt && tt <= TOK_KEYWORD_LAST) || + (TOK_KEYWORD_BINOP_FIRST <= tt && tt <= TOK_KEYWORD_BINOP_LAST) || + (TOK_KEYWORD_UNOP_FIRST <= tt && tt <= TOK_KEYWORD_UNOP_LAST); +} + +inline MOZ_MUST_USE bool +TokenKindIsContextualKeyword(TokenKind tt) +{ + return TOK_CONTEXTUAL_KEYWORD_FIRST <= tt && tt <= TOK_CONTEXTUAL_KEYWORD_LAST; +} + +inline MOZ_MUST_USE bool +TokenKindIsFutureReservedWord(TokenKind tt) +{ + return TOK_FUTURE_RESERVED_KEYWORD_FIRST <= tt && tt <= TOK_FUTURE_RESERVED_KEYWORD_LAST; +} + +inline MOZ_MUST_USE bool +TokenKindIsStrictReservedWord(TokenKind tt) +{ + return TOK_STRICT_RESERVED_KEYWORD_FIRST <= tt && tt <= TOK_STRICT_RESERVED_KEYWORD_LAST; +} + +inline MOZ_MUST_USE bool +TokenKindIsReservedWordLiteral(TokenKind tt) +{ + return TOK_RESERVED_WORD_LITERAL_FIRST <= tt && tt <= TOK_RESERVED_WORD_LITERAL_LAST; +} + +inline MOZ_MUST_USE bool +TokenKindIsReservedWord(TokenKind tt) +{ + return TokenKindIsKeyword(tt) || + TokenKindIsFutureReservedWord(tt) || + TokenKindIsReservedWordLiteral(tt); +} + +inline MOZ_MUST_USE bool +TokenKindIsPossibleIdentifier(TokenKind tt) +{ + return tt == TOK_NAME || + TokenKindIsContextualKeyword(tt) || + TokenKindIsStrictReservedWord(tt); +} + +inline MOZ_MUST_USE bool +TokenKindIsPossibleIdentifierName(TokenKind tt) +{ + return TokenKindIsPossibleIdentifier(tt) || + TokenKindIsReservedWord(tt); +} + } // namespace frontend } // namespace js diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index 76ea7e821..b8623d545 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -24,10 +24,10 @@ #include "jsnum.h" #include "frontend/BytecodeCompiler.h" +#include "frontend/ReservedWords.h" #include "js/CharacterEncoding.h" #include "js/UniquePtr.h" #include "vm/HelperThreads.h" -#include "vm/Keywords.h" #include "vm/StringBuffer.h" #include "vm/Unicode.h" @@ -40,65 +40,65 @@ using mozilla::PodAssign; using mozilla::PodCopy; using mozilla::PodZero; -struct KeywordInfo { - const char* chars; // C string with keyword text +struct ReservedWordInfo { + const char* chars; // C string with reserved word text TokenKind tokentype; }; -static const KeywordInfo keywords[] = { -#define KEYWORD_INFO(keyword, name, type) \ - {js_##keyword##_str, type}, - FOR_EACH_JAVASCRIPT_KEYWORD(KEYWORD_INFO) -#undef KEYWORD_INFO +static const ReservedWordInfo reservedWords[] = { +#define RESERVED_WORD_INFO(word, name, type) \ + {js_##word##_str, type}, + FOR_EACH_JAVASCRIPT_RESERVED_WORD(RESERVED_WORD_INFO) +#undef RESERVED_WORD_INFO }; -// Returns a KeywordInfo for the specified characters, or nullptr if the string -// is not a keyword. +// Returns a ReservedWordInfo for the specified characters, or nullptr if the +// string is not a reserved word. template -static const KeywordInfo* -FindKeyword(const CharT* s, size_t length) +static const ReservedWordInfo* +FindReservedWord(const CharT* s, size_t length) { MOZ_ASSERT(length != 0); size_t i; - const KeywordInfo* kw; + const ReservedWordInfo* rw; const char* chars; -#define JSKW_LENGTH() length -#define JSKW_AT(column) s[column] -#define JSKW_GOT_MATCH(index) i = (index); goto got_match; -#define JSKW_TEST_GUESS(index) i = (index); goto test_guess; -#define JSKW_NO_MATCH() goto no_match; -#include "jsautokw.h" -#undef JSKW_NO_MATCH -#undef JSKW_TEST_GUESS -#undef JSKW_GOT_MATCH -#undef JSKW_AT -#undef JSKW_LENGTH +#define JSRW_LENGTH() length +#define JSRW_AT(column) s[column] +#define JSRW_GOT_MATCH(index) i = (index); goto got_match; +#define JSRW_TEST_GUESS(index) i = (index); goto test_guess; +#define JSRW_NO_MATCH() goto no_match; +#include "frontend/ReservedWordsGenerated.h" +#undef JSRW_NO_MATCH +#undef JSRW_TEST_GUESS +#undef JSRW_GOT_MATCH +#undef JSRW_AT +#undef JSRW_LENGTH got_match: - return &keywords[i]; + return &reservedWords[i]; test_guess: - kw = &keywords[i]; - chars = kw->chars; + rw = &reservedWords[i]; + chars = rw->chars; do { if (*s++ != (unsigned char)(*chars++)) goto no_match; } while (--length != 0); - return kw; + return rw; no_match: return nullptr; } -static const KeywordInfo* -FindKeyword(JSLinearString* str) +static const ReservedWordInfo* +FindReservedWord(JSLinearString* str) { JS::AutoCheckCannotGC nogc; return str->hasLatin1Chars() - ? FindKeyword(str->latin1Chars(nogc), str->length()) - : FindKeyword(str->twoByteChars(nogc), str->length()); + ? FindReservedWord(str->latin1Chars(nogc), str->length()) + : FindReservedWord(str->twoByteChars(nogc), str->length()); } template @@ -188,7 +188,68 @@ frontend::IsIdentifier(const char16_t* chars, size_t length) bool frontend::IsKeyword(JSLinearString* str) { - return FindKeyword(str) != nullptr; + if (const ReservedWordInfo* rw = FindReservedWord(str)) + return TokenKindIsKeyword(rw->tokentype); + + return false; +} + +bool +frontend::IsFutureReservedWord(JSLinearString* str) +{ + if (const ReservedWordInfo* rw = FindReservedWord(str)) + return TokenKindIsFutureReservedWord(rw->tokentype); + + return false; +} + +bool +frontend::IsStrictReservedWord(JSLinearString* str) +{ + if (const ReservedWordInfo* rw = FindReservedWord(str)) + return TokenKindIsStrictReservedWord(rw->tokentype); + + return false; +} + +bool +frontend::IsReservedWordLiteral(JSLinearString* str) +{ + if (const ReservedWordInfo* rw = FindReservedWord(str)) + return TokenKindIsReservedWordLiteral(rw->tokentype); + + return false; +} + +const char* +frontend::ReservedWordToCharZ(PropertyName* str) +{ + const ReservedWordInfo* rw = FindReservedWord(str); + if (rw == nullptr) + return nullptr; + + switch (rw->tokentype) { +#define EMIT_CASE(word, name, type) case type: return js_##word##_str; + FOR_EACH_JAVASCRIPT_RESERVED_WORD(EMIT_CASE) +#undef EMIT_CASE + default: + MOZ_ASSERT_UNREACHABLE("Not a reserved word PropertyName."); + } + return nullptr; +} + +PropertyName* +TokenStream::reservedWordToPropertyName(TokenKind tt) const +{ + MOZ_ASSERT(tt != TOK_NAME); + switch (tt) { +#define EMIT_CASE(word, name, type) case type: return cx->names().name; + FOR_EACH_JAVASCRIPT_RESERVED_WORD(EMIT_CASE) +#undef EMIT_CASE + default: + MOZ_ASSERT_UNREACHABLE("Not a reserved word TokenKind."); + } + return nullptr; } TokenStream::SourceCoords::SourceCoords(ExclusiveContext* cx, uint32_t ln) @@ -1169,38 +1230,6 @@ TokenStream::putIdentInTokenbuf(const char16_t* identStart) return true; } -bool -TokenStream::checkForKeyword(const KeywordInfo* kw, TokenKind* ttp) -{ - if (!awaitIsKeyword && kw->tokentype == TOK_AWAIT) { - if (ttp) - *ttp = TOK_NAME; - return true; - } - - if (kw->tokentype == TOK_RESERVED) { - error(JSMSG_RESERVED_ID, kw->chars); - return false; - } - - if (kw->tokentype == TOK_STRICT_RESERVED) - return reportStrictModeError(JSMSG_RESERVED_ID, kw->chars); - - // Working keyword. - *ttp = kw->tokentype; - return true; -} - -bool -TokenStream::checkForKeyword(JSAtom* atom, TokenKind* ttp) -{ - const KeywordInfo* kw = FindKeyword(atom); - if (!kw) - return true; - - return checkForKeyword(kw, ttp); -} - enum FirstCharKind { // A char16_t has the 'OneChar' kind if it, by itself, constitutes a valid // token that cannot also be a prefix of a longer token. E.g. ';' has the @@ -1424,36 +1453,18 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier) length = userbuf.addressOfNextRawChar() - identStart; } - // Represent keywords as keyword tokens unless told otherwise. - if (modifier != KeywordIsName) { - if (const KeywordInfo* kw = FindKeyword(chars, length)) { - // That said, keywords can't contain escapes. (Contexts where - // keywords are treated as names, that also sometimes treat - // keywords as keywords, must manually check this requirement.) - // There are two exceptions - // 1) StrictReservedWords: These keywords need to be treated as - // names in non-strict mode. - // 2) yield is also treated as a name if it contains an escape - // sequence. The parser must handle this case separately. - if (hadUnicodeEscape && !( - (kw->tokentype == TOK_STRICT_RESERVED && !strictMode()) || - kw->tokentype == TOK_YIELD)) - { - reportError(JSMSG_ESCAPED_KEYWORD); - goto error; - } - - tp->type = TOK_NAME; - if (!checkForKeyword(kw, &tp->type)) - goto error; - if (tp->type != TOK_NAME && !hadUnicodeEscape) - goto out; + // Represent reserved words as reserved word tokens. + if (!hadUnicodeEscape) { + if (const ReservedWordInfo* rw = FindReservedWord(chars, length)) { + tp->type = rw->tokentype; + goto out; } } JSAtom* atom = AtomizeChars(cx, chars, length); - if (!atom) + if (!atom) { goto error; + } tp->type = TOK_NAME; tp->setName(atom->asPropertyName()); goto out; diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index e0119c83d..e92de4b03 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -26,14 +26,13 @@ #include "js/UniquePtr.h" #include "js/Vector.h" #include "vm/RegExpObject.h" +#include "vm/String.h" struct KeywordInfo; namespace js { namespace frontend { -class AutoAwaitIsKeyword; - struct TokenPos { uint32_t begin; // Offset of the token's first char. uint32_t end; // Offset of 1 past the token's last char. @@ -120,9 +119,6 @@ struct Token // TOK_DIV. Operand, - // Treat keywords as names by returning TOK_NAME. - KeywordIsName, - // Treat subsequent characters as the tail of a template literal, after // a template substitution, beginning with a "}", continuing with zero // or more template literal characters, and ending with either "${" or @@ -164,10 +160,6 @@ struct Token // If a semicolon is inserted automatically, the next token is already // gotten with None, but we expect Operand. OperandIsNone, - - // If name of method definition is `get` or `set`, the next token is - // already gotten with KeywordIsName, but we expect None. - NoneIsKeywordIsName, }; friend class TokenStream; @@ -224,11 +216,6 @@ struct Token return u.name->JSAtom::asPropertyName(); // poor-man's type verification } - bool nameContainsEscape() const { - PropertyName* n = name(); - return pos.begin + n->length() != pos.end; - } - JSAtom* atom() const { MOZ_ASSERT(type == TOK_STRING || type == TOK_TEMPLATE_HEAD || @@ -254,10 +241,22 @@ struct Token }; class CompileError : public JSErrorReport { -public: + public: void throwError(JSContext* cx); }; +extern const char* +ReservedWordToCharZ(PropertyName* str); + +extern MOZ_MUST_USE bool +IsFutureReservedWord(JSLinearString* str); + +extern MOZ_MUST_USE bool +IsReservedWordLiteral(JSLinearString* str); + +extern MOZ_MUST_USE bool +IsStrictReservedWord(JSLinearString* str); + // Ideally, tokenizing would be entirely independent of context. But the // strict mode flag, which is in SharedContext, affects tokenizing, and // TokenStream needs to see it. @@ -344,25 +343,26 @@ class MOZ_STACK_CLASS TokenStream JSVersion versionNumber() const { return VersionNumber(options().version); } JSVersion versionWithFlags() const { return options().version; } + private: + PropertyName* reservedWordToPropertyName(TokenKind tt) const; + + public: PropertyName* currentName() const { - if (isCurrentTokenType(TOK_YIELD)) - return cx->names().yield; - MOZ_ASSERT(isCurrentTokenType(TOK_NAME)); - return currentToken().name(); + if (isCurrentTokenType(TOK_NAME)) { + return currentToken().name(); + } + + MOZ_ASSERT(TokenKindIsPossibleIdentifierName(currentToken().type)); + return reservedWordToPropertyName(currentToken().type); } PropertyName* nextName() const { - if (nextToken().type == TOK_YIELD) - return cx->names().yield; - MOZ_ASSERT(nextToken().type == TOK_NAME); - return nextToken().name(); - } + if (nextToken().type != TOK_NAME) { + return nextToken().name(); + } - bool nextNameContainsEscape() const { - if (nextToken().type == TOK_YIELD) - return false; - MOZ_ASSERT(nextToken().type == TOK_NAME); - return nextToken().nameContainsEscape(); + MOZ_ASSERT(TokenKindIsPossibleIdentifierName(nextToken().type)); + return reservedWordToPropertyName(nextToken().type); } bool isCurrentTokenAssignment() const { @@ -498,9 +498,6 @@ class MOZ_STACK_CLASS TokenStream {} }; - bool awaitIsKeyword = false; - friend class AutoAwaitIsKeyword; - uint32_t invalidTemplateEscapeOffset = 0; InvalidEscapeType invalidTemplateEscapeType = InvalidEscapeType::None; @@ -508,14 +505,12 @@ class MOZ_STACK_CLASS TokenStream typedef Token::Modifier Modifier; static constexpr Modifier None = Token::None; static constexpr Modifier Operand = Token::Operand; - static constexpr Modifier KeywordIsName = Token::KeywordIsName; static constexpr Modifier TemplateTail = Token::TemplateTail; typedef Token::ModifierException ModifierException; static constexpr ModifierException NoException = Token::NoException; static constexpr ModifierException NoneIsOperand = Token::NoneIsOperand; static constexpr ModifierException OperandIsNone = Token::OperandIsNone; - static constexpr ModifierException NoneIsKeywordIsName = Token::NoneIsKeywordIsName; void addModifierException(ModifierException modifierException) { #ifdef DEBUG @@ -544,10 +539,6 @@ class MOZ_STACK_CLASS TokenStream MOZ_ASSERT(next.type != TOK_DIV && next.type != TOK_REGEXP, "next token requires contextual specifier to be parsed unambiguously"); break; - case NoneIsKeywordIsName: - MOZ_ASSERT(next.modifier == KeywordIsName); - MOZ_ASSERT(next.type != TOK_NAME); - break; default: MOZ_CRASH("unexpected modifier exception"); } @@ -574,12 +565,6 @@ class MOZ_STACK_CLASS TokenStream return; } - if (lookaheadToken.modifierException == NoneIsKeywordIsName) { - // getToken() permissibly following getToken(KeywordIsName). - if (modifier == None && lookaheadToken.modifier == KeywordIsName) - return; - } - MOZ_ASSERT_UNREACHABLE("this token was previously looked up with a " "different modifier, potentially making " "tokenization non-deterministic"); @@ -714,36 +699,6 @@ class MOZ_STACK_CLASS TokenStream MOZ_ALWAYS_TRUE(matched); } - // Like matchToken(..., TOK_NAME) but further matching the name token only - // if it has the given characters, without containing escape sequences. - // If the name token has the given characters yet *does* contain an escape, - // a syntax error will be reported. - // - // This latter behavior makes this method unsuitable for use in any context - // where ASI might occur. In such places, an escaped "contextual keyword" - // on a new line is the start of an ExpressionStatement, not a continuation - // of a StatementListItem (or ImportDeclaration or ExportDeclaration, in - // modules). - MOZ_MUST_USE bool matchContextualKeyword(bool* matchedp, Handle keyword, - Modifier modifier = None) - { - TokenKind token; - if (!getToken(&token, modifier)) - return false; - if (token == TOK_NAME && currentToken().name() == keyword) { - if (currentToken().nameContainsEscape()) { - reportError(JSMSG_ESCAPED_KEYWORD); - return false; - } - - *matchedp = true; - } else { - *matchedp = false; - ungetToken(); - } - return true; - } - MOZ_MUST_USE bool nextTokenEndsExpr(bool* endsExpr) { TokenKind tt; if (!peekToken(&tt)) @@ -809,19 +764,6 @@ class MOZ_STACK_CLASS TokenStream return sourceMapURL_.get(); } - // If |atom| is not a keyword in this version, return true with *ttp - // unchanged. - // - // If it is a reserved word in this version and strictness mode, and thus - // can't be present in correct code, report a SyntaxError and return false. - // - // If it is a keyword, like "if", return true with the keyword's TokenKind - // in *ttp. - MOZ_MUST_USE bool checkForKeyword(JSAtom* atom, TokenKind* ttp); - - // Same semantics as above, but for the provided keyword. - MOZ_MUST_USE bool checkForKeyword(const KeywordInfo* kw, TokenKind* ttp); - // This class maps a userbuf offset (which is 0-indexed) to a line number // (which is 1-indexed) and a column index (which is 0-indexed). class SourceCoords @@ -1103,25 +1045,6 @@ class MOZ_STACK_CLASS TokenStream StrictModeGetter* strictModeGetter; // used to test for strict mode }; -class MOZ_STACK_CLASS AutoAwaitIsKeyword -{ -private: - TokenStream* ts_; - bool oldAwaitIsKeyword_; - -public: - AutoAwaitIsKeyword(TokenStream* ts, bool awaitIsKeyword) { - ts_ = ts; - oldAwaitIsKeyword_ = ts_->awaitIsKeyword; - ts_->awaitIsKeyword = awaitIsKeyword; - } - - ~AutoAwaitIsKeyword() { - ts_->awaitIsKeyword = oldAwaitIsKeyword_; - ts_ = nullptr; - } -}; - extern const char* TokenKindToDesc(TokenKind tt); diff --git a/js/src/jit-test/tests/modules/export-declaration.js b/js/src/jit-test/tests/modules/export-declaration.js index 3c4a9b735..48d1072bf 100644 --- a/js/src/jit-test/tests/modules/export-declaration.js +++ b/js/src/jit-test/tests/modules/export-declaration.js @@ -403,9 +403,7 @@ assertThrowsInstanceOf(function() { parseAsModule("export {,} from 'a'"); }, SyntaxError); -assertThrowsInstanceOf(function() { - parseAsModule("export { true as a } from 'b'"); -}, SyntaxError); +parseAsModule("export { true as a } from 'b'"); assertThrowsInstanceOf(function () { parseAsModule("export { a } from 'b' f();"); diff --git a/js/src/js.msg b/js/src/js.msg index 495e3bfad..ce039cbc8 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -265,6 +265,7 @@ MSG_DEF(JSMSG_IMPORT_DECL_AT_TOP_LEVEL, 0, JSEXN_SYNTAXERR, "import declarations MSG_DEF(JSMSG_OF_AFTER_FOR_LOOP_DECL, 0, JSEXN_SYNTAXERR, "a declaration in the head of a for-of loop can't have an initializer") MSG_DEF(JSMSG_IN_AFTER_LEXICAL_FOR_DECL,0,JSEXN_SYNTAXERR, "a lexical declaration in the head of a for-in loop can't have an initializer") MSG_DEF(JSMSG_INVALID_FOR_IN_DECL_WITH_INIT,0,JSEXN_SYNTAXERR,"for-in loop head declarations may not have initializers") +MSG_DEF(JSMSG_INVALID_ID, 1, JSEXN_SYNTAXERR, "{0} is an invalid identifier") MSG_DEF(JSMSG_LABEL_NOT_FOUND, 0, JSEXN_SYNTAXERR, "label not found") MSG_DEF(JSMSG_LET_COMP_BINDING, 0, JSEXN_SYNTAXERR, "'let' is not a valid name for a comprehension variable") MSG_DEF(JSMSG_LEXICAL_DECL_NOT_IN_BLOCK, 1, JSEXN_SYNTAXERR, "{0} declaration not directly within block") diff --git a/js/src/jsatom.cpp b/js/src/jsatom.cpp index 2a3c58638..280ec3e9c 100644 --- a/js/src/jsatom.cpp +++ b/js/src/jsatom.cpp @@ -54,41 +54,9 @@ FOR_EACH_COMMON_PROPERTYNAME(CONST_CHAR_STR) #undef CONST_CHAR_STR /* Constant strings that are not atomized. */ -const char js_break_str[] = "break"; -const char js_case_str[] = "case"; -const char js_catch_str[] = "catch"; -const char js_class_str[] = "class"; -const char js_const_str[] = "const"; -const char js_continue_str[] = "continue"; -const char js_debugger_str[] = "debugger"; -const char js_default_str[] = "default"; -const char js_do_str[] = "do"; -const char js_else_str[] = "else"; -const char js_enum_str[] = "enum"; -const char js_export_str[] = "export"; -const char js_extends_str[] = "extends"; -const char js_finally_str[] = "finally"; -const char js_for_str[] = "for"; const char js_getter_str[] = "getter"; -const char js_if_str[] = "if"; -const char js_implements_str[] = "implements"; -const char js_import_str[] = "import"; -const char js_in_str[] = "in"; -const char js_instanceof_str[] = "instanceof"; -const char js_interface_str[] = "interface"; -const char js_package_str[] = "package"; -const char js_private_str[] = "private"; -const char js_protected_str[] = "protected"; -const char js_public_str[] = "public"; const char js_send_str[] = "send"; const char js_setter_str[] = "setter"; -const char js_switch_str[] = "switch"; -const char js_this_str[] = "this"; -const char js_try_str[] = "try"; -const char js_typeof_str[] = "typeof"; -const char js_void_str[] = "void"; -const char js_while_str[] = "while"; -const char js_with_str[] = "with"; // Use a low initial capacity for atom hash tables to avoid penalizing runtimes // which create a small number of atoms. diff --git a/js/src/jsatom.h b/js/src/jsatom.h index 496dcbb4c..0a5fd3c14 100644 --- a/js/src/jsatom.h +++ b/js/src/jsatom.h @@ -142,44 +142,9 @@ FOR_EACH_COMMON_PROPERTYNAME(DECLARE_CONST_CHAR_STR) #undef DECLARE_CONST_CHAR_STR /* Constant strings that are not atomized. */ -extern const char js_break_str[]; -extern const char js_case_str[]; -extern const char js_catch_str[]; -extern const char js_class_str[]; -extern const char js_close_str[]; -extern const char js_const_str[]; -extern const char js_continue_str[]; -extern const char js_debugger_str[]; -extern const char js_default_str[]; -extern const char js_do_str[]; -extern const char js_else_str[]; -extern const char js_enum_str[]; -extern const char js_export_str[]; -extern const char js_extends_str[]; -extern const char js_finally_str[]; -extern const char js_for_str[]; extern const char js_getter_str[]; -extern const char js_if_str[]; -extern const char js_implements_str[]; -extern const char js_import_str[]; -extern const char js_in_str[]; -extern const char js_instanceof_str[]; -extern const char js_interface_str[]; -extern const char js_package_str[]; -extern const char js_private_str[]; -extern const char js_protected_str[]; -extern const char js_public_str[]; extern const char js_send_str[]; extern const char js_setter_str[]; -extern const char js_static_str[]; -extern const char js_super_str[]; -extern const char js_switch_str[]; -extern const char js_this_str[]; -extern const char js_try_str[]; -extern const char js_typeof_str[]; -extern const char js_void_str[]; -extern const char js_while_str[]; -extern const char js_with_str[]; namespace js { diff --git a/js/src/moz.build b/js/src/moz.build index eb30866c8..a0f074d1c 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -619,11 +619,11 @@ else: 'perf/pm_stub.cpp' ] -GENERATED_FILES += ['jsautokw.h'] -jsautokw = GENERATED_FILES['jsautokw.h'] -jsautokw.script = 'jsautokw.py' -jsautokw.inputs += [ - 'vm/Keywords.h' +GENERATED_FILES += ['frontend/ReservedWordsGenerated.h'] +ReservedWordsGenerated = GENERATED_FILES['frontend/ReservedWordsGenerated.h'] +ReservedWordsGenerated.script = 'frontend/GenerateReservedWords.py' +ReservedWordsGenerated.inputs += [ + 'frontend/ReservedWords.h' ] # JavaScript must be built shared, even for static builds, as it is used by diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h index eaeea84b9..8e35e1aae 100644 --- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -38,6 +38,7 @@ macro(Bool32x4, Bool32x4, "Bool32x4") \ macro(Bool64x2, Bool64x2, "Bool64x2") \ macro(boundWithSpace, boundWithSpace, "bound ") \ + macro(break, break_, "break") \ macro(breakdown, breakdown, "breakdown") \ macro(buffer, buffer, "buffer") \ macro(builder, builder, "builder") \ @@ -52,8 +53,10 @@ macro(callee, callee, "callee") \ macro(caller, caller, "caller") \ macro(callFunction, callFunction, "callFunction") \ + macro(case, case_, "case") \ macro(caseFirst, caseFirst, "caseFirst") \ - macro(class_, class_, "class") \ + macro(catch, catch_, "catch") \ + macro(class, class_, "class") \ macro(close, close, "close") \ macro(Collator, Collator, "Collator") \ macro(CollatorCompareGet, CollatorCompareGet, "Intl_Collator_compare_get") \ @@ -62,9 +65,11 @@ macro(comma, comma, ",") \ macro(compare, compare, "compare") \ macro(configurable, configurable, "configurable") \ + macro(const, const_, "const") \ macro(construct, construct, "construct") \ macro(constructContentFunction, constructContentFunction, "constructContentFunction") \ macro(constructor, constructor, "constructor") \ + macro(continue, continue_, "continue") \ macro(ConvertAndCopyTo, ConvertAndCopyTo, "ConvertAndCopyTo") \ macro(copyWithin, copyWithin, "copyWithin") \ macro(count, count, "count") \ @@ -76,28 +81,32 @@ macro(DateTimeFormatFormatToParts, DateTimeFormatFormatToParts, "Intl_DateTimeFormat_formatToParts") \ macro(day, day, "day") \ macro(dayPeriod, dayPeriod, "dayPeriod") \ + macro(debugger, debugger, "debugger") \ macro(decodeURI, decodeURI, "decodeURI") \ macro(decodeURIComponent, decodeURIComponent, "decodeURIComponent") \ macro(DefaultBaseClassConstructor, DefaultBaseClassConstructor, "DefaultBaseClassConstructor") \ macro(DefaultDerivedClassConstructor, DefaultDerivedClassConstructor, "DefaultDerivedClassConstructor") \ - macro(default_, default_, "default") \ + macro(default, default_, "default") \ macro(defineGetter, defineGetter, "__defineGetter__") \ macro(defineProperty, defineProperty, "defineProperty") \ macro(defineSetter, defineSetter, "__defineSetter__") \ macro(delete, delete_, "delete") \ macro(deleteProperty, deleteProperty, "deleteProperty") \ macro(displayURL, displayURL, "displayURL") \ + macro(do, do_, "do") \ macro(done, done, "done") \ macro(dotGenerator, dotGenerator, ".generator") \ macro(dotThis, dotThis, ".this") \ macro(each, each, "each") \ macro(elementType, elementType, "elementType") \ + macro(else, else_, "else") \ macro(empty, empty, "") \ macro(emptyRegExp, emptyRegExp, "(?:)") \ macro(encodeURI, encodeURI, "encodeURI") \ macro(encodeURIComponent, encodeURIComponent, "encodeURIComponent") \ macro(endTimestamp, endTimestamp, "endTimestamp") \ macro(entries, entries, "entries") \ + macro(enum, enum_, "enum") \ macro(enumerable, enumerable, "enumerable") \ macro(enumerate, enumerate, "enumerate") \ macro(era, era, "era") \ @@ -105,11 +114,14 @@ macro(escape, escape, "escape") \ macro(eval, eval, "eval") \ macro(exec, exec, "exec") \ + macro(export, export_, "export") \ + macro(extends, extends, "extends") \ macro(false, false_, "false") \ macro(fieldOffsets, fieldOffsets, "fieldOffsets") \ macro(fieldTypes, fieldTypes, "fieldTypes") \ macro(fileName, fileName, "fileName") \ macro(fill, fill, "fill") \ + macro(finally, finally_, "finally") \ macro(find, find, "find") \ macro(findIndex, findIndex, "findIndex") \ macro(firstDayOfWeek, firstDayOfWeek, "firstDayOfWeek") \ @@ -121,6 +133,7 @@ macro(Float32x4, Float32x4, "Float32x4") \ macro(float64, float64, "float64") \ macro(Float64x2, Float64x2, "Float64x2") \ + macro(for, for_, "for") \ macro(forceInterpreter, forceInterpreter, "forceInterpreter") \ macro(forEach, forEach, "forEach") \ macro(format, format, "format") \ @@ -146,8 +159,12 @@ macro(hasOwn, hasOwn, "hasOwn") \ macro(hasOwnProperty, hasOwnProperty, "hasOwnProperty") \ macro(hour, hour, "hour") \ + macro(if, if_, "if") \ macro(ignoreCase, ignoreCase, "ignoreCase") \ macro(ignorePunctuation, ignorePunctuation, "ignorePunctuation") \ + macro(implements, implements, "implements") \ + macro(import, import, "import") \ + macro(in, in, "in") \ macro(includes, includes, "includes") \ macro(incumbentGlobal, incumbentGlobal, "incumbentGlobal") \ macro(index, index, "index") \ @@ -158,12 +175,14 @@ macro(innermost, innermost, "innermost") \ macro(inNursery, inNursery, "inNursery") \ macro(input, input, "input") \ + macro(instanceof, instanceof, "instanceof") \ macro(int8, int8, "int8") \ macro(int16, int16, "int16") \ macro(int32, int32, "int32") \ macro(Int8x16, Int8x16, "Int8x16") \ macro(Int16x8, Int16x8, "Int16x8") \ macro(Int32x4, Int32x4, "Int32x4") \ + macro(interface, interface, "interface") \ macro(InterpretGeneratorResume, InterpretGeneratorResume, "InterpretGeneratorResume") \ macro(isEntryPoint, isEntryPoint, "isEntryPoint") \ macro(isExtensible, isExtensible, "isExtensible") \ @@ -240,13 +259,17 @@ macro(outOfMemory, outOfMemory, "out of memory") \ macro(ownKeys, ownKeys, "ownKeys") \ macro(Object_valueOf, Object_valueOf, "Object_valueOf") \ + macro(package, package, "package") \ macro(parseFloat, parseFloat, "parseFloat") \ macro(parseInt, parseInt, "parseInt") \ macro(pattern, pattern, "pattern") \ macro(pending, pending, "pending") \ + macro(public, public_, "public") \ macro(preventExtensions, preventExtensions, "preventExtensions") \ + macro(private, private_, "private") \ macro(promise, promise, "promise") \ macro(propertyIsEnumerable, propertyIsEnumerable, "propertyIsEnumerable") \ + macro(protected, protected_, "protected") \ macro(proto, proto, "__proto__") \ macro(prototype, prototype, "prototype") \ macro(proxy, proxy, "proxy") \ @@ -295,10 +318,12 @@ macro(StructType, StructType, "StructType") \ macro(style, style, "style") \ macro(super, super, "super") \ + macro(switch, switch_, "switch") \ macro(Symbol_iterator_fun, Symbol_iterator_fun, "[Symbol.iterator]") \ macro(target, target, "target") \ macro(test, test, "test") \ macro(then, then, "then") \ + macro(this, this_, "this") \ macro(throw, throw_, "throw") \ macro(timestamp, timestamp, "timestamp") \ macro(timeZone, timeZone, "timeZone") \ @@ -311,7 +336,9 @@ macro(toString, toString, "toString") \ macro(toUTCString, toUTCString, "toUTCString") \ macro(true, true_, "true") \ + macro(try, try_, "try") \ macro(type, type, "type") \ + macro(typeof, typeof_, "typeof") \ macro(uint8, uint8, "uint8") \ macro(uint8Clamped, uint8Clamped, "uint8Clamped") \ macro(uint16, uint16, "uint16") \ @@ -331,6 +358,7 @@ macro(useAsm, useAsm, "use asm") \ macro(useGrouping, useGrouping, "useGrouping") \ macro(useStrict, useStrict, "use strict") \ + macro(void, void_, "void") \ macro(value, value, "value") \ macro(valueOf, valueOf, "valueOf") \ macro(values, values, "values") \ @@ -345,6 +373,8 @@ macro(weekday, weekday, "weekday") \ macro(weekendEnd, weekendEnd, "weekendEnd") \ macro(weekendStart, weekendStart, "weekendStart") \ + macro(while, while_, "while") \ + macro(with, with, "with") \ macro(writable, writable, "writable") \ macro(year, year, "year") \ macro(yield, yield, "yield") \ diff --git a/js/src/vm/Keywords.h b/js/src/vm/Keywords.h deleted file mode 100644 index ef37c4419..000000000 --- a/js/src/vm/Keywords.h +++ /dev/null @@ -1,66 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * 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/. */ - -/* A higher-order macro for enumerating keyword tokens. */ - -#ifndef vm_Keywords_h -#define vm_Keywords_h - -#define FOR_EACH_JAVASCRIPT_KEYWORD(macro) \ - macro(false, false_, TOK_FALSE) \ - macro(true, true_, TOK_TRUE) \ - macro(null, null, TOK_NULL) \ - /* Keywords. */ \ - macro(break, break_, TOK_BREAK) \ - macro(case, case_, TOK_CASE) \ - macro(catch, catch_, TOK_CATCH) \ - macro(const, const_, TOK_CONST) \ - macro(continue, continue_, TOK_CONTINUE) \ - macro(debugger, debugger, TOK_DEBUGGER) \ - macro(default, default_, TOK_DEFAULT) \ - macro(delete, delete_, TOK_DELETE) \ - macro(do, do_, TOK_DO) \ - macro(else, else_, TOK_ELSE) \ - macro(finally, finally_, TOK_FINALLY) \ - macro(for, for_, TOK_FOR) \ - macro(function, function, TOK_FUNCTION) \ - macro(if, if_, TOK_IF) \ - macro(in, in, TOK_IN) \ - macro(instanceof, instanceof, TOK_INSTANCEOF) \ - macro(new, new_, TOK_NEW) \ - macro(return, return_, TOK_RETURN) \ - macro(switch, switch_, TOK_SWITCH) \ - macro(this, this_, TOK_THIS) \ - macro(throw, throw_, TOK_THROW) \ - macro(try, try_, TOK_TRY) \ - macro(typeof, typeof, TOK_TYPEOF) \ - macro(var, var, TOK_VAR) \ - macro(void, void_, TOK_VOID) \ - macro(while, while_, TOK_WHILE) \ - macro(with, with, TOK_WITH) \ - macro(import, import, TOK_IMPORT) \ - macro(export, export, TOK_EXPORT) \ - macro(class, class_, TOK_CLASS) \ - macro(extends, extends, TOK_EXTENDS) \ - macro(super, super, TOK_SUPER) \ - /* Reserved keywords. */ \ - macro(enum, enum_, TOK_RESERVED) \ - /* Future reserved keywords, but only in strict mode. */ \ - macro(implements, implements, TOK_STRICT_RESERVED) \ - macro(interface, interface, TOK_STRICT_RESERVED) \ - macro(package, package, TOK_STRICT_RESERVED) \ - macro(private, private_, TOK_STRICT_RESERVED) \ - macro(protected, protected_, TOK_STRICT_RESERVED) \ - macro(public, public_, TOK_STRICT_RESERVED) \ - macro(await, await, TOK_AWAIT) \ - /* \ - * Yield is a token inside function*. Outside of a function*, it is a \ - * future reserved keyword in strict mode, but a keyword in JS1.7 even \ - * when strict. Punt logic to parser. \ - */ \ - macro(yield, yield, TOK_YIELD) - -#endif /* vm_Keywords_h */ diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp index 81795b47d..51632a683 100644 --- a/js/src/wasm/AsmJS.cpp +++ b/js/src/wasm/AsmJS.cpp @@ -7057,7 +7057,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line) TokenKind tk; if (!tokenStream.getToken(&tk, TokenStream::Operand)) return false; - if (tk != TOK_NAME && tk != TOK_YIELD) + if (!TokenKindIsPossibleIdentifier(tk)) return false; // The regular parser will throw a SyntaxError, no need to m.fail. RootedPropertyName name(m.cx(), m.parser().bindingIdentifier(YieldIsName)); -- cgit v1.2.3 From fcdc8929f376207be3594f809adda3c65d487101 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 9 Jun 2019 16:25:42 -0400 Subject: 1336783 - Part 2: Remove Parser::checkStrictBinding. --- js/src/frontend/Parser.cpp | 138 ++++++++++++++++++++++----------------------- js/src/frontend/Parser.h | 5 +- 2 files changed, 70 insertions(+), 73 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 9b057fb72..560dc5ec8 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -974,44 +974,6 @@ ParserBase::isValidStrictBinding(PropertyName* name) !IsStrictReservedWord(name); } -/* - * Check that it is permitted to introduce a binding for |name|. Use |pos| for - * reporting error locations. - */ -template -bool -Parser::checkStrictBinding(PropertyName* name, TokenPos pos) -{ - if (!pc->sc()->needStrictChecks()) - return true; - - if (name == context->names().arguments) - return strictModeErrorAt(pos.begin, JSMSG_BAD_BINDING, "arguments"); - - if (name == context->names().eval) - return strictModeErrorAt(pos.begin, JSMSG_BAD_BINDING, "eval"); - - if (name == context->names().let) { - errorAt(pos.begin, JSMSG_RESERVED_ID, "let"); - return false; - } - - if (name == context->names().static_) { - errorAt(pos.begin, JSMSG_RESERVED_ID, "static"); - return false; - } - - if (name == context->names().yield) { - errorAt(pos.begin, JSMSG_RESERVED_ID, "yield"); - return false; - } - - if (IsStrictReservedWord(name)) - return strictModeErrorAt(pos.begin, JSMSG_RESERVED_ID, ReservedWordToCharZ(name)); - - return true; -} - /* * Returns true if all parameter names are valid strict mode binding names and * no duplicate parameter names are present. @@ -1094,9 +1056,6 @@ Parser::notePositionalFormalParameter(Node fn, HandlePropertyName if (!paramNode) return false; - if (!checkStrictBinding(name, pos())) - return false; - handler.addFunctionFormalParameter(fn, paramNode); return true; } @@ -1357,9 +1316,6 @@ Parser::noteDeclaredName(HandlePropertyName name, DeclarationKind if (pc->useAsmOrInsideUseAsm()) return true; - if (!checkStrictBinding(name, pos)) - return false; - switch (kind) { case DeclarationKind::Var: case DeclarationKind::BodyLevelFunction: @@ -3608,8 +3564,26 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if ((kind != Method && !IsConstructorKind(kind)) && fun->explicitName()) { RootedPropertyName propertyName(context, fun->explicitName()->asPropertyName()); - if (!checkStrictBinding(propertyName, handler.getPosition(pn))) - return false; + // `await` cannot be checked at this point because of different context. + // It should already be checked before this point. + if (propertyName != context->names().await) { + YieldHandling nameYieldHandling; + if (kind == Expression) { + // Named lambda has binding inside it. + nameYieldHandling = bodyYieldHandling; + } else { + // Otherwise YieldHandling cannot be checked at this point + // because of different context. + // It should already be checked before this point. + nameYieldHandling = YieldIsName; + } + + if (!checkBindingIdentifier(propertyName, handler.getPosition(pn).begin, + nameYieldHandling)) + { + return false; + } + } } if (bodyType == StatementListBody) { @@ -4178,6 +4152,9 @@ Parser::checkDestructuringName(ParseNode* expr, Maybename()); + // `yield` is already checked, so pass YieldIsName to skip that check. + if (!checkBindingIdentifier(name, expr->pn_pos.begin, YieldIsName)) + return false; return noteDeclaredName(name, *maybeDecl, expr->pn_pos); } @@ -8120,7 +8097,7 @@ Parser::comprehensionFor(GeneratorKind comprehensionKind) // FIXME: Destructuring binding (bug 980828). MUST_MATCH_TOKEN_FUNC(TokenKindIsPossibleIdentifier, JSMSG_NO_VARIABLE_NAME); - RootedPropertyName name(context, tokenStream.currentName()); + RootedPropertyName name(context, bindingIdentifier(YieldIsKeyword)); if (name == context->names().let) { error(JSMSG_LET_COMP_BINDING); return null(); @@ -8644,12 +8621,16 @@ Parser::checkLabelOrIdentifierReference(PropertyName* ident, { if (ident == context->names().yield) { if (yieldHandling == YieldIsKeyword || - pc->sc()->strict() || versionNumber() >= JSVERSION_1_7) { errorAt(offset, JSMSG_RESERVED_ID, "yield"); return nullptr; } + if (pc->sc()->needStrictChecks()) { + if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID, "yield")) + return nullptr; + } + return ident; } @@ -8671,20 +8652,49 @@ Parser::checkLabelOrIdentifierReference(PropertyName* ident, return nullptr; } - if (pc->sc()->strict()) { + if (pc->sc()->needStrictChecks()) { if (IsStrictReservedWord(ident)) { - errorAt(offset, JSMSG_RESERVED_ID, ReservedWordToCharZ(ident)); - return nullptr; + if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID, ReservedWordToCharZ(ident))) + return nullptr; + return ident; } if (ident == context->names().let) { - errorAt(offset, JSMSG_RESERVED_ID, "let"); - return nullptr; + if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID, "let")) + return nullptr; + return ident; } if (ident == context->names().static_) { - errorAt(offset, JSMSG_RESERVED_ID, "static"); - return nullptr; + if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID, "static")) + return nullptr; + return ident; + } + } + + return ident; +} + +template +PropertyName* +Parser::checkBindingIdentifier(PropertyName* ident, + uint32_t offset, + YieldHandling yieldHandling) +{ + if (!checkLabelOrIdentifierReference(ident, offset, yieldHandling)) + return nullptr; + + if (pc->sc()->needStrictChecks()) { + if (ident == context->names().arguments) { + if (!strictModeErrorAt(offset, JSMSG_BAD_STRICT_ASSIGN, "arguments")) + return nullptr; + return ident; + } + + if (ident == context->names().eval) { + if (!strictModeErrorAt(offset, JSMSG_BAD_STRICT_ASSIGN, "eval")) + return nullptr; + return ident; } } @@ -8709,23 +8719,7 @@ template PropertyName* Parser::bindingIdentifier(YieldHandling yieldHandling) { - PropertyName* ident = labelOrIdentifierReference(yieldHandling); - if (!ident) - return nullptr; - - if (pc->sc()->strict()) { - if (ident == context->names().arguments) { - error(JSMSG_BAD_STRICT_ASSIGN, "arguments"); - return nullptr; - } - - if (ident == context->names().eval) { - error(JSMSG_BAD_STRICT_ASSIGN, "eval"); - return nullptr; - } - } - - return ident; + return checkBindingIdentifier(tokenStream.currentName(), pos().begin, yieldHandling); } template diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 9ec862d92..d53a64eeb 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1335,6 +1335,10 @@ class Parser final : public ParserBase, private JS::AutoGCRooter uint32_t offset, YieldHandling yieldHandling); + PropertyName* checkBindingIdentifier(PropertyName* ident, + uint32_t offset, + YieldHandling yieldHandling); + PropertyName* labelOrIdentifierReference(YieldHandling yieldHandling); PropertyName* labelIdentifier(YieldHandling yieldHandling) { @@ -1404,7 +1408,6 @@ class Parser final : public ParserBase, private JS::AutoGCRooter private: bool checkIncDecOperand(Node operand, uint32_t operandOffset); bool checkStrictAssignment(Node lhs); - bool checkStrictBinding(PropertyName* name, TokenPos pos); bool hasValidSimpleStrictParameterNames(); -- cgit v1.2.3 From dd0057fbf08d56bbcb3c61900ae2cfc8d359080d Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 9 Jun 2019 16:29:42 -0400 Subject: 1336783 - Part 3 - Use simpler macro to avoid internal compiler error on SM-tc(H). --- js/src/frontend/Parser.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 560dc5ec8..82057f62e 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -63,24 +63,27 @@ using BindingIter = ParseContext::Scope::BindingIter; using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr; // Read a token. Report an error and return null() if that token doesn't match -// to the given func's condition. -#define MUST_MATCH_TOKEN_FUNC_MOD(func, modifier, errorNumber) \ +// to the condition. Do not use MUST_MATCH_TOKEN_INTERNAL directly. +#define MUST_MATCH_TOKEN_INTERNAL(cond, modifier, errorNumber) \ JS_BEGIN_MACRO \ TokenKind token; \ if (!tokenStream.getToken(&token, modifier)) \ return null(); \ - if (!(func)(token)) { \ + if (!(cond)) { \ error(errorNumber); \ return null(); \ } \ JS_END_MACRO #define MUST_MATCH_TOKEN_MOD(tt, modifier, errorNumber) \ - MUST_MATCH_TOKEN_FUNC_MOD([](TokenKind tok) { return tok == tt; }, modifier, errorNumber) + MUST_MATCH_TOKEN_INTERNAL(token == tt, modifier, errorNumber) #define MUST_MATCH_TOKEN(tt, errorNumber) \ MUST_MATCH_TOKEN_MOD(tt, TokenStream::None, errorNumber) +#define MUST_MATCH_TOKEN_FUNC_MOD(func, modifier, errorNumber) \ + MUST_MATCH_TOKEN_INTERNAL((func)(token), modifier, errorNumber) + #define MUST_MATCH_TOKEN_FUNC(func, errorNumber) \ MUST_MATCH_TOKEN_FUNC_MOD(func, TokenStream::None, errorNumber) -- cgit v1.2.3 From 0f5f3c30490741c3053627de4fd5a27964c9953c Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 9 Jun 2019 16:36:59 -0400 Subject: 1336783 - followup: Fix rooting. --- js/src/frontend/Parser.cpp | 58 +++++++++++++++++++++++++--------------------- js/src/frontend/Parser.h | 10 ++++---- 2 files changed, 37 insertions(+), 31 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 82057f62e..322f428e5 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -8617,8 +8617,8 @@ Parser::newName(PropertyName* name, TokenPos pos) } template -PropertyName* -Parser::checkLabelOrIdentifierReference(PropertyName* ident, +bool +Parser::checkLabelOrIdentifierReference(HandlePropertyName ident, uint32_t offset, YieldHandling yieldHandling) { @@ -8627,81 +8627,81 @@ Parser::checkLabelOrIdentifierReference(PropertyName* ident, versionNumber() >= JSVERSION_1_7) { errorAt(offset, JSMSG_RESERVED_ID, "yield"); - return nullptr; + return false; } if (pc->sc()->needStrictChecks()) { if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID, "yield")) - return nullptr; + return false; } - return ident; + return true; } if (ident == context->names().await) { if (awaitIsKeyword()) { errorAt(offset, JSMSG_RESERVED_ID, "await"); - return nullptr; + return false; } - return ident; + return true; } if (IsKeyword(ident) || IsReservedWordLiteral(ident)) { errorAt(offset, JSMSG_INVALID_ID, ReservedWordToCharZ(ident)); - return nullptr; + return false; } if (IsFutureReservedWord(ident)) { errorAt(offset, JSMSG_RESERVED_ID, ReservedWordToCharZ(ident)); - return nullptr; + return false; } if (pc->sc()->needStrictChecks()) { if (IsStrictReservedWord(ident)) { if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID, ReservedWordToCharZ(ident))) - return nullptr; - return ident; + return false; + return true; } if (ident == context->names().let) { if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID, "let")) - return nullptr; - return ident; + return false; + return true; } if (ident == context->names().static_) { if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID, "static")) - return nullptr; - return ident; + return false; + return true; } } - return ident; + return true; } template -PropertyName* -Parser::checkBindingIdentifier(PropertyName* ident, +bool +Parser::checkBindingIdentifier(HandlePropertyName ident, uint32_t offset, YieldHandling yieldHandling) { if (!checkLabelOrIdentifierReference(ident, offset, yieldHandling)) - return nullptr; + return false; if (pc->sc()->needStrictChecks()) { if (ident == context->names().arguments) { if (!strictModeErrorAt(offset, JSMSG_BAD_STRICT_ASSIGN, "arguments")) - return nullptr; - return ident; + return false; + return true; } if (ident == context->names().eval) { if (!strictModeErrorAt(offset, JSMSG_BAD_STRICT_ASSIGN, "eval")) - return nullptr; - return ident; + return false; + return true; } } - return ident; + return true; } template @@ -8715,14 +8715,20 @@ Parser::labelOrIdentifierReference(YieldHandling yieldHandling) // // Use PropertyName* instead of TokenKind to reflect the normalization. - return checkLabelOrIdentifierReference(tokenStream.currentName(), pos().begin, yieldHandling); + RootedPropertyName ident(context, tokenStream.currentName()); + if (!checkLabelOrIdentifierReference(ident, pos().begin, yieldHandling)) + return nullptr; + return ident; } template PropertyName* Parser::bindingIdentifier(YieldHandling yieldHandling) { - return checkBindingIdentifier(tokenStream.currentName(), pos().begin, yieldHandling); + RootedPropertyName ident(context, tokenStream.currentName()); + if (!checkBindingIdentifier(ident, pos().begin, yieldHandling)) + return nullptr; + return ident; } template diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index d53a64eeb..4eb0f5a39 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1331,14 +1331,14 @@ class Parser final : public ParserBase, private JS::AutoGCRooter Node classDefinition(YieldHandling yieldHandling, ClassContext classContext, DefaultHandling defaultHandling); - PropertyName* checkLabelOrIdentifierReference(PropertyName* ident, - uint32_t offset, - YieldHandling yieldHandling); - - PropertyName* checkBindingIdentifier(PropertyName* ident, + bool checkLabelOrIdentifierReference(HandlePropertyName ident, uint32_t offset, YieldHandling yieldHandling); + bool checkBindingIdentifier(HandlePropertyName ident, + uint32_t offset, + YieldHandling yieldHandling); + PropertyName* labelOrIdentifierReference(YieldHandling yieldHandling); PropertyName* labelIdentifier(YieldHandling yieldHandling) { -- cgit v1.2.3 From c1ba97eeae3171fb96283583c33f0238cedacab6 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 9 Jun 2019 17:20:09 -0400 Subject: 1340089 - Check the binding name in comprehensionFor. --- js/src/frontend/Parser.cpp | 2 + .../ecma_6/Comprehensions/for-reserved-word.js | 107 +++++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 js/src/tests/ecma_6/Comprehensions/for-reserved-word.js (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 322f428e5..fc4b0e965 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -8101,6 +8101,8 @@ Parser::comprehensionFor(GeneratorKind comprehensionKind) MUST_MATCH_TOKEN_FUNC(TokenKindIsPossibleIdentifier, JSMSG_NO_VARIABLE_NAME); RootedPropertyName name(context, bindingIdentifier(YieldIsKeyword)); + if (!name) + return null(); if (name == context->names().let) { error(JSMSG_LET_COMP_BINDING); return null(); diff --git a/js/src/tests/ecma_6/Comprehensions/for-reserved-word.js b/js/src/tests/ecma_6/Comprehensions/for-reserved-word.js new file mode 100644 index 000000000..9b320fc91 --- /dev/null +++ b/js/src/tests/ecma_6/Comprehensions/for-reserved-word.js @@ -0,0 +1,107 @@ +var BUGNUMBER = 1340089; +var summary = "Comprehension should check the binding names"; + +print(BUGNUMBER + ": " + summary); + +// Non strict mode. +// Keywords, literals, 'let', and 'yield' are not allowed. + +assertThrowsInstanceOf(function () { + eval("[for (true of [1]) 2]"); +}, SyntaxError); +assertThrowsInstanceOf(function () { + eval("(for (true of [1]) 2)"); +}, SyntaxError); + +assertThrowsInstanceOf(function () { + eval("[for (throw of [1]) 2]"); +}, SyntaxError); +assertThrowsInstanceOf(function () { + eval("(for (throw of [1]) 2)"); +}, SyntaxError); + +assertThrowsInstanceOf(function () { + eval("[for (let of [1]) 2]"); +}, SyntaxError); +assertThrowsInstanceOf(function () { + eval("(for (let of [1]) 2)"); +}, SyntaxError); + +assertThrowsInstanceOf(function () { + eval("[for (yield of [1]) 2]"); +}, SyntaxError); +assertThrowsInstanceOf(function () { + eval("(for (yield of [1]) 2)"); +}, SyntaxError); + +eval("[for (public of [1]) 2]"); +eval("(for (public of [1]) 2)"); + +eval("[for (static of [1]) 2]"); +eval("(for (static of [1]) 2)"); + +// Strict mode. +// All reserved words are not allowed. + +assertThrowsInstanceOf(function () { + "use strict"; + eval("[for (true of [1]) 2]"); +}, SyntaxError); +assertThrowsInstanceOf(function () { + "use strict"; + eval("(for (true of [1]) 2)"); +}, SyntaxError); + +assertThrowsInstanceOf(function () { + "use strict"; + eval("[for (throw of [1]) 2]"); +}, SyntaxError); +assertThrowsInstanceOf(function () { + "use strict"; + eval("(for (throw of [1]) 2)"); +}, SyntaxError); + +assertThrowsInstanceOf(function () { + "use strict"; + eval("[for (let of [1]) 2]"); +}, SyntaxError); +assertThrowsInstanceOf(function () { + "use strict"; + eval("(for (let of [1]) 2)"); +}, SyntaxError); + +assertThrowsInstanceOf(function () { + "use strict"; + eval("[for (yield of [1]) 2]"); +}, SyntaxError); +assertThrowsInstanceOf(function () { + "use strict"; + eval("(for (yield of [1]) 2)"); +}, SyntaxError); + +assertThrowsInstanceOf(function () { + "use strict"; + eval("[for (public of [1]) 2]"); +}, SyntaxError); +assertThrowsInstanceOf(function () { + "use strict"; + eval("(for (public of [1]) 2)"); +}, SyntaxError); + +assertThrowsInstanceOf(function () { + "use strict"; + eval("[for (static of [1]) 2]"); +}, SyntaxError); +assertThrowsInstanceOf(function () { + "use strict"; + eval("(for (static of [1]) 2)"); +}, SyntaxError); + +(function () { + "use strict"; + eval("[for (await of [1]) 2]"); + eval("(for (await of [1]) 2)"); +})(); + +if (typeof reportCompare === "function") + reportCompare(true, true); -- cgit v1.2.3 From 50de15c3a64577f1523ec456df028dc20f539beb Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 7 Jul 2019 20:36:27 -0400 Subject: 1317387: The intrinsic %ThrowTypeError% function should be frozen. --- js/src/jsfun.cpp | 22 ++++++++++++++++++++++ js/src/tests/ecma_6/Function/throw-type-error.js | 16 ++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 js/src/tests/ecma_6/Function/throw-type-error.js (limited to 'js/src') diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 3453a59e1..470746d50 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -861,6 +861,28 @@ CreateFunctionPrototype(JSContext* cx, JSProtoKey key) if (!throwTypeError || !PreventExtensions(cx, throwTypeError)) return nullptr; + // The "length" property of %ThrowTypeError% is non-configurable, adjust + // the default property attributes accordingly. + Rooted nonConfigurableDesc(cx); + nonConfigurableDesc.setAttributes(JSPROP_PERMANENT | JSPROP_IGNORE_READONLY | + JSPROP_IGNORE_ENUMERATE | JSPROP_IGNORE_VALUE); + + RootedId lengthId(cx, NameToId(cx->names().length)); + ObjectOpResult lengthResult; + if (!NativeDefineProperty(cx, throwTypeError, lengthId, nonConfigurableDesc, lengthResult)) + return nullptr; + MOZ_ASSERT(lengthResult); + + // Non-standard: Also change "name" to non-configurable. ECMAScript defines + // %ThrowTypeError% as an anonymous function, i.e. it shouldn't actually + // get an own "name" property. To be consistent with other built-in, + // anonymous functions, we don't delete %ThrowTypeError%'s "name" property. + RootedId nameId(cx, NameToId(cx->names().name)); + ObjectOpResult nameResult; + if (!NativeDefineProperty(cx, throwTypeError, nameId, nonConfigurableDesc, nameResult)) + return nullptr; + MOZ_ASSERT(nameResult); + self->setThrowTypeError(throwTypeError); return functionProto; diff --git a/js/src/tests/ecma_6/Function/throw-type-error.js b/js/src/tests/ecma_6/Function/throw-type-error.js new file mode 100644 index 000000000..68dd6e1d0 --- /dev/null +++ b/js/src/tests/ecma_6/Function/throw-type-error.js @@ -0,0 +1,16 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/publicdomain/zero/1.0/ + +const ThrowTypeError = function(){ + "use strict"; + return Object.getOwnPropertyDescriptor(arguments, "callee").get; +}(); + +assertDeepEq(Object.getOwnPropertyDescriptor(ThrowTypeError, "length"), { + value: 0, writable: false, enumerable: false, configurable: false +}); + +assertEq(Object.isFrozen(ThrowTypeError), true); + +if (typeof reportCompare == "function") + reportCompare(true, true); -- cgit v1.2.3 From f39640128068a3816a9bfc28d619f8fa8f161435 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 30 Jun 2019 01:52:56 -0400 Subject: Fix a thread assertion in NewCopiedArrayTryUseGroup --- js/src/jsarray.cpp | 2 +- js/src/vm/NativeObject-inl.h | 2 +- js/src/vm/NativeObject.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'js/src') diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 8bbcac320..33ff67f36 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -3643,7 +3643,7 @@ js::NewCopiedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, if (!obj) return nullptr; - DenseElementResult result = obj->setOrExtendDenseElements(cx->asJSContext(), 0, vp, length, updateTypes); + DenseElementResult result = obj->setOrExtendDenseElements(cx, 0, vp, length, updateTypes); if (result == DenseElementResult::Failure) return nullptr; MOZ_ASSERT(result == DenseElementResult::Success); diff --git a/js/src/vm/NativeObject-inl.h b/js/src/vm/NativeObject-inl.h index 052a3385c..e55e3db04 100644 --- a/js/src/vm/NativeObject-inl.h +++ b/js/src/vm/NativeObject-inl.h @@ -236,7 +236,7 @@ NativeObject::ensureDenseElements(ExclusiveContext* cx, uint32_t index, uint32_t } inline DenseElementResult -NativeObject::setOrExtendDenseElements(JSContext* cx, uint32_t start, const Value* vp, +NativeObject::setOrExtendDenseElements(ExclusiveContext* cx, uint32_t start, const Value* vp, uint32_t count, ShouldUpdateTypes updateTypes) { diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h index d0279556d..9cc6d5436 100644 --- a/js/src/vm/NativeObject.h +++ b/js/src/vm/NativeObject.h @@ -1150,7 +1150,7 @@ class NativeObject : public ShapedObject } inline DenseElementResult - setOrExtendDenseElements(JSContext* cx, uint32_t start, const Value* vp, uint32_t count, + setOrExtendDenseElements(ExclusiveContext* cx, uint32_t start, const Value* vp, uint32_t count, ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update); bool shouldConvertDoubleElements() { -- cgit v1.2.3 From 57a8b65fc0c4bd12149855d972aea05828e4d6e7 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 9 Jun 2019 22:30:59 -0400 Subject: 1339963 - Part 1: Split Parser::exportDeclaration. --- js/src/frontend/Parser.cpp | 659 ++++++++++++++++++++++++----------- js/src/frontend/Parser.h | 23 +- js/src/frontend/SyntaxParseHandler.h | 14 + 3 files changed, 486 insertions(+), 210 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index fc4b0e965..16d4a377a 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -4692,8 +4692,10 @@ Parser::declarationList(YieldHandling yieldHandling, template typename ParseHandler::Node -Parser::lexicalDeclaration(YieldHandling yieldHandling, bool isConst) +Parser::lexicalDeclaration(YieldHandling yieldHandling, DeclarationKind kind) { + MOZ_ASSERT(kind == DeclarationKind::Const || kind == DeclarationKind::Let); + /* * Parse body-level lets without a new block object. ES6 specs * that an execution environment's initial lexical environment @@ -4705,7 +4707,8 @@ Parser::lexicalDeclaration(YieldHandling yieldHandling, bool isCon * * See 8.1.1.1.6 and the note in 13.2.1. */ - Node decl = declarationList(yieldHandling, isConst ? PNK_CONST : PNK_LET); + Node decl = declarationList(yieldHandling, + kind == DeclarationKind::Const ? PNK_CONST : PNK_LET); if (!decl || !matchOrInsertSemicolonAfterExpression()) return null(); @@ -4994,279 +4997,517 @@ Parser::checkExportedNamesForDeclaration(Node node) } template<> -ParseNode* -Parser::exportDeclaration() +bool +Parser::checkExportedNameForClause(ParseNode* node) { - MOZ_ASSERT(tokenStream.currentToken().type == TOK_EXPORT); + return checkExportedName(node->pn_atom); +} - if (!pc->atModuleLevel()) { - error(JSMSG_EXPORT_DECL_AT_TOP_LEVEL); +template<> +bool +Parser::checkExportedNameForClause(Node node) +{ + MOZ_ALWAYS_FALSE(abortIfSyntaxParser()); + return false; +} + +template<> +bool +Parser::checkExportedNameForFunction(ParseNode* node) +{ + return checkExportedName(node->pn_funbox->function()->explicitName()); +} + +template<> +bool +Parser::checkExportedNameForFunction(Node node) +{ + MOZ_ALWAYS_FALSE(abortIfSyntaxParser()); + return false; +} + +template<> +bool +Parser::checkExportedNameForClass(ParseNode* node) +{ + const ClassNode& cls = node->as(); + MOZ_ASSERT(cls.names()); + return checkExportedName(cls.names()->innerBinding()->pn_atom); +} + +template<> +bool +Parser::checkExportedNameForClass(Node node) +{ + MOZ_ALWAYS_FALSE(abortIfSyntaxParser()); + return false; +} + +template<> +bool +Parser::processExport(ParseNode* node) +{ + return pc->sc()->asModuleContext()->builder.processExport(node); +} + +template<> +bool +Parser::processExport(Node node) +{ + MOZ_ALWAYS_FALSE(abortIfSyntaxParser()); + return false; +} + +template<> +bool +Parser::processExportFrom(ParseNode* node) +{ + return pc->sc()->asModuleContext()->builder.processExportFrom(node); +} + +template<> +bool +Parser::processExportFrom(Node node) +{ + MOZ_ALWAYS_FALSE(abortIfSyntaxParser()); + return false; +} + +template +typename ParseHandler::Node +Parser::exportFrom(uint32_t begin, Node specList) +{ + if (!abortIfSyntaxParser()) return null(); - } - uint32_t begin = pos().begin; + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FROM)); - Node kid; - TokenKind tt; - if (!tokenStream.getToken(&tt)) + if (!abortIfSyntaxParser()) return null(); - switch (tt) { - case TOK_LC: { - kid = handler.newList(PNK_EXPORT_SPEC_LIST); - if (!kid) - return null(); - while (true) { - // Handle the forms |export {}| and |export { ..., }| (where ... - // is non empty), by escaping the loop early if the next token - // is }. - if (!tokenStream.getToken(&tt)) - return null(); + MUST_MATCH_TOKEN(TOK_STRING, JSMSG_MODULE_SPEC_AFTER_FROM); - if (tt == TOK_RC) - break; + Node moduleSpec = stringLiteral(); + if (!moduleSpec) + return null(); - if (!TokenKindIsPossibleIdentifierName(tt)) { - error(JSMSG_NO_BINDING_NAME); - return null(); - } + if (!matchOrInsertSemicolonAfterNonExpression()) + return null(); - Node bindingName = newName(tokenStream.currentName()); - if (!bindingName) - return null(); + Node node = handler.newExportFromDeclaration(begin, specList, moduleSpec); + if (!node) + return null(); - bool foundAs; - if (!tokenStream.matchToken(&foundAs, TOK_AS)) - return null(); - if (foundAs) - MUST_MATCH_TOKEN_FUNC(TokenKindIsPossibleIdentifierName, JSMSG_NO_EXPORT_NAME); + if (!processExportFrom(node)) + return null(); - Node exportName = newName(tokenStream.currentName()); - if (!exportName) - return null(); + return node; +} - if (!checkExportedName(exportName->pn_atom)) - return null(); +template +typename ParseHandler::Node +Parser::exportBatch(uint32_t begin) +{ + if (!abortIfSyntaxParser()) + return null(); - Node exportSpec = handler.newBinary(PNK_EXPORT_SPEC, bindingName, exportName); - if (!exportSpec) - return null(); + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_MUL)); - handler.addList(kid, exportSpec); + Node kid = handler.newList(PNK_EXPORT_SPEC_LIST); + if (!kid) + return null(); - TokenKind next; - if (!tokenStream.getToken(&next)) - return null(); + // Handle the form |export *| by adding a special export batch + // specifier to the list. + Node exportSpec = handler.newNullary(PNK_EXPORT_BATCH_SPEC, JSOP_NOP, pos()); + if (!exportSpec) + return null(); - if (next == TOK_RC) - break; + handler.addList(kid, exportSpec); - if (next != TOK_COMMA) { - error(JSMSG_RC_AFTER_EXPORT_SPEC_LIST); - return null(); - } - } + TokenKind tt; + if (!tokenStream.getToken(&tt)) + return null(); + if (tt != TOK_FROM) { + error(JSMSG_FROM_AFTER_EXPORT_STAR); + return null(); + } - // Careful! If |from| follows, even on a new line, it must start a - // FromClause: - // - // export { x } - // from "foo"; // a single ExportDeclaration - // - // But if it doesn't, we might have an ASI opportunity in Operand - // context: - // - // export { x } // ExportDeclaration, terminated by ASI - // fro\u006D // ExpressionStatement, the name "from" - // - // In that case let matchOrInsertSemicolonAfterNonExpression sort out - // ASI or any necessary error. - bool matched; - if (!tokenStream.matchToken(&matched, TOK_FROM, TokenStream::Operand)) - return null(); + return exportFrom(begin, kid); +} - if (matched) { - MUST_MATCH_TOKEN(TOK_STRING, JSMSG_MODULE_SPEC_AFTER_FROM); +template +typename ParseHandler::Node +Parser::exportClause(uint32_t begin) +{ + if (!abortIfSyntaxParser()) + return null(); - Node moduleSpec = stringLiteral(); - if (!moduleSpec) - return null(); + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LC)); - if (!matchOrInsertSemicolonAfterNonExpression()) - return null(); + Node kid = handler.newList(PNK_EXPORT_SPEC_LIST); + if (!kid) + return null(); - ParseNode* node = handler.newExportFromDeclaration(begin, kid, moduleSpec); - if (!node || !pc->sc()->asModuleContext()->builder.processExportFrom(node)) - return null(); + TokenKind tt; + while (true) { + // Handle the forms |export {}| and |export { ..., }| (where ... is non + // empty), by escaping the loop early if the next token is }. + if (!tokenStream.getToken(&tt)) + return null(); + + if (tt == TOK_RC) + break; - return node; + if (!TokenKindIsPossibleIdentifierName(tt)) { + error(JSMSG_NO_BINDING_NAME); + return null(); } - if (!matchOrInsertSemicolonAfterNonExpression()) + Node bindingName = newName(tokenStream.currentName()); + if (!bindingName) return null(); - break; - } - case TOK_MUL: { - kid = handler.newList(PNK_EXPORT_SPEC_LIST); - if (!kid) + bool foundAs; + if (!tokenStream.matchToken(&foundAs, TOK_AS)) + return null(); + if (foundAs) + MUST_MATCH_TOKEN_FUNC(TokenKindIsPossibleIdentifierName, JSMSG_NO_EXPORT_NAME); + + Node exportName = newName(tokenStream.currentName()); + if (!exportName) return null(); - // Handle the form |export *| by adding a special export batch - // specifier to the list. - Node exportSpec = handler.newNullary(PNK_EXPORT_BATCH_SPEC, JSOP_NOP, pos()); + if (!checkExportedNameForClause(exportName)) + return null(); + + Node exportSpec = handler.newBinary(PNK_EXPORT_SPEC, bindingName, exportName); if (!exportSpec) return null(); handler.addList(kid, exportSpec); - if (!tokenStream.getToken(&tt)) + TokenKind next; + if (!tokenStream.getToken(&next)) return null(); - if (tt != TOK_FROM) { - error(JSMSG_FROM_AFTER_EXPORT_STAR); + + if (next == TOK_RC) + break; + + if (next != TOK_COMMA) { + error(JSMSG_RC_AFTER_EXPORT_SPEC_LIST); return null(); } + } - MUST_MATCH_TOKEN(TOK_STRING, JSMSG_MODULE_SPEC_AFTER_FROM); + // Careful! If |from| follows, even on a new line, it must start a + // FromClause: + // + // export { x } + // from "foo"; // a single ExportDeclaration + // + // But if it doesn't, we might have an ASI opportunity in Operand context: + // + // export { x } // ExportDeclaration, terminated by ASI + // fro\u006D // ExpressionStatement, the name "from" + // + // In that case let matchOrInsertSemicolonAfterNonExpression sort out ASI + // or any necessary error. + bool matched; + if (!tokenStream.matchToken(&matched, TOK_FROM, TokenStream::Operand)) + return null(); - Node moduleSpec = stringLiteral(); - if (!moduleSpec) - return null(); + if (matched) + return exportFrom(begin, kid); - if (!matchOrInsertSemicolonAfterNonExpression()) - return null(); + if (!matchOrInsertSemicolonAfterNonExpression()) + return null(); - ParseNode* node = handler.newExportFromDeclaration(begin, kid, moduleSpec); - if (!node || !pc->sc()->asModuleContext()->builder.processExportFrom(node)) - return null(); + Node node = handler.newExportDeclaration(kid, TokenPos(begin, pos().end)); + if (!node) + return null(); - return node; + if (!processExport(node)) + return null(); - } + return node; +} + +template +typename ParseHandler::Node +Parser::exportVariableStatement(uint32_t begin) +{ + if (!abortIfSyntaxParser()) + return null(); + + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_VAR)); + + Node kid = declarationList(YieldIsName, PNK_VAR); + if (!kid) + return null(); + if (!matchOrInsertSemicolonAfterExpression()) + return null(); + if (!checkExportedNamesForDeclaration(kid)) + return null(); + + Node node = handler.newExportDeclaration(kid, TokenPos(begin, pos().end)); + if (!node) + return null(); + + if (!processExport(node)) + return null(); + + return node; +} + +template +typename ParseHandler::Node +Parser::exportFunctionDeclaration(uint32_t begin) +{ + if (!abortIfSyntaxParser()) + return null(); + + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION)); + + Node kid = functionStmt(pos().begin, YieldIsKeyword, NameRequired); + if (!kid) + return null(); + + if (!checkExportedNameForFunction(kid)) + return null(); + + Node node = handler.newExportDeclaration(kid, TokenPos(begin, pos().end)); + if (!node) + return null(); + + if (!processExport(node)) + return null(); + + return node; +} + +template +typename ParseHandler::Node +Parser::exportClassDeclaration(uint32_t begin) +{ + if (!abortIfSyntaxParser()) + return null(); + + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_CLASS)); + + Node kid = classDefinition(YieldIsKeyword, ClassStatement, NameRequired); + if (!kid) + return null(); + + if (!checkExportedNameForClass(kid)) + return null(); + + Node node = handler.newExportDeclaration(kid, TokenPos(begin, pos().end)); + if (!node) + return null(); + + if (!processExport(node)) + return null(); + + return node; +} + +template +typename ParseHandler::Node +Parser::exportLexicalDeclaration(uint32_t begin, DeclarationKind kind) +{ + if (!abortIfSyntaxParser()) + return null(); + + MOZ_ASSERT(kind == DeclarationKind::Const || kind == DeclarationKind::Let); + MOZ_ASSERT_IF(kind == DeclarationKind::Const, tokenStream.isCurrentTokenType(TOK_CONST)); + MOZ_ASSERT_IF(kind == DeclarationKind::Let, tokenStream.isCurrentTokenType(TOK_LET)); + + Node kid = lexicalDeclaration(YieldIsName, kind); + if (!kid) + return null(); + if (!checkExportedNamesForDeclaration(kid)) + return null(); + + Node node = handler.newExportDeclaration(kid, TokenPos(begin, pos().end)); + if (!node) + return null(); + + if (!processExport(node)) + return null(); + + return node; +} + +template +typename ParseHandler::Node +Parser::exportDefaultFunctionDeclaration(uint32_t begin, + FunctionAsyncKind asyncKind + /* = SyncFunction */) +{ + if (!abortIfSyntaxParser()) + return null(); + + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION)); + + Node kid = functionStmt(pos().begin, YieldIsKeyword, AllowDefaultName, asyncKind); + if (!kid) + return null(); + + Node node = handler.newExportDefaultDeclaration(kid, null(), TokenPos(begin, pos().end)); + if (!node) + return null(); + + if (!processExport(node)) + return null(); + + return node; +} + +template +typename ParseHandler::Node +Parser::exportDefaultClassDeclaration(uint32_t begin) +{ + if (!abortIfSyntaxParser()) + return null(); + + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_CLASS)); + + Node kid = classDefinition(YieldIsKeyword, ClassStatement, AllowDefaultName); + if (!kid) + return null(); + + Node node = handler.newExportDefaultDeclaration(kid, null(), TokenPos(begin, pos().end)); + if (!node) + return null(); + + if (!processExport(node)) + return null(); + + return node; +} + +template +typename ParseHandler::Node +Parser::exportDefaultAssignExpr(uint32_t begin) +{ + if (!abortIfSyntaxParser()) + return null(); + + RootedPropertyName name(context, context->names().starDefaultStar); + Node nameNode = newName(name); + if (!nameNode) + return null(); + if (!noteDeclaredName(name, DeclarationKind::Const, pos())) + return null(); + + Node kid = assignExpr(InAllowed, YieldIsKeyword, TripledotProhibited); + if (!kid) + return null(); + if (!matchOrInsertSemicolonAfterExpression()) + return null(); + + Node node = handler.newExportDefaultDeclaration(kid, nameNode, TokenPos(begin, pos().end)); + if (!node) + return null(); + + if (!processExport(node)) + return null(); + + return node; +} + +template +typename ParseHandler::Node +Parser::exportDefault(uint32_t begin) +{ + if (!abortIfSyntaxParser()) + return null(); + + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_DEFAULT)); + + TokenKind tt; + if (!tokenStream.getToken(&tt, TokenStream::Operand)) + return null(); + + if (!checkExportedName(context->names().default_)) + return null(); + switch (tt) { case TOK_FUNCTION: - kid = functionStmt(pos().begin, YieldIsKeyword, NameRequired); - if (!kid) - return null(); + return exportDefaultFunctionDeclaration(begin); - if (!checkExportedName(kid->pn_funbox->function()->explicitName())) + case TOK_ASYNC: { + TokenKind nextSameLine = TOK_EOF; + if (!tokenStream.peekTokenSameLine(&nextSameLine)) return null(); - break; - case TOK_CLASS: { - kid = classDefinition(YieldIsKeyword, ClassStatement, NameRequired); - if (!kid) - return null(); + if (nextSameLine == TOK_FUNCTION) { + tokenStream.consumeKnownToken(TOK_FUNCTION); + return exportDefaultFunctionDeclaration(begin, AsyncFunction); + } - const ClassNode& cls = kid->as(); - MOZ_ASSERT(cls.names()); - if (!checkExportedName(cls.names()->innerBinding()->pn_atom)) - return null(); - break; + tokenStream.ungetToken(); + return exportDefaultAssignExpr(begin); } - case TOK_VAR: - kid = declarationList(YieldIsName, PNK_VAR); - if (!kid) - return null(); - if (!matchOrInsertSemicolonAfterExpression()) - return null(); - if (!checkExportedNamesForDeclaration(kid)) - return null(); - break; + case TOK_CLASS: + return exportDefaultClassDeclaration(begin); - case TOK_DEFAULT: { - if (!tokenStream.getToken(&tt, TokenStream::Operand)) - return null(); + default: + tokenStream.ungetToken(); + return exportDefaultAssignExpr(begin); + } +} - if (!checkExportedName(context->names().default_)) - return null(); +template +typename ParseHandler::Node +Parser::exportDeclaration() +{ + if (!abortIfSyntaxParser()) + return null(); - ParseNode* nameNode = nullptr; - switch (tt) { - case TOK_FUNCTION: - kid = functionStmt(pos().begin, YieldIsKeyword, AllowDefaultName); - if (!kid) - return null(); - break; - case TOK_CLASS: - kid = classDefinition(YieldIsKeyword, ClassStatement, AllowDefaultName); - if (!kid) - return null(); - break; - default: { - if (tt == TOK_ASYNC) { - TokenKind nextSameLine = TOK_EOF; - if (!tokenStream.peekTokenSameLine(&nextSameLine)) - return null(); + MOZ_ASSERT(tokenStream.currentToken().type == TOK_EXPORT); - if (nextSameLine == TOK_FUNCTION) { - tokenStream.consumeKnownToken(nextSameLine); - kid = functionStmt(pos().begin, YieldIsName, AllowDefaultName, AsyncFunction); - if (!kid) - return null(); - break; - } - } + if (!pc->atModuleLevel()) { + error(JSMSG_EXPORT_DECL_AT_TOP_LEVEL); + return null(); + } - tokenStream.ungetToken(); - RootedPropertyName name(context, context->names().starDefaultStar); - nameNode = newName(name); - if (!nameNode) - return null(); - if (!noteDeclaredName(name, DeclarationKind::Const, pos())) - return null(); - kid = assignExpr(InAllowed, YieldIsKeyword, TripledotProhibited); - if (!kid) - return null(); - if (!matchOrInsertSemicolonAfterExpression()) - return null(); - break; - } - } + uint32_t begin = pos().begin; - ParseNode* node = handler.newExportDefaultDeclaration(kid, nameNode, - TokenPos(begin, pos().end)); - if (!node || !pc->sc()->asModuleContext()->builder.processExport(node)) - return null(); + TokenKind tt; + if (!tokenStream.getToken(&tt)) + return null(); + switch (tt) { + case TOK_MUL: + return exportBatch(begin); - return node; - } + case TOK_LC: + return exportClause(begin); + + case TOK_VAR: + return exportVariableStatement(begin); + + case TOK_FUNCTION: + return exportFunctionDeclaration(begin); + + case TOK_CLASS: + return exportClassDeclaration(begin); case TOK_CONST: - kid = lexicalDeclaration(YieldIsName, /* isConst = */ true); - if (!kid) - return null(); - if (!checkExportedNamesForDeclaration(kid)) - return null(); - break; + return exportLexicalDeclaration(begin, DeclarationKind::Const); case TOK_LET: - kid = lexicalDeclaration(YieldIsName, /* isConst = */ false); - if (!kid) - return null(); - if (!checkExportedNamesForDeclaration(kid)) - return null(); - break; + return exportLexicalDeclaration(begin, DeclarationKind::Let); + + case TOK_DEFAULT: + return exportDefault(begin); default: error(JSMSG_DECLARATION_AFTER_EXPORT); return null(); } - - ParseNode* node = handler.newExportDeclaration(kid, TokenPos(begin, pos().end)); - if (!node || !pc->sc()->asModuleContext()->builder.processExport(node)) - return null(); - - return node; -} - -template<> -SyntaxParseHandler::Node -Parser::exportDeclaration() -{ - JS_ALWAYS_FALSE(abortIfSyntaxParser()); - return SyntaxParseHandler::NodeFailure; } template @@ -7132,7 +7373,7 @@ Parser::statementListItem(YieldHandling yieldHandling, return null(); if (tt == TOK_LET && nextTokenContinuesLetDeclaration(next, yieldHandling)) - return lexicalDeclaration(yieldHandling, /* isConst = */ false); + return lexicalDeclaration(yieldHandling, DeclarationKind::Let); if (tt == TOK_ASYNC) { TokenKind nextSameLine = TOK_EOF; @@ -7228,7 +7469,7 @@ Parser::statementListItem(YieldHandling yieldHandling, case TOK_CONST: // [In] is the default behavior, because for-loops specially parse // their heads to handle |in| in this situation. - return lexicalDeclaration(yieldHandling, /* isConst = */ true); + return lexicalDeclaration(yieldHandling, DeclarationKind::Const); // ImportDeclaration (only inside modules) case TOK_IMPORT: diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 4eb0f5a39..e322a4b26 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1193,9 +1193,26 @@ class Parser final : public ParserBase, private JS::AutoGCRooter // continues a LexicalDeclaration. bool nextTokenContinuesLetDeclaration(TokenKind next, YieldHandling yieldHandling); - Node lexicalDeclaration(YieldHandling yieldHandling, bool isConst); + Node lexicalDeclaration(YieldHandling yieldHandling, DeclarationKind kind); Node importDeclaration(); + + bool processExport(Node node); + bool processExportFrom(Node node); + + Node exportFrom(uint32_t begin, Node specList); + Node exportBatch(uint32_t begin); + Node exportClause(uint32_t begin); + Node exportFunctionDeclaration(uint32_t begin); + Node exportVariableStatement(uint32_t begin); + Node exportClassDeclaration(uint32_t begin); + Node exportLexicalDeclaration(uint32_t begin, DeclarationKind kind); + Node exportDefaultFunctionDeclaration(uint32_t begin, + FunctionAsyncKind asyncKind = SyncFunction); + Node exportDefaultClassDeclaration(uint32_t begin); + Node exportDefaultAssignExpr(uint32_t begin); + Node exportDefault(uint32_t begin); + Node exportDeclaration(); Node expressionStatement(YieldHandling yieldHandling, InvokedPrediction invoked = PredictUninvoked); @@ -1327,6 +1344,10 @@ class Parser final : public ParserBase, private JS::AutoGCRooter bool checkExportedName(JSAtom* exportName); bool checkExportedNamesForDeclaration(Node node); + bool checkExportedNameForClause(Node node); + bool checkExportedNameForFunction(Node node); + bool checkExportedNameForClass(Node node); + enum ClassContext { ClassStatement, ClassExpression }; Node classDefinition(YieldHandling yieldHandling, ClassContext classContext, DefaultHandling defaultHandling); diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index aa85a631e..f492bab66 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -241,6 +241,10 @@ class SyntaxParseHandler return NodeUnparenthesizedUnary; } + Node newNullary(ParseNodeKind kind, JSOp op, const TokenPos& pos) { + return NodeGeneric; + } + Node newUnary(ParseNodeKind kind, JSOp op, uint32_t begin, Node kid) { return NodeUnparenthesizedUnary; } @@ -308,6 +312,16 @@ class SyntaxParseHandler MOZ_MUST_USE bool prependInitialYield(Node stmtList, Node gen) { return true; } Node newEmptyStatement(const TokenPos& pos) { return NodeEmptyStatement; } + Node newExportDeclaration(Node kid, const TokenPos& pos) { + return NodeGeneric; + } + Node newExportFromDeclaration(uint32_t begin, Node exportSpecSet, Node moduleSpec) { + return NodeGeneric; + } + Node newExportDefaultDeclaration(Node kid, Node maybeBinding, const TokenPos& pos) { + return NodeGeneric; + } + Node newSetThis(Node thisName, Node value) { return value; } Node newExprStatement(Node expr, uint32_t end) { -- cgit v1.2.3 From d2aa017a88a4b918ded2159cd202ce6c7c7218d0 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 9 Jun 2019 22:32:35 -0400 Subject: 1339963 - Part 2: Use MUST_MATCH_TOKEN for contextual keyword where it can be used. --- js/src/frontend/Parser.cpp | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 16d4a377a..f382ec5e9 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -4915,13 +4915,7 @@ Parser::importDeclaration() return null(); } - if (!tokenStream.getToken(&tt)) - return null(); - - if (tt != TOK_FROM) { - error(JSMSG_FROM_AFTER_IMPORT_CLAUSE); - return null(); - } + MUST_MATCH_TOKEN(TOK_FROM, JSMSG_FROM_AFTER_IMPORT_CLAUSE); MUST_MATCH_TOKEN(TOK_STRING, JSMSG_MODULE_SPEC_AFTER_FROM); } @@ -5125,13 +5119,7 @@ Parser::exportBatch(uint32_t begin) handler.addList(kid, exportSpec); - TokenKind tt; - if (!tokenStream.getToken(&tt)) - return null(); - if (tt != TOK_FROM) { - error(JSMSG_FROM_AFTER_EXPORT_STAR); - return null(); - } + MUST_MATCH_TOKEN(TOK_FROM, JSMSG_FROM_AFTER_EXPORT_STAR); return exportFrom(begin, kid); } -- cgit v1.2.3 From 64fd7ae4546424c42a9e2022e05b83379411109a Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 9 Jun 2019 22:35:15 -0400 Subject: 1339963 - Part 3: Check IdentifierName in ExportClause without from. --- js/src/frontend/Parser.cpp | 28 +++++++++++++ js/src/frontend/Parser.h | 5 +++ .../jit-test/tests/modules/export-declaration.js | 46 +++++++++++++++++++++- 3 files changed, 77 insertions(+), 2 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index f382ec5e9..ffece5721 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -5124,6 +5124,31 @@ Parser::exportBatch(uint32_t begin) return exportFrom(begin, kid); } +template<> +bool +Parser::checkLocalExportNames(ParseNode* node) +{ + // ES 2017 draft 15.2.3.1. + for (ParseNode* next = node->pn_head; next; next = next->pn_next) { + ParseNode* name = next->pn_left; + MOZ_ASSERT(name->isKind(PNK_NAME)); + + RootedPropertyName ident(context, name->pn_atom->asPropertyName()); + if (!checkLocalExportName(ident, name->pn_pos.begin)) + return false; + } + + return true; +} + +template<> +bool +Parser::checkLocalExportNames(Node node) +{ + MOZ_ALWAYS_FALSE(abortIfSyntaxParser()); + return false; +} + template typename ParseHandler::Node Parser::exportClause(uint32_t begin) @@ -5211,6 +5236,9 @@ Parser::exportClause(uint32_t begin) if (!matchOrInsertSemicolonAfterNonExpression()) return null(); + if (!checkLocalExportNames(kid)) + return null(); + Node node = handler.newExportDeclaration(kid, TokenPos(begin, pos().end)); if (!node) return null(); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index e322a4b26..824dddb58 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1202,6 +1202,7 @@ class Parser final : public ParserBase, private JS::AutoGCRooter Node exportFrom(uint32_t begin, Node specList); Node exportBatch(uint32_t begin); + bool checkLocalExportNames(Node node); Node exportClause(uint32_t begin); Node exportFunctionDeclaration(uint32_t begin); Node exportVariableStatement(uint32_t begin); @@ -1356,6 +1357,10 @@ class Parser final : public ParserBase, private JS::AutoGCRooter uint32_t offset, YieldHandling yieldHandling); + bool checkLocalExportName(HandlePropertyName ident, uint32_t offset) { + return checkLabelOrIdentifierReference(ident, offset, YieldIsName); + } + bool checkBindingIdentifier(HandlePropertyName ident, uint32_t offset, YieldHandling yieldHandling); diff --git a/js/src/jit-test/tests/modules/export-declaration.js b/js/src/jit-test/tests/modules/export-declaration.js index 48d1072bf..9925f2c68 100644 --- a/js/src/jit-test/tests/modules/export-declaration.js +++ b/js/src/jit-test/tests/modules/export-declaration.js @@ -403,10 +403,52 @@ assertThrowsInstanceOf(function() { parseAsModule("export {,} from 'a'"); }, SyntaxError); -parseAsModule("export { true as a } from 'b'"); +program([ + exportDeclaration( + null, + [ + exportSpecifier( + ident("true"), + ident("true") + ), + ], + lit("b"), + false + ) +]).assert(parseAsModule("export { true } from 'b'")); + +program([ + exportDeclaration( + null, + [ + exportSpecifier( + ident("true"), + ident("name") + ), + ], + lit("b"), + false + ) +]).assert(parseAsModule("export { true as name } from 'b'")); + +assertThrowsInstanceOf(function() { + parseAsModule("export { true }"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("export { true as name }"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("export { static }"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("export { static as name }"); +}, SyntaxError); assertThrowsInstanceOf(function () { - parseAsModule("export { a } from 'b' f();"); + parseAsModule("export { name } from 'b' f();"); }, SyntaxError); assertThrowsInstanceOf(function () { -- cgit v1.2.3 From 8a4aeb6f58649af6e0a6d1df30b133510cbb2187 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 9 Jun 2019 22:44:25 -0400 Subject: 1342273 - Improve frontend tracelogging. [PARTIAL] Only implemented const to rvalue changes, no tracelogging --- js/src/frontend/BytecodeEmitter.cpp | 32 +++++++++++++++++--------------- js/src/frontend/BytecodeEmitter.h | 2 +- 2 files changed, 18 insertions(+), 16 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 7b8b41727..c15d67b7c 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -3539,9 +3539,10 @@ BytecodeEmitter::needsImplicitThis() bool BytecodeEmitter::maybeSetDisplayURL() { - if (tokenStream()->hasDisplayURL()) { - if (!parser->ss->setDisplayURL(cx, tokenStream()->displayURL())) + if (tokenStream().hasDisplayURL()) { + if (!parser->ss->setDisplayURL(cx, tokenStream().displayURL())) { return false; + } } return true; } @@ -3549,10 +3550,11 @@ BytecodeEmitter::maybeSetDisplayURL() bool BytecodeEmitter::maybeSetSourceMap() { - if (tokenStream()->hasSourceMapURL()) { + if (tokenStream().hasSourceMapURL()) { MOZ_ASSERT(!parser->ss->hasSourceMapURL()); - if (!parser->ss->setSourceMapURL(cx, tokenStream()->sourceMapURL())) + if (!parser->ss->setSourceMapURL(cx, tokenStream().sourceMapURL())) { return false; + } } /* @@ -3591,21 +3593,21 @@ BytecodeEmitter::tellDebuggerAboutCompiledScript(ExclusiveContext* cx) } } -inline TokenStream* +inline TokenStream& BytecodeEmitter::tokenStream() { - return &parser->tokenStream; + return parser->tokenStream; } bool BytecodeEmitter::reportError(ParseNode* pn, unsigned errorNumber, ...) { - TokenPos pos = pn ? pn->pn_pos : tokenStream()->currentToken().pos; + TokenPos pos = pn ? pn->pn_pos : tokenStream().currentToken().pos; va_list args; va_start(args, errorNumber); - bool result = tokenStream()->reportCompileErrorNumberVA(nullptr, pos.begin, JSREPORT_ERROR, - errorNumber, args); + bool result = tokenStream().reportCompileErrorNumberVA(nullptr, pos.begin, JSREPORT_ERROR, + errorNumber, args); va_end(args); return result; } @@ -3613,12 +3615,12 @@ BytecodeEmitter::reportError(ParseNode* pn, unsigned errorNumber, ...) bool BytecodeEmitter::reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...) { - TokenPos pos = pn ? pn->pn_pos : tokenStream()->currentToken().pos; + TokenPos pos = pn ? pn->pn_pos : tokenStream().currentToken().pos; va_list args; va_start(args, errorNumber); - bool result = tokenStream()->reportExtraWarningErrorNumberVA(nullptr, pos.begin, - errorNumber, args); + bool result = tokenStream().reportExtraWarningErrorNumberVA(nullptr, pos.begin, + errorNumber, args); va_end(args); return result; } @@ -3626,12 +3628,12 @@ BytecodeEmitter::reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...) bool BytecodeEmitter::reportStrictModeError(ParseNode* pn, unsigned errorNumber, ...) { - TokenPos pos = pn ? pn->pn_pos : tokenStream()->currentToken().pos; + TokenPos pos = pn ? pn->pn_pos : tokenStream().currentToken().pos; va_list args; va_start(args, errorNumber); - bool result = tokenStream()->reportStrictModeErrorNumberVA(nullptr, pos.begin, sc->strict(), - errorNumber, args); + bool result = tokenStream().reportStrictModeErrorNumberVA(nullptr, pos.begin, sc->strict(), + errorNumber, args); va_end(args); return result; } diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index 29050c846..4e5209593 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -356,7 +356,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter MOZ_MUST_USE bool maybeSetSourceMap(); void tellDebuggerAboutCompiledScript(ExclusiveContext* cx); - inline TokenStream* tokenStream(); + inline TokenStream& tokenStream(); BytecodeVector& code() const { return current->code; } jsbytecode* code(ptrdiff_t offset) const { return current->code.begin() + offset; } -- cgit v1.2.3 From dab8877c10fcc9dd5d86e6fd3d1924e474076726 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 9 Jun 2019 23:03:08 -0400 Subject: 104442 - Part 1: Report the position and the kind of previous declaration for redeclaration error. --- js/src/frontend/NameAnalysisTypes.h | 12 +- js/src/frontend/Parser.cpp | 106 +++++++++--- js/src/frontend/Parser.h | 16 +- js/src/jit-test/tests/parser/redeclaration.js | 230 ++++++++++++++++++++++++++ js/src/js.msg | 1 + 5 files changed, 330 insertions(+), 35 deletions(-) create mode 100644 js/src/jit-test/tests/parser/redeclaration.js (limited to 'js/src') diff --git a/js/src/frontend/NameAnalysisTypes.h b/js/src/frontend/NameAnalysisTypes.h index d39e177fb..b94ca6cc0 100644 --- a/js/src/frontend/NameAnalysisTypes.h +++ b/js/src/frontend/NameAnalysisTypes.h @@ -124,6 +124,7 @@ DeclarationKindIsLexical(DeclarationKind kind) // Used in Parser to track declared names. class DeclaredNameInfo { + uint32_t pos_; DeclarationKind kind_; // If the declared name is a binding, whether the binding is closed @@ -132,8 +133,9 @@ class DeclaredNameInfo bool closedOver_; public: - explicit DeclaredNameInfo(DeclarationKind kind) - : kind_(kind), + explicit DeclaredNameInfo(DeclarationKind kind, uint32_t pos) + : pos_(pos), + kind_(kind), closedOver_(false) { } @@ -144,6 +146,12 @@ class DeclaredNameInfo return kind_; } + static const uint32_t npos = uint32_t(-1); + + uint32_t pos() const { + return pos_; + } + void alterKind(DeclarationKind kind) { kind_ = kind; } diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index ffece5721..c96e8c065 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -19,6 +19,8 @@ #include "frontend/Parser.h" +#include "mozilla/Sprintf.h" + #include #include "jsapi.h" @@ -200,11 +202,12 @@ ParseContext::Scope::addCatchParameters(ParseContext* pc, Scope& catchParamScope for (DeclaredNameMap::Range r = catchParamScope.declared_->all(); !r.empty(); r.popFront()) { DeclarationKind kind = r.front().value()->kind(); + uint32_t pos = r.front().value()->pos(); MOZ_ASSERT(DeclarationKindIsCatchParameter(kind)); JSAtom* name = r.front().key(); AddDeclaredNamePtr p = lookupDeclaredNameForAdd(name); MOZ_ASSERT(!p); - if (!addDeclaredName(pc, p, name, kind)) + if (!addDeclaredName(pc, p, name, kind, pos)) return false; } @@ -343,7 +346,8 @@ ParseContext::init() namedLambdaScope_->lookupDeclaredNameForAdd(fun->explicitName()); MOZ_ASSERT(!p); if (!namedLambdaScope_->addDeclaredName(this, p, fun->explicitName(), - DeclarationKind::Const)) + DeclarationKind::Const, + DeclaredNameInfo::npos)) { return false; } @@ -1001,13 +1005,42 @@ Parser::hasValidSimpleStrictParameterNames() template void -Parser::reportRedeclaration(HandlePropertyName name, DeclarationKind kind, - TokenPos pos) +Parser::reportRedeclaration(HandlePropertyName name, DeclarationKind prevKind, + TokenPos pos, uint32_t prevPos) { JSAutoByteString bytes; if (!AtomToPrintableString(context, name, &bytes)) return; - errorAt(pos.begin, JSMSG_REDECLARED_VAR, DeclarationKindString(kind), bytes.ptr()); + + if (prevPos == DeclaredNameInfo::npos) { + errorAt(pos.begin, JSMSG_REDECLARED_VAR, DeclarationKindString(prevKind), bytes.ptr()); + return; + } + + auto notes = MakeUnique(); + if (!notes) + return; + + uint32_t line, column; + tokenStream.srcCoords.lineNumAndColumnIndex(prevPos, &line, &column); + + const size_t MaxWidth = sizeof("4294967295"); + char columnNumber[MaxWidth]; + SprintfLiteral(columnNumber, "%" PRIu32, column); + char lineNumber[MaxWidth]; + SprintfLiteral(lineNumber, "%" PRIu32, line); + + if (!notes->addNoteLatin1(pc->sc()->context, + getFilename(), line, column, + GetErrorMessage, nullptr, + JSMSG_REDECLARED_PREV, + lineNumber, columnNumber)) + { + return; + } + + errorWithNotesAt(Move(notes), pos.begin, JSMSG_REDECLARED_VAR, + DeclarationKindString(prevKind), bytes.ptr()); } // notePositionalFormalParameter is called for both the arguments of a regular @@ -1022,6 +1055,7 @@ Parser::reportRedeclaration(HandlePropertyName name, DeclarationKi template bool Parser::notePositionalFormalParameter(Node fn, HandlePropertyName name, + uint32_t beginPos, bool disallowDuplicateParams, bool* duplicatedParam) { @@ -1046,7 +1080,7 @@ Parser::notePositionalFormalParameter(Node fn, HandlePropertyName *duplicatedParam = true; } else { DeclarationKind kind = DeclarationKind::PositionalFormalParameter; - if (!pc->functionScope().addDeclaredName(pc, p, name, kind)) + if (!pc->functionScope().addDeclaredName(pc, p, name, kind, beginPos)) return false; } @@ -1150,8 +1184,8 @@ DeclarationKindIsParameter(DeclarationKind kind) template bool -Parser::tryDeclareVar(HandlePropertyName name, DeclarationKind kind, - Maybe* redeclaredKind) +Parser::tryDeclareVar(HandlePropertyName name, DeclarationKind kind, uint32_t beginPos, + Maybe* redeclaredKind, uint32_t* prevPos) { MOZ_ASSERT(DeclarationKindIsVar(kind)); @@ -1224,23 +1258,29 @@ Parser::tryDeclareVar(HandlePropertyName name, DeclarationKind kin if (!annexB35Allowance && !annexB33Allowance) { *redeclaredKind = Some(declaredKind); + *prevPos = p->value()->pos(); return true; } } else if (kind == DeclarationKind::VarForAnnexBLexicalFunction) { MOZ_ASSERT(DeclarationKindIsParameter(declaredKind)); // Annex B.3.3.1 disallows redeclaring parameter names. + // We don't need to set *prevPos here since this case is not + // an error. *redeclaredKind = Some(declaredKind); return true; } } else { - if (!scope->addDeclaredName(pc, p, name, kind)) + if (!scope->addDeclaredName(pc, p, name, kind, beginPos)) return false; } } - if (!pc->sc()->strict() && pc->sc()->isEvalContext()) + if (!pc->sc()->strict() && pc->sc()->isEvalContext()) { *redeclaredKind = isVarRedeclaredInEval(name, kind); + // We don't have position information at runtime. + *prevPos = DeclaredNameInfo::npos; + } return true; } @@ -1248,11 +1288,15 @@ Parser::tryDeclareVar(HandlePropertyName name, DeclarationKind kin template bool Parser::tryDeclareVarForAnnexBLexicalFunction(HandlePropertyName name, - bool* tryAnnexB) + uint32_t beginPos, bool* tryAnnexB) { Maybe redeclaredKind; - if (!tryDeclareVar(name, DeclarationKind::VarForAnnexBLexicalFunction, &redeclaredKind)) + uint32_t unused; + if (!tryDeclareVar(name, DeclarationKind::VarForAnnexBLexicalFunction, beginPos, + &redeclaredKind, &unused)) + { return false; + } if (!redeclaredKind && pc->isFunctionBox()) { ParseContext::Scope& funScope = pc->functionScope(); @@ -1324,11 +1368,12 @@ Parser::noteDeclaredName(HandlePropertyName name, DeclarationKind case DeclarationKind::BodyLevelFunction: case DeclarationKind::ForOfVar: { Maybe redeclaredKind; - if (!tryDeclareVar(name, kind, &redeclaredKind)) + uint32_t prevPos; + if (!tryDeclareVar(name, kind, pos.begin, &redeclaredKind, &prevPos)) return false; if (redeclaredKind) { - reportRedeclaration(name, *redeclaredKind, pos); + reportRedeclaration(name, *redeclaredKind, pos, prevPos); return false; } @@ -1345,7 +1390,7 @@ Parser::noteDeclaredName(HandlePropertyName name, DeclarationKind return false; } - if (!pc->functionScope().addDeclaredName(pc, p, name, kind)) + if (!pc->functionScope().addDeclaredName(pc, p, name, kind, pos.begin)) return false; break; @@ -1368,7 +1413,7 @@ Parser::noteDeclaredName(HandlePropertyName name, DeclarationKind (p->value()->kind() != DeclarationKind::LexicalFunction && p->value()->kind() != DeclarationKind::VarForAnnexBLexicalFunction)) { - reportRedeclaration(name, p->value()->kind(), pos); + reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos()); return false; } @@ -1376,7 +1421,7 @@ Parser::noteDeclaredName(HandlePropertyName name, DeclarationKind // declaration that shadows the VarForAnnexBLexicalFunction. p->value()->alterKind(kind); } else { - if (!scope->addDeclaredName(pc, p, name, kind)) + if (!scope->addDeclaredName(pc, p, name, kind, pos.begin)) return false; } @@ -1416,7 +1461,7 @@ Parser::noteDeclaredName(HandlePropertyName name, DeclarationKind if (pc->isFunctionExtraBodyVarScopeInnermost()) { DeclaredNamePtr p = pc->functionScope().lookupDeclaredName(name); if (p && DeclarationKindIsParameter(p->value()->kind())) { - reportRedeclaration(name, p->value()->kind(), pos); + reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos()); return false; } } @@ -1433,12 +1478,12 @@ Parser::noteDeclaredName(HandlePropertyName name, DeclarationKind p = scope->lookupDeclaredNameForAdd(name); MOZ_ASSERT(!p); } else { - reportRedeclaration(name, p->value()->kind(), pos); + reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos()); return false; } } - if (!p && !scope->addDeclaredName(pc, p, name, kind)) + if (!p && !scope->addDeclaredName(pc, p, name, kind, pos.begin)) return false; break; @@ -2188,8 +2233,11 @@ Parser::declareFunctionThis() ParseContext::Scope& funScope = pc->functionScope(); AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(dotThis); MOZ_ASSERT(!p); - if (!funScope.addDeclaredName(pc, p, dotThis, DeclarationKind::Var)) + if (!funScope.addDeclaredName(pc, p, dotThis, DeclarationKind::Var, + DeclaredNameInfo::npos)) + { return false; + } funbox->setHasThisBinding(); } @@ -2231,8 +2279,11 @@ Parser::declareDotGeneratorName() ParseContext::Scope& funScope = pc->functionScope(); HandlePropertyName dotGenerator = context->names().dotGenerator; AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(dotGenerator); - if (!p && !funScope.addDeclaredName(pc, p, dotGenerator, DeclarationKind::Var)) + if (!p && !funScope.addDeclaredName(pc, p, dotGenerator, DeclarationKind::Var, + DeclaredNameInfo::npos)) + { return false; + } return true; } @@ -2481,8 +2532,11 @@ Parser::declareFunctionArgumentsObject() if (tryDeclareArguments) { AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(argumentsName); if (!p) { - if (!funScope.addDeclaredName(pc, p, argumentsName, DeclarationKind::Var)) + if (!funScope.addDeclaredName(pc, p, argumentsName, DeclarationKind::Var, + DeclaredNameInfo::npos)) + { return false; + } funbox->declaredArguments = true; funbox->usesArguments = true; } else if (hasExtraBodyVarScope) { @@ -2964,8 +3018,8 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn if (!name) return false; - if (!notePositionalFormalParameter(funcpn, name, disallowDuplicateParams, - &duplicatedParam)) + if (!notePositionalFormalParameter(funcpn, name, pos().begin, + disallowDuplicateParams, &duplicatedParam)) { return false; } @@ -3689,7 +3743,7 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan // early error, do so. This 'var' binding would be assigned // the function object when its declaration is reached, not at // the start of the block. - if (!tryDeclareVarForAnnexBLexicalFunction(name, &tryAnnexB)) + if (!tryDeclareVarForAnnexBLexicalFunction(name, pos().begin, &tryAnnexB)) return null(); } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 824dddb58..6b5ade425 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -146,9 +146,9 @@ class ParseContext : public Nestable } MOZ_MUST_USE bool addDeclaredName(ParseContext* pc, AddDeclaredNamePtr& p, JSAtom* name, - DeclarationKind kind) + DeclarationKind kind, uint32_t pos) { - return maybeReportOOM(pc, declared_->add(p, name, DeclaredNameInfo(kind))); + return maybeReportOOM(pc, declared_->add(p, name, DeclaredNameInfo(kind, pos))); } // Remove all VarForAnnexBLexicalFunction declarations of a certain @@ -1437,15 +1437,17 @@ class Parser final : public ParserBase, private JS::AutoGCRooter bool hasValidSimpleStrictParameterNames(); - void reportRedeclaration(HandlePropertyName name, DeclarationKind kind, TokenPos pos); - bool notePositionalFormalParameter(Node fn, HandlePropertyName name, + void reportRedeclaration(HandlePropertyName name, DeclarationKind prevKind, TokenPos pos, + uint32_t prevPos); + bool notePositionalFormalParameter(Node fn, HandlePropertyName name, uint32_t beginPos, bool disallowDuplicateParams, bool* duplicatedParam); bool noteDestructuredPositionalFormalParameter(Node fn, Node destruct); mozilla::Maybe isVarRedeclaredInEval(HandlePropertyName name, DeclarationKind kind); - bool tryDeclareVar(HandlePropertyName name, DeclarationKind kind, - mozilla::Maybe* redeclaredKind); - bool tryDeclareVarForAnnexBLexicalFunction(HandlePropertyName name, bool* tryAnnexB); + bool tryDeclareVar(HandlePropertyName name, DeclarationKind kind, uint32_t beginPos, + mozilla::Maybe* redeclaredKind, uint32_t* prevPos); + bool tryDeclareVarForAnnexBLexicalFunction(HandlePropertyName name, uint32_t beginPos, + bool* tryAnnexB); bool checkLexicalDeclarationDirectlyWithinBlock(ParseContext::Statement& stmt, DeclarationKind kind, TokenPos pos); bool noteDeclaredName(HandlePropertyName name, DeclarationKind kind, TokenPos pos); diff --git a/js/src/jit-test/tests/parser/redeclaration.js b/js/src/jit-test/tests/parser/redeclaration.js new file mode 100644 index 000000000..f719021ac --- /dev/null +++ b/js/src/jit-test/tests/parser/redeclaration.js @@ -0,0 +1,230 @@ +// Error message for redeclaration should show the position where the variable +// was declared. + +const npos = -1; + +function test_one(fun, filename, name, + [prevLineNumber, prevColumnNumber], + [lineNumber, columnNumber]) { + let caught = false; + try { + fun(); + } catch (e) { + assertEq(e.message.includes("redeclaration"), true); + assertEq(e.lineNumber, lineNumber); + assertEq(e.columnNumber, columnNumber); + let notes = getErrorNotes(e); + if (prevLineNumber == npos) { + assertEq(notes.length, 0); + } else { + assertEq(notes.length, 1); + let note = notes[0]; + assertEq(note.message, + `Previously declared at line ${prevLineNumber}, column ${prevColumnNumber}`); + assertEq(note.lineNumber, prevLineNumber); + assertEq(note.columnNumber, prevColumnNumber); + if (filename) + assertEq(note.fileName, filename); + } + caught = true; + } + assertEq(caught, true); +} + +function test_parse(source, ...args) { + test_one(() => { + Reflect.parse(source, { source: "foo.js" }); + }, "foo.js", ...args); +} + +function test_eval(source, ...args) { + test_one(() => { + eval(source); + }, undefined, ...args); +} + +function test(...args) { + test_parse(...args); + test_eval(...args); +} + +// let + +test(` +let a, a; +`, "a", [2, 4], [2, 7]); + +test(` +let a; +let a; +`, "a", [2, 4], [3, 4]); + +test(` +let a; +const a = 1; +`, "a", [2, 4], [3, 6]); + +test(` +let a; +var a; +`, "a", [2, 4], [3, 4]); + +test(` +let a; +function a() { +} +`, "a", [2, 4], [3, 9]); + +test(` +{ + let a; + function a() { + } +} +`, "a", [3, 6], [4, 11]); + +// const + +test(` +const a = 1, a = 2; +`, "a", [2, 6], [2, 13]); + +test(` +const a = 1; +const a = 2; +`, "a", [2, 6], [3, 6]); + +test(` +const a = 1; +let a; +`, "a", [2, 6], [3, 4]); + +test(` +const a = 1; +var a; +`, "a", [2, 6], [3, 4]); + +test(` +const a = 1; +function a() { +} +`, "a", [2, 6], [3, 9]); + +test(` +{ + const a = 1; + function a() { + } +} +`, "a", [3, 8], [4, 11]); + +// var + +test(` +var a; +let a; +`, "a", [2, 4], [3, 4]); + +test(` +var a; +const a = 1; +`, "a", [2, 4], [3, 6]); + +// function + +test(` +function a() {}; +let a; +`, "a", [2, 9], [3, 4]); + +test(` +function a() {}; +const a = 1; +`, "a", [2, 9], [3, 6]); + +// Annex B lexical function + +test(` +{ + function a() {}; + let a; +} +`, "a", [3, 11], [4, 6]); + +test(` +{ + function a() {}; + const a = 1; +} +`, "a", [3, 11], [4, 8]); + +// catch parameter + +test(` +try { +} catch (a) { + let a; +} +`, "a", [3, 9], [4, 6]); + +test(` +try { +} catch (a) { + const a = 1; +} +`, "a", [3, 9], [4, 8]); + +test(` +try { +} catch (a) { + function a() { + } +} +`, "a", [3, 9], [4, 11]); + +// parameter + +test(` +function f(a) { + let a; +} +`, "a", [2, 11], [3, 6]); + +test(` +function f(a) { + const a = 1; +} +`, "a", [2, 11], [3, 8]); + +test(` +function f([a]) { + let a; +} +`, "a", [2, 12], [3, 6]); + +test(` +function f({a}) { + let a; +} +`, "a", [2, 12], [3, 6]); + +test(` +function f(...a) { + let a; +} +`, "a", [2, 14], [3, 6]); + +test(` +function f(a=1) { + let a; +} +`, "a", [2, 11], [3, 6]); + +// eval +// We don't have position information at runtime. +// No note should be shown. + +test_eval(` +let a; +eval("var a"); +`, "a", [npos, npos], [1, 4]); diff --git a/js/src/js.msg b/js/src/js.msg index ce039cbc8..569928be8 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -63,6 +63,7 @@ MSG_DEF(JSMSG_SPREAD_TOO_LARGE, 0, JSEXN_RANGEERR, "array too large due t MSG_DEF(JSMSG_BAD_WEAKMAP_KEY, 0, JSEXN_TYPEERR, "cannot use the given object as a weak map key") MSG_DEF(JSMSG_BAD_GETTER_OR_SETTER, 1, JSEXN_TYPEERR, "invalid {0} usage") MSG_DEF(JSMSG_BAD_ARRAY_LENGTH, 0, JSEXN_RANGEERR, "invalid array length") +MSG_DEF(JSMSG_REDECLARED_PREV, 2, JSEXN_NOTE, "Previously declared at line {0}, column {1}") MSG_DEF(JSMSG_REDECLARED_VAR, 2, JSEXN_SYNTAXERR, "redeclaration of {0} {1}") MSG_DEF(JSMSG_UNDECLARED_VAR, 1, JSEXN_REFERENCEERR, "assignment to undeclared variable {0}") MSG_DEF(JSMSG_GETTER_ONLY, 1, JSEXN_TYPEERR, "setting getter-only property {0}") -- cgit v1.2.3 From d1c146adf23e317facd03cd5c097f12a69947392 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Mon, 10 Jun 2019 18:41:38 -0400 Subject: 1340148 - Disallow function redeclarations at module top level. --- js/src/frontend/NameAnalysisTypes.h | 2 + js/src/frontend/Parser.cpp | 28 +++++-- .../jit-test/modules/export-default-async-asi.js | 2 + .../tests/modules/function-redeclaration.js | 94 ++++++++++++++++++++++ 4 files changed, 121 insertions(+), 5 deletions(-) create mode 100644 js/src/jit-test/modules/export-default-async-asi.js create mode 100644 js/src/jit-test/tests/modules/function-redeclaration.js (limited to 'js/src') diff --git a/js/src/frontend/NameAnalysisTypes.h b/js/src/frontend/NameAnalysisTypes.h index b94ca6cc0..2d327c827 100644 --- a/js/src/frontend/NameAnalysisTypes.h +++ b/js/src/frontend/NameAnalysisTypes.h @@ -78,6 +78,7 @@ enum class DeclarationKind : uint8_t Const, Import, BodyLevelFunction, + ModuleBodyLevelFunction, LexicalFunction, VarForAnnexBLexicalFunction, SimpleCatchParameter, @@ -95,6 +96,7 @@ DeclarationKindToBindingKind(DeclarationKind kind) case DeclarationKind::Var: case DeclarationKind::BodyLevelFunction: + case DeclarationKind::ModuleBodyLevelFunction: case DeclarationKind::VarForAnnexBLexicalFunction: case DeclarationKind::ForOfVar: return BindingKind::Var; diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index c96e8c065..d62a26f76 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -119,6 +119,7 @@ DeclarationKindString(DeclarationKind kind) case DeclarationKind::Import: return "import"; case DeclarationKind::BodyLevelFunction: + case DeclarationKind::ModuleBodyLevelFunction: case DeclarationKind::LexicalFunction: return "function"; case DeclarationKind::VarForAnnexBLexicalFunction: @@ -1380,6 +1381,24 @@ Parser::noteDeclaredName(HandlePropertyName name, DeclarationKind break; } + case DeclarationKind::ModuleBodyLevelFunction: { + MOZ_ASSERT(pc->atModuleLevel()); + + AddDeclaredNamePtr p = pc->varScope().lookupDeclaredNameForAdd(name); + if (p) { + reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos()); + return false; + } + + if (!pc->varScope().addDeclaredName(pc, p, name, kind, pos.begin)) + return false; + + // Body-level functions in modules are always closed over. + pc->varScope().lookupDeclaredName(name)->value()->setClosedOver(); + + break; + } + case DeclarationKind::FormalParameter: { // It is an early error if any non-positional formal parameter name // (e.g., destructuring formal parameter) is duplicated. @@ -3750,12 +3769,11 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan if (!noteDeclaredName(name, DeclarationKind::LexicalFunction, pos())) return null(); } else { - if (!noteDeclaredName(name, DeclarationKind::BodyLevelFunction, pos())) + DeclarationKind kind = pc->atModuleLevel() + ? DeclarationKind::ModuleBodyLevelFunction + : DeclarationKind::BodyLevelFunction; + if (!noteDeclaredName(name, kind, pos())) return null(); - - // Body-level functions in modules are always closed over. - if (pc->atModuleLevel()) - pc->varScope().lookupDeclaredName(name)->value()->setClosedOver(); } Node pn = handler.newFunctionStatement(); diff --git a/js/src/jit-test/modules/export-default-async-asi.js b/js/src/jit-test/modules/export-default-async-asi.js new file mode 100644 index 000000000..a69a7aa3d --- /dev/null +++ b/js/src/jit-test/modules/export-default-async-asi.js @@ -0,0 +1,2 @@ +export default async // ASI occurs here due to the [no LineTerminator here] restriction on default-exporting an async function +function async() { return 17; } diff --git a/js/src/jit-test/tests/modules/function-redeclaration.js b/js/src/jit-test/tests/modules/function-redeclaration.js new file mode 100644 index 000000000..b84704641 --- /dev/null +++ b/js/src/jit-test/tests/modules/function-redeclaration.js @@ -0,0 +1,94 @@ +load(libdir + "asserts.js"); + +var functionDeclarations = [ + "function f(){}", + "function* f(){}", + "async function f(){}", +]; + +var varDeclarations = [ + "var f", + "{ var f; }", + "for (var f in null);", + "for (var f of null);", + "for (var f; ;);", +]; + +var lexicalDeclarations = [ + "let f;", + "const f = 0;", + "class f {};", +]; + +var imports = [ + "import f from '';", + "import f, {} from '';", + "import d, {f} from '';", + "import d, {f as f} from '';", + "import d, {foo as f} from '';", + "import f, * as d from '';", + "import d, * as f from '';", + "import {f} from '';", + "import {f as f} from '';", + "import {foo as f} from '';", + "import* as f from '';", +]; + +var exports = [ + "export var f;", + ...functionDeclarations.map(fn => `export ${fn};`), + ...lexicalDeclarations.map(ld => `export ${ld};`), + ...functionDeclarations.map(fn => `export default ${fn};`), + "export default class f {};", +]; + +var redeclarations = [ + ...functionDeclarations, + ...varDeclarations, + ...lexicalDeclarations, + ...imports, + ...exports, +]; + +var noredeclarations = [ + ...functionDeclarations.map(fn => `{ ${fn} }`), + ...lexicalDeclarations.map(ld => `{ ${ld} }`), + ...["let", "const"].map(ld => `for (${ld} f in null);`), + ...["let", "const"].map(ld => `for (${ld} f of null);`), + ...["let", "const"].map(ld => `for (${ld} f = 0; ;);`), + "export {f};", + "export {f as f};", + "export {foo as f}; var foo;", + "export {f} from '';", + "export {f as f} from '';", + "export {foo as f} from '';", +]; + +for (var decl of functionDeclarations) { + for (var redecl of redeclarations) { + assertThrowsInstanceOf(() => { + parseModule(` + ${decl} + ${redecl} + `); + }, SyntaxError); + + assertThrowsInstanceOf(() => { + parseModule(` + ${redecl} + ${decl} + `); + }, SyntaxError); + } + + for (var redecl of noredeclarations) { + parseModule(` + ${decl} + ${redecl} + `); + parseModule(` + ${redecl} + ${decl} + `); + } +} -- cgit v1.2.3 From 53e46b1e12ef01ccaabb3256738ea1eac74b7941 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 13 Jul 2019 21:33:52 -0400 Subject: 1216630 - Print class source when calling toString on the constructor. This is accomplished in the following ways. LazyScripts and JSScripts now have 4 offsets: - Source begin and end for the actual source. This is used for lazy parsing. - toString begin and end for toString. Some kinds of functions, like async, only have a different begin offset. Class constructors have different offsets for both begin and end. For syntactically present (i.e. non-default) constructors, the class source span is remembered directly on the LazyScript or JSScript. The toString implementation then splices out the substring directly. For default constructors, a new SRC_CLASS SrcNote type is added. It's binary and has as its arguments the begin and end offsets of the class expression or statement. MakeDefaultConstructor reads the note and overrides the cloned self-hosted function's source object. This is probably the least intrusive way to accomplish this. --- js/src/frontend/BytecodeCompiler.cpp | 16 ++++--- js/src/frontend/BytecodeEmitter.cpp | 10 ++++- js/src/frontend/FullParseHandler.h | 6 ++- js/src/frontend/ParseNode.h | 5 ++- js/src/frontend/Parser.cpp | 85 ++++++++++++++++++++++++++---------- js/src/frontend/Parser.h | 37 ++++++++++++++++ js/src/frontend/SharedContext.h | 11 +++++ js/src/frontend/SourceNotes.h | 3 +- js/src/frontend/SyntaxParseHandler.h | 2 +- js/src/jsfun.cpp | 41 ++++++++--------- js/src/jsscript.cpp | 34 ++++++++++++--- js/src/jsscript.h | 39 ++++++++++++++--- js/src/shell/js.cpp | 8 ++++ js/src/vm/Interpreter.cpp | 25 ++++++++--- 14 files changed, 248 insertions(+), 74 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index a4b7dba6b..e0bb64e05 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -77,7 +77,13 @@ class MOZ_STACK_CLASS BytecodeCompiler bool canLazilyParse(); bool createParser(); bool createSourceAndParser(Maybe parameterListEnd = Nothing()); - bool createScript(uint32_t preludeStart = 0); + + // If toString{Start,End} are not explicitly passed, assume the script's + // offsets in the source used to parse it are the same as what should be + // used to compute its Function.prototype.toString() value. + bool createScript(); + bool createScript(uint32_t toStringStart, uint32_t toStringEnd); + bool emplaceEmitter(Maybe& emitter, SharedContext* sharedContext); bool handleParseFailure(const Directives& newDirectives); bool deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObject environment); @@ -242,11 +248,11 @@ BytecodeCompiler::createSourceAndParser(Maybe parameterListEnd /* = No } bool -BytecodeCompiler::createScript(uint32_t preludeStart /* = 0 */) +BytecodeCompiler::createScript(uint32_t preludeStart /* = 0 */, uint32_t postludeEnd /* = 0 */) { script = JSScript::Create(cx, options, sourceObject, /* sourceStart = */ 0, sourceBuffer.length(), - preludeStart); + preludeStart, postludeEnd); return script != nullptr; } @@ -458,7 +464,7 @@ BytecodeCompiler::compileStandaloneFunction(MutableHandleFunction fun, if (fn->pn_funbox->function()->isInterpreted()) { MOZ_ASSERT(fun == fn->pn_funbox->function()); - if (!createScript(fn->pn_funbox->preludeStart)) + if (!createScript(fn->pn_funbox->preludeStart, fn->pn_funbox->postludeEnd)) return false; Maybe emitter; @@ -653,7 +659,7 @@ frontend::CompileLazyFunction(JSContext* cx, Handle lazy, const cha Rooted script(cx, JSScript::Create(cx, options, sourceObject, lazy->begin(), lazy->end(), - lazy->preludeStart())); + lazy->preludeStart(), lazy->postludeEnd())); if (!script) return false; diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index c15d67b7c..c788e0086 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -7846,7 +7846,8 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto) Rooted sourceObject(cx, script->sourceObject()); Rooted script(cx, JSScript::Create(cx, options, sourceObject, funbox->bufStart, funbox->bufEnd, - funbox->preludeStart)); + funbox->preludeStart, + funbox->postludeEnd)); if (!script) return false; @@ -10226,6 +10227,13 @@ BytecodeEmitter::emitClass(ParseNode* pn) return false; } } else { + // In the case of default class constructors, emit the start and end + // offsets in the source buffer as source notes so that when we + // actually make the constructor during execution, we can give it the + // correct toString output. + if (!newSrcNote3(SRC_CLASS_SPAN, ptrdiff_t(pn->pn_pos.begin), ptrdiff_t(pn->pn_pos.end))) + return false; + JSAtom *name = names ? names->innerBinding()->pn_atom : cx->names().empty; if (heritageExpression) { if (!emitAtomOp(name, JSOP_DERIVEDCONSTRUCTOR)) diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index f0fc7700d..7ddd8d306 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -333,8 +333,10 @@ class FullParseHandler return literal; } - ParseNode* newClass(ParseNode* name, ParseNode* heritage, ParseNode* methodBlock) { - return new_(name, heritage, methodBlock); + ParseNode* newClass(ParseNode* name, ParseNode* heritage, ParseNode* methodBlock, + const TokenPos& pos) + { + return new_(name, heritage, methodBlock, pos); } ParseNode* newClassMethodList(uint32_t begin) { return new_(PNK_CLASSMETHODLIST, TokenPos(begin, begin + 1)); diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index c0669d85e..1f20f3988 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -1309,8 +1309,9 @@ struct ClassNames : public BinaryNode { }; struct ClassNode : public TernaryNode { - ClassNode(ParseNode* names, ParseNode* heritage, ParseNode* methodsOrBlock) - : TernaryNode(PNK_CLASS, JSOP_NOP, names, heritage, methodsOrBlock) + ClassNode(ParseNode* names, ParseNode* heritage, ParseNode* methodsOrBlock, + const TokenPos& pos) + : TernaryNode(PNK_CLASS, JSOP_NOP, names, heritage, methodsOrBlock, pos) { MOZ_ASSERT_IF(names, names->is()); MOZ_ASSERT(methodsOrBlock->is() || diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index d62a26f76..299b8b93a 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -141,7 +141,8 @@ StatementKindIsBraced(StatementKind kind) kind == StatementKind::Switch || kind == StatementKind::Try || kind == StatementKind::Catch || - kind == StatementKind::Finally; + kind == StatementKind::Finally || + kind == StatementKind::Class; } void @@ -472,6 +473,7 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* trac startLine(1), startColumn(0), preludeStart(preludeStart), + postludeEnd(0), length(0), generatorKindBits_(GeneratorKindAsBits(generatorKind)), asyncKindBits_(AsyncKindAsBits(asyncKind)), @@ -542,10 +544,16 @@ FunctionBox::initWithEnclosingParseContext(ParseContext* enclosing, FunctionSynt allowNewTarget_ = true; allowSuperProperty_ = fun->allowSuperProperty(); - if (kind == DerivedClassConstructor) { - setDerivedClassConstructor(); - allowSuperCall_ = true; - needsThisTDZChecks_ = true; + if (kind == ClassConstructor || kind == DerivedClassConstructor) { + auto stmt = enclosing->findInnermostStatement(); + MOZ_ASSERT(stmt); + stmt->setConstructorBox(this); + + if (kind == DerivedClassConstructor) { + setDerivedClassConstructor(); + allowSuperCall_ = true; + needsThisTDZChecks_ = true; + } } if (isGenexpLambda) @@ -565,6 +573,16 @@ FunctionBox::initWithEnclosingParseContext(ParseContext* enclosing, FunctionSynt } } +void +FunctionBox::resetForAbortedSyntaxParse(ParseContext* enclosing, FunctionSyntaxKind kind) +{ + if (kind == ClassConstructor || kind == DerivedClassConstructor) { + auto stmt = enclosing->findInnermostStatement(); + MOZ_ASSERT(stmt); + stmt->clearConstructorBoxForAbortedSyntaxParse(this); + } +} + void FunctionBox::initWithEnclosingScope(Scope* enclosingScope) { @@ -3389,6 +3407,7 @@ Parser::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunct // correctness. parser->clearAbortedSyntaxParse(); usedNames.rewind(token); + funbox->resetForAbortedSyntaxParse(pc, kind); MOZ_ASSERT_IF(parser->context->isJSContext(), !parser->context->asJSContext()->isExceptionPending()); break; @@ -3670,14 +3689,14 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, error(JSMSG_CURLY_AFTER_BODY); return false; } - funbox->bufEnd = pos().end; + funbox->setEnd(pos().end); } else { #if !JS_HAS_EXPR_CLOSURES MOZ_ASSERT(kind == Arrow); #endif if (tokenStream.hadError()) return false; - funbox->bufEnd = pos().end; + funbox->setEnd(pos().end); if (kind == Statement && !matchOrInsertSemicolonAfterExpression()) return false; } @@ -6935,6 +6954,7 @@ Parser::classDefinition(YieldHandling yieldHandling, { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_CLASS)); + uint32_t classStartOffset = pos().begin; bool savedStrictness = setLocalStrictMode(true); TokenKind tt; @@ -6960,16 +6980,20 @@ Parser::classDefinition(YieldHandling yieldHandling, tokenStream.ungetToken(); } + // Push a ParseContext::ClassStatement to keep track of the constructor + // funbox. + ParseContext::ClassStatement classStmt(pc); + RootedAtom propAtom(context); // A named class creates a new lexical scope with a const binding of the - // class name. - Maybe classStmt; - Maybe classScope; + // class name for the "inner name". + Maybe innerScopeStmt; + Maybe innerScope; if (name) { - classStmt.emplace(pc, StatementKind::Block); - classScope.emplace(this); - if (!classScope->init(pc)) + innerScopeStmt.emplace(pc, StatementKind::Block); + innerScope.emplace(this); + if (!innerScope->init(pc)) return null(); } @@ -6996,7 +7020,6 @@ Parser::classDefinition(YieldHandling yieldHandling, if (!classMethods) return null(); - bool seenConstructor = false; for (;;) { TokenKind tt; if (!tokenStream.getToken(&tt)) @@ -7048,16 +7071,17 @@ Parser::classDefinition(YieldHandling yieldHandling, propType = PropertyType::GetterNoExpressionClosure; if (propType == PropertyType::Setter) propType = PropertyType::SetterNoExpressionClosure; - if (!isStatic && propAtom == context->names().constructor) { + + bool isConstructor = !isStatic && propAtom == context->names().constructor; + if (isConstructor) { if (propType != PropertyType::Method) { errorAt(nameOffset, JSMSG_BAD_METHOD_DEF); return null(); } - if (seenConstructor) { + if (classStmt.constructorBox()) { errorAt(nameOffset, JSMSG_DUPLICATE_PROPERTY, "constructor"); return null(); } - seenConstructor = true; propType = hasHeritage ? PropertyType::DerivedConstructor : PropertyType::Constructor; } else if (isStatic && propAtom == context->names().prototype) { errorAt(nameOffset, JSMSG_BAD_METHOD_DEF); @@ -7082,7 +7106,12 @@ Parser::classDefinition(YieldHandling yieldHandling, if (!tokenStream.isCurrentTokenType(TOK_RB)) funName = propAtom; } - Node fn = methodDefinition(nameOffset, propType, funName); + + // Calling toString on constructors need to return the source text for + // the entire class. The end offset is unknown at this point in + // parsing and will be amended when class parsing finishes below. + Node fn = methodDefinition(isConstructor ? classStartOffset : nameOffset, + propType, funName); if (!fn) return null(); @@ -7093,6 +7122,15 @@ Parser::classDefinition(YieldHandling yieldHandling, return null(); } + // Amend the postlude offset for the constructor now that we've finished + // parsing the class. + uint32_t classEndOffset = pos().end; + if (FunctionBox* ctorbox = classStmt.constructorBox()) { + if (ctorbox->function()->isInterpretedLazy()) + ctorbox->function()->lazyScript()->setPostludeEnd(classEndOffset); + ctorbox->postludeEnd = classEndOffset; + } + Node nameNode = null(); Node methodsOrBlock = classMethods; if (name) { @@ -7104,15 +7142,15 @@ Parser::classDefinition(YieldHandling yieldHandling, if (!innerName) return null(); - Node classBlock = finishLexicalScope(*classScope, classMethods); + Node classBlock = finishLexicalScope(*innerScope, classMethods); if (!classBlock) return null(); methodsOrBlock = classBlock; // Pop the inner scope. - classScope.reset(); - classStmt.reset(); + innerScope.reset(); + innerScopeStmt.reset(); Node outerName = null(); if (classContext == ClassStatement) { @@ -7132,7 +7170,8 @@ Parser::classDefinition(YieldHandling yieldHandling, MOZ_ALWAYS_TRUE(setLocalStrictMode(savedStrictness)); - return handler.newClass(nameNode, classHeritage, methodsOrBlock); + return handler.newClass(nameNode, classHeritage, methodsOrBlock, + TokenPos(classStartOffset, classEndOffset)); } template @@ -8388,7 +8427,7 @@ Parser::generatorComprehensionLambda(unsigned begin) uint32_t end = pos().end; handler.setBeginPosition(comp, begin); handler.setEndPosition(comp, end); - genFunbox->bufEnd = end; + genFunbox->setEnd(end); handler.addStatementToList(body, comp); handler.setEndPosition(body, end); handler.setBeginPosition(genfn, begin); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 6b5ade425..efb543efa 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -85,6 +85,31 @@ class ParseContext : public Nestable } }; + class ClassStatement : public Statement + { + FunctionBox* constructorBox_; + + public: + explicit ClassStatement(ParseContext* pc) + : Statement(pc, StatementKind::Class), + constructorBox_(nullptr) + { } + + void clearConstructorBoxForAbortedSyntaxParse(FunctionBox* funbox) { + MOZ_ASSERT(constructorBox_ == funbox); + constructorBox_ = nullptr; + } + + void setConstructorBox(FunctionBox* funbox) { + MOZ_ASSERT(!constructorBox_); + constructorBox_ = funbox; + } + + FunctionBox* constructorBox() const { + return constructorBox_; + } + }; + // The intra-function scope stack. // // Tracks declared and used names within a scope. @@ -432,6 +457,11 @@ class ParseContext : public Nestable return Statement::findNearest(innermostStatement_, predicate); } + template + T* findInnermostStatement() { + return Statement::findNearest(innermostStatement_); + } + AtomVector& positionalFormalParameterNames() { return *positionalFormalParameterNames_; } @@ -532,6 +562,13 @@ ParseContext::Statement::is() const return kind_ == StatementKind::Label; } +template <> +inline bool +ParseContext::Statement::is() const +{ + return kind_ == StatementKind::Class; +} + template inline T& ParseContext::Statement::as() diff --git a/js/src/frontend/SharedContext.h b/js/src/frontend/SharedContext.h index f5a74e18c..213a0a461 100644 --- a/js/src/frontend/SharedContext.h +++ b/js/src/frontend/SharedContext.h @@ -38,6 +38,7 @@ enum class StatementKind : uint8_t ForOfLoop, DoLoop, WhileLoop, + Class, // Used only by BytecodeEmitter. Spread @@ -451,6 +452,7 @@ class FunctionBox : public ObjectBox, public SharedContext uint32_t startLine; uint32_t startColumn; uint32_t preludeStart; + uint32_t postludeEnd; uint16_t length; uint8_t generatorKindBits_; /* The GeneratorKind of this function. */ @@ -501,6 +503,7 @@ class FunctionBox : public ObjectBox, public SharedContext void initFromLazyFunction(); void initStandaloneFunction(Scope* enclosingScope); void initWithEnclosingParseContext(ParseContext* enclosing, FunctionSyntaxKind kind); + void resetForAbortedSyntaxParse(ParseContext* enclosing, FunctionSyntaxKind kind); ObjectBox* toObjectBox() override { return this; } JSFunction* function() const { return &object->as(); } @@ -603,6 +606,14 @@ class FunctionBox : public ObjectBox, public SharedContext tokenStream.srcCoords.lineNumAndColumnIndex(bufStart, &startLine, &startColumn); } + void setEnd(uint32_t end) { + // For all functions except class constructors, the buffer and + // postlude ending positions are the same. Class constructors override + // the postlude ending position with the end of the class definition. + bufEnd = end; + postludeEnd = end; + } + void trace(JSTracer* trc) override; }; diff --git a/js/src/frontend/SourceNotes.h b/js/src/frontend/SourceNotes.h index dd2a95ad1..6ae184ae4 100644 --- a/js/src/frontend/SourceNotes.h +++ b/js/src/frontend/SourceNotes.h @@ -56,13 +56,14 @@ namespace js { M(SRC_NEXTCASE, "nextcase", 1) /* Distance forward from one CASE in a CONDSWITCH to \ the next. */ \ M(SRC_ASSIGNOP, "assignop", 0) /* += or another assign-op follows. */ \ + M(SRC_CLASS_SPAN, "class", 2) /* The starting and ending offsets for the class, used \ + for toString correctness for default ctors. */ \ M(SRC_TRY, "try", 1) /* JSOP_TRY, offset points to goto at the end of the \ try block. */ \ /* All notes above here are "gettable". See SN_IS_GETTABLE below. */ \ M(SRC_COLSPAN, "colspan", 1) /* Number of columns this opcode spans. */ \ M(SRC_NEWLINE, "newline", 0) /* Bytecode follows a source newline. */ \ M(SRC_SETLINE, "setline", 1) /* A file-absolute source line number note. */ \ - M(SRC_UNUSED20, "unused20", 0) /* Unused. */ \ M(SRC_UNUSED21, "unused21", 0) /* Unused. */ \ M(SRC_UNUSED22, "unused22", 0) /* Unused. */ \ M(SRC_UNUSED23, "unused23", 0) /* Unused. */ \ diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index f492bab66..895ba6416 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -289,7 +289,7 @@ class SyntaxParseHandler Node newObjectLiteral(uint32_t begin) { return NodeUnparenthesizedObject; } Node newClassMethodList(uint32_t begin) { return NodeGeneric; } Node newClassNames(Node outer, Node inner, const TokenPos& pos) { return NodeGeneric; } - Node newClass(Node name, Node heritage, Node methodBlock) { return NodeGeneric; } + Node newClass(Node name, Node heritage, Node methodBlock, const TokenPos& pos) { return NodeGeneric; } Node newNewTarget(Node newHolder, Node targetHolder) { return NodeGeneric; } Node newPosHolder(const TokenPos& pos) { return NodeGeneric; } diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 470746d50..4f15e78c2 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -821,7 +821,7 @@ CreateFunctionPrototype(JSContext* cx, JSProtoKey key) sourceObject, begin, ss->length(), - 0)); + 0, 0)); if (!script || !JSScript::initFunctionPrototype(cx, script, functionProto)) return nullptr; @@ -954,7 +954,13 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint) } bool funIsNonArrowLambda = fun->isLambda() && !fun->isArrow(); - bool haveSource = fun->isInterpreted() && !fun->isSelfHostedBuiltin(); + + // Default class constructors are self-hosted, but have their source + // objects overridden to refer to the span of the class statement or + // expression. Non-default class constructors are never self-hosted. So, + // all class constructors always have source. + bool haveSource = fun->isInterpreted() && (fun->isClassConstructor() || + !fun->isSelfHostedBuiltin()); // If we're not in pretty mode, put parentheses around lambda functions // so that eval returns lambda, not function statement. @@ -995,7 +1001,7 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint) }; if (haveSource) { - Rooted src(cx, JSScript::sourceDataWithPrelude(cx, script)); + Rooted src(cx, JSScript::sourceDataForToString(cx, script)); if (!src) return nullptr; @@ -1015,27 +1021,18 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint) return nullptr; } } else { - bool derived = fun->infallibleIsDefaultClassConstructor(cx); - if (derived && fun->isDerivedClassConstructor()) { - if (!AppendPrelude() || - !out.append("(...args) {\n ") || - !out.append("super(...args);\n}")) - { - return nullptr; - } - } else { - if (!AppendPrelude() || - !out.append("() {\n ")) - return nullptr; + // Default class constructors should always haveSource. + MOZ_ASSERT(!fun->infallibleIsDefaultClassConstructor(cx)); - if (!derived) { - if (!out.append("[native code]")) - return nullptr; - } + if (!AppendPrelude() || + !out.append("() {\n ")) + return nullptr; - if (!out.append("\n}")) - return nullptr; - } + if (!out.append("[native code]")) + return nullptr; + + if (!out.append("\n}")) + return nullptr; } return out.finishString(); } diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index ddc98ef3f..ad4cb2338 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -236,6 +236,7 @@ XDRRelazificationInfo(XDRState* xdr, HandleFunction fun, HandleScript scri uint32_t begin = script->sourceStart(); uint32_t end = script->sourceEnd(); uint32_t preludeStart = script->preludeStart(); + uint32_t postludeEnd = script->postludeEnd(); uint32_t lineno = script->lineno(); uint32_t column = script->column(); @@ -244,6 +245,7 @@ XDRRelazificationInfo(XDRState* xdr, HandleFunction fun, HandleScript scri MOZ_ASSERT(begin == lazy->begin()); MOZ_ASSERT(end == lazy->end()); MOZ_ASSERT(preludeStart == lazy->preludeStart()); + MOZ_ASSERT(postludeEnd == lazy->postludeEnd()); MOZ_ASSERT(lineno == lazy->lineno()); MOZ_ASSERT(column == lazy->column()); // We can assert we have no inner functions because we don't @@ -259,6 +261,11 @@ XDRRelazificationInfo(XDRState* xdr, HandleFunction fun, HandleScript scri lazy.set(LazyScript::Create(cx, fun, script, enclosingScope, script, packedFields, begin, end, preludeStart, lineno, column)); + if (!lazy) + return false; + + lazy->setPostludeEnd(postludeEnd); + // As opposed to XDRLazyScript, we need to restore the runtime bits // of the script, as we are trying to match the fact this function // has already been parsed and that it would need to be re-lazified. @@ -522,7 +529,7 @@ js::XDRScript(XDRState* xdr, HandleScope scriptEnclosingScope, HandleScrip sourceObject = &enclosingScript->sourceObject()->as(); } - script = JSScript::Create(cx, options, sourceObject, 0, 0, 0); + script = JSScript::Create(cx, options, sourceObject, 0, 0, 0, 0); if (!script) return false; @@ -609,6 +616,8 @@ js::XDRScript(XDRState* xdr, HandleScope scriptEnclosingScope, HandleScrip return false; if (!xdr->codeUint32(&script->preludeStart_)) return false; + if (!xdr->codeUint32(&script->postludeEnd_)) + return false; if (!xdr->codeUint32(&lineno) || !xdr->codeUint32(&column) || @@ -940,6 +949,7 @@ js::XDRLazyScript(XDRState* xdr, HandleScope enclosingScope, HandleScript uint32_t begin; uint32_t end; uint32_t preludeStart; + uint32_t postludeEnd; uint32_t lineno; uint32_t column; uint64_t packedFields; @@ -954,6 +964,7 @@ js::XDRLazyScript(XDRState* xdr, HandleScope enclosingScope, HandleScript begin = lazy->begin(); end = lazy->end(); preludeStart = lazy->preludeStart(); + postludeEnd = lazy->postludeEnd(); lineno = lazy->lineno(); column = lazy->column(); packedFields = lazy->packedFields(); @@ -961,6 +972,7 @@ js::XDRLazyScript(XDRState* xdr, HandleScope enclosingScope, HandleScript if (!xdr->codeUint32(&begin) || !xdr->codeUint32(&end) || !xdr->codeUint32(&preludeStart) || + !xdr->codeUint32(&postludeEnd) || !xdr->codeUint32(&lineno) || !xdr->codeUint32(&column) || !xdr->codeUint64(&packedFields)) { @@ -972,6 +984,7 @@ js::XDRLazyScript(XDRState* xdr, HandleScope enclosingScope, HandleScript packedFields, begin, end, preludeStart, lineno, column)); if (!lazy) return false; + lazy->setPostludeEnd(postludeEnd); fun->initLazyScript(lazy); } } @@ -1015,6 +1028,15 @@ JSScript::setSourceObject(JSObject* object) sourceObject_ = object; } +void +JSScript::setDefaultClassConstructorSpan(JSObject* sourceObject, uint32_t start, uint32_t end) +{ + MOZ_ASSERT(isDefaultClassConstructor()); + setSourceObject(sourceObject); + preludeStart_ = start; + postludeEnd_ = end; +} + js::ScriptSourceObject& JSScript::scriptSourceUnwrap() const { return UncheckedUnwrap(sourceObject())->as(); @@ -1443,10 +1465,10 @@ JSScript::sourceData(JSContext* cx, HandleScript script) } /* static */ JSFlatString* -JSScript::sourceDataWithPrelude(JSContext* cx, HandleScript script) +JSScript::sourceDataForToString(JSContext* cx, HandleScript script) { MOZ_ASSERT(script->scriptSource()->hasSourceData()); - return script->scriptSource()->substring(cx, script->preludeStart(), script->sourceEnd()); + return script->scriptSource()->substring(cx, script->preludeStart(), script->postludeEnd()); } UncompressedSourceCache::AutoHoldEntry::AutoHoldEntry() @@ -2448,7 +2470,7 @@ JSScript::initCompartment(ExclusiveContext* cx) /* static */ JSScript* JSScript::Create(ExclusiveContext* cx, const ReadOnlyCompileOptions& options, HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd, - uint32_t preludeStart) + uint32_t preludeStart, uint32_t postludeEnd) { MOZ_ASSERT(bufStart <= bufEnd); @@ -2471,6 +2493,7 @@ JSScript::Create(ExclusiveContext* cx, const ReadOnlyCompileOptions& options, script->sourceStart_ = bufStart; script->sourceEnd_ = bufEnd; script->preludeStart_ = preludeStart; + script->postludeEnd_ = postludeEnd; return script; } @@ -3407,7 +3430,7 @@ CreateEmptyScriptForClone(JSContext* cx, HandleScript src) .setVersion(src->getVersion()); return JSScript::Create(cx, options, sourceObject, src->sourceStart(), src->sourceEnd(), - src->preludeStart()); + src->preludeStart(), src->postludeEnd()); } JSScript* @@ -3968,6 +3991,7 @@ LazyScript::LazyScript(JSFunction* fun, void* table, uint64_t packedFields, begin_(begin), end_(end), preludeStart_(preludeStart), + postludeEnd_(end), lineno_(lineno), column_(column) { diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 62502a3c7..8a21d394a 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -863,9 +863,19 @@ class JSScript : public js::gc::TenuredCell // | // preludeStart_ // + // And, in the case of class constructors, an additional postlude offset + // is used for use with toString. + // + // class C { constructor() { this.field = 42; } } + // ^ ^ ^ ^ + // | | | `---------` + // | sourceStart_ sourceEnd_ | + // | | + // preludeStart_ postludeEnd_ uint32_t sourceStart_; uint32_t sourceEnd_; uint32_t preludeStart_; + uint32_t postludeEnd_; // Number of times the script has been called or has had backedges taken. // When running in ion, also increased for any inlined scripts. Reset if @@ -1027,7 +1037,7 @@ class JSScript : public js::gc::TenuredCell // instead of private to suppress -Wunused-private-field compiler warnings. protected: #if JS_BITS_PER_WORD == 32 - uint32_t padding; + // Currently no padding is needed. #endif // @@ -1037,8 +1047,9 @@ class JSScript : public js::gc::TenuredCell public: static JSScript* Create(js::ExclusiveContext* cx, const JS::ReadOnlyCompileOptions& options, - js::HandleObject sourceObject, uint32_t sourceStart, - uint32_t sourceEnd, uint32_t preludeStart); + js::HandleObject sourceObject, + uint32_t sourceStart, uint32_t sourceEnd, + uint32_t preludeStart, uint32_t postludeEnd); void initCompartment(js::ExclusiveContext* cx); @@ -1185,10 +1196,14 @@ class JSScript : public js::gc::TenuredCell return sourceEnd_; } - size_t preludeStart() const { + uint32_t preludeStart() const { return preludeStart_; } + uint32_t postludeEnd() const { + return postludeEnd_; + } + bool noScriptRval() const { return noScriptRval_; } @@ -1519,7 +1534,7 @@ class JSScript : public js::gc::TenuredCell bool mayReadFrameArgsDirectly(); static JSFlatString* sourceData(JSContext* cx, JS::HandleScript script); - static JSFlatString* sourceDataWithPrelude(JSContext* cx, JS::HandleScript script); + static JSFlatString* sourceDataForToString(JSContext* cx, JS::HandleScript script); static bool loadSource(JSContext* cx, js::ScriptSource* ss, bool* worked); @@ -1534,6 +1549,8 @@ class JSScript : public js::gc::TenuredCell const char* filename() const { return scriptSource()->filename(); } const char* maybeForwardedFilename() const { return maybeForwardedScriptSource()->filename(); } + void setDefaultClassConstructorSpan(JSObject* sourceObject, uint32_t start, uint32_t end); + public: /* Return whether this script was compiled for 'eval' */ @@ -1939,8 +1956,7 @@ class LazyScript : public gc::TenuredCell // instead of private to suppress -Wunused-private-field compiler warnings. protected: #if JS_BITS_PER_WORD == 32 - // uint32_t padding; - // Currently no padding is needed. + uint32_t padding; #endif private: @@ -1989,6 +2005,7 @@ class LazyScript : public gc::TenuredCell uint32_t begin_; uint32_t end_; uint32_t preludeStart_; + uint32_t postludeEnd_; // Line and column of |begin_| position, that is the position where we // start parsing. uint32_t lineno_; @@ -2213,6 +2230,9 @@ class LazyScript : public gc::TenuredCell uint32_t preludeStart() const { return preludeStart_; } + uint32_t postludeEnd() const { + return postludeEnd_; + } uint32_t lineno() const { return lineno_; } @@ -2220,6 +2240,11 @@ class LazyScript : public gc::TenuredCell return column_; } + void setPostludeEnd(uint32_t postludeEnd) { + MOZ_ASSERT(postludeEnd_ >= end_); + postludeEnd_ = postludeEnd; + } + bool hasUncompiledEnclosingScript() const; friend class GCMarker; diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 1e2435955..51cd11fe8 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -2550,6 +2550,14 @@ SrcNotes(JSContext* cx, HandleScript script, Sprinter* sp) return false; break; + case SRC_CLASS_SPAN: { + unsigned startOffset = GetSrcNoteOffset(sn, 0); + unsigned endOffset = GetSrcNoteOffset(sn, 1); + if (!sp->jsprintf(" %u %u", startOffset, endOffset)) + return false; + break; + } + default: MOZ_ASSERT_UNREACHABLE("unrecognized srcnote"); } diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 23a1ad2a5..ad9e87a50 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -261,11 +261,16 @@ SetPropertyOperation(JSContext* cx, JSOp op, HandleValue lval, HandleId id, Hand } static JSFunction* -MakeDefaultConstructor(JSContext* cx, JSOp op, JSAtom* atom, HandleObject proto) +MakeDefaultConstructor(JSContext* cx, HandleScript script, jsbytecode* pc, HandleObject proto) { + JSOp op = JSOp(*pc); + JSAtom* atom = script->getAtom(pc); bool derived = op == JSOP_DERIVEDCONSTRUCTOR; MOZ_ASSERT(derived == !!proto); + jssrcnote* classNote = GetSrcNote(cx, script, pc); + MOZ_ASSERT(classNote && SN_TYPE(classNote) == SRC_CLASS_SPAN); + PropertyName* lookup = derived ? cx->names().DefaultDerivedClassConstructor : cx->names().DefaultBaseClassConstructor; @@ -285,6 +290,17 @@ MakeDefaultConstructor(JSContext* cx, JSOp op, JSAtom* atom, HandleObject proto) MOZ_ASSERT(ctor->infallibleIsDefaultClassConstructor(cx)); + // Create the script now, as the source span needs to be overridden for + // toString. Calling toString on a class constructor must not return the + // source for just the constructor function. + JSScript *ctorScript = JSFunction::getOrCreateScript(cx, ctor); + if (!ctorScript) + return nullptr; + uint32_t classStartOffset = GetSrcNoteOffset(classNote, 0); + uint32_t classEndOffset = GetSrcNoteOffset(classNote, 1); + ctorScript->setDefaultClassConstructorSpan(script->sourceObject(), classStartOffset, + classEndOffset); + return ctor; } @@ -4174,8 +4190,8 @@ CASE(JSOP_DERIVEDCONSTRUCTOR) MOZ_ASSERT(REGS.sp[-1].isObject()); ReservedRooted proto(&rootObject0, ®S.sp[-1].toObject()); - JSFunction* constructor = MakeDefaultConstructor(cx, JSOp(*REGS.pc), script->getAtom(REGS.pc), - proto); + JSFunction* constructor = MakeDefaultConstructor(cx, script, REGS.pc, proto); + if (!constructor) goto error; @@ -4185,8 +4201,7 @@ END_CASE(JSOP_DERIVEDCONSTRUCTOR) CASE(JSOP_CLASSCONSTRUCTOR) { - JSFunction* constructor = MakeDefaultConstructor(cx, JSOp(*REGS.pc), script->getAtom(REGS.pc), - nullptr); + JSFunction* constructor = MakeDefaultConstructor(cx, script, REGS.pc, nullptr); if (!constructor) goto error; PUSH_OBJECT(*constructor); -- cgit v1.2.3 From 22dba02b7bcab4d6dfe6b326ecc0a746e5a87191 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 13 Jul 2019 23:02:36 -0400 Subject: 1216630 - Rename preludeStart and postludeEnd to toStringStart and toStringEnd and misc fixes. --- js/src/frontend/BytecodeCompiler.cpp | 14 ++++-- js/src/frontend/BytecodeEmitter.cpp | 4 +- js/src/frontend/Parser.cpp | 82 ++++++++++++++++++------------------ js/src/frontend/Parser.h | 18 ++++---- js/src/frontend/SharedContext.h | 12 +++--- js/src/jsfun.cpp | 3 +- js/src/jsscript.cpp | 71 +++++++++++++++++-------------- js/src/jsscript.h | 62 +++++++++++++++------------ js/src/wasm/AsmJS.cpp | 14 +++--- 9 files changed, 151 insertions(+), 129 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index e0bb64e05..a1abbfeda 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -248,11 +248,17 @@ BytecodeCompiler::createSourceAndParser(Maybe parameterListEnd /* = No } bool -BytecodeCompiler::createScript(uint32_t preludeStart /* = 0 */, uint32_t postludeEnd /* = 0 */) +BytecodeCompiler::createScript() +{ + return createScript(0, sourceBuffer.length()); +} + +bool +BytecodeCompiler::createScript(uint32_t toStringStart, uint32_t toStringEnd) { script = JSScript::Create(cx, options, sourceObject, /* sourceStart = */ 0, sourceBuffer.length(), - preludeStart, postludeEnd); + toStringStart, toStringEnd); return script != nullptr; } @@ -464,7 +470,7 @@ BytecodeCompiler::compileStandaloneFunction(MutableHandleFunction fun, if (fn->pn_funbox->function()->isInterpreted()) { MOZ_ASSERT(fun == fn->pn_funbox->function()); - if (!createScript(fn->pn_funbox->preludeStart, fn->pn_funbox->postludeEnd)) + if (!createScript(fn->pn_funbox->toStringStart, fn->pn_funbox->toStringEnd)) return false; Maybe emitter; @@ -659,7 +665,7 @@ frontend::CompileLazyFunction(JSContext* cx, Handle lazy, const cha Rooted script(cx, JSScript::Create(cx, options, sourceObject, lazy->begin(), lazy->end(), - lazy->preludeStart(), lazy->postludeEnd())); + lazy->toStringStart(), lazy->toStringEnd())); if (!script) return false; diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index c788e0086..7582e8df1 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -7846,8 +7846,8 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto) Rooted sourceObject(cx, script->sourceObject()); Rooted script(cx, JSScript::Create(cx, options, sourceObject, funbox->bufStart, funbox->bufEnd, - funbox->preludeStart, - funbox->postludeEnd)); + funbox->toStringStart, + funbox->toStringEnd)); if (!script) return false; diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 299b8b93a..1be57f8f5 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -458,7 +458,7 @@ UsedNameTracker::rewind(RewindToken token) } FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead, - JSFunction* fun, uint32_t preludeStart, + JSFunction* fun, uint32_t toStringStart, Directives directives, bool extraWarnings, GeneratorKind generatorKind, FunctionAsyncKind asyncKind) : ObjectBox(fun, traceListHead), @@ -472,8 +472,8 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* trac bufEnd(0), startLine(1), startColumn(0), - preludeStart(preludeStart), - postludeEnd(0), + toStringStart(toStringStart), + toStringEnd(0), length(0), generatorKindBits_(GeneratorKindAsBits(generatorKind)), asyncKindBits_(AsyncKindAsBits(asyncKind)), @@ -888,7 +888,7 @@ Parser::newObjectBox(JSObject* obj) template FunctionBox* -Parser::newFunctionBox(Node fn, JSFunction* fun, uint32_t preludeStart, +Parser::newFunctionBox(Node fn, JSFunction* fun, uint32_t toStringStart, Directives inheritedDirectives, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB) @@ -904,7 +904,7 @@ Parser::newFunctionBox(Node fn, JSFunction* fun, uint32_t preludeS * function. */ FunctionBox* funbox = - alloc.new_(context, alloc, traceListHead, fun, preludeStart, + alloc.new_(context, alloc, traceListHead, fun, toStringStart, inheritedDirectives, options().extraWarningsOption, generatorKind, asyncKind); if (!funbox) { @@ -2404,7 +2404,7 @@ Parser::finishFunction(bool isStandaloneFunction /* = false LazyScript* lazy = LazyScript::Create(context, fun, pc->closedOverBindingsForLazy(), pc->innerFunctionsForLazy, versionNumber(), funbox->bufStart, funbox->bufEnd, - funbox->preludeStart, + funbox->toStringStart, funbox->startLine, funbox->startColumn); if (!lazy) return false; @@ -2495,7 +2495,7 @@ Parser::standaloneFunction(HandleFunction fun, return null(); fn->pn_body = argsbody; - FunctionBox* funbox = newFunctionBox(fn, fun, /* preludeStart = */ 0, inheritedDirectives, + FunctionBox* funbox = newFunctionBox(fn, fun, /* toStringStart = */ 0, inheritedDirectives, generatorKind, asyncKind, /* tryAnnexB = */ false); if (!funbox) return null(); @@ -3158,7 +3158,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn template <> bool -Parser::skipLazyInnerFunction(ParseNode* pn, uint32_t preludeStart, +Parser::skipLazyInnerFunction(ParseNode* pn, uint32_t toStringStart, FunctionSyntaxKind kind, bool tryAnnexB) { // When a lazily-parsed function is called, we only fully parse (and emit) @@ -3168,7 +3168,7 @@ Parser::skipLazyInnerFunction(ParseNode* pn, uint32_t preludeS RootedFunction fun(context, handler.nextLazyInnerFunction()); MOZ_ASSERT(!fun->isLegacyGenerator()); - FunctionBox* funbox = newFunctionBox(pn, fun, preludeStart, Directives(/* strict = */ false), + FunctionBox* funbox = newFunctionBox(pn, fun, toStringStart, Directives(/* strict = */ false), fun->generatorKind(), fun->asyncKind(), tryAnnexB); if (!funbox) return false; @@ -3205,7 +3205,7 @@ Parser::skipLazyInnerFunction(ParseNode* pn, uint32_t preludeS template <> bool -Parser::skipLazyInnerFunction(Node pn, uint32_t preludeStart, +Parser::skipLazyInnerFunction(Node pn, uint32_t toStringStart, FunctionSyntaxKind kind, bool tryAnnexB) { MOZ_CRASH("Cannot skip lazy inner functions when syntax parsing"); @@ -3282,7 +3282,7 @@ Parser::templateLiteral(YieldHandling yieldHandling) template typename ParseHandler::Node -Parser::functionDefinition(uint32_t preludeStart, Node pn, InHandling inHandling, +Parser::functionDefinition(uint32_t toStringStart, Node pn, InHandling inHandling, YieldHandling yieldHandling, HandleAtom funName, FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, @@ -3295,7 +3295,7 @@ Parser::functionDefinition(uint32_t preludeStart, Node pn, InHandl // functions, which are also lazy. Instead, their free variables and // source extents are recorded and may be skipped. if (handler.canSkipLazyInnerFunctions()) { - if (!skipLazyInnerFunction(pn, preludeStart, kind, tryAnnexB)) + if (!skipLazyInnerFunction(pn, toStringStart, kind, tryAnnexB)) return null(); return pn; } @@ -3328,7 +3328,7 @@ Parser::functionDefinition(uint32_t preludeStart, Node pn, InHandl // reparse a function due to failed syntax parsing and encountering new // "use foo" directives. while (true) { - if (trySyntaxParseInnerFunction(pn, fun, preludeStart, inHandling, yieldHandling, kind, + if (trySyntaxParseInnerFunction(pn, fun, toStringStart, inHandling, yieldHandling, kind, generatorKind, asyncKind, tryAnnexB, directives, &newDirectives)) { @@ -3357,7 +3357,7 @@ Parser::functionDefinition(uint32_t preludeStart, Node pn, InHandl template <> bool Parser::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunction fun, - uint32_t preludeStart, + uint32_t toStringStart, InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind, @@ -3391,13 +3391,13 @@ Parser::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunct // Make a FunctionBox before we enter the syntax parser, because |pn| // still expects a FunctionBox to be attached to it during BCE, and // the syntax parser cannot attach one to it. - FunctionBox* funbox = newFunctionBox(pn, fun, preludeStart, inheritedDirectives, + FunctionBox* funbox = newFunctionBox(pn, fun, toStringStart, inheritedDirectives, generatorKind, asyncKind, tryAnnexB); if (!funbox) return false; funbox->initWithEnclosingParseContext(pc, kind); - if (!parser->innerFunction(SyntaxParseHandler::NodeGeneric, pc, funbox, preludeStart, + if (!parser->innerFunction(SyntaxParseHandler::NodeGeneric, pc, funbox, toStringStart, inHandling, yieldHandling, kind, inheritedDirectives, newDirectives)) { @@ -3426,14 +3426,14 @@ Parser::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunct } while (false); // We failed to do a syntax parse above, so do the full parse. - return innerFunction(pn, pc, fun, preludeStart, inHandling, yieldHandling, kind, + return innerFunction(pn, pc, fun, toStringStart, inHandling, yieldHandling, kind, generatorKind, asyncKind, tryAnnexB, inheritedDirectives, newDirectives); } template <> bool Parser::trySyntaxParseInnerFunction(Node pn, HandleFunction fun, - uint32_t preludeStart, + uint32_t toStringStart, InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind, @@ -3444,14 +3444,14 @@ Parser::trySyntaxParseInnerFunction(Node pn, HandleFunction Directives* newDirectives) { // This is already a syntax parser, so just parse the inner function. - return innerFunction(pn, pc, fun, preludeStart, inHandling, yieldHandling, kind, + return innerFunction(pn, pc, fun, toStringStart, inHandling, yieldHandling, kind, generatorKind, asyncKind, tryAnnexB, inheritedDirectives, newDirectives); } template bool Parser::innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox, - uint32_t preludeStart, + uint32_t toStringStart, InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind, Directives inheritedDirectives, Directives* newDirectives) @@ -3475,7 +3475,7 @@ Parser::innerFunction(Node pn, ParseContext* outerpc, FunctionBox* template bool Parser::innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun, - uint32_t preludeStart, + uint32_t toStringStart, InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, @@ -3487,13 +3487,13 @@ Parser::innerFunction(Node pn, ParseContext* outerpc, HandleFuncti // parser. In that case, outerpc is a ParseContext from the full parser // instead of the current top of the stack of the syntax parser. - FunctionBox* funbox = newFunctionBox(pn, fun, preludeStart, inheritedDirectives, + FunctionBox* funbox = newFunctionBox(pn, fun, toStringStart, inheritedDirectives, generatorKind, asyncKind, tryAnnexB); if (!funbox) return false; funbox->initWithEnclosingParseContext(outerpc, kind); - return innerFunction(pn, outerpc, funbox, preludeStart, inHandling, yieldHandling, kind, + return innerFunction(pn, outerpc, funbox, toStringStart, inHandling, yieldHandling, kind, inheritedDirectives, newDirectives); } @@ -3529,7 +3529,7 @@ Parser::standaloneLazyFunction(HandleFunction fun, bool strict return null(); Directives directives(strict); - FunctionBox* funbox = newFunctionBox(pn, fun, /* preludeStart = */ 0, directives, + FunctionBox* funbox = newFunctionBox(pn, fun, /* toStringStart = */ 0, directives, generatorKind, asyncKind, /* tryAnnexB = */ false); if (!funbox) return null(); @@ -3716,7 +3716,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, template typename ParseHandler::Node -Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHandling, +Parser::functionStmt(uint32_t toStringStart, YieldHandling yieldHandling, DefaultHandling defaultHandling, FunctionAsyncKind asyncKind) { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION)); @@ -3800,13 +3800,13 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan return null(); YieldHandling newYieldHandling = GetYieldHandling(generatorKind, asyncKind); - return functionDefinition(preludeStart, pn, InAllowed, newYieldHandling, + return functionDefinition(toStringStart, pn, InAllowed, newYieldHandling, name, Statement, generatorKind, asyncKind, tryAnnexB); } template typename ParseHandler::Node -Parser::functionExpr(uint32_t preludeStart, InvokedPrediction invoked, +Parser::functionExpr(uint32_t toStringStart, InvokedPrediction invoked, FunctionAsyncKind asyncKind) { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION)); @@ -3845,7 +3845,7 @@ Parser::functionExpr(uint32_t preludeStart, InvokedPrediction invo if (invoked) pn = handler.setLikelyIIFE(pn); - return functionDefinition(preludeStart, pn, InAllowed, yieldHandling, name, Expression, + return functionDefinition(toStringStart, pn, InAllowed, yieldHandling, name, Expression, generatorKind, asyncKind); } @@ -7122,13 +7122,13 @@ Parser::classDefinition(YieldHandling yieldHandling, return null(); } - // Amend the postlude offset for the constructor now that we've finished - // parsing the class. + // Amend the toStringEnd offset for the constructor now that we've + // finished parsing the class. uint32_t classEndOffset = pos().end; if (FunctionBox* ctorbox = classStmt.constructorBox()) { if (ctorbox->function()->isInterpretedLazy()) - ctorbox->function()->lazyScript()->setPostludeEnd(classEndOffset); - ctorbox->postludeEnd = classEndOffset; + ctorbox->function()->lazyScript()->setToStringEnd(classEndOffset); + ctorbox->toStringEnd = classEndOffset; } Node nameNode = null(); @@ -7507,9 +7507,9 @@ Parser::statementListItem(YieldHandling yieldHandling, if (!tokenStream.peekTokenSameLine(&nextSameLine)) return null(); if (nextSameLine == TOK_FUNCTION) { - uint32_t preludeStart = pos().begin; + uint32_t toStringStart = pos().begin; tokenStream.consumeKnownToken(TOK_FUNCTION); - return functionStmt(preludeStart, yieldHandling, NameRequired, AsyncFunction); + return functionStmt(toStringStart, yieldHandling, NameRequired, AsyncFunction); } } @@ -8053,7 +8053,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl if (!tokenStream.getToken(&next, TokenStream::Operand)) return null(); - uint32_t preludeStart = pos().begin; + uint32_t toStringStart = pos().begin; tokenStream.ungetToken(); GeneratorKind generatorKind = NotGenerator; @@ -8078,7 +8078,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl if (!pn) return null(); - Node arrowFunc = functionDefinition(preludeStart, pn, inHandling, yieldHandling, nullptr, + Node arrowFunc = functionDefinition(toStringStart, pn, inHandling, yieldHandling, nullptr, Arrow, generatorKind, asyncKind); if (!arrowFunc) return null(); @@ -8391,7 +8391,7 @@ Parser::generatorComprehensionLambda(unsigned begin) // Create box for fun->object early to root it. Directives directives(/* strict = */ outerpc->sc()->strict()); - FunctionBox* genFunbox = newFunctionBox(genfn, fun, /* preludeStart = */ 0, directives, + FunctionBox* genFunbox = newFunctionBox(genfn, fun, /* toStringStart = */ 0, directives, StarGenerator, SyncFunction, /* tryAnnexB = */ false); if (!genFunbox) return null(); @@ -9662,7 +9662,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* template typename ParseHandler::Node -Parser::methodDefinition(uint32_t preludeStart, PropertyType propType, +Parser::methodDefinition(uint32_t toStringStart, PropertyType propType, HandleAtom funName) { FunctionSyntaxKind kind; @@ -9716,7 +9716,7 @@ Parser::methodDefinition(uint32_t preludeStart, PropertyType propT if (!pn) return null(); - return functionDefinition(preludeStart, pn, InAllowed, yieldHandling, funName, + return functionDefinition(toStringStart, pn, InAllowed, yieldHandling, funName, kind, generatorKind, asyncKind); } @@ -9845,9 +9845,9 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling return null(); if (nextSameLine == TOK_FUNCTION) { - uint32_t preludeStart = pos().begin; + uint32_t toStringStart = pos().begin; tokenStream.consumeKnownToken(TOK_FUNCTION); - return functionExpr(preludeStart, PredictUninvoked, AsyncFunction); + return functionExpr(toStringStart, PredictUninvoked, AsyncFunction); } } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index efb543efa..65e46a65e 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1081,7 +1081,7 @@ class Parser final : public ParserBase, private JS::AutoGCRooter * cx->tempLifoAlloc. */ ObjectBox* newObjectBox(JSObject* obj); - FunctionBox* newFunctionBox(Node fn, JSFunction* fun, uint32_t preludeStart, + FunctionBox* newFunctionBox(Node fn, JSFunction* fun, uint32_t toStringStart, Directives directives, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB); @@ -1152,7 +1152,7 @@ class Parser final : public ParserBase, private JS::AutoGCRooter // Parse an inner function given an enclosing ParseContext and a // FunctionBox for the inner function. - bool innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox, uint32_t preludeStart, + bool innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox, uint32_t toStringStart, InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind, Directives inheritedDirectives, Directives* newDirectives); @@ -1186,10 +1186,10 @@ class Parser final : public ParserBase, private JS::AutoGCRooter * Some parsers have two versions: an always-inlined version (with an 'i' * suffix) and a never-inlined version (with an 'n' suffix). */ - Node functionStmt(uint32_t preludeStart, + Node functionStmt(uint32_t toStringStart, YieldHandling yieldHandling, DefaultHandling defaultHandling, FunctionAsyncKind asyncKind = SyncFunction); - Node functionExpr(uint32_t preludeStart, InvokedPrediction invoked = PredictUninvoked, + Node functionExpr(uint32_t toStringStart, InvokedPrediction invoked = PredictUninvoked, FunctionAsyncKind asyncKind = SyncFunction); Node statementList(YieldHandling yieldHandling); @@ -1338,7 +1338,7 @@ class Parser final : public ParserBase, private JS::AutoGCRooter bool tryNewTarget(Node& newTarget); bool checkAndMarkSuperScope(); - Node methodDefinition(uint32_t preludeStart, PropertyType propType, HandleAtom funName); + Node methodDefinition(uint32_t toStringStart, PropertyType propType, HandleAtom funName); /* * Additional JS parsers. @@ -1346,7 +1346,7 @@ class Parser final : public ParserBase, private JS::AutoGCRooter bool functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind, Node funcpn); - Node functionDefinition(uint32_t preludeStart, Node pn, + Node functionDefinition(uint32_t toStringStart, Node pn, InHandling inHandling, YieldHandling yieldHandling, HandleAtom name, FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, @@ -1438,14 +1438,14 @@ class Parser final : public ParserBase, private JS::AutoGCRooter Node newDotGeneratorName(); bool declareDotGeneratorName(); - bool skipLazyInnerFunction(Node pn, uint32_t preludeStart, FunctionSyntaxKind kind, + bool skipLazyInnerFunction(Node pn, uint32_t toStringStart, FunctionSyntaxKind kind, bool tryAnnexB); - bool innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun, uint32_t preludeStart, + bool innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun, uint32_t toStringStart, InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB, Directives inheritedDirectives, Directives* newDirectives); - bool trySyntaxParseInnerFunction(Node pn, HandleFunction fun, uint32_t preludeStart, + bool trySyntaxParseInnerFunction(Node pn, HandleFunction fun, uint32_t toStringStart, InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, diff --git a/js/src/frontend/SharedContext.h b/js/src/frontend/SharedContext.h index 213a0a461..3499a53fb 100644 --- a/js/src/frontend/SharedContext.h +++ b/js/src/frontend/SharedContext.h @@ -451,8 +451,8 @@ class FunctionBox : public ObjectBox, public SharedContext uint32_t bufEnd; uint32_t startLine; uint32_t startColumn; - uint32_t preludeStart; - uint32_t postludeEnd; + uint32_t toStringStart; + uint32_t toStringEnd; uint16_t length; uint8_t generatorKindBits_; /* The GeneratorKind of this function. */ @@ -482,7 +482,7 @@ class FunctionBox : public ObjectBox, public SharedContext FunctionContextFlags funCxFlags; FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead, JSFunction* fun, - uint32_t preludeStart, Directives directives, bool extraWarnings, + uint32_t toStringStart, Directives directives, bool extraWarnings, GeneratorKind generatorKind, FunctionAsyncKind asyncKind); MutableHandle namedLambdaBindings() { @@ -608,10 +608,10 @@ class FunctionBox : public ObjectBox, public SharedContext void setEnd(uint32_t end) { // For all functions except class constructors, the buffer and - // postlude ending positions are the same. Class constructors override - // the postlude ending position with the end of the class definition. + // toString ending positions are the same. Class constructors override + // the toString ending position with the end of the class definition. bufEnd = end; - postludeEnd = end; + toStringEnd = end; } void trace(JSTracer* trc) override; diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 4f15e78c2..0886923fd 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -821,7 +821,8 @@ CreateFunctionPrototype(JSContext* cx, JSProtoKey key) sourceObject, begin, ss->length(), - 0, 0)); + 0, + ss->length())); if (!script || !JSScript::initFunctionPrototype(cx, script, functionProto)) return nullptr; diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index ad4cb2338..fc7438e3b 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -235,8 +235,8 @@ XDRRelazificationInfo(XDRState* xdr, HandleFunction fun, HandleScript scri { uint32_t begin = script->sourceStart(); uint32_t end = script->sourceEnd(); - uint32_t preludeStart = script->preludeStart(); - uint32_t postludeEnd = script->postludeEnd(); + uint32_t toStringStart = script->toStringStart(); + uint32_t toStringEnd = script->toStringEnd(); uint32_t lineno = script->lineno(); uint32_t column = script->column(); @@ -244,8 +244,8 @@ XDRRelazificationInfo(XDRState* xdr, HandleFunction fun, HandleScript scri packedFields = lazy->packedFields(); MOZ_ASSERT(begin == lazy->begin()); MOZ_ASSERT(end == lazy->end()); - MOZ_ASSERT(preludeStart == lazy->preludeStart()); - MOZ_ASSERT(postludeEnd == lazy->postludeEnd()); + MOZ_ASSERT(toStringStart == lazy->toStringStart()); + MOZ_ASSERT(toStringEnd == lazy->toStringEnd()); MOZ_ASSERT(lineno == lazy->lineno()); MOZ_ASSERT(column == lazy->column()); // We can assert we have no inner functions because we don't @@ -259,12 +259,12 @@ XDRRelazificationInfo(XDRState* xdr, HandleFunction fun, HandleScript scri if (mode == XDR_DECODE) { lazy.set(LazyScript::Create(cx, fun, script, enclosingScope, script, - packedFields, begin, end, preludeStart, lineno, column)); + packedFields, begin, end, toStringStart, lineno, column)); if (!lazy) return false; - lazy->setPostludeEnd(postludeEnd); + lazy->setToStringEnd(toStringEnd); // As opposed to XDRLazyScript, we need to restore the runtime bits // of the script, as we are trying to match the fact this function @@ -614,9 +614,9 @@ js::XDRScript(XDRState* xdr, HandleScope scriptEnclosingScope, HandleScrip return false; if (!xdr->codeUint32(&script->sourceEnd_)) return false; - if (!xdr->codeUint32(&script->preludeStart_)) + if (!xdr->codeUint32(&script->toStringStart_)) return false; - if (!xdr->codeUint32(&script->postludeEnd_)) + if (!xdr->codeUint32(&script->toStringEnd_)) return false; if (!xdr->codeUint32(&lineno) || @@ -948,8 +948,8 @@ js::XDRLazyScript(XDRState* xdr, HandleScope enclosingScope, HandleScript { uint32_t begin; uint32_t end; - uint32_t preludeStart; - uint32_t postludeEnd; + uint32_t toStringStart; + uint32_t toStringEnd; uint32_t lineno; uint32_t column; uint64_t packedFields; @@ -963,16 +963,16 @@ js::XDRLazyScript(XDRState* xdr, HandleScope enclosingScope, HandleScript begin = lazy->begin(); end = lazy->end(); - preludeStart = lazy->preludeStart(); - postludeEnd = lazy->postludeEnd(); + toStringStart = lazy->toStringStart(); + toStringEnd = lazy->toStringEnd(); lineno = lazy->lineno(); column = lazy->column(); packedFields = lazy->packedFields(); } if (!xdr->codeUint32(&begin) || !xdr->codeUint32(&end) || - !xdr->codeUint32(&preludeStart) || - !xdr->codeUint32(&postludeEnd) || + !xdr->codeUint32(&toStringStart) || + !xdr->codeUint32(&toStringEnd) || !xdr->codeUint32(&lineno) || !xdr->codeUint32(&column) || !xdr->codeUint64(&packedFields)) { @@ -981,10 +981,10 @@ js::XDRLazyScript(XDRState* xdr, HandleScope enclosingScope, HandleScript if (mode == XDR_DECODE) { lazy.set(LazyScript::Create(cx, fun, nullptr, enclosingScope, enclosingScript, - packedFields, begin, end, preludeStart, lineno, column)); + packedFields, begin, end, toStringStart, lineno, column)); if (!lazy) return false; - lazy->setPostludeEnd(postludeEnd); + lazy->setToStringEnd(toStringEnd); fun->initLazyScript(lazy); } } @@ -1033,8 +1033,8 @@ JSScript::setDefaultClassConstructorSpan(JSObject* sourceObject, uint32_t start, { MOZ_ASSERT(isDefaultClassConstructor()); setSourceObject(sourceObject); - preludeStart_ = start; - postludeEnd_ = end; + toStringStart_ = start; + toStringEnd_ = end; } js::ScriptSourceObject& @@ -1468,7 +1468,7 @@ JSScript::sourceData(JSContext* cx, HandleScript script) JSScript::sourceDataForToString(JSContext* cx, HandleScript script) { MOZ_ASSERT(script->scriptSource()->hasSourceData()); - return script->scriptSource()->substring(cx, script->preludeStart(), script->postludeEnd()); + return script->scriptSource()->substring(cx, script->toStringStart(), script->toStringEnd()); } UncompressedSourceCache::AutoHoldEntry::AutoHoldEntry() @@ -2470,9 +2470,15 @@ JSScript::initCompartment(ExclusiveContext* cx) /* static */ JSScript* JSScript::Create(ExclusiveContext* cx, const ReadOnlyCompileOptions& options, HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd, - uint32_t preludeStart, uint32_t postludeEnd) + uint32_t toStringStart, uint32_t toStringEnd) { + // bufStart and bufEnd specify the range of characters parsed by the + // Parser to produce this script. toStringStart and toStringEnd specify + // the range of characters to be returned for Function.prototype.toString. MOZ_ASSERT(bufStart <= bufEnd); + MOZ_ASSERT(toStringStart <= toStringEnd); + MOZ_ASSERT(toStringStart <= bufStart); + MOZ_ASSERT(toStringEnd >= bufEnd); RootedScript script(cx, Allocate(cx)); if (!script) @@ -2492,8 +2498,8 @@ JSScript::Create(ExclusiveContext* cx, const ReadOnlyCompileOptions& options, script->setSourceObject(sourceObject); script->sourceStart_ = bufStart; script->sourceEnd_ = bufEnd; - script->preludeStart_ = preludeStart; - script->postludeEnd_ = postludeEnd; + script->toStringStart_ = toStringStart; + script->toStringEnd_ = toStringEnd; return script; } @@ -3430,7 +3436,7 @@ CreateEmptyScriptForClone(JSContext* cx, HandleScript src) .setVersion(src->getVersion()); return JSScript::Create(cx, options, sourceObject, src->sourceStart(), src->sourceEnd(), - src->preludeStart(), src->postludeEnd()); + src->toStringStart(), src->toStringEnd()); } JSScript* @@ -3981,7 +3987,7 @@ JSScript::formalLivesInArgumentsObject(unsigned argSlot) LazyScript::LazyScript(JSFunction* fun, void* table, uint64_t packedFields, uint32_t begin, uint32_t end, - uint32_t preludeStart, uint32_t lineno, uint32_t column) + uint32_t toStringStart, uint32_t lineno, uint32_t column) : script_(nullptr), function_(fun), enclosingScope_(nullptr), @@ -3990,12 +3996,13 @@ LazyScript::LazyScript(JSFunction* fun, void* table, uint64_t packedFields, packedFields_(packedFields), begin_(begin), end_(end), - preludeStart_(preludeStart), - postludeEnd_(end), + toStringStart_(toStringStart), + toStringEnd_(end), lineno_(lineno), column_(column) { MOZ_ASSERT(begin <= end); + MOZ_ASSERT(toStringStart <= begin); } void @@ -4041,7 +4048,7 @@ LazyScript::maybeForwardedScriptSource() const /* static */ LazyScript* LazyScript::CreateRaw(ExclusiveContext* cx, HandleFunction fun, uint64_t packedFields, uint32_t begin, uint32_t end, - uint32_t preludeStart, uint32_t lineno, uint32_t column) + uint32_t toStringStart, uint32_t lineno, uint32_t column) { union { PackedView p; @@ -4070,7 +4077,7 @@ LazyScript::CreateRaw(ExclusiveContext* cx, HandleFunction fun, cx->compartment()->scheduleDelazificationForDebugger(); return new (res) LazyScript(fun, table.forget(), packed, begin, end, - preludeStart, lineno, column); + toStringStart, lineno, column); } /* static */ LazyScript* @@ -4079,7 +4086,7 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun, Handle> innerFunctions, JSVersion version, uint32_t begin, uint32_t end, - uint32_t preludeStart, uint32_t lineno, uint32_t column) + uint32_t toStringStart, uint32_t lineno, uint32_t column) { union { PackedView p; @@ -4103,7 +4110,7 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun, p.isDerivedClassConstructor = false; p.needsHomeObject = false; - LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, preludeStart, + LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, toStringStart, lineno, column); if (!res) return nullptr; @@ -4125,7 +4132,7 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun, HandleScript script, HandleScope enclosingScope, HandleScript enclosingScript, uint64_t packedFields, uint32_t begin, uint32_t end, - uint32_t preludeStart, uint32_t lineno, uint32_t column) + uint32_t toStringStart, uint32_t lineno, uint32_t column) { // Dummy atom which is not a valid property name. RootedAtom dummyAtom(cx, cx->names().comma); @@ -4134,7 +4141,7 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun, // holding this lazy script. HandleFunction dummyFun = fun; - LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, preludeStart, + LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, toStringStart, lineno, column); if (!res) return nullptr; diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 8a21d394a..23ad44718 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -853,29 +853,36 @@ class JSScript : public js::gc::TenuredCell uint32_t bodyScopeIndex_; /* index into the scopes array of the body scope */ - // Range of characters in scriptSource which contains this script's source. - // each field points the following location. + // Range of characters in scriptSource which contains this script's + // source, that is, the range used by the Parser to produce this script. + // + // Most scripted functions have sourceStart_ == toStringStart_ and + // sourceEnd_ == toStringEnd_. However, for functions with extra + // qualifiers (e.g. generators, async) and for class constructors (which + // need to return the entire class source), their values differ. + // + // Each field points the following locations. // // function * f(a, b) { return a + b; } // ^ ^ ^ // | | | // | sourceStart_ sourceEnd_ - // | - // preludeStart_ + // | | + // toStringStart_ toStringEnd_ // - // And, in the case of class constructors, an additional postlude offset - // is used for use with toString. + // And, in the case of class constructors, an additional toStringEnd + // offset is used. // // class C { constructor() { this.field = 42; } } // ^ ^ ^ ^ // | | | `---------` // | sourceStart_ sourceEnd_ | // | | - // preludeStart_ postludeEnd_ + // toStringStart_ toStringEnd_ uint32_t sourceStart_; uint32_t sourceEnd_; - uint32_t preludeStart_; - uint32_t postludeEnd_; + uint32_t toStringStart_; + uint32_t toStringEnd_; // Number of times the script has been called or has had backedges taken. // When running in ion, also increased for any inlined scripts. Reset if @@ -1049,7 +1056,7 @@ class JSScript : public js::gc::TenuredCell const JS::ReadOnlyCompileOptions& options, js::HandleObject sourceObject, uint32_t sourceStart, uint32_t sourceEnd, - uint32_t preludeStart, uint32_t postludeEnd); + uint32_t toStringStart, uint32_t toStringEnd); void initCompartment(js::ExclusiveContext* cx); @@ -1196,12 +1203,12 @@ class JSScript : public js::gc::TenuredCell return sourceEnd_; } - uint32_t preludeStart() const { - return preludeStart_; + uint32_t toStringStart() const { + return toStringStart_; } - uint32_t postludeEnd() const { - return postludeEnd_; + uint32_t toStringEnd() const { + return toStringEnd_; } bool noScriptRval() const { @@ -2004,15 +2011,15 @@ class LazyScript : public gc::TenuredCell // See the comment in JSScript for the details. uint32_t begin_; uint32_t end_; - uint32_t preludeStart_; - uint32_t postludeEnd_; + uint32_t toStringStart_; + uint32_t toStringEnd_; // Line and column of |begin_| position, that is the position where we // start parsing. uint32_t lineno_; uint32_t column_; LazyScript(JSFunction* fun, void* table, uint64_t packedFields, - uint32_t begin, uint32_t end, uint32_t preludeStart, + uint32_t begin, uint32_t end, uint32_t toStringStart, uint32_t lineno, uint32_t column); // Create a LazyScript without initializing the closedOverBindings and the @@ -2020,7 +2027,7 @@ class LazyScript : public gc::TenuredCell // with valid atoms and functions. static LazyScript* CreateRaw(ExclusiveContext* cx, HandleFunction fun, uint64_t packedData, uint32_t begin, uint32_t end, - uint32_t preludeStart, uint32_t lineno, uint32_t column); + uint32_t toStringStart, uint32_t lineno, uint32_t column); public: static const uint32_t NumClosedOverBindingsLimit = 1 << NumClosedOverBindingsBits; @@ -2032,7 +2039,7 @@ class LazyScript : public gc::TenuredCell const frontend::AtomVector& closedOverBindings, Handle> innerFunctions, JSVersion version, uint32_t begin, uint32_t end, - uint32_t preludeStart, uint32_t lineno, uint32_t column); + uint32_t toStringStart, uint32_t lineno, uint32_t column); // Create a LazyScript and initialize the closedOverBindings and the // innerFunctions with dummy values to be replaced in a later initialization @@ -2047,7 +2054,7 @@ class LazyScript : public gc::TenuredCell HandleScript script, HandleScope enclosingScope, HandleScript enclosingScript, uint64_t packedData, uint32_t begin, uint32_t end, - uint32_t preludeStart, uint32_t lineno, uint32_t column); + uint32_t toStringStart, uint32_t lineno, uint32_t column); void initRuntimeFields(uint64_t packedFields); @@ -2227,11 +2234,11 @@ class LazyScript : public gc::TenuredCell uint32_t end() const { return end_; } - uint32_t preludeStart() const { - return preludeStart_; + uint32_t toStringStart() const { + return toStringStart_; } - uint32_t postludeEnd() const { - return postludeEnd_; + uint32_t toStringEnd() const { + return toStringEnd_; } uint32_t lineno() const { return lineno_; @@ -2240,9 +2247,10 @@ class LazyScript : public gc::TenuredCell return column_; } - void setPostludeEnd(uint32_t postludeEnd) { - MOZ_ASSERT(postludeEnd_ >= end_); - postludeEnd_ = postludeEnd; + void setToStringEnd(uint32_t toStringEnd) { + MOZ_ASSERT(toStringStart_ <= toStringEnd); + MOZ_ASSERT(toStringEnd_ >= end_); + toStringEnd_ = toStringEnd; } bool hasUncompiledEnclosingScript() const; diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp index 51632a683..52b8eeed1 100644 --- a/js/src/wasm/AsmJS.cpp +++ b/js/src/wasm/AsmJS.cpp @@ -319,7 +319,7 @@ struct js::AsmJSMetadata : Metadata, AsmJSMetadataCacheablePod // Function constructor, this will be the first character in the function // source. Otherwise, it will be the opening parenthesis of the arguments // list. - uint32_t preludeStart; + uint32_t toStringStart; uint32_t srcStart; uint32_t srcBodyStart; bool strict; @@ -1760,7 +1760,7 @@ class MOZ_STACK_CLASS ModuleValidator if (!asmJSMetadata_) return false; - asmJSMetadata_->preludeStart = moduleFunctionNode_->pn_funbox->preludeStart; + asmJSMetadata_->toStringStart = moduleFunctionNode_->pn_funbox->toStringStart; asmJSMetadata_->srcStart = moduleFunctionNode_->pn_body->pn_pos.begin; asmJSMetadata_->srcBodyStart = parser_.tokenStream.currentToken().pos.end; asmJSMetadata_->strict = parser_.pc->sc()->strict() && @@ -7051,7 +7051,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line) TokenStream& tokenStream = m.tokenStream(); tokenStream.consumeKnownToken(TOK_FUNCTION, TokenStream::Operand); - uint32_t preludeStart = tokenStream.currentToken().pos.begin; + uint32_t toStringStart = tokenStream.currentToken().pos.begin; *line = tokenStream.srcCoords.lineNum(tokenStream.currentToken().pos.end); TokenKind tk; @@ -7074,7 +7074,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line) ParseContext* outerpc = m.parser().pc; Directives directives(outerpc); - FunctionBox* funbox = m.parser().newFunctionBox(fn, fun, preludeStart, directives, NotGenerator, + FunctionBox* funbox = m.parser().newFunctionBox(fn, fun, toStringStart, directives, NotGenerator, SyncFunction, /* tryAnnexB = */ false); if (!funbox) return false; @@ -8071,7 +8071,7 @@ HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& me return false; } - uint32_t begin = metadata.preludeStart; + uint32_t begin = metadata.toStringStart; uint32_t end = metadata.srcEndAfterCurly(); Rooted src(cx, source->substringDontDeflate(cx, begin, end)); if (!src) @@ -8554,7 +8554,7 @@ LookupAsmJSModuleInCache(ExclusiveContext* cx, AsmJSParser& parser, bool* loaded return true; // See AsmJSMetadata comment as well as ModuleValidator::init(). - asmJSMetadata->preludeStart = parser.pc->functionBox()->preludeStart; + asmJSMetadata->toStringStart = parser.pc->functionBox()->toStringStart; asmJSMetadata->srcStart = parser.pc->functionBox()->functionNode->pn_body->pn_pos.begin; asmJSMetadata->srcBodyStart = parser.tokenStream.currentToken().pos.end; asmJSMetadata->strict = parser.pc->sc()->strict() && !parser.pc->sc()->hasExplicitUseStrict(); @@ -8852,7 +8852,7 @@ js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool addParenToLambda MOZ_ASSERT(IsAsmJSModule(fun)); const AsmJSMetadata& metadata = AsmJSModuleFunctionToModule(fun).metadata().asAsmJS(); - uint32_t begin = metadata.preludeStart; + uint32_t begin = metadata.toStringStart; uint32_t end = metadata.srcEndAfterCurly(); ScriptSource* source = metadata.scriptSource.get(); -- cgit v1.2.3 From 92ca89f5f791656b593596e0ce992cf1e1e42b41 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 13 Jul 2019 23:06:35 -0400 Subject: 1357483 - Stop changing the end position of parenthesized expression ParseNodes. --- js/src/frontend/Parser.cpp | 1 - js/src/tests/ecma_6/Class/parenExprToString.js | 8 ++++++++ 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 js/src/tests/ecma_6/Class/parenExprToString.js (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 1be57f8f5..ec4a975e6 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -9820,7 +9820,6 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling if (!expr) return null(); MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN); - handler.setEndPosition(expr, pos().end); return handler.parenthesize(expr); } diff --git a/js/src/tests/ecma_6/Class/parenExprToString.js b/js/src/tests/ecma_6/Class/parenExprToString.js new file mode 100644 index 000000000..a93972ce9 --- /dev/null +++ b/js/src/tests/ecma_6/Class/parenExprToString.js @@ -0,0 +1,8 @@ +// Test that parenthesized class expressions don't get their toString offsets +// messed up. + +assertEq((class {}).toString(), "class {}"); +assertEq(((class {})).toString(), "class {}"); + +if (typeof reportCompare === "function") + reportCompare(0, 0, "OK"); -- cgit v1.2.3 From 7b1c6a022c4c0606b1b75e492a256ae7f4af305d Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 13 Jul 2019 23:10:10 -0400 Subject: Bug 1364573 - Don't relazify class default constructors. Because of the wacko way we handle toString offsets for class default constructors, those offsets cannot be recovered if we relazify the functions. Luckily there's no reason to relazify them, their JSScripts are very small: either a single 'retrval' for non-derived, and still fairly small for derived. --- js/src/jsscript.h | 1 + 1 file changed, 1 insertion(+) (limited to 'js/src') diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 23ad44718..85eb2938d 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -1494,6 +1494,7 @@ class JSScript : public js::gc::TenuredCell bool isRelazifiable() const { return (selfHosted() || lazyScript) && !hasInnerFunctions_ && !types_ && !isGenerator() && !hasBaselineScript() && !hasAnyIonScript() && + !isDefaultClassConstructor() && !doNotRelazify_; } void setLazyScript(js::LazyScript* lazy) { -- cgit v1.2.3 From 7e510ee9b4dee7c2d15005baac89a2017f5673ef Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 13 Jul 2019 23:12:12 -0400 Subject: 1359622 - Fix assert for calling Function.toString on class constructors when the compartment has had source discarded. --- js/src/jit-test/tests/class/bug1359622.js | 4 ++++ js/src/jsfun.cpp | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 js/src/jit-test/tests/class/bug1359622.js (limited to 'js/src') diff --git a/js/src/jit-test/tests/class/bug1359622.js b/js/src/jit-test/tests/class/bug1359622.js new file mode 100644 index 000000000..b4a0df749 --- /dev/null +++ b/js/src/jit-test/tests/class/bug1359622.js @@ -0,0 +1,4 @@ +setDiscardSource(true) +evaluate(` + unescape(class get { static staticMethod() {} }); +`); diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 0886923fd..06dc40162 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -1022,8 +1022,10 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint) return nullptr; } } else { - // Default class constructors should always haveSource. - MOZ_ASSERT(!fun->infallibleIsDefaultClassConstructor(cx)); + // Default class constructors should always haveSource unless source + // has been discarded for the whole compartment. + MOZ_ASSERT(!fun->infallibleIsDefaultClassConstructor(cx) || + fun->compartment()->behaviors().discardSource()); if (!AppendPrelude() || !out.append("() {\n ")) -- cgit v1.2.3 From fe80b3d80d20241ff03338de4351d580796fd2c7 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 13 Jul 2019 23:20:19 -0400 Subject: 1357506 - Remove assert that constructorBox can only be set once when parsing classes. Both asm.js and syntax parsing can abort and rewind parsing of an inner function. The bookkeeping to make sure that a class's constructor FunctionBox is only set once is not worth it -- duplicate constructor definitions already throw an early error. --- js/src/frontend/Parser.cpp | 17 +++-------------- js/src/frontend/Parser.h | 21 +++------------------ js/src/frontend/SharedContext.h | 1 - js/src/jit-test/tests/class/bug1357506.js | 8 ++++++++ 4 files changed, 14 insertions(+), 33 deletions(-) create mode 100644 js/src/jit-test/tests/class/bug1357506.js (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index ec4a975e6..01ab3f64c 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -547,7 +547,7 @@ FunctionBox::initWithEnclosingParseContext(ParseContext* enclosing, FunctionSynt if (kind == ClassConstructor || kind == DerivedClassConstructor) { auto stmt = enclosing->findInnermostStatement(); MOZ_ASSERT(stmt); - stmt->setConstructorBox(this); + stmt->constructorBox = this; if (kind == DerivedClassConstructor) { setDerivedClassConstructor(); @@ -573,16 +573,6 @@ FunctionBox::initWithEnclosingParseContext(ParseContext* enclosing, FunctionSynt } } -void -FunctionBox::resetForAbortedSyntaxParse(ParseContext* enclosing, FunctionSyntaxKind kind) -{ - if (kind == ClassConstructor || kind == DerivedClassConstructor) { - auto stmt = enclosing->findInnermostStatement(); - MOZ_ASSERT(stmt); - stmt->clearConstructorBoxForAbortedSyntaxParse(this); - } -} - void FunctionBox::initWithEnclosingScope(Scope* enclosingScope) { @@ -3407,7 +3397,6 @@ Parser::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunct // correctness. parser->clearAbortedSyntaxParse(); usedNames.rewind(token); - funbox->resetForAbortedSyntaxParse(pc, kind); MOZ_ASSERT_IF(parser->context->isJSContext(), !parser->context->asJSContext()->isExceptionPending()); break; @@ -7078,7 +7067,7 @@ Parser::classDefinition(YieldHandling yieldHandling, errorAt(nameOffset, JSMSG_BAD_METHOD_DEF); return null(); } - if (classStmt.constructorBox()) { + if (classStmt.constructorBox) { errorAt(nameOffset, JSMSG_DUPLICATE_PROPERTY, "constructor"); return null(); } @@ -7125,7 +7114,7 @@ Parser::classDefinition(YieldHandling yieldHandling, // Amend the toStringEnd offset for the constructor now that we've // finished parsing the class. uint32_t classEndOffset = pos().end; - if (FunctionBox* ctorbox = classStmt.constructorBox()) { + if (FunctionBox* ctorbox = classStmt.constructorBox) { if (ctorbox->function()->isInterpretedLazy()) ctorbox->function()->lazyScript()->setToStringEnd(classEndOffset); ctorbox->toStringEnd = classEndOffset; diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 65e46a65e..7866bc4fd 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -85,29 +85,14 @@ class ParseContext : public Nestable } }; - class ClassStatement : public Statement + struct ClassStatement : public Statement { - FunctionBox* constructorBox_; + FunctionBox* constructorBox; - public: explicit ClassStatement(ParseContext* pc) : Statement(pc, StatementKind::Class), - constructorBox_(nullptr) + constructorBox(nullptr) { } - - void clearConstructorBoxForAbortedSyntaxParse(FunctionBox* funbox) { - MOZ_ASSERT(constructorBox_ == funbox); - constructorBox_ = nullptr; - } - - void setConstructorBox(FunctionBox* funbox) { - MOZ_ASSERT(!constructorBox_); - constructorBox_ = funbox; - } - - FunctionBox* constructorBox() const { - return constructorBox_; - } }; // The intra-function scope stack. diff --git a/js/src/frontend/SharedContext.h b/js/src/frontend/SharedContext.h index 3499a53fb..013444690 100644 --- a/js/src/frontend/SharedContext.h +++ b/js/src/frontend/SharedContext.h @@ -503,7 +503,6 @@ class FunctionBox : public ObjectBox, public SharedContext void initFromLazyFunction(); void initStandaloneFunction(Scope* enclosingScope); void initWithEnclosingParseContext(ParseContext* enclosing, FunctionSyntaxKind kind); - void resetForAbortedSyntaxParse(ParseContext* enclosing, FunctionSyntaxKind kind); ObjectBox* toObjectBox() override { return this; } JSFunction* function() const { return &object->as(); } diff --git a/js/src/jit-test/tests/class/bug1357506.js b/js/src/jit-test/tests/class/bug1357506.js new file mode 100644 index 000000000..52a5643e6 --- /dev/null +++ b/js/src/jit-test/tests/class/bug1357506.js @@ -0,0 +1,8 @@ +// Test that constructors that abort due to asm.js do not assert due to the +// parser keeping track of the FunctionBox corresponding to the constructor. + +class a { + constructor() { + "use asm"; + } +} -- cgit v1.2.3 From 03df00e45ff4dd24b739a973d56edaf800313f7f Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 13 Jul 2019 23:21:45 -0400 Subject: 1367204 - Generate "[sourceless code]" for class constructors when sourceIsLazy and no source hook is set. --- js/src/jsfun.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'js/src') diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 06dc40162..9edf238ef 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -1013,7 +1013,20 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint) if (!out.append(")")) return nullptr; } - } else if (fun->isInterpreted() && !fun->isSelfHostedBuiltin()) { + } else if (fun->isInterpreted() && + (!fun->isSelfHostedBuiltin() || + fun->infallibleIsDefaultClassConstructor(cx))) + { + // Default class constructors should always haveSource except; + // + // 1. Source has been discarded for the whole compartment. + // + // 2. The source is marked as "lazy", i.e., retrieved on demand, and + // the embedding has not provided a hook to retrieve sources. + MOZ_ASSERT_IF(fun->infallibleIsDefaultClassConstructor(cx), + !cx->runtime()->sourceHook || + !script->scriptSource()->sourceRetrievable() || + fun->compartment()->behaviors().discardSource()); if (!AppendPrelude() || !out.append("() {\n ") || !out.append("[sourceless code]") || @@ -1022,10 +1035,6 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint) return nullptr; } } else { - // Default class constructors should always haveSource unless source - // has been discarded for the whole compartment. - MOZ_ASSERT(!fun->infallibleIsDefaultClassConstructor(cx) || - fun->compartment()->behaviors().discardSource()); if (!AppendPrelude() || !out.append("() {\n ")) -- cgit v1.2.3 From ccb322db6d1f14c3013bacb01dcb064a3f7fa28f Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 14 Jul 2019 10:15:10 -0400 Subject: 420857 - Part 1: Report the position of opening brace for missing brace error in function body. --- js/src/frontend/Parser.cpp | 44 +++++++++++++++++++--- js/src/frontend/Parser.h | 2 + .../jit-test/tests/parser/missing-closing-brace.js | 30 +++++++++++++++ js/src/js.msg | 1 + 4 files changed, 71 insertions(+), 6 deletions(-) create mode 100644 js/src/jit-test/tests/parser/missing-closing-brace.js (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 01ab3f64c..9aed88ce9 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -1012,6 +1012,35 @@ Parser::hasValidSimpleStrictParameterNames() return true; } +template +void +Parser::reportMissingClosing(unsigned errorNumber, unsigned noteNumber, + uint32_t openedPos) +{ + auto notes = MakeUnique(); + if (!notes) + return; + + uint32_t line, column; + tokenStream.srcCoords.lineNumAndColumnIndex(openedPos, &line, &column); + + const size_t MaxWidth = sizeof("4294967295"); + char columnNumber[MaxWidth]; + SprintfLiteral(columnNumber, "%" PRIu32, column); + char lineNumber[MaxWidth]; + SprintfLiteral(lineNumber, "%" PRIu32, line); + + if (!notes->addNoteASCII(pc->sc()->context, + getFilename(), line, column, + GetErrorMessage, nullptr, + noteNumber, lineNumber, columnNumber)) + { + return; + } + + errorWithNotes(Move(notes), errorNumber); +} + template void Parser::reportRedeclaration(HandlePropertyName name, DeclarationKind prevKind, @@ -1039,11 +1068,11 @@ Parser::reportRedeclaration(HandlePropertyName name, DeclarationKi char lineNumber[MaxWidth]; SprintfLiteral(lineNumber, "%" PRIu32, line); - if (!notes->addNoteLatin1(pc->sc()->context, - getFilename(), line, column, - GetErrorMessage, nullptr, - JSMSG_REDECLARED_PREV, - lineNumber, columnNumber)) + if (!notes->addNoteASCII(pc->sc()->context, + getFilename(), line, column, + GetErrorMessage, nullptr, + JSMSG_REDECLARED_PREV, + lineNumber, columnNumber)) { return; } @@ -3613,6 +3642,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, TokenKind tt; if (!tokenStream.getToken(&tt, TokenStream::Operand)) return false; + uint32_t openedPos = 0; if (tt != TOK_LC) { if ((funbox->isStarGenerator() && !funbox->isAsync()) || kind == Method || kind == GetterNoExpressionClosure || kind == SetterNoExpressionClosure || @@ -3634,6 +3664,8 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, tokenStream.ungetToken(); bodyType = ExpressionBody; funbox->setIsExprBody(); + } else { + openedPos = pos().begin; } // Arrow function parameters inherit yieldHandling from the enclosing @@ -3675,7 +3707,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if (!tokenStream.matchToken(&matched, TOK_RC, TokenStream::Operand)) return false; if (!matched) { - error(JSMSG_CURLY_AFTER_BODY); + reportMissingClosing(JSMSG_CURLY_AFTER_BODY, JSMSG_CURLY_OPENED, openedPos); return false; } funbox->setEnd(pos().end); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 7866bc4fd..b1d3bdee0 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1459,6 +1459,8 @@ class Parser final : public ParserBase, private JS::AutoGCRooter bool hasValidSimpleStrictParameterNames(); + void reportMissingClosing(unsigned errorNumber, unsigned noteNumber, uint32_t openedPos); + void reportRedeclaration(HandlePropertyName name, DeclarationKind prevKind, TokenPos pos, uint32_t prevPos); bool notePositionalFormalParameter(Node fn, HandlePropertyName name, uint32_t beginPos, diff --git a/js/src/jit-test/tests/parser/missing-closing-brace.js b/js/src/jit-test/tests/parser/missing-closing-brace.js new file mode 100644 index 000000000..4512ad133 --- /dev/null +++ b/js/src/jit-test/tests/parser/missing-closing-brace.js @@ -0,0 +1,30 @@ +function test(source, [lineNumber, columnNumber]) { + let caught = false; + try { + Reflect.parse(source, { source: "foo.js" }); + } catch (e) { + assertEq(e.message.includes("missing } "), true); + let notes = getErrorNotes(e); + assertEq(notes.length, 1); + let note = notes[0]; + assertEq(note.message, "{ opened at line " + lineNumber + ", column " + columnNumber); + assertEq(note.fileName, "foo.js"); + assertEq(note.lineNumber, lineNumber); + assertEq(note.columnNumber, columnNumber); + caught = true; + } + assertEq(caught, true); +} + +// Function + +test(` +function test1() { +} +function test2() { + if (true) { + //} +} +function test3() { +} +`, [4, 17]); diff --git a/js/src/js.msg b/js/src/js.msg index 569928be8..a51d99933 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -228,6 +228,7 @@ MSG_DEF(JSMSG_COLON_IN_COND, 0, JSEXN_SYNTAXERR, "missing : in conditi MSG_DEF(JSMSG_COMP_PROP_UNTERM_EXPR, 0, JSEXN_SYNTAXERR, "missing ] in computed property name") MSG_DEF(JSMSG_CONTRARY_NONDIRECTIVE, 1, JSEXN_SYNTAXERR, "'{0}' statement won't be enforced as a directive because it isn't in directive prologue position") MSG_DEF(JSMSG_CURLY_AFTER_BODY, 0, JSEXN_SYNTAXERR, "missing } after function body") +MSG_DEF(JSMSG_CURLY_OPENED, 2, JSEXN_NOTE, "{ opened at line {0}, column {1}") MSG_DEF(JSMSG_CURLY_AFTER_CATCH, 0, JSEXN_SYNTAXERR, "missing } after catch block") MSG_DEF(JSMSG_CURLY_AFTER_FINALLY, 0, JSEXN_SYNTAXERR, "missing } after finally block") MSG_DEF(JSMSG_CURLY_AFTER_LIST, 0, JSEXN_SYNTAXERR, "missing } after property list") -- cgit v1.2.3 From 3e1a8a74f2fc69f9df6f18ab19f5095722da7a60 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 14 Jul 2019 10:22:32 -0400 Subject: 420857 - Part 2: Report the position of opening brace for missing brace error in block. --- js/src/frontend/Parser.cpp | 44 ++++++++++++++------- .../jit-test/tests/parser/missing-closing-brace.js | 46 ++++++++++++++++++++++ 2 files changed, 75 insertions(+), 15 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 9aed88ce9..ef352ec35 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -66,29 +66,32 @@ using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr; // Read a token. Report an error and return null() if that token doesn't match // to the condition. Do not use MUST_MATCH_TOKEN_INTERNAL directly. -#define MUST_MATCH_TOKEN_INTERNAL(cond, modifier, errorNumber) \ +#define MUST_MATCH_TOKEN_INTERNAL(cond, modifier, errorReport) \ JS_BEGIN_MACRO \ TokenKind token; \ if (!tokenStream.getToken(&token, modifier)) \ return null(); \ if (!(cond)) { \ - error(errorNumber); \ + errorReport; \ return null(); \ } \ JS_END_MACRO #define MUST_MATCH_TOKEN_MOD(tt, modifier, errorNumber) \ - MUST_MATCH_TOKEN_INTERNAL(token == tt, modifier, errorNumber) + MUST_MATCH_TOKEN_INTERNAL(token == tt, modifier, error(errorNumber)) #define MUST_MATCH_TOKEN(tt, errorNumber) \ MUST_MATCH_TOKEN_MOD(tt, TokenStream::None, errorNumber) #define MUST_MATCH_TOKEN_FUNC_MOD(func, modifier, errorNumber) \ - MUST_MATCH_TOKEN_INTERNAL((func)(token), modifier, errorNumber) + MUST_MATCH_TOKEN_INTERNAL((func)(token), modifier, error(errorNumber)) #define MUST_MATCH_TOKEN_FUNC(func, errorNumber) \ MUST_MATCH_TOKEN_FUNC_MOD(func, TokenStream::None, errorNumber) +#define MUST_MATCH_TOKEN_MOD_WITH_REPORT(tt, modifier, errorReport) \ + MUST_MATCH_TOKEN_INTERNAL(token == tt, modifier, errorReport) + template static inline void PropagateTransitiveParseFlags(const T* inner, U* outer) @@ -3703,13 +3706,9 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, } if (bodyType == StatementListBody) { - bool matched; - if (!tokenStream.matchToken(&matched, TOK_RC, TokenStream::Operand)) - return false; - if (!matched) { - reportMissingClosing(JSMSG_CURLY_AFTER_BODY, JSMSG_CURLY_OPENED, openedPos); - return false; - } + MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::Operand, + reportMissingClosing(JSMSG_CURLY_AFTER_BODY, + JSMSG_CURLY_OPENED, openedPos)); funbox->setEnd(pos().end); } else { #if !JS_HAS_EXPR_CLOSURES @@ -4481,6 +4480,7 @@ typename ParseHandler::Node Parser::blockStatement(YieldHandling yieldHandling, unsigned errorNumber) { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LC)); + uint32_t openedPos = pos().begin; ParseContext::Statement stmt(pc, StatementKind::Block); ParseContext::Scope scope(this); @@ -4491,7 +4491,9 @@ Parser::blockStatement(YieldHandling yieldHandling, unsigned error if (!list) return null(); - MUST_MATCH_TOKEN_MOD(TOK_RC, TokenStream::Operand, errorNumber); + MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::Operand, + reportMissingClosing(errorNumber, JSMSG_CURLY_OPENED, + openedPos)); return finishLexicalScope(scope, list); } @@ -6743,6 +6745,8 @@ Parser::tryStatement(YieldHandling yieldHandling) { MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_TRY); + uint32_t openedPos = pos().begin; + ParseContext::Statement stmt(pc, StatementKind::Try); ParseContext::Scope scope(this); if (!scope.init(pc)) @@ -6756,7 +6760,9 @@ Parser::tryStatement(YieldHandling yieldHandling) if (!innerBlock) return null(); - MUST_MATCH_TOKEN_MOD(TOK_RC, TokenStream::Operand, JSMSG_CURLY_AFTER_TRY); + MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::Operand, + reportMissingClosing(JSMSG_CURLY_AFTER_TRY, + JSMSG_CURLY_OPENED, openedPos)); } bool hasUnconditionalCatch = false; @@ -6872,6 +6878,8 @@ Parser::tryStatement(YieldHandling yieldHandling) if (tt == TOK_FINALLY) { MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_FINALLY); + uint32_t openedPos = pos().begin; + ParseContext::Statement stmt(pc, StatementKind::Finally); ParseContext::Scope scope(this); if (!scope.init(pc)) @@ -6885,7 +6893,9 @@ Parser::tryStatement(YieldHandling yieldHandling) if (!finallyBlock) return null(); - MUST_MATCH_TOKEN_MOD(TOK_RC, TokenStream::Operand, JSMSG_CURLY_AFTER_FINALLY); + MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::Operand, + reportMissingClosing(JSMSG_CURLY_AFTER_FINALLY, + JSMSG_CURLY_OPENED, openedPos)); } else { tokenStream.ungetToken(); } @@ -6902,6 +6912,8 @@ typename ParseHandler::Node Parser::catchBlockStatement(YieldHandling yieldHandling, ParseContext::Scope& catchParamScope) { + uint32_t openedPos = pos().begin; + ParseContext::Statement stmt(pc, StatementKind::Block); // ES 13.15.7 CatchClauseEvaluation @@ -6921,7 +6933,9 @@ Parser::catchBlockStatement(YieldHandling yieldHandling, if (!list) return null(); - MUST_MATCH_TOKEN_MOD(TOK_RC, TokenStream::Operand, JSMSG_CURLY_AFTER_CATCH); + MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::Operand, + reportMissingClosing(JSMSG_CURLY_AFTER_CATCH, + JSMSG_CURLY_OPENED, openedPos)); // The catch parameter names are not bound in the body scope, so remove // them before generating bindings. diff --git a/js/src/jit-test/tests/parser/missing-closing-brace.js b/js/src/jit-test/tests/parser/missing-closing-brace.js index 4512ad133..2bb96b11b 100644 --- a/js/src/jit-test/tests/parser/missing-closing-brace.js +++ b/js/src/jit-test/tests/parser/missing-closing-brace.js @@ -28,3 +28,49 @@ function test2() { function test3() { } `, [4, 17]); + +// Block statement. +test(` +{ + if (true) { +} +`, [2, 0]); +test(` +if (true) { + if (true) { +} +`, [2, 10]); +test(` +for (;;) { + if (true) { +} +`, [2, 9]); +test(` +while (true) { + if (true) { +} +`, [2, 13]); +test(` +do { + do { +} while(true); +`, [2, 3]); + +// try-catch-finally. +test(` +try { + if (true) { +} +`, [2, 4]); +test(` +try { +} catch (e) { + if (true) { +} +`, [3, 12]); +test(` +try { +} finally { + if (true) { +} +`, [3, 10]); -- cgit v1.2.3 From 10227d77bfccda845a63e20b22bc4367ecc7b4e0 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 14 Jul 2019 10:24:25 -0400 Subject: 420857 - Part 3: Report the position of opening brace for missing brace error in object literal. --- js/src/frontend/Parser.cpp | 4 +++- js/src/jit-test/tests/parser/missing-closing-brace.js | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index ef352ec35..7dc3cdf8f 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -9524,6 +9524,8 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LC)); + uint32_t openedPos = pos().begin; + Node literal = handler.newObjectLiteral(pos().begin); if (!literal) return null(); @@ -9686,7 +9688,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* if (tt == TOK_RC) break; if (tt != TOK_COMMA) { - error(JSMSG_CURLY_AFTER_LIST); + reportMissingClosing(JSMSG_CURLY_AFTER_LIST, JSMSG_CURLY_OPENED, openedPos); return null(); } } diff --git a/js/src/jit-test/tests/parser/missing-closing-brace.js b/js/src/jit-test/tests/parser/missing-closing-brace.js index 2bb96b11b..f97cefd81 100644 --- a/js/src/jit-test/tests/parser/missing-closing-brace.js +++ b/js/src/jit-test/tests/parser/missing-closing-brace.js @@ -74,3 +74,10 @@ try { if (true) { } `, [3, 10]); + +// Object literal. +test(` +var x = { + foo: { +}; +`, [2, 8]); -- cgit v1.2.3 From e93a48121a1a14ac228bebe362e7c27b1aadd4d5 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 14 Jul 2019 10:26:41 -0400 Subject: 420857 - Part 4: Report the position of opening bracket for missing bracket error in array literal. --- js/src/frontend/Parser.cpp | 4 +++- js/src/jit-test/tests/parser/missing-closing-brace.js | 13 ++++++++++--- js/src/js.msg | 1 + 3 files changed, 14 insertions(+), 4 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 7dc3cdf8f..3154e41d5 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -9289,7 +9289,9 @@ Parser::arrayInitializer(YieldHandling yieldHandling, PossibleErro } } - MUST_MATCH_TOKEN_MOD(TOK_RB, modifier, JSMSG_BRACKET_AFTER_LIST); + MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RB, modifier, + reportMissingClosing(JSMSG_BRACKET_AFTER_LIST, + JSMSG_BRACKET_OPENED, begin)); } handler.setEndPosition(literal, pos().end); return literal; diff --git a/js/src/jit-test/tests/parser/missing-closing-brace.js b/js/src/jit-test/tests/parser/missing-closing-brace.js index f97cefd81..6820954ae 100644 --- a/js/src/jit-test/tests/parser/missing-closing-brace.js +++ b/js/src/jit-test/tests/parser/missing-closing-brace.js @@ -1,13 +1,13 @@ -function test(source, [lineNumber, columnNumber]) { +function test(source, [lineNumber, columnNumber], openType = "{", closeType = "}") { let caught = false; try { Reflect.parse(source, { source: "foo.js" }); } catch (e) { - assertEq(e.message.includes("missing } "), true); + assertEq(e.message.includes("missing " + closeType + " "), true); let notes = getErrorNotes(e); assertEq(notes.length, 1); let note = notes[0]; - assertEq(note.message, "{ opened at line " + lineNumber + ", column " + columnNumber); + assertEq(note.message, openType + " opened at line " + lineNumber + ", column " + columnNumber); assertEq(note.fileName, "foo.js"); assertEq(note.lineNumber, lineNumber); assertEq(note.columnNumber, columnNumber); @@ -81,3 +81,10 @@ var x = { foo: { }; `, [2, 8]); + +// Array literal. +test(` +var x = [ + [ +]; +`, [2, 8], "[", "]"); diff --git a/js/src/js.msg b/js/src/js.msg index a51d99933..ec49d06c9 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -218,6 +218,7 @@ MSG_DEF(JSMSG_BAD_SUPERCALL, 0, JSEXN_SYNTAXERR, "super() is only vali MSG_DEF(JSMSG_BRACKET_AFTER_ARRAY_COMPREHENSION, 0, JSEXN_SYNTAXERR, "missing ] after array comprehension") MSG_DEF(JSMSG_BRACKET_AFTER_LIST, 0, JSEXN_SYNTAXERR, "missing ] after element list") MSG_DEF(JSMSG_BRACKET_IN_INDEX, 0, JSEXN_SYNTAXERR, "missing ] in index expression") +MSG_DEF(JSMSG_BRACKET_OPENED, 2, JSEXN_NOTE, "[ opened at line {0}, column {1}") MSG_DEF(JSMSG_CATCH_AFTER_GENERAL, 0, JSEXN_SYNTAXERR, "catch after unconditional catch") MSG_DEF(JSMSG_CATCH_IDENTIFIER, 0, JSEXN_SYNTAXERR, "missing identifier in catch") MSG_DEF(JSMSG_CATCH_OR_FINALLY, 0, JSEXN_SYNTAXERR, "missing catch or finally after try") -- cgit v1.2.3 From b02f52f8a7cfedb92b1f6cf9a09c0a220b68b2f4 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 14 Jul 2019 12:54:05 -0400 Subject: 1303703 - Part 1: Separate binding pattern parsing from object/array literal parsing. --- js/src/frontend/Parser.cpp | 398 +++++++++++++++++++++++++++++++++++---------- js/src/frontend/Parser.h | 30 ++-- 2 files changed, 331 insertions(+), 97 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 3154e41d5..85f7ee846 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -4243,7 +4243,7 @@ Parser::PossibleError::transferErrorsTo(PossibleError* other) template <> bool -Parser::checkDestructuringName(ParseNode* expr, Maybe maybeDecl) +Parser::checkDestructuringAssignmentName(ParseNode* expr) { MOZ_ASSERT(!handler.isUnparenthesizedDestructuringPattern(expr)); @@ -4255,24 +4255,8 @@ Parser::checkDestructuringName(ParseNode* expr, Maybepn_pos.begin, JSMSG_NO_VARIABLE_NAME); - return false; - } - - RootedPropertyName name(context, expr->name()); - // `yield` is already checked, so pass YieldIsName to skip that check. - if (!checkBindingIdentifier(name, expr->pn_pos.begin, YieldIsName)) - return false; - return noteDeclaredName(name, *maybeDecl, expr->pn_pos); - } - - // Otherwise this is an expression in destructuring outside a declaration. + // The expression must be a simple assignment target, i.e. either a name + // or a property accessor. if (handler.isNameAnyParentheses(expr)) { if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(expr, context)) { if (!strictModeErrorAt(expr->pn_pos.begin, JSMSG_BAD_STRICT_ASSIGN, chars)) @@ -4291,14 +4275,12 @@ Parser::checkDestructuringName(ParseNode* expr, Maybe bool -Parser::checkDestructuringPattern(ParseNode* pattern, - Maybe maybeDecl, - PossibleError* possibleError /* = nullptr */); +Parser::checkDestructuringAssignmentPattern(ParseNode* pattern, + PossibleError* possibleError /* = nullptr */); template <> bool -Parser::checkDestructuringObject(ParseNode* objectPattern, - Maybe maybeDecl) +Parser::checkDestructuringAssignmentObject(ParseNode* objectPattern) { MOZ_ASSERT(objectPattern->isKind(PNK_OBJECT)); @@ -4319,10 +4301,10 @@ Parser::checkDestructuringObject(ParseNode* objectPattern, target = target->pn_left; if (handler.isUnparenthesizedDestructuringPattern(target)) { - if (!checkDestructuringPattern(target, maybeDecl)) + if (!checkDestructuringAssignmentPattern(target)) return false; } else { - if (!checkDestructuringName(target, maybeDecl)) + if (!checkDestructuringAssignmentName(target)) return false; } } @@ -4332,8 +4314,7 @@ Parser::checkDestructuringObject(ParseNode* objectPattern, template <> bool -Parser::checkDestructuringArray(ParseNode* arrayPattern, - Maybe maybeDecl) +Parser::checkDestructuringAssignmentArray(ParseNode* arrayPattern) { MOZ_ASSERT(arrayPattern->isKind(PNK_ARRAY)); @@ -4355,10 +4336,10 @@ Parser::checkDestructuringArray(ParseNode* arrayPattern, } if (handler.isUnparenthesizedDestructuringPattern(target)) { - if (!checkDestructuringPattern(target, maybeDecl)) + if (!checkDestructuringAssignmentPattern(target)) return false; } else { - if (!checkDestructuringName(target, maybeDecl)) + if (!checkDestructuringAssignmentName(target)) return false; } } @@ -4379,32 +4360,28 @@ Parser::checkDestructuringArray(ParseNode* arrayPattern, * these cases, the patterns' property value positions must be * simple names; the destructuring defines them as new variables. * - * In both cases, other code parses the pattern as an arbitrary - * primaryExpr, and then, here in checkDestructuringPattern, verify - * that the tree is a valid AssignmentPattern or BindingPattern. + * In the first case, other code parses the pattern as an arbitrary + * primaryExpr, and then, here in checkDestructuringAssignmentPattern, verify + * that the tree is a valid AssignmentPattern. * * In assignment-like contexts, we parse the pattern with - * pc->inDestructuringDecl clear, so the lvalue expressions in the - * pattern are parsed normally. primaryExpr links variable references - * into the appropriate use chains; creates placeholder definitions; - * and so on. checkDestructuringPattern won't bind any new names and - * we specialize lvalues as appropriate. + * pc->inDestructuringDecl clear, so the lvalue expressions in the pattern are + * parsed normally. identifierReference() links variable references into the + * appropriate use chains; creates placeholder definitions; and so on. + * checkDestructuringAssignmentPattern won't bind any new names and we + * specialize lvalues as appropriate. * - * In declaration-like contexts, the normal variable reference - * processing would just be an obstruction, because we're going to - * define the names that appear in the property value positions as new - * variables anyway. In this case, we parse the pattern with - * pc->inDestructuringDecl set, which directs primaryExpr to leave - * whatever name nodes it creates unconnected. Then, here in - * checkDestructuringPattern, we require the pattern's property value - * positions to be simple names, and define them as appropriate to the - * context. + * In declaration-like contexts, the normal variable reference processing + * would just be an obstruction, because we're going to define the names that + * appear in the property value positions as new variables anyway. In this + * case, we parse the pattern in destructuringDeclaration() with + * pc->inDestructuringDecl set, which directs identifierReference() to leave + * whatever name nodes it creates unconnected. */ template <> bool -Parser::checkDestructuringPattern(ParseNode* pattern, - Maybe maybeDecl, - PossibleError* possibleError /* = nullptr */) +Parser::checkDestructuringAssignmentPattern(ParseNode* pattern, + PossibleError* possibleError /* = nullptr */) { if (pattern->isKind(PNK_ARRAYCOMP)) { errorAt(pattern->pn_pos.begin, JSMSG_ARRAY_COMP_LEFTSIDE); @@ -4412,8 +4389,8 @@ Parser::checkDestructuringPattern(ParseNode* pattern, } bool isDestructuring = pattern->isKind(PNK_ARRAY) - ? checkDestructuringArray(pattern, maybeDecl) - : checkDestructuringObject(pattern, maybeDecl); + ? checkDestructuringAssignmentArray(pattern) + : checkDestructuringAssignmentObject(pattern); // Report any pending destructuring error. if (isDestructuring && possibleError && !possibleError->checkForDestructuringError()) @@ -4422,11 +4399,275 @@ Parser::checkDestructuringPattern(ParseNode* pattern, return isDestructuring; } +class AutoClearInDestructuringDecl +{ + ParseContext* pc_; + Maybe saved_; + + public: + explicit AutoClearInDestructuringDecl(ParseContext* pc) + : pc_(pc), + saved_(pc->inDestructuringDecl) + { + pc->inDestructuringDecl = Nothing(); + if (saved_ && *saved_ == DeclarationKind::FormalParameter) + pc->functionBox()->hasParameterExprs = true; + } + + ~AutoClearInDestructuringDecl() { + pc_->inDestructuringDecl = saved_; + } +}; + +template +typename ParseHandler::Node +Parser::bindingInitializer(Node lhs, YieldHandling yieldHandling) +{ + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_ASSIGN)); + + Node rhs; + { + AutoClearInDestructuringDecl autoClear(pc); + rhs = assignExpr(InAllowed, yieldHandling, TripledotProhibited); + if (!rhs) + return null(); + } + + handler.checkAndSetIsDirectRHSAnonFunction(rhs); + + Node assign = handler.newAssignment(PNK_ASSIGN, lhs, rhs, JSOP_NOP); + if (!assign) + return null(); + + if (foldConstants && !FoldConstants(context, &assign, this)) + return null(); + + return assign; +} + +template +typename ParseHandler::Node +Parser::bindingIdentifier(DeclarationKind kind, YieldHandling yieldHandling) +{ + Rooted name(context, bindingIdentifier(yieldHandling)); + if (!name) + return null(); + + Node binding = newName(name); + if (!binding || !noteDeclaredName(name, kind, pos())) + return null(); + + return binding; +} + +template +typename ParseHandler::Node +Parser::bindingIdentifierOrPattern(DeclarationKind kind, YieldHandling yieldHandling, + TokenKind tt) +{ + if (tt == TOK_LB) + return arrayBindingPattern(kind, yieldHandling); + + if (tt == TOK_LC) + return objectBindingPattern(kind, yieldHandling); + + if (!TokenKindIsPossibleIdentifierName(tt)) { + error(JSMSG_NO_VARIABLE_NAME); + return null(); + } + + return bindingIdentifier(kind, yieldHandling); +} + +template +typename ParseHandler::Node +Parser::objectBindingPattern(DeclarationKind kind, YieldHandling yieldHandling) +{ + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LC)); + + JS_CHECK_RECURSION(context, return null()); + + uint32_t begin = pos().begin; + Node literal = handler.newObjectLiteral(begin); + if (!literal) + return null(); + + RootedAtom propAtom(context); + for (;;) { + TokenKind tt; + if (!tokenStream.getToken(&tt)) + return null(); + if (tt == TOK_RC) + break; + + TokenPos namePos = pos(); + + tokenStream.ungetToken(); + + PropertyType propType; + Node propName = propertyName(yieldHandling, literal, &propType, &propAtom); + if (!propName) + return null(); + + if (propType == PropertyType::Normal) { + // Handle e.g., |var {p: x} = o| and |var {p: x=0} = o|. + + if (!tokenStream.getToken(&tt, TokenStream::Operand)) + return null(); + + Node binding = bindingIdentifierOrPattern(kind, yieldHandling, tt); + if (!binding) + return null(); + + bool hasInitializer; + if (!tokenStream.matchToken(&hasInitializer, TOK_ASSIGN)) + return null(); + + Node bindingExpr = hasInitializer + ? bindingInitializer(binding, yieldHandling) + : binding; + if (!bindingExpr) + return null(); + + if (!handler.addPropertyDefinition(literal, propName, bindingExpr)) + return null(); + } else if (propType == PropertyType::Shorthand) { + // Handle e.g., |var {x, y} = o| as destructuring shorthand + // for |var {x: x, y: y} = o|. + MOZ_ASSERT(TokenKindIsPossibleIdentifierName(tt)); + + Node binding = bindingIdentifier(kind, yieldHandling); + if (!binding) + return null(); + + if (!handler.addShorthand(literal, propName, binding)) + return null(); + } else if (propType == PropertyType::CoverInitializedName) { + // Handle e.g., |var {x=1, y=2} = o| as destructuring shorthand + // with default values. + MOZ_ASSERT(TokenKindIsPossibleIdentifierName(tt)); + + Node binding = bindingIdentifier(kind, yieldHandling); + if (!binding) + return null(); + + tokenStream.consumeKnownToken(TOK_ASSIGN); + + Node bindingExpr = bindingInitializer(binding, yieldHandling); + if (!bindingExpr) + return null(); + + if (!handler.addPropertyDefinition(literal, propName, bindingExpr)) + return null(); + } else { + errorAt(namePos.begin, JSMSG_NO_VARIABLE_NAME); + return null(); + } + + if (!tokenStream.getToken(&tt)) + return null(); + if (tt == TOK_RC) + break; + if (tt != TOK_COMMA) { + reportMissingClosing(JSMSG_CURLY_AFTER_LIST, JSMSG_CURLY_OPENED, begin); + return null(); + } + } + + handler.setEndPosition(literal, pos().end); + return literal; +} + +template +typename ParseHandler::Node +Parser::arrayBindingPattern(DeclarationKind kind, YieldHandling yieldHandling) +{ + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LB)); + + JS_CHECK_RECURSION(context, return null()); + + uint32_t begin = pos().begin; + Node literal = handler.newArrayLiteral(begin); + if (!literal) + return null(); + + uint32_t index = 0; + TokenStream::Modifier modifier = TokenStream::Operand; + for (; ; index++) { + if (index >= NativeObject::MAX_DENSE_ELEMENTS_COUNT) { + error(JSMSG_ARRAY_INIT_TOO_BIG); + return null(); + } + + TokenKind tt; + if (!tokenStream.getToken(&tt, TokenStream::Operand)) + return null(); + + if (tt == TOK_RB) { + tokenStream.ungetToken(); + break; + } + + if (tt == TOK_COMMA) { + if (!handler.addElision(literal, pos())) + return null(); + } else if (tt == TOK_TRIPLEDOT) { + uint32_t begin = pos().begin; + + TokenKind tt; + if (!tokenStream.getToken(&tt, TokenStream::Operand)) + return null(); + + Node inner = bindingIdentifierOrPattern(kind, yieldHandling, tt); + if (!inner) + return null(); + + if (!handler.addSpreadElement(literal, begin, inner)) + return null(); + } else { + Node binding = bindingIdentifierOrPattern(kind, yieldHandling, tt); + if (!binding) + return null(); + + bool hasInitializer; + if (!tokenStream.matchToken(&hasInitializer, TOK_ASSIGN)) + return null(); + + Node element = hasInitializer ? bindingInitializer(binding, yieldHandling) : binding; + if (!element) + return null(); + + handler.addArrayElement(literal, element); + } + + if (tt != TOK_COMMA) { + // If we didn't already match TOK_COMMA in above case. + bool matched; + if (!tokenStream.matchToken(&matched, TOK_COMMA)) + return null(); + if (!matched) { + modifier = TokenStream::None; + break; + } + if (tt == TOK_TRIPLEDOT) { + error(JSMSG_REST_WITH_COMMA); + return null(); + } + } + } + + MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RB, modifier, + reportMissingClosing(JSMSG_BRACKET_AFTER_LIST, + JSMSG_BRACKET_OPENED, begin)); + + handler.setEndPosition(literal, pos().end); + return literal; +} + template <> bool -Parser::checkDestructuringPattern(Node pattern, - Maybe maybeDecl, - PossibleError* possibleError /* = nullptr */) +Parser::checkDestructuringAssignmentPattern(Node pattern, + PossibleError* possibleError /* = nullptr */) { return abortIfSyntaxParser(); } @@ -4439,17 +4680,16 @@ Parser::destructuringDeclaration(DeclarationKind kind, YieldHandli MOZ_ASSERT(tokenStream.isCurrentTokenType(tt)); MOZ_ASSERT(tt == TOK_LB || tt == TOK_LC); - PossibleError possibleError(*this); Node pattern; { pc->inDestructuringDecl = Some(kind); - pattern = primaryExpr(yieldHandling, TripledotProhibited, tt, &possibleError); + if (tt == TOK_LB) + pattern = arrayBindingPattern(kind, yieldHandling); + else + pattern = objectBindingPattern(kind, yieldHandling); pc->inDestructuringDecl = Nothing(); } - if (!pattern || !checkDestructuringPattern(pattern, Some(kind), &possibleError)) - return null(); - return pattern; } @@ -4564,6 +4804,12 @@ Parser::declarationPattern(Node decl, DeclarationKind declKind, To // binary operator (examined with modifier None) terminated |init|. // For all other declarations, through ASI's infinite majesty, a next // token on a new line would begin an expression. + // Similar to the case in initializerInNameDeclaration(), we need to + // peek at the next token when assignExpr() is a lazily parsed arrow + // function. + TokenKind ignored; + if (!tokenStream.peekToken(&ignored)) + return null(); tokenStream.addModifierException(TokenStream::OperandIsNone); } @@ -5975,7 +6221,7 @@ Parser::forHeadStart(YieldHandling yieldHandling, // Verify the left-hand side expression doesn't have a forbidden form. if (handler.isUnparenthesizedDestructuringPattern(*forInitialPart)) { - if (!checkDestructuringPattern(*forInitialPart, Nothing(), &possibleError)) + if (!checkDestructuringAssignmentPattern(*forInitialPart, &possibleError)) return false; } else if (handler.isNameAnyParentheses(*forInitialPart)) { const char* chars = handler.nameIsArgumentsEvalAnyParentheses(*forInitialPart, context); @@ -7920,26 +8166,6 @@ Parser::condExpr1(InHandling inHandling, YieldHandling yieldHandli return handler.newConditional(condition, thenExpr, elseExpr); } -class AutoClearInDestructuringDecl -{ - ParseContext* pc_; - Maybe saved_; - - public: - explicit AutoClearInDestructuringDecl(ParseContext* pc) - : pc_(pc), - saved_(pc->inDestructuringDecl) - { - pc->inDestructuringDecl = Nothing(); - if (saved_ && *saved_ == DeclarationKind::FormalParameter) - pc->functionBox()->hasParameterExprs = true; - } - - ~AutoClearInDestructuringDecl() { - pc_->inDestructuringDecl = saved_; - } -}; - template typename ParseHandler::Node Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandling, @@ -8170,7 +8396,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl return null(); } - if (!checkDestructuringPattern(lhs, Nothing(), &possibleErrorInner)) + if (!checkDestructuringAssignmentPattern(lhs, &possibleErrorInner)) return null(); } else if (handler.isNameAnyParentheses(lhs)) { if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(lhs, context)) { @@ -9505,7 +9731,7 @@ Parser::computedPropertyName(YieldHandling yieldHandling, Node lit // Turn off the inDestructuringDecl flag when parsing computed property // names. In short, when parsing 'let {[x + y]: z} = obj;', noteUsedName() // should be called on x and y, but not on z. See the comment on - // Parser<>::checkDestructuringPattern() for details. + // Parser<>::checkDestructuringAssignmentPattern() for details. AutoClearInDestructuringDecl autoClear(pc); assignNode = assignExpr(InAllowed, yieldHandling, TripledotProhibited); if (!assignNode) @@ -9593,8 +9819,8 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* } } else if (propType == PropertyType::Shorthand) { /* - * Support, e.g., |var {x, y} = o| as destructuring shorthand - * for |var {x: x, y: y} = o|, and |var o = {x, y}| as initializer + * Support, e.g., |({x, y} = o)| as destructuring shorthand + * for |({x: x, y: y} = o)|, and |var o = {x, y}| as initializer * shorthand for |var o = {x: x, y: y}|. */ Rooted name(context, identifierReference(yieldHandling)); @@ -9609,7 +9835,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* return null(); } else if (propType == PropertyType::CoverInitializedName) { /* - * Support, e.g., |var {x=1, y=2} = o| as destructuring shorthand + * Support, e.g., |({x=1, y=2} = o)| as destructuring shorthand * with default values, as per ES6 12.14.5 */ Rooted name(context, identifierReference(yieldHandling)); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index b1d3bdee0..9b6387c9f 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1498,17 +1498,25 @@ class Parser final : public ParserBase, private JS::AutoGCRooter Node objectLiteral(YieldHandling yieldHandling, PossibleError* possibleError); - // Top-level entrypoint into destructuring pattern checking/name-analyzing. - bool checkDestructuringPattern(Node pattern, mozilla::Maybe maybeDecl, - PossibleError* possibleError = nullptr); - - // Recursive methods for checking/name-analyzing subcomponents of a - // destructuring pattern. The array/object methods *must* be passed arrays - // or objects. The name method may be passed anything but will report an - // error if not passed a name. - bool checkDestructuringArray(Node arrayPattern, mozilla::Maybe maybeDecl); - bool checkDestructuringObject(Node objectPattern, mozilla::Maybe maybeDecl); - bool checkDestructuringName(Node expr, mozilla::Maybe maybeDecl); + Node bindingInitializer(Node lhs, YieldHandling yieldHandling); + Node bindingIdentifier(DeclarationKind kind, YieldHandling yieldHandling); + Node bindingIdentifierOrPattern(DeclarationKind kind, YieldHandling yieldHandling, + TokenKind tt); + Node objectBindingPattern(DeclarationKind kind, YieldHandling yieldHandling); + Node arrayBindingPattern(DeclarationKind kind, YieldHandling yieldHandling); + + // Top-level entrypoint into destructuring assignment pattern checking and + // name-analyzing. + bool checkDestructuringAssignmentPattern(Node pattern, + PossibleError* possibleError = nullptr); + + // Recursive methods for checking/name-analyzing subcomponents of an + // destructuring assignment pattern. The array/object methods *must* be + // passed arrays or objects. The name method may be passed anything but + // will report an error if not passed a name. + bool checkDestructuringAssignmentArray(Node arrayPattern); + bool checkDestructuringAssignmentObject(Node objectPattern); + bool checkDestructuringAssignmentName(Node expr); Node newNumber(const Token& tok) { return handler.newNumber(tok.number(), tok.decimalPoint(), tok.pos); -- cgit v1.2.3 From 55c897db3c504c10650b94d97bb13ed79b0e23c6 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 14 Jul 2019 13:05:27 -0400 Subject: 1303703 - Part 2: Clean-up bits of destructuring parsing which are no longer needed. --- js/src/frontend/Parser.cpp | 151 +++++++++++++++------------------------------ js/src/frontend/Parser.h | 19 ++---- 2 files changed, 54 insertions(+), 116 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 85f7ee846..16eb7d85c 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -4363,20 +4363,6 @@ Parser::checkDestructuringAssignmentArray(ParseNode* arrayPatt * In the first case, other code parses the pattern as an arbitrary * primaryExpr, and then, here in checkDestructuringAssignmentPattern, verify * that the tree is a valid AssignmentPattern. - * - * In assignment-like contexts, we parse the pattern with - * pc->inDestructuringDecl clear, so the lvalue expressions in the pattern are - * parsed normally. identifierReference() links variable references into the - * appropriate use chains; creates placeholder definitions; and so on. - * checkDestructuringAssignmentPattern won't bind any new names and we - * specialize lvalues as appropriate. - * - * In declaration-like contexts, the normal variable reference processing - * would just be an obstruction, because we're going to define the names that - * appear in the property value positions as new variables anyway. In this - * case, we parse the pattern in destructuringDeclaration() with - * pc->inDestructuringDecl set, which directs identifierReference() to leave - * whatever name nodes it creates unconnected. */ template <> bool @@ -4399,39 +4385,19 @@ Parser::checkDestructuringAssignmentPattern(ParseNode* pattern return isDestructuring; } -class AutoClearInDestructuringDecl -{ - ParseContext* pc_; - Maybe saved_; - - public: - explicit AutoClearInDestructuringDecl(ParseContext* pc) - : pc_(pc), - saved_(pc->inDestructuringDecl) - { - pc->inDestructuringDecl = Nothing(); - if (saved_ && *saved_ == DeclarationKind::FormalParameter) - pc->functionBox()->hasParameterExprs = true; - } - - ~AutoClearInDestructuringDecl() { - pc_->inDestructuringDecl = saved_; - } -}; - template typename ParseHandler::Node -Parser::bindingInitializer(Node lhs, YieldHandling yieldHandling) +Parser::bindingInitializer(Node lhs, DeclarationKind kind, + YieldHandling yieldHandling) { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_ASSIGN)); - Node rhs; - { - AutoClearInDestructuringDecl autoClear(pc); - rhs = assignExpr(InAllowed, yieldHandling, TripledotProhibited); - if (!rhs) - return null(); - } + if (kind == DeclarationKind::FormalParameter) + pc->functionBox()->hasParameterExprs = true; + + Node rhs = assignExpr(InAllowed, yieldHandling, TripledotProhibited); + if (!rhs) + return null(); handler.checkAndSetIsDirectRHSAnonFunction(rhs); @@ -4449,7 +4415,7 @@ template typename ParseHandler::Node Parser::bindingIdentifier(DeclarationKind kind, YieldHandling yieldHandling) { - Rooted name(context, bindingIdentifier(yieldHandling)); + RootedPropertyName name(context, bindingIdentifier(yieldHandling)); if (!name) return null(); @@ -4492,6 +4458,7 @@ Parser::objectBindingPattern(DeclarationKind kind, YieldHandling y if (!literal) return null(); + Maybe declKind = Some(kind); RootedAtom propAtom(context); for (;;) { TokenKind tt; @@ -4505,7 +4472,7 @@ Parser::objectBindingPattern(DeclarationKind kind, YieldHandling y tokenStream.ungetToken(); PropertyType propType; - Node propName = propertyName(yieldHandling, literal, &propType, &propAtom); + Node propName = propertyName(yieldHandling, declKind, literal, &propType, &propAtom); if (!propName) return null(); @@ -4524,7 +4491,7 @@ Parser::objectBindingPattern(DeclarationKind kind, YieldHandling y return null(); Node bindingExpr = hasInitializer - ? bindingInitializer(binding, yieldHandling) + ? bindingInitializer(binding, kind, yieldHandling) : binding; if (!bindingExpr) return null(); @@ -4553,7 +4520,7 @@ Parser::objectBindingPattern(DeclarationKind kind, YieldHandling y tokenStream.consumeKnownToken(TOK_ASSIGN); - Node bindingExpr = bindingInitializer(binding, yieldHandling); + Node bindingExpr = bindingInitializer(binding, kind, yieldHandling); if (!bindingExpr) return null(); @@ -4633,7 +4600,9 @@ Parser::arrayBindingPattern(DeclarationKind kind, YieldHandling yi if (!tokenStream.matchToken(&hasInitializer, TOK_ASSIGN)) return null(); - Node element = hasInitializer ? bindingInitializer(binding, yieldHandling) : binding; + Node element = hasInitializer + ? bindingInitializer(binding, kind, yieldHandling) + : binding; if (!element) return null(); @@ -4680,17 +4649,9 @@ Parser::destructuringDeclaration(DeclarationKind kind, YieldHandli MOZ_ASSERT(tokenStream.isCurrentTokenType(tt)); MOZ_ASSERT(tt == TOK_LB || tt == TOK_LC); - Node pattern; - { - pc->inDestructuringDecl = Some(kind); - if (tt == TOK_LB) - pattern = arrayBindingPattern(kind, yieldHandling); - else - pattern = objectBindingPattern(kind, yieldHandling); - pc->inDestructuringDecl = Nothing(); - } - - return pattern; + return tt == TOK_LB + ? arrayBindingPattern(kind, yieldHandling) + : objectBindingPattern(kind, yieldHandling); } template @@ -7066,14 +7027,10 @@ Parser::tryStatement(YieldHandling yieldHandling) return null(); } - RootedPropertyName param(context, bindingIdentifier(yieldHandling)); - if (!param) - return null(); - catchName = newName(param); + catchName = bindingIdentifier(DeclarationKind::SimpleCatchParameter, + yieldHandling); if (!catchName) return null(); - if (!noteDeclaredName(param, DeclarationKind::SimpleCatchParameter, pos())) - return null(); break; } } @@ -7301,6 +7258,7 @@ Parser::classDefinition(YieldHandling yieldHandling, if (!classMethods) return null(); + Maybe declKind = Nothing(); for (;;) { TokenKind tt; if (!tokenStream.getToken(&tt)) @@ -7335,7 +7293,7 @@ Parser::classDefinition(YieldHandling yieldHandling, return null(); PropertyType propType; - Node propName = propertyName(yieldHandling, classMethods, &propType, &propAtom); + Node propName = propertyName(yieldHandling, declKind, classMethods, &propType, &propAtom); if (!propName) return null(); @@ -8419,13 +8377,9 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl if (!possibleErrorInner.checkForExpressionError()) return null(); - Node rhs; - { - AutoClearInDestructuringDecl autoClear(pc); - rhs = assignExpr(inHandling, yieldHandling, TripledotProhibited); - if (!rhs) - return null(); - } + Node rhs = assignExpr(inHandling, yieldHandling, TripledotProhibited); + if (!rhs) + return null(); if (kind == PNK_ASSIGN) handler.checkAndSetIsDirectRHSAnonFunction(rhs); @@ -9370,7 +9324,7 @@ Parser::identifierReference(Handle name) if (!pn) return null(); - if (!pc->inDestructuringDecl && !noteUsedName(name)) + if (!noteUsedName(name)) return null(); return pn; @@ -9533,7 +9487,8 @@ DoubleToAtom(ExclusiveContext* cx, double value) template typename ParseHandler::Node -Parser::propertyName(YieldHandling yieldHandling, Node propList, +Parser::propertyName(YieldHandling yieldHandling, + const Maybe& maybeDecl, Node propList, PropertyType* propType, MutableHandleAtom propAtom) { TokenKind ltok; @@ -9594,7 +9549,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, break; case TOK_LB: - propName = computedPropertyName(yieldHandling, propList); + propName = computedPropertyName(yieldHandling, maybeDecl, propList); if (!propName) return null(); break; @@ -9652,7 +9607,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, if (tt == TOK_LB) { tokenStream.consumeKnownToken(TOK_LB); - return computedPropertyName(yieldHandling, propList); + return computedPropertyName(yieldHandling, maybeDecl, propList); } // Not an accessor property after all. @@ -9722,28 +9677,25 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, template typename ParseHandler::Node -Parser::computedPropertyName(YieldHandling yieldHandling, Node literal) +Parser::computedPropertyName(YieldHandling yieldHandling, + const Maybe& maybeDecl, + Node literal) { uint32_t begin = pos().begin; - Node assignNode; - { - // Turn off the inDestructuringDecl flag when parsing computed property - // names. In short, when parsing 'let {[x + y]: z} = obj;', noteUsedName() - // should be called on x and y, but not on z. See the comment on - // Parser<>::checkDestructuringAssignmentPattern() for details. - AutoClearInDestructuringDecl autoClear(pc); - assignNode = assignExpr(InAllowed, yieldHandling, TripledotProhibited); - if (!assignNode) - return null(); + if (maybeDecl) { + if (*maybeDecl == DeclarationKind::FormalParameter) + pc->functionBox()->hasParameterExprs = true; + } else { + handler.setListFlag(literal, PNX_NONCONST); } - MUST_MATCH_TOKEN(TOK_RB, JSMSG_COMP_PROP_UNTERM_EXPR); - Node propname = handler.newComputedName(assignNode, begin, pos().end); - if (!propname) + Node assignNode = assignExpr(InAllowed, yieldHandling, TripledotProhibited); + if (!assignNode) return null(); - handler.setListFlag(literal, PNX_NONCONST); - return propname; + + MUST_MATCH_TOKEN(TOK_RB, JSMSG_COMP_PROP_UNTERM_EXPR); + return handler.newComputedName(assignNode, begin, pos().end); } template @@ -9760,6 +9712,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* bool seenPrototypeMutation = false; bool seenCoverInitializedName = false; + Maybe declKind = Nothing(); RootedAtom propAtom(context); for (;;) { TokenKind tt; @@ -9773,7 +9726,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* tokenStream.ungetToken(); PropertyType propType; - Node propName = propertyName(yieldHandling, literal, &propType, &propAtom); + Node propName = propertyName(yieldHandling, declKind, literal, &propType, &propAtom); if (!propName) return null(); @@ -9867,15 +9820,9 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* possibleError->setPendingExpressionErrorAt(pos(), JSMSG_COLON_AFTER_ID); } - Node rhs; - { - // Clearing `inDestructuringDecl` allows name use to be noted - // in Parser::identifierReference. See bug 1255167. - AutoClearInDestructuringDecl autoClear(pc); - rhs = assignExpr(InAllowed, yieldHandling, TripledotProhibited); - if (!rhs) - return null(); - } + Node rhs = assignExpr(InAllowed, yieldHandling, TripledotProhibited); + if (!rhs) + return null(); handler.checkAndSetIsDirectRHSAnonFunction(rhs); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 9b6387c9f..8bd691fc4 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -340,17 +340,6 @@ class ParseContext : public Nestable // pointer may be nullptr. Directives* newDirectives; - // Set when parsing a declaration-like destructuring pattern. This flag - // causes PrimaryExpr to create PN_NAME parse nodes for variable references - // which are not hooked into any definition's use chain, added to any tree - // context's AtomList, etc. etc. checkDestructuring will do that work - // later. - // - // The comments atop checkDestructuring explain the distinction between - // assignment-like and declaration-like destructuring patterns, and why - // they need to be treated differently. - mozilla::Maybe inDestructuringDecl; - // Set when parsing a function and it has 'return ;' bool funHasReturnExpr; @@ -1490,15 +1479,17 @@ class Parser final : public ParserBase, private JS::AutoGCRooter mozilla::Maybe newLexicalScopeData(ParseContext::Scope& scope); Node finishLexicalScope(ParseContext::Scope& scope, Node body); - Node propertyName(YieldHandling yieldHandling, Node propList, + Node propertyName(YieldHandling yieldHandling, + const mozilla::Maybe& maybeDecl, Node propList, PropertyType* propType, MutableHandleAtom propAtom); - Node computedPropertyName(YieldHandling yieldHandling, Node literal); + Node computedPropertyName(YieldHandling yieldHandling, + const mozilla::Maybe& maybeDecl, Node literal); Node arrayInitializer(YieldHandling yieldHandling, PossibleError* possibleError); Node newRegExp(); Node objectLiteral(YieldHandling yieldHandling, PossibleError* possibleError); - Node bindingInitializer(Node lhs, YieldHandling yieldHandling); + Node bindingInitializer(Node lhs, DeclarationKind kind, YieldHandling yieldHandling); Node bindingIdentifier(DeclarationKind kind, YieldHandling yieldHandling); Node bindingIdentifierOrPattern(DeclarationKind kind, YieldHandling yieldHandling, TokenKind tt); -- cgit v1.2.3 From a4b91b5a8faf9dc09db252c89921775910f1c233 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 14 Jul 2019 13:39:17 -0400 Subject: 1303703 - Part 3: Syntax parse destructuring assignment patterns. --- js/src/frontend/FullParseHandler.h | 6 +- js/src/frontend/Parser.cpp | 333 +++++++++++++++++------------------ js/src/frontend/Parser.h | 53 +++--- js/src/frontend/SyntaxParseHandler.h | 6 +- js/src/js.msg | 2 + 5 files changed, 202 insertions(+), 198 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index 7ddd8d306..c7a7e0843 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -878,6 +878,10 @@ class FullParseHandler return node->isKind(PNK_NAME); } + bool isArgumentsAnyParentheses(ParseNode* node, ExclusiveContext* cx) { + return node->isKind(PNK_NAME) && node->pn_atom == cx->names().arguments; + } + bool isEvalAnyParentheses(ParseNode* node, ExclusiveContext* cx) { return node->isKind(PNK_NAME) && node->pn_atom == cx->names().eval; } @@ -888,7 +892,7 @@ class FullParseHandler if (isEvalAnyParentheses(node, cx)) return js_eval_str; - if (node->pn_atom == cx->names().arguments) + if (isArgumentsAnyParentheses(node, cx)) return js_arguments_str; return nullptr; } diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 16eb7d85c..c1e165db5 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -689,6 +689,19 @@ ParserBase::extraWarning(unsigned errorNumber, ...) return result; } +bool +ParserBase::extraWarningAt(uint32_t offset, unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); + + bool result = + tokenStream.reportExtraWarningErrorNumberVA(nullptr, offset, errorNumber, args); + + va_end(args); + return result; +} + bool ParserBase::strictModeError(unsigned errorNumber, ...) { @@ -743,14 +756,6 @@ ParserBase::reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumb return result; } -template <> -bool -Parser::abortIfSyntaxParser() -{ - handler.disableSyntaxParser(); - return true; -} - template <> bool Parser::abortIfSyntaxParser() @@ -4128,8 +4133,17 @@ Parser::PossibleError::error(ErrorKind kind) { if (kind == ErrorKind::Expression) return exprError_; - MOZ_ASSERT(kind == ErrorKind::Destructuring); - return destructuringError_; + if (kind == ErrorKind::Destructuring) + return destructuringError_; + MOZ_ASSERT(kind == ErrorKind::DestructuringWarning); + return destructuringWarning_; +} + +template +bool +Parser::PossibleError::hasPendingDestructuringError() +{ + return hasError(ErrorKind::Destructuring); } template @@ -4171,6 +4185,14 @@ Parser::PossibleError::setPendingDestructuringErrorAt(const TokenP setPending(ErrorKind::Destructuring, pos, errorNumber); } +template +void +Parser::PossibleError::setPendingDestructuringWarningAt(const TokenPos& pos, + unsigned errorNumber) +{ + setPending(ErrorKind::DestructuringWarning, pos, errorNumber); +} + template void Parser::PossibleError::setPendingExpressionErrorAt(const TokenPos& pos, @@ -4193,23 +4215,36 @@ Parser::PossibleError::checkForError(ErrorKind kind) template bool -Parser::PossibleError::checkForDestructuringError() +Parser::PossibleError::checkForWarning(ErrorKind kind) +{ + if (!hasError(kind)) + return true; + + Error& err = error(kind); + return parser_.extraWarningAt(err.offset_, err.errorNumber_); +} + +template +bool +Parser::PossibleError::checkForDestructuringErrorOrWarning() { // Clear pending expression error, because we're definitely not in an // expression context. setResolved(ErrorKind::Expression); - // Report any pending destructuring error. - return checkForError(ErrorKind::Destructuring); + // Report any pending destructuring error or warning. + return checkForError(ErrorKind::Destructuring) && + checkForWarning(ErrorKind::DestructuringWarning); } template bool Parser::PossibleError::checkForExpressionError() { - // Clear pending destructuring error, because we're definitely not in a - // destructuring context. + // Clear pending destructuring error or warning, because we're definitely + // not in a destructuring context. setResolved(ErrorKind::Destructuring); + setResolved(ErrorKind::DestructuringWarning); // Report any pending expression error. return checkForError(ErrorKind::Expression); @@ -4241,150 +4276,6 @@ Parser::PossibleError::transferErrorsTo(PossibleError* other) transferErrorTo(ErrorKind::Expression, other); } -template <> -bool -Parser::checkDestructuringAssignmentName(ParseNode* expr) -{ - MOZ_ASSERT(!handler.isUnparenthesizedDestructuringPattern(expr)); - - // Parentheses are forbidden around destructuring *patterns* (but allowed - // around names). Use our nicer error message for parenthesized, nested - // patterns. - if (handler.isParenthesizedDestructuringPattern(expr)) { - errorAt(expr->pn_pos.begin, JSMSG_BAD_DESTRUCT_PARENS); - return false; - } - - // The expression must be a simple assignment target, i.e. either a name - // or a property accessor. - if (handler.isNameAnyParentheses(expr)) { - if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(expr, context)) { - if (!strictModeErrorAt(expr->pn_pos.begin, JSMSG_BAD_STRICT_ASSIGN, chars)) - return false; - } - - return true; - } - - if (handler.isPropertyAccess(expr)) - return true; - - errorAt(expr->pn_pos.begin, JSMSG_BAD_DESTRUCT_TARGET); - return false; -} - -template <> -bool -Parser::checkDestructuringAssignmentPattern(ParseNode* pattern, - PossibleError* possibleError /* = nullptr */); - -template <> -bool -Parser::checkDestructuringAssignmentObject(ParseNode* objectPattern) -{ - MOZ_ASSERT(objectPattern->isKind(PNK_OBJECT)); - - for (ParseNode* member = objectPattern->pn_head; member; member = member->pn_next) { - ParseNode* target; - if (member->isKind(PNK_MUTATEPROTO)) { - target = member->pn_kid; - } else { - MOZ_ASSERT(member->isKind(PNK_COLON) || member->isKind(PNK_SHORTHAND)); - MOZ_ASSERT_IF(member->isKind(PNK_SHORTHAND), - member->pn_left->isKind(PNK_OBJECT_PROPERTY_NAME) && - member->pn_right->isKind(PNK_NAME) && - member->pn_left->pn_atom == member->pn_right->pn_atom); - - target = member->pn_right; - } - if (handler.isUnparenthesizedAssignment(target)) - target = target->pn_left; - - if (handler.isUnparenthesizedDestructuringPattern(target)) { - if (!checkDestructuringAssignmentPattern(target)) - return false; - } else { - if (!checkDestructuringAssignmentName(target)) - return false; - } - } - - return true; -} - -template <> -bool -Parser::checkDestructuringAssignmentArray(ParseNode* arrayPattern) -{ - MOZ_ASSERT(arrayPattern->isKind(PNK_ARRAY)); - - for (ParseNode* element = arrayPattern->pn_head; element; element = element->pn_next) { - if (element->isKind(PNK_ELISION)) - continue; - - ParseNode* target; - if (element->isKind(PNK_SPREAD)) { - if (element->pn_next) { - errorAt(element->pn_next->pn_pos.begin, JSMSG_PARAMETER_AFTER_REST); - return false; - } - target = element->pn_kid; - } else if (handler.isUnparenthesizedAssignment(element)) { - target = element->pn_left; - } else { - target = element; - } - - if (handler.isUnparenthesizedDestructuringPattern(target)) { - if (!checkDestructuringAssignmentPattern(target)) - return false; - } else { - if (!checkDestructuringAssignmentName(target)) - return false; - } - } - - return true; -} - -/* - * Destructuring patterns can appear in two kinds of contexts: - * - * - assignment-like: assignment expressions and |for| loop heads. In - * these cases, the patterns' property value positions can be - * arbitrary lvalue expressions; the destructuring is just a fancy - * assignment. - * - * - binding-like: |var| and |let| declarations, functions' formal - * parameter lists, |catch| clauses, and comprehension tails. In - * these cases, the patterns' property value positions must be - * simple names; the destructuring defines them as new variables. - * - * In the first case, other code parses the pattern as an arbitrary - * primaryExpr, and then, here in checkDestructuringAssignmentPattern, verify - * that the tree is a valid AssignmentPattern. - */ -template <> -bool -Parser::checkDestructuringAssignmentPattern(ParseNode* pattern, - PossibleError* possibleError /* = nullptr */) -{ - if (pattern->isKind(PNK_ARRAYCOMP)) { - errorAt(pattern->pn_pos.begin, JSMSG_ARRAY_COMP_LEFTSIDE); - return false; - } - - bool isDestructuring = pattern->isKind(PNK_ARRAY) - ? checkDestructuringAssignmentArray(pattern) - : checkDestructuringAssignmentObject(pattern); - - // Report any pending destructuring error. - if (isDestructuring && possibleError && !possibleError->checkForDestructuringError()) - return false; - - return isDestructuring; -} - template typename ParseHandler::Node Parser::bindingInitializer(Node lhs, DeclarationKind kind, @@ -5153,14 +5044,6 @@ Parser::namedImportsOrNamespaceImport(TokenKind tt, Node impor return true; } -template<> -bool -Parser::namedImportsOrNamespaceImport(TokenKind tt, Node importSpecSet) -{ - MOZ_ALWAYS_FALSE(abortIfSyntaxParser()); - return false; -} - template<> ParseNode* Parser::importDeclaration() @@ -6182,7 +6065,7 @@ Parser::forHeadStart(YieldHandling yieldHandling, // Verify the left-hand side expression doesn't have a forbidden form. if (handler.isUnparenthesizedDestructuringPattern(*forInitialPart)) { - if (!checkDestructuringAssignmentPattern(*forInitialPart, &possibleError)) + if (!possibleError.checkForDestructuringErrorOrWarning()) return false; } else if (handler.isNameAnyParentheses(*forInitialPart)) { const char* chars = handler.nameIsArgumentsEvalAnyParentheses(*forInitialPart, context); @@ -8148,7 +8031,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); - uint32_t exprOffset = pos().begin; + TokenPos exprPos = pos(); bool endsExpr; @@ -8354,12 +8237,12 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl return null(); } - if (!checkDestructuringAssignmentPattern(lhs, &possibleErrorInner)) + if (!possibleErrorInner.checkForDestructuringErrorOrWarning()) return null(); } else if (handler.isNameAnyParentheses(lhs)) { if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(lhs, context)) { // |chars| is "arguments" or "eval" here. - if (!strictModeErrorAt(exprOffset, JSMSG_BAD_STRICT_ASSIGN, chars)) + if (!strictModeErrorAt(exprPos.begin, JSMSG_BAD_STRICT_ASSIGN, chars)) return null(); } @@ -8367,10 +8250,13 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl } else if (handler.isPropertyAccess(lhs)) { // Permitted: no additional testing/fixup needed. } else if (handler.isFunctionCall(lhs)) { - if (!strictModeErrorAt(exprOffset, JSMSG_BAD_LEFTSIDE_OF_ASS)) + if (!strictModeErrorAt(exprPos.begin, JSMSG_BAD_LEFTSIDE_OF_ASS)) return null(); + + if (possibleError) + possibleError->setPendingDestructuringErrorAt(exprPos, JSMSG_BAD_DESTRUCT_TARGET); } else { - errorAt(exprOffset, JSMSG_BAD_LEFTSIDE_OF_ASS); + errorAt(exprPos.begin, JSMSG_BAD_LEFTSIDE_OF_ASS); return null(); } @@ -9390,6 +9276,74 @@ Parser::newRegExp() return handler.newRegExp(reobj, pos(), *this); } +template +void +Parser::checkDestructuringAssignmentTarget(Node expr, TokenPos exprPos, + PossibleError* possibleError) +{ + // Return early if a pending destructuring error is already present. + if (possibleError->hasPendingDestructuringError()) + return; + + if (pc->sc()->needStrictChecks()) { + if (handler.isArgumentsAnyParentheses(expr, context)) { + if (pc->sc()->strict()) { + possibleError->setPendingDestructuringErrorAt(exprPos, + JSMSG_BAD_STRICT_ASSIGN_ARGUMENTS); + } else { + possibleError->setPendingDestructuringWarningAt(exprPos, + JSMSG_BAD_STRICT_ASSIGN_ARGUMENTS); + } + return; + } + + if (handler.isEvalAnyParentheses(expr, context)) { + if (pc->sc()->strict()) { + possibleError->setPendingDestructuringErrorAt(exprPos, + JSMSG_BAD_STRICT_ASSIGN_EVAL); + } else { + possibleError->setPendingDestructuringWarningAt(exprPos, + JSMSG_BAD_STRICT_ASSIGN_EVAL); + } + return; + } + } + + // The expression must be either a simple assignment target, i.e. a name + // or a property accessor, or a nested destructuring pattern. + if (!handler.isUnparenthesizedDestructuringPattern(expr) && + !handler.isNameAnyParentheses(expr) && + !handler.isPropertyAccess(expr)) + { + // Parentheses are forbidden around destructuring *patterns* (but + // allowed around names). Use our nicer error message for + // parenthesized, nested patterns. + if (handler.isParenthesizedDestructuringPattern(expr)) + possibleError->setPendingDestructuringErrorAt(exprPos, JSMSG_BAD_DESTRUCT_PARENS); + else + possibleError->setPendingDestructuringErrorAt(exprPos, JSMSG_BAD_DESTRUCT_TARGET); + } +} + +template +void +Parser::checkDestructuringAssignmentElement(Node expr, TokenPos exprPos, + PossibleError* possibleError) +{ + // ES2018 draft rev 0719f44aab93215ed9a626b2f45bd34f36916834 + // 12.15.5 Destructuring Assignment + // + // AssignmentElement[Yield, Await]: + // DestructuringAssignmentTarget[?Yield, ?Await] + // DestructuringAssignmentTarget[?Yield, ?Await] Initializer[+In, ?Yield, ?Await] + + // If |expr| is an assignment element with an initializer expression, its + // destructuring assignment target was already validated in assignExpr(). + // Otherwise we need to check that |expr| is a valid destructuring target. + if (!handler.isUnparenthesizedAssignment(expr)) + checkDestructuringAssignmentTarget(expr, exprPos, possibleError); +} + template typename ParseHandler::Node Parser::arrayInitializer(YieldHandling yieldHandling, PossibleError* possibleError) @@ -9439,17 +9393,29 @@ Parser::arrayInitializer(YieldHandling yieldHandling, PossibleErro } else if (tt == TOK_TRIPLEDOT) { tokenStream.consumeKnownToken(TOK_TRIPLEDOT, TokenStream::Operand); uint32_t begin = pos().begin; + + TokenPos innerPos; + if (!tokenStream.peekTokenPos(&innerPos, TokenStream::Operand)) + return null(); + Node inner = assignExpr(InAllowed, yieldHandling, TripledotProhibited, possibleError); if (!inner) return null(); + if (possibleError) + checkDestructuringAssignmentTarget(inner, innerPos, possibleError); if (!handler.addSpreadElement(literal, begin, inner)) return null(); } else { + TokenPos elementPos; + if (!tokenStream.peekTokenPos(&elementPos, TokenStream::Operand)) + return null(); Node element = assignExpr(InAllowed, yieldHandling, TripledotProhibited, possibleError); if (!element) return null(); + if (possibleError) + checkDestructuringAssignmentElement(element, elementPos, possibleError); if (foldConstants && !FoldConstants(context, &element, this)) return null(); handler.addArrayElement(literal, element); @@ -9731,6 +9697,9 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* return null(); if (propType == PropertyType::Normal) { + TokenPos exprPos; + if (!tokenStream.peekTokenPos(&exprPos, TokenStream::Operand)) + return null(); Node propExpr = assignExpr(InAllowed, yieldHandling, TripledotProhibited, possibleError); if (!propExpr) @@ -9770,6 +9739,9 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* if (!handler.addPropertyDefinition(literal, propName, propExpr)) return null(); } + + if (possibleError) + checkDestructuringAssignmentElement(propExpr, exprPos, possibleError); } else if (propType == PropertyType::Shorthand) { /* * Support, e.g., |({x, y} = o)| as destructuring shorthand @@ -9784,6 +9756,9 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* if (!nameExpr) return null(); + if (possibleError) + checkDestructuringAssignmentTarget(nameExpr, namePos, possibleError); + if (!handler.addShorthand(literal, propName, nameExpr)) return null(); } else if (propType == PropertyType::CoverInitializedName) { @@ -9820,6 +9795,12 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* possibleError->setPendingExpressionErrorAt(pos(), JSMSG_COLON_AFTER_ID); } + if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(lhs, context)) { + // |chars| is "arguments" or "eval" here. + if (!strictModeErrorAt(namePos.begin, JSMSG_BAD_STRICT_ASSIGN, chars)) + return null(); + } + Node rhs = assignExpr(InAllowed, yieldHandling, TripledotProhibited); if (!rhs) return null(); @@ -9832,9 +9813,6 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* if (!handler.addPropertyDefinition(literal, propName, propExpr)) return null(); - - if (!abortIfSyntaxParser()) - return null(); } else { RootedAtom funName(context); if (!tokenStream.isCurrentTokenType(TOK_RB)) { @@ -9856,6 +9834,9 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* JSOp op = JSOpFromPropertyType(propType); if (!handler.addObjectMethodDefinition(literal, propName, fn, op)) return null(); + + if (possibleError) + possibleError->setPendingDestructuringErrorAt(namePos, JSMSG_BAD_DESTRUCT_TARGET); } if (!tokenStream.getToken(&tt)) diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 8bd691fc4..88d2dad18 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -877,6 +877,12 @@ class ParserBase : public StrictModeGetter */ MOZ_MUST_USE bool extraWarning(unsigned errorNumber, ...); + /* + * If extra warnings are enabled, report the given warning at the given + * offset. + */ + MOZ_MUST_USE bool extraWarningAt(uint32_t offset, unsigned errorNumber, ...); + bool isValidStrictBinding(PropertyName* name); bool warnOnceAboutExprClosure(); @@ -941,7 +947,7 @@ class Parser final : public ParserBase, private JS::AutoGCRooter class MOZ_STACK_CLASS PossibleError { private: - enum class ErrorKind { Expression, Destructuring }; + enum class ErrorKind { Expression, Destructuring, DestructuringWarning }; enum class ErrorState { None, Pending }; @@ -956,11 +962,12 @@ class Parser final : public ParserBase, private JS::AutoGCRooter Parser& parser_; Error exprError_; Error destructuringError_; + Error destructuringWarning_; // Returns the error report. Error& error(ErrorKind kind); - // Return true if an error is pending without reporting + // Return true if an error is pending without reporting. bool hasError(ErrorKind kind); // Resolve any pending error. @@ -972,7 +979,11 @@ class Parser final : public ParserBase, private JS::AutoGCRooter // If there is a pending error, report it and return false, otherwise // return true. - bool checkForError(ErrorKind kind); + MOZ_MUST_USE bool checkForError(ErrorKind kind); + + // If there is a pending warning, report it and return either false or + // true depending on the werror option, otherwise return true. + MOZ_MUST_USE bool checkForWarning(ErrorKind kind); // Transfer an existing error to another instance. void transferErrorTo(ErrorKind kind, PossibleError* other); @@ -980,23 +991,33 @@ class Parser final : public ParserBase, private JS::AutoGCRooter public: explicit PossibleError(Parser& parser); + // Return true if a pending destructuring error is present. + bool hasPendingDestructuringError(); + // Set a pending destructuring error. Only a single error may be set // per instance, i.e. subsequent calls to this method are ignored and // won't overwrite the existing pending error. void setPendingDestructuringErrorAt(const TokenPos& pos, unsigned errorNumber); + // Set a pending destructuring warning. Only a single warning may be + // set per instance, i.e. subsequent calls to this method are ignored + // and won't overwrite the existing pending warning. + void setPendingDestructuringWarningAt(const TokenPos& pos, unsigned errorNumber); + // Set a pending expression error. Only a single error may be set per // instance, i.e. subsequent calls to this method are ignored and won't // overwrite the existing pending error. void setPendingExpressionErrorAt(const TokenPos& pos, unsigned errorNumber); - // If there is a pending destructuring error, report it and return - // false, otherwise return true. Clears any pending expression error. - bool checkForDestructuringError(); + // If there is a pending destructuring error or warning, report it and + // return false, otherwise return true. Clears any pending expression + // error. + MOZ_MUST_USE bool checkForDestructuringErrorOrWarning(); // If there is a pending expression error, report it and return false, - // otherwise return true. Clears any pending destructuring error. - bool checkForExpressionError(); + // otherwise return true. Clears any pending destructuring error or + // warning. + MOZ_MUST_USE bool checkForExpressionError(); // Pass pending errors between possible error instances. This is useful // for extending the lifetime of a pending error beyond the scope of @@ -1496,18 +1517,10 @@ class Parser final : public ParserBase, private JS::AutoGCRooter Node objectBindingPattern(DeclarationKind kind, YieldHandling yieldHandling); Node arrayBindingPattern(DeclarationKind kind, YieldHandling yieldHandling); - // Top-level entrypoint into destructuring assignment pattern checking and - // name-analyzing. - bool checkDestructuringAssignmentPattern(Node pattern, - PossibleError* possibleError = nullptr); - - // Recursive methods for checking/name-analyzing subcomponents of an - // destructuring assignment pattern. The array/object methods *must* be - // passed arrays or objects. The name method may be passed anything but - // will report an error if not passed a name. - bool checkDestructuringAssignmentArray(Node arrayPattern); - bool checkDestructuringAssignmentObject(Node objectPattern); - bool checkDestructuringAssignmentName(Node expr); + void checkDestructuringAssignmentTarget(Node expr, TokenPos exprPos, + PossibleError* possibleError); + void checkDestructuringAssignmentElement(Node expr, TokenPos exprPos, + PossibleError* possibleError); Node newNumber(const Token& tok) { return handler.newNumber(tok.number(), tok.decimalPoint(), tok.pos); diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index 895ba6416..7de6a242e 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -561,6 +561,10 @@ class SyntaxParseHandler node == NodeParenthesizedName; } + bool isArgumentsAnyParentheses(Node node, ExclusiveContext* cx) { + return node == NodeUnparenthesizedArgumentsName || node == NodeParenthesizedArgumentsName; + } + bool isEvalAnyParentheses(Node node, ExclusiveContext* cx) { return node == NodeUnparenthesizedEvalName || node == NodeParenthesizedEvalName; } @@ -571,7 +575,7 @@ class SyntaxParseHandler if (isEvalAnyParentheses(node, cx)) return js_eval_str; - if (node == NodeUnparenthesizedArgumentsName || node == NodeParenthesizedArgumentsName) + if (isArgumentsAnyParentheses(node, cx)) return js_arguments_str; return nullptr; } diff --git a/js/src/js.msg b/js/src/js.msg index ec49d06c9..f57b36a90 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -211,6 +211,8 @@ MSG_DEF(JSMSG_BAD_POW_LEFTSIDE, 0, JSEXN_SYNTAXERR, "unparenthesized unar MSG_DEF(JSMSG_BAD_PROP_ID, 0, JSEXN_SYNTAXERR, "invalid property id") MSG_DEF(JSMSG_BAD_RETURN_OR_YIELD, 1, JSEXN_SYNTAXERR, "{0} not in function") MSG_DEF(JSMSG_BAD_STRICT_ASSIGN, 1, JSEXN_SYNTAXERR, "'{0}' can't be defined or assigned to in strict mode code") +MSG_DEF(JSMSG_BAD_STRICT_ASSIGN_ARGUMENTS, 0, JSEXN_SYNTAXERR, "'arguments' can't be defined or assigned to in strict mode code") +MSG_DEF(JSMSG_BAD_STRICT_ASSIGN_EVAL, 0, JSEXN_SYNTAXERR, "'eval' can't be defined or assigned to in strict mode code") MSG_DEF(JSMSG_BAD_SWITCH, 0, JSEXN_SYNTAXERR, "invalid switch statement") MSG_DEF(JSMSG_BAD_SUPER, 0, JSEXN_SYNTAXERR, "invalid use of keyword 'super'") MSG_DEF(JSMSG_BAD_SUPERPROP, 1, JSEXN_SYNTAXERR, "use of super {0} accesses only valid within methods or eval code within methods") -- cgit v1.2.3 From aa65e8a189d81cba75f101d07ef591b751881fe8 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 14 Jul 2019 15:34:51 -0400 Subject: Refactor abortIfSyntaxParser after destructring --- js/src/frontend/Parser.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index c1e165db5..bbdffa064 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -757,7 +757,15 @@ ParserBase::reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumb } template <> -bool +inline bool +Parser::abortIfSyntaxParser() +{ + handler.disableSyntaxParser(); + return true; +} + +template <> +inline bool Parser::abortIfSyntaxParser() { abortedSyntaxParse = true; @@ -4524,14 +4532,6 @@ Parser::arrayBindingPattern(DeclarationKind kind, YieldHandling yi return literal; } -template <> -bool -Parser::checkDestructuringAssignmentPattern(Node pattern, - PossibleError* possibleError /* = nullptr */) -{ - return abortIfSyntaxParser(); -} - template typename ParseHandler::Node Parser::destructuringDeclaration(DeclarationKind kind, YieldHandling yieldHandling, -- cgit v1.2.3 From 449ea84dcc7dffb2f042fc414eb7238ae842d596 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 14 Jul 2019 19:04:34 -0400 Subject: 1344477 - Part 1: Add JSOP_CALL_IGNORES_RV for function call that ignores return value. --- js/src/frontend/BytecodeEmitter.cpp | 64 ++++++++++++++++++++++--------------- js/src/frontend/BytecodeEmitter.h | 19 ++++++++--- js/src/jit/BaselineCompiler.cpp | 6 ++++ js/src/jit/BaselineCompiler.h | 1 + js/src/jit/BaselineIC.cpp | 24 +++++++++++--- js/src/jit/BaselineIC.h | 10 ++++-- js/src/jit/CodeGenerator.cpp | 26 +++++++++++---- js/src/jit/CodeGenerator.h | 4 +-- js/src/jit/IonBuilder.cpp | 48 +++++++++++++++++----------- js/src/jit/IonBuilder.h | 17 ++++++++-- js/src/jit/MIR.cpp | 4 +-- js/src/jit/MIR.h | 21 ++++++++---- js/src/jit/VMFunctions.cpp | 8 ++--- js/src/jit/VMFunctions.h | 4 +-- js/src/jit/shared/LIR-shared.h | 3 ++ js/src/jsfriendapi.h | 6 ++++ js/src/jsfun.h | 4 +++ js/src/jsopcode.cpp | 8 +++-- js/src/vm/Interpreter.cpp | 12 +++++-- js/src/vm/Opcodes.h | 13 ++++++-- js/src/vm/Stack.h | 11 +++++++ 21 files changed, 226 insertions(+), 87 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 7582e8df1..c2eae4344 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -4603,7 +4603,7 @@ BytecodeEmitter::emitSwitch(ParseNode* pn) // If the expression is a literal, suppress line number emission so // that debugging works more naturally. if (caseValue) { - if (!emitTree(caseValue, + if (!emitTree(caseValue, ValueUsage::WantValue, caseValue->isLiteral() ? SUPPRESS_LINENOTE : EMIT_LINENOTE)) { return false; @@ -6652,7 +6652,7 @@ BytecodeEmitter::emitLexicalScopeBody(ParseNode* body, EmitLineNumberNote emitLi } // Line notes were updated by emitLexicalScope. - return emitTree(body, emitLineNote); + return emitTree(body, ValueUsage::WantValue, emitLineNote); } // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See @@ -6754,9 +6754,9 @@ BytecodeEmitter::emitRequireObjectCoercible() return false; if (!emit2(JSOP_PICK, 2)) // VAL REQUIREOBJECTCOERCIBLE UNDEFINED VAL return false; - if (!emitCall(JSOP_CALL, 1)) // VAL IGNORED + if (!emitCall(JSOP_CALL_IGNORES_RV, 1))// VAL IGNORED return false; - checkTypeSet(JSOP_CALL); + checkTypeSet(JSOP_CALL_IGNORES_RV); if (!emit1(JSOP_POP)) // VAL return false; @@ -7276,12 +7276,14 @@ BytecodeEmitter::emitCStyleFor(ParseNode* pn, EmitterScope* headLexicalEmitterSc // scope, but we still need to emit code for the initializers.) if (!updateSourceCoordNotes(init->pn_pos.begin)) return false; - if (!emitTree(init)) - return false; - - if (!init->isForLoopDeclaration()) { + if (init->isForLoopDeclaration()) { + if (!emitTree(init)) + return false; + } else { // 'init' is an expression, not a declaration. emitTree left its // value on the stack. + if (!emitTree(init, ValueUsage::IgnoreValue)) + return false; if (!emit1(JSOP_POP)) return false; } @@ -7363,7 +7365,7 @@ BytecodeEmitter::emitCStyleFor(ParseNode* pn, EmitterScope* headLexicalEmitterSc if (!updateSourceCoordNotes(update->pn_pos.begin)) return false; - if (!emitTree(update)) + if (!emitTree(update, ValueUsage::IgnoreValue)) return false; if (!emit1(JSOP_POP)) return false; @@ -8690,8 +8692,9 @@ BytecodeEmitter::emitStatement(ParseNode* pn) if (useful) { JSOp op = wantval ? JSOP_SETRVAL : JSOP_POP; + ValueUsage valueUsage = wantval ? ValueUsage::WantValue : ValueUsage::IgnoreValue; MOZ_ASSERT_IF(pn2->isKind(PNK_ASSIGN), pn2->isOp(JSOP_NOP)); - if (!emitTree(pn2)) + if (!emitTree(pn2, valueUsage)) return false; if (!emit1(op)) return false; @@ -9041,7 +9044,7 @@ BytecodeEmitter::emitOptimizeSpread(ParseNode* arg0, JumpList* jmp, bool* emitte } bool -BytecodeEmitter::emitCallOrNew(ParseNode* pn) +BytecodeEmitter::emitCallOrNew(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::WantValue */) { bool callop = pn->isKind(PNK_CALL) || pn->isKind(PNK_TAGGED_TEMPLATE); /* @@ -9220,13 +9223,20 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn) } if (!spread) { - if (!emitCall(pn->getOp(), argc, pn)) - return false; + if (pn->getOp() == JSOP_CALL && valueUsage == ValueUsage::IgnoreValue) { + if (!emitCall(JSOP_CALL_IGNORES_RV, argc, pn)) + return false; + checkTypeSet(JSOP_CALL_IGNORES_RV); + } else { + if (!emitCall(pn->getOp(), argc, pn)) + return false; + checkTypeSet(pn->getOp()); + } } else { if (!emit1(pn->getOp())) return false; + checkTypeSet(pn->getOp()); } - checkTypeSet(pn->getOp()); if (pn->isOp(JSOP_EVAL) || pn->isOp(JSOP_STRICTEVAL) || pn->isOp(JSOP_SPREADEVAL) || @@ -9324,12 +9334,13 @@ BytecodeEmitter::emitLogical(ParseNode* pn) } bool -BytecodeEmitter::emitSequenceExpr(ParseNode* pn) +BytecodeEmitter::emitSequenceExpr(ParseNode* pn, + ValueUsage valueUsage /* = ValueUsage::WantValue */) { for (ParseNode* child = pn->pn_head; ; child = child->pn_next) { if (!updateSourceCoordNotes(child->pn_pos.begin)) return false; - if (!emitTree(child)) + if (!emitTree(child, child->pn_next ? ValueUsage::IgnoreValue : valueUsage)) return false; if (!child->pn_next) break; @@ -9392,7 +9403,8 @@ BytecodeEmitter::emitLabeledStatement(const LabeledStatement* pn) } bool -BytecodeEmitter::emitConditionalExpression(ConditionalExpression& conditional) +BytecodeEmitter::emitConditionalExpression(ConditionalExpression& conditional, + ValueUsage valueUsage /* = ValueUsage::WantValue */) { /* Emit the condition, then branch if false to the else part. */ if (!emitTree(&conditional.condition())) @@ -9402,13 +9414,13 @@ BytecodeEmitter::emitConditionalExpression(ConditionalExpression& conditional) if (!ifThenElse.emitCond()) return false; - if (!emitTreeInBranch(&conditional.thenExpression())) + if (!emitTreeInBranch(&conditional.thenExpression(), valueUsage)) return false; if (!ifThenElse.emitElse()) return false; - if (!emitTreeInBranch(&conditional.elseExpression())) + if (!emitTreeInBranch(&conditional.elseExpression(), valueUsage)) return false; if (!ifThenElse.emitEnd()) @@ -10288,7 +10300,8 @@ BytecodeEmitter::emitClass(ParseNode* pn) } bool -BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote) +BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::WantValue */, + EmitLineNumberNote emitLineNote /* = EMIT_LINENOTE */) { JS_CHECK_RECURSION(cx, return false); @@ -10410,7 +10423,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote) break; case PNK_COMMA: - if (!emitSequenceExpr(pn)) + if (!emitSequenceExpr(pn, valueUsage)) return false; break; @@ -10432,7 +10445,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote) break; case PNK_CONDITIONAL: - if (!emitConditionalExpression(pn->as())) + if (!emitConditionalExpression(pn->as(), valueUsage)) return false; break; @@ -10545,7 +10558,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote) case PNK_CALL: case PNK_GENEXP: case PNK_SUPERCALL: - if (!emitCallOrNew(pn)) + if (!emitCallOrNew(pn, valueUsage)) return false; break; @@ -10703,12 +10716,13 @@ BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote) } bool -BytecodeEmitter::emitTreeInBranch(ParseNode* pn) +BytecodeEmitter::emitTreeInBranch(ParseNode* pn, + ValueUsage valueUsage /* = ValueUsage::WantValue */) { // Code that may be conditionally executed always need their own TDZ // cache. TDZCheckCache tdzCache(this); - return emitTree(pn); + return emitTree(pn, valueUsage); } static bool diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index 4e5209593..99d6a2ff7 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -171,6 +171,11 @@ struct JumpList { void patchAll(jsbytecode* code, JumpTarget target); }; +enum class ValueUsage { + WantValue, + IgnoreValue +}; + struct MOZ_STACK_CLASS BytecodeEmitter { class TDZCheckCache; @@ -434,10 +439,12 @@ struct MOZ_STACK_CLASS BytecodeEmitter }; // Emit code for the tree rooted at pn. - MOZ_MUST_USE bool emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote = EMIT_LINENOTE); + MOZ_MUST_USE bool emitTree(ParseNode* pn, ValueUsage valueUsage = ValueUsage::WantValue, + EmitLineNumberNote emitLineNote = EMIT_LINENOTE); // Emit code for the tree rooted at pn with its own TDZ cache. - MOZ_MUST_USE bool emitTreeInBranch(ParseNode* pn); + MOZ_MUST_USE bool emitTreeInBranch(ParseNode* pn, + ValueUsage valueUsage = ValueUsage::WantValue); // Emit global, eval, or module code for tree rooted at body. Always // encompasses the entire source. @@ -724,16 +731,18 @@ struct MOZ_STACK_CLASS BytecodeEmitter MOZ_MUST_USE bool emitRightAssociative(ParseNode* pn); MOZ_MUST_USE bool emitLeftAssociative(ParseNode* pn); MOZ_MUST_USE bool emitLogical(ParseNode* pn); - MOZ_MUST_USE bool emitSequenceExpr(ParseNode* pn); + MOZ_MUST_USE bool emitSequenceExpr(ParseNode* pn, + ValueUsage valueUsage = ValueUsage::WantValue); MOZ_NEVER_INLINE MOZ_MUST_USE bool emitIncOrDec(ParseNode* pn); - MOZ_MUST_USE bool emitConditionalExpression(ConditionalExpression& conditional); + MOZ_MUST_USE bool emitConditionalExpression(ConditionalExpression& conditional, + ValueUsage valueUsage = ValueUsage::WantValue); MOZ_MUST_USE bool isRestParameter(ParseNode* pn, bool* result); MOZ_MUST_USE bool emitOptimizeSpread(ParseNode* arg0, JumpList* jmp, bool* emitted); - MOZ_MUST_USE bool emitCallOrNew(ParseNode* pn); + MOZ_MUST_USE bool emitCallOrNew(ParseNode* pn, ValueUsage valueUsage = ValueUsage::WantValue); MOZ_MUST_USE bool emitSelfHostedCallFunction(ParseNode* pn); MOZ_MUST_USE bool emitSelfHostedResumeGenerator(ParseNode* pn); MOZ_MUST_USE bool emitSelfHostedForceInterpreter(ParseNode* pn); diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index 6b64bfb44..b2f9d3b23 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -3291,6 +3291,12 @@ BaselineCompiler::emit_JSOP_CALL() return emitCall(); } +bool +BaselineCompiler::emit_JSOP_CALL_IGNORES_RV() +{ + return emitCall(); +} + bool BaselineCompiler::emit_JSOP_CALLITER() { diff --git a/js/src/jit/BaselineCompiler.h b/js/src/jit/BaselineCompiler.h index 910a52980..95e0c77ad 100644 --- a/js/src/jit/BaselineCompiler.h +++ b/js/src/jit/BaselineCompiler.h @@ -159,6 +159,7 @@ namespace jit { _(JSOP_INITALIASEDLEXICAL) \ _(JSOP_UNINITIALIZED) \ _(JSOP_CALL) \ + _(JSOP_CALL_IGNORES_RV) \ _(JSOP_CALLITER) \ _(JSOP_FUNCALL) \ _(JSOP_FUNAPPLY) \ diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 506cbf1d2..8a7c68e59 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -10,6 +10,8 @@ #include "mozilla/SizePrintfMacros.h" #include "mozilla/TemplateLib.h" +#include "jsfriendapi.h" +#include "jsfun.h" #include "jslibmath.h" #include "jstypes.h" @@ -5494,11 +5496,17 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb MOZ_ASSERT_IF(templateObject, !templateObject->group()->maybePreliminaryObjects()); } + bool ignoresReturnValue = false; + if (op == JSOP_CALL_IGNORES_RV && fun->isNative()) { + const JSJitInfo* jitInfo = fun->jitInfo(); + ignoresReturnValue = jitInfo && jitInfo->type() == JSJitInfo::IgnoresReturnValueNative; + } + JitSpew(JitSpew_BaselineIC, " Generating Call_Native stub (fun=%p, cons=%s, spread=%s)", fun.get(), constructing ? "yes" : "no", isSpread ? "yes" : "no"); ICCall_Native::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(), - fun, templateObject, constructing, isSpread, - script->pcToOffset(pc)); + fun, templateObject, constructing, ignoresReturnValue, + isSpread, script->pcToOffset(pc)); ICStub* newStub = compiler.getStub(compiler.getStubSpace(script)); if (!newStub) return false; @@ -5601,12 +5609,14 @@ DoCallFallback(JSContext* cx, BaselineFrame* frame, ICCall_Fallback* stub_, uint MOZ_ASSERT(argc == GET_ARGC(pc)); bool constructing = (op == JSOP_NEW); + bool ignoresReturnValue = (op == JSOP_CALL_IGNORES_RV); // Ensure vp array is rooted - we may GC in here. size_t numValues = argc + 2 + constructing; AutoArrayRooter vpRoot(cx, numValues, vp); - CallArgs callArgs = CallArgsFromSp(argc + constructing, vp + numValues, constructing); + CallArgs callArgs = CallArgsFromSp(argc + constructing, vp + numValues, constructing, + ignoresReturnValue); RootedValue callee(cx, vp[0]); // Handle funapply with JSOP_ARGUMENTS @@ -5636,6 +5646,7 @@ DoCallFallback(JSContext* cx, BaselineFrame* frame, ICCall_Fallback* stub_, uint return false; } else { MOZ_ASSERT(op == JSOP_CALL || + op == JSOP_CALL_IGNORES_RV || op == JSOP_CALLITER || op == JSOP_FUNCALL || op == JSOP_FUNAPPLY || @@ -6686,7 +6697,12 @@ ICCall_Native::Compiler::generateStubCode(MacroAssembler& masm) // stub and use that instead of the original one. masm.callWithABI(Address(ICStubReg, ICCall_Native::offsetOfNative())); #else - masm.callWithABI(Address(callee, JSFunction::offsetOfNativeOrScript())); + if (ignoresReturnValue_) { + masm.loadPtr(Address(callee, JSFunction::offsetOfJitInfo()), callee); + masm.callWithABI(Address(callee, JSJitInfo::offsetOfIgnoresReturnValueNative())); + } else { + masm.callWithABI(Address(callee, JSFunction::offsetOfNativeOrScript())); + } #endif // Test for failure. diff --git a/js/src/jit/BaselineIC.h b/js/src/jit/BaselineIC.h index 9941cc93d..e1ad12559 100644 --- a/js/src/jit/BaselineIC.h +++ b/js/src/jit/BaselineIC.h @@ -2277,6 +2277,7 @@ class ICSetProp_CallNative : public ICSetPropCallSetter // Call // JSOP_CALL +// JSOP_CALL_IGNORES_RV // JSOP_FUNAPPLY // JSOP_FUNCALL // JSOP_NEW @@ -2547,6 +2548,7 @@ class ICCall_Native : public ICMonitoredStub protected: ICStub* firstMonitorStub_; bool isConstructing_; + bool ignoresReturnValue_; bool isSpread_; RootedFunction callee_; RootedObject templateObject_; @@ -2556,17 +2558,19 @@ class ICCall_Native : public ICMonitoredStub virtual int32_t getKey() const { return static_cast(engine_) | (static_cast(kind) << 1) | - (static_cast(isConstructing_) << 17) | - (static_cast(isSpread_) << 18); + (static_cast(isSpread_) << 17) | + (static_cast(isConstructing_) << 18) | + (static_cast(ignoresReturnValue_) << 19); } public: Compiler(JSContext* cx, ICStub* firstMonitorStub, HandleFunction callee, HandleObject templateObject, - bool isConstructing, bool isSpread, uint32_t pcOffset) + bool isConstructing, bool ignoresReturnValue, bool isSpread, uint32_t pcOffset) : ICCallStubCompiler(cx, ICStub::Call_Native), firstMonitorStub_(firstMonitorStub), isConstructing_(isConstructing), + ignoresReturnValue_(ignoresReturnValue), isSpread_(isSpread), callee_(cx, callee), templateObject_(cx, templateObject), diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 573993d5e..114fc96b3 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -3688,7 +3688,13 @@ CodeGenerator::visitCallNative(LCallNative* call) masm.passABIArg(argContextReg); masm.passABIArg(argUintNReg); masm.passABIArg(argVpReg); - masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, target->native())); + JSNative native = target->native(); + if (call->ignoresReturnValue()) { + const JSJitInfo* jitInfo = target->jitInfo(); + if (jitInfo && jitInfo->type() == JSJitInfo::IgnoresReturnValueNative) + native = jitInfo->ignoresReturnValueMethod; + } + masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, native)); emitTracelogStopEvent(TraceLogger_Call); @@ -3845,13 +3851,15 @@ CodeGenerator::visitCallGetIntrinsicValue(LCallGetIntrinsicValue* lir) callVM(GetIntrinsicValueInfo, lir); } -typedef bool (*InvokeFunctionFn)(JSContext*, HandleObject, bool, uint32_t, Value*, MutableHandleValue); +typedef bool (*InvokeFunctionFn)(JSContext*, HandleObject, bool, bool, uint32_t, Value*, + MutableHandleValue); static const VMFunction InvokeFunctionInfo = FunctionInfo(InvokeFunction, "InvokeFunction"); void CodeGenerator::emitCallInvokeFunction(LInstruction* call, Register calleereg, - bool constructing, uint32_t argc, uint32_t unusedStack) + bool constructing, bool ignoresReturnValue, + uint32_t argc, uint32_t unusedStack) { // Nestle %esp up to the argument vector. // Each path must account for framePushed_ separately, for callVM to be valid. @@ -3859,6 +3867,7 @@ CodeGenerator::emitCallInvokeFunction(LInstruction* call, Register calleereg, pushArg(masm.getStackPointer()); // argv. pushArg(Imm32(argc)); // argc. + pushArg(Imm32(ignoresReturnValue)); pushArg(Imm32(constructing)); // constructing. pushArg(calleereg); // JSFunction*. @@ -3945,8 +3954,8 @@ CodeGenerator::visitCallGeneric(LCallGeneric* call) // Handle uncompiled or native functions. masm.bind(&invoke); - emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->numActualArgs(), - unusedStack); + emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->ignoresReturnValue(), + call->numActualArgs(), unusedStack); masm.bind(&end); @@ -4001,7 +4010,8 @@ CodeGenerator::visitCallKnown(LCallKnown* call) masm.checkStackAlignment(); if (target->isClassConstructor() && !call->isConstructing()) { - emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->numActualArgs(), unusedStack); + emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->ignoresReturnValue(), + call->numActualArgs(), unusedStack); return; } @@ -4045,7 +4055,8 @@ CodeGenerator::visitCallKnown(LCallKnown* call) if (call->isConstructing() && target->nargs() > call->numActualArgs()) emitCallInvokeFunctionShuffleNewTarget(call, calleereg, target->nargs(), unusedStack); else - emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->numActualArgs(), unusedStack); + emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->ignoresReturnValue(), + call->numActualArgs(), unusedStack); masm.bind(&end); @@ -4072,6 +4083,7 @@ CodeGenerator::emitCallInvokeFunction(T* apply, Register extraStackSize) pushArg(objreg); // argv. pushArg(ToRegister(apply->getArgc())); // argc. + pushArg(Imm32(false)); // ignoresReturnValue. pushArg(Imm32(false)); // isConstrucing. pushArg(ToRegister(apply->getFunction())); // JSFunction*. diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h index b5f170d84..1c9a7e89b 100644 --- a/js/src/jit/CodeGenerator.h +++ b/js/src/jit/CodeGenerator.h @@ -165,8 +165,8 @@ class CodeGenerator final : public CodeGeneratorSpecific void visitOutOfLineCallPostWriteElementBarrier(OutOfLineCallPostWriteElementBarrier* ool); void visitCallNative(LCallNative* call); void emitCallInvokeFunction(LInstruction* call, Register callereg, - bool isConstructing, uint32_t argc, - uint32_t unusedStack); + bool isConstructing, bool ignoresReturnValue, + uint32_t argc, uint32_t unusedStack); void visitCallGeneric(LCallGeneric* call); void emitCallInvokeFunctionShuffleNewTarget(LCallKnown *call, Register calleeReg, diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index e98a4056e..2d053de5a 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -1939,6 +1939,7 @@ IonBuilder::inspectOpcode(JSOp op) return jsop_funapply(GET_ARGC(pc)); case JSOP_CALL: + case JSOP_CALL_IGNORES_RV: case JSOP_CALLITER: case JSOP_NEW: case JSOP_SUPERCALL: @@ -1946,7 +1947,8 @@ IonBuilder::inspectOpcode(JSOp op) if (!outermostBuilder()->iterators_.append(current->peek(-1))) return false; } - return jsop_call(GET_ARGC(pc), (JSOp)*pc == JSOP_NEW || (JSOp)*pc == JSOP_SUPERCALL); + return jsop_call(GET_ARGC(pc), (JSOp)*pc == JSOP_NEW || (JSOp)*pc == JSOP_SUPERCALL, + (JSOp)*pc == JSOP_CALL_IGNORES_RV); case JSOP_EVAL: case JSOP_STRICTEVAL: @@ -5874,7 +5876,7 @@ IonBuilder::inlineGenericFallback(JSFunction* target, CallInfo& callInfo, MBasic return false; // Create a new CallInfo to track modified state within this block. - CallInfo fallbackInfo(alloc(), callInfo.constructing()); + CallInfo fallbackInfo(alloc(), callInfo.constructing(), callInfo.ignoresReturnValue()); if (!fallbackInfo.init(callInfo)) return false; fallbackInfo.popFormals(fallbackBlock); @@ -5913,7 +5915,7 @@ IonBuilder::inlineObjectGroupFallback(CallInfo& callInfo, MBasicBlock* dispatchB MOZ_ASSERT(cache->idempotent()); // Create a new CallInfo to track modified state within the fallback path. - CallInfo fallbackInfo(alloc(), callInfo.constructing()); + CallInfo fallbackInfo(alloc(), callInfo.constructing(), callInfo.ignoresReturnValue()); if (!fallbackInfo.init(callInfo)) return false; @@ -6089,7 +6091,7 @@ IonBuilder::inlineCalls(CallInfo& callInfo, const ObjectVector& targets, BoolVec inlineBlock->rewriteSlot(funIndex, funcDef); // Create a new CallInfo to track modified state within the inline block. - CallInfo inlineInfo(alloc(), callInfo.constructing()); + CallInfo inlineInfo(alloc(), callInfo.constructing(), callInfo.ignoresReturnValue()); if (!inlineInfo.init(callInfo)) return false; inlineInfo.popFormals(inlineBlock); @@ -6538,7 +6540,8 @@ IonBuilder::jsop_funcall(uint32_t argc) TemporaryTypeSet* calleeTypes = current->peek(calleeDepth)->resultTypeSet(); JSFunction* native = getSingleCallTarget(calleeTypes); if (!native || !native->isNative() || native->native() != &fun_call) { - CallInfo callInfo(alloc(), false); + CallInfo callInfo(alloc(), /* constructing = */ false, + /* ignoresReturnValue = */ BytecodeIsPopped(pc)); if (!callInfo.init(current, argc)) return false; return makeCall(native, callInfo); @@ -6563,7 +6566,8 @@ IonBuilder::jsop_funcall(uint32_t argc) argc -= 1; } - CallInfo callInfo(alloc(), false); + CallInfo callInfo(alloc(), /* constructing = */ false, + /* ignoresReturnValue = */ BytecodeIsPopped(pc)); if (!callInfo.init(current, argc)) return false; @@ -6600,7 +6604,8 @@ IonBuilder::jsop_funapply(uint32_t argc) TemporaryTypeSet* calleeTypes = current->peek(calleeDepth)->resultTypeSet(); JSFunction* native = getSingleCallTarget(calleeTypes); if (argc != 2 || info().analysisMode() == Analysis_ArgumentsUsage) { - CallInfo callInfo(alloc(), false); + CallInfo callInfo(alloc(), /* constructing = */ false, + /* ignoresReturnValue = */ BytecodeIsPopped(pc)); if (!callInfo.init(current, argc)) return false; return makeCall(native, callInfo); @@ -6629,7 +6634,8 @@ IonBuilder::jsop_funapply(uint32_t argc) return jsop_funapplyarray(argc); } - CallInfo callInfo(alloc(), false); + CallInfo callInfo(alloc(), /* constructing = */ false, + /* ignoresReturnValue = */ BytecodeIsPopped(pc)); if (!callInfo.init(current, argc)) return false; return makeCall(native, callInfo); @@ -6738,7 +6744,8 @@ IonBuilder::jsop_funapplyarguments(uint32_t argc) // can inline the apply() target and don't care about the actual arguments // that were passed in. - CallInfo callInfo(alloc(), false); + CallInfo callInfo(alloc(), /* constructing = */ false, + /* ignoresReturnValue = */ BytecodeIsPopped(pc)); // Vp MDefinition* vp = current->pop(); @@ -6784,7 +6791,7 @@ IonBuilder::jsop_funapplyarguments(uint32_t argc) } bool -IonBuilder::jsop_call(uint32_t argc, bool constructing) +IonBuilder::jsop_call(uint32_t argc, bool constructing, bool ignoresReturnValue) { startTrackingOptimizations(); @@ -6810,7 +6817,7 @@ IonBuilder::jsop_call(uint32_t argc, bool constructing) if (calleeTypes && !getPolyCallTargets(calleeTypes, constructing, targets, 4)) return false; - CallInfo callInfo(alloc(), constructing); + CallInfo callInfo(alloc(), constructing, ignoresReturnValue); if (!callInfo.init(current, argc)) return false; @@ -6946,7 +6953,8 @@ IonBuilder::makeCallHelper(JSFunction* target, CallInfo& callInfo) } MCall* call = MCall::New(alloc(), target, targetArgs + 1 + callInfo.constructing(), - callInfo.argc(), callInfo.constructing(), isDOMCall); + callInfo.argc(), callInfo.constructing(), + callInfo.ignoresReturnValue(), isDOMCall); if (!call) return nullptr; @@ -7047,7 +7055,7 @@ IonBuilder::jsop_eval(uint32_t argc) // Emit a normal call if the eval has never executed. This keeps us from // disabling compilation for the script when testing with --ion-eager. if (calleeTypes && calleeTypes->empty()) - return jsop_call(argc, /* constructing = */ false); + return jsop_call(argc, /* constructing = */ false, false); JSFunction* singleton = getSingleCallTarget(calleeTypes); if (!singleton) @@ -7063,7 +7071,8 @@ IonBuilder::jsop_eval(uint32_t argc) if (info().funMaybeLazy()->isArrow()) return abort("Direct eval from arrow function"); - CallInfo callInfo(alloc(), /* constructing = */ false); + CallInfo callInfo(alloc(), /* constructing = */ false, + /* ignoresReturnValue = */ BytecodeIsPopped(pc)); if (!callInfo.init(current, argc)) return false; callInfo.setImplicitlyUsedUnchecked(); @@ -7102,7 +7111,8 @@ IonBuilder::jsop_eval(uint32_t argc) current->push(dynamicName); current->push(constant(UndefinedValue())); // thisv - CallInfo evalCallInfo(alloc(), /* constructing = */ false); + CallInfo evalCallInfo(alloc(), /* constructing = */ false, + /* ignoresReturnValue = */ BytecodeIsPopped(pc)); if (!evalCallInfo.init(current, /* argc = */ 0)) return false; @@ -7119,7 +7129,7 @@ IonBuilder::jsop_eval(uint32_t argc) return resumeAfter(ins) && pushTypeBarrier(ins, types, BarrierKind::TypeSet); } - return jsop_call(argc, /* constructing = */ false); + return jsop_call(argc, /* constructing = */ false, false); } bool @@ -12001,7 +12011,8 @@ IonBuilder::getPropTryCommonGetter(bool* emitted, MDefinition* obj, PropertyName current->push(obj); - CallInfo callInfo(alloc(), false); + CallInfo callInfo(alloc(), /* constructing = */ false, + /* ignoresReturnValue = */ BytecodeIsPopped(pc)); if (!callInfo.init(current, 0)) return false; @@ -12496,7 +12507,8 @@ IonBuilder::setPropTryCommonSetter(bool* emitted, MDefinition* obj, // Call the setter. Note that we have to push the original value, not // the setter's return value. - CallInfo callInfo(alloc(), false); + CallInfo callInfo(alloc(), /* constructing = */ false, + /* ignoresReturnValue = */ BytecodeIsPopped(pc)); if (!callInfo.init(current, 1)) return false; diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index dd40b4bd6..9e40b3959 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -699,6 +699,7 @@ class IonBuilder MOZ_MUST_USE bool jsop_funapplyarguments(uint32_t argc); MOZ_MUST_USE bool jsop_funapplyarray(uint32_t argc); MOZ_MUST_USE bool jsop_call(uint32_t argc, bool constructing); + MOZ_MUST_USE bool jsop_call(uint32_t argc, bool constructing, bool ignoresReturnValue); MOZ_MUST_USE bool jsop_eval(uint32_t argc); MOZ_MUST_USE bool jsop_ifeq(JSOp op); MOZ_MUST_USE bool jsop_try(); @@ -1352,16 +1353,21 @@ class CallInfo MDefinition* newTargetArg_; MDefinitionVector args_; - bool constructing_; - bool setter_; + bool constructing_:1; + + // True if the caller does not use the return value. + bool ignoresReturnValue_:1; + + bool setter_:1; public: - CallInfo(TempAllocator& alloc, bool constructing) + CallInfo(TempAllocator& alloc, bool constructing, bool ignoresReturnValue) : fun_(nullptr), thisArg_(nullptr), newTargetArg_(nullptr), args_(alloc), constructing_(constructing), + ignoresReturnValue_(ignoresReturnValue), setter_(false) { } @@ -1370,6 +1376,7 @@ class CallInfo fun_ = callInfo.fun(); thisArg_ = callInfo.thisArg(); + ignoresReturnValue_ = callInfo.ignoresReturnValue(); if (constructing()) newTargetArg_ = callInfo.getNewTarget(); @@ -1466,6 +1473,10 @@ class CallInfo return constructing_; } + bool ignoresReturnValue() const { + return ignoresReturnValue_; + } + void setNewTarget(MDefinition* newTarget) { MOZ_ASSERT(constructing()); newTargetArg_ = newTarget; diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index fa9cc3019..10671cfda 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -1970,7 +1970,7 @@ WrappedFunction::WrappedFunction(JSFunction* fun) MCall* MCall::New(TempAllocator& alloc, JSFunction* target, size_t maxArgc, size_t numActualArgs, - bool construct, bool isDOMCall) + bool construct, bool ignoresReturnValue, bool isDOMCall) { WrappedFunction* wrappedTarget = target ? new(alloc) WrappedFunction(target) : nullptr; MOZ_ASSERT(maxArgc >= numActualArgs); @@ -1979,7 +1979,7 @@ MCall::New(TempAllocator& alloc, JSFunction* target, size_t maxArgc, size_t numA MOZ_ASSERT(!construct); ins = new(alloc) MCallDOMNative(wrappedTarget, numActualArgs); } else { - ins = new(alloc) MCall(wrappedTarget, numActualArgs, construct); + ins = new(alloc) MCall(wrappedTarget, numActualArgs, construct, ignoresReturnValue); } if (!ins->init(alloc, maxArgc + NumNonArgumentOperands)) return nullptr; diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 9076339f1..ac55b1150 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -4043,14 +4043,18 @@ class MCall uint32_t numActualArgs_; // True if the call is for JSOP_NEW. - bool construct_; + bool construct_:1; - bool needsArgCheck_; + // True if the caller does not use the return value. + bool ignoresReturnValue_:1; - MCall(WrappedFunction* target, uint32_t numActualArgs, bool construct) + bool needsArgCheck_:1; + + MCall(WrappedFunction* target, uint32_t numActualArgs, bool construct, bool ignoresReturnValue) : target_(target), numActualArgs_(numActualArgs), construct_(construct), + ignoresReturnValue_(ignoresReturnValue), needsArgCheck_(true) { setResultType(MIRType::Value); @@ -4059,7 +4063,7 @@ class MCall public: INSTRUCTION_HEADER(Call) static MCall* New(TempAllocator& alloc, JSFunction* target, size_t maxArgc, size_t numActualArgs, - bool construct, bool isDOMCall); + bool construct, bool ignoresReturnValue, bool isDOMCall); void initFunction(MDefinition* func) { initOperand(FunctionOperandIndex, func); @@ -4104,6 +4108,10 @@ class MCall return construct_; } + bool ignoresReturnValue() const { + return ignoresReturnValue_; + } + // The number of stack arguments is the max between the number of formal // arguments and the number of actual arguments. The number of stack // argument includes the |undefined| padding added in case of underflow. @@ -4147,7 +4155,7 @@ class MCallDOMNative : public MCall // virtual things from MCall. protected: MCallDOMNative(WrappedFunction* target, uint32_t numActualArgs) - : MCall(target, numActualArgs, false) + : MCall(target, numActualArgs, false, false) { MOZ_ASSERT(getJitInfo()->type() != JSJitInfo::InlinableNative); @@ -4162,7 +4170,8 @@ class MCallDOMNative : public MCall } friend MCall* MCall::New(TempAllocator& alloc, JSFunction* target, size_t maxArgc, - size_t numActualArgs, bool construct, bool isDOMCall); + size_t numActualArgs, bool construct, bool ignoresReturnValue, + bool isDOMCall); const JSJitInfo* getJitInfo() const; public: diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 5bcd36ba0..e58c3f570 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -54,8 +54,8 @@ VMFunction::addToFunctions() } bool -InvokeFunction(JSContext* cx, HandleObject obj, bool constructing, uint32_t argc, Value* argv, - MutableHandleValue rval) +InvokeFunction(JSContext* cx, HandleObject obj, bool constructing, bool ignoresReturnValue, + uint32_t argc, Value* argv, MutableHandleValue rval) { TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime()); TraceLogStartEvent(logger, TraceLogger_Call); @@ -104,7 +104,7 @@ InvokeFunction(JSContext* cx, HandleObject obj, bool constructing, uint32_t argc return InternalConstructWithProvidedThis(cx, fval, thisv, cargs, newTarget, rval); } - InvokeArgs args(cx); + InvokeArgsMaybeIgnoresReturnValue args(cx, ignoresReturnValue); if (!args.init(cx, argc)) return false; @@ -120,7 +120,7 @@ InvokeFunctionShuffleNewTarget(JSContext* cx, HandleObject obj, uint32_t numActu { MOZ_ASSERT(numFormalArgs > numActualArgs); argv[1 + numActualArgs] = argv[1 + numFormalArgs]; - return InvokeFunction(cx, obj, true, numActualArgs, argv, rval); + return InvokeFunction(cx, obj, true, false, numActualArgs, argv, rval); } bool diff --git a/js/src/jit/VMFunctions.h b/js/src/jit/VMFunctions.h index 9a2edd0f3..bd65df134 100644 --- a/js/src/jit/VMFunctions.h +++ b/js/src/jit/VMFunctions.h @@ -584,8 +584,8 @@ class AutoDetectInvalidation }; MOZ_MUST_USE bool -InvokeFunction(JSContext* cx, HandleObject obj0, bool constructing, uint32_t argc, Value* argv, - MutableHandleValue rval); +InvokeFunction(JSContext* cx, HandleObject obj0, bool constructing, bool ignoresReturnValue, + uint32_t argc, Value* argv, MutableHandleValue rval); MOZ_MUST_USE bool InvokeFunctionShuffleNewTarget(JSContext* cx, HandleObject obj, uint32_t numActualArgs, uint32_t numFormalArgs, Value* argv, MutableHandleValue rval); diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h index ffa4d8367..2b242d2e4 100644 --- a/js/src/jit/shared/LIR-shared.h +++ b/js/src/jit/shared/LIR-shared.h @@ -1898,6 +1898,9 @@ class LJSCallInstructionHelper : public LCallInstructionHelperisConstructing(); } + bool ignoresReturnValue() const { + return mir()->ignoresReturnValue(); + } }; // Generates a polymorphic callsite, wherein the function being called is diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index d29285483..351667fb3 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -2254,6 +2254,7 @@ struct JSJitInfo { Method, StaticMethod, InlinableNative, + IgnoresReturnValueNative, // Must be last OpTypeCount }; @@ -2345,8 +2346,13 @@ struct JSJitInfo { JSJitMethodOp method; /** A DOM static method, used for Promise wrappers */ JSNative staticMethod; + JSNative ignoresReturnValueMethod; }; + static unsigned offsetOfIgnoresReturnValueNative() { + return offsetof(JSJitInfo, ignoresReturnValueMethod); + } + union { uint16_t protoID; js::jit::InlinableNative inlinableNative; diff --git a/js/src/jsfun.h b/js/src/jsfun.h index f3643f1e6..234169507 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -585,6 +585,10 @@ class JSFunction : public js::NativeObject return offsetof(JSFunction, u.nativeOrScript); } + static unsigned offsetOfJitInfo() { + return offsetof(JSFunction, u.n.jitinfo); + } + inline void trace(JSTracer* trc); /* Bound function accessors. */ diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index b6897908b..d1ae3cd5e 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -132,7 +132,8 @@ js::StackUses(JSScript* script, jsbytecode* pc) return 2 + GET_ARGC(pc) + 1; default: /* stack: fun, this, [argc arguments] */ - MOZ_ASSERT(op == JSOP_CALL || op == JSOP_EVAL || op == JSOP_CALLITER || + MOZ_ASSERT(op == JSOP_CALL || op == JSOP_CALL_IGNORES_RV || op == JSOP_EVAL || + op == JSOP_CALLITER || op == JSOP_STRICTEVAL || op == JSOP_FUNCALL || op == JSOP_FUNAPPLY); return 2 + GET_ARGC(pc); } @@ -1363,6 +1364,7 @@ ExpressionDecompiler::decompilePC(jsbytecode* pc) case JSOP_NEWTARGET: return write("new.target"); case JSOP_CALL: + case JSOP_CALL_IGNORES_RV: case JSOP_CALLITER: case JSOP_FUNCALL: return decompilePCForStackOperand(pc, -int32_t(GET_ARGC(pc) + 2)) && @@ -1662,7 +1664,7 @@ DecompileArgumentFromStack(JSContext* cx, int formalIndex, char** res) /* Don't handle getters, setters or calls from fun.call/fun.apply. */ JSOp op = JSOp(*current); - if (op != JSOP_CALL && op != JSOP_NEW) + if (op != JSOP_CALL && op != JSOP_CALL_IGNORES_RV && op != JSOP_NEW) return true; if (static_cast(formalIndex) >= GET_ARGC(current)) @@ -1725,6 +1727,8 @@ js::CallResultEscapes(jsbytecode* pc) if (*pc == JSOP_CALL) pc += JSOP_CALL_LENGTH; + else if (*pc == JSOP_CALL_IGNORES_RV) + pc += JSOP_CALL_IGNORES_RV_LENGTH; else if (*pc == JSOP_SPREADCALL) pc += JSOP_SPREADCALL_LENGTH; else diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index ad9e87a50..030f0f3b6 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -470,7 +470,13 @@ js::InternalCallOrConstruct(JSContext* cx, const CallArgs& args, MaybeConstruct if (fun->isNative()) { MOZ_ASSERT_IF(construct, !fun->isConstructor()); - return CallJSNative(cx, fun->native(), args); + JSNative native = fun->native(); + if (!construct && args.ignoresReturnValue()) { + const JSJitInfo* jitInfo = fun->jitInfo(); + if (jitInfo && jitInfo->type() == JSJitInfo::IgnoresReturnValueNative) + native = jitInfo->ignoresReturnValueMethod; + } + return CallJSNative(cx, native, args); } if (!JSFunction::getOrCreateScript(cx, fun)) @@ -2975,6 +2981,7 @@ CASE(JSOP_FUNAPPLY) CASE(JSOP_NEW) CASE(JSOP_CALL) +CASE(JSOP_CALL_IGNORES_RV) CASE(JSOP_CALLITER) CASE(JSOP_SUPERCALL) CASE(JSOP_FUNCALL) @@ -2983,10 +2990,11 @@ CASE(JSOP_FUNCALL) cx->runtime()->spsProfiler.updatePC(script, REGS.pc); MaybeConstruct construct = MaybeConstruct(*REGS.pc == JSOP_NEW || *REGS.pc == JSOP_SUPERCALL); + bool ignoresReturnValue = *REGS.pc == JSOP_CALL_IGNORES_RV; unsigned argStackSlots = GET_ARGC(REGS.pc) + construct; MOZ_ASSERT(REGS.stackDepth() >= 2u + GET_ARGC(REGS.pc)); - CallArgs args = CallArgsFromSp(argStackSlots, REGS.sp, construct); + CallArgs args = CallArgsFromSp(argStackSlots, REGS.sp, construct, ignoresReturnValue); JSFunction* maybeFun; bool isFunction = IsFunctionObject(args.calleev(), &maybeFun); diff --git a/js/src/vm/Opcodes.h b/js/src/vm/Opcodes.h index 095ef57ae..3c4d61a67 100644 --- a/js/src/vm/Opcodes.h +++ b/js/src/vm/Opcodes.h @@ -2282,14 +2282,23 @@ * Operands: * Stack: => */ \ - macro(JSOP_JUMPTARGET, 230, "jumptarget", NULL, 1, 0, 0, JOF_BYTE) + macro(JSOP_JUMPTARGET, 230, "jumptarget", NULL, 1, 0, 0, JOF_BYTE)\ + /* + * Like JSOP_CALL, but tells the function that the return value is ignored. + * stack. + * Category: Statements + * Type: Function + * Operands: uint16_t argc + * Stack: callee, this, args[0], ..., args[argc-1] => rval + * nuses: (argc+2) + */ \ + macro(JSOP_CALL_IGNORES_RV, 231, "call-ignores-rv", NULL, 3, -1, 1, JOF_UINT16|JOF_INVOKE|JOF_TYPESET) /* * In certain circumstances it may be useful to "pad out" the opcode space to * a power of two. Use this macro to do so. */ #define FOR_EACH_TRAILING_UNUSED_OPCODE(macro) \ - macro(231) \ macro(232) \ macro(233) \ macro(234) \ diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index dc9306c99..23e621344 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -1006,6 +1006,17 @@ class InvokeArgs : public detail::GenericArgsBase explicit InvokeArgs(JSContext* cx) : Base(cx) {} }; +/** Function call args of statically-unknown count. */ +class InvokeArgsMaybeIgnoresReturnValue : public detail::GenericArgsBase +{ + using Base = detail::GenericArgsBase; + + public: + explicit InvokeArgsMaybeIgnoresReturnValue(JSContext* cx, bool ignoresReturnValue) : Base(cx) { + this->ignoresReturnValue_ = ignoresReturnValue; + } +}; + /** Function call args of statically-known count. */ template class FixedInvokeArgs : public detail::FixedArgsBase -- cgit v1.2.3 From 85aeff765ea921ea2c947fa9d68756eb989b6287 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 14 Jul 2019 19:04:52 -0400 Subject: 1344477 - Part 2: Optimize Array.prototype.splice with JSOP_NORVCALL. --- js/src/jit/CodeGenerator.cpp | 13 ------------ js/src/jit/CodeGenerator.h | 1 - js/src/jit/InlinableNatives.h | 1 - js/src/jit/IonBuilder.h | 1 - js/src/jit/Lowering.cpp | 10 --------- js/src/jit/Lowering.h | 1 - js/src/jit/MCallOptimize.cpp | 42 ------------------------------------- js/src/jit/MIR.h | 21 ------------------- js/src/jit/MOpcodes.h | 1 - js/src/jit/VMFunctions.cpp | 12 ----------- js/src/jit/VMFunctions.h | 3 --- js/src/jit/shared/LIR-shared.h | 28 ------------------------- js/src/jit/shared/LOpcodes-shared.h | 1 - js/src/jsarray.cpp | 35 ++++++++++++++++++++++--------- js/src/jsarray.h | 5 ++--- js/src/vm/SelfHosting.cpp | 2 +- 16 files changed, 28 insertions(+), 149 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 114fc96b3..205812942 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -4440,19 +4440,6 @@ CodeGenerator::visitApplyArrayGeneric(LApplyArrayGeneric* apply) emitApplyGeneric(apply); } -typedef bool (*ArraySpliceDenseFn)(JSContext*, HandleObject, uint32_t, uint32_t); -static const VMFunction ArraySpliceDenseInfo = - FunctionInfo(ArraySpliceDense, "ArraySpliceDense"); - -void -CodeGenerator::visitArraySplice(LArraySplice* lir) -{ - pushArg(ToRegister(lir->getDeleteCount())); - pushArg(ToRegister(lir->getStart())); - pushArg(ToRegister(lir->getObject())); - callVM(ArraySpliceDenseInfo, lir); -} - void CodeGenerator::visitBail(LBail* lir) { diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h index 1c9a7e89b..12f1238ef 100644 --- a/js/src/jit/CodeGenerator.h +++ b/js/src/jit/CodeGenerator.h @@ -251,7 +251,6 @@ class CodeGenerator final : public CodeGeneratorSpecific void emitSetPropertyPolymorphic(LInstruction* lir, Register obj, Register scratch, const ConstantOrRegister& value); void visitSetPropertyPolymorphicV(LSetPropertyPolymorphicV* ins); - void visitArraySplice(LArraySplice* splice); void visitSetPropertyPolymorphicT(LSetPropertyPolymorphicT* ins); void visitAbsI(LAbsI* lir); void visitAtan2D(LAtan2D* lir); diff --git a/js/src/jit/InlinableNatives.h b/js/src/jit/InlinableNatives.h index 18535389a..1d0506f74 100644 --- a/js/src/jit/InlinableNatives.h +++ b/js/src/jit/InlinableNatives.h @@ -15,7 +15,6 @@ _(ArrayShift) \ _(ArrayPush) \ _(ArraySlice) \ - _(ArraySplice) \ \ _(AtomicsCompareExchange) \ _(AtomicsExchange) \ diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index 9e40b3959..1f763a4f2 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -821,7 +821,6 @@ class IonBuilder InliningStatus inlineArrayPush(CallInfo& callInfo); InliningStatus inlineArraySlice(CallInfo& callInfo); InliningStatus inlineArrayJoin(CallInfo& callInfo); - InliningStatus inlineArraySplice(CallInfo& callInfo); // Math natives. InliningStatus inlineMathAbs(CallInfo& callInfo); diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 68417138b..22f1d5f70 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -656,16 +656,6 @@ LIRGenerator::visitAssertRecoveredOnBailout(MAssertRecoveredOnBailout* assertion MOZ_CRASH("AssertRecoveredOnBailout nodes are always recovered on bailouts."); } -void -LIRGenerator::visitArraySplice(MArraySplice* ins) -{ - LArraySplice* lir = new(alloc()) LArraySplice(useRegisterAtStart(ins->object()), - useRegisterAtStart(ins->start()), - useRegisterAtStart(ins->deleteCount())); - add(lir, ins); - assignSafepoint(lir, ins); -} - void LIRGenerator::visitGetDynamicName(MGetDynamicName* ins) { diff --git a/js/src/jit/Lowering.h b/js/src/jit/Lowering.h index b096bb143..9342ef471 100644 --- a/js/src/jit/Lowering.h +++ b/js/src/jit/Lowering.h @@ -107,7 +107,6 @@ class LIRGenerator : public LIRGeneratorSpecific void visitCall(MCall* call); void visitApplyArgs(MApplyArgs* apply); void visitApplyArray(MApplyArray* apply); - void visitArraySplice(MArraySplice* splice); void visitBail(MBail* bail); void visitUnreachable(MUnreachable* unreachable); void visitEncodeSnapshot(MEncodeSnapshot* ins); diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 359f04639..5eee30e49 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -85,8 +85,6 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target) return inlineArrayPush(callInfo); case InlinableNative::ArraySlice: return inlineArraySlice(callInfo); - case InlinableNative::ArraySplice: - return inlineArraySplice(callInfo); // Atomic natives. case InlinableNative::AtomicsCompareExchange: @@ -653,46 +651,6 @@ IonBuilder::inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode) return InliningStatus_Inlined; } -IonBuilder::InliningStatus -IonBuilder::inlineArraySplice(CallInfo& callInfo) -{ - if (callInfo.argc() != 2 || callInfo.constructing()) { - trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm); - return InliningStatus_NotInlined; - } - - // Ensure |this|, argument and result are objects. - if (getInlineReturnType() != MIRType::Object) - return InliningStatus_NotInlined; - if (callInfo.thisArg()->type() != MIRType::Object) - return InliningStatus_NotInlined; - if (callInfo.getArg(0)->type() != MIRType::Int32) - return InliningStatus_NotInlined; - if (callInfo.getArg(1)->type() != MIRType::Int32) - return InliningStatus_NotInlined; - - callInfo.setImplicitlyUsedUnchecked(); - - // Specialize arr.splice(start, deleteCount) with unused return value and - // avoid creating the result array in this case. - if (!BytecodeIsPopped(pc)) { - trackOptimizationOutcome(TrackedOutcome::CantInlineGeneric); - return InliningStatus_NotInlined; - } - - MArraySplice* ins = MArraySplice::New(alloc(), - callInfo.thisArg(), - callInfo.getArg(0), - callInfo.getArg(1)); - - current->add(ins); - pushConstant(UndefinedValue()); - - if (!resumeAfter(ins)) - return InliningStatus_Error; - return InliningStatus_Inlined; -} - IonBuilder::InliningStatus IonBuilder::inlineArrayJoin(CallInfo& callInfo) { diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index ac55b1150..6c376d528 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -4186,27 +4186,6 @@ class MCallDOMNative : public MCall virtual void computeMovable() override; }; -// arr.splice(start, deleteCount) with unused return value. -class MArraySplice - : public MTernaryInstruction, - public Mix3Policy, IntPolicy<1>, IntPolicy<2> >::Data -{ - private: - - MArraySplice(MDefinition* object, MDefinition* start, MDefinition* deleteCount) - : MTernaryInstruction(object, start, deleteCount) - { } - - public: - INSTRUCTION_HEADER(ArraySplice) - TRIVIAL_NEW_WRAPPERS - NAMED_OPERANDS((0, object), (1, start), (2, deleteCount)) - - bool possiblyCalls() const override { - return true; - } -}; - // fun.apply(self, arguments) class MApplyArgs : public MAryInstruction<3>, diff --git a/js/src/jit/MOpcodes.h b/js/src/jit/MOpcodes.h index ab37604b4..9e460a2ba 100644 --- a/js/src/jit/MOpcodes.h +++ b/js/src/jit/MOpcodes.h @@ -69,7 +69,6 @@ namespace jit { _(Call) \ _(ApplyArgs) \ _(ApplyArray) \ - _(ArraySplice) \ _(Bail) \ _(Unreachable) \ _(EncodeSnapshot) \ diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index e58c3f570..1ff7adfd1 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -303,18 +303,6 @@ StringsEqual(JSContext* cx, HandleString lhs, HandleString rhs, bool* res) template bool StringsEqual(JSContext* cx, HandleString lhs, HandleString rhs, bool* res); template bool StringsEqual(JSContext* cx, HandleString lhs, HandleString rhs, bool* res); -bool -ArraySpliceDense(JSContext* cx, HandleObject obj, uint32_t start, uint32_t deleteCount) -{ - JS::AutoValueArray<4> argv(cx); - argv[0].setUndefined(); - argv[1].setObject(*obj); - argv[2].set(Int32Value(start)); - argv[3].set(Int32Value(deleteCount)); - - return js::array_splice_impl(cx, 2, argv.begin(), false); -} - bool ArrayPopDense(JSContext* cx, HandleObject obj, MutableHandleValue rval) { diff --git a/js/src/jit/VMFunctions.h b/js/src/jit/VMFunctions.h index bd65df134..94f741397 100644 --- a/js/src/jit/VMFunctions.h +++ b/js/src/jit/VMFunctions.h @@ -738,9 +738,6 @@ InitBaselineFrameForOsr(BaselineFrame* frame, InterpreterFrame* interpFrame, JSObject* CreateDerivedTypedObj(JSContext* cx, HandleObject descr, HandleObject owner, int32_t offset); -MOZ_MUST_USE bool -ArraySpliceDense(JSContext* cx, HandleObject obj, uint32_t start, uint32_t deleteCount); - MOZ_MUST_USE bool Recompile(JSContext* cx); MOZ_MUST_USE bool diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h index 2b242d2e4..ecf02816e 100644 --- a/js/src/jit/shared/LIR-shared.h +++ b/js/src/jit/shared/LIR-shared.h @@ -2221,34 +2221,6 @@ class LApplyArrayGeneric : public LCallInstructionHelper -{ - public: - LIR_HEADER(ArraySplice) - - LArraySplice(const LAllocation& object, const LAllocation& start, - const LAllocation& deleteCount) - { - setOperand(0, object); - setOperand(1, start); - setOperand(2, deleteCount); - } - - MArraySplice* mir() const { - return mir_->toArraySplice(); - } - - const LAllocation* getObject() { - return getOperand(0); - } - const LAllocation* getStart() { - return getOperand(1); - } - const LAllocation* getDeleteCount() { - return getOperand(2); - } -}; - class LGetDynamicName : public LCallInstructionHelper { public: diff --git a/js/src/jit/shared/LOpcodes-shared.h b/js/src/jit/shared/LOpcodes-shared.h index deae92839..e260d7e94 100644 --- a/js/src/jit/shared/LOpcodes-shared.h +++ b/js/src/jit/shared/LOpcodes-shared.h @@ -69,7 +69,6 @@ _(NewArrayDynamicLength) \ _(NewTypedArray) \ _(NewTypedArrayDynamicLength) \ - _(ArraySplice) \ _(NewObject) \ _(NewTypedObject) \ _(NewNamedLambdaObject) \ diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 33ff67f36..e618c319f 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -2380,13 +2380,6 @@ CopyDenseElements(JSContext* cx, NativeObject* dst, NativeObject* src, return DenseElementResult::Success; } -/* ES 2016 draft Mar 25, 2016 22.1.3.26. */ -bool -js::array_splice(JSContext* cx, unsigned argc, Value* vp) -{ - return array_splice_impl(cx, argc, vp, true); -} - static inline bool ArraySpliceCopy(JSContext* cx, HandleObject arr, HandleObject obj, uint32_t actualStart, uint32_t actualDeleteCount) @@ -2416,8 +2409,8 @@ ArraySpliceCopy(JSContext* cx, HandleObject arr, HandleObject obj, return SetLengthProperty(cx, arr, actualDeleteCount); } -bool -js::array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueIsUsed) +static bool +array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueIsUsed) { AutoSPSEntry pseudoFrame(cx->runtime(), "Array.prototype.splice"); CallArgs args = CallArgsFromVp(argc, vp); @@ -2667,6 +2660,19 @@ js::array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueI return true; } +/* ES 2016 draft Mar 25, 2016 22.1.3.26. */ +bool +js::array_splice(JSContext* cx, unsigned argc, Value* vp) +{ + return array_splice_impl(cx, argc, vp, true); +} + +static bool +array_splice_noRetVal(JSContext* cx, unsigned argc, Value* vp) +{ + return array_splice_impl(cx, argc, vp, false); +} + struct SortComparatorIndexes { bool operator()(uint32_t a, uint32_t b, bool* lessOrEqualp) { @@ -3084,6 +3090,15 @@ array_of(JSContext* cx, unsigned argc, Value* vp) return true; } +const JSJitInfo js::array_splice_info = { + { (JSJitGetterOp)array_splice_noRetVal }, + { 0 }, /* unused */ + { 0 }, /* unused */ + JSJitInfo::IgnoresReturnValueNative, + JSJitInfo::AliasEverything, + JSVAL_TYPE_UNDEFINED, +}; + static const JSFunctionSpec array_methods[] = { #if JS_HAS_TOSOURCE JS_FN(js_toSource_str, array_toSource, 0,0), @@ -3099,7 +3114,7 @@ static const JSFunctionSpec array_methods[] = { JS_INLINABLE_FN("pop", array_pop, 0,0, ArrayPop), JS_INLINABLE_FN("shift", array_shift, 0,0, ArrayShift), JS_FN("unshift", array_unshift, 1,0), - JS_INLINABLE_FN("splice", array_splice, 2,0, ArraySplice), + JS_FNINFO("splice", array_splice, &array_splice_info, 2,0), /* Pythonic sequence methods. */ JS_SELF_HOSTED_FN("concat", "ArrayConcat", 1,0), diff --git a/js/src/jsarray.h b/js/src/jsarray.h index 00b475a8e..d0084731f 100644 --- a/js/src/jsarray.h +++ b/js/src/jsarray.h @@ -146,9 +146,6 @@ array_push(JSContext* cx, unsigned argc, js::Value* vp); extern bool array_pop(JSContext* cx, unsigned argc, js::Value* vp); -extern bool -array_splice_impl(JSContext* cx, unsigned argc, js::Value* vp, bool pop); - extern bool array_join(JSContext* cx, unsigned argc, js::Value* vp); @@ -173,6 +170,8 @@ array_reverse(JSContext* cx, unsigned argc, js::Value* vp); extern bool array_splice(JSContext* cx, unsigned argc, js::Value* vp); +extern const JSJitInfo array_splice_info; + /* * Append the given (non-hole) value to the end of an array. The array must be * a newborn array -- that is, one which has not been exposed to script for diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index 2ff20cfea..792a00490 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -2154,7 +2154,7 @@ static const JSFunctionSpec intrinsic_functions[] = { JS_INLINABLE_FN("std_Array_slice", array_slice, 2,0, ArraySlice), JS_FN("std_Array_sort", array_sort, 1,0), JS_FN("std_Array_reverse", array_reverse, 0,0), - JS_INLINABLE_FN("std_Array_splice", array_splice, 2,0, ArraySplice), + JS_FNINFO("std_Array_splice", array_splice, &array_splice_info, 2,0), JS_FN("std_Date_now", date_now, 0,0), JS_FN("std_Date_valueOf", date_valueOf, 0,0), -- cgit v1.2.3 From 6444d5d0ef586bda0a6e2745847fc1228ad7e5a2 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 14 Jul 2019 16:18:57 -0400 Subject: 1339395 - Part 1: Align parse method for object literals to match array literals. --- js/src/frontend/FullParseHandler.h | 5 +- js/src/frontend/Parser.cpp | 377 +++++++++++++++++++------------------ 2 files changed, 199 insertions(+), 183 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index c7a7e0843..d34cdf43d 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -302,10 +302,9 @@ class FullParseHandler } MOZ_MUST_USE bool addSpreadElement(ParseNode* literal, uint32_t begin, ParseNode* inner) { - TokenPos pos(begin, inner->pn_pos.end); - ParseNode* spread = new_(PNK_SPREAD, JSOP_NOP, pos, inner); + ParseNode* spread = newSpread(begin, inner); if (!spread) - return null(); + return false; literal->append(spread); literal->pn_xflags |= PNX_ARRAYHOLESPREAD | PNX_NONCONST; return true; diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index bbdffa064..585eef59d 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -4361,85 +4361,90 @@ Parser::objectBindingPattern(DeclarationKind kind, YieldHandling y RootedAtom propAtom(context); for (;;) { TokenKind tt; - if (!tokenStream.getToken(&tt)) + if (!tokenStream.peekToken(&tt)) return null(); if (tt == TOK_RC) break; - TokenPos namePos = pos(); - - tokenStream.ungetToken(); - - PropertyType propType; - Node propName = propertyName(yieldHandling, declKind, literal, &propType, &propAtom); - if (!propName) + if (tt == TOK_TRIPLEDOT) { + // TODO: rest-binding property + error(JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(tt)); return null(); + } else { + TokenPos namePos = tokenStream.nextToken().pos; - if (propType == PropertyType::Normal) { - // Handle e.g., |var {p: x} = o| and |var {p: x=0} = o|. - - if (!tokenStream.getToken(&tt, TokenStream::Operand)) + PropertyType propType; + Node propName = propertyName(yieldHandling, declKind, literal, &propType, &propAtom); + if (!propName) return null(); + if (propType == PropertyType::Normal) { + // Handle e.g., |var {p: x} = o| and |var {p: x=0} = o|. - Node binding = bindingIdentifierOrPattern(kind, yieldHandling, tt); - if (!binding) - return null(); + if (!tokenStream.getToken(&tt, TokenStream::Operand)) + return null(); - bool hasInitializer; - if (!tokenStream.matchToken(&hasInitializer, TOK_ASSIGN)) - return null(); + Node binding = bindingIdentifierOrPattern(kind, yieldHandling, tt); + if (!binding) + return null(); - Node bindingExpr = hasInitializer - ? bindingInitializer(binding, kind, yieldHandling) - : binding; - if (!bindingExpr) - return null(); + bool hasInitializer; + if (!tokenStream.matchToken(&hasInitializer, TOK_ASSIGN)) + return null(); - if (!handler.addPropertyDefinition(literal, propName, bindingExpr)) - return null(); - } else if (propType == PropertyType::Shorthand) { - // Handle e.g., |var {x, y} = o| as destructuring shorthand - // for |var {x: x, y: y} = o|. - MOZ_ASSERT(TokenKindIsPossibleIdentifierName(tt)); + Node bindingExpr = hasInitializer + ? bindingInitializer(binding, kind, yieldHandling) + : binding; + if (!bindingExpr) + return null(); - Node binding = bindingIdentifier(kind, yieldHandling); - if (!binding) - return null(); + if (!handler.addPropertyDefinition(literal, propName, bindingExpr)) + return null(); + } else if (propType == PropertyType::Shorthand) { + // Handle e.g., |var {x, y} = o| as destructuring shorthand + // for |var {x: x, y: y} = o|. + MOZ_ASSERT(TokenKindIsPossibleIdentifierName(tt)); - if (!handler.addShorthand(literal, propName, binding)) - return null(); - } else if (propType == PropertyType::CoverInitializedName) { - // Handle e.g., |var {x=1, y=2} = o| as destructuring shorthand - // with default values. - MOZ_ASSERT(TokenKindIsPossibleIdentifierName(tt)); + Node binding = bindingIdentifier(kind, yieldHandling); + if (!binding) + return null(); - Node binding = bindingIdentifier(kind, yieldHandling); - if (!binding) - return null(); + if (!handler.addShorthand(literal, propName, binding)) + return null(); + } else if (propType == PropertyType::CoverInitializedName) { + // Handle e.g., |var {x=1, y=2} = o| as destructuring + // shorthand with default values. + MOZ_ASSERT(TokenKindIsPossibleIdentifierName(tt)); - tokenStream.consumeKnownToken(TOK_ASSIGN); + Node binding = bindingIdentifier(kind, yieldHandling); + if (!binding) + return null(); - Node bindingExpr = bindingInitializer(binding, kind, yieldHandling); - if (!bindingExpr) - return null(); + tokenStream.consumeKnownToken(TOK_ASSIGN); + + Node bindingExpr = bindingInitializer(binding, kind, yieldHandling); + if (!bindingExpr) + return null(); - if (!handler.addPropertyDefinition(literal, propName, bindingExpr)) + if (!handler.addPropertyDefinition(literal, propName, bindingExpr)) + return null(); + } else { + errorAt(namePos.begin, JSMSG_NO_VARIABLE_NAME); return null(); - } else { - errorAt(namePos.begin, JSMSG_NO_VARIABLE_NAME); - return null(); + + } } - if (!tokenStream.getToken(&tt)) + bool matched; + if (!tokenStream.matchToken(&matched, TOK_COMMA)) return null(); - if (tt == TOK_RC) + if (!matched) break; - if (tt != TOK_COMMA) { - reportMissingClosing(JSMSG_CURLY_AFTER_LIST, JSMSG_CURLY_OPENED, begin); - return null(); - } } + MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::None, + reportMissingClosing(JSMSG_CURLY_AFTER_LIST, + JSMSG_CURLY_OPENED, begin)); + handler.setEndPosition(literal, pos().end); return literal; } @@ -9682,173 +9687,185 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* RootedAtom propAtom(context); for (;;) { TokenKind tt; - if (!tokenStream.getToken(&tt)) + if (!tokenStream.peekToken(&tt)) return null(); if (tt == TOK_RC) break; - TokenPos namePos = pos(); - - tokenStream.ungetToken(); - - PropertyType propType; - Node propName = propertyName(yieldHandling, declKind, literal, &propType, &propAtom); - if (!propName) + if (tt == TOK_TRIPLEDOT) { + // TODO: object spread + error(JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(tt)); return null(); + } else { + TokenPos namePos = tokenStream.nextToken().pos; + + PropertyType propType; + Node propName = propertyName(yieldHandling, declKind, literal, &propType, &propAtom); + if (!propName) - if (propType == PropertyType::Normal) { - TokenPos exprPos; - if (!tokenStream.peekTokenPos(&exprPos, TokenStream::Operand)) - return null(); - Node propExpr = assignExpr(InAllowed, yieldHandling, TripledotProhibited, - possibleError); - if (!propExpr) return null(); - handler.checkAndSetIsDirectRHSAnonFunction(propExpr); + if (propType == PropertyType::Normal) { + TokenPos exprPos; + if (!tokenStream.peekTokenPos(&exprPos, TokenStream::Operand)) + return null(); - if (foldConstants && !FoldConstants(context, &propExpr, this)) - return null(); + Node propExpr = assignExpr(InAllowed, yieldHandling, TripledotProhibited, + possibleError); + if (!propExpr) + return null(); - if (propAtom == context->names().proto) { - if (seenPrototypeMutation) { - // Directly report the error when we're not in a - // destructuring context. - if (!possibleError) { - errorAt(namePos.begin, JSMSG_DUPLICATE_PROTO_PROPERTY); - return null(); - } + handler.checkAndSetIsDirectRHSAnonFunction(propExpr); - // Otherwise delay error reporting until we've determined - // whether or not we're destructuring. - possibleError->setPendingExpressionErrorAt(namePos, - JSMSG_DUPLICATE_PROTO_PROPERTY); - } - seenPrototypeMutation = true; + if (possibleError) + checkDestructuringAssignmentElement(propExpr, exprPos, possibleError); - // Note: this occurs *only* if we observe TOK_COLON! Only - // __proto__: v mutates [[Prototype]]. Getters, setters, - // method/generator definitions, computed property name - // versions of all of these, and shorthands do not. - if (!handler.addPrototypeMutation(literal, namePos.begin, propExpr)) + if (foldConstants && !FoldConstants(context, &propExpr, this)) return null(); - } else { - if (!handler.isConstant(propExpr)) - handler.setListFlag(literal, PNX_NONCONST); - if (!handler.addPropertyDefinition(literal, propName, propExpr)) + if (propAtom == context->names().proto) { + if (seenPrototypeMutation) { + // Directly report the error when we're not in a + // destructuring context. + if (!possibleError) { + errorAt(namePos.begin, JSMSG_DUPLICATE_PROTO_PROPERTY); + return null(); + } + + // Otherwise delay error reporting until we've + // determined whether or not we're destructuring. + possibleError->setPendingExpressionErrorAt(namePos, + JSMSG_DUPLICATE_PROTO_PROPERTY); + } + seenPrototypeMutation = true; + + // Note: this occurs *only* if we observe TOK_COLON! Only + // __proto__: v mutates [[Prototype]]. Getters, setters, + // method/generator definitions, computed property name + // versions of all of these, and shorthands do not. + if (!handler.addPrototypeMutation(literal, namePos.begin, propExpr)) + return null(); + } else { + if (!handler.isConstant(propExpr)) + handler.setListFlag(literal, PNX_NONCONST); + + if (!handler.addPropertyDefinition(literal, propName, propExpr)) + return null(); + } + } else if (propType == PropertyType::Shorthand) { + /* + * Support, e.g., |({x, y} = o)| as destructuring shorthand + * for |({x: x, y: y} = o)|, and |var o = {x, y}| as + * initializer shorthand for |var o = {x: x, y: y}|. + */ + Rooted name(context, identifierReference(yieldHandling)); + if (!name) return null(); - } - if (possibleError) - checkDestructuringAssignmentElement(propExpr, exprPos, possibleError); - } else if (propType == PropertyType::Shorthand) { - /* - * Support, e.g., |({x, y} = o)| as destructuring shorthand - * for |({x: x, y: y} = o)|, and |var o = {x, y}| as initializer - * shorthand for |var o = {x: x, y: y}|. - */ - Rooted name(context, identifierReference(yieldHandling)); - if (!name) - return null(); + Node nameExpr = identifierReference(name); + if (!nameExpr) + return null(); - Node nameExpr = identifierReference(name); - if (!nameExpr) - return null(); + if (possibleError) + checkDestructuringAssignmentTarget(nameExpr, namePos, possibleError); - if (possibleError) - checkDestructuringAssignmentTarget(nameExpr, namePos, possibleError); + if (!handler.addShorthand(literal, propName, nameExpr)) + return null(); + } else if (propType == PropertyType::CoverInitializedName) { + /* + * Support, e.g., |({x=1, y=2} = o)| as destructuring + * shorthand with default values, as per ES6 12.14.5 + */ + Rooted name(context, identifierReference(yieldHandling)); + if (!name) + return null(); - if (!handler.addShorthand(literal, propName, nameExpr)) - return null(); - } else if (propType == PropertyType::CoverInitializedName) { - /* - * Support, e.g., |({x=1, y=2} = o)| as destructuring shorthand - * with default values, as per ES6 12.14.5 - */ - Rooted name(context, identifierReference(yieldHandling)); - if (!name) - return null(); + Node lhs = identifierReference(name); + if (!lhs) + return null(); - Node lhs = identifierReference(name); - if (!lhs) - return null(); + tokenStream.consumeKnownToken(TOK_ASSIGN); - tokenStream.consumeKnownToken(TOK_ASSIGN); + if (!seenCoverInitializedName) { + // "shorthand default" or "CoverInitializedName" syntax is + // only valid in the case of destructuring. + seenCoverInitializedName = true; - if (!seenCoverInitializedName) { - // "shorthand default" or "CoverInitializedName" syntax is only - // valid in the case of destructuring. - seenCoverInitializedName = true; + if (!possibleError) { + // Destructuring defaults are definitely not allowed + // in this object literal, because of something the + // caller knows about the preceding code. For example, + // maybe the preceding token is an operator: + // |x + {y=z}|. + error(JSMSG_COLON_AFTER_ID); + return null(); + } - if (!possibleError) { - // Destructuring defaults are definitely not allowed in this object literal, - // because of something the caller knows about the preceding code. - // For example, maybe the preceding token is an operator: `x + {y=z}`. - error(JSMSG_COLON_AFTER_ID); - return null(); + // Here we set a pending error so that later in the parse, + // once we've determined whether or not we're + // destructuring, the error can be reported or ignored + // appropriately. + possibleError->setPendingExpressionErrorAt(pos(), JSMSG_COLON_AFTER_ID); } - // Here we set a pending error so that later in the parse, once we've - // determined whether or not we're destructuring, the error can be - // reported or ignored appropriately. - possibleError->setPendingExpressionErrorAt(pos(), JSMSG_COLON_AFTER_ID); - } + if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(lhs, context)) { + // |chars| is "arguments" or "eval" here. + if (!strictModeErrorAt(namePos.begin, JSMSG_BAD_STRICT_ASSIGN, chars)) + return null(); + } - if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(lhs, context)) { - // |chars| is "arguments" or "eval" here. - if (!strictModeErrorAt(namePos.begin, JSMSG_BAD_STRICT_ASSIGN, chars)) + Node rhs = assignExpr(InAllowed, yieldHandling, TripledotProhibited); + if (!rhs) return null(); - } - Node rhs = assignExpr(InAllowed, yieldHandling, TripledotProhibited); - if (!rhs) - return null(); + handler.checkAndSetIsDirectRHSAnonFunction(rhs); - handler.checkAndSetIsDirectRHSAnonFunction(rhs); - - Node propExpr = handler.newAssignment(PNK_ASSIGN, lhs, rhs, JSOP_NOP); - if (!propExpr) - return null(); + Node propExpr = handler.newAssignment(PNK_ASSIGN, lhs, rhs, JSOP_NOP); + if (!propExpr) + return null(); - if (!handler.addPropertyDefinition(literal, propName, propExpr)) - return null(); - } else { - RootedAtom funName(context); - if (!tokenStream.isCurrentTokenType(TOK_RB)) { - funName = propAtom; + if (!handler.addPropertyDefinition(literal, propName, propExpr)) + return null(); + } else { + RootedAtom funName(context); + if (!tokenStream.isCurrentTokenType(TOK_RB)) { + funName = propAtom; - if (propType == PropertyType::Getter || propType == PropertyType::Setter) { - funName = prefixAccessorName(propType, propAtom); - if (!funName) - return null(); + if (propType == PropertyType::Getter || propType == PropertyType::Setter) { + funName = prefixAccessorName(propType, propAtom); + if (!funName) + return null(); + } } - } - Node fn = methodDefinition(namePos.begin, propType, funName); - if (!fn) - return null(); + Node fn = methodDefinition(namePos.begin, propType, funName); + if (!fn) + return null(); - handler.checkAndSetIsDirectRHSAnonFunction(fn); + handler.checkAndSetIsDirectRHSAnonFunction(fn); - JSOp op = JSOpFromPropertyType(propType); - if (!handler.addObjectMethodDefinition(literal, propName, fn, op)) - return null(); + JSOp op = JSOpFromPropertyType(propType); + if (!handler.addObjectMethodDefinition(literal, propName, fn, op)) + return null(); - if (possibleError) - possibleError->setPendingDestructuringErrorAt(namePos, JSMSG_BAD_DESTRUCT_TARGET); + if (possibleError) { + possibleError->setPendingDestructuringErrorAt(namePos, + JSMSG_BAD_DESTRUCT_TARGET); + } + } } - if (!tokenStream.getToken(&tt)) + bool matched; + if (!tokenStream.matchToken(&matched, TOK_COMMA)) return null(); - if (tt == TOK_RC) + if (!matched) break; - if (tt != TOK_COMMA) { - reportMissingClosing(JSMSG_CURLY_AFTER_LIST, JSMSG_CURLY_OPENED, openedPos); - return null(); - } } + MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::None, + reportMissingClosing(JSMSG_CURLY_AFTER_LIST, + JSMSG_CURLY_OPENED, openedPos)); + handler.setEndPosition(literal, pos().end); return literal; } -- cgit v1.2.3 From 638a904d0dbe4bcc5a625ea472c7e65ac75dbc06 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 14 Jul 2019 16:28:47 -0400 Subject: Refactor Token& nextToken --- js/src/frontend/TokenStream.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index e92de4b03..2744fd144 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -571,6 +571,11 @@ class MOZ_STACK_CLASS TokenStream #endif } + const Token& nextToken() const { + MOZ_ASSERT(hasLookahead()); + return tokens[(cursor + 1) & ntokensMask]; + } + // Advance to the next token. If the token stream encountered an error, // return false. Otherwise return true and store the token kind in |*ttp|. MOZ_MUST_USE bool getToken(TokenKind* ttp, Modifier modifier = None) { @@ -1017,10 +1022,6 @@ class MOZ_STACK_CLASS TokenStream void updateLineInfoForEOL(); void updateFlagsForEOL(); - const Token& nextToken() const { - MOZ_ASSERT(hasLookahead()); - return tokens[(cursor + 1) & ntokensMask]; - } bool hasLookahead() const { return lookahead > 0; } -- cgit v1.2.3 From 091d00f1bd22f821d3926c46dd1d6cf7fbc746f4 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 14 Jul 2019 16:37:57 -0400 Subject: 1339395 - Part 2: Add parser support for rest and spread object properties. --- js/src/builtin/ReflectParse.cpp | 12 +++++++++++ js/src/frontend/BytecodeEmitter.cpp | 12 +++++++++++ js/src/frontend/FullParseHandler.h | 12 +++++++++++ js/src/frontend/Parser.cpp | 42 ++++++++++++++++++++++++++++++------ js/src/frontend/SyntaxParseHandler.h | 1 + 5 files changed, 73 insertions(+), 6 deletions(-) (limited to 'js/src') diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp index 3495ede2f..8e8bb2417 100644 --- a/js/src/builtin/ReflectParse.cpp +++ b/js/src/builtin/ReflectParse.cpp @@ -3222,6 +3222,8 @@ ASTSerializer::property(ParseNode* pn, MutableHandleValue dst) return expression(pn->pn_kid, &val) && builder.prototypeMutation(val, &pn->pn_pos, dst); } + if (pn->isKind(PNK_SPREAD)) + return expression(pn, dst); PropKind kind; switch (pn->getOp()) { @@ -3342,6 +3344,16 @@ ASTSerializer::objectPattern(ParseNode* pn, MutableHandleValue dst) return false; for (ParseNode* propdef = pn->pn_head; propdef; propdef = propdef->pn_next) { + if (propdef->isKind(PNK_SPREAD)) { + RootedValue target(cx); + RootedValue spread(cx); + if (!pattern(propdef->pn_kid, &target)) + return false; + if(!builder.spreadExpression(target, &propdef->pn_pos, &spread)) + return false; + elts.infallibleAppend(spread); + continue; + } LOCAL_ASSERT(propdef->isKind(PNK_MUTATEPROTO) != propdef->isOp(JSOP_INITPROP)); RootedValue key(cx); diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index c2eae4344..f9a1f8675 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -5815,6 +5815,11 @@ BytecodeEmitter::emitDestructuringOpsObject(ParseNode* pattern, DestructuringFla return false; for (ParseNode* member = pattern->pn_head; member; member = member->pn_next) { + if (member->isKind(PNK_SPREAD)) { + // FIXME: Implement + continue; + } + ParseNode* subpattern; if (member->isKind(PNK_MUTATEPROTO)) subpattern = member->pn_kid; @@ -9449,6 +9454,13 @@ BytecodeEmitter::emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp, continue; } + if (propdef->isKind(PNK_SPREAD)) { + MOZ_ASSERT(type == ObjectLiteral); + objp.set(nullptr); + // FIXME: implement + continue; + } + bool extraPop = false; if (type == ClassBody && propdef->as().isStatic()) { extraPop = true; diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index d34cdf43d..2d7f57e1e 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -395,6 +395,18 @@ class FullParseHandler return true; } + MOZ_MUST_USE bool addSpreadProperty(ParseNode* literal, uint32_t begin, ParseNode* inner) { + MOZ_ASSERT(literal->isKind(PNK_OBJECT)); + MOZ_ASSERT(literal->isArity(PN_LIST)); + + setListFlag(literal, PNX_NONCONST); + ParseNode* spread = newSpread(begin, inner); + if (!spread) + return false; + literal->append(spread); + return true; + } + MOZ_MUST_USE bool addObjectMethodDefinition(ParseNode* literal, ParseNode* key, ParseNode* fn, JSOp op) { diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 585eef59d..47e0f943d 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -4367,9 +4367,20 @@ Parser::objectBindingPattern(DeclarationKind kind, YieldHandling y break; if (tt == TOK_TRIPLEDOT) { - // TODO: rest-binding property - error(JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(tt)); - return null(); + // rest-binding property + tokenStream.consumeKnownToken(TOK_TRIPLEDOT); + uint32_t begin = pos().begin; + + TokenKind tt; + if (!tokenStream.getToken(&tt)) + return null(); + + Node inner = bindingIdentifierOrPattern(kind, yieldHandling, tt); + if (!inner) + return null(); + + if (!handler.addSpreadProperty(literal, begin, inner)) + return null(); } else { TokenPos namePos = tokenStream.nextToken().pos; @@ -4439,6 +4450,10 @@ Parser::objectBindingPattern(DeclarationKind kind, YieldHandling y return null(); if (!matched) break; + if (tt == TOK_TRIPLEDOT) { + error(JSMSG_REST_WITH_COMMA); + return null(); + } } MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::None, @@ -9693,9 +9708,22 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* break; if (tt == TOK_TRIPLEDOT) { - // TODO: object spread - error(JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(tt)); - return null(); + // object spread + tokenStream.consumeKnownToken(TOK_TRIPLEDOT); + uint32_t begin = pos().begin; + + TokenPos innerPos; + if (!tokenStream.peekTokenPos(&innerPos, TokenStream::Operand)) + return null(); + + Node inner = assignExpr(InAllowed, yieldHandling, TripledotProhibited, + possibleError); + if (!inner) + return null(); + if (possibleError) + checkDestructuringAssignmentTarget(inner, innerPos, possibleError); + if (!handler.addSpreadProperty(literal, begin, inner)) + return null(); } else { TokenPos namePos = tokenStream.nextToken().pos; @@ -9860,6 +9888,8 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* return null(); if (!matched) break; + if (tt == TOK_TRIPLEDOT && possibleError) + possibleError->setPendingDestructuringErrorAt(pos(), JSMSG_REST_WITH_COMMA); } MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::None, diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index 7de6a242e..a604b599f 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -298,6 +298,7 @@ class SyntaxParseHandler MOZ_MUST_USE bool addPrototypeMutation(Node literal, uint32_t begin, Node expr) { return true; } MOZ_MUST_USE bool addPropertyDefinition(Node literal, Node name, Node expr) { return true; } MOZ_MUST_USE bool addShorthand(Node literal, Node name, Node expr) { return true; } + MOZ_MUST_USE bool addSpreadProperty(Node literal, uint32_t begin, Node inner) { return true; } MOZ_MUST_USE bool addObjectMethodDefinition(Node literal, Node name, Node fn, JSOp op) { return true; } MOZ_MUST_USE bool addClassMethodDefinition(Node literal, Node name, Node fn, JSOp op, bool isStatic) { return true; } Node newYieldExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; } -- cgit v1.2.3 From 3048ff4346bf2021059bdecec6343c73bb26833a Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 14 Jul 2019 20:14:28 -0400 Subject: 1339395 - Part 3: Add BytecodeEmitter support for object rest and spread properties. --- js/src/builtin/Utilities.js | 63 ++++++++ js/src/frontend/BytecodeEmitter.cpp | 304 ++++++++++++++++++++++++++++++------ js/src/frontend/BytecodeEmitter.h | 15 ++ js/src/vm/CommonPropertyNames.h | 2 + 4 files changed, 339 insertions(+), 45 deletions(-) (limited to 'js/src') diff --git a/js/src/builtin/Utilities.js b/js/src/builtin/Utilities.js index c73bc5e7f..ec5c88336 100644 --- a/js/src/builtin/Utilities.js +++ b/js/src/builtin/Utilities.js @@ -229,6 +229,69 @@ function GetInternalError(msg) { // To be used when a function is required but calling it shouldn't do anything. function NullFunction() {} +// Object Rest/Spread Properties proposal +// Abstract operation: CopyDataProperties (target, source, excluded) +function CopyDataProperties(target, source, excluded) { + // Step 1. + assert(IsObject(target), "target is an object"); + + // Step 2. + assert(IsObject(excluded), "excluded is an object"); + + // Steps 3, 6. + if (source === undefined || source === null) + return; + + // Step 4.a. + source = ToObject(source); + + // Step 4.b. + var keys = OwnPropertyKeys(source, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS); + + // Step 5. + for (var index = 0; index < keys.length; index++) { + var key = keys[index]; + + // We abbreviate this by calling propertyIsEnumerable which is faster + // and returns false for not defined properties. + if (!callFunction(std_Object_hasOwnProperty, key, excluded) && callFunction(std_Object_propertyIsEnumerable, source, key)) + _DefineDataProperty(target, key, source[key]); + } + + // Step 6 (Return). +} + +// Object Rest/Spread Properties proposal +// Abstract operation: CopyDataProperties (target, source, excluded) +function CopyDataPropertiesUnfiltered(target, source) { + // Step 1. + assert(IsObject(target), "target is an object"); + + // Step 2 (Not applicable). + + // Steps 3, 6. + if (source === undefined || source === null) + return; + + // Step 4.a. + source = ToObject(source); + + // Step 4.b. + var keys = OwnPropertyKeys(source, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS); + + // Step 5. + for (var index = 0; index < keys.length; index++) { + var key = keys[index]; + + // We abbreviate this by calling propertyIsEnumerable which is faster + // and returns false for not defined properties. + if (callFunction(std_Object_propertyIsEnumerable, source, key)) + _DefineDataProperty(target, key, source[key]); + } + + // Step 6 (Return). +} + /*************************************** Testing functions ***************************************/ function outer() { return function inner() { diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index f9a1f8675..b3b658a2d 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -5814,41 +5814,78 @@ BytecodeEmitter::emitDestructuringOpsObject(ParseNode* pattern, DestructuringFla if (!emitRequireObjectCoercible()) // ... RHS return false; - for (ParseNode* member = pattern->pn_head; member; member = member->pn_next) { - if (member->isKind(PNK_SPREAD)) { - // FIXME: Implement - continue; - } + bool needsRestPropertyExcludedSet = pattern->pn_count > 1 && + pattern->last()->isKind(PNK_SPREAD); + if (needsRestPropertyExcludedSet) { + if (!emitDestructuringObjRestExclusionSet(pattern)) // ... RHS SET + return false; + if (!emit1(JSOP_SWAP)) // ... SET RHS + return false; + } + + for (ParseNode* member = pattern->pn_head; member; member = member->pn_next) { ParseNode* subpattern; - if (member->isKind(PNK_MUTATEPROTO)) + if (member->isKind(PNK_MUTATEPROTO) || member->isKind(PNK_SPREAD)) subpattern = member->pn_kid; else subpattern = member->pn_right; + ParseNode* lhs = subpattern; + MOZ_ASSERT_IF(member->isKind(PNK_SPREAD), !lhs->isKind(PNK_ASSIGN)); if (lhs->isKind(PNK_ASSIGN)) lhs = lhs->pn_left; size_t emitted; - if (!emitDestructuringLHSRef(lhs, &emitted)) // ... RHS *LREF + if (!emitDestructuringLHSRef(lhs, &emitted)) // ... *SET RHS *LREF return false; // Duplicate the value being destructured to use as a reference base. if (emitted) { - if (!emitDupAt(emitted)) // ... RHS *LREF RHS + if (!emitDupAt(emitted)) // ... *SET RHS *LREF RHS return false; } else { - if (!emit1(JSOP_DUP)) // ... RHS RHS + if (!emit1(JSOP_DUP)) // ... *SET RHS RHS return false; } + if (member->isKind(PNK_SPREAD)) { + if (!updateSourceCoordNotes(member->pn_pos.begin)) + return false; + + if (!emitNewInit(JSProto_Object)) // ... *SET RHS *LREF RHS TARGET + return false; + if (!emit1(JSOP_DUP)) // ... *SET RHS *LREF RHS TARGET TARGET + return false; + if (!emit2(JSOP_PICK, 2)) // ... *SET RHS *LREF TARGET TARGET RHS + return false; + + if (needsRestPropertyExcludedSet) { + if (!emit2(JSOP_PICK, emitted + 4)) // ... RHS *LREF TARGET TARGET RHS SET + return false; + } + + CopyOption option = needsRestPropertyExcludedSet + ? CopyOption::Filtered + : CopyOption::Unfiltered; + if (!emitCopyDataProperties(option)) // ... RHS *LREF TARGET + return false; + + // Destructure TARGET per this member's lhs. + if (!emitSetOrInitializeDestructuring(lhs, flav)) // ... RHS + return false; + + MOZ_ASSERT(member == pattern->last(), "Rest property is always last"); + break; + } + // Now push the property name currently being matched, which is the // current property name "label" on the left of a colon in the object // initialiser. bool needsGetElem = true; if (member->isKind(PNK_MUTATEPROTO)) { - if (!emitAtomOp(cx->names().proto, JSOP_GETPROP)) // ... RHS *LREF PROP + if (!emitAtomOp(cx->names().proto, JSOP_GETPROP)) // ... *SET RHS *LREF PROP return false; needsGetElem = false; } else { @@ -5856,7 +5893,7 @@ BytecodeEmitter::emitDestructuringOpsObject(ParseNode* pattern, DestructuringFla ParseNode* key = member->pn_left; if (key->isKind(PNK_NUMBER)) { - if (!emitNumberOp(key->pn_dval)) // ... RHS *LREF RHS KEY + if (!emitNumberOp(key->pn_dval)) // ... *SET RHS *LREF RHS KEY return false; } else if (key->isKind(PNK_OBJECT_PROPERTY_NAME) || key->isKind(PNK_STRING)) { PropertyName* name = key->pn_atom->asPropertyName(); @@ -5866,30 +5903,142 @@ BytecodeEmitter::emitDestructuringOpsObject(ParseNode* pattern, DestructuringFla // as indexes for simplification of downstream analysis. jsid id = NameToId(name); if (id != IdToTypeId(id)) { - if (!emitTree(key)) // ... RHS *LREF RHS KEY + if (!emitTree(key)) // ... *SET RHS *LREF RHS KEY return false; } else { - if (!emitAtomOp(name, JSOP_GETPROP)) // ... RHS *LREF PROP + if (!emitAtomOp(name, JSOP_GETPROP)) // ... *SET RHS *LREF PROP return false; needsGetElem = false; } } else { - if (!emitComputedPropertyName(key)) // ... RHS *LREF RHS KEY + if (!emitComputedPropertyName(key)) // ... *SET RHS *LREF RHS KEY return false; + + // Add the computed property key to the exclusion set. + if (needsRestPropertyExcludedSet) { + if (!emitDupAt(emitted + 3)) // ... SET RHS *LREF RHS KEY SET + return false; + if (!emitDupAt(1)) // ... SET RHS *LREF RHS KEY SET KEY + return false; + if (!emit1(JSOP_UNDEFINED)) // ... SET RHS *LREF RHS KEY SET KEY UNDEFINED + return false; + if (!emit1(JSOP_INITELEM)) // ... SET RHS *LREF RHS KEY SET + return false; + if (!emit1(JSOP_POP)) // ... SET RHS *LREF RHS KEY + return false; + } } } // Get the property value if not done already. - if (needsGetElem && !emitElemOpBase(JSOP_GETELEM)) // ... RHS *LREF PROP + if (needsGetElem && !emitElemOpBase(JSOP_GETELEM)) // ... *SET RHS *LREF PROP return false; if (subpattern->isKind(PNK_ASSIGN)) { - if (!emitDefault(subpattern->pn_right, lhs)) // ... RHS *LREF VALUE + if (!emitDefault(subpattern->pn_right, lhs)) // ... *SET RHS *LREF VALUE return false; } // Destructure PROP per this member's lhs. - if (!emitSetOrInitializeDestructuring(subpattern, flav)) // ... RHS + if (!emitSetOrInitializeDestructuring(subpattern, flav)) // ... *SET RHS + return false; + } + + return true; +} + +bool +BytecodeEmitter::emitDestructuringObjRestExclusionSet(ParseNode* pattern) +{ + MOZ_ASSERT(pattern->isKind(PNK_OBJECT)); + MOZ_ASSERT(pattern->isArity(PN_LIST)); + MOZ_ASSERT(pattern->last()->isKind(PNK_SPREAD)); + + ptrdiff_t offset = this->offset(); + if (!emitNewInit(JSProto_Object)) + return false; + + // Try to construct the shape of the object as we go, so we can emit a + // JSOP_NEWOBJECT with the final shape instead. + // In the case of computed property names and indices, we cannot fix the + // shape at bytecode compile time. When the shape cannot be determined, + // |obj| is nulled out. + + // No need to do any guessing for the object kind, since we know the upper + // bound of how many properties we plan to have. + gc::AllocKind kind = gc::GetGCObjectKind(pattern->pn_count - 1); + RootedPlainObject obj(cx, NewBuiltinClassInstance(cx, kind, TenuredObject)); + if (!obj) + return false; + + RootedAtom pnatom(cx); + for (ParseNode* member = pattern->pn_head; member; member = member->pn_next) { + if (member->isKind(PNK_SPREAD)) + break; + + bool isIndex = false; + if (member->isKind(PNK_MUTATEPROTO)) { + pnatom.set(cx->names().proto); + } else { + ParseNode* key = member->pn_left; + if (key->isKind(PNK_NUMBER)) { + if (!emitNumberOp(key->pn_dval)) + return false; + isIndex = true; + } else if (key->isKind(PNK_OBJECT_PROPERTY_NAME) || key->isKind(PNK_STRING)) { + // The parser already checked for atoms representing indexes and + // used PNK_NUMBER instead, but also watch for ids which TI treats + // as indexes for simplification of downstream analysis. + jsid id = NameToId(key->pn_atom->asPropertyName()); + if (id != IdToTypeId(id)) { + if (!emitTree(key)) + return false; + isIndex = true; + } else { + pnatom.set(key->pn_atom); + } + } else { + // Otherwise this is a computed property name which needs to + // be added dynamically. + obj.set(nullptr); + continue; + } + } + + // Initialize elements with |undefined|. + if (!emit1(JSOP_UNDEFINED)) + return false; + + if (isIndex) { + obj.set(nullptr); + if (!emit1(JSOP_INITELEM)) + return false; + } else { + uint32_t index; + if (!makeAtomIndex(pnatom, &index)) + return false; + + if (obj) { + MOZ_ASSERT(!obj->inDictionaryMode()); + Rooted id(cx, AtomToId(pnatom)); + if (!NativeDefineProperty(cx, obj, id, UndefinedHandleValue, nullptr, nullptr, + JSPROP_ENUMERATE)) + { + return false; + } + if (obj->inDictionaryMode()) + obj.set(nullptr); + } + + if (!emitIndex32(JSOP_INITPROP, index)) + return false; + } + } + + if (obj) { + // The object survived and has a predictable shape: update the + // original bytecode. + if (!replaceNewInitWithNewObject(obj, offset)) return false; } @@ -6770,6 +6919,53 @@ BytecodeEmitter::emitRequireObjectCoercible() return true; } +bool +BytecodeEmitter::emitCopyDataProperties(CopyOption option) +{ + DebugOnly depth = this->stackDepth; + + uint32_t argc; + if (option == CopyOption::Filtered) { + MOZ_ASSERT(depth > 2); // TARGET SOURCE SET + argc = 3; + + if (!emitAtomOp(cx->names().CopyDataProperties, + JSOP_GETINTRINSIC)) // TARGET SOURCE SET COPYDATAPROPERTIES + { + return false; + } + } else { + MOZ_ASSERT(depth > 1); // TARGET SOURCE + argc = 2; + + if (!emitAtomOp(cx->names().CopyDataPropertiesUnfiltered, + JSOP_GETINTRINSIC)) // TARGET SOURCE COPYDATAPROPERTIES + { + return false; + } + } + + if (!emit1(JSOP_UNDEFINED)) // TARGET SOURCE *SET COPYDATAPROPERTIES UNDEFINED + return false; + if (!emit2(JSOP_PICK, argc + 1)) // SOURCE *SET COPYDATAPROPERTIES UNDEFINED TARGET + return false; + if (!emit2(JSOP_PICK, argc + 1)) // *SET COPYDATAPROPERTIES UNDEFINED TARGET SOURCE + return false; + if (option == CopyOption::Filtered) { + if (!emit2(JSOP_PICK, argc + 1)) // COPYDATAPROPERTIES UNDEFINED TARGET SOURCE SET + return false; + } + if (!emitCall(JSOP_CALL_IGNORES_RV, argc)) // IGNORED + return false; + checkTypeSet(JSOP_CALL_IGNORES_RV); + + if (!emit1(JSOP_POP)) // - + return false; + + MOZ_ASSERT(depth - int(argc) == this->stackDepth); + return true; +} + bool BytecodeEmitter::emitIterator() { @@ -9456,8 +9652,17 @@ BytecodeEmitter::emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp, if (propdef->isKind(PNK_SPREAD)) { MOZ_ASSERT(type == ObjectLiteral); + + if (!emit1(JSOP_DUP)) + return false; + + if (!emitTree(propdef->pn_kid)) + return false; + + if (!emitCopyDataProperties(CopyOption::Unfiltered)) + return false; + objp.set(nullptr); - // FIXME: implement continue; } @@ -9487,7 +9692,7 @@ BytecodeEmitter::emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp, // The parser already checked for atoms representing indexes and // used PNK_NUMBER instead, but also watch for ids which TI treats - // as indexes for simpliciation of downstream analysis. + // as indexes for simplification of downstream analysis. jsid id = NameToId(key->pn_atom->asPropertyName()); if (id != IdToTypeId(id)) { if (!emitTree(key)) @@ -9574,8 +9779,7 @@ BytecodeEmitter::emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp, MOZ_ASSERT(!IsHiddenInitOp(op)); MOZ_ASSERT(!objp->inDictionaryMode()); Rooted id(cx, AtomToId(key->pn_atom)); - RootedValue undefinedValue(cx, UndefinedValue()); - if (!NativeDefineProperty(cx, objp, id, undefinedValue, nullptr, nullptr, + if (!NativeDefineProperty(cx, objp, id, UndefinedHandleValue, nullptr, nullptr, JSPROP_ENUMERATE)) { return false; @@ -9618,15 +9822,16 @@ BytecodeEmitter::emitObject(ParseNode* pn) if (!emitNewInit(JSProto_Object)) return false; - /* - * Try to construct the shape of the object as we go, so we can emit a - * JSOP_NEWOBJECT with the final shape instead. - */ - RootedPlainObject obj(cx); - // No need to do any guessing for the object kind, since we know exactly - // how many properties we plan to have. + // Try to construct the shape of the object as we go, so we can emit a + // JSOP_NEWOBJECT with the final shape instead. + // In the case of computed property names and indices, we cannot fix the + // shape at bytecode compile time. When the shape cannot be determined, + // |obj| is nulled out. + + // No need to do any guessing for the object kind, since we know the upper + // bound of how many properties we plan to have. gc::AllocKind kind = gc::GetGCObjectKind(pn->pn_count); - obj = NewBuiltinClassInstance(cx, kind, TenuredObject); + RootedPlainObject obj(cx, NewBuiltinClassInstance(cx, kind, TenuredObject)); if (!obj) return false; @@ -9634,25 +9839,34 @@ BytecodeEmitter::emitObject(ParseNode* pn) return false; if (obj) { - /* - * The object survived and has a predictable shape: update the original - * bytecode. - */ - ObjectBox* objbox = parser->newObjectBox(obj); - if (!objbox) + // The object survived and has a predictable shape: update the original + // bytecode. + if (!replaceNewInitWithNewObject(obj, offset)) return false; + } - static_assert(JSOP_NEWINIT_LENGTH == JSOP_NEWOBJECT_LENGTH, - "newinit and newobject must have equal length to edit in-place"); + return true; +} - uint32_t index = objectList.add(objbox); - jsbytecode* code = this->code(offset); - code[0] = JSOP_NEWOBJECT; - code[1] = jsbytecode(index >> 24); - code[2] = jsbytecode(index >> 16); - code[3] = jsbytecode(index >> 8); - code[4] = jsbytecode(index); - } +bool +BytecodeEmitter::replaceNewInitWithNewObject(JSObject* obj, ptrdiff_t offset) +{ + ObjectBox* objbox = parser->newObjectBox(obj); + if (!objbox) + return false; + + static_assert(JSOP_NEWINIT_LENGTH == JSOP_NEWOBJECT_LENGTH, + "newinit and newobject must have equal length to edit in-place"); + + uint32_t index = objectList.add(objbox); + jsbytecode* code = this->code(offset); + + MOZ_ASSERT(code[0] == JSOP_NEWINIT); + code[0] = JSOP_NEWOBJECT; + code[1] = jsbytecode(index >> 24); + code[2] = jsbytecode(index >> 16); + code[3] = jsbytecode(index >> 8); + code[4] = jsbytecode(index); return true; } diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index 99d6a2ff7..595ee6405 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -540,6 +540,8 @@ struct MOZ_STACK_CLASS BytecodeEmitter MOZ_NEVER_INLINE MOZ_MUST_USE bool emitFunction(ParseNode* pn, bool needsProto = false); MOZ_NEVER_INLINE MOZ_MUST_USE bool emitObject(ParseNode* pn); + MOZ_MUST_USE bool replaceNewInitWithNewObject(JSObject* obj, ptrdiff_t offset); + MOZ_MUST_USE bool emitHoistedFunctionsInList(ParseNode* pn); MOZ_MUST_USE bool emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp, @@ -667,6 +669,10 @@ struct MOZ_STACK_CLASS BytecodeEmitter // []/{} expression). MOZ_MUST_USE bool emitSetOrInitializeDestructuring(ParseNode* target, DestructuringFlavor flav); + // emitDestructuringObjRestExclusionSet emits the property exclusion set + // for the rest-property in an object pattern. + MOZ_MUST_USE bool emitDestructuringObjRestExclusionSet(ParseNode* pattern); + // emitDestructuringOps assumes the to-be-destructured value has been // pushed on the stack and emits code to destructure each part of a [] or // {} lhs expression. @@ -684,6 +690,15 @@ struct MOZ_STACK_CLASS BytecodeEmitter // object, with no overall effect on the stack. MOZ_MUST_USE bool emitRequireObjectCoercible(); + enum class CopyOption { + Filtered, Unfiltered + }; + + // Calls either the |CopyDataProperties| or the + // |CopyDataPropertiesUnfiltered| intrinsic function, consumes three (or + // two in the latter case) elements from the stack. + MOZ_MUST_USE bool emitCopyDataProperties(CopyOption option); + // emitIterator expects the iterable to already be on the stack. // It will replace that stack value with the corresponding iterator MOZ_MUST_USE bool emitIterator(); diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h index 8e35e1aae..fd1c9f5e6 100644 --- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -71,6 +71,8 @@ macro(constructor, constructor, "constructor") \ macro(continue, continue_, "continue") \ macro(ConvertAndCopyTo, ConvertAndCopyTo, "ConvertAndCopyTo") \ + macro(CopyDataProperties, CopyDataProperties, "CopyDataProperties") \ + macro(CopyDataPropertiesUnfiltered, CopyDataPropertiesUnfiltered, "CopyDataPropertiesUnfiltered") \ macro(copyWithin, copyWithin, "copyWithin") \ macro(count, count, "count") \ macro(CreateResolvingFunctions, CreateResolvingFunctions, "CreateResolvingFunctions") \ -- cgit v1.2.3 From 262b1194ffeba70fcb81abad4adfa40f1bf646be Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 14 Jul 2019 20:54:31 -0400 Subject: 1339395 - Part 5: Add Reflect.parse tests for object rest and spread properties. --- js/src/tests/js1_8_5/reflect-parse/object-rest.js | 45 ++++++++++++++++++++++ .../tests/js1_8_5/reflect-parse/object-spread.js | 29 ++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 js/src/tests/js1_8_5/reflect-parse/object-rest.js create mode 100644 js/src/tests/js1_8_5/reflect-parse/object-spread.js (limited to 'js/src') diff --git a/js/src/tests/js1_8_5/reflect-parse/object-rest.js b/js/src/tests/js1_8_5/reflect-parse/object-rest.js new file mode 100644 index 000000000..5af06909b --- /dev/null +++ b/js/src/tests/js1_8_5/reflect-parse/object-rest.js @@ -0,0 +1,45 @@ +// |reftest| skip-if(!xulRuntime.shell) + +function property(key, value = key, shorthand = key === value) { + return { key, value, shorthand }; +} + +function assertDestrAssign(src, pattern) { + assertExpr(`(${src} = 0)`, aExpr("=", pattern, lit(0))); +} + +function assertDestrBinding(src, pattern) { + assertDecl(`var ${src} = 0`, varDecl([{id: pattern, init: lit(0)}])); +} + +function test() { + // Target expression must be a simple assignment target or a nested pattern + // in object assignment patterns. + assertDestrAssign("{...x}", objPatt([spread(ident("x"))])); + assertDestrAssign("{...(x)}", objPatt([spread(ident("x"))])); + assertDestrAssign("{...obj.p}", objPatt([spread(dotExpr(ident("obj"), ident("p")))])); + assertDestrAssign("{...{}}", objPatt([spread(objPatt([]))])); + assertDestrAssign("{...[]}", objPatt([spread(arrPatt([]))])); + + // Object binding patterns only allow binding identifiers or nested patterns. + assertDestrBinding("{...x}", objPatt([spread(ident("x"))])); + assertDestrBinding("{...{}}", objPatt([spread(objPatt([]))])); + assertDestrBinding("{...[]}", objPatt([spread(arrPatt([]))])); + + // The rest-property can be preceded by other properties. + for (var assertDestr of [assertDestrAssign, assertDestrBinding]) { + assertDestr("{a, ...x}", objPatt([property(ident("a")), spread(ident("x"))])); + assertDestr("{a: b, ...x}", objPatt([property(ident("a"), ident("b")), spread(ident("x"))])); + assertDestr("{[a]: b, ...x}", objPatt([property(comp(ident("a")), ident("b")), spread(ident("x"))])); + } + + // Tests when __proto__ is used in the object pattern. + for (var assertDestr of [assertDestrAssign, assertDestrBinding]) { + assertDestr("{...__proto__}", objPatt([spread(ident("__proto__"))])); + assertDestr("{__proto__, ...x}", objPatt([property(ident("__proto__")), spread(ident("x"))])); + } + assertDestrAssign("{__proto__: a, ...x}", objPatt([property(lit("__proto__"), ident("a")), spread(ident("x"))])); + assertDestrBinding("{__proto__: a, ...x}", objPatt([property(ident("__proto__"), ident("a")), spread(ident("x"))])); +} + +runtest(test); diff --git a/js/src/tests/js1_8_5/reflect-parse/object-spread.js b/js/src/tests/js1_8_5/reflect-parse/object-spread.js new file mode 100644 index 000000000..a4b269c40 --- /dev/null +++ b/js/src/tests/js1_8_5/reflect-parse/object-spread.js @@ -0,0 +1,29 @@ +// |reftest| skip-if(!xulRuntime.shell) + +function property(key, value = key, shorthand = key === value) { + return { key, value, shorthand }; +} + +function test() { + // Any expression can be spreaded. + assertExpr("({...x})", objExpr([spread(ident("x"))])); + assertExpr("({...f()})", objExpr([spread(callExpr(ident("f"), []))])); + assertExpr("({...123})", objExpr([spread(lit(123))])); + + // Multiple spread expression are allowed. + assertExpr("({...x, ...obj.p})", objExpr([spread(ident("x")), spread(dotExpr(ident("obj"), ident("p")))])); + + // Spread expression can appear anywhere in an object literal. + assertExpr("({p, ...x})", objExpr([property(ident("p")), spread(ident("x"))])); + assertExpr("({p: a, ...x})", objExpr([property(ident("p"), ident("a")), spread(ident("x"))])); + assertExpr("({...x, p: a})", objExpr([spread(ident("x")), property(ident("p"), ident("a"))])); + + // Trailing comma after spread expression is allowed. + assertExpr("({...x,})", objExpr([spread(ident("x"))])); + + // __proto__ is not special in spread expressions. + assertExpr("({...__proto__})", objExpr([spread(ident("__proto__"))])); + assertExpr("({...__proto__, ...__proto__})", objExpr([spread(ident("__proto__")), spread(ident("__proto__"))])); +} + +runtest(test); -- cgit v1.2.3 From 8b4ee77d34ce04e3c8bb2ba017b009d5f25d1eb9 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 14 Jul 2019 20:55:37 -0400 Subject: 1339395 - Part 6: Update jit-tests now that object rest/spread properties are a thing. --- js/src/jit-test/tests/parser/arrow-rest.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'js/src') diff --git a/js/src/jit-test/tests/parser/arrow-rest.js b/js/src/jit-test/tests/parser/arrow-rest.js index 53750f25b..b1429066e 100644 --- a/js/src/jit-test/tests/parser/arrow-rest.js +++ b/js/src/jit-test/tests/parser/arrow-rest.js @@ -39,7 +39,7 @@ testThrow(` testThrow(` ({...a)=> -`, 2); +`, 6); testThrow(` function f([... ...a)=> @@ -47,7 +47,7 @@ function f([... ...a)=> testThrow(` function f({...a)=> -`, 12); +`, 16); // arrow @@ -67,7 +67,7 @@ var [... ...a)=> testThrow(` var {...a)=> -`, 5); +`, 9); // initializer -- cgit v1.2.3 From 221239a77c6d7de58424448de7b83af04c638378 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 14 Jul 2019 20:59:26 -0400 Subject: 1339395 - Part 7: Remove no longer needed check for jsid strings which are indices from frontend. --- js/src/frontend/BytecodeEmitter.cpp | 39 ++++--------------------------------- js/src/frontend/FoldConstants.cpp | 7 ------- 2 files changed, 4 insertions(+), 42 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index b3b658a2d..309d6c290 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -5896,20 +5896,9 @@ BytecodeEmitter::emitDestructuringOpsObject(ParseNode* pattern, DestructuringFla if (!emitNumberOp(key->pn_dval)) // ... *SET RHS *LREF RHS KEY return false; } else if (key->isKind(PNK_OBJECT_PROPERTY_NAME) || key->isKind(PNK_STRING)) { - PropertyName* name = key->pn_atom->asPropertyName(); - - // The parser already checked for atoms representing indexes and - // used PNK_NUMBER instead, but also watch for ids which TI treats - // as indexes for simplification of downstream analysis. - jsid id = NameToId(name); - if (id != IdToTypeId(id)) { - if (!emitTree(key)) // ... *SET RHS *LREF RHS KEY - return false; - } else { - if (!emitAtomOp(name, JSOP_GETPROP)) // ... *SET RHS *LREF PROP - return false; - needsGetElem = false; - } + if (!emitAtomOp(key->pn_atom, JSOP_GETPROP)) // ... *SET RHS *LREF PROP + return false; + needsGetElem = false; } else { if (!emitComputedPropertyName(key)) // ... *SET RHS *LREF RHS KEY return false; @@ -5986,17 +5975,7 @@ BytecodeEmitter::emitDestructuringObjRestExclusionSet(ParseNode* pattern) return false; isIndex = true; } else if (key->isKind(PNK_OBJECT_PROPERTY_NAME) || key->isKind(PNK_STRING)) { - // The parser already checked for atoms representing indexes and - // used PNK_NUMBER instead, but also watch for ids which TI treats - // as indexes for simplification of downstream analysis. - jsid id = NameToId(key->pn_atom->asPropertyName()); - if (id != IdToTypeId(id)) { - if (!emitTree(key)) - return false; - isIndex = true; - } else { - pnatom.set(key->pn_atom); - } + pnatom.set(key->pn_atom); } else { // Otherwise this is a computed property name which needs to // be added dynamically. @@ -9689,16 +9668,6 @@ BytecodeEmitter::emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp, { continue; } - - // The parser already checked for atoms representing indexes and - // used PNK_NUMBER instead, but also watch for ids which TI treats - // as indexes for simplification of downstream analysis. - jsid id = NameToId(key->pn_atom->asPropertyName()); - if (id != IdToTypeId(id)) { - if (!emitTree(key)) - return false; - isIndex = true; - } } else { if (!emitComputedPropertyName(key)) return false; diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.cpp index 441a72a45..689fa02b4 100644 --- a/js/src/frontend/FoldConstants.cpp +++ b/js/src/frontend/FoldConstants.cpp @@ -1345,15 +1345,8 @@ FoldElement(ExclusiveContext* cx, ParseNode** nodePtr, Parser& if (!name) return true; - // Also don't optimize if the name doesn't map directly to its id for TI's - // purposes. - if (NameToId(name) != IdToTypeId(NameToId(name))) - return true; - // Optimization 3: We have expr["foo"] where foo is not an index. Convert // to a property access (like expr.foo) that optimizes better downstream. - // Don't bother with this for names that TI considers to be indexes, to - // simplify downstream analysis. ParseNode* dottedAccess = parser.handler.newPropertyAccess(expr, name, node->pn_pos.end); if (!dottedAccess) return false; -- cgit v1.2.3 From 076ad08ac6f001626e63bc382d3b3d709f692a68 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 14 Jul 2019 21:00:54 -0400 Subject: 1339395 - Part 8: Add separate variables for wasm debugger test. --- js/src/jit-test/tests/debug/wasm-12.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 js/src/jit-test/tests/debug/wasm-12.js (limited to 'js/src') diff --git a/js/src/jit-test/tests/debug/wasm-12.js b/js/src/jit-test/tests/debug/wasm-12.js new file mode 100644 index 000000000..18d3b574d --- /dev/null +++ b/js/src/jit-test/tests/debug/wasm-12.js @@ -0,0 +1,26 @@ +// Tests that wasm module scripts have special URLs. + +if (!wasmIsSupported()) + quit(); + +var g = newGlobal(); +g.eval(` +function initWasm(s) { return new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(s))); } +o = initWasm('(module (func) (export "" 0))'); +o2 = initWasm('(module (func) (func) (export "" 1))'); +`); + +function isWasm(script) { return script.format === "wasm"; } + +function isValidWasmURL(url) { + // The URLs will have the following format: + // wasm: [ ":"] <64-bit-hash> + return /^wasm:(?:[^:]*:)*?[0-9a-f]{16}$/.test(url); +} + +var dbg = new Debugger(g); +var foundScripts = dbg.findScripts().filter(isWasm); +assertEq(foundScripts.length, 2); +assertEq(isValidWasmURL(foundScripts[0].source.url), true); +assertEq(isValidWasmURL(foundScripts[1].source.url), true); +assertEq(foundScripts[0].source.url != foundScripts[1].source.url, true); -- cgit v1.2.3 From 28c5b8c0589d7548382d205de8df03b42b32ccc7 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 14 Jul 2019 21:41:35 -0400 Subject: 1344334 - Make DoTypeUpdateFallback infallible. --- js/src/jit-test/tests/baseline/bug1344334.js | 14 ++++++++++++++ js/src/jit/BaselineIC.cpp | 9 ++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 js/src/jit-test/tests/baseline/bug1344334.js (limited to 'js/src') diff --git a/js/src/jit-test/tests/baseline/bug1344334.js b/js/src/jit-test/tests/baseline/bug1344334.js new file mode 100644 index 000000000..66994338a --- /dev/null +++ b/js/src/jit-test/tests/baseline/bug1344334.js @@ -0,0 +1,14 @@ +if (!('oomTest' in this)) + quit(); + +function f(s) { + s + "x"; + s.indexOf("y") === 0; + oomTest(new Function(s)); +} +var s = ` + class TestClass { constructor() {} } + for (var fun of hasPrototype) {} +`; +if (s.length) + f(s); diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 8a7c68e59..a001357f8 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -323,7 +323,14 @@ DoTypeUpdateFallback(JSContext* cx, BaselineFrame* frame, ICUpdatedStub* stub, H MOZ_CRASH("Invalid stub"); } - return stub->addUpdateStubForValue(cx, script /* = outerScript */, obj, id, value); + if (!stub->addUpdateStubForValue(cx, script /* = outerScript */, obj, id, value)) { + // The calling JIT code assumes this function is infallible (for + // instance we may reallocate dynamic slots before calling this), + // so ignore OOMs if we failed to attach a stub. + cx->recoverFromOutOfMemory(); + } + + return true; } typedef bool (*DoTypeUpdateFallbackFn)(JSContext*, BaselineFrame*, ICUpdatedStub*, HandleValue, -- cgit v1.2.3 From 4a84afdc892dcc3a1732b45e5ac65812daa53fae Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 14 Jul 2019 22:12:08 -0400 Subject: 1353691 - Report SyntaxError when arrow function has await-identifier in async function context. --- js/src/frontend/Parser.cpp | 59 ++++++++------ .../AsyncFunctions/await-in-arrow-parameters.js | 94 ++++++++++++++++++++++ 2 files changed, 128 insertions(+), 25 deletions(-) create mode 100644 js/src/tests/ecma_2017/AsyncFunctions/await-in-arrow-parameters.js (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 47e0f943d..0c279591f 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -3623,9 +3623,14 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, FunctionBox* funbox = pc->functionBox(); RootedFunction fun(context, funbox->function()); - AutoAwaitIsKeyword awaitIsKeyword(this, funbox->isAsync()); - if (!functionArguments(yieldHandling, kind, pn)) - return false; + // See below for an explanation why arrow function parameters and arrow + // function bodies are parsed with different yield/await settings. + { + bool asyncOrArrowInAsync = funbox->isAsync() || (kind == Arrow && awaitIsKeyword()); + AutoAwaitIsKeyword awaitIsKeyword(this, asyncOrArrowInAsync); + if (!functionArguments(yieldHandling, kind, pn)) + return false; + } Maybe varScope; if (funbox->hasParameterExprs) { @@ -3689,32 +3694,36 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, // |yield| in the parameters is either a name or keyword, depending on // whether the arrow function is enclosed in a generator function or not. // Whereas the |yield| in the function body is always parsed as a name. + // The same goes when parsing |await| in arrow functions. YieldHandling bodyYieldHandling = GetYieldHandling(pc->generatorKind(), pc->asyncKind()); - Node body = functionBody(inHandling, bodyYieldHandling, kind, bodyType); - if (!body) - return false; + Node body; + { + AutoAwaitIsKeyword awaitIsKeyword(this, funbox->isAsync()); + body = functionBody(inHandling, bodyYieldHandling, kind, bodyType); + if (!body) + return false; + } - if ((kind != Method && !IsConstructorKind(kind)) && fun->explicitName()) { + if ((kind == Statement || kind == Expression) && fun->explicitName()) { RootedPropertyName propertyName(context, fun->explicitName()->asPropertyName()); - // `await` cannot be checked at this point because of different context. - // It should already be checked before this point. - if (propertyName != context->names().await) { - YieldHandling nameYieldHandling; - if (kind == Expression) { - // Named lambda has binding inside it. - nameYieldHandling = bodyYieldHandling; - } else { - // Otherwise YieldHandling cannot be checked at this point - // because of different context. - // It should already be checked before this point. - nameYieldHandling = YieldIsName; - } + YieldHandling nameYieldHandling; + if (kind == Expression) { + // Named lambda has binding inside it. + nameYieldHandling = bodyYieldHandling; + } else { + // Otherwise YieldHandling cannot be checked at this point + // because of different context. + // It should already be checked before this point. + nameYieldHandling = YieldIsName; + } - if (!checkBindingIdentifier(propertyName, handler.getPosition(pn).begin, - nameYieldHandling)) - { - return false; - } + // We already use the correct await-handling at this point, therefore + // we don't need call AutoAwaitIsKeyword here. + + if (!checkBindingIdentifier(propertyName, handler.getPosition(pn).begin, + nameYieldHandling)) + { + return false; } } diff --git a/js/src/tests/ecma_2017/AsyncFunctions/await-in-arrow-parameters.js b/js/src/tests/ecma_2017/AsyncFunctions/await-in-arrow-parameters.js new file mode 100644 index 000000000..ebb4ea9da --- /dev/null +++ b/js/src/tests/ecma_2017/AsyncFunctions/await-in-arrow-parameters.js @@ -0,0 +1,94 @@ +var ieval = eval; +var AsyncFunction = async function(){}.constructor; + +var functionContext = { + Function: { + constructor: Function, + toSourceBody: code => `function f() { ${code} }`, + toSourceParameter: code => `function f(x = ${code}) { }`, + }, + AsyncFunction: { + constructor: AsyncFunction, + toSourceBody: code => `async function f() { ${code} }`, + toSourceParameter: code => `async function f(x = ${code}) { }`, + }, +}; + +function assertSyntaxError(kind, code) { + var {constructor, toSourceBody, toSourceParameter} = functionContext[kind]; + var body = toSourceBody(code); + var parameter = toSourceParameter(code); + + assertThrowsInstanceOf(() => { constructor(code); }, SyntaxError, constructor.name + ":" + code); + assertThrowsInstanceOf(() => { constructor(`x = ${code}`, ""); }, SyntaxError, constructor.name + ":" + code); + + assertThrowsInstanceOf(() => { eval(body); }, SyntaxError, "eval:" + body); + assertThrowsInstanceOf(() => { ieval(body); }, SyntaxError, "indirect eval:" + body); + + assertThrowsInstanceOf(() => { eval(parameter); }, SyntaxError, "eval:" + parameter); + assertThrowsInstanceOf(() => { ieval(parameter); }, SyntaxError, "indirect eval:" + parameter); +} + +function assertNoSyntaxError(kind, code) { + var {constructor, toSourceBody, toSourceParameter} = functionContext[kind]; + var body = toSourceBody(code); + var parameter = toSourceParameter(code); + + constructor(code); + constructor(`x = ${code}`, ""); + + eval(body); + ieval(body); + + eval(parameter); + ieval(parameter); +} + +function assertSyntaxErrorAsync(code) { + assertNoSyntaxError("Function", code); + assertSyntaxError("AsyncFunction", code); +} + +function assertSyntaxErrorBoth(code) { + assertSyntaxError("Function", code); + assertSyntaxError("AsyncFunction", code); +} + + +// Bug 1353691 +// |await| expression is invalid in arrow functions in async-context. +// |await/r/g| first parses as |AwaitExpression RegularExpressionLiteral|, when reparsing the +// arrow function, it is parsed as |IdentRef DIV IdentRef DIV IdentRef|. We need to ensure in this +// case, that we still treat |await| as a keyword and hence throw a SyntaxError. +assertSyntaxErrorAsync("(a = await/r/g) => {}"); +assertSyntaxErrorBoth("async(a = await/r/g) => {}"); + +// Also applies when nesting arrow functions. +assertSyntaxErrorAsync("(a = (b = await/r/g) => {}) => {}"); +assertSyntaxErrorBoth("async(a = (b = await/r/g) => {}) => {}"); +assertSyntaxErrorBoth("(a = async(b = await/r/g) => {}) => {}"); +assertSyntaxErrorBoth("async(a = async(b = await/r/g) => {}) => {}"); + + +// Bug 1355860 +// |await| cannot be used as rest-binding parameter in arrow functions in async-context. +assertSyntaxErrorAsync("(...await) => {}"); +assertSyntaxErrorBoth("async(...await) => {}"); + +assertSyntaxErrorAsync("(a, ...await) => {}"); +assertSyntaxErrorBoth("async(a, ...await) => {}"); + +// Also test nested arrow functions. +assertSyntaxErrorAsync("(a = (...await) => {}) => {}"); +assertSyntaxErrorBoth("(a = async(...await) => {}) => {}"); +assertSyntaxErrorBoth("async(a = (...await) => {}) => {}"); +assertSyntaxErrorBoth("async(a = async(...await) => {}) => {}"); + +assertSyntaxErrorAsync("(a = (b, ...await) => {}) => {}"); +assertSyntaxErrorBoth("(a = async(b, ...await) => {}) => {}"); +assertSyntaxErrorBoth("async(a = (b, ...await) => {}) => {}"); +assertSyntaxErrorBoth("async(a = async(b, ...await) => {}) => {}"); + + +if (typeof reportCompare === "function") + reportCompare(true, true); -- cgit v1.2.3 From d2cfd332ac04f630ab1eb93b71f78a0474f43b88 Mon Sep 17 00:00:00 2001 From: Moonchild Date: Fri, 19 Jul 2019 15:48:48 +0200 Subject: Fix order of OwnProperty check for rest parameters. This was a small mistake when converting from the `hasOwn()` function format (swapped parameters). Fixing this properly makes rest parameters exclude the parameters that are defined (which is the whole point of `...rest` --- js/src/builtin/Utilities.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'js/src') diff --git a/js/src/builtin/Utilities.js b/js/src/builtin/Utilities.js index ec5c88336..d5f233d05 100644 --- a/js/src/builtin/Utilities.js +++ b/js/src/builtin/Utilities.js @@ -254,7 +254,7 @@ function CopyDataProperties(target, source, excluded) { // We abbreviate this by calling propertyIsEnumerable which is faster // and returns false for not defined properties. - if (!callFunction(std_Object_hasOwnProperty, key, excluded) && callFunction(std_Object_propertyIsEnumerable, source, key)) + if (!callFunction(std_Object_hasOwnProperty, excluded, key) && callFunction(std_Object_propertyIsEnumerable, source, key)) _DefineDataProperty(target, key, source[key]); } -- cgit v1.2.3 From 7e6342a01158d689cb8cbfcb7ffb34f4aa2817c9 Mon Sep 17 00:00:00 2001 From: Lars T Hansen Date: Sat, 20 Jul 2019 15:43:01 +0200 Subject: Define JumpImmediateRange on ARM64. There are comments in the code suggesting that we've made plans at some point to handle very far jumps via patching + indirect jumps, but all of those comments are TODO/FIXME. Absent such a strategy, the furthest jump is 2^27-1 bytes, and we need to define JumpImmediateRange to reflect that. --- js/src/jit/arm64/Architecture-arm64.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/arm64/Architecture-arm64.h b/js/src/jit/arm64/Architecture-arm64.h index e74340f13..bee212db7 100644 --- a/js/src/jit/arm64/Architecture-arm64.h +++ b/js/src/jit/arm64/Architecture-arm64.h @@ -299,10 +299,12 @@ static const uint32_t ION_FRAME_SLACK_SIZE = 24; static const uint32_t ShadowStackSpace = 0; -// TODO: -// This constant needs to be updated to account for whatever near/far branching -// strategy is used by ARM64. -static const uint32_t JumpImmediateRange = UINT32_MAX; +// When our only strategy for far jumps is to encode the offset directly, and +// not insert any jump islands during assembly for even further jumps, then the +// architecture restricts us to -2^27 .. 2^27-4, to fit into a signed 28-bit +// value. We further reduce this range to allow the far-jump inserting code to +// have some breathing room. +static const uint32_t JumpImmediateRange = ((1 << 27) - (20 * 1024 * 1024)); static const uint32_t ABIStackAlignment = 16; static const uint32_t CodeAlignment = 16; -- cgit v1.2.3 From 04ac84ff56b9780335560319a8ecd3e8b510874e Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 21 Jul 2019 22:31:02 -0400 Subject: Issue #1195 - Fix errant use of JSContext in ErrorNotes We want to ensure that ErrorNotes stays on the main thread to prevent a race condition that was introduced in 1283712 - Part 1. This fixes #1195. --- js/src/jsapi.cpp | 8 ++++---- js/src/jscntxt.cpp | 2 +- js/src/jscntxt.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'js/src') diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 7cc7bd035..84a315587 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -6326,7 +6326,7 @@ JSErrorNotes::~JSErrorNotes() } static UniquePtr -CreateErrorNoteVA(JSContext* cx, +CreateErrorNoteVA(ExclusiveContext* cx, const char* filename, unsigned lineno, unsigned column, JSErrorCallback errorCallback, void* userRef, const unsigned errorNumber, @@ -6357,7 +6357,7 @@ JSErrorNotes::addNoteASCII(ExclusiveContext* cx, { va_list ap; va_start(ap, errorNumber); - auto note = CreateErrorNoteVA(cx->asJSContext(), filename, lineno, column, errorCallback, userRef, + auto note = CreateErrorNoteVA(cx, filename, lineno, column, errorCallback, userRef, errorNumber, ArgumentsAreASCII, ap); va_end(ap); @@ -6376,7 +6376,7 @@ JSErrorNotes::addNoteLatin1(ExclusiveContext* cx, { va_list ap; va_start(ap, errorNumber); - auto note = CreateErrorNoteVA(cx->asJSContext(), filename, lineno, column, errorCallback, userRef, + auto note = CreateErrorNoteVA(cx, filename, lineno, column, errorCallback, userRef, errorNumber, ArgumentsAreLatin1, ap); va_end(ap); @@ -6395,7 +6395,7 @@ JSErrorNotes::addNoteUTF8(ExclusiveContext* cx, { va_list ap; va_start(ap, errorNumber); - auto note = CreateErrorNoteVA(cx->asJSContext(), filename, lineno, column, errorCallback, userRef, + auto note = CreateErrorNoteVA(cx, filename, lineno, column, errorCallback, userRef, errorNumber, ArgumentsAreUTF8, ap); va_end(ap); diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 441b006d6..e505a4b34 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -748,7 +748,7 @@ js::ExpandErrorArgumentsVA(ExclusiveContext* cx, JSErrorCallback callback, } bool -js::ExpandErrorArgumentsVA(JSContext* cx, JSErrorCallback callback, +js::ExpandErrorArgumentsVA(ExclusiveContext* cx, JSErrorCallback callback, void* userRef, const unsigned errorNumber, const char16_t** messageArgs, ErrorArgumentsType argumentsType, diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index c949d18fd..8be3376cf 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -622,7 +622,7 @@ ExpandErrorArgumentsVA(ExclusiveContext* cx, JSErrorCallback callback, JSErrorReport* reportp, va_list ap); extern bool -ExpandErrorArgumentsVA(JSContext* cx, JSErrorCallback callback, +ExpandErrorArgumentsVA(ExclusiveContext* cx, JSErrorCallback callback, void* userRef, const unsigned errorNumber, const char16_t** messageArgs, ErrorArgumentsType argumentsType, -- cgit v1.2.3 From 8cd6a5a3361c155114c5dc9fedbee18e3e2720a7 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Mon, 22 Jul 2019 10:22:35 +0200 Subject: Remove unused checking function for unboxed types. Tag #1030 --- js/src/jit/MIR.cpp | 34 ---------------------------------- 1 file changed, 34 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 10671cfda..0cf31adb3 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -2630,40 +2630,6 @@ jit::EqualTypes(MIRType type1, TemporaryTypeSet* typeset1, return typeset1->equals(typeset2); } -// Tests whether input/inputTypes can always be stored to an unboxed -// object/array property with the given unboxed type. -bool -jit::CanStoreUnboxedType(TempAllocator& alloc, - JSValueType unboxedType, MIRType input, TypeSet* inputTypes) -{ - TemporaryTypeSet types; - - switch (unboxedType) { - case JSVAL_TYPE_BOOLEAN: - case JSVAL_TYPE_INT32: - case JSVAL_TYPE_DOUBLE: - case JSVAL_TYPE_STRING: - types.addType(TypeSet::PrimitiveType(unboxedType), alloc.lifoAlloc()); - break; - - case JSVAL_TYPE_OBJECT: - types.addType(TypeSet::AnyObjectType(), alloc.lifoAlloc()); - types.addType(TypeSet::NullType(), alloc.lifoAlloc()); - break; - - default: - MOZ_CRASH("Bad unboxed type"); - } - - return TypeSetIncludes(&types, input, inputTypes); -} - -static bool -CanStoreUnboxedType(TempAllocator& alloc, JSValueType unboxedType, MDefinition* value) -{ - return CanStoreUnboxedType(alloc, unboxedType, value->type(), value->resultTypeSet()); -} - bool MPhi::specializeType(TempAllocator& alloc) { -- cgit v1.2.3 From 4d4924e5105dbdfdcc3ff821671fba0dfeb11b11 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Wed, 4 Sep 2019 21:04:07 +0200 Subject: Fix a crash in IndexedDB. --- js/src/jsapi.cpp | 22 ++++++++++++++++++++++ js/src/jsapi.h | 3 +++ 2 files changed, 25 insertions(+) (limited to 'js/src') diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 84a315587..cad0840e0 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -2010,6 +2010,28 @@ JS_GetOwnUCPropertyDescriptor(JSContext* cx, HandleObject obj, const char16_t* n return JS_GetOwnPropertyDescriptorById(cx, obj, id, desc); } +JS_PUBLIC_API(bool) +JS_GetOwnElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleValue vp) +{ + RootedId id(cx); + if (!IndexToId(cx, index, &id)) { + return false; + } + + Rooted desc(cx); + if (!JS_GetOwnPropertyDescriptorById(cx, obj, id, &desc)) { + return false; + } + + if (desc.object() && desc.isDataDescriptor()) { + vp.set(desc.value()); + } else { + vp.setUndefined(); + } + + return true; +} + JS_PUBLIC_API(bool) JS_GetPropertyDescriptorById(JSContext* cx, HandleObject obj, HandleId id, MutableHandle desc) diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 67b3d4267..dc00c650d 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -2922,6 +2922,9 @@ extern JS_PUBLIC_API(bool) JS_GetOwnUCPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, JS::MutableHandle desc); +extern JS_PUBLIC_API(bool) +JS_GetOwnElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleValue vp); + /** * Like JS_GetOwnPropertyDescriptorById, but also searches the prototype chain * if no own property is found directly on obj. The object on which the -- cgit v1.2.3 From 2b223cce089bb8cbfb1a463fdd42e09eee63c7b2 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 5 Sep 2019 13:03:09 +0200 Subject: Use the correct group for JIT constraints. This fixes a rare crash/CTD in JS. This adds information about the constraints to a new RAII class so we can finish all constraints at the end. Based on changes in BZ 1568397 --- js/src/jit/IonAnalysis.cpp | 32 ++++++++++++----- js/src/jit/IonAnalysis.h | 7 ++-- js/src/vm/TypeInference.cpp | 84 +++++++++++++++++++++++++++++++++++++++++---- js/src/vm/TypeInference.h | 59 ++++++++++++++++++++++++++++++- 4 files changed, 164 insertions(+), 18 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index 5fc624fb1..ace6cd81e 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -4005,7 +4005,7 @@ jit::ConvertLinearInequality(TempAllocator& alloc, MBasicBlock* block, const Lin } static bool -AnalyzePoppedThis(JSContext* cx, ObjectGroup* group, +AnalyzePoppedThis(JSContext* cx, DPAConstraintInfo& constraintInfo, ObjectGroup* group, MDefinition* thisValue, MInstruction* ins, bool definitelyExecuted, HandlePlainObject baseobj, Vector* initializerList, @@ -4046,7 +4046,12 @@ AnalyzePoppedThis(JSContext* cx, ObjectGroup* group, return true; RootedId id(cx, NameToId(setprop->name())); - if (!AddClearDefiniteGetterSetterForPrototypeChain(cx, group, id)) { + bool added = false; + if (!AddClearDefiniteGetterSetterForPrototypeChain(cx, constraintInfo, + group, id, &added)) { + return false; + } + if (!added) { // The prototype chain already contains a getter/setter for this // property, or type information is too imprecise. return true; @@ -4106,7 +4111,12 @@ AnalyzePoppedThis(JSContext* cx, ObjectGroup* group, if (!baseobj->lookup(cx, id) && !accessedProperties->append(get->name())) return false; - if (!AddClearDefiniteGetterSetterForPrototypeChain(cx, group, id)) { + bool added = false; + if (!AddClearDefiniteGetterSetterForPrototypeChain(cx, constraintInfo, + group, id, &added)) { + return false; + } + if (!added) { // The |this| value can escape if any property reads it does go // through a getter. return true; @@ -4132,8 +4142,11 @@ CmpInstructions(const void* a, const void* b) } bool -jit::AnalyzeNewScriptDefiniteProperties(JSContext* cx, HandleFunction fun, - ObjectGroup* group, HandlePlainObject baseobj, +jit::AnalyzeNewScriptDefiniteProperties(JSContext* cx, + DPAConstraintInfo& constraintInfo, + HandleFunction fun, + ObjectGroup* group, + HandlePlainObject baseobj, Vector* initializerList) { MOZ_ASSERT(cx->zone()->types.activeAnalysis); @@ -4293,7 +4306,7 @@ jit::AnalyzeNewScriptDefiniteProperties(JSContext* cx, HandleFunction fun, bool handled = false; size_t slotSpan = baseobj->slotSpan(); - if (!AnalyzePoppedThis(cx, group, thisValue, ins, definitelyExecuted, + if (!AnalyzePoppedThis(cx, constraintInfo, group, thisValue, ins, definitelyExecuted, baseobj, initializerList, &accessedProperties, &handled)) { return false; @@ -4312,7 +4325,6 @@ jit::AnalyzeNewScriptDefiniteProperties(JSContext* cx, HandleFunction fun, // contingent on the correct frames being inlined. Add constraints to // invalidate the definite properties if additional functions could be // called at the inline frame sites. - Vector exitBlocks(cx); for (MBasicBlockIterator block(graph.begin()); block != graph.end(); block++) { // Inlining decisions made after the last new property was added to // the object don't need to be frozen. @@ -4320,9 +4332,11 @@ jit::AnalyzeNewScriptDefiniteProperties(JSContext* cx, HandleFunction fun, break; if (MResumePoint* rp = block->callerResumePoint()) { if (block->numPredecessors() == 1 && block->getPredecessor(0) == rp->block()) { - JSScript* script = rp->block()->info().script(); - if (!AddClearDefiniteFunctionUsesInScript(cx, group, script, block->info().script())) + JSScript* caller = rp->block()->info().script(); + JSScript* callee = block->info().script(); + if (!constraintInfo.addInliningConstraint(caller, callee)) { return false; + } } } } diff --git a/js/src/jit/IonAnalysis.h b/js/src/jit/IonAnalysis.h index efd31415b..49bc0b591 100644 --- a/js/src/jit/IonAnalysis.h +++ b/js/src/jit/IonAnalysis.h @@ -196,8 +196,11 @@ MCompare* ConvertLinearInequality(TempAllocator& alloc, MBasicBlock* block, const LinearSum& sum); MOZ_MUST_USE bool -AnalyzeNewScriptDefiniteProperties(JSContext* cx, HandleFunction fun, - ObjectGroup* group, HandlePlainObject baseobj, +AnalyzeNewScriptDefiniteProperties(JSContext* cx, + DPAConstraintInfo& constraintInfo, + HandleFunction fun, + ObjectGroup* group, + HandlePlainObject baseobj, Vector* initializerList); MOZ_MUST_USE bool diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index 7c2c0194e..88327b47e 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -3084,29 +3084,39 @@ class TypeConstraintClearDefiniteGetterSetter : public TypeConstraint }; bool -js::AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx, ObjectGroup* group, HandleId id) +js::AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx, + DPAConstraintInfo& constraintInfo, + ObjectGroup* group, + HandleId id, + bool* added) { /* * Ensure that if the properties named here could have a getter, setter or * a permanent property in any transitive prototype, the definite * properties get cleared from the group. */ + + *added = false; + RootedObject proto(cx, group->proto().toObjectOrNull()); while (proto) { ObjectGroup* protoGroup = JSObject::getGroup(cx, proto); if (!protoGroup) { - cx->recoverFromOutOfMemory(); return false; } if (protoGroup->unknownProperties()) - return false; + return true; HeapTypeSet* protoTypes = protoGroup->getProperty(cx, proto, id); - if (!protoTypes || protoTypes->nonDataProperty() || protoTypes->nonWritableProperty()) + if (!protoTypes) return false; - if (!protoTypes->addConstraint(cx, cx->typeLifoAlloc().new_(group))) + if (protoTypes->nonDataProperty() || protoTypes->nonWritableProperty()) + return true; + if (!constraintInfo.addProtoConstraint(proto, id)) return false; proto = proto->staticPrototype(); } + + *added = true; return true; } @@ -3612,6 +3622,43 @@ struct DestroyTypeNewScript } // namespace +bool DPAConstraintInfo::finishConstraints(JSContext* cx, ObjectGroup* group) { + for (const ProtoConstraint& constraint : protoConstraints_) { + ObjectGroup* protoGroup = constraint.proto->group(); + + // Note: we rely on the group's type information being unchanged since + // AddClearDefiniteGetterSetterForPrototypeChain. + + bool unknownProperties = protoGroup->unknownProperties(); + MOZ_RELEASE_ASSERT(!unknownProperties); + + HeapTypeSet* protoTypes = + protoGroup->getProperty(cx, constraint.proto, constraint.id); + MOZ_RELEASE_ASSERT(protoTypes); + + MOZ_ASSERT(!protoTypes->nonDataProperty()); + MOZ_ASSERT(!protoTypes->nonWritableProperty()); + + if (!protoTypes->addConstraint( + cx, + cx->typeLifoAlloc().new_( + group))) { + ReportOutOfMemory(cx); + return false; + } + } + + for (const InliningConstraint& constraint : inliningConstraints_) { + if (!AddClearDefiniteFunctionUsesInScript(cx, group, constraint.caller, + constraint.callee)) { + ReportOutOfMemory(cx); + return false; + } + } + + return true; +} + bool TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate, bool force) { @@ -3715,10 +3762,17 @@ TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate, return false; Vector initializerVector(cx); + + DPAConstraintInfo constraintInfo(cx); RootedPlainObject templateRoot(cx, templateObject()); RootedFunction fun(cx, function()); - if (!jit::AnalyzeNewScriptDefiniteProperties(cx, fun, group, templateRoot, &initializerVector)) + if (!jit::AnalyzeNewScriptDefiniteProperties(cx, + constraintInfo, + fun, + group, + templateRoot, + &initializerVector)) return false; if (!group->newScript()) @@ -3772,6 +3826,14 @@ TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate, // The definite properties analysis found exactly the properties that // are held in common by the preliminary objects. No further analysis // is needed. + + if (!constraintInfo.finishConstraints(cx, group)) { + return false; + } + if (!group->newScript()) { + return true; + } + group->addDefiniteProperties(cx, templateObject()->lastProperty()); destroyNewScript.group = nullptr; @@ -3792,6 +3854,16 @@ TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate, initialFlags); if (!initialGroup) return false; + + // Add the constraints. Use the initialGroup as group referenced by the + // constraints because that's the group that will have the TypeNewScript + // associated with it. See the detachNewScript and setNewScript calls below. + if (!constraintInfo.finishConstraints(cx, initialGroup)) { + return false; + } + if (!group->newScript()) { + return true; + } initialGroup->addDefiniteProperties(cx, templateObject()->lastProperty()); group->addDefiniteProperties(cx, prefixShape); diff --git a/js/src/vm/TypeInference.h b/js/src/vm/TypeInference.h index 94ce7e871..fd021fc96 100644 --- a/js/src/vm/TypeInference.h +++ b/js/src/vm/TypeInference.h @@ -789,8 +789,65 @@ class TemporaryTypeSet : public TypeSet TypedArraySharedness* sharedness); }; +// Stack class to record information about constraints that need to be added +// after finishing the Definite Properties Analysis. When the analysis succeeds, +// the |finishConstraints| method must be called to add the constraints to the +// TypeSets. +// +// There are two constraint types managed here: +// +// 1. Proto constraints for HeapTypeSets, to guard against things like getters +// and setters on the proto chain. +// +// 2. Inlining constraints for StackTypeSets, to invalidate when additional +// functions could be called at call sites where we inlined a function. +// +// This class uses bare GC-thing pointers because GC is suppressed when the +// analysis runs. +class MOZ_RAII DPAConstraintInfo { + struct ProtoConstraint { + JSObject* proto; + jsid id; + ProtoConstraint(JSObject* proto, jsid id) : proto(proto), id(id) {} + }; + struct InliningConstraint { + JSScript* caller; + JSScript* callee; + InliningConstraint(JSScript* caller, JSScript* callee) + : caller(caller), callee(callee) {} + }; + + JS::AutoCheckCannotGC nogc_; + Vector protoConstraints_; + Vector inliningConstraints_; + +public: + explicit DPAConstraintInfo(JSContext* cx) + : nogc_(cx) + , protoConstraints_(cx) + , inliningConstraints_(cx) + { + } + + DPAConstraintInfo(const DPAConstraintInfo&) = delete; + void operator=(const DPAConstraintInfo&) = delete; + + MOZ_MUST_USE bool addProtoConstraint(JSObject* proto, jsid id) { + return protoConstraints_.emplaceBack(proto, id); + } + MOZ_MUST_USE bool addInliningConstraint(JSScript* caller, JSScript* callee) { + return inliningConstraints_.emplaceBack(caller, callee); + } + + MOZ_MUST_USE bool finishConstraints(JSContext* cx, ObjectGroup* group); +}; + bool -AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx, ObjectGroup* group, HandleId id); +AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx, + DPAConstraintInfo& constraintInfo, + ObjectGroup* group, + HandleId id, + bool* added); bool AddClearDefiniteFunctionUsesInScript(JSContext* cx, ObjectGroup* group, -- cgit v1.2.3 From 924693bdb01ec7e8053317cd45e8d4215ddbc320 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Wed, 2 Oct 2019 14:00:30 +0200 Subject: No issue - Update TZ data to 2019c --- js/src/builtin/IntlTimeZoneData.h | 2 +- js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js | 2 +- js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js | 2 +- js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js | 2 +- js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'js/src') diff --git a/js/src/builtin/IntlTimeZoneData.h b/js/src/builtin/IntlTimeZoneData.h index 8f963ffbc..1612f0f6b 100644 --- a/js/src/builtin/IntlTimeZoneData.h +++ b/js/src/builtin/IntlTimeZoneData.h @@ -1,5 +1,5 @@ // Generated by make_intl_data.py. DO NOT EDIT. -// tzdata version = 2019a +// tzdata version = 2019c #ifndef builtin_IntlTimeZoneData_h #define builtin_IntlTimeZoneData_h diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js b/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js index 8cda44d87..8bd0512c5 100644 --- a/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js +++ b/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js @@ -1,7 +1,7 @@ // |reftest| skip-if(!this.hasOwnProperty("Intl")) // Generated by make_intl_data.py. DO NOT EDIT. -// tzdata version = 2019a +// tzdata version = 2019c const tzMapper = [ x => x, diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js index a3efe0310..c760fd85e 100644 --- a/js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js +++ b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js @@ -1,7 +1,7 @@ // |reftest| skip-if(!this.hasOwnProperty("Intl")) // Generated by make_intl_data.py. DO NOT EDIT. -// tzdata version = 2019a +// tzdata version = 2019c const tzMapper = [ x => x, diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js index b61593f78..38db5e77d 100644 --- a/js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js +++ b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js @@ -1,7 +1,7 @@ // |reftest| skip-if(!this.hasOwnProperty("Intl")) // Generated by make_intl_data.py. DO NOT EDIT. -// tzdata version = 2019a +// tzdata version = 2019c const tzMapper = [ x => x, diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js b/js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js index 12b55c214..64a25c241 100644 --- a/js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js +++ b/js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js @@ -1,7 +1,7 @@ // |reftest| skip-if(!this.hasOwnProperty("Intl")) // Generated by make_intl_data.py. DO NOT EDIT. -// tzdata version = 2019a +// tzdata version = 2019c const tzMapper = [ x => x, -- cgit v1.2.3 From a68a09618787980ff58b248c484b4017e3d2e663 Mon Sep 17 00:00:00 2001 From: Dmitry Grigoryev Date: Fri, 4 Oct 2019 22:58:16 +0200 Subject: Replace calls to undefined functions isMarkable() and toMarkablePointer() --- js/src/jit/arm/MacroAssembler-arm.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index a4161ab00..3421001f7 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -3462,8 +3462,8 @@ MacroAssemblerARMCompat::storePayload(const Value& val, const Address& dest) ScratchRegisterScope scratch(asMasm()); SecondScratchRegisterScope scratch2(asMasm()); - if (val.isMarkable()) - ma_mov(ImmGCPtr(val.toMarkablePointer()), scratch); + if (val.isGCThing()) + ma_mov(ImmGCPtr(val.toGCThing()), scratch); else ma_mov(Imm32(val.toNunboxPayload()), scratch); ma_str(scratch, ToPayload(dest), scratch2); -- cgit v1.2.3 From e31d79e8da99456247df84c2f99ba9083d46efe1 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Wed, 16 Oct 2019 12:37:07 -0400 Subject: Fix build errors with newer glibc versions --- js/src/jsnativestack.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'js/src') diff --git a/js/src/jsnativestack.cpp b/js/src/jsnativestack.cpp index 98f8fc741..94a296bd0 100644 --- a/js/src/jsnativestack.cpp +++ b/js/src/jsnativestack.cpp @@ -26,11 +26,7 @@ # include # include # include -static pid_t -gettid() -{ - return syscall(__NR_gettid); -} +# define gettid() static_cast(syscall(SYS_gettid)) # endif #else -- cgit v1.2.3 From afc187cc3f907947453b428f857acf16b2b0774e Mon Sep 17 00:00:00 2001 From: athenian200 Date: Tue, 1 Oct 2019 06:07:31 -0500 Subject: MoonchildProductions#1251 - Part 1: Restore initial Solaris support, fixed up. Compared with what Pale Moon had for Solaris originally, this is mostly the same zero point I started patching from, but I've made the following changes here after reviewing all this initial code I never looked at closely before. 1. In package-manifest.in for both Basilisk and Pale Moon, I've made the SPARC code for libfreebl not interefere with the x86 code, use the proper build flags, and also updated it to allow a SPARC64 build which is more likely to be used than the 32-bit SPARC code we had there. 2. See Mozilla bug #832272 and the old rules.mk patch from around Firefox 30 in oracle/solaris-userland. I believe they screwed up NSINSTALL on Solaris when they were trying to streamline the NSS buildsystem, because they started having unexplained issues with it around that time after Firefox 22 that they never properly resolved until Mozilla began building NSS with gyp files. I'm actually not even sure how relevant the thing they broke actually is to Solaris at this point, bug 665509 is so old it predates Firefox itself and goes back to the Mozilla suite days. I believe $(INSTALL) -t was wrong, and they meant $(NSINSTALL) -t because that makes more sense and is closer to what was there originally. It's what they have for WINNT, and it's possible a fix more like that could serve for Solaris as well. Alternatively, we could get rid of all these half-broken Makefiles and start building NSS with gyp files like Mozilla did. 3. I've completely cut out support for the Sun compiler and taken into account the reality that everyone builds Firefox (and therefore its forks) with GCC now on Solaris. This alone helped clean up a lot of the uglier parts of the code. 4. I've updated all remaining SOLARIS build flags to the newer XP_SOLARIS, because the SOLARIS flag is no longer set when building Solaris. 5. I've confirmed the workaround in gtxFontconfigFonts.cpp is no longer necessary. The Solaris people got impatient about implementing a half-baked patch for a fontconfig feature that wasn't ready yet back in 2009, and somehow convinced Mozilla to patch their software to work around it when really they should have just fixed or removed their broken fontconfig patch. The feature they wanted has since been implemented properly, and no version of Solaris still uses the broken patch that required this fix. If anyone had ever properly audited this code, it would have been removed a long time ago. --- js/src/Makefile.in | 11 +++++++++++ js/src/builtin/TestingFunctions.cpp | 5 ++++- js/src/ctypes/CTypes.cpp | 4 ++++ js/src/jsnativestack.cpp | 13 +++++++++++++ js/src/moz.build | 8 ++++++++ js/src/vm/Time.cpp | 12 ++++++++++++ 6 files changed, 52 insertions(+), 1 deletion(-) (limited to 'js/src') diff --git a/js/src/Makefile.in b/js/src/Makefile.in index 20678c68c..bc99e62b5 100644 --- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -138,6 +138,17 @@ distclean:: CFLAGS += $(MOZ_ZLIB_CFLAGS) +ifeq ($(OS_ARCH),SunOS) +ifeq ($(TARGET_CPU),sparc) + +ifdef GNU_CC +CFLAGS += -mcpu=v9 +CXXFLAGS += -mcpu=v9 +endif #GNU_CC + +endif +endif + $(LIBRARY_NAME).pc: js.pc cp $^ $@ diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 992fe2c97..6beb82932 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -239,8 +239,11 @@ GetBuildConfiguration(JSContext* cx, unsigned argc, Value* vp) value = BooleanValue(true); if (!JS_SetProperty(cx, info, "intl-api", value)) return false; - +#if defined(XP_SOLARIS) + value = BooleanValue(false); +#else value = BooleanValue(true); +#endif if (!JS_SetProperty(cx, info, "mapped-array-buffer", value)) return false; diff --git a/js/src/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp index d6adfac2c..aed1114bd 100644 --- a/js/src/ctypes/CTypes.cpp +++ b/js/src/ctypes/CTypes.cpp @@ -20,6 +20,10 @@ #include #endif +#if defined(XP_SOLARIS) +#include +#endif + #ifdef HAVE_SSIZE_T #include #endif diff --git a/js/src/jsnativestack.cpp b/js/src/jsnativestack.cpp index 94a296bd0..389d7e657 100644 --- a/js/src/jsnativestack.cpp +++ b/js/src/jsnativestack.cpp @@ -67,6 +67,19 @@ js::GetNativeStackBaseImpl() # endif } +#elif defined(XP_SOLARIS) + +#include + +JS_STATIC_ASSERT(JS_STACK_GROWTH_DIRECTION < 0); + +void js::GetNativeStackBaseImpl() +{ + stack_t st; + stack_getbounds(&st); + return static_cast(st.ss_sp) + st.ss_size; +} + #elif defined(XP_LINUX) && !defined(ANDROID) && defined(__GLIBC__) void* js::GetNativeStackBaseImpl() diff --git a/js/src/moz.build b/js/src/moz.build index a0f074d1c..47ffe0159 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -721,6 +721,14 @@ if CONFIG['OS_ARCH'] == 'Linux': 'dl', ] +if CONFIG['OS_ARCH'] == 'SunOS': + OS_LIBS += [ + 'posix4', + 'dl', + 'nsl', + 'socket', + ] + OS_LIBS += CONFIG['REALTIME_LIBS'] CFLAGS += CONFIG['MOZ_ICU_CFLAGS'] diff --git a/js/src/vm/Time.cpp b/js/src/vm/Time.cpp index 87531c148..a9a5b7f0f 100644 --- a/js/src/vm/Time.cpp +++ b/js/src/vm/Time.cpp @@ -11,6 +11,10 @@ #include "mozilla/DebugOnly.h" #include "mozilla/MathAlgorithms.h" +#ifdef XP_SOLARIS +#define _REENTRANT 1 +#endif + #include #include @@ -30,6 +34,10 @@ #ifdef XP_UNIX +#ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris */ +extern int gettimeofday(struct timeval* tv); +#endif + #include #endif /* XP_UNIX */ @@ -42,7 +50,11 @@ PRMJ_Now() { struct timeval tv; +#ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris */ + gettimeofday(&tv); +#else gettimeofday(&tv, 0); +#endif /* _SVID_GETTOD */ return int64_t(tv.tv_sec) * PRMJ_USEC_PER_SEC + int64_t(tv.tv_usec); } -- cgit v1.2.3 From 3647f42c27761472e4ee204bade964e8ffad4679 Mon Sep 17 00:00:00 2001 From: athenian200 Date: Tue, 1 Oct 2019 21:36:29 -0500 Subject: MoonchildProductions#1251 - Part 7: All the posix_m* memory-related stuff, gathered together. https://bugzilla.mozilla.org/show_bug.cgi?id=1158445 https://bugzilla.mozilla.org/show_bug.cgi?id=963983 https://bugzilla.mozilla.org/show_bug.cgi?id=1542758 Solaris madvise and malign don't perfectly map to their POSIX counterparts, and some Linux versions (especially Android) don't define the POSIX counterparts at all, so options are limited. Ideally posix_madvise and posix_malign should be the safer and more portable options for all platforms. --- js/src/gc/Memory.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'js/src') diff --git a/js/src/gc/Memory.cpp b/js/src/gc/Memory.cpp index 268e1e489..5cf0cd2f7 100644 --- a/js/src/gc/Memory.cpp +++ b/js/src/gc/Memory.cpp @@ -678,7 +678,11 @@ MarkPagesUnused(void* p, size_t size) return false; MOZ_ASSERT(OffsetFromAligned(p, pageSize) == 0); - int result = madvise(p, size, MADV_DONTNEED); +#if defined(XP_SOLARIS) + int result = posix_madvise(p, size, POSIX_MADV_DONTNEED); +#else + int result = madvise(p, size, MADV_DONTNEED); +#endif return result != -1; } -- cgit v1.2.3 From c0d814c1d52b0e9ae884b83f214218b954133acb Mon Sep 17 00:00:00 2001 From: athenian200 Date: Tue, 1 Oct 2019 22:59:38 -0500 Subject: MoonchildProductions#1251 - Part 8: Align pointer for char_16t. https://bugzilla.mozilla.org/show_bug.cgi?id=1352449 Mozilla patch that's been in the code since Firefox 55. Seems like there have been no ill effects from implementing it, and it would only increase the portability of the UXP code. All the Solaris Firefox repos I've seen implement some variation on the jsexn patch, and this seems to be the cleanest version of it. I can add ifdefs if needed or there are performance concerns associated with this patch, but I get the impression this alignment backlog issue might affect a few platforms other than Solaris, though none were named. Otherwise I think they wouldn't have used "platforms that need it" in plural form or failed to ifdef it. --- js/src/jsexn.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'js/src') diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index 65cc81a1a..3fc9200c1 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -205,7 +205,12 @@ size_t ExtraMallocSize(JSErrorReport* report) { if (report->linebuf()) - return (report->linebufLength() + 1) * sizeof(char16_t); + /* + * Mozilla bug 1352449. Count with null + * terminator and alignment. See CopyExtraData for + * the details about alignment. + */ + return (report->linebufLength() + 1) * sizeof(char16_t) + 1; return 0; } @@ -220,10 +225,20 @@ bool CopyExtraData(JSContext* cx, uint8_t** cursor, JSErrorReport* copy, JSErrorReport* report) { if (report->linebuf()) { + /* + * Make sure cursor is properly aligned for char16_t for platforms + * which need it and it's at the end of the buffer on exit. + */ + size_t alignment_backlog = 0; + if (size_t(*cursor) % 2) + (*cursor)++; + else + alignment_backlog = 1; + size_t linebufSize = (report->linebufLength() + 1) * sizeof(char16_t); const char16_t* linebufCopy = (const char16_t*)(*cursor); js_memcpy(*cursor, report->linebuf(), linebufSize); - *cursor += linebufSize; + *cursor += linebufSize + alignment_backlog; copy->initBorrowedLinebuf(linebufCopy, report->linebufLength(), report->tokenOffset()); } -- cgit v1.2.3 From cf75ede0de7cc8febc12d666783631836c6b8e43 Mon Sep 17 00:00:00 2001 From: athenian200 Date: Tue, 1 Oct 2019 23:39:11 -0500 Subject: MoonchildProductions#1251 - Part 9: Look for hypot in the math library (libm). https://bugzilla.mozilla.org/show_bug.cgi?id=1351309 https://bugzilla.mozilla.org/show_bug.cgi?id=1309157 I assess this change to be low-risk for the following reasons: 1. It has been in Firefox since version 55 without issues. 2. It's nearly identical to the fix for bug 1309157 which is already in our tree, so that one would be causing problems if this one were going to. 3. Linux, Windows, and BSD are known to have a hypot function in their math libraries. 4. Even if it does break something, it should only break a test and not critical functionality. --- js/src/jit-test/tests/ctypes/function-definition.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'js/src') diff --git a/js/src/jit-test/tests/ctypes/function-definition.js b/js/src/jit-test/tests/ctypes/function-definition.js index 4df317a09..5882ba889 100644 --- a/js/src/jit-test/tests/ctypes/function-definition.js +++ b/js/src/jit-test/tests/ctypes/function-definition.js @@ -27,7 +27,7 @@ function test() { let lib; try { - lib = ctypes.open(ctypes.libraryName("c")); + lib = ctypes.open(ctypes.libraryName("m")); } catch (e) { } if (!lib) -- cgit v1.2.3 From 76c55f747ce5878d1d37d8bf3bd0a50c1b478bec Mon Sep 17 00:00:00 2001 From: athenian200 Date: Wed, 2 Oct 2019 14:08:55 -0500 Subject: MoonchildProductions#1251 - Part 12: Add Solaris/illumos support to WasmSignalHandlers. https://www.illumos.org/issues/5876 https://bugzilla.mozilla.org/show_bug.cgi?id=135050 --- js/src/wasm/WasmSignalHandlers.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'js/src') diff --git a/js/src/wasm/WasmSignalHandlers.cpp b/js/src/wasm/WasmSignalHandlers.cpp index c4733cc96..21093ca9a 100644 --- a/js/src/wasm/WasmSignalHandlers.cpp +++ b/js/src/wasm/WasmSignalHandlers.cpp @@ -130,11 +130,16 @@ class AutoSetHandlingSegFault # define EPC_sig(p) ((p)->sc_pc) # define RFP_sig(p) ((p)->sc_regs[30]) # endif -#elif defined(__linux__) +#elif defined(__linux__) || defined(__sun) # if defined(__linux__) # define XMM_sig(p,i) ((p)->uc_mcontext.fpregs->_xmm[i]) # define EIP_sig(p) ((p)->uc_mcontext.gregs[REG_EIP]) -# else +# else // defined(__sun) +/* See https://www.illumos.org/issues/5876. They keep arguing over whether + * should provide the register index defines in regset.h or + * require applications to request them specifically, and we need them here. */ +#include +#include # define XMM_sig(p,i) ((p)->uc_mcontext.fpregs.fp_reg_set.fpchip_state.xmm[i]) # define EIP_sig(p) ((p)->uc_mcontext.gregs[REG_PC]) # endif -- cgit v1.2.3 From beea314ffe6c9cefeb232e9b38fcecf66154854f Mon Sep 17 00:00:00 2001 From: athenian200 Date: Wed, 2 Oct 2019 19:51:00 -0500 Subject: MoonchildProductions#1251 - Part 17: All the libffi and libxul.so issues, resolved. https://bugzilla.mozilla.org/show_bug.cgi?id=1185424 http://www.mindfruit.co.uk/2012/06/relocations-relocations.html The libxul.so fix was implemented by Mozilla in Firefox 57 and personally recommended to me by an Oracle employee on the OpenIndiana mailing list. It can easily be made ifdef XP_SOLARIS, but it seems like the new way is considered a better solution overall by the original author of the code that had it use that null pointer hack to begin with. I can't link where I found the fix for libffi because I came up with it myself while looking at the way sysv.S does things. Something clicked in my brain while reading that mindfruit link above, though, and gave me enough of a sense of what was going on to be able to fix libffi. The libffi fix looks a bit hairy because of all the FDE_ENCODE statements, but if you examine the code closely, you should find that it does exactly what it did before on all platforms besides Solaris. I later discovered that people who originally ported Firefox to Solaris never figured this out during the Firefox 52 era and had to use GNU LD for linking libxul.so while using the Sun LD for the rest of the build to make it work. For whatever reason, it works for me now without the GNU LD trick. --- js/src/ctypes/libffi/src/x86/win32.S | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) (limited to 'js/src') diff --git a/js/src/ctypes/libffi/src/x86/win32.S b/js/src/ctypes/libffi/src/x86/win32.S index daf0e799c..4f702e8b1 100644 --- a/js/src/ctypes/libffi/src/x86/win32.S +++ b/js/src/ctypes/libffi/src/x86/win32.S @@ -1158,8 +1158,24 @@ L_ffi_closure_SYSV_inner$stub: .byte 0x7c /* .sleb128 -4; CIE Data Alignment Factor */ .byte 0x8 /* CIE RA Column */ #ifdef __PIC__ - .byte 0x1 /* .uleb128 0x1; Augmentation size */ - .byte 0x1b /* FDE Encoding (pcrel sdata4) */ +# if defined __sun__ && defined __svr4__ +/* 32-bit Solaris 2/x86 uses datarel encoding for PIC. GNU ld before 2.22 + doesn't correctly sort .eh_frame_hdr with mixed encodings, so match this. */ +# define FDE_ENCODING 0x30 /* datarel */ +# define FDE_ENCODE(X) X@GOTOFF +# else +# define FDE_ENCODING 0x1b /* pcrel sdata4 */ +# if defined HAVE_AS_X86_PCREL +# define FDE_ENCODE(X) X-. +# else +# define FDE_ENCODE(X) X@rel +# endif +# endif +#else +# define FDE_ENCODING 0 /* absolute */ +# define FDE_ENCODE(X) X +.byte 0x1 /* .uleb128 0x1; Augmentation size */ +.byte FDE_ENCODING #endif .byte 0xc /* DW_CFA_def_cfa CFA = r4 + 4 = 4(%esp) */ .byte 0x4 /* .uleb128 0x4 */ @@ -1176,7 +1192,7 @@ L_ffi_closure_SYSV_inner$stub: #if defined __PIC__ && defined HAVE_AS_X86_PCREL .long .LFB1-. /* FDE initial location */ #else - .long .LFB1 + .long FDE_ENCODE(.LFB1) #endif .long .LFE1-.LFB1 /* FDE address range */ #ifdef __PIC__ @@ -1207,7 +1223,7 @@ L_ffi_closure_SYSV_inner$stub: #if defined __PIC__ && defined HAVE_AS_X86_PCREL .long .LFB3-. /* FDE initial location */ #else - .long .LFB3 + .long FDE_ENCODE(.LFB3) #endif .long .LFE3-.LFB3 /* FDE address range */ #ifdef __PIC__ @@ -1240,7 +1256,7 @@ L_ffi_closure_SYSV_inner$stub: #if defined __PIC__ && defined HAVE_AS_X86_PCREL .long .LFB4-. /* FDE initial location */ #else - .long .LFB4 + .long FDE_ENCODE(.LFB4) #endif .long .LFE4-.LFB4 /* FDE address range */ #ifdef __PIC__ @@ -1278,7 +1294,7 @@ L_ffi_closure_SYSV_inner$stub: #if defined __PIC__ && defined HAVE_AS_X86_PCREL .long .LFB5-. /* FDE initial location */ #else - .long .LFB5 + .long FDE_ENCODE(.LFB5) #endif .long .LFE5-.LFB5 /* FDE address range */ #ifdef __PIC__ -- cgit v1.2.3 From 575f51a27d6b3627ae5675cc8e920c8dcae073bd Mon Sep 17 00:00:00 2001 From: athenian200 Date: Fri, 4 Oct 2019 04:37:51 -0500 Subject: Fix a bunch of dumb typos and omissions. --- js/src/jsnativestack.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'js/src') diff --git a/js/src/jsnativestack.cpp b/js/src/jsnativestack.cpp index 389d7e657..4e96e01e8 100644 --- a/js/src/jsnativestack.cpp +++ b/js/src/jsnativestack.cpp @@ -73,7 +73,8 @@ js::GetNativeStackBaseImpl() JS_STATIC_ASSERT(JS_STACK_GROWTH_DIRECTION < 0); -void js::GetNativeStackBaseImpl() +void* +js::GetNativeStackBaseImpl() { stack_t st; stack_getbounds(&st); -- cgit v1.2.3 From 2f4488521db663520c703a9a836d5549d679266c Mon Sep 17 00:00:00 2001 From: athenian200 Date: Thu, 10 Oct 2019 15:38:27 -0500 Subject: MoonchildProductions#1251 - Part 23: Allow AMD64 build to work. https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Build_Instructions/Compiling_32-bit_Firefox_on_a_Linux_64-bit_OS Setting this up turned out to be easier than I thought it would be. All I had to do was apply these instructions in reverse and add the following to my .mozconfig file: CC="gcc -m64" CXX="g++ -m64" AS="gas --64" ac_add_options --target=x86_64-pc-solaris2.11 export PKG_CONFIG_PATH=/usr/lib/amd64/pkgconfig ac_add_options --libdir=/usr/lib/amd64 ac_add_options --x-libraries=/usr/lib/amd64 Most of these changes were fairly trivial, just requiring me to make a few of the changes I made earlier conditional on a 32-bit build. The biggest challenge was figuring out why the JavaScript engine triggered a segfault everytime it tried to allocate memory. But this patch fixes it: https://github.com/OpenIndiana/oi-userland/blob/oi/hipster/components/web/firefox/patches/patch-js_src_gc_Memory.cpp.patch Turns out that Solaris on AMD64 handles memory management in a fairly unusual way with a segmented memory model, but it's not that different from what we see on other 64-bit processors. In fact, I saw a SPARC crash for a similar reason, and noticed that it looked just like mine except the numbers in the first segment were reversed. Having played around with hex editors before, I had a feeling I might be dealing with a little-endian version of a big-endian problem, but I didn't expect that knowledge to actually yield an easy solution. https://bugzilla.mozilla.org/show_bug.cgi?id=577056 https://www.oracle.com/technetwork/server-storage/solaris10/solaris-memory-135224.html As far as I can tell, this was the last barrier to an AMD64 Solaris build of Pale Moon. --- js/src/gc/Memory.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'js/src') diff --git a/js/src/gc/Memory.cpp b/js/src/gc/Memory.cpp index 5cf0cd2f7..2bc1b9f50 100644 --- a/js/src/gc/Memory.cpp +++ b/js/src/gc/Memory.cpp @@ -415,8 +415,15 @@ InitMemorySubsystem() static inline void* MapMemoryAt(void* desired, size_t length, int prot = PROT_READ | PROT_WRITE, int flags = MAP_PRIVATE | MAP_ANON, int fd = -1, off_t offset = 0) + +// Solaris manages 64-bit address space in a different manner from every other +// AMD64 operating system, but fortunately the fix is the same one +// required for every operating system on 64-bit SPARC, Itanium, and ARM. +// Most people's intuition failed them here and they thought this couldn't +// possibly be correct on AMD64, but for Solaris/illumos it is. + { -#if defined(__ia64__) || (defined(__sparc64__) && defined(__NetBSD__)) || defined(__aarch64__) +#if defined(__ia64__) || (defined(__sparc64__) && defined(__NetBSD__)) || defined(__aarch64__) || (defined(__sun) && defined(__x86_64__)) MOZ_ASSERT((0xffff800000000000ULL & (uintptr_t(desired) + length - 1)) == 0); #endif void* region = mmap(desired, length, prot, flags, fd, offset); @@ -466,7 +473,7 @@ MapMemory(size_t length, int prot = PROT_READ | PROT_WRITE, return nullptr; } return region; -#elif defined(__aarch64__) +#elif defined(__aarch64__) || (defined(__sun) && defined(__x86_64__)) /* * There might be similar virtual address issue on arm64 which depends on * hardware and kernel configurations. But the work around is slightly -- cgit v1.2.3 From 21146d0d5e4b6c985a3dce26460a5f495f1deb6e Mon Sep 17 00:00:00 2001 From: athenian200 Date: Thu, 17 Oct 2019 17:26:58 -0500 Subject: MoonchildProductions#1251 - Part 25: Fix link paths. This fix is a bit ugly and may need to be changed later if we switch a new GCC version, but the fact is that we use an architecture-specific path for GCC libraries on Solaris, so knowing the right prefix for GCC would only help so much, because it would still need to decide between ${gccdir}/lib and ${gccdir}/lib/amd64. The MOZ_FIX_LINK_PATHS variable puts the search paths into the right order without the need for me to use elfedit on the binaries afterwards. --- js/src/old-configure.in | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'js/src') diff --git a/js/src/old-configure.in b/js/src/old-configure.in index 45108ee59..6566ce05e 100644 --- a/js/src/old-configure.in +++ b/js/src/old-configure.in @@ -923,6 +923,14 @@ case "$target" in fi ;; +i*86-*-solaris*) + MOZ_FIX_LINK_PATHS="-L${DIST}/bin -R'\$\$ORIGIN':/usr/gcc/7/lib" + ;; + +x86_64-*-solaris*) + MOZ_FIX_LINK_PATHS="-L${DIST}/bin -R'\$\$ORIGIN':/usr/gcc/7/lib/amd64" + ;; + esac dnl Only one oddball right now (QNX), but this gives us flexibility -- cgit v1.2.3 From 687a798e6dedacb8b42826debcd8e89baa69ce94 Mon Sep 17 00:00:00 2001 From: athenian200 Date: Sat, 19 Oct 2019 14:24:49 -0500 Subject: MoonchildProductions#1251 - Part 27: Fix ifdef style. This should do it for all the commits to files I changed, but while I'm in here I could probably go ahead and turn ALL the singular if defined statements into ifdef statements by using grep/find on the tree. On the other hand, perhaps we should do that as a separate issue so that this doesn't become a case of scope creep. --- js/src/builtin/TestingFunctions.cpp | 2 +- js/src/gc/Memory.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'js/src') diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 6beb82932..4363c7aed 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -239,7 +239,7 @@ GetBuildConfiguration(JSContext* cx, unsigned argc, Value* vp) value = BooleanValue(true); if (!JS_SetProperty(cx, info, "intl-api", value)) return false; -#if defined(XP_SOLARIS) +#ifdef XP_SOLARIS value = BooleanValue(false); #else value = BooleanValue(true); diff --git a/js/src/gc/Memory.cpp b/js/src/gc/Memory.cpp index 2bc1b9f50..418984057 100644 --- a/js/src/gc/Memory.cpp +++ b/js/src/gc/Memory.cpp @@ -685,7 +685,7 @@ MarkPagesUnused(void* p, size_t size) return false; MOZ_ASSERT(OffsetFromAligned(p, pageSize) == 0); -#if defined(XP_SOLARIS) +#ifdef XP_SOLARIS int result = posix_madvise(p, size, POSIX_MADV_DONTNEED); #else int result = madvise(p, size, MADV_DONTNEED); -- cgit v1.2.3 From dee457e63aa52ac83c0545ae87dc273cbdd072f1 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Tue, 22 Oct 2019 20:57:58 +0200 Subject: Avoid uint32_t overflow in js shell by checking size of file before trying to stuff something insanely large into a Uint8Array. See also: BMO 1571911 --- js/src/shell/OSObject.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'js/src') diff --git a/js/src/shell/OSObject.cpp b/js/src/shell/OSObject.cpp index 846ec7b15..4fb3d4e77 100644 --- a/js/src/shell/OSObject.cpp +++ b/js/src/shell/OSObject.cpp @@ -184,6 +184,11 @@ FileAsTypedArray(JSContext* cx, JS::HandleString pathnameStr) return nullptr; JS_ReportErrorUTF8(cx, "can't seek start of %s", pathname.ptr()); } else { + if (len > INT32_MAX) { + JS_ReportErrorUTF8(cx, "file %s is too large for a Uint8Array", + pathname.ptr()); + return nullptr; + } obj = JS_NewUint8Array(cx, len); if (!obj) return nullptr; -- cgit v1.2.3 From e8c5582bec49058508b2de9f2f292f3a25e5278e Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 24 Oct 2019 12:13:26 +0200 Subject: Fix type barrier in IonBuilder::jsop_getimport. --- js/src/jit/IonBuilder.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 2d053de5a..0c69729a4 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -8895,10 +8895,8 @@ IonBuilder::jsop_getimport(PropertyName* name) if (!emitted) { // This can happen if we don't have type information. - TypeSet::ObjectKey* staticKey = TypeSet::ObjectKey::get(targetEnv); TemporaryTypeSet* types = bytecodeTypes(pc); - BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), staticKey, - name, types, /* updateObserved = */ true); + BarrierKind barrier = BarrierKind::TypeSet; if (!loadStaticSlot(targetEnv, barrier, types, shape->slot())) return false; -- cgit v1.2.3 From c59c9682d351e641f184e1f8095f399fee179f62 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 26 Oct 2019 13:08:45 +0200 Subject: Issue #1257 - Part1: Remove watch class-hook and proxy trap. --- js/src/builtin/TypedObject.cpp | 1 - js/src/jsobj.cpp | 6 ------ js/src/jsobj.h | 2 -- js/src/jswrapper.h | 7 ------- js/src/proxy/BaseProxyHandler.cpp | 14 -------------- js/src/proxy/Proxy.cpp | 27 --------------------------- js/src/proxy/Proxy.h | 3 --- js/src/proxy/SecurityWrapper.cpp | 19 ------------------- js/src/vm/EnvironmentObject.cpp | 3 --- 9 files changed, 82 deletions(-) (limited to 'js/src') diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index ff3680774..50bf0b836 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -2215,7 +2215,6 @@ const ObjectOps TypedObject::objectOps_ = { TypedObject::obj_setProperty, TypedObject::obj_getOwnPropertyDescriptor, TypedObject::obj_deleteProperty, - nullptr, nullptr, /* watch/unwatch */ nullptr, /* getElements */ TypedObject::obj_enumerate, nullptr, /* thisValue */ diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 6f9596924..ee66addc9 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -2836,9 +2836,6 @@ js::UnwatchGuts(JSContext* cx, JS::HandleObject origObj, JS::HandleId id) bool js::WatchProperty(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable) { - if (WatchOp op = obj->getOpsWatch()) - return op(cx, obj, id, callable); - if (!obj->isNative() || obj->is()) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_WATCH, obj->getClass()->name); @@ -2851,9 +2848,6 @@ js::WatchProperty(JSContext* cx, HandleObject obj, HandleId id, HandleObject cal bool js::UnwatchProperty(JSContext* cx, HandleObject obj, HandleId id) { - if (UnwatchOp op = obj->getOpsUnwatch()) - return op(cx, obj, id); - return UnwatchGuts(cx, obj, id); } diff --git a/js/src/jsobj.h b/js/src/jsobj.h index db2c22b76..8a41d155e 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -141,8 +141,6 @@ class JSObject : public js::gc::Cell js::GetOwnPropertyOp getOpsGetOwnPropertyDescriptor() const { return getClass()->getOpsGetOwnPropertyDescriptor(); } js::DeletePropertyOp getOpsDeleteProperty() const { return getClass()->getOpsDeleteProperty(); } - js::WatchOp getOpsWatch() const { return getClass()->getOpsWatch(); } - js::UnwatchOp getOpsUnwatch() const { return getClass()->getOpsUnwatch(); } js::GetElementsOp getOpsGetElements() const { return getClass()->getOpsGetElements(); } JSNewEnumerateOp getOpsEnumerate() const { return getClass()->getOpsEnumerate(); } JSFunToStringOp getOpsFunToString() const { return getClass()->getOpsFunToString(); } diff --git a/js/src/jswrapper.h b/js/src/jswrapper.h index 5f3704e32..32336c68b 100644 --- a/js/src/jswrapper.h +++ b/js/src/jswrapper.h @@ -315,13 +315,6 @@ class JS_FRIEND_API(SecurityWrapper) : public Base virtual bool regexp_toShared(JSContext* cx, HandleObject proxy, RegExpGuard* g) const override; virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const override; - // Allow isCallable and isConstructor. They used to be class-level, and so could not be guarded - // against. - - virtual bool watch(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, - JS::HandleObject callable) const override; - virtual bool unwatch(JSContext* cx, JS::HandleObject proxy, JS::HandleId id) const override; - /* * Allow our subclasses to select the superclass behavior they want without * needing to specify an exact superclass. diff --git a/js/src/proxy/BaseProxyHandler.cpp b/js/src/proxy/BaseProxyHandler.cpp index 8d5f30a19..423aa8671 100644 --- a/js/src/proxy/BaseProxyHandler.cpp +++ b/js/src/proxy/BaseProxyHandler.cpp @@ -418,20 +418,6 @@ BaseProxyHandler::setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* return true; } -bool -BaseProxyHandler::watch(JSContext* cx, HandleObject proxy, HandleId id, HandleObject callable) const -{ - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_WATCH, - proxy->getClass()->name); - return false; -} - -bool -BaseProxyHandler::unwatch(JSContext* cx, HandleObject proxy, HandleId id) const -{ - return true; -} - bool BaseProxyHandler::getElements(JSContext* cx, HandleObject proxy, uint32_t begin, uint32_t end, ElementAdder* adder) const diff --git a/js/src/proxy/Proxy.cpp b/js/src/proxy/Proxy.cpp index 2c1cffb77..6b3a3d1e9 100644 --- a/js/src/proxy/Proxy.cpp +++ b/js/src/proxy/Proxy.cpp @@ -504,20 +504,6 @@ Proxy::boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp JSObject * const TaggedProto::LazyProto = reinterpret_cast(0x1); -/* static */ bool -Proxy::watch(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, JS::HandleObject callable) -{ - JS_CHECK_RECURSION(cx, return false); - return proxy->as().handler()->watch(cx, proxy, id, callable); -} - -/* static */ bool -Proxy::unwatch(JSContext* cx, JS::HandleObject proxy, JS::HandleId id) -{ - JS_CHECK_RECURSION(cx, return false); - return proxy->as().handler()->unwatch(cx, proxy, id); -} - /* static */ bool Proxy::getElements(JSContext* cx, HandleObject proxy, uint32_t begin, uint32_t end, ElementAdder* adder) @@ -698,18 +684,6 @@ js::proxy_Construct(JSContext* cx, unsigned argc, Value* vp) return Proxy::construct(cx, proxy, args); } -bool -js::proxy_Watch(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable) -{ - return Proxy::watch(cx, obj, id, callable); -} - -bool -js::proxy_Unwatch(JSContext* cx, HandleObject obj, HandleId id) -{ - return Proxy::unwatch(cx, obj, id); -} - bool js::proxy_GetElements(JSContext* cx, HandleObject proxy, uint32_t begin, uint32_t end, ElementAdder* adder) @@ -750,7 +724,6 @@ const ObjectOps js::ProxyObjectOps = { js::proxy_SetProperty, js::proxy_GetOwnPropertyDescriptor, js::proxy_DeleteProperty, - js::proxy_Watch, js::proxy_Unwatch, js::proxy_GetElements, nullptr, /* enumerate */ js::proxy_FunToString diff --git a/js/src/proxy/Proxy.h b/js/src/proxy/Proxy.h index 89909a085..4a8ecf8ab 100644 --- a/js/src/proxy/Proxy.h +++ b/js/src/proxy/Proxy.h @@ -65,9 +65,6 @@ class Proxy static bool regexp_toShared(JSContext* cx, HandleObject proxy, RegExpGuard* g); static bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp); - static bool watch(JSContext* cx, HandleObject proxy, HandleId id, HandleObject callable); - static bool unwatch(JSContext* cx, HandleObject proxy, HandleId id); - static bool getElements(JSContext* cx, HandleObject obj, uint32_t begin, uint32_t end, ElementAdder* adder); diff --git a/js/src/proxy/SecurityWrapper.cpp b/js/src/proxy/SecurityWrapper.cpp index 710faf9b0..71d22fca6 100644 --- a/js/src/proxy/SecurityWrapper.cpp +++ b/js/src/proxy/SecurityWrapper.cpp @@ -130,24 +130,5 @@ SecurityWrapper::defineProperty(JSContext* cx, HandleObject wrapper, Handl return Base::defineProperty(cx, wrapper, id, desc, result); } -template -bool -SecurityWrapper::watch(JSContext* cx, HandleObject proxy, - HandleId id, HandleObject callable) const -{ - ReportUnwrapDenied(cx); - return false; -} - -template -bool -SecurityWrapper::unwatch(JSContext* cx, HandleObject proxy, - HandleId id) const -{ - ReportUnwrapDenied(cx); - return false; -} - - template class js::SecurityWrapper; template class js::SecurityWrapper; diff --git a/js/src/vm/EnvironmentObject.cpp b/js/src/vm/EnvironmentObject.cpp index a5aac2ab4..3680c5b7b 100644 --- a/js/src/vm/EnvironmentObject.cpp +++ b/js/src/vm/EnvironmentObject.cpp @@ -408,7 +408,6 @@ const ObjectOps ModuleEnvironmentObject::objectOps_ = { ModuleEnvironmentObject::setProperty, ModuleEnvironmentObject::getOwnPropertyDescriptor, ModuleEnvironmentObject::deleteProperty, - nullptr, nullptr, /* watch/unwatch */ nullptr, /* getElements */ ModuleEnvironmentObject::enumerate, nullptr @@ -790,7 +789,6 @@ static const ObjectOps WithEnvironmentObjectOps = { with_SetProperty, with_GetOwnPropertyDescriptor, with_DeleteProperty, - nullptr, nullptr, /* watch/unwatch */ nullptr, /* getElements */ nullptr, /* enumerate (native enumeration of target doesn't work) */ nullptr, @@ -1159,7 +1157,6 @@ static const ObjectOps RuntimeLexicalErrorObjectObjectOps = { lexicalError_SetProperty, lexicalError_GetOwnPropertyDescriptor, lexicalError_DeleteProperty, - nullptr, nullptr, /* watch/unwatch */ nullptr, /* getElements */ nullptr, /* enumerate (native enumeration of target doesn't work) */ nullptr, /* this */ -- cgit v1.2.3 From 44a077980abb92dcea9ed374fd9719eaaf2f1458 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sun, 27 Oct 2019 02:51:11 +0200 Subject: Issue #1257 - Part 2: Remove watch/unwatch and JS watchpoint class. --- js/src/builtin/Object.cpp | 95 ----------------- js/src/gc/Marking.cpp | 7 +- js/src/gc/RootMarking.cpp | 1 - js/src/jit/BaselineIC.cpp | 6 -- js/src/jit/IonCaches.cpp | 5 +- js/src/js.msg | 2 - js/src/jsapi.cpp | 1 - js/src/jscntxt.cpp | 1 - js/src/jscompartment.cpp | 12 --- js/src/jscompartment.h | 3 - js/src/jsfriendapi.cpp | 2 - js/src/jsfriendapi.h | 24 ----- js/src/jsgc.cpp | 14 --- js/src/jsobj.cpp | 66 +----------- js/src/jsobj.h | 20 ---- js/src/jsobjinlines.h | 6 -- js/src/jsversion.h | 1 - js/src/jswatchpoint.cpp | 246 ------------------------------------------- js/src/jswatchpoint.h | 90 ---------------- js/src/moz.build | 1 - js/src/vm/NativeObject-inl.h | 8 +- js/src/vm/NativeObject.cpp | 14 +-- js/src/vm/Runtime.cpp | 1 - js/src/vm/Shape.h | 2 +- js/src/vm/TypeInference.cpp | 114 ++++++++++---------- 25 files changed, 65 insertions(+), 677 deletions(-) delete mode 100644 js/src/jswatchpoint.cpp delete mode 100644 js/src/jswatchpoint.h (limited to 'js/src') diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp index 56c77f304..bfcc8d20e 100644 --- a/js/src/builtin/Object.cpp +++ b/js/src/builtin/Object.cpp @@ -568,97 +568,6 @@ obj_setPrototypeOf(JSContext* cx, unsigned argc, Value* vp) return true; } -#if JS_HAS_OBJ_WATCHPOINT - -bool -js::WatchHandler(JSContext* cx, JSObject* obj_, jsid id_, const JS::Value& old, - JS::Value* nvp, void* closure) -{ - RootedObject obj(cx, obj_); - RootedId id(cx, id_); - - /* Avoid recursion on (obj, id) already being watched on cx. */ - AutoResolving resolving(cx, obj, id, AutoResolving::WATCH); - if (resolving.alreadyStarted()) - return true; - - FixedInvokeArgs<3> args(cx); - - args[0].set(IdToValue(id)); - args[1].set(old); - args[2].set(*nvp); - - RootedValue callable(cx, ObjectValue(*static_cast(closure))); - RootedValue thisv(cx, ObjectValue(*obj)); - RootedValue rv(cx); - if (!Call(cx, callable, thisv, args, &rv)) - return false; - - *nvp = rv; - return true; -} - -static bool -obj_watch(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - - RootedObject obj(cx, ToObject(cx, args.thisv())); - if (!obj) - return false; - - if (!GlobalObject::warnOnceAboutWatch(cx, obj)) - return false; - - if (args.length() <= 1) { - ReportMissingArg(cx, args.calleev(), 1); - return false; - } - - RootedObject callable(cx, ValueToCallable(cx, args[1], args.length() - 2)); - if (!callable) - return false; - - RootedId propid(cx); - if (!ValueToId(cx, args[0], &propid)) - return false; - - if (!WatchProperty(cx, obj, propid, callable)) - return false; - - args.rval().setUndefined(); - return true; -} - -static bool -obj_unwatch(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - - RootedObject obj(cx, ToObject(cx, args.thisv())); - if (!obj) - return false; - - if (!GlobalObject::warnOnceAboutWatch(cx, obj)) - return false; - - RootedId id(cx); - if (args.length() != 0) { - if (!ValueToId(cx, args[0], &id)) - return false; - } else { - id = JSID_VOID; - } - - if (!UnwatchProperty(cx, obj, id)) - return false; - - args.rval().setUndefined(); - return true; -} - -#endif /* JS_HAS_OBJ_WATCHPOINT */ - /* ECMA 15.2.4.5. */ bool js::obj_hasOwnProperty(JSContext* cx, unsigned argc, Value* vp) @@ -1290,10 +1199,6 @@ static const JSFunctionSpec object_methods[] = { JS_FN(js_toString_str, obj_toString, 0,0), JS_SELF_HOSTED_FN(js_toLocaleString_str, "Object_toLocaleString", 0, 0), JS_SELF_HOSTED_FN(js_valueOf_str, "Object_valueOf", 0,0), -#if JS_HAS_OBJ_WATCHPOINT - JS_FN(js_watch_str, obj_watch, 2,0), - JS_FN(js_unwatch_str, obj_unwatch, 1,0), -#endif JS_FN(js_hasOwnProperty_str, obj_hasOwnProperty, 1,0), JS_FN(js_isPrototypeOf_str, obj_isPrototypeOf, 1,0), JS_FN(js_propertyIsEnumerable_str, obj_propertyIsEnumerable, 1,0), diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index da3ef7d0d..262fc8cbc 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -2846,10 +2846,9 @@ struct UnmarkGrayTracer : public JS::CallbackTracer * * There is an additional complication for certain kinds of edges that are not * contained explicitly in the source object itself, such as from a weakmap key - * to its value, and from an object being watched by a watchpoint to the - * watchpoint's closure. These "implicit edges" are represented in some other - * container object, such as the weakmap or the watchpoint itself. In these - * cases, calling unmark gray on an object won't find all of its children. + * to its value. These "implicit edges" are represented in some other + * container object, such as the weakmap itself. In these cases, calling unmark + * gray on an object won't find all of its children. * * Handling these implicit edges has two parts: * - A special pass enumerating all of the containers that know about the diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index f5969bc1f..7d665e8eb 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -14,7 +14,6 @@ #include "jsgc.h" #include "jsprf.h" #include "jstypes.h" -#include "jswatchpoint.h" #include "builtin/MapObject.h" #include "frontend/BytecodeCompiler.h" diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index a001357f8..9530f65fa 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -4053,9 +4053,6 @@ TryAttachSetValuePropStub(JSContext* cx, HandleScript script, jsbytecode* pc, IC { MOZ_ASSERT(!*attached); - if (obj->watched()) - return true; - RootedShape shape(cx); RootedObject holder(cx); if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape)) @@ -4151,9 +4148,6 @@ TryAttachSetAccessorPropStub(JSContext* cx, HandleScript script, jsbytecode* pc, MOZ_ASSERT(!*attached); MOZ_ASSERT(!*isTemporarilyUnoptimizable); - if (obj->watched()) - return true; - RootedShape shape(cx); RootedObject holder(cx); if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape)) diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index 48e0792bb..fb4291188 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -3232,7 +3232,7 @@ SetPropertyIC::tryAttachStub(JSContext* cx, HandleScript outerScript, IonScript* MOZ_ASSERT(!*emitted); MOZ_ASSERT(!*tryNativeAddSlot); - if (!canAttachStub() || obj->watched()) + if (!canAttachStub()) return true; // Fail cache emission if the object is frozen @@ -3897,9 +3897,6 @@ IsDenseElementSetInlineable(JSObject* obj, const Value& idval, const ConstantOrR if (!obj->is()) return false; - if (obj->watched()) - return false; - if (!idval.isInt32()) return false; diff --git a/js/src/js.msg b/js/src/js.msg index f57b36a90..1612c831d 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -47,7 +47,6 @@ MSG_DEF(JSMSG_MORE_ARGS_NEEDED, 3, JSEXN_TYPEERR, "{0} requires more than MSG_DEF(JSMSG_INCOMPATIBLE_PROTO, 3, JSEXN_TYPEERR, "{0}.prototype.{1} called on incompatible {2}") MSG_DEF(JSMSG_NO_CONSTRUCTOR, 1, JSEXN_TYPEERR, "{0} has no constructor") MSG_DEF(JSMSG_BAD_SORT_ARG, 0, JSEXN_TYPEERR, "invalid Array.prototype.sort argument") -MSG_DEF(JSMSG_CANT_WATCH, 1, JSEXN_TYPEERR, "can't watch non-native objects of class {0}") MSG_DEF(JSMSG_READ_ONLY, 1, JSEXN_TYPEERR, "{0} is read-only") MSG_DEF(JSMSG_CANT_DELETE, 1, JSEXN_TYPEERR, "property {0} is non-configurable and can't be deleted") MSG_DEF(JSMSG_CANT_TRUNCATE_ARRAY, 0, JSEXN_TYPEERR, "can't delete non-configurable array element") @@ -72,7 +71,6 @@ MSG_DEF(JSMSG_UNDEFINED_PROP, 1, JSEXN_REFERENCEERR, "reference to unde MSG_DEF(JSMSG_INVALID_MAP_ITERABLE, 1, JSEXN_TYPEERR, "iterable for {0} should have array-like objects") MSG_DEF(JSMSG_NESTING_GENERATOR, 0, JSEXN_TYPEERR, "already executing generator") MSG_DEF(JSMSG_INCOMPATIBLE_METHOD, 3, JSEXN_TYPEERR, "{0} {1} called on incompatible {2}") -MSG_DEF(JSMSG_OBJECT_WATCH_DEPRECATED, 0, JSEXN_WARN, "Object.prototype.watch and unwatch are very slow, non-standard, and deprecated; use a getter/setter instead") MSG_DEF(JSMSG_ARRAYBUFFER_SLICE_DEPRECATED, 0, JSEXN_WARN, "ArrayBuffer.slice is deprecated; use ArrayBuffer.prototype.slice instead") MSG_DEF(JSMSG_BAD_SURROGATE_CHAR, 1, JSEXN_TYPEERR, "bad surrogate character {0}") MSG_DEF(JSMSG_UTF8_CHAR_TOO_LARGE, 1, JSEXN_TYPEERR, "UTF-8 character {0} too large") diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index cad0840e0..f9a0c6a6b 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -39,7 +39,6 @@ #include "jsstr.h" #include "jstypes.h" #include "jsutil.h" -#include "jswatchpoint.h" #include "jsweakmap.h" #include "jswrapper.h" diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index e505a4b34..23b9d27ae 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -37,7 +37,6 @@ #include "jsscript.h" #include "jsstr.h" #include "jstypes.h" -#include "jswatchpoint.h" #include "gc/Marking.h" #include "jit/Ion.h" diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index d0caeb558..8ba186b08 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -13,7 +13,6 @@ #include "jsfriendapi.h" #include "jsgc.h" #include "jsiter.h" -#include "jswatchpoint.h" #include "jswrapper.h" #include "gc/Marking.h" @@ -76,7 +75,6 @@ JSCompartment::JSCompartment(Zone* zone, const JS::CompartmentOptions& options = gcIncomingGrayPointers(nullptr), debugModeBits(0), randomKeyGenerator_(runtime_->forkRandomKeyGenerator()), - watchpointMap(nullptr), scriptCountsMap(nullptr), debugScriptMap(nullptr), debugEnvs(nullptr), @@ -103,7 +101,6 @@ JSCompartment::~JSCompartment() rt->lcovOutput.writeLCovResult(lcovOutput); js_delete(jitCompartment_); - js_delete(watchpointMap); js_delete(scriptCountsMap); js_delete(debugScriptMap); js_delete(debugEnvs); @@ -662,12 +659,6 @@ JSCompartment::traceRoots(JSTracer* trc, js::gc::GCRuntime::TraceOrMarkRuntime t if (traceOrMark == js::gc::GCRuntime::MarkRuntime && !zone()->isCollecting()) return; - // During a GC, these are treated as weak pointers. - if (traceOrMark == js::gc::GCRuntime::TraceRuntime) { - if (watchpointMap) - watchpointMap->markAll(trc); - } - /* Mark debug scopes, if present */ if (debugEnvs) debugEnvs->mark(trc); @@ -712,9 +703,6 @@ JSCompartment::traceRoots(JSTracer* trc, js::gc::GCRuntime::TraceOrMarkRuntime t void JSCompartment::finishRoots() { - if (watchpointMap) - watchpointMap->clear(); - if (debugEnvs) debugEnvs->finish(); diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index 83c15da3b..05ff40b43 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -282,7 +282,6 @@ class MOZ_RAII AutoSetNewObjectMetadata : private JS::CustomAutoRooter namespace js { class DebugEnvironments; class ObjectWeakMap; -class WatchpointMap; class WeakMapBase; } // namespace js @@ -811,8 +810,6 @@ struct JSCompartment void sweepBreakpoints(js::FreeOp* fop); public: - js::WatchpointMap* watchpointMap; - js::ScriptCountsMap* scriptCountsMap; js::DebugScriptMap* debugScriptMap; diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index f7622cb44..bdb3c0a4d 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -15,7 +15,6 @@ #include "jsgc.h" #include "jsobj.h" #include "jsprf.h" -#include "jswatchpoint.h" #include "jsweakmap.h" #include "jswrapper.h" @@ -579,7 +578,6 @@ void js::TraceWeakMaps(WeakMapTracer* trc) { WeakMapBase::traceAllMappings(trc); - WatchpointMap::traceAll(trc); } extern JS_FRIEND_API(bool) diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index 351667fb3..491215456 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -2110,30 +2110,6 @@ JS_FRIEND_API(void*) JS_GetDataViewData(JSObject* obj, const JS::AutoCheckCannotGC&); namespace js { - -/** - * Add a watchpoint -- in the Object.prototype.watch sense -- to |obj| for the - * property |id|, using the callable object |callable| as the function to be - * called for notifications. - * - * This is an internal function exposed -- temporarily -- only so that DOM - * proxies can be watchable. Don't use it! We'll soon kill off the - * Object.prototype.{,un}watch functions, at which point this will go too. - */ -extern JS_FRIEND_API(bool) -WatchGuts(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable); - -/** - * Remove a watchpoint -- in the Object.prototype.watch sense -- from |obj| for - * the property |id|. - * - * This is an internal function exposed -- temporarily -- only so that DOM - * proxies can be watchable. Don't use it! We'll soon kill off the - * Object.prototype.{,un}watch functions, at which point this will go too. - */ -extern JS_FRIEND_API(bool) -UnwatchGuts(JSContext* cx, JS::HandleObject obj, JS::HandleId id); - namespace jit { enum class InlinableNative : uint16_t; diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index b2ee8d67b..5a9d732b6 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -207,7 +207,6 @@ #include "jsscript.h" #include "jstypes.h" #include "jsutil.h" -#include "jswatchpoint.h" #include "jsweakmap.h" #ifdef XP_WIN # include "jswin.h" @@ -2392,11 +2391,6 @@ GCRuntime::updatePointersToRelocatedCells(Zone* zone, AutoLockForExclusiveAccess Debugger::markIncomingCrossCompartmentEdges(&trc); WeakMapBase::markAll(zone, &trc); - for (CompartmentsInZoneIter c(zone); !c.done(); c.next()) { - c->trace(&trc); - if (c->watchpointMap) - c->watchpointMap->markAll(&trc); - } // Mark all gray roots, making sure we call the trace callback to get the // current set. @@ -2405,7 +2399,6 @@ GCRuntime::updatePointersToRelocatedCells(Zone* zone, AutoLockForExclusiveAccess } // Sweep everything to fix up weak pointers - WatchpointMap::sweepAll(rt); Debugger::sweepAll(rt->defaultFreeOp()); jit::JitRuntime::SweepJitcodeGlobalTable(rt); rt->gc.sweepZoneAfterCompacting(zone); @@ -3850,10 +3843,6 @@ GCRuntime::markWeakReferences(gcstats::Phase phase) for (ZoneIterT zone(rt); !zone.done(); zone.next()) markedAny |= WeakMapBase::markZoneIteratively(zone, &marker); } - for (CompartmentsIterT c(rt); !c.done(); c.next()) { - if (c->watchpointMap) - markedAny |= c->watchpointMap->markIteratively(&marker); - } markedAny |= Debugger::markAllIteratively(&marker); markedAny |= jit::JitRuntime::MarkJitcodeGlobalTableIteratively(&marker); @@ -4625,9 +4614,6 @@ GCRuntime::beginSweepingZoneGroup(AutoLockForExclusiveAccess& lock) // Bug 1071218: the following two methods have not yet been // refactored to work on a single zone-group at once. - // Collect watch points associated with unreachable objects. - WatchpointMap::sweepAll(rt); - // Detach unreachable debuggers and global objects from each other. Debugger::sweepAll(&fop); diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index ee66addc9..ef1291079 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -33,7 +33,6 @@ #include "jsstr.h" #include "jstypes.h" #include "jsutil.h" -#include "jswatchpoint.h" #include "jswin.h" #include "jswrapper.h" @@ -1011,13 +1010,7 @@ js::CreateThisForFunction(JSContext* cx, HandleObject callee, HandleObject newTa JSObject::nonNativeSetProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v, HandleValue receiver, ObjectOpResult& result) { - RootedValue value(cx, v); - if (MOZ_UNLIKELY(obj->watched())) { - WatchpointMap* wpmap = cx->compartment()->watchpointMap; - if (wpmap && !wpmap->triggerWatchpoint(cx, obj, id, &value)) - return false; - } - return obj->getOpsSetProperty()(cx, obj, id, value, receiver, result); + return obj->getOpsSetProperty()(cx, obj, id, v, receiver, result); } /* static */ bool @@ -2795,62 +2788,6 @@ js::GetPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id, return true; } -bool -js::WatchGuts(JSContext* cx, JS::HandleObject origObj, JS::HandleId id, JS::HandleObject callable) -{ - RootedObject obj(cx, ToWindowIfWindowProxy(origObj)); - if (obj->isNative()) { - // Use sparse indexes for watched objects, as dense elements can be - // written to without checking the watchpoint map. - if (!NativeObject::sparsifyDenseElements(cx, obj.as())) - return false; - - MarkTypePropertyNonData(cx, obj, id); - } - - WatchpointMap* wpmap = cx->compartment()->watchpointMap; - if (!wpmap) { - wpmap = cx->runtime()->new_(); - if (!wpmap || !wpmap->init()) { - ReportOutOfMemory(cx); - js_delete(wpmap); - return false; - } - cx->compartment()->watchpointMap = wpmap; - } - - return wpmap->watch(cx, obj, id, js::WatchHandler, callable); -} - -bool -js::UnwatchGuts(JSContext* cx, JS::HandleObject origObj, JS::HandleId id) -{ - // Looking in the map for an unsupported object will never hit, so we don't - // need to check for nativeness or watchable-ness here. - RootedObject obj(cx, ToWindowIfWindowProxy(origObj)); - if (WatchpointMap* wpmap = cx->compartment()->watchpointMap) - wpmap->unwatch(obj, id, nullptr, nullptr); - return true; -} - -bool -js::WatchProperty(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable) -{ - if (!obj->isNative() || obj->is()) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_WATCH, - obj->getClass()->name); - return false; - } - - return WatchGuts(cx, obj, id, callable); -} - -bool -js::UnwatchProperty(JSContext* cx, HandleObject obj, HandleId id) -{ - return UnwatchGuts(cx, obj, id); -} - const char* js::GetObjectClassName(JSContext* cx, HandleObject obj) { @@ -3410,7 +3347,6 @@ JSObject::dump(FILE* fp) const if (obj->isBoundFunction()) fprintf(fp, " bound_function"); if (obj->isQualifiedVarObj()) fprintf(fp, " varobj"); if (obj->isUnqualifiedVarObj()) fprintf(fp, " unqualified_varobj"); - if (obj->watched()) fprintf(fp, " watched"); if (obj->isIteratedSingleton()) fprintf(fp, " iterated_singleton"); if (obj->isNewGroupUnknown()) fprintf(fp, " new_type_unknown"); if (obj->hasUncacheableProto()) fprintf(fp, " has_uncacheable_proto"); diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 8a41d155e..01845d7e6 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -219,11 +219,6 @@ class JSObject : public js::gc::Cell inline bool isBoundFunction() const; inline bool hasSpecialEquality() const; - inline bool watched() const; - static bool setWatched(js::ExclusiveContext* cx, JS::HandleObject obj) { - return setFlags(cx, obj, js::BaseShape::WATCHED, GENERATE_SHAPE); - } - // A "qualified" varobj is the object on which "qualified" variable // declarations (i.e., those defined with "var") are kept. // @@ -1030,21 +1025,6 @@ extern bool DefineFunctions(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs, DefineAsIntrinsic intrinsic); -/* - * Set a watchpoint: a synchronous callback when the given property of the - * given object is set. - * - * Watchpoints are nonstandard and do not fit in well with the way ES6 - * specifies [[Set]]. They are also insufficient for implementing - * Object.observe. - */ -extern bool -WatchProperty(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable); - -/* Clear a watchpoint. */ -extern bool -UnwatchProperty(JSContext* cx, HandleObject obj, HandleId id); - /* ES6 draft rev 36 (2015 March 17) 7.1.1 ToPrimitive(vp[, preferredType]) */ extern bool ToPrimitiveSlow(JSContext* cx, JSType hint, MutableHandleValue vp); diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index c132ee6b2..98e740142 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -463,12 +463,6 @@ JSObject::isBoundFunction() const return is() && as().isBoundFunction(); } -inline bool -JSObject::watched() const -{ - return hasAllFlags(js::BaseShape::WATCHED); -} - inline bool JSObject::isDelegate() const { diff --git a/js/src/jsversion.h b/js/src/jsversion.h index 8bdfe47b6..cf4c6e73a 100644 --- a/js/src/jsversion.h +++ b/js/src/jsversion.h @@ -12,7 +12,6 @@ */ #define JS_HAS_STR_HTML_HELPERS 1 /* (no longer used) */ #define JS_HAS_OBJ_PROTO_PROP 1 /* has o.__proto__ etc. */ -#define JS_HAS_OBJ_WATCHPOINT 1 /* has o.watch and o.unwatch */ #define JS_HAS_TOSOURCE 1 /* has Object/Array toSource method */ #define JS_HAS_CATCH_GUARD 1 /* has exception handling catch guard */ #define JS_HAS_UNEVAL 1 /* has uneval() top-level function */ diff --git a/js/src/jswatchpoint.cpp b/js/src/jswatchpoint.cpp deleted file mode 100644 index 34479a990..000000000 --- a/js/src/jswatchpoint.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * 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/. */ - -#include "jswatchpoint.h" - -#include "jsatom.h" -#include "jscompartment.h" -#include "jsfriendapi.h" - -#include "gc/Marking.h" -#include "vm/Shape.h" - -#include "jsgcinlines.h" - -using namespace js; -using namespace js::gc; - -inline HashNumber -WatchKeyHasher::hash(const Lookup& key) -{ - return MovableCellHasher::hash(key.object) ^ HashId(key.id); -} - -namespace { - -class AutoEntryHolder { - typedef WatchpointMap::Map Map; - Generation gen; - Map& map; - Map::Ptr p; - RootedObject obj; - RootedId id; - - public: - AutoEntryHolder(JSContext* cx, Map& map, Map::Ptr p) - : gen(map.generation()), map(map), p(p), obj(cx, p->key().object), id(cx, p->key().id) - { - MOZ_ASSERT(!p->value().held); - p->value().held = true; - } - - ~AutoEntryHolder() { - if (gen != map.generation()) - p = map.lookup(WatchKey(obj, id)); - if (p) - p->value().held = false; - } -}; - -} /* anonymous namespace */ - -bool -WatchpointMap::init() -{ - return map.init(); -} - -bool -WatchpointMap::watch(JSContext* cx, HandleObject obj, HandleId id, - JSWatchPointHandler handler, HandleObject closure) -{ - MOZ_ASSERT(JSID_IS_STRING(id) || JSID_IS_INT(id) || JSID_IS_SYMBOL(id)); - - if (!JSObject::setWatched(cx, obj)) - return false; - - Watchpoint w(handler, closure, false); - if (!map.put(WatchKey(obj, id), w)) { - ReportOutOfMemory(cx); - return false; - } - /* - * For generational GC, we don't need to post-barrier writes to the - * hashtable here because we mark all watchpoints as part of root marking in - * markAll(). - */ - return true; -} - -void -WatchpointMap::unwatch(JSObject* obj, jsid id, - JSWatchPointHandler* handlerp, JSObject** closurep) -{ - if (Map::Ptr p = map.lookup(WatchKey(obj, id))) { - if (handlerp) - *handlerp = p->value().handler; - if (closurep) { - // Read barrier to prevent an incorrectly gray closure from escaping the - // watchpoint. See the comment before UnmarkGrayChildren in gc/Marking.cpp - JS::ExposeObjectToActiveJS(p->value().closure); - *closurep = p->value().closure; - } - map.remove(p); - } -} - -void -WatchpointMap::unwatchObject(JSObject* obj) -{ - for (Map::Enum e(map); !e.empty(); e.popFront()) { - Map::Entry& entry = e.front(); - if (entry.key().object == obj) - e.removeFront(); - } -} - -void -WatchpointMap::clear() -{ - map.clear(); -} - -bool -WatchpointMap::triggerWatchpoint(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp) -{ - Map::Ptr p = map.lookup(WatchKey(obj, id)); - if (!p || p->value().held) - return true; - - AutoEntryHolder holder(cx, map, p); - - /* Copy the entry, since GC would invalidate p. */ - JSWatchPointHandler handler = p->value().handler; - RootedObject closure(cx, p->value().closure); - - /* Determine the property's old value. */ - Value old; - old.setUndefined(); - if (obj->isNative()) { - NativeObject* nobj = &obj->as(); - if (Shape* shape = nobj->lookup(cx, id)) { - if (shape->hasSlot()) - old = nobj->getSlot(shape->slot()); - } - } - - // Read barrier to prevent an incorrectly gray closure from escaping the - // watchpoint. See the comment before UnmarkGrayChildren in gc/Marking.cpp - JS::ExposeObjectToActiveJS(closure); - - /* Call the handler. */ - return handler(cx, obj, id, old, vp.address(), closure); -} - -bool -WatchpointMap::markIteratively(JSTracer* trc) -{ - bool marked = false; - for (Map::Enum e(map); !e.empty(); e.popFront()) { - Map::Entry& entry = e.front(); - JSObject* priorKeyObj = entry.key().object; - jsid priorKeyId(entry.key().id.get()); - bool objectIsLive = - IsMarked(trc->runtime(), const_cast(&entry.key().object)); - if (objectIsLive || entry.value().held) { - if (!objectIsLive) { - TraceEdge(trc, const_cast(&entry.key().object), - "held Watchpoint object"); - marked = true; - } - - MOZ_ASSERT(JSID_IS_STRING(priorKeyId) || - JSID_IS_INT(priorKeyId) || - JSID_IS_SYMBOL(priorKeyId)); - TraceEdge(trc, const_cast(&entry.key().id), "WatchKey::id"); - - if (entry.value().closure && !IsMarked(trc->runtime(), &entry.value().closure)) { - TraceEdge(trc, &entry.value().closure, "Watchpoint::closure"); - marked = true; - } - - /* We will sweep this entry in sweepAll if !objectIsLive. */ - if (priorKeyObj != entry.key().object || priorKeyId != entry.key().id) - e.rekeyFront(WatchKey(entry.key().object, entry.key().id)); - } - } - return marked; -} - -void -WatchpointMap::markAll(JSTracer* trc) -{ - for (Map::Enum e(map); !e.empty(); e.popFront()) { - Map::Entry& entry = e.front(); - JSObject* object = entry.key().object; - jsid id = entry.key().id; - JSObject* priorObject = object; - jsid priorId = id; - MOZ_ASSERT(JSID_IS_STRING(priorId) || JSID_IS_INT(priorId) || JSID_IS_SYMBOL(priorId)); - - TraceManuallyBarrieredEdge(trc, &object, "held Watchpoint object"); - TraceManuallyBarrieredEdge(trc, &id, "WatchKey::id"); - TraceEdge(trc, &entry.value().closure, "Watchpoint::closure"); - - if (priorObject != object || priorId != id) - e.rekeyFront(WatchKey(object, id)); - } -} - -void -WatchpointMap::sweepAll(JSRuntime* rt) -{ - for (GCCompartmentsIter c(rt); !c.done(); c.next()) { - if (WatchpointMap* wpmap = c->watchpointMap) - wpmap->sweep(); - } -} - -void -WatchpointMap::sweep() -{ - for (Map::Enum e(map); !e.empty(); e.popFront()) { - Map::Entry& entry = e.front(); - JSObject* obj(entry.key().object); - if (IsAboutToBeFinalizedUnbarriered(&obj)) { - MOZ_ASSERT(!entry.value().held); - e.removeFront(); - } else if (obj != entry.key().object) { - e.rekeyFront(WatchKey(obj, entry.key().id)); - } - } -} - -void -WatchpointMap::traceAll(WeakMapTracer* trc) -{ - JSRuntime* rt = trc->context; - for (CompartmentsIter comp(rt, SkipAtoms); !comp.done(); comp.next()) { - if (WatchpointMap* wpmap = comp->watchpointMap) - wpmap->trace(trc); - } -} - -void -WatchpointMap::trace(WeakMapTracer* trc) -{ - for (Map::Range r = map.all(); !r.empty(); r.popFront()) { - Map::Entry& entry = r.front(); - trc->trace(nullptr, - JS::GCCellPtr(entry.key().object.get()), - JS::GCCellPtr(entry.value().closure.get())); - } -} diff --git a/js/src/jswatchpoint.h b/js/src/jswatchpoint.h deleted file mode 100644 index bba6c38ce..000000000 --- a/js/src/jswatchpoint.h +++ /dev/null @@ -1,90 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * 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/. */ - -#ifndef jswatchpoint_h -#define jswatchpoint_h - -#include "jsalloc.h" - -#include "gc/Barrier.h" -#include "js/HashTable.h" - -namespace js { - -struct WeakMapTracer; - -struct WatchKey { - WatchKey() {} - WatchKey(JSObject* obj, jsid id) : object(obj), id(id) {} - WatchKey(const WatchKey& key) : object(key.object.get()), id(key.id.get()) {} - - // These are traced unconditionally during minor GC, so do not require - // post-barriers. - PreBarrieredObject object; - PreBarrieredId id; - - bool operator!=(const WatchKey& other) const { - return object != other.object || id != other.id; - } -}; - -typedef bool -(* JSWatchPointHandler)(JSContext* cx, JSObject* obj, jsid id, const JS::Value& old, - JS::Value* newp, void* closure); - -struct Watchpoint { - JSWatchPointHandler handler; - PreBarrieredObject closure; /* This is always marked in minor GCs and so doesn't require a postbarrier. */ - bool held; /* true if currently running handler */ - Watchpoint(JSWatchPointHandler handler, JSObject* closure, bool held) - : handler(handler), closure(closure), held(held) {} -}; - -struct WatchKeyHasher -{ - typedef WatchKey Lookup; - static inline js::HashNumber hash(const Lookup& key); - - static bool match(const WatchKey& k, const Lookup& l) { - return MovableCellHasher::match(k.object, l.object) && - DefaultHasher::match(k.id, l.id); - } - - static void rekey(WatchKey& k, const WatchKey& newKey) { - k.object.unsafeSet(newKey.object); - k.id.unsafeSet(newKey.id); - } -}; - -class WatchpointMap { - public: - typedef HashMap Map; - - bool init(); - bool watch(JSContext* cx, HandleObject obj, HandleId id, - JSWatchPointHandler handler, HandleObject closure); - void unwatch(JSObject* obj, jsid id, - JSWatchPointHandler* handlerp, JSObject** closurep); - void unwatchObject(JSObject* obj); - void clear(); - - bool triggerWatchpoint(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp); - - bool markIteratively(JSTracer* trc); - void markAll(JSTracer* trc); - static void sweepAll(JSRuntime* rt); - void sweep(); - - static void traceAll(WeakMapTracer* trc); - void trace(WeakMapTracer* trc); - - private: - Map map; -}; - -} // namespace js - -#endif /* jswatchpoint_h */ diff --git a/js/src/moz.build b/js/src/moz.build index a0f074d1c..5ce0dfd98 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -291,7 +291,6 @@ UNIFIED_SOURCES += [ 'jspropertytree.cpp', 'jsscript.cpp', 'jsstr.cpp', - 'jswatchpoint.cpp', 'jsweakmap.cpp', 'perf/jsperf.cpp', 'proxy/BaseProxyHandler.cpp', diff --git a/js/src/vm/NativeObject-inl.h b/js/src/vm/NativeObject-inl.h index e55e3db04..030d92c12 100644 --- a/js/src/vm/NativeObject-inl.h +++ b/js/src/vm/NativeObject-inl.h @@ -158,11 +158,11 @@ NativeObject::extendDenseElements(ExclusiveContext* cx, MOZ_ASSERT(!denseElementsAreFrozen()); /* - * Don't grow elements for non-extensible objects or watched objects. Dense - * elements can be added/written with no extensible or watchpoint checks as - * long as there is capacity for them. + * Don't grow elements for non-extensible objects. Dense elements can be + * added/written with no extensible checks as long as there is capacity + * for them. */ - if (!nonProxyIsExtensible() || watched()) { + if (!nonProxyIsExtensible()) { MOZ_ASSERT(getDenseCapacity() == 0); return DenseElementResult::Incomplete; } diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp index da0f59fe2..d801fad06 100644 --- a/js/src/vm/NativeObject.cpp +++ b/js/src/vm/NativeObject.cpp @@ -9,8 +9,6 @@ #include "mozilla/ArrayUtils.h" #include "mozilla/Casting.h" -#include "jswatchpoint.h" - #include "gc/Marking.h" #include "js/Value.h" #include "vm/Debugger.h" @@ -602,7 +600,7 @@ NativeObject::maybeDensifySparseElements(js::ExclusiveContext* cx, HandleNativeO return DenseElementResult::Incomplete; /* Watch for conditions under which an object's elements cannot be dense. */ - if (!obj->nonProxyIsExtensible() || obj->watched()) + if (!obj->nonProxyIsExtensible()) return DenseElementResult::Incomplete; /* @@ -2410,17 +2408,9 @@ SetExistingProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleVa } bool -js::NativeSetProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleValue value, +js::NativeSetProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleValue v, HandleValue receiver, QualifiedBool qualified, ObjectOpResult& result) { - // Fire watchpoints, if any. - RootedValue v(cx, value); - if (MOZ_UNLIKELY(obj->watched())) { - WatchpointMap* wpmap = cx->compartment()->watchpointMap; - if (wpmap && !wpmap->triggerWatchpoint(cx, obj, id, &v)) - return false; - } - // Step numbers below reference ES6 rev 27 9.1.9, the [[Set]] internal // method for ordinary objects. We substitute our own names for these names // used in the spec: O -> pobj, P -> id, ownDesc -> shape. diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index 5fc8e0e17..284a4f3d7 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -34,7 +34,6 @@ #include "jsnativestack.h" #include "jsobj.h" #include "jsscript.h" -#include "jswatchpoint.h" #include "jswin.h" #include "jswrapper.h" diff --git a/js/src/vm/Shape.h b/js/src/vm/Shape.h index fd6d843e0..85bc044a5 100644 --- a/js/src/vm/Shape.h +++ b/js/src/vm/Shape.h @@ -387,7 +387,7 @@ class BaseShape : public gc::TenuredCell INDEXED = 0x20, /* (0x40 is unused) */ HAD_ELEMENTS_ACCESS = 0x80, - WATCHED = 0x100, + /* (0x100 is unused) */ ITERATED_SINGLETON = 0x200, NEW_GROUP_UNKNOWN = 0x400, UNCACHEABLE_PROTO = 0x800, diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index 88327b47e..2b1fa0e3b 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -2670,14 +2670,6 @@ ObjectGroup::updateNewPropertyTypes(ExclusiveContext* cx, JSObject* objArg, jsid if (shape) UpdatePropertyType(cx, types, obj, shape, false); } - - if (obj->watched()) { - /* - * Mark the property as non-data, to inhibit optimizations on it - * and avoid bypassing the watchpoint handler. - */ - types->setNonDataProperty(cx); - } } void @@ -3622,42 +3614,42 @@ struct DestroyTypeNewScript } // namespace -bool DPAConstraintInfo::finishConstraints(JSContext* cx, ObjectGroup* group) { - for (const ProtoConstraint& constraint : protoConstraints_) { - ObjectGroup* protoGroup = constraint.proto->group(); - - // Note: we rely on the group's type information being unchanged since - // AddClearDefiniteGetterSetterForPrototypeChain. - - bool unknownProperties = protoGroup->unknownProperties(); - MOZ_RELEASE_ASSERT(!unknownProperties); - - HeapTypeSet* protoTypes = - protoGroup->getProperty(cx, constraint.proto, constraint.id); - MOZ_RELEASE_ASSERT(protoTypes); - - MOZ_ASSERT(!protoTypes->nonDataProperty()); - MOZ_ASSERT(!protoTypes->nonWritableProperty()); - - if (!protoTypes->addConstraint( - cx, - cx->typeLifoAlloc().new_( - group))) { - ReportOutOfMemory(cx); - return false; - } - } - - for (const InliningConstraint& constraint : inliningConstraints_) { - if (!AddClearDefiniteFunctionUsesInScript(cx, group, constraint.caller, - constraint.callee)) { - ReportOutOfMemory(cx); - return false; - } - } - - return true; -} +bool DPAConstraintInfo::finishConstraints(JSContext* cx, ObjectGroup* group) { + for (const ProtoConstraint& constraint : protoConstraints_) { + ObjectGroup* protoGroup = constraint.proto->group(); + + // Note: we rely on the group's type information being unchanged since + // AddClearDefiniteGetterSetterForPrototypeChain. + + bool unknownProperties = protoGroup->unknownProperties(); + MOZ_RELEASE_ASSERT(!unknownProperties); + + HeapTypeSet* protoTypes = + protoGroup->getProperty(cx, constraint.proto, constraint.id); + MOZ_RELEASE_ASSERT(protoTypes); + + MOZ_ASSERT(!protoTypes->nonDataProperty()); + MOZ_ASSERT(!protoTypes->nonWritableProperty()); + + if (!protoTypes->addConstraint( + cx, + cx->typeLifoAlloc().new_( + group))) { + ReportOutOfMemory(cx); + return false; + } + } + + for (const InliningConstraint& constraint : inliningConstraints_) { + if (!AddClearDefiniteFunctionUsesInScript(cx, group, constraint.caller, + constraint.callee)) { + ReportOutOfMemory(cx); + return false; + } + } + + return true; +} bool TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate, bool force) @@ -3826,13 +3818,13 @@ TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate, // The definite properties analysis found exactly the properties that // are held in common by the preliminary objects. No further analysis // is needed. - - if (!constraintInfo.finishConstraints(cx, group)) { - return false; - } - if (!group->newScript()) { - return true; - } + + if (!constraintInfo.finishConstraints(cx, group)) { + return false; + } + if (!group->newScript()) { + return true; + } group->addDefiniteProperties(cx, templateObject()->lastProperty()); @@ -3854,16 +3846,16 @@ TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate, initialFlags); if (!initialGroup) return false; - - // Add the constraints. Use the initialGroup as group referenced by the - // constraints because that's the group that will have the TypeNewScript - // associated with it. See the detachNewScript and setNewScript calls below. - if (!constraintInfo.finishConstraints(cx, initialGroup)) { - return false; - } - if (!group->newScript()) { - return true; - } + + // Add the constraints. Use the initialGroup as group referenced by the + // constraints because that's the group that will have the TypeNewScript + // associated with it. See the detachNewScript and setNewScript calls below. + if (!constraintInfo.finishConstraints(cx, initialGroup)) { + return false; + } + if (!group->newScript()) { + return true; + } initialGroup->addDefiniteProperties(cx, templateObject()->lastProperty()); group->addDefiniteProperties(cx, prefixShape); -- cgit v1.2.3 From 24027f0df9d23304709a80c22c6bfdbd27a95046 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sun, 27 Oct 2019 02:14:16 +0100 Subject: Issue #1257 - Part 3: Remove/update tests. This removes a ton of tests that are no longer relevant with (un)watch removed (e.g. testing stability/bugs in the watchpoint system itself which has never been the most stable), and updates others that would previously rely on watch/unwatch, so that they don't unexpectedly fail. --- js/src/jit-test/tests/auto-regress/bug466654.js | 8 -- js/src/jit-test/tests/auto-regress/bug516897.js | 6 -- js/src/jit-test/tests/auto-regress/bug537854.js | 4 - js/src/jit-test/tests/auto-regress/bug560796.js | 9 -- js/src/jit-test/tests/auto-regress/bug638735.js | 1 - js/src/jit-test/tests/auto-regress/bug639413.js | 9 -- js/src/jit-test/tests/auto-regress/bug698899.js | 9 -- js/src/jit-test/tests/auto-regress/bug746397.js | 10 --- js/src/jit-test/tests/auto-regress/bug769192.js | 6 -- js/src/jit-test/tests/baseline/bug843444.js | 8 -- js/src/jit-test/tests/basic/bug510437.js | 13 --- js/src/jit-test/tests/basic/bug605015.js | 9 -- js/src/jit-test/tests/basic/bug631305.js | 9 -- js/src/jit-test/tests/basic/bug662562.js | 6 -- js/src/jit-test/tests/basic/bug690292.js | 12 --- js/src/jit-test/tests/basic/bug696748.js | 3 - js/src/jit-test/tests/basic/bug831846.js | 3 - .../basic/testAssigningWatchedDeletedProperty.js | 7 -- js/src/jit-test/tests/basic/testBug566556.js | 9 -- js/src/jit-test/tests/basic/testBug578044.js | 13 --- js/src/jit-test/tests/basic/testBug584650.js | 9 -- js/src/jit-test/tests/basic/testBug780288-1.js | 20 ----- js/src/jit-test/tests/basic/testBug780288-2.js | 20 ----- .../basic/testEvalCalledFromWatchOverSetter.js | 3 - js/src/jit-test/tests/basic/testNonStubGetter.js | 7 -- .../basic/testSettingWatchPointOnReadOnlyProp.js | 7 -- js/src/jit-test/tests/basic/testTrueShiftTrue.js | 16 ---- js/src/jit-test/tests/basic/testWatchRecursion.js | 63 ------------- js/src/jit-test/tests/gc/bug-900405.js | 3 - js/src/jit-test/tests/gc/bug-913261.js | 5 -- js/src/jit-test/tests/gc/bug-986864.js | 8 -- js/src/jit-test/tests/ion/bug1063182.js | 8 -- js/src/jit-test/tests/ion/bug772901.js | 2 +- js/src/jit-test/tests/ion/bug774257-1.js | 8 -- js/src/jit-test/tests/ion/bug774257-2.js | 10 --- js/src/jit-test/tests/ion/bug779631.js | 9 -- js/src/jit-test/tests/ion/bug783590.js | 1 - js/src/jit-test/tests/jaeger/bug550665.js | 8 -- js/src/jit-test/tests/jaeger/bug557063.js | 7 -- js/src/jit-test/tests/jaeger/bug588338.js | 1 - js/src/jit-test/tests/jaeger/bug625438.js | 10 --- js/src/jit-test/tests/jaeger/bug630366.js | 7 -- .../jit-test/tests/jaeger/recompile/bug641225.js | 1 - js/src/jit-test/tests/pic/fuzz1.js | 4 - js/src/jit-test/tests/pic/fuzz3.js | 3 - js/src/jit-test/tests/pic/watch1.js | 7 -- js/src/jit-test/tests/pic/watch1a.js | 17 ---- js/src/jit-test/tests/pic/watch2.js | 8 -- js/src/jit-test/tests/pic/watch2a.js | 18 ---- js/src/jit-test/tests/pic/watch3.js | 7 -- js/src/jit-test/tests/pic/watch3a.js | 19 ---- js/src/jit-test/tests/pic/watch3b.js | 20 ----- js/src/jit-test/tests/pic/watch4.js | 9 -- js/src/jit-test/tests/pic/watch5.js | 27 ------ js/src/jit-test/tests/profiler/bug1140643.js | 14 --- js/src/tests/ecma_5/Array/frozen-dense-array.js | 19 ---- .../tests/ecma_5/extensions/watch-array-length.js | 41 --------- .../ecma_5/extensions/watch-inherited-property.js | 38 -------- .../ecma_5/extensions/watch-replaced-setter.js | 46 ---------- .../extensions/watch-setter-become-setter.js | 44 --------- .../extensions/watch-value-prop-becoming-setter.js | 43 --------- .../watchpoint-deletes-JSPropertyOp-setter.js | 56 ------------ js/src/tests/js1_5/Object/regress-362872-01.js | 41 --------- js/src/tests/js1_5/Object/regress-362872-02.js | 24 ----- js/src/tests/js1_5/Regress/regress-127243.js | 75 ---------------- js/src/tests/js1_5/Regress/regress-213482.js | 29 ------ js/src/tests/js1_5/Regress/regress-240577.js | 37 -------- js/src/tests/js1_5/Regress/regress-355341.js | 29 ------ js/src/tests/js1_5/Regress/regress-355344.js | 49 ---------- js/src/tests/js1_5/Regress/regress-361467.js | 32 ------- js/src/tests/js1_5/Regress/regress-361617.js | 35 -------- js/src/tests/js1_5/Regress/regress-385393-06.js | 28 ------ js/src/tests/js1_5/Regress/regress-506567.js | 45 ---------- js/src/tests/js1_5/extensions/regress-303277.js | 19 ---- js/src/tests/js1_5/extensions/regress-355339.js | 32 ------- js/src/tests/js1_5/extensions/regress-361346.js | 22 ----- js/src/tests/js1_5/extensions/regress-361360.js | 32 ------- js/src/tests/js1_5/extensions/regress-361552.js | 27 ------ js/src/tests/js1_5/extensions/regress-361558.js | 19 ---- js/src/tests/js1_5/extensions/regress-361571.js | 38 -------- js/src/tests/js1_5/extensions/regress-361856.js | 35 -------- js/src/tests/js1_5/extensions/regress-361964.js | 54 ----------- js/src/tests/js1_5/extensions/regress-385134.js | 38 -------- js/src/tests/js1_5/extensions/regress-385393-09.js | 18 ---- js/src/tests/js1_5/extensions/regress-390597.js | 42 --------- js/src/tests/js1_5/extensions/regress-420612.js | 21 ----- js/src/tests/js1_5/extensions/regress-435345-01.js | 100 --------------------- js/src/tests/js1_5/extensions/regress-454040.js | 25 ------ js/src/tests/js1_5/extensions/regress-454142.js | 30 ------- js/src/tests/js1_5/extensions/regress-455413.js | 24 ----- js/src/tests/js1_5/extensions/regress-465145.js | 24 ----- js/src/tests/js1_5/extensions/regress-472787.js | 31 ------- js/src/tests/js1_5/extensions/regress-488995.js | 46 ---------- js/src/tests/js1_6/Regress/regress-476655.js | 40 --------- js/src/tests/js1_6/extensions/regress-457521.js | 24 ----- js/src/tests/js1_6/extensions/regress-479567.js | 33 ------- js/src/tests/js1_7/extensions/regress-453955.js | 31 ------- js/src/tests/js1_7/extensions/regress-473282.js | 20 ----- js/src/tests/js1_7/regress/regress-385133-01.js | 37 -------- js/src/tests/js1_8/extensions/regress-394709.js | 51 ----------- js/src/tests/js1_8/extensions/regress-481989.js | 19 ---- .../tests/js1_8_1/extensions/regress-452498-193.js | 34 ------- .../tests/js1_8_1/extensions/regress-452498-196.js | 9 -- js/src/tests/js1_8_1/extensions/regress-520572.js | 41 --------- js/src/tests/js1_8_1/regress/regress-452498-160.js | 5 -- .../tests/js1_8_5/extensions/regress-604781-1.js | 24 ----- .../tests/js1_8_5/extensions/regress-604781-2.js | 13 --- .../tests/js1_8_5/extensions/regress-627984-1.js | 16 ---- .../tests/js1_8_5/extensions/regress-627984-2.js | 15 ---- .../tests/js1_8_5/extensions/regress-627984-3.js | 14 --- .../tests/js1_8_5/extensions/regress-627984-4.js | 15 ---- .../tests/js1_8_5/extensions/regress-627984-5.js | 13 --- .../tests/js1_8_5/extensions/regress-627984-6.js | 15 ---- .../tests/js1_8_5/extensions/regress-627984-7.js | 9 -- js/src/tests/js1_8_5/extensions/regress-631723.js | 10 --- js/src/tests/js1_8_5/extensions/regress-636697.js | 11 --- js/src/tests/js1_8_5/extensions/regress-637985.js | 8 -- js/src/tests/js1_8_5/extensions/regress-691746.js | 11 --- .../js1_8_5/extensions/watch-undefined-setter.js | 19 ---- js/src/tests/js1_8_5/regress/regress-533876.js | 23 ----- js/src/tests/js1_8_5/regress/regress-548276.js | 10 --- js/src/tests/js1_8_5/regress/regress-584648.js | 16 ---- js/src/tests/js1_8_5/regress/regress-635195.js | 8 -- js/src/tests/js1_8_5/regress/regress-636394.js | 10 --- 124 files changed, 1 insertion(+), 2531 deletions(-) delete mode 100644 js/src/jit-test/tests/auto-regress/bug466654.js delete mode 100644 js/src/jit-test/tests/auto-regress/bug516897.js delete mode 100644 js/src/jit-test/tests/auto-regress/bug537854.js delete mode 100644 js/src/jit-test/tests/auto-regress/bug560796.js delete mode 100644 js/src/jit-test/tests/auto-regress/bug639413.js delete mode 100644 js/src/jit-test/tests/auto-regress/bug698899.js delete mode 100644 js/src/jit-test/tests/auto-regress/bug746397.js delete mode 100644 js/src/jit-test/tests/auto-regress/bug769192.js delete mode 100644 js/src/jit-test/tests/baseline/bug843444.js delete mode 100644 js/src/jit-test/tests/basic/bug510437.js delete mode 100644 js/src/jit-test/tests/basic/bug605015.js delete mode 100644 js/src/jit-test/tests/basic/bug631305.js delete mode 100644 js/src/jit-test/tests/basic/bug662562.js delete mode 100644 js/src/jit-test/tests/basic/bug690292.js delete mode 100644 js/src/jit-test/tests/basic/bug831846.js delete mode 100644 js/src/jit-test/tests/basic/testAssigningWatchedDeletedProperty.js delete mode 100644 js/src/jit-test/tests/basic/testBug566556.js delete mode 100644 js/src/jit-test/tests/basic/testBug578044.js delete mode 100644 js/src/jit-test/tests/basic/testBug584650.js delete mode 100644 js/src/jit-test/tests/basic/testBug780288-1.js delete mode 100644 js/src/jit-test/tests/basic/testBug780288-2.js delete mode 100644 js/src/jit-test/tests/basic/testEvalCalledFromWatchOverSetter.js delete mode 100644 js/src/jit-test/tests/basic/testNonStubGetter.js delete mode 100644 js/src/jit-test/tests/basic/testSettingWatchPointOnReadOnlyProp.js delete mode 100644 js/src/jit-test/tests/basic/testTrueShiftTrue.js delete mode 100644 js/src/jit-test/tests/basic/testWatchRecursion.js delete mode 100644 js/src/jit-test/tests/gc/bug-900405.js delete mode 100644 js/src/jit-test/tests/gc/bug-913261.js delete mode 100644 js/src/jit-test/tests/gc/bug-986864.js delete mode 100644 js/src/jit-test/tests/ion/bug1063182.js delete mode 100644 js/src/jit-test/tests/ion/bug774257-1.js delete mode 100644 js/src/jit-test/tests/ion/bug774257-2.js delete mode 100644 js/src/jit-test/tests/ion/bug779631.js delete mode 100644 js/src/jit-test/tests/jaeger/bug550665.js delete mode 100644 js/src/jit-test/tests/jaeger/bug557063.js delete mode 100644 js/src/jit-test/tests/jaeger/bug625438.js delete mode 100644 js/src/jit-test/tests/jaeger/bug630366.js delete mode 100644 js/src/jit-test/tests/pic/fuzz1.js delete mode 100644 js/src/jit-test/tests/pic/fuzz3.js delete mode 100644 js/src/jit-test/tests/pic/watch1.js delete mode 100644 js/src/jit-test/tests/pic/watch1a.js delete mode 100644 js/src/jit-test/tests/pic/watch2.js delete mode 100644 js/src/jit-test/tests/pic/watch2a.js delete mode 100644 js/src/jit-test/tests/pic/watch3.js delete mode 100644 js/src/jit-test/tests/pic/watch3a.js delete mode 100644 js/src/jit-test/tests/pic/watch3b.js delete mode 100644 js/src/jit-test/tests/pic/watch4.js delete mode 100644 js/src/jit-test/tests/pic/watch5.js delete mode 100644 js/src/jit-test/tests/profiler/bug1140643.js delete mode 100644 js/src/tests/ecma_5/extensions/watch-array-length.js delete mode 100644 js/src/tests/ecma_5/extensions/watch-inherited-property.js delete mode 100644 js/src/tests/ecma_5/extensions/watch-replaced-setter.js delete mode 100644 js/src/tests/ecma_5/extensions/watch-setter-become-setter.js delete mode 100644 js/src/tests/ecma_5/extensions/watch-value-prop-becoming-setter.js delete mode 100644 js/src/tests/ecma_5/extensions/watchpoint-deletes-JSPropertyOp-setter.js delete mode 100644 js/src/tests/js1_5/Object/regress-362872-01.js delete mode 100644 js/src/tests/js1_5/Object/regress-362872-02.js delete mode 100644 js/src/tests/js1_5/Regress/regress-127243.js delete mode 100644 js/src/tests/js1_5/Regress/regress-213482.js delete mode 100644 js/src/tests/js1_5/Regress/regress-240577.js delete mode 100644 js/src/tests/js1_5/Regress/regress-355341.js delete mode 100644 js/src/tests/js1_5/Regress/regress-355344.js delete mode 100644 js/src/tests/js1_5/Regress/regress-361467.js delete mode 100644 js/src/tests/js1_5/Regress/regress-361617.js delete mode 100644 js/src/tests/js1_5/Regress/regress-385393-06.js delete mode 100644 js/src/tests/js1_5/Regress/regress-506567.js delete mode 100644 js/src/tests/js1_5/extensions/regress-303277.js delete mode 100644 js/src/tests/js1_5/extensions/regress-355339.js delete mode 100644 js/src/tests/js1_5/extensions/regress-361346.js delete mode 100644 js/src/tests/js1_5/extensions/regress-361360.js delete mode 100644 js/src/tests/js1_5/extensions/regress-361552.js delete mode 100644 js/src/tests/js1_5/extensions/regress-361558.js delete mode 100644 js/src/tests/js1_5/extensions/regress-361571.js delete mode 100644 js/src/tests/js1_5/extensions/regress-361856.js delete mode 100644 js/src/tests/js1_5/extensions/regress-361964.js delete mode 100644 js/src/tests/js1_5/extensions/regress-385134.js delete mode 100644 js/src/tests/js1_5/extensions/regress-385393-09.js delete mode 100644 js/src/tests/js1_5/extensions/regress-390597.js delete mode 100644 js/src/tests/js1_5/extensions/regress-420612.js delete mode 100644 js/src/tests/js1_5/extensions/regress-435345-01.js delete mode 100644 js/src/tests/js1_5/extensions/regress-454040.js delete mode 100644 js/src/tests/js1_5/extensions/regress-454142.js delete mode 100644 js/src/tests/js1_5/extensions/regress-455413.js delete mode 100644 js/src/tests/js1_5/extensions/regress-465145.js delete mode 100755 js/src/tests/js1_5/extensions/regress-472787.js delete mode 100644 js/src/tests/js1_5/extensions/regress-488995.js delete mode 100644 js/src/tests/js1_6/Regress/regress-476655.js delete mode 100644 js/src/tests/js1_6/extensions/regress-457521.js delete mode 100644 js/src/tests/js1_6/extensions/regress-479567.js delete mode 100644 js/src/tests/js1_7/extensions/regress-453955.js delete mode 100644 js/src/tests/js1_7/extensions/regress-473282.js delete mode 100644 js/src/tests/js1_7/regress/regress-385133-01.js delete mode 100644 js/src/tests/js1_8/extensions/regress-394709.js delete mode 100644 js/src/tests/js1_8/extensions/regress-481989.js delete mode 100644 js/src/tests/js1_8_1/extensions/regress-452498-193.js delete mode 100644 js/src/tests/js1_8_1/extensions/regress-520572.js delete mode 100644 js/src/tests/js1_8_5/extensions/regress-604781-1.js delete mode 100644 js/src/tests/js1_8_5/extensions/regress-604781-2.js delete mode 100644 js/src/tests/js1_8_5/extensions/regress-627984-1.js delete mode 100644 js/src/tests/js1_8_5/extensions/regress-627984-2.js delete mode 100644 js/src/tests/js1_8_5/extensions/regress-627984-3.js delete mode 100644 js/src/tests/js1_8_5/extensions/regress-627984-4.js delete mode 100644 js/src/tests/js1_8_5/extensions/regress-627984-5.js delete mode 100644 js/src/tests/js1_8_5/extensions/regress-627984-6.js delete mode 100644 js/src/tests/js1_8_5/extensions/regress-627984-7.js delete mode 100644 js/src/tests/js1_8_5/extensions/regress-631723.js delete mode 100644 js/src/tests/js1_8_5/extensions/regress-636697.js delete mode 100644 js/src/tests/js1_8_5/extensions/regress-637985.js delete mode 100644 js/src/tests/js1_8_5/extensions/regress-691746.js delete mode 100644 js/src/tests/js1_8_5/extensions/watch-undefined-setter.js delete mode 100644 js/src/tests/js1_8_5/regress/regress-533876.js delete mode 100644 js/src/tests/js1_8_5/regress/regress-548276.js delete mode 100644 js/src/tests/js1_8_5/regress/regress-584648.js delete mode 100644 js/src/tests/js1_8_5/regress/regress-635195.js delete mode 100644 js/src/tests/js1_8_5/regress/regress-636394.js (limited to 'js/src') diff --git a/js/src/jit-test/tests/auto-regress/bug466654.js b/js/src/jit-test/tests/auto-regress/bug466654.js deleted file mode 100644 index 6c82c425b..000000000 --- a/js/src/jit-test/tests/auto-regress/bug466654.js +++ /dev/null @@ -1,8 +0,0 @@ -// |jit-test| error:TypeError - -// Binary: cache/js-dbg-32-29add08d84ae-linux -// Flags: -j -// -this.watch('y', /x/g ); -for each (y in ['q', 'q', 'q']) continue; -gc(); diff --git a/js/src/jit-test/tests/auto-regress/bug516897.js b/js/src/jit-test/tests/auto-regress/bug516897.js deleted file mode 100644 index e3caf4e6e..000000000 --- a/js/src/jit-test/tests/auto-regress/bug516897.js +++ /dev/null @@ -1,6 +0,0 @@ -// Binary: cache/js-dbg-64-38754465ffde-linux -// Flags: -// -this.__defineSetter__("x", gc); -this.watch("x",function(){return}); -x = 3; diff --git a/js/src/jit-test/tests/auto-regress/bug537854.js b/js/src/jit-test/tests/auto-regress/bug537854.js deleted file mode 100644 index 80fb3c14a..000000000 --- a/js/src/jit-test/tests/auto-regress/bug537854.js +++ /dev/null @@ -1,4 +0,0 @@ -// Binary: cache/js-dbg-64-9d51f2a931f7-linux -// Flags: -// -({x:function(){}}).watch('x',function(){}); diff --git a/js/src/jit-test/tests/auto-regress/bug560796.js b/js/src/jit-test/tests/auto-regress/bug560796.js deleted file mode 100644 index 4ab93567e..000000000 --- a/js/src/jit-test/tests/auto-regress/bug560796.js +++ /dev/null @@ -1,9 +0,0 @@ -// Binary: cache/js-dbg-64-a6d7a5677b4c-linux -// Flags: -// -this.__defineSetter__("x", function(){}) -this.watch("x", "".localeCompare) -window = x -Object.defineProperty(this, "x", ({ - set: window -})) diff --git a/js/src/jit-test/tests/auto-regress/bug638735.js b/js/src/jit-test/tests/auto-regress/bug638735.js index 63071aa7c..c941f5369 100644 --- a/js/src/jit-test/tests/auto-regress/bug638735.js +++ b/js/src/jit-test/tests/auto-regress/bug638735.js @@ -4,7 +4,6 @@ var o9 = Function.prototype; var o13 = Array; function f5(o) { -o.watch('p3', function() {}); ox1 = new Proxy(o, {}); } f5(o9); diff --git a/js/src/jit-test/tests/auto-regress/bug639413.js b/js/src/jit-test/tests/auto-regress/bug639413.js deleted file mode 100644 index d8dd58eaf..000000000 --- a/js/src/jit-test/tests/auto-regress/bug639413.js +++ /dev/null @@ -1,9 +0,0 @@ -// |jit-test| error:TypeError - -// Binary: cache/js-dbg-32-1c8e91b2e3a4-linux -// Flags: -// -a = evalcx("lazy"); -a.watch("x", function() {}); -({}).watch("x", function() {}); -a.__defineGetter__("y", {}); diff --git a/js/src/jit-test/tests/auto-regress/bug698899.js b/js/src/jit-test/tests/auto-regress/bug698899.js deleted file mode 100644 index 644f45ec2..000000000 --- a/js/src/jit-test/tests/auto-regress/bug698899.js +++ /dev/null @@ -1,9 +0,0 @@ -// Binary: cache/js-dbg-32-f951e9151626-linux -// Flags: -m -n -// -o = evalcx("lazy").__proto__ -gc() -try { - o.watch() -} catch (e) {} -o.constructor() diff --git a/js/src/jit-test/tests/auto-regress/bug746397.js b/js/src/jit-test/tests/auto-regress/bug746397.js deleted file mode 100644 index d915ca7bb..000000000 --- a/js/src/jit-test/tests/auto-regress/bug746397.js +++ /dev/null @@ -1,10 +0,0 @@ -// |jit-test| error:ReferenceError - -// Binary: cache/js-dbg-64-67bf9a4a1f77-linux -// Flags: --ion-eager -// - -(function () { - var a = ['x', 'y']; - obj.watch(a[+("0")], counter); -})(); diff --git a/js/src/jit-test/tests/auto-regress/bug769192.js b/js/src/jit-test/tests/auto-regress/bug769192.js deleted file mode 100644 index 531e37912..000000000 --- a/js/src/jit-test/tests/auto-regress/bug769192.js +++ /dev/null @@ -1,6 +0,0 @@ -// |jit-test| error:TypeError - -// Binary: cache/js-dbg-64-bf8f2961d0cc-linux -// Flags: -// -Object.watch.call(new Uint8ClampedArray, "length", function() {}); diff --git a/js/src/jit-test/tests/baseline/bug843444.js b/js/src/jit-test/tests/baseline/bug843444.js deleted file mode 100644 index 3a77402ac..000000000 --- a/js/src/jit-test/tests/baseline/bug843444.js +++ /dev/null @@ -1,8 +0,0 @@ -gczeal(8, 1) -function recurse(x) { - recurse; - if (x < 20) - recurse(x + 1); -}; -this.watch(5, (function () {})) -recurse(0) diff --git a/js/src/jit-test/tests/basic/bug510437.js b/js/src/jit-test/tests/basic/bug510437.js deleted file mode 100644 index 2418b9b11..000000000 --- a/js/src/jit-test/tests/basic/bug510437.js +++ /dev/null @@ -1,13 +0,0 @@ -// Don't crash or assert. - -var d; -this.watch("d", eval); -(function () { - (eval("\ - (function () {\ - for (let x = 0; x < 2; ++x) {\ - d = x\ - }\ - })\ -"))() -})() diff --git a/js/src/jit-test/tests/basic/bug605015.js b/js/src/jit-test/tests/basic/bug605015.js deleted file mode 100644 index a35f7b6c7..000000000 --- a/js/src/jit-test/tests/basic/bug605015.js +++ /dev/null @@ -1,9 +0,0 @@ -// |jit-test| error: TypeError -// don't assert - -print(this.watch("x", -function() { - Object.defineProperty(this, "x", ({ - get: (Int8Array) - })) -}))(x = /x/) diff --git a/js/src/jit-test/tests/basic/bug631305.js b/js/src/jit-test/tests/basic/bug631305.js deleted file mode 100644 index b0cbbbb24..000000000 --- a/js/src/jit-test/tests/basic/bug631305.js +++ /dev/null @@ -1,9 +0,0 @@ -var n = 0; -var a = []; -for (var i = 0; i < 20; i++) - a[i] = {}; -a[18].watch("p", function () { n++; }); -delete a[18].p; -for (var i = 0; i < 20; i++) - a[i].p = 0; -assertEq(n, 1); diff --git a/js/src/jit-test/tests/basic/bug662562.js b/js/src/jit-test/tests/basic/bug662562.js deleted file mode 100644 index 45b48589a..000000000 --- a/js/src/jit-test/tests/basic/bug662562.js +++ /dev/null @@ -1,6 +0,0 @@ -// |jit-test| error: TypeError -function f(o) { - o.watch("x", this); -} -var c = evalcx(""); -f(c); diff --git a/js/src/jit-test/tests/basic/bug690292.js b/js/src/jit-test/tests/basic/bug690292.js deleted file mode 100644 index 43ab56dd7..000000000 --- a/js/src/jit-test/tests/basic/bug690292.js +++ /dev/null @@ -1,12 +0,0 @@ - -done = false; -try { - function x() {} - print(this.watch("d", Object.create)) - var d = {} -} catch (e) {} -try { - eval("d = ''") - done = true; -} catch (e) {} -assertEq(done, false); diff --git a/js/src/jit-test/tests/basic/bug696748.js b/js/src/jit-test/tests/basic/bug696748.js index fe171f976..33fb4d52f 100644 --- a/js/src/jit-test/tests/basic/bug696748.js +++ b/js/src/jit-test/tests/basic/bug696748.js @@ -1,6 +1,3 @@ -try { -this.watch("b", "".substring); -} catch(exc1) {} eval("\ var URI = '';\ test();\ diff --git a/js/src/jit-test/tests/basic/bug831846.js b/js/src/jit-test/tests/basic/bug831846.js deleted file mode 100644 index 30bb3aa86..000000000 --- a/js/src/jit-test/tests/basic/bug831846.js +++ /dev/null @@ -1,3 +0,0 @@ -// |jit-test| error:TypeError - -evalcx('').watch("", /()/); diff --git a/js/src/jit-test/tests/basic/testAssigningWatchedDeletedProperty.js b/js/src/jit-test/tests/basic/testAssigningWatchedDeletedProperty.js deleted file mode 100644 index c22eabed0..000000000 --- a/js/src/jit-test/tests/basic/testAssigningWatchedDeletedProperty.js +++ /dev/null @@ -1,7 +0,0 @@ -var o = {}; -o.watch("p", function() { }); - -for (var i = 0; i < 10; i++) { - o.p = 123; - delete o.p; -} diff --git a/js/src/jit-test/tests/basic/testBug566556.js b/js/src/jit-test/tests/basic/testBug566556.js deleted file mode 100644 index 244be57d2..000000000 --- a/js/src/jit-test/tests/basic/testBug566556.js +++ /dev/null @@ -1,9 +0,0 @@ -var msg = ""; -try { - this.__defineSetter__('x', Object.create); - this.watch('x', function() {}); - x = 3; -} catch (e) { - msg = e.toString(); -} -assertEq(msg, "TypeError: undefined is not an object or null"); diff --git a/js/src/jit-test/tests/basic/testBug578044.js b/js/src/jit-test/tests/basic/testBug578044.js deleted file mode 100644 index c5b811dc9..000000000 --- a/js/src/jit-test/tests/basic/testBug578044.js +++ /dev/null @@ -1,13 +0,0 @@ -this.watch("x", Object.create) -try { - (function() { - this.__defineGetter__("x", - function() { - return this - }) - })() -} catch(e) {} -Object.defineProperty(x, "x", ({ - set: Uint16Array -})) - diff --git a/js/src/jit-test/tests/basic/testBug584650.js b/js/src/jit-test/tests/basic/testBug584650.js deleted file mode 100644 index b6c9d8ab7..000000000 --- a/js/src/jit-test/tests/basic/testBug584650.js +++ /dev/null @@ -1,9 +0,0 @@ -if (typeof gczeal != "function") - gczeal = function() {} - -// don't crash -x = (evalcx('lazy')) -x.watch("", function () {}) -gczeal(1) -for (w in x) {} - diff --git a/js/src/jit-test/tests/basic/testBug780288-1.js b/js/src/jit-test/tests/basic/testBug780288-1.js deleted file mode 100644 index 90746a04a..000000000 --- a/js/src/jit-test/tests/basic/testBug780288-1.js +++ /dev/null @@ -1,20 +0,0 @@ -s = newGlobal() -try { - evalcx("\ - Object.defineProperty(this,\"i\",{enumerable:true,get:function(){t}});\ - for each(y in this)true\ - ", s) -} catch (e) {} -try { - evalcx("\ - for(z=0,(7).watch(\"\",eval);;g){\ - if(z=1){({t:function(){}})\ - }\ - ", s) -} catch (e) {} -try { - evalcx("\ - Object.defineProperty(this,\"g2\",{get:function(){return this}});\ - g2.y()\ - ", s) -} catch (e) {} diff --git a/js/src/jit-test/tests/basic/testBug780288-2.js b/js/src/jit-test/tests/basic/testBug780288-2.js deleted file mode 100644 index 8c4c1737c..000000000 --- a/js/src/jit-test/tests/basic/testBug780288-2.js +++ /dev/null @@ -1,20 +0,0 @@ -s = newGlobal() -try { - evalcx("\ - Object.defineProperty(this,\"i\",{enumerable:true,get:function(){t}});\ - for each(y in this)true\ - ", s) -} catch (e) {} -try { - evalcx("\ - for(z=0,(7).watch(\"\",eval);;g){\ - if(z=1){({t:function(){}})\ - }\ - ", s) -} catch (e) {} -try { - evalcx("\ - Object.defineProperty(this,\"g2\",{get:function(){return this}});\ - g2.y(\"\")\ - ", s) -} catch (e) {} diff --git a/js/src/jit-test/tests/basic/testEvalCalledFromWatchOverSetter.js b/js/src/jit-test/tests/basic/testEvalCalledFromWatchOverSetter.js deleted file mode 100644 index bcd60fd80..000000000 --- a/js/src/jit-test/tests/basic/testEvalCalledFromWatchOverSetter.js +++ /dev/null @@ -1,3 +0,0 @@ -this.__defineSetter__("x", function(){}); -this.watch("x", eval); -x = 0; diff --git a/js/src/jit-test/tests/basic/testNonStubGetter.js b/js/src/jit-test/tests/basic/testNonStubGetter.js deleted file mode 100644 index 58a698eb4..000000000 --- a/js/src/jit-test/tests/basic/testNonStubGetter.js +++ /dev/null @@ -1,7 +0,0 @@ -function testNonStubGetter() { - { let [] = []; (this.watch("x", function(p, o, n) { return /a/g.exec(p, o, n); })); }; - (function () { (eval("(function(){for each (x in [1, 2, 2]);});"))(); })(); - this.unwatch("x"); - return "ok"; -} -assertEq(testNonStubGetter(), "ok"); diff --git a/js/src/jit-test/tests/basic/testSettingWatchPointOnReadOnlyProp.js b/js/src/jit-test/tests/basic/testSettingWatchPointOnReadOnlyProp.js deleted file mode 100644 index 78c281f05..000000000 --- a/js/src/jit-test/tests/basic/testSettingWatchPointOnReadOnlyProp.js +++ /dev/null @@ -1,7 +0,0 @@ -for (var i = 0; i < 5; ++i) { - var o = {} - Object.defineProperty(o, 'x', { value:"cow", writable:false }); - var r = o.watch('x', function() {}); - assertEq(r, undefined); - o.x = 4; -} diff --git a/js/src/jit-test/tests/basic/testTrueShiftTrue.js b/js/src/jit-test/tests/basic/testTrueShiftTrue.js deleted file mode 100644 index 44c1290d8..000000000 --- a/js/src/jit-test/tests/basic/testTrueShiftTrue.js +++ /dev/null @@ -1,16 +0,0 @@ -// Test no assert or crash from outer recorders (bug 465145) -function testBug465145() { - this.__defineSetter__("x", function(){}); - this.watch("x", function(){}); - y = this; - for (var z = 0; z < 2; ++z) { x = y }; - this.__defineSetter__("x", function(){}); - for (var z = 0; z < 2; ++z) { x = y }; -} - -function testTrueShiftTrue() { - var a = new Array(5); - for (var i=0;i<5;++i) a[i] = "" + (true << true); - return a.join(","); -} -assertEq(testTrueShiftTrue(), "2,2,2,2,2"); diff --git a/js/src/jit-test/tests/basic/testWatchRecursion.js b/js/src/jit-test/tests/basic/testWatchRecursion.js deleted file mode 100644 index e5d5877df..000000000 --- a/js/src/jit-test/tests/basic/testWatchRecursion.js +++ /dev/null @@ -1,63 +0,0 @@ -// Test that the watch handler is not called recursively for the same object -// and property. -(function() { - var obj1 = {}, obj2 = {}; - var handler_entry_count = 0; - var handler_exit_count = 0; - - obj1.watch('x', handler); - obj1.watch('y', handler); - obj2.watch('x', handler); - obj1.x = 1; - assertEq(handler_entry_count, 3); - assertEq(handler_exit_count, 3); - - function handler(id) { - handler_entry_count++; - assertEq(handler_exit_count, 0); - switch (true) { - case this === obj1 && id === "x": - assertEq(handler_entry_count, 1); - obj2.x = 3; - assertEq(handler_exit_count, 2); - break; - case this === obj2 && id === "x": - assertEq(handler_entry_count, 2); - obj1.y = 4; - assertEq(handler_exit_count, 1); - break; - default: - assertEq(this, obj1); - assertEq(id, "y"); - assertEq(handler_entry_count, 3); - - // We expect no more watch handler invocations - obj1.x = 5; - obj1.y = 6; - obj2.x = 7; - assertEq(handler_exit_count, 0); - break; - } - ++handler_exit_count; - assertEq(handler_entry_count, 3); - } -})(); - - -// Test that run-away recursion in watch handlers is properly handled. -(function() { - var obj = {}; - var i = 0; - try { - handler(); - throw new Error("Unreachable"); - } catch(e) { - assertEq(e instanceof InternalError, true); - } - - function handler() { - var prop = "a" + ++i; - obj.watch(prop, handler); - obj[prop] = 2; - } -})(); diff --git a/js/src/jit-test/tests/gc/bug-900405.js b/js/src/jit-test/tests/gc/bug-900405.js deleted file mode 100644 index eeec6f25f..000000000 --- a/js/src/jit-test/tests/gc/bug-900405.js +++ /dev/null @@ -1,3 +0,0 @@ -(function() { - [{ "9": [] }.watch([], function(){})] -})() diff --git a/js/src/jit-test/tests/gc/bug-913261.js b/js/src/jit-test/tests/gc/bug-913261.js deleted file mode 100644 index 43066053f..000000000 --- a/js/src/jit-test/tests/gc/bug-913261.js +++ /dev/null @@ -1,5 +0,0 @@ -// |jit-test| error: InternalError: too much recursion -(function f() { - "".watch(2, function() {}); - f(); -})() diff --git a/js/src/jit-test/tests/gc/bug-986864.js b/js/src/jit-test/tests/gc/bug-986864.js deleted file mode 100644 index abb8de6b2..000000000 --- a/js/src/jit-test/tests/gc/bug-986864.js +++ /dev/null @@ -1,8 +0,0 @@ -// |jit-test| slow -function x() {} -for (var j = 0; j < 9999; ++j) { - (function() { - x += x.watch("endsWith", ArrayBuffer); - return 0 >> Function(x) - })() -} diff --git a/js/src/jit-test/tests/ion/bug1063182.js b/js/src/jit-test/tests/ion/bug1063182.js deleted file mode 100644 index 9cda48099..000000000 --- a/js/src/jit-test/tests/ion/bug1063182.js +++ /dev/null @@ -1,8 +0,0 @@ -// |jit-test| error: ReferenceError - -eval("(function() { " + "\ -var o = {};\ -o.watch('p', function() { });\ -for (var i = 0; i < 10; \u5ede ++)\ - o.p = 123;\ -" + " })();"); diff --git a/js/src/jit-test/tests/ion/bug772901.js b/js/src/jit-test/tests/ion/bug772901.js index eb71f6afb..164afd151 100644 --- a/js/src/jit-test/tests/ion/bug772901.js +++ b/js/src/jit-test/tests/ion/bug772901.js @@ -4,4 +4,4 @@ function f(x) { delete ((x)++); arguments[0] !== undefined; } -f(1, x = [f.ArrayBuffer,unwatch.Int32Array], this, this, this) ; +f(1, x = [f.ArrayBuffer, undefined], this, this, this) ; diff --git a/js/src/jit-test/tests/ion/bug774257-1.js b/js/src/jit-test/tests/ion/bug774257-1.js deleted file mode 100644 index 9c998a028..000000000 --- a/js/src/jit-test/tests/ion/bug774257-1.js +++ /dev/null @@ -1,8 +0,0 @@ -Object.defineProperty(Object.prototype, 'x', { - set: function() { evalcx('lazy'); } -}); -var obj = {}; -obj.watch("x", function (id, oldval, newval) {}); -for (var str in 'A') { - obj.x = 1; -} diff --git a/js/src/jit-test/tests/ion/bug774257-2.js b/js/src/jit-test/tests/ion/bug774257-2.js deleted file mode 100644 index b31043b08..000000000 --- a/js/src/jit-test/tests/ion/bug774257-2.js +++ /dev/null @@ -1,10 +0,0 @@ -Object.defineProperty(Object.prototype, 'x', { - set: function() { evalcx('lazy'); } -}); -var obj = {}; -var prot = {}; -obj.__proto__ = prot; -obj.watch("x", function (id, oldval, newval) {}); -for (var str in 'A') { - obj.x = 1; -} diff --git a/js/src/jit-test/tests/ion/bug779631.js b/js/src/jit-test/tests/ion/bug779631.js deleted file mode 100644 index 087aa01ac..000000000 --- a/js/src/jit-test/tests/ion/bug779631.js +++ /dev/null @@ -1,9 +0,0 @@ -var flag = 0; -var a = {}; -Object.defineProperty(a, "value", {set: function(x) {}}); -a.watch("value", function(){flag++;}); - -for(var i = 0; i < 100; i++) { - a.value = i; - assertEq(flag, i+1); -} diff --git a/js/src/jit-test/tests/ion/bug783590.js b/js/src/jit-test/tests/ion/bug783590.js index d48cb609e..9d277e02c 100644 --- a/js/src/jit-test/tests/ion/bug783590.js +++ b/js/src/jit-test/tests/ion/bug783590.js @@ -7,7 +7,6 @@ Object.defineProperty(arr, 0, { glob.__proto__; }) }); -this.watch("s", function() {}); try { arr.pop(); } catch (e) {} diff --git a/js/src/jit-test/tests/jaeger/bug550665.js b/js/src/jit-test/tests/jaeger/bug550665.js deleted file mode 100644 index 816888b5e..000000000 --- a/js/src/jit-test/tests/jaeger/bug550665.js +++ /dev/null @@ -1,8 +0,0 @@ -(function () { - var a; - eval("for(w in ((function(x,y){b:0})())) ;"); -})(); - -this.__defineSetter__("l", function() { gc() }); -this.watch("l", function(x) { yield {} }); -l = true; diff --git a/js/src/jit-test/tests/jaeger/bug557063.js b/js/src/jit-test/tests/jaeger/bug557063.js deleted file mode 100644 index ea77fd2c8..000000000 --- a/js/src/jit-test/tests/jaeger/bug557063.js +++ /dev/null @@ -1,7 +0,0 @@ -(function() { - for (a = 0; a < 2; a++) - ''.watch("", function() {}) -})() - -/* Don't crash or assert. */ - diff --git a/js/src/jit-test/tests/jaeger/bug588338.js b/js/src/jit-test/tests/jaeger/bug588338.js index 457be238a..c400d7687 100644 --- a/js/src/jit-test/tests/jaeger/bug588338.js +++ b/js/src/jit-test/tests/jaeger/bug588338.js @@ -9,7 +9,6 @@ function f() { } } })(/x/))) -for (z = 0; z < 100; x.unwatch(), z++) for (e in [0]) { gczeal(2) } ( [1,2,3])("") diff --git a/js/src/jit-test/tests/jaeger/bug625438.js b/js/src/jit-test/tests/jaeger/bug625438.js deleted file mode 100644 index 32586d8ab..000000000 --- a/js/src/jit-test/tests/jaeger/bug625438.js +++ /dev/null @@ -1,10 +0,0 @@ -// vim: set ts=8 sts=4 et sw=4 tw=99: - -var count = 0; -this.watch("x", function() { - count++; -}); -for(var i=0; i<10; i++) { - x = 2; -} -assertEq(count, 10); diff --git a/js/src/jit-test/tests/jaeger/bug630366.js b/js/src/jit-test/tests/jaeger/bug630366.js deleted file mode 100644 index acac8d3ef..000000000 --- a/js/src/jit-test/tests/jaeger/bug630366.js +++ /dev/null @@ -1,7 +0,0 @@ -var o = {}; -for(var i=0; i<5; i++) { - o.p = 2; - o.watch("p", function() { }); - o.p = 2; - delete o.p; -} diff --git a/js/src/jit-test/tests/jaeger/recompile/bug641225.js b/js/src/jit-test/tests/jaeger/recompile/bug641225.js index a6e3a86c7..7b7978197 100644 --- a/js/src/jit-test/tests/jaeger/recompile/bug641225.js +++ b/js/src/jit-test/tests/jaeger/recompile/bug641225.js @@ -118,7 +118,6 @@ for(var o2 in f5) { f2(o5); f2(o5); f0(o3); - o9.watch('p3', function() {}); o8[o8] = o8; f0(o5); f1(o6); diff --git a/js/src/jit-test/tests/pic/fuzz1.js b/js/src/jit-test/tests/pic/fuzz1.js deleted file mode 100644 index 2481a1314..000000000 --- a/js/src/jit-test/tests/pic/fuzz1.js +++ /dev/null @@ -1,4 +0,0 @@ -(function() { - for (a = 0; a < 2; a++) - ''.watch("", function() {}) -})() diff --git a/js/src/jit-test/tests/pic/fuzz3.js b/js/src/jit-test/tests/pic/fuzz3.js deleted file mode 100644 index 17613b6f5..000000000 --- a/js/src/jit-test/tests/pic/fuzz3.js +++ /dev/null @@ -1,3 +0,0 @@ -for each(let w in [[], 0, [], 0]) { - w.unwatch() -} diff --git a/js/src/jit-test/tests/pic/watch1.js b/js/src/jit-test/tests/pic/watch1.js deleted file mode 100644 index 09d6347bf..000000000 --- a/js/src/jit-test/tests/pic/watch1.js +++ /dev/null @@ -1,7 +0,0 @@ -// assignments to watched objects must not be cached -var obj = {x: 0}; -var hits = 0; -obj.watch("x", function (id, oldval, newval) { hits++; return newval; }); -for (var i = 0; i < 10; i++) - obj.x = i; -assertEq(hits, 10); diff --git a/js/src/jit-test/tests/pic/watch1a.js b/js/src/jit-test/tests/pic/watch1a.js deleted file mode 100644 index 4b404f507..000000000 --- a/js/src/jit-test/tests/pic/watch1a.js +++ /dev/null @@ -1,17 +0,0 @@ -// assignments to watched objects must not be traced -var hits = 0; -function counter(id, oldval, newval) { - hits++; - return newval; -} - -(function () { - var obj = {x: 0, y: 0}; - var a = ['x', 'y']; - obj.watch('z', counter); - for (var i = 0; i < 14; i++) { - obj.watch(a[+(i > 8)], counter); - obj.y = i; - } -})(); -assertEq(hits, 5); diff --git a/js/src/jit-test/tests/pic/watch2.js b/js/src/jit-test/tests/pic/watch2.js deleted file mode 100644 index fb3e29617..000000000 --- a/js/src/jit-test/tests/pic/watch2.js +++ /dev/null @@ -1,8 +0,0 @@ -// assignments to watched properties via ++ must not be cached -var obj = {x: 0}; -var hits = 0; -obj.watch("x", function (id, oldval, newval) { hits++; return newval; }); -for (var i = 0; i < 10; i++) - obj.x++; -assertEq(hits, 10); - diff --git a/js/src/jit-test/tests/pic/watch2a.js b/js/src/jit-test/tests/pic/watch2a.js deleted file mode 100644 index ce3294ba3..000000000 --- a/js/src/jit-test/tests/pic/watch2a.js +++ /dev/null @@ -1,18 +0,0 @@ -// assignments to watched properties via ++ must not be traced -var hits = 0; -function counter(id, oldval, newval) { - hits++; - return newval; -} - -(function () { - var obj = {x: 0, y: 0}; - var a = ['x', 'y']; - obj.watch('z', counter); - for (var i = 0; i < 14; i++) { - obj.watch(a[+(i > 8)], counter); - obj.y++; - } -})(); -assertEq(hits, 5); - diff --git a/js/src/jit-test/tests/pic/watch3.js b/js/src/jit-test/tests/pic/watch3.js deleted file mode 100644 index 4c5c93d8b..000000000 --- a/js/src/jit-test/tests/pic/watch3.js +++ /dev/null @@ -1,7 +0,0 @@ -// assignment to watched global properties must not be cached -x = 0; -var hits = 0; -this.watch("x", function (id, oldval, newval) { hits++; return newval; }); -for (var i = 0; i < 10; i++) - x = i; -assertEq(hits, 10); diff --git a/js/src/jit-test/tests/pic/watch3a.js b/js/src/jit-test/tests/pic/watch3a.js deleted file mode 100644 index 700daf6af..000000000 --- a/js/src/jit-test/tests/pic/watch3a.js +++ /dev/null @@ -1,19 +0,0 @@ -// assignment to watched global properties must not be traced -var hits = 0; -function counter(id, oldval, newval) { - hits++; - return newval; -} - -var x = 0; -var y = 0; -(function () { - var a = ['x', 'y']; - this.watch('z', counter); - for (var i = 0; i < 14; i++) { - this.watch(a[+(i > 8)], counter); - y = 1; - } -})(); -assertEq(hits, 5); - diff --git a/js/src/jit-test/tests/pic/watch3b.js b/js/src/jit-test/tests/pic/watch3b.js deleted file mode 100644 index 9b0dc8cc9..000000000 --- a/js/src/jit-test/tests/pic/watch3b.js +++ /dev/null @@ -1,20 +0,0 @@ -// assignment to watched global properties must not be traced -var hits = 0; -function counter(id, oldval, newval) { - hits++; - return newval; -} - -var x = 0; -var y = 0; -function f() { - var a = [{}, this]; - for (var i = 0; i < 14; i++) { - print(shapeOf(this)); - Object.prototype.watch.call(a[+(i > 8)], "y", counter); - y++; - } -} -f(); -assertEq(hits, 5); - diff --git a/js/src/jit-test/tests/pic/watch4.js b/js/src/jit-test/tests/pic/watch4.js deleted file mode 100644 index 4b640c4df..000000000 --- a/js/src/jit-test/tests/pic/watch4.js +++ /dev/null @@ -1,9 +0,0 @@ -// adding assignment + watchpoint vs. caching -var hits = 0; -var obj = {}; -obj.watch("x", function (id, oldval, newval) { hits++; return newval; }); -for (var i = 0; i < 10; i++) { - obj.x = 1; - delete obj.x; -} -assertEq(hits, 10); diff --git a/js/src/jit-test/tests/pic/watch5.js b/js/src/jit-test/tests/pic/watch5.js deleted file mode 100644 index 6b22951a4..000000000 --- a/js/src/jit-test/tests/pic/watch5.js +++ /dev/null @@ -1,27 +0,0 @@ -// test against future pic support for symbols - -// assignments to watched objects must not be cached -var obj = {}; -var x = Symbol.for("x"); -obj[x] = 0; -var hits = 0; -obj.watch(x, function (id, oldval, newval) { hits++; return newval; }); -for (var i = 0; i < 10; i++) - obj[x] = i; -assertEq(hits, 10); - -// assignments to watched properties via ++ must not be cached -hits = 0; -for (var i = 0; i < 10; i++) - obj[x]++; -assertEq(hits, 10); - -// adding assignment + watchpoint vs. caching -hits = 0; -obj = {}; -obj.watch(x, function (id, oldval, newval) { hits++; return newval; }); -for (var i = 0; i < 10; i++) { - obj[x] = 1; - delete obj[x]; -} -assertEq(hits, 10); diff --git a/js/src/jit-test/tests/profiler/bug1140643.js b/js/src/jit-test/tests/profiler/bug1140643.js deleted file mode 100644 index 1b171aea2..000000000 --- a/js/src/jit-test/tests/profiler/bug1140643.js +++ /dev/null @@ -1,14 +0,0 @@ -// |jit-test| allow-oom -enableSPSProfiling(); -loadFile('\ -for (var i = 0; i < 2; i++) {\ - obj = { m: function () {} };\ - obj.watch("m", function () { float32 = 0 + obj.foo; });\ - obj.m = 0;\ -}\ -'); -gcparam("maxBytes", gcparam("gcBytes") + (1)*1024); -newGlobal("same-compartment"); -function loadFile(lfVarx) { - evaluate(lfVarx, { noScriptRval : true, isRunOnce : true }); -} diff --git a/js/src/tests/ecma_5/Array/frozen-dense-array.js b/js/src/tests/ecma_5/Array/frozen-dense-array.js index 9db63036f..cdb86daa3 100644 --- a/js/src/tests/ecma_5/Array/frozen-dense-array.js +++ b/js/src/tests/ecma_5/Array/frozen-dense-array.js @@ -38,24 +38,5 @@ assertEq(delete a[0], false); assertArrayIsExpected(); -var watchpointCalled = false; -// NOTE: Be careful with the position of this test, since this sparsifies the -// elements and you might not test what you think you're testing otherwise. -a.watch(2, function(prop, oldValue, newValue) { - watchpointCalled = true; - assertEq(prop, 2); - assertEq(oldValue, 1); - assertEq(newValue, "foo"); -}); - -assertArrayIsExpected(); - -a.length = 5; -a[2] = "foo"; -assertEq(watchpointCalled, true); -assertEq(delete a[0], false); - -assertArrayIsExpected(); - if (typeof reportCompare === "function") reportCompare(true, true); diff --git a/js/src/tests/ecma_5/extensions/watch-array-length.js b/js/src/tests/ecma_5/extensions/watch-array-length.js deleted file mode 100644 index e9b356efa..000000000 --- a/js/src/tests/ecma_5/extensions/watch-array-length.js +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/licenses/publicdomain/ - */ - -var hitCount; -function watcher(p,o,n) { hitCount++; return n; } - -var a = [1]; -a.watch('length', watcher); -hitCount = 0; -a.length = 0; -reportCompare(1, hitCount, "lenient; configurable: watchpoint hit"); - -var b = Object.defineProperty([1],'0',{configurable:false}); -b.watch('length', watcher); -hitCount = 0; -var result; -try { - b.length = 0; - result = "no error"; -} catch (x) { - result = x.toString(); -} -reportCompare(1, hitCount, "lenient; non-configurable: watchpoint hit"); -reportCompare(1, b.length, "lenient; non-configurable: length unchanged"); -reportCompare("no error", result, "lenient; non-configurable: no error thrown"); - -var c = Object.defineProperty([1],'0',{configurable:false}); -c.watch('length', watcher); -hitCount = 0; -var threwTypeError; -try { - (function(){'use strict'; c.length = 0;})(); - threwTypeError = false; -} catch (x) { - threwTypeError = x instanceof TypeError; -} -reportCompare(1, hitCount, "strict; non-configurable: watchpoint hit"); -reportCompare(1, c.length, "strict; non-configurable: length unchanged"); -reportCompare(true, threwTypeError, "strict; non-configurable: TypeError thrown"); diff --git a/js/src/tests/ecma_5/extensions/watch-inherited-property.js b/js/src/tests/ecma_5/extensions/watch-inherited-property.js deleted file mode 100644 index 1a0ad566b..000000000 --- a/js/src/tests/ecma_5/extensions/watch-inherited-property.js +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/licenses/publicdomain/ - */ - -/* Create a prototype object with a setter property. */ -var protoSetterCount; -var proto = ({ set x(v) { protoSetterCount++; } }); - -/* Put a watchpoint on that setter. */ -var protoWatchCount; -proto.watch('x', function() { protoWatchCount++; }); - -/* Make an object with the above as its prototype. */ -function C() { } -C.prototype = proto; -var o = new C(); - -/* - * Set a watchpoint on the property in the inheriting object. We have - * defined this to mean "duplicate the property, setter and all, in the - * inheriting object." I don't think debugging observation mechanisms - * should mutate the program being run, but that's what we've got. - */ -var oWatchCount; -o.watch('x', function() { oWatchCount++; }); - -/* - * Assign to the property. This should trip the watchpoint on the inheriting object and - * the setter. - */ -protoSetterCount = protoWatchCount = oWatchCount = 0; -o.x = 1; -assertEq(protoWatchCount, 0); -assertEq(oWatchCount, 1); -assertEq(protoSetterCount, 1); - -reportCompare(true, true); diff --git a/js/src/tests/ecma_5/extensions/watch-replaced-setter.js b/js/src/tests/ecma_5/extensions/watch-replaced-setter.js deleted file mode 100644 index 05cf60aff..000000000 --- a/js/src/tests/ecma_5/extensions/watch-replaced-setter.js +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/licenses/publicdomain/ - */ - -/* A stock watcher function. */ -var watcherCount; -function watcher(id, oldval, newval) { watcherCount++; return newval; } - -/* Create an object with a JavaScript setter. */ -var setterCount; -var o = { w:2, set x(v) { setterCount++; } }; - -/* - * Put the object in dictionary mode, so that JSObject::putProperty will - * mutate its shapes instead of creating new ones. - */ -delete o.w; - -/* - * Place a watchpoint on the property. The watchpoint structure holds the - * original JavaScript setter, and a pointer to the shape. - */ -o.watch('x', watcher); - -/* - * Replace the accessor property with a value property. The shape's setter - * should become a non-JS setter, js_watch_set, and the watchpoint - * structure's saved setter should be updated (in this case, cleared). - */ -Object.defineProperty(o, 'x', { value:3, - writable:true, - enumerable:true, - configurable:true }); - -/* - * Assign to the property. This should trigger js_watch_set, which should - * call the handler, and then see that there is no JS-level setter to pass - * control on to, and return. - */ -watcherCount = setterCount = 0; -o.x = 3; -assertEq(watcherCount, 1); -assertEq(setterCount, 0); - -reportCompare(true, true); diff --git a/js/src/tests/ecma_5/extensions/watch-setter-become-setter.js b/js/src/tests/ecma_5/extensions/watch-setter-become-setter.js deleted file mode 100644 index f5eff98b8..000000000 --- a/js/src/tests/ecma_5/extensions/watch-setter-become-setter.js +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/licenses/publicdomain/ - */ - -/* Create an object with a JavaScript setter. */ -var firstSetterCount; -var o = { w:2, set x(v) { firstSetterCount++; } }; - -/* - * Put the object in dictionary mode, so that JSObject::putProperty will - * mutate its shapes instead of creating new ones. - */ -delete o.w; - -/* A stock watcher function. */ -var watcherCount; -function watcher(id, oldval, newval) { watcherCount++; return newval; } - -/* - * Place a watchpoint on the property. The property's shape now has the - * watchpoint setter, with the original setter saved in the watchpoint - * structure. - */ -o.watch('x', watcher); - -/* - * Replace the setter with a new setter. The shape should get updated to - * refer to the new setter, and then the watchpoint setter should be - * re-established. - */ -var secondSetterCount; -Object.defineProperty(o, 'x', { set: function () { secondSetterCount++ } }); - -/* - * Assign to the property. This should trigger the watchpoint and the new setter. - */ -watcherCount = firstSetterCount = secondSetterCount = 0; -o.x = 3; -assertEq(watcherCount, 1); -assertEq(firstSetterCount, 0); -assertEq(secondSetterCount, 1); - -reportCompare(true, true); diff --git a/js/src/tests/ecma_5/extensions/watch-value-prop-becoming-setter.js b/js/src/tests/ecma_5/extensions/watch-value-prop-becoming-setter.js deleted file mode 100644 index 03cdd788e..000000000 --- a/js/src/tests/ecma_5/extensions/watch-value-prop-becoming-setter.js +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/licenses/publicdomain/ - */ - -/* A stock watcher function. */ -var watcherCount; -function watcher(id, old, newval) { - watcherCount++; - return newval; -} - -/* Create an object with a value property. */ -var o = { w:2, x:3 }; - -/* - * Place a watchpoint on the value property. The watchpoint structure holds - * the original JavaScript setter, and a pointer to the shape. - */ -o.watch('x', watcher); - -/* - * Put the object in dictionary mode, so that JSObject::putProperty will - * mutate its shapes instead of creating new ones. - */ -delete o.w; - -/* - * Replace the value property with a setter. - */ -var setterCount; -o.__defineSetter__('x', function() { setterCount++; }); - -/* - * Trigger the watchpoint. The watchpoint handler should run, and then the - * setter should run. - */ -watcherCount = setterCount = 0; -o.x = 4; -assertEq(watcherCount, 1); -assertEq(setterCount, 1); - -reportCompare(true, true); diff --git a/js/src/tests/ecma_5/extensions/watchpoint-deletes-JSPropertyOp-setter.js b/js/src/tests/ecma_5/extensions/watchpoint-deletes-JSPropertyOp-setter.js deleted file mode 100644 index 85410bbd4..000000000 --- a/js/src/tests/ecma_5/extensions/watchpoint-deletes-JSPropertyOp-setter.js +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/licenses/publicdomain/ - */ - -function make_watcher(name) { - return function (id, oldv, newv) { - print("watched " + name + "[0]"); - }; -} - -var o, p; -function f(flag) { - if (flag) { - o = arguments; - } else { - p = arguments; - o.watch(0, make_watcher('o')); - p.watch(0, make_watcher('p')); - - /* - * Previously, the watchpoint implementation actually substituted its magic setter - * functions for the setters of shared shapes, and then 1) carefully ignored calls - * to its magic setter from unrelated objects, and 2) avoided restoring the - * original setter until all watchpoints on that shape had been removed. - * - * However, when the watchpoint code began using JSObject::changeProperty and - * js_ChangeNativePropertyAttrs to change shapes' setters, the shape tree code - * became conscious of the presence of watchpoints, and shared shapes between - * objects only when their watchpoint nature coincided. Clearing the magic setter - * from one object's shape would not affect other objects, because the - * watchpointed and non-watchpointed shapes were distinct if they were shared. - * - * Thus, the first unwatch call must go ahead and fix p's shape, even though a - * watchpoint exists on the same shape in o. o's watchpoint's presence shouldn't - * cause 'unwatch' to leave p's magic setter in place. - */ - - /* DropWatchPointAndUnlock would see o's watchpoint, and not change p's property. */ - p.unwatch(0); - - /* DropWatchPointAndUnlock would fix o's property, but not p's; p's setter would be gone. */ - o.unwatch(0); - - /* This would fail to invoke the arguments object's setter. */ - p[0] = 4; - - /* And the formal parameter would not get updated. */ - assertEq(flag, 4); - } -} - -f(true); -f(false); - -reportCompare(true, true); diff --git a/js/src/tests/js1_5/Object/regress-362872-01.js b/js/src/tests/js1_5/Object/regress-362872-01.js deleted file mode 100644 index 0808ee82b..000000000 --- a/js/src/tests/js1_5/Object/regress-362872-01.js +++ /dev/null @@ -1,41 +0,0 @@ -/* -*- tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 362872; -var summary = 'script should not drop watchpoint that is in use'; -var actual = 'No Crash'; -var expect = 'No Crash'; - - -//----------------------------------------------------------------------------- -test(); -//----------------------------------------------------------------------------- - -function test() -{ - enterFunc ('test'); - printBugNumber(BUGNUMBER); - printStatus (summary); - - function exploit() { - var rooter = {}, object = {}, filler1 = "", filler2 = "\u5555"; - for(var i = 0; i < 32/2-2; i++) { filler1 += "\u5050"; } - object.watch("foo", function(){ - object.unwatch("foo"); - object.unwatch("foo"); - for(var i = 0; i < 8 * 1024; i++) { - rooter[i] = filler1 + filler2; - } - }); - object.foo = "bar"; - } - exploit(); - - - reportCompare(expect, actual, summary); - - exitFunc ('test'); -} diff --git a/js/src/tests/js1_5/Object/regress-362872-02.js b/js/src/tests/js1_5/Object/regress-362872-02.js deleted file mode 100644 index edee43a4a..000000000 --- a/js/src/tests/js1_5/Object/regress-362872-02.js +++ /dev/null @@ -1,24 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* - * Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/licenses/publicdomain/ - * Contributor: Blake Kaplan - */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 362872; -var summary = 'script should not drop watchpoint that is in use'; -var actual = 'No Crash'; -var expect = 'No Crash'; - -printBugNumber(BUGNUMBER); -printStatus (summary); - -this.watch('x', function f() { - print("before"); - x = 3; - print("after"); - }); -x = 3; - -reportCompare(expect, actual, summary); diff --git a/js/src/tests/js1_5/Regress/regress-127243.js b/js/src/tests/js1_5/Regress/regress-127243.js deleted file mode 100644 index 11779f803..000000000 --- a/js/src/tests/js1_5/Regress/regress-127243.js +++ /dev/null @@ -1,75 +0,0 @@ -// |reftest| skip-if(xulRuntime.OS=="WINNT"&&isDebugBuild) slow -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 127243; -var summary = 'Do not crash on watch'; -var actual = 'No Crash'; -var expect = 'No Crash'; - -printBugNumber(BUGNUMBER); -printStatus (summary); - -if (typeof window != 'undefined' && typeof document != 'undefined') -{ - // delay test driver end - gDelayTestDriverEnd = true; - window.addEventListener('load', handleLoad, false); -} -else -{ - printStatus('This test must be run in the browser'); - reportCompare(expect, actual, summary); - -} - -var div; - -function handleLoad() -{ - div = document.createElement('div'); - document.body.appendChild(div); - div.setAttribute('id', 'id1'); - div.style.width = '50px'; - div.style.height = '100px'; - div.style.overflow = 'auto'; - - for (var i = 0; i < 5; i++) - { - var p = document.createElement('p'); - var t = document.createTextNode('blah'); - p.appendChild(t); - div.appendChild(p); - } - - div.watch('scrollTop', wee); - - setTimeout('setScrollTop()', 1000); -} - -function wee(id, oldval, newval) -{ - var t = document.createTextNode('setting ' + id + - ' value ' + div.scrollTop + - ' oldval ' + oldval + - ' newval ' + newval); - var p = document.createElement('p'); - p.appendChild(t); - document.body.appendChild(p); - - return newval; -} - -function setScrollTop() -{ - div.scrollTop = 42; - - reportCompare(expect, actual, summary); - - gDelayTestDriverEnd = false; - jsTestDriverEnd(); - -} diff --git a/js/src/tests/js1_5/Regress/regress-213482.js b/js/src/tests/js1_5/Regress/regress-213482.js deleted file mode 100644 index 26ed7e894..000000000 --- a/js/src/tests/js1_5/Regress/regress-213482.js +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 213482; -var summary = 'Do not crash watching property when watcher sets property'; -var actual = 'No Crash'; -var expect = 'No Crash'; - -printBugNumber(BUGNUMBER); -printStatus (summary); - -var testobj = {value: 'foo'}; - -function watched (a, b, c) { - testobj.value = (new Date()).getTime(); -} - -function setTest() { - testobj.value = 'b'; -} - -testobj.watch("value", watched); - -setTest(); - -reportCompare(expect, actual, summary); diff --git a/js/src/tests/js1_5/Regress/regress-240577.js b/js/src/tests/js1_5/Regress/regress-240577.js deleted file mode 100644 index ba8330aa0..000000000 --- a/js/src/tests/js1_5/Regress/regress-240577.js +++ /dev/null @@ -1,37 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* - * Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/licenses/publicdomain/ - * Contributor: Bob Clary - */ - -//----------------------------------------------------------------------------- -// originally reported by Jens Thiele in -var BUGNUMBER = 240577; -var summary = 'object.watch execution context'; -var actual = ''; -var expect = ''; - -printBugNumber(BUGNUMBER); -printStatus (summary); - -var createWatcher = function ( watchlabel ) -{ - var watcher = function (property, oldvalue, newvalue) - { - actual += watchlabel; return newvalue; - }; - return watcher; -}; - -var watcher1 = createWatcher('watcher1'); - -var object = {property: 'value'}; - -object.watch('property', watcher1); - -object.property = 'newvalue'; - -expect = 'watcher1'; - -reportCompare(expect, actual, summary); diff --git a/js/src/tests/js1_5/Regress/regress-355341.js b/js/src/tests/js1_5/Regress/regress-355341.js deleted file mode 100644 index ab2a4b884..000000000 --- a/js/src/tests/js1_5/Regress/regress-355341.js +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 355341; -var summary = 'Do not crash with watch and setter'; -var actual = ''; -var expect = ''; - - -//----------------------------------------------------------------------------- -test(); -//----------------------------------------------------------------------------- - -function test() -{ - enterFunc ('test'); - printBugNumber(BUGNUMBER); - printStatus (summary); - - Object.defineProperty(this, "x", { set: Function, enumerable: true, configurable: true }); - this.watch('x', function () { }); x = 3; - - reportCompare(expect, actual, summary); - - exitFunc ('test'); -} diff --git a/js/src/tests/js1_5/Regress/regress-355344.js b/js/src/tests/js1_5/Regress/regress-355344.js deleted file mode 100644 index 00bd39147..000000000 --- a/js/src/tests/js1_5/Regress/regress-355344.js +++ /dev/null @@ -1,49 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 355344; -var summary = 'Exceptions thrown by watch point'; -var actual = ''; -var expect = ''; - - -//----------------------------------------------------------------------------- -test(); -//----------------------------------------------------------------------------- - -function test() -{ - enterFunc ('test'); - printBugNumber(BUGNUMBER); - printStatus (summary); - - var o = {}; - - expect = 'setter: yikes'; - - o.watch('x', function(){throw 'yikes'}); - try - { - o.x = 3; - } - catch(ex) - { - actual = "setter: " + ex; - } - - try - { - eval("") ; - } - catch(e) - { - actual = "eval: " + e; - } - - reportCompare(expect, actual, summary); - - exitFunc ('test'); -} diff --git a/js/src/tests/js1_5/Regress/regress-361467.js b/js/src/tests/js1_5/Regress/regress-361467.js deleted file mode 100644 index 371c0a8b5..000000000 --- a/js/src/tests/js1_5/Regress/regress-361467.js +++ /dev/null @@ -1,32 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 361467; -var summary = 'Do not crash with certain watchers'; -var actual = ''; -var expect = ''; - - -//----------------------------------------------------------------------------- -test(); -//----------------------------------------------------------------------------- - -function test() -{ - enterFunc ('test'); - printBugNumber(BUGNUMBER); - printStatus (summary); - - expect = actual = 'No Crash'; - - var x; - this.watch('x', print); - x = 5; - - reportCompare(expect, actual, summary); - - exitFunc ('test'); -} diff --git a/js/src/tests/js1_5/Regress/regress-361617.js b/js/src/tests/js1_5/Regress/regress-361617.js deleted file mode 100644 index 5d20fd78f..000000000 --- a/js/src/tests/js1_5/Regress/regress-361617.js +++ /dev/null @@ -1,35 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 361617; -var summary = 'Do not crash with getter, watch and gc'; -var actual = 'No Crash'; -var expect = 'No Crash'; - - -//----------------------------------------------------------------------------- -test(); -//----------------------------------------------------------------------------- - -function test() -{ - enterFunc ('test'); - printBugNumber(BUGNUMBER); - printStatus (summary); - - (function() { - Object.defineProperty(this, "x", { get: function(){}, enumerable: true, configurable: true }); - })(); - this.watch('x', print); - Object.defineProperty(this, "x", { get: function(){}, enumerable: true, configurable: true }); - gc(); - this.unwatch('x'); - x; - - reportCompare(expect, actual, summary); - - exitFunc ('test'); -} diff --git a/js/src/tests/js1_5/Regress/regress-385393-06.js b/js/src/tests/js1_5/Regress/regress-385393-06.js deleted file mode 100644 index 327103f39..000000000 --- a/js/src/tests/js1_5/Regress/regress-385393-06.js +++ /dev/null @@ -1,28 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - - -//----------------------------------------------------------------------------- -var BUGNUMBER = 385393; -var summary = 'Regression test for bug 385393'; -var actual = 'No Crash'; -var expect = 'No Crash'; - -//----------------------------------------------------------------------------- -test(); -//----------------------------------------------------------------------------- - -function test() -{ - enterFunc ('test'); - printBugNumber(BUGNUMBER); - printStatus (summary); - - reportCompare(expect, actual, summary); - - true.watch("x", function(){}); - - exitFunc ('test'); -} diff --git a/js/src/tests/js1_5/Regress/regress-506567.js b/js/src/tests/js1_5/Regress/regress-506567.js deleted file mode 100644 index e78dfe1db..000000000 --- a/js/src/tests/js1_5/Regress/regress-506567.js +++ /dev/null @@ -1,45 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 506567; -var summary = 'Do not crash with watched variables'; -var actual = ''; -var expect = ''; - - -//----------------------------------------------------------------------------- -test(); -//----------------------------------------------------------------------------- - -function test() -{ - enterFunc ('test'); - printBugNumber(BUGNUMBER); - printStatus (summary); - - if (typeof clearInterval == 'undefined') - { - clearInterval = (function () {}); - } - - var obj = new Object(); - obj.test = null; - obj.watch("test", (function(prop, oldval, newval) - { - if(false) - { - var test = newval % oldval; - var func = (function(){clearInterval(myInterval);}); - } - })); - - obj.test = 'null'; - print(obj.test); - - reportCompare(expect, actual, summary); - - exitFunc ('test'); -} diff --git a/js/src/tests/js1_5/extensions/regress-303277.js b/js/src/tests/js1_5/extensions/regress-303277.js deleted file mode 100644 index 319d9a2ed..000000000 --- a/js/src/tests/js1_5/extensions/regress-303277.js +++ /dev/null @@ -1,19 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 303277; -var summary = 'Do not crash with crash with a watchpoint for __proto__ property '; -var actual = 'No Crash'; -var expect = 'No Crash'; - -printBugNumber(BUGNUMBER); -printStatus (summary); - -var o = {}; -o.watch("__proto__", function(){return null;}); -o.__proto__ = null; - -reportCompare(expect, actual, summary); diff --git a/js/src/tests/js1_5/extensions/regress-355339.js b/js/src/tests/js1_5/extensions/regress-355339.js deleted file mode 100644 index 9b15bd742..000000000 --- a/js/src/tests/js1_5/extensions/regress-355339.js +++ /dev/null @@ -1,32 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 355339; -var summary = 'Do not assert: sprop->setter != js_watch_set'; -var actual = ''; -var expect = ''; - - -//----------------------------------------------------------------------------- -test(); -//----------------------------------------------------------------------------- - -function test() -{ - enterFunc ('test'); - printBugNumber(BUGNUMBER); - printStatus (summary); - - expect = actual = 'No Crash'; - o = {}; - o.watch("j", function(a,b,c) { print("*",a,b,c) }); - o.unwatch("j"); - o.watch("j", function(a,b,c) { print("*",a,b,c) }); - - reportCompare(expect, actual, summary); - - exitFunc ('test'); -} diff --git a/js/src/tests/js1_5/extensions/regress-361346.js b/js/src/tests/js1_5/extensions/regress-361346.js deleted file mode 100644 index 297c3b1f2..000000000 --- a/js/src/tests/js1_5/extensions/regress-361346.js +++ /dev/null @@ -1,22 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 361346; -var summary = 'Crash with setter, watch, GC'; -var actual = ''; -var expect = ''; - -printBugNumber(BUGNUMBER); -printStatus (summary); - -expect = actual = 'No Crash'; - -Object.defineProperty(this, "x", { set: new Function, enumerable: true, configurable: true }); -this.watch('x', function(){}); -gc(); -x = {}; - -reportCompare(expect, actual, summary); diff --git a/js/src/tests/js1_5/extensions/regress-361360.js b/js/src/tests/js1_5/extensions/regress-361360.js deleted file mode 100644 index 98e6575d9..000000000 --- a/js/src/tests/js1_5/extensions/regress-361360.js +++ /dev/null @@ -1,32 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 361360; -var summary = 'Do not assert: !caller || caller->pc involving setter and watch'; -var actual = ''; -var expect = ''; - - -//----------------------------------------------------------------------------- -test(); -//----------------------------------------------------------------------------- - -function test() -{ - enterFunc ('test'); - printBugNumber(BUGNUMBER); - printStatus (summary); - - expect = actual = 'No Crash'; - - this.__defineSetter__('x', eval); - this.watch('x', function(){}); - x = 3; - - reportCompare(expect, actual, summary); - - exitFunc ('test'); -} diff --git a/js/src/tests/js1_5/extensions/regress-361552.js b/js/src/tests/js1_5/extensions/regress-361552.js deleted file mode 100644 index eed54e6dd..000000000 --- a/js/src/tests/js1_5/extensions/regress-361552.js +++ /dev/null @@ -1,27 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 361552; -var summary = 'Crash with setter, watch, Script'; -var actual = ''; -var expect = ''; - -printBugNumber(BUGNUMBER); -printStatus (summary); - -expect = actual = 'No Crash'; - -if (typeof Script == 'undefined') -{ - print('Test skipped. Script not defined.'); -} -else -{ - this.__defineSetter__('x', gc); - this.watch('x', new Script('')); - x = 3; -} -reportCompare(expect, actual, summary); diff --git a/js/src/tests/js1_5/extensions/regress-361558.js b/js/src/tests/js1_5/extensions/regress-361558.js deleted file mode 100644 index a9a3ae725..000000000 --- a/js/src/tests/js1_5/extensions/regress-361558.js +++ /dev/null @@ -1,19 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 361558; -var summary = 'Do not assert: sprop->setter != js_watch_set'; -var actual = ''; -var expect = ''; - -printBugNumber(BUGNUMBER); -printStatus (summary); - -expect = actual = 'No Crash'; - -({}.__proto__.watch('x', print)); ({}.watch('x', print)); - -reportCompare(expect, actual, summary); diff --git a/js/src/tests/js1_5/extensions/regress-361571.js b/js/src/tests/js1_5/extensions/regress-361571.js deleted file mode 100644 index bf89d794b..000000000 --- a/js/src/tests/js1_5/extensions/regress-361571.js +++ /dev/null @@ -1,38 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 361571; -var summary = 'Do not assert: fp->scopeChain == parent'; -var actual = 'No Crash'; -var expect = 'No Crash'; - -//----------------------------------------------------------------------------- -test(); -//----------------------------------------------------------------------------- - -function test() -{ - enterFunc ('test'); - printBugNumber(BUGNUMBER); - printStatus (summary); - - try - { - o = {}; - o.__defineSetter__('y', eval); - o.watch('y', function () { return "";}); - o.y = 1; - } - catch(ex) - { - printStatus('Note eval can no longer be called directly'); - expect = 'EvalError: function eval must be called directly, and not by way of a function of another name'; - actual = ex + ''; - } - reportCompare(expect, actual, summary); - - exitFunc ('test'); -} diff --git a/js/src/tests/js1_5/extensions/regress-361856.js b/js/src/tests/js1_5/extensions/regress-361856.js deleted file mode 100644 index e7e2f675b..000000000 --- a/js/src/tests/js1_5/extensions/regress-361856.js +++ /dev/null @@ -1,35 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 361856; -var summary = 'Do not assert: overwriting @ js_AddScopeProperty'; -var actual = ''; -var expect = ''; - - -//----------------------------------------------------------------------------- -test(); -//----------------------------------------------------------------------------- - -function test() -{ - enterFunc ('test'); - printBugNumber(BUGNUMBER); - printStatus (summary); - - function testit() { - var obj = {}; - obj.watch("foo", function(){}); - delete obj.foo; - obj = null; - gc(); - } - testit(); - - reportCompare(expect, actual, summary); - - exitFunc ('test'); -} diff --git a/js/src/tests/js1_5/extensions/regress-361964.js b/js/src/tests/js1_5/extensions/regress-361964.js deleted file mode 100644 index fcb8bba01..000000000 --- a/js/src/tests/js1_5/extensions/regress-361964.js +++ /dev/null @@ -1,54 +0,0 @@ -// |reftest| skip -- slow, alert not dismissed, now busted by harness -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 361964; -var summary = 'Crash [@ MarkGCThingChildren] involving watch and setter'; -var actual = 'No Crash'; -var expect = 'No Crash'; - - -//----------------------------------------------------------------------------- -test(); -//----------------------------------------------------------------------------- - -function test() -{ - enterFunc ('test'); - printBugNumber(BUGNUMBER); - printStatus (summary); - - var doc; - if (typeof document == 'undefined') - { - doc = {}; - } - else - { - doc = document; - } - - if (typeof alert == 'undefined') - { - alert = print; - } - -// Crash: - doc.watch("title", function(a,b,c,d) { - return { toString : function() { alert(1); } }; - }); - doc.title = "xxx"; - -// No crash: - doc.watch("title", function() { - return { toString : function() { alert(1); } }; - }); - doc.title = "xxx"; - - reportCompare(expect, actual, summary); - - exitFunc ('test'); -} diff --git a/js/src/tests/js1_5/extensions/regress-385134.js b/js/src/tests/js1_5/extensions/regress-385134.js deleted file mode 100644 index 041f4d6e7..000000000 --- a/js/src/tests/js1_5/extensions/regress-385134.js +++ /dev/null @@ -1,38 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 385134; -var summary = 'Do not crash with setter, watch, uneval'; -var actual = 'No Crash'; -var expect = 'No Crash'; - - -//----------------------------------------------------------------------------- -test(); -//----------------------------------------------------------------------------- - -function test() -{ - enterFunc ('test'); - printBugNumber(BUGNUMBER); - printStatus (summary); - - if (typeof this.__defineSetter__ != 'undefined' && - typeof this.watch != 'undefined' && - typeof uneval != 'undefined') - { - try { - this.__defineSetter__(0, function(){}); - } catch (exc) { - // In the browser, this fails. Ignore the error. - } - this.watch(0, function(){}); - uneval(this); - } - reportCompare(expect, actual, summary); - - exitFunc ('test'); -} diff --git a/js/src/tests/js1_5/extensions/regress-385393-09.js b/js/src/tests/js1_5/extensions/regress-385393-09.js deleted file mode 100644 index 42834824a..000000000 --- a/js/src/tests/js1_5/extensions/regress-385393-09.js +++ /dev/null @@ -1,18 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - - -//----------------------------------------------------------------------------- -var BUGNUMBER = 385393; -var summary = 'Regression test for bug 385393'; -var actual = 'No Crash'; -var expect = 'No Crash'; - -printBugNumber(BUGNUMBER); -printStatus (summary); - -eval("this.__defineSetter__('x', gc); this.watch('x', [].slice); x = 1;"); - -reportCompare(expect, actual, summary); diff --git a/js/src/tests/js1_5/extensions/regress-390597.js b/js/src/tests/js1_5/extensions/regress-390597.js deleted file mode 100644 index 9f8596adc..000000000 --- a/js/src/tests/js1_5/extensions/regress-390597.js +++ /dev/null @@ -1,42 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 390597; -var summary = 'watch point + eval-as-setter allows access to dead JSStackFrame'; -var actual = 'No Crash'; -var expect = 'No Crash'; - - -//----------------------------------------------------------------------------- -test(); -//----------------------------------------------------------------------------- - -function test() -{ - enterFunc ('test'); - printBugNumber(BUGNUMBER); - printStatus (summary); - - function exploit() { - try - { - var obj = this, args = null; - obj.__defineSetter__("evil", eval); - obj.watch("evil", function() { return "args = arguments;"; }); - obj.evil = null; - eval("print(args[0]);"); - } - catch(ex) - { - print('Caught ' + ex); - } - } - exploit(); - - reportCompare(expect, actual, summary); - - exitFunc ('test'); -} diff --git a/js/src/tests/js1_5/extensions/regress-420612.js b/js/src/tests/js1_5/extensions/regress-420612.js deleted file mode 100644 index a4491095e..000000000 --- a/js/src/tests/js1_5/extensions/regress-420612.js +++ /dev/null @@ -1,21 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 420612; -var summary = 'Do not assert: obj == pobj'; -var actual = 'No Crash'; -var expect = 'No Crash'; - -printBugNumber(BUGNUMBER); -printStatus (summary); - -var obj = Object.create([]); -obj.unwatch("x"); - -if (typeof reportCompare === "function") - reportCompare(true, true); - -print("Tests complete"); diff --git a/js/src/tests/js1_5/extensions/regress-435345-01.js b/js/src/tests/js1_5/extensions/regress-435345-01.js deleted file mode 100644 index 28beab473..000000000 --- a/js/src/tests/js1_5/extensions/regress-435345-01.js +++ /dev/null @@ -1,100 +0,0 @@ -// |reftest| fails -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 435345; -var summary = 'Watch the length property of arrays'; -var actual = ''; -var expect = ''; - -// see http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Object:watch - -//----------------------------------------------------------------------------- -test(); -//----------------------------------------------------------------------------- - -function test() -{ - enterFunc ('test'); - printBugNumber(BUGNUMBER); - printStatus (summary); - - var arr; - - try - { - expect = 'watcher: propname=length, oldval=0, newval=1; '; - actual = ''; - arr = []; - arr.watch('length', watcher); - arr[0] = '0'; - } - catch(ex) - { - actual = ex + ''; - } - reportCompare(expect, actual, summary + ': 1'); - - try - { - expect = 'watcher: propname=length, oldval=1, newval=2; ' + - 'watcher: propname=length, oldval=2, newval=2; '; - actual = ''; - arr.push(5); - } - catch(ex) - { - actual = ex + ''; - } - reportCompare(expect, actual, summary + ': 2'); - - try - { - expect = 'watcher: propname=length, oldval=2, newval=1; '; - actual = ''; - arr.pop(); - } - catch(ex) - { - actual = ex + ''; - } - reportCompare(expect, actual, summary + ': 3'); - - try - { - expect = 'watcher: propname=length, oldval=1, newval=2; '; - actual = ''; - arr.length++; - } - catch(ex) - { - actual = ex + ''; - } - reportCompare(expect, actual, summary + ': 4'); - - try - { - expect = 'watcher: propname=length, oldval=2, newval=5; '; - actual = ''; - arr.length = 5; - } - catch(ex) - { - actual = ex + ''; - } - reportCompare(expect, actual, summary + ': 5'); - - exitFunc ('test'); -} - -function watcher(propname, oldval, newval) -{ - actual += 'watcher: propname=' + propname + ', oldval=' + oldval + - ', newval=' + newval + '; '; - - return newval; -} - diff --git a/js/src/tests/js1_5/extensions/regress-454040.js b/js/src/tests/js1_5/extensions/regress-454040.js deleted file mode 100644 index 63b5e1488..000000000 --- a/js/src/tests/js1_5/extensions/regress-454040.js +++ /dev/null @@ -1,25 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 454040; -var summary = 'Do not crash @ js_ComputeFilename'; -var actual = ''; -var expect = ''; - -printBugNumber(BUGNUMBER); -printStatus (summary); - -try -{ - this.__defineGetter__("x", Function); - this.__defineSetter__("x", Function); - this.watch("x", x.__proto__); - x = 1; -} -catch(ex) -{ -} -reportCompare(expect, actual, summary); diff --git a/js/src/tests/js1_5/extensions/regress-454142.js b/js/src/tests/js1_5/extensions/regress-454142.js deleted file mode 100644 index 05f331278..000000000 --- a/js/src/tests/js1_5/extensions/regress-454142.js +++ /dev/null @@ -1,30 +0,0 @@ -// |reftest| skip-if(Android) -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 454142; -var summary = 'Do not crash with gczeal, setter, watch'; -var actual = ''; -var expect = ''; - -printBugNumber(BUGNUMBER); -printStatus (summary); - -this.watch("x", function(){}); -delete x; -if (typeof gczeal == 'function') -{ - gczeal(2); -} - -this.__defineSetter__("x", function(){}); - -if (typeof gczeal == 'function') -{ - gczeal(0); -} - -reportCompare(expect, actual, summary); diff --git a/js/src/tests/js1_5/extensions/regress-455413.js b/js/src/tests/js1_5/extensions/regress-455413.js deleted file mode 100644 index d00ab135b..000000000 --- a/js/src/tests/js1_5/extensions/regress-455413.js +++ /dev/null @@ -1,24 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 455413; -var summary = 'Do not assert with JIT: (m != JSVAL_INT) || isInt32(*vp)'; -var actual = 'No Crash'; -var expect = 'No Crash'; - - -//----------------------------------------------------------------------------- -test(); -//----------------------------------------------------------------------------- - -printBugNumber(BUGNUMBER); -printStatus (summary); - - -this.watch('x', Math.pow); (function() { for(var j=0;j<4;++j){x=1;} })(); - - -reportCompare(expect, actual, summary); diff --git a/js/src/tests/js1_5/extensions/regress-465145.js b/js/src/tests/js1_5/extensions/regress-465145.js deleted file mode 100644 index 84f81703b..000000000 --- a/js/src/tests/js1_5/extensions/regress-465145.js +++ /dev/null @@ -1,24 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 465145; -var summary = 'Do not crash with watched defined setter'; -var actual = ''; -var expect = ''; - -printBugNumber(BUGNUMBER); -printStatus (summary); - - -this.__defineSetter__("x", function(){}); -this.watch("x", function(){}); -y = this; -for (var z = 0; z < 2; ++z) { x = y }; -this.__defineSetter__("x", function(){}); -for (var z = 0; z < 2; ++z) { x = y }; - - -reportCompare(expect, actual, summary); diff --git a/js/src/tests/js1_5/extensions/regress-472787.js b/js/src/tests/js1_5/extensions/regress-472787.js deleted file mode 100755 index d3196f05f..000000000 --- a/js/src/tests/js1_5/extensions/regress-472787.js +++ /dev/null @@ -1,31 +0,0 @@ -// |reftest| skip-if(Android) -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 472787; -var summary = 'Do not hang with gczeal, watch and concat'; -var actual = ''; -var expect = ''; - -printBugNumber(BUGNUMBER); -printStatus (summary); - -this.__defineSetter__("x", Math.sin); -this.watch("x", '' .concat); - -if (typeof gczeal == 'function') -{ - gczeal(2); -} - -x = 1; - -if (typeof gczeal == 'function') -{ - gczeal(0); -} - -reportCompare(expect, actual, summary); diff --git a/js/src/tests/js1_5/extensions/regress-488995.js b/js/src/tests/js1_5/extensions/regress-488995.js deleted file mode 100644 index f7abbe439..000000000 --- a/js/src/tests/js1_5/extensions/regress-488995.js +++ /dev/null @@ -1,46 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 488995; -var summary = 'Do not crash with watch, __defineSetter__ on svg'; -var actual = ''; -var expect = ''; - - -//----------------------------------------------------------------------------- -test(); -//----------------------------------------------------------------------------- - -function test() -{ - enterFunc ('test'); - printBugNumber(BUGNUMBER); - printStatus (summary); - - if (typeof document == 'undefined') - { - print('Test skipped: requires browser.'); - } - else - { - try - { - var o=document.createElementNS("http://www.w3.org/2000/svg", "svg"); - var p=o.y; - p.watch('animVal', function(id, oldvar, newval) {} ); - p.type='xxx'; - p.__defineSetter__('animVal', function() {}); - p.animVal=0; - } - catch(ex) - { - } - } - - reportCompare(expect, actual, summary); - - exitFunc ('test'); -} diff --git a/js/src/tests/js1_6/Regress/regress-476655.js b/js/src/tests/js1_6/Regress/regress-476655.js deleted file mode 100644 index 9077ba3a0..000000000 --- a/js/src/tests/js1_6/Regress/regress-476655.js +++ /dev/null @@ -1,40 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 476655; -var summary = 'TM: Do not assert: count <= (size_t) (fp->regs->sp - StackBase(fp) - depth)'; -var actual = ''; -var expect = ''; - - -//----------------------------------------------------------------------------- -test(); -//----------------------------------------------------------------------------- - -function test() -{ - enterFunc ('test'); - printBugNumber(BUGNUMBER); - printStatus (summary); - - - try - { - eval( - "(function (){ for (var y in this) {} })();" + - "[''.watch(\"\", function(){}) for each (x in ['', '', eval, '', '']) if " + - "(x)].map(Function)" - ); - } - catch(ex) - { - } - - - reportCompare(expect, actual, summary); - - exitFunc ('test'); -} diff --git a/js/src/tests/js1_6/extensions/regress-457521.js b/js/src/tests/js1_6/extensions/regress-457521.js deleted file mode 100644 index 6f4fbda50..000000000 --- a/js/src/tests/js1_6/extensions/regress-457521.js +++ /dev/null @@ -1,24 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 457521; -var summary = 'Do not crash @ js_DecompileValueGenerator'; -var actual = ''; -var expect = ''; - -printBugNumber(BUGNUMBER); -printStatus (summary); - -try -{ - this.__defineSetter__("x", [,,,].map); - this.watch("x", (new Function("var y, eval"))); - x = true; -} -catch(ex) -{ -} -reportCompare(expect, actual, summary); diff --git a/js/src/tests/js1_6/extensions/regress-479567.js b/js/src/tests/js1_6/extensions/regress-479567.js deleted file mode 100644 index 6f3525130..000000000 --- a/js/src/tests/js1_6/extensions/regress-479567.js +++ /dev/null @@ -1,33 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 479567; -var summary = 'Do not assert: thing'; -var actual = ''; -var expect = ''; - -printBugNumber(BUGNUMBER); -printStatus (summary); - - -function f() -{ - (eval("(function(){for each (y in [false, false, false]);});"))(); -} - -try -{ - this.__defineGetter__("x", gc); - uneval(this.watch("y", this.toSource)) - f(); - throw x; -} -catch(ex) -{ -} - - -reportCompare(expect, actual, summary); diff --git a/js/src/tests/js1_7/extensions/regress-453955.js b/js/src/tests/js1_7/extensions/regress-453955.js deleted file mode 100644 index 454f712f3..000000000 --- a/js/src/tests/js1_7/extensions/regress-453955.js +++ /dev/null @@ -1,31 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 453955; -var summary = 'Do not assert: sprop->setter != js_watch_set || pobj != obj'; -var actual = ''; -var expect = ''; - - -//----------------------------------------------------------------------------- -test(); -//----------------------------------------------------------------------------- - -function test() -{ - enterFunc ('test'); - printBugNumber(BUGNUMBER); - printStatus (summary); - - for (var z = 0; z < 2; ++z) - { - [].filter.watch("9", function(y) { yield y; }); - } - - reportCompare(expect, actual, summary); - - exitFunc ('test'); -} diff --git a/js/src/tests/js1_7/extensions/regress-473282.js b/js/src/tests/js1_7/extensions/regress-473282.js deleted file mode 100644 index c50ac9234..000000000 --- a/js/src/tests/js1_7/extensions/regress-473282.js +++ /dev/null @@ -1,20 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 473282; -var summary = 'Do not assert: thing'; -var actual = ''; -var expect = ''; - -printBugNumber(BUGNUMBER); -printStatus (summary); - -this.watch("b", "".substring); -this.__defineGetter__("a", gc); -for each (b in [this, null, null]); -a; - -reportCompare(expect, actual, summary); diff --git a/js/src/tests/js1_7/regress/regress-385133-01.js b/js/src/tests/js1_7/regress/regress-385133-01.js deleted file mode 100644 index 03b09f535..000000000 --- a/js/src/tests/js1_7/regress/regress-385133-01.js +++ /dev/null @@ -1,37 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 385133; -var summary = 'Do not crash due to recursion with watch, setter, delete, generator'; -var actual = 'No Crash'; -var expect = 'No Crash'; - - -//----------------------------------------------------------------------------- -test(); -//----------------------------------------------------------------------------- - -function test() -{ - enterFunc ('test'); - printBugNumber(BUGNUMBER); - printStatus (summary); - - try - { - Object.defineProperty(this, "x", { set: {}.watch, enumerable: true, configurable: true }); - this.watch('x', 'foo'.split); - delete x; - function g(){ x = 1; yield; } - for (i in g()) { } - } - catch(ex) - { - } - reportCompare(expect, actual, summary); - - exitFunc ('test'); -} diff --git a/js/src/tests/js1_8/extensions/regress-394709.js b/js/src/tests/js1_8/extensions/regress-394709.js deleted file mode 100644 index d04d8832f..000000000 --- a/js/src/tests/js1_8/extensions/regress-394709.js +++ /dev/null @@ -1,51 +0,0 @@ -// |reftest| skip-if(!xulRuntime.shell) -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 394709; -var summary = 'Do not leak with object.watch and closure'; -var actual = 'No Leak'; -var expect = 'No Leak'; - -//----------------------------------------------------------------------------- -test(); -//----------------------------------------------------------------------------- - -function test() -{ - enterFunc ('test'); - printBugNumber(BUGNUMBER); - printStatus (summary); - - assertEq(finalizeCount(), 0, "invalid initial state"); - - runtest(); - gc(); - assertEq(finalizeCount(), 1, "leaked"); - - runtest(); - gc(); - assertEq(finalizeCount(), 2, "leaked"); - - runtest(); - gc(); - assertEq(finalizeCount(), 3, "leaked"); - - - function runtest () { - var obj = { b: makeFinalizeObserver() }; - obj.watch('b', watcher); - - function watcher(id, old, value) { - ++obj.n; - return value; - } - } - - reportCompare(expect, actual, summary); - - exitFunc ('test'); -} diff --git a/js/src/tests/js1_8/extensions/regress-481989.js b/js/src/tests/js1_8/extensions/regress-481989.js deleted file mode 100644 index 36efb7567..000000000 --- a/js/src/tests/js1_8/extensions/regress-481989.js +++ /dev/null @@ -1,19 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 481989; -var summary = 'TM: Do not assert: SPROP_HAS_STUB_SETTER(sprop)'; -var actual = ''; -var expect = ''; - -printBugNumber(BUGNUMBER); -printStatus (summary); - - -y = this.watch("x", function(){}); for each (let y in ['', '']) x = y; - - -reportCompare(expect, actual, summary); diff --git a/js/src/tests/js1_8_1/extensions/regress-452498-193.js b/js/src/tests/js1_8_1/extensions/regress-452498-193.js deleted file mode 100644 index 1397bf4bb..000000000 --- a/js/src/tests/js1_8_1/extensions/regress-452498-193.js +++ /dev/null @@ -1,34 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 452498; -var summary = 'TM: upvar2 regression tests'; -var actual = ''; -var expect = ''; - -//------- Comment #193 From Gary Kwong - -//----------------------------------------------------------------------------- -test(); -//----------------------------------------------------------------------------- - -function test() -{ - enterFunc ('test'); - printBugNumber(BUGNUMBER); - printStatus (summary); - -// Assertion failure: afunbox->parent, at ../jsparse.cpp:1912 - - this.x = undefined; - this.watch("x", Function); - NaN = uneval({ get \u3056 (){ return undefined } }); - x+=NaN; - - reportCompare(expect, actual, summary); - - exitFunc ('test'); -} diff --git a/js/src/tests/js1_8_1/extensions/regress-452498-196.js b/js/src/tests/js1_8_1/extensions/regress-452498-196.js index 69d5a3586..5b9191199 100644 --- a/js/src/tests/js1_8_1/extensions/regress-452498-196.js +++ b/js/src/tests/js1_8_1/extensions/regress-452498-196.js @@ -21,15 +21,6 @@ function test() printBugNumber(BUGNUMBER); printStatus (summary); -// Assertion failure: localKind == JSLOCAL_VAR || localKind == JSLOCAL_CONST, at ../jsfun.cpp:916 - - this.x = undefined; - this.watch("x", Function); - NaN = uneval({ get \u3056 (){ return undefined } }); - x+=NaN; - - reportCompare(expect, actual, summary + ': 1'); - // Assertion failure: lexdep->isLet(), at ../jsparse.cpp:1900 (function (){ diff --git a/js/src/tests/js1_8_1/extensions/regress-520572.js b/js/src/tests/js1_8_1/extensions/regress-520572.js deleted file mode 100644 index 97f00029a..000000000 --- a/js/src/tests/js1_8_1/extensions/regress-520572.js +++ /dev/null @@ -1,41 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */ -/* - * Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/licenses/publicdomain/ - * Contributor: Blake Kaplan - */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 520572; -var summary = 'watch should innerize the object being watched'; -var actual = 0; -var expect = 2; - - -//----------------------------------------------------------------------------- -test(); -//----------------------------------------------------------------------------- - -function test() -{ - enterFunc ('test'); - printBugNumber(BUGNUMBER); - printStatus (summary); - - if ("evalcx" in this) { - // shell - let s = evalcx("lazy"); - s.n = 0; - evalcx('this.watch("x", function(){ n++; }); this.x = 4; x = 6', s); - actual = s.n; - reportCompare(expect, actual, summary); - } else { - // browser - this.watch('x', function(){ actual++; }); - this.x = 4; - x = 6; - reportCompare(expect, actual, summary); - } - - exitFunc ('test'); -} diff --git a/js/src/tests/js1_8_1/regress/regress-452498-160.js b/js/src/tests/js1_8_1/regress/regress-452498-160.js index 6498a0b5a..305b41795 100644 --- a/js/src/tests/js1_8_1/regress/regress-452498-160.js +++ b/js/src/tests/js1_8_1/regress/regress-452498-160.js @@ -21,11 +21,6 @@ function test() printBugNumber(BUGNUMBER); printStatus (summary); -// crash [@ js_Interpret] - (eval("(function(){ this.watch(\"x\", function () { new function ()y } ); const y = undefined });"))(); - x = NaN; - reportCompare(expect, actual, summary + ': 2'); - // Assertion failure: JOF_OPTYPE(op) == JOF_ATOM, at ../jsemit.cpp:5916 ({ set z(v){}, set y(v)--x, set w(v)--w }); reportCompare(expect, actual, summary + ': 3'); diff --git a/js/src/tests/js1_8_5/extensions/regress-604781-1.js b/js/src/tests/js1_8_5/extensions/regress-604781-1.js deleted file mode 100644 index a7c43f95d..000000000 --- a/js/src/tests/js1_8_5/extensions/regress-604781-1.js +++ /dev/null @@ -1,24 +0,0 @@ -// Any copyright is dedicated to the Public Domain. -// http://creativecommons.org/licenses/publicdomain/ - -var watcherCount, setterCount; -function watcher(id, oldval, newval) { watcherCount++; return newval; } -function setter(newval) { setterCount++; } - -var p = { set x(v) { setter(v); } }; -p.watch('x', watcher); - -watcherCount = setterCount = 0; -p.x = 2; -assertEq(setterCount, 1); -assertEq(watcherCount, 1); - -var o = Object.defineProperty({}, 'x', { set:setter, enumerable:true, configurable:true }); -o.watch('x', watcher); - -watcherCount = setterCount = 0; -o.x = 2; -assertEq(setterCount, 1); -assertEq(watcherCount, 1); - -reportCompare(0, 0, 'ok'); diff --git a/js/src/tests/js1_8_5/extensions/regress-604781-2.js b/js/src/tests/js1_8_5/extensions/regress-604781-2.js deleted file mode 100644 index 7aba4a274..000000000 --- a/js/src/tests/js1_8_5/extensions/regress-604781-2.js +++ /dev/null @@ -1,13 +0,0 @@ -// Any copyright is dedicated to the Public Domain. -// http://creativecommons.org/licenses/publicdomain/ - -var log; -function watcher(id, old, newval) { log += 'watcher'; return newval; } -var o = { set x(v) { log += 'setter'; } }; -o.watch('x', watcher); -Object.defineProperty(o, 'x', {value: 3, writable: true}); -log = ''; -o.x = 3; -assertEq(log, 'watcher'); - -reportCompare(0, 0, 'ok'); diff --git a/js/src/tests/js1_8_5/extensions/regress-627984-1.js b/js/src/tests/js1_8_5/extensions/regress-627984-1.js deleted file mode 100644 index a3726630a..000000000 --- a/js/src/tests/js1_8_5/extensions/regress-627984-1.js +++ /dev/null @@ -1,16 +0,0 @@ -// Any copyright is dedicated to the Public Domain. -// http://creativecommons.org/licenses/publicdomain/ - -// See bug 627984, comment 17, item 1. -var obj; -var methods = []; -for (var i = 0; i < 2; i++) { - obj = {m: function () { return this.x; }}; - obj.watch("m", function (id, oldval, newval) { methods[i] = oldval; }); - obj.m = 0; -} -assertEq(typeof methods[0], "function"); -assertEq(typeof methods[1], "function"); -assertEq(methods[0] !== methods[1], true); - -reportCompare(0, 0, 'ok'); diff --git a/js/src/tests/js1_8_5/extensions/regress-627984-2.js b/js/src/tests/js1_8_5/extensions/regress-627984-2.js deleted file mode 100644 index c4f1b508c..000000000 --- a/js/src/tests/js1_8_5/extensions/regress-627984-2.js +++ /dev/null @@ -1,15 +0,0 @@ -// Any copyright is dedicated to the Public Domain. -// http://creativecommons.org/licenses/publicdomain/ - -// See bug 627984, comment 17, item 2. -var obj = {}; -var x; -obj.watch("m", function (id, oldval, newval) { - x = this.m; - return newval; - }); -delete obj.m; -obj.m = function () { return this.method; }; -obj.m = 2; - -reportCompare(0, 0, 'ok'); diff --git a/js/src/tests/js1_8_5/extensions/regress-627984-3.js b/js/src/tests/js1_8_5/extensions/regress-627984-3.js deleted file mode 100644 index cbe4e10fa..000000000 --- a/js/src/tests/js1_8_5/extensions/regress-627984-3.js +++ /dev/null @@ -1,14 +0,0 @@ -// Any copyright is dedicated to the Public Domain. -// http://creativecommons.org/licenses/publicdomain/ - -// Don't write string value to method slot. -// See bug 627984, comment 17, item 2. -var obj = {}; -obj.watch("m", function (id, oldval, newval) { - return 'ok'; - }); -delete obj.m; -obj.m = function () { return this.x; }; -assertEq(obj.m, 'ok'); - -reportCompare(0, 0, 'ok'); diff --git a/js/src/tests/js1_8_5/extensions/regress-627984-4.js b/js/src/tests/js1_8_5/extensions/regress-627984-4.js deleted file mode 100644 index bbc017ffb..000000000 --- a/js/src/tests/js1_8_5/extensions/regress-627984-4.js +++ /dev/null @@ -1,15 +0,0 @@ -// Any copyright is dedicated to the Public Domain. -// http://creativecommons.org/licenses/publicdomain/ - -// See bug 627984, comment 17, item 3. -var obj = {}; -obj.watch("m", function (id, oldval, newval) { - delete obj.m; - obj.m = function () {}; - return newval; - }); -delete obj.m; -obj.m = 1; -assertEq(obj.m, 1); - -reportCompare(0, 0, 'ok'); diff --git a/js/src/tests/js1_8_5/extensions/regress-627984-5.js b/js/src/tests/js1_8_5/extensions/regress-627984-5.js deleted file mode 100644 index 704d8421c..000000000 --- a/js/src/tests/js1_8_5/extensions/regress-627984-5.js +++ /dev/null @@ -1,13 +0,0 @@ -// Any copyright is dedicated to the Public Domain. -// http://creativecommons.org/licenses/publicdomain/ - -// Bug 627984 comment 11. -var o = ({}); -o.p = function() {}; -o.watch('p', function() { }); -o.q = function() {} -delete o.p; -o.p = function() {}; -assertEq(o.p, void 0); - -reportCompare(0, 0, 'ok'); diff --git a/js/src/tests/js1_8_5/extensions/regress-627984-6.js b/js/src/tests/js1_8_5/extensions/regress-627984-6.js deleted file mode 100644 index cb1a0fca9..000000000 --- a/js/src/tests/js1_8_5/extensions/regress-627984-6.js +++ /dev/null @@ -1,15 +0,0 @@ -// Any copyright is dedicated to the Public Domain. -// http://creativecommons.org/licenses/publicdomain/ - -// Bug 627984 description. -var o = Array; -o.p = function() {}; -o.watch('p', function() { }); -for(var x in o) { - o[x]; -} -delete o.p; -o.p = function() {}; -assertEq(o.p, void 0); - -reportCompare(0, 0, 'ok'); diff --git a/js/src/tests/js1_8_5/extensions/regress-627984-7.js b/js/src/tests/js1_8_5/extensions/regress-627984-7.js deleted file mode 100644 index b13a0e912..000000000 --- a/js/src/tests/js1_8_5/extensions/regress-627984-7.js +++ /dev/null @@ -1,9 +0,0 @@ -// Any copyright is dedicated to the Public Domain. -// http://creativecommons.org/licenses/publicdomain/ - -// See bug 627984 comment 20. -var obj = {m: function () {}}; -obj.watch("m", function () { throw 'FAIL'; }); -var f = obj.m; // don't call the watchpoint - -reportCompare(0, 0, 'ok'); diff --git a/js/src/tests/js1_8_5/extensions/regress-631723.js b/js/src/tests/js1_8_5/extensions/regress-631723.js deleted file mode 100644 index f7c755603..000000000 --- a/js/src/tests/js1_8_5/extensions/regress-631723.js +++ /dev/null @@ -1,10 +0,0 @@ -// Any copyright is dedicated to the Public Domain. -// http://creativecommons.org/licenses/publicdomain/ - -var o = {a:1, b:2}; -o.watch("p", function() { return 13; }); -delete o.p; -o.p = 0; -assertEq(o.p, 13); - -reportCompare(0, 0, 'ok'); diff --git a/js/src/tests/js1_8_5/extensions/regress-636697.js b/js/src/tests/js1_8_5/extensions/regress-636697.js deleted file mode 100644 index 6b3b1de37..000000000 --- a/js/src/tests/js1_8_5/extensions/regress-636697.js +++ /dev/null @@ -1,11 +0,0 @@ -// Any copyright is dedicated to the Public Domain. -// http://creativecommons.org/licenses/publicdomain/ - -var a = {set p(x) {}}; -a.watch('p', function () {}); -var b = Object.create(a); -b.watch('p', function () {}); -delete b.p; -b.p = 0; - -reportCompare(0, 0, 'ok'); diff --git a/js/src/tests/js1_8_5/extensions/regress-637985.js b/js/src/tests/js1_8_5/extensions/regress-637985.js deleted file mode 100644 index 305bfc820..000000000 --- a/js/src/tests/js1_8_5/extensions/regress-637985.js +++ /dev/null @@ -1,8 +0,0 @@ -// Any copyright is dedicated to the Public Domain. -// http://creativecommons.org/licenses/publicdomain/ - -var obj = {}; -obj.watch(-1, function(){}); -obj.unwatch("-1"); // don't assert - -reportCompare(0, 0, 'ok'); \ No newline at end of file diff --git a/js/src/tests/js1_8_5/extensions/regress-691746.js b/js/src/tests/js1_8_5/extensions/regress-691746.js deleted file mode 100644 index 26f732d07..000000000 --- a/js/src/tests/js1_8_5/extensions/regress-691746.js +++ /dev/null @@ -1,11 +0,0 @@ -// Any copyright is dedicated to the Public Domain. -// http://creativecommons.org/licenses/publicdomain/ - -var obj = {}; -try { - obj.watch(QName(), function () {}); -} catch (exc) { -} -gc(); - -reportCompare(0, 0, 'ok'); diff --git a/js/src/tests/js1_8_5/extensions/watch-undefined-setter.js b/js/src/tests/js1_8_5/extensions/watch-undefined-setter.js deleted file mode 100644 index 92608de0e..000000000 --- a/js/src/tests/js1_8_5/extensions/watch-undefined-setter.js +++ /dev/null @@ -1,19 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* - * Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/licenses/publicdomain/ - * Contributor: - * Gary Kwong - */ - -var gTestfile = 'watch-undefined-setter.js'; -//----------------------------------------------------------------------------- -var BUGNUMBER = 560277; -var summary = - 'Crash [@ JSObject::getParent] or [@ js_WrapWatchedSetter] or ' + - '[@ js_GetClassPrototype]'; - -this.watch("x", function() { }); -Object.defineProperty(this, "x", { set: undefined, configurable: true }); - -reportCompare(true, true); diff --git a/js/src/tests/js1_8_5/regress/regress-533876.js b/js/src/tests/js1_8_5/regress/regress-533876.js deleted file mode 100644 index e44bc8a4f..000000000 --- a/js/src/tests/js1_8_5/regress/regress-533876.js +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/licenses/publicdomain/ - * Contributors: Gary Kwong and Jason Orendorff - */ - -var savedEval = eval; -var x = [0]; -eval(); - -x.__proto__ = this; // x has non-dictionary scope -try { - DIE; -} catch(e) { -} - -delete eval; // force dictionary scope for global -gc(); -eval = savedEval; -var f = eval("(function () { return /x/; })"); -x.watch('x', f); // clone property from global to x, including SPROP_IN_DICTIONARY flag - -reportCompare("ok", "ok", "bug 533876"); diff --git a/js/src/tests/js1_8_5/regress/regress-548276.js b/js/src/tests/js1_8_5/regress/regress-548276.js deleted file mode 100644 index 5e306eba1..000000000 --- a/js/src/tests/js1_8_5/regress/regress-548276.js +++ /dev/null @@ -1,10 +0,0 @@ -// |reftest| skip -/* - * Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/licenses/publicdomain/ - * Contributors: Gary Kwong and Jason Orendorff - */ -var obj = {}; -obj.__defineSetter__("x", function() {}); -obj.watch("x", function() {}); -obj.__defineSetter__("x", /a/); diff --git a/js/src/tests/js1_8_5/regress/regress-584648.js b/js/src/tests/js1_8_5/regress/regress-584648.js deleted file mode 100644 index a1635ea51..000000000 --- a/js/src/tests/js1_8_5/regress/regress-584648.js +++ /dev/null @@ -1,16 +0,0 @@ -// |reftest| skip -// Any copyright is dedicated to the Public Domain. -// http://creativecommons.org/licenses/publicdomain/ -// Contributors: Gary Kwong -// Jason Orendorff - -// on a non-global object -var x = {}; -x.watch("p", function () { evalcx(''); }); -x.p = 0; - -// on the global -watch("e", (function () { evalcx(''); })); -e = function () {}; - -reportCompare(0, 0, "ok"); diff --git a/js/src/tests/js1_8_5/regress/regress-635195.js b/js/src/tests/js1_8_5/regress/regress-635195.js deleted file mode 100644 index 89980b05a..000000000 --- a/js/src/tests/js1_8_5/regress/regress-635195.js +++ /dev/null @@ -1,8 +0,0 @@ -// Any copyright is dedicated to the Public Domain. -// http://creativecommons.org/licenses/publicdomain/ - -var obj = {set x(v) {}}; -obj.watch("x", function() { delete obj.x; }); -obj.x = "hi"; // don't assert - -reportCompare(0, 0, 'ok'); diff --git a/js/src/tests/js1_8_5/regress/regress-636394.js b/js/src/tests/js1_8_5/regress/regress-636394.js deleted file mode 100644 index d1a249786..000000000 --- a/js/src/tests/js1_8_5/regress/regress-636394.js +++ /dev/null @@ -1,10 +0,0 @@ -// Any copyright is dedicated to the Public Domain. -// http://creativecommons.org/licenses/publicdomain/ - -var a = {p0: function () {}}; -var b = /f/; -b.__proto__ = a; -b.watch("p0", function () {}); -b.p0; - -reportCompare(0, 0, "ok"); -- cgit v1.2.3