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

- Bug 1236321 - Annotate intentional switch fallthroughs to suppress -Wimplicit-fallthrough warnings in js/. r=luke (32d46328ef)
- Bug 1236552 - Odin: handle unfinished AsmJSModuleObject in addSizeOfMisc (r=bbouvier) (dafbd77b10)
- Bug 1229399: Make writing the IR fallible, provide a fallible readingAPI; r=luke (cbc536c3fa)
- Bug 1237272 - Only for Coverity - check arg1, arg2 and arg3 for validity. r=luke (1456e58951)
- Bug 1229399: Split FuncIR into Bytecode/Encoder/Decoder/FuncBytecode; r=luke (9f438b4d5f)
- Bug 1237508 - Odin: make AsmJSModule derive wasm::Module (r=bbouvier) (0186bf908b)
- Bug 1238195 - Switch over some AutoVectorRooters to Rooted<TraceableVector>s and fill in some missing support (r=terrence) (b556fdc27e)
- Bug 1234193 - IsRelazifiableFunction: Return false when we report an error. r=jandem (bd3c33e1e6)
- Bug 1221361: Mark SetARMHwCapFlags as unsafe for fuzzing; r=jolesen (3134febc32)
- Bug 1236564 - Fix various minor issues with getting/setting GC parameters r=terrence (45e251eba7)
- Bug 1235237 - Annotate intentional switch fallthrough to suppress -Wimplicit-fallthrough warning in storage/. r=mak (f81714fdab)
- Bug 1235236 - Annotate intentional switch fallthrough to suppress -Wimplicit-fallthrough warning in modules/libjar/. r=aklotz (f3a210802b)
- Bug 1236324 - Annotate intentional switch fallthroughs to suppress -Wimplicit-fallthrough warnings in toolkit/components/places/. r=mak (f2d09b5041)
- Bug 1238711 - Rename TraceableVector to GCVector; r=sfink Bug 1237153 - Fix gcparam() parameter verification to not allow negative numbers r=terrence (deccfd7f01)
- Bug 1235092 - Part 1: Optimize spread call with rest parameter. r=efaust (e6cc1294d1)
- Bug 1235092 - Part 2: Support allowContentSpread in the optimization for spread call with rest parameter. r=efaust (31c881893d)
- Bug 1235092 - Part 3: Root function in BytecodeEmitter::isRestParameter. r=bustage (ede37f48b6)
- Bug 1233152 - Use PersistentRooted for ParseTask script and sourceObject. r=terrence (d99d9b81fb)
- Bug 1236476: Report out of memory in ExpandErrorArgumentsVA; r=jandem (6a2327222c)
- Bug 1239601 - improve the UniquePtr situation (r=jorendorff) (640322c8c1)
- Bug 1239724: Introduce RegExp registers to non-ion builds; r=arai (f2d837e65b)
- Bug 1137624 - Remove ArrayJoin code duplication, and use a correct alias set. r=jandem (ab8a98a5e3)
- Bug 1237284: Make SIMD names more consistent in MCallOptimize; r=jolesen (d50f74a31e)
- Bug 1238582 - Fix spurious assertion failure in array sort due to over-eager OOM simulation r=jandem (587f4976e5)
- Bug 1235874 - handle null filename in DescribeScriptedCaller (r=sunfish) (b347469108)
- Bug 1239601 - improve the UniquePtr situation (r=jandem) (a8b9f15dcb)
This commit is contained in:
2023-08-04 10:46:07 +08:00
parent c975928fff
commit cc81aca6b2
152 changed files with 3787 additions and 3250 deletions
+1 -1
View File
@@ -465,7 +465,7 @@ nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(JSContext *cx)
unsigned lineNum = 0;
NS_NAMED_LITERAL_STRING(scriptSample, "call to eval() or related function blocked by CSP");
JS::AutoFilename scriptFilename;
JS::UniqueChars scriptFilename;
if (JS::DescribeScriptedCaller(cx, &scriptFilename, &lineNum)) {
if (const char *file = scriptFilename.get()) {
CopyUTF8toUTF16(nsDependentCString(file), fileName);
+1 -1
View File
@@ -14106,7 +14106,7 @@ nsDocShell::NotifyJSRunToCompletionStart(const char* aReason,
RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
if (timelines && timelines->HasConsumer(this)) {
timelines->AddMarkerForDocShell(this, Move(
MakeUnique<JavascriptTimelineMarker>(
mozilla::MakeUnique<JavascriptTimelineMarker>(
aReason, aFunctionName, aFilename, aLineNumber, MarkerTracingType::START,
aAsyncStack, aAsyncCause)));
}
+2 -2
View File
@@ -1261,7 +1261,7 @@ WebSocket::Constructor(const GlobalObject& aGlobal,
}
unsigned lineno, column;
JS::AutoFilename file;
JS::UniqueChars file;
if (!JS::DescribeScriptedCaller(aGlobal.Context(), &file, &lineno,
&column)) {
NS_WARNING("Failed to get line number and filename in workers.");
@@ -1496,7 +1496,7 @@ WebSocketImpl::Init(JSContext* aCx,
MOZ_ASSERT(aCx);
unsigned lineno, column;
JS::AutoFilename file;
JS::UniqueChars file;
if (JS::DescribeScriptedCaller(aCx, &file, &lineno, &column)) {
mScriptFile = file.get();
mScriptLine = lineno;
+1 -1
View File
@@ -11141,7 +11141,7 @@ nsGlobalWindow::ShowSlowScriptDialog()
}
// Check if we should offer the option to debug
JS::AutoFilename filename;
JS::UniqueChars filename;
unsigned lineno;
bool hasFrame = JS::DescribeScriptedCaller(cx, &filename, &lineno);
+2 -2
View File
@@ -37,7 +37,7 @@ bool
nsJSUtils::GetCallingLocation(JSContext* aContext, nsACString& aFilename,
uint32_t* aLineno, uint32_t* aColumn)
{
JS::AutoFilename filename;
JS::UniqueChars filename;
if (!JS::DescribeScriptedCaller(aContext, &filename, aLineno, aColumn)) {
return false;
}
@@ -50,7 +50,7 @@ bool
nsJSUtils::GetCallingLocation(JSContext* aContext, nsAString& aFilename,
uint32_t* aLineno, uint32_t* aColumn)
{
JS::AutoFilename filename;
JS::UniqueChars filename;
if (!JS::DescribeScriptedCaller(aContext, &filename, aLineno, aColumn)) {
return false;
}
+1 -1
View File
@@ -643,7 +643,7 @@ ContentSecurityPolicyAllows(JSContext* aCx)
nsString fileName;
uint32_t lineNum = 0;
JS::AutoFilename file;
JS::UniqueChars file;
if (JS::DescribeScriptedCaller(aCx, &file, &lineNum) && file.get()) {
fileName = NS_ConvertUTF8toUTF16(file.get());
} else {
+1 -1
View File
@@ -4325,7 +4325,7 @@ WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow,
// We're being created outside of a window. Need to figure out the script
// that is creating us in order for us to use relative URIs later on.
JS::AutoFilename fileName;
JS::UniqueChars fileName;
if (JS::DescribeScriptedCaller(aCx, &fileName)) {
// In most cases, fileName is URI. In a few other cases
// (e.g. xpcshell), fileName is a file path. Ideally, we would
+3 -3
View File
@@ -895,10 +895,10 @@ void
WorkerDebuggerGlobalScope::ReportError(JSContext* aCx,
const nsAString& aMessage)
{
JS::AutoFilename afn;
JS::UniqueChars chars;
uint32_t lineno = 0;
JS::DescribeScriptedCaller(aCx, &afn, &lineno);
nsString filename(NS_ConvertUTF8toUTF16(afn.get()));
JS::DescribeScriptedCaller(aCx, &chars, &lineno);
nsString filename(NS_ConvertUTF8toUTF16(chars.get()));
mWorkerPrivate->ReportErrorToDebugger(filename, lineno, aMessage);
}
-4
View File
@@ -12,7 +12,6 @@
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/UniquePtr.h"
#include "jsapi.h"
#include "jspubtd.h"
@@ -26,9 +25,6 @@ class Debugger;
} // namespace js
namespace JS {
using mozilla::UniquePtr;
namespace dbg {
// Helping embedding code build objects for Debugger
+2 -4
View File
@@ -7,10 +7,10 @@
#ifndef js_GCAPI_h
#define js_GCAPI_h
#include "mozilla/UniquePtr.h"
#include "mozilla/Vector.h"
#include "js/HeapAPI.h"
#include "js/UniquePtr.h"
namespace js {
namespace gc {
@@ -48,8 +48,6 @@ typedef enum JSGCInvocationKind {
namespace JS {
using mozilla::UniquePtr;
#define GCREASONS(D) \
/* Reasons internal to the JS engine */ \
D(API) \
@@ -292,7 +290,7 @@ class GarbageCollectionEvent
, collections()
{ }
using Ptr = UniquePtr<GarbageCollectionEvent, DeletePolicy<GarbageCollectionEvent>>;
using Ptr = js::UniquePtr<GarbageCollectionEvent>;
static Ptr Create(JSRuntime* rt, ::js::gcstats::Statistics& stats, uint64_t majorGCNumber);
JSObject* toJSObject(JSContext* cx) const;
@@ -4,8 +4,8 @@
* 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 js_TraceableVector_h
#define js_TraceableVector_h
#ifndef js_GCVector_h
#define js_GCVector_h
#include "mozilla/Vector.h"
@@ -15,7 +15,7 @@
namespace js {
// A TraceableVector is a Vector with an additional trace method that knows how
// A GCVector is a Vector with an additional trace method that knows how
// to visit all of the items stored in the Vector. For vectors that contain GC
// things, this is usually more convenient than manually iterating and marking
// the contents.
@@ -33,20 +33,20 @@ template <typename T,
size_t MinInlineCapacity = 0,
typename AllocPolicy = TempAllocPolicy,
typename GCPolicy = DefaultGCPolicy<T>>
class TraceableVector : public JS::Traceable
class GCVector : public JS::Traceable
{
mozilla::Vector<T, MinInlineCapacity, AllocPolicy> vector;
public:
explicit TraceableVector(AllocPolicy alloc = AllocPolicy())
explicit GCVector(AllocPolicy alloc = AllocPolicy())
: vector(alloc)
{}
TraceableVector(TraceableVector&& vec)
GCVector(GCVector&& vec)
: vector(mozilla::Move(vec.vector))
{}
TraceableVector& operator=(TraceableVector&& vec) {
GCVector& operator=(GCVector&& vec) {
vector = mozilla::Move(vec.vector);
return *this;
}
@@ -118,7 +118,7 @@ class TraceableVector : public JS::Traceable
return vector.sizeOfIncludingThis(mallocSizeOf);
}
static void trace(TraceableVector* vec, JSTracer* trc) { vec->trace(trc); }
static void trace(GCVector* vec, JSTracer* trc) { vec->trace(trc); }
void trace(JSTracer* trc) {
for (auto& elem : vector)
@@ -127,9 +127,9 @@ class TraceableVector : public JS::Traceable
};
template <typename Outer, typename T, size_t Capacity, typename AllocPolicy, typename GCPolicy>
class TraceableVectorOperations
class GCVectorOperations
{
using Vec = TraceableVector<T, Capacity, AllocPolicy, GCPolicy>;
using Vec = GCVector<T, Capacity, AllocPolicy, GCPolicy>;
const Vec& vec() const { return static_cast<const Outer*>(this)->get(); }
public:
@@ -147,10 +147,10 @@ class TraceableVectorOperations
};
template <typename Outer, typename T, size_t Capacity, typename AllocPolicy, typename GCPolicy>
class MutableTraceableVectorOperations
: public TraceableVectorOperations<Outer, T, Capacity, AllocPolicy, GCPolicy>
class MutableGCVectorOperations
: public GCVectorOperations<Outer, T, Capacity, AllocPolicy, GCPolicy>
{
using Vec = TraceableVector<T, Capacity, AllocPolicy, GCPolicy>;
using Vec = GCVector<T, Capacity, AllocPolicy, GCPolicy>;
const Vec& vec() const { return static_cast<const Outer*>(this)->get(); }
Vec& vec() { return static_cast<Outer*>(this)->get(); }
@@ -161,10 +161,12 @@ class MutableTraceableVectorOperations
T* begin() { return vec().begin(); }
const T* end() const { return vec().end(); }
T* end() { return vec().end(); }
const T& operator[](size_t aIndex) const { return vec().operator[](aIndex); }
const T& back() const { return vec().back(); }
T& back() { return vec().back(); }
JS::Handle<T> operator[](size_t aIndex) const {
return JS::Handle<T>::fromMarkedLocation(&vec().operator[](aIndex));
}
JS::MutableHandle<T> operator[](size_t aIndex) {
return JS::MutableHandle<T>::fromMarkedLocation(&vec().operator[](aIndex));
}
@@ -212,27 +214,27 @@ class MutableTraceableVectorOperations
};
template <typename T, size_t N, typename AP, typename GP>
class RootedBase<TraceableVector<T,N,AP,GP>>
: public MutableTraceableVectorOperations<JS::Rooted<TraceableVector<T,N,AP,GP>>, T,N,AP,GP>
class RootedBase<GCVector<T,N,AP,GP>>
: public MutableGCVectorOperations<JS::Rooted<GCVector<T,N,AP,GP>>, T,N,AP,GP>
{};
template <typename T, size_t N, typename AP, typename GP>
class MutableHandleBase<TraceableVector<T,N,AP,GP>>
: public MutableTraceableVectorOperations<JS::MutableHandle<TraceableVector<T,N,AP,GP>>,
class MutableHandleBase<GCVector<T,N,AP,GP>>
: public MutableGCVectorOperations<JS::MutableHandle<GCVector<T,N,AP,GP>>,
T,N,AP,GP>
{};
template <typename T, size_t N, typename AP, typename GP>
class HandleBase<TraceableVector<T,N,AP,GP>>
: public TraceableVectorOperations<JS::Handle<TraceableVector<T,N,AP,GP>>, T,N,AP,GP>
class HandleBase<GCVector<T,N,AP,GP>>
: public GCVectorOperations<JS::Handle<GCVector<T,N,AP,GP>>, T,N,AP,GP>
{};
template <typename T, size_t N, typename AP, typename GP>
class PersistentRootedBase<TraceableVector<T,N,AP,GP>>
: public MutableTraceableVectorOperations<JS::PersistentRooted<TraceableVector<T,N,AP,GP>>,
class PersistentRootedBase<GCVector<T,N,AP,GP>>
: public MutableGCVectorOperations<JS::PersistentRooted<GCVector<T,N,AP,GP>>,
T,N,AP,GP>
{};
} // namespace js
#endif // js_TraceableVector_h
#endif // js_GCVector_h
+6 -6
View File
@@ -606,21 +606,21 @@ template <class T>
struct DefaultHasher<T*> : PointerHasher<T*, mozilla::tl::FloorLog2<sizeof(void*)>::value>
{};
// Specialize hashing policy for mozilla::UniquePtr<T> to proxy the UniquePtr's
// Specialize hashing policy for mozilla::UniquePtr to proxy the UniquePtr's
// raw pointer to PointerHasher.
template <class T>
struct DefaultHasher<mozilla::UniquePtr<T>>
template <class T, class D>
struct DefaultHasher<mozilla::UniquePtr<T, D>>
{
using Lookup = mozilla::UniquePtr<T>;
using Lookup = mozilla::UniquePtr<T, D>;
using PtrHasher = PointerHasher<T*, mozilla::tl::FloorLog2<sizeof(void*)>::value>;
static HashNumber hash(const Lookup& l) {
return PtrHasher::hash(l.get());
}
static bool match(const mozilla::UniquePtr<T>& k, const Lookup& l) {
static bool match(const mozilla::UniquePtr<T, D>& k, const Lookup& l) {
return PtrHasher::match(k.get(), l.get());
}
static void rekey(mozilla::UniquePtr<T>& k, mozilla::UniquePtr<T>&& newKey) {
static void rekey(mozilla::UniquePtr<T, D>& k, mozilla::UniquePtr<T, D>&& newKey) {
k = mozilla::Move(newKey);
}
};
+8
View File
@@ -390,6 +390,14 @@ struct DefaultGCPolicy<jsid>
}
};
template <>
struct DefaultGCPolicy<JS::Value>
{
static void trace(JSTracer* trc, JS::Value* v, const char* name) {
js::UnsafeTraceManuallyBarrieredEdge(trc, v, name);
}
};
template <> struct DefaultGCPolicy<uint32_t> : public IgnoreGCPolicy<uint32_t> {};
template <> struct DefaultGCPolicy<uint64_t> : public IgnoreGCPolicy<uint64_t> {};
+10 -24
View File
@@ -15,7 +15,6 @@
#include "mozilla/Move.h"
#include "mozilla/RangedPtr.h"
#include "mozilla/TypeTraits.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Variant.h"
#include "jspubtd.h"
@@ -25,6 +24,7 @@
#include "js/RootingAPI.h"
#include "js/TracingAPI.h"
#include "js/TypeDecls.h"
#include "js/UniquePtr.h"
#include "js/Value.h"
#include "js/Vector.h"
@@ -174,16 +174,6 @@ class StackFrame;
} // namespace ubi
} // namespace JS
namespace mozilla {
template<>
class DefaultDelete<JS::ubi::EdgeRange> : public JS::DeletePolicy<JS::ubi::EdgeRange> { };
template<>
class DefaultDelete<JS::ubi::StackFrame> : public JS::DeletePolicy<JS::ubi::StackFrame> { };
} // namespace mozilla
namespace JS {
namespace ubi {
@@ -191,7 +181,6 @@ using mozilla::Forward;
using mozilla::Maybe;
using mozilla::Move;
using mozilla::RangedPtr;
using mozilla::UniquePtr;
using mozilla::Variant;
/*** ubi::StackFrame ******************************************************************************/
@@ -597,7 +586,7 @@ class JS_FRIEND_API(Base) {
//
// If wantNames is true, compute names for edges. Doing so can be expensive
// in time and memory.
virtual UniquePtr<EdgeRange> edges(JSRuntime* rt, bool wantNames) const = 0;
virtual js::UniquePtr<EdgeRange> edges(JSRuntime* rt, bool wantNames) const = 0;
// Return the Zone to which this node's referent belongs, or nullptr if the
// referent is not of a type allocated in SpiderMonkey Zones.
@@ -633,8 +622,7 @@ class JS_FRIEND_API(Base) {
// Otherwise, place nullptr in the out parameter. Caller maintains ownership
// of the out parameter. True is returned on success, false is returned on
// OOM.
virtual bool jsObjectConstructorName(JSContext* cx,
UniquePtr<char16_t[], JS::FreePolicy>& outName) const {
virtual bool jsObjectConstructorName(JSContext* cx, UniqueTwoByteChars& outName) const {
outName.reset(nullptr);
return true;
}
@@ -780,8 +768,7 @@ class JS_FRIEND_API(Node) {
JS::Zone* zone() const { return base()->zone(); }
JSCompartment* compartment() const { return base()->compartment(); }
const char* jsObjectClassName() const { return base()->jsObjectClassName(); }
bool jsObjectConstructorName(JSContext* cx,
UniquePtr<char16_t[], JS::FreePolicy>& outName) const {
bool jsObjectConstructorName(JSContext* cx, UniqueTwoByteChars& outName) const {
return base()->jsObjectConstructorName(cx, outName);
}
@@ -796,7 +783,7 @@ class JS_FRIEND_API(Node) {
return size;
}
UniquePtr<EdgeRange> edges(JSRuntime* rt, bool wantNames = true) const {
js::UniquePtr<EdgeRange> edges(JSRuntime* rt, bool wantNames = true) const {
return base()->edges(rt, wantNames);
}
@@ -830,7 +817,7 @@ class JS_FRIEND_API(Node) {
/*** Edge and EdgeRange ***************************************************************************/
using EdgeName = UniquePtr<const char16_t[], JS::FreePolicy>;
using EdgeName = UniqueTwoByteChars;
// An outgoing edge to a referent node.
class Edge {
@@ -1002,7 +989,7 @@ class MOZ_STACK_CLASS JS_FRIEND_API(RootList) {
template<>
struct JS_FRIEND_API(Concrete<RootList>) : public Base {
UniquePtr<EdgeRange> edges(JSRuntime* rt, bool wantNames) const override;
js::UniquePtr<EdgeRange> edges(JSRuntime* rt, bool wantNames) const override;
const char16_t* typeName() const override { return concreteTypeName; }
protected:
@@ -1019,7 +1006,7 @@ struct JS_FRIEND_API(Concrete<RootList>) : public Base {
template<typename Referent>
class JS_FRIEND_API(TracerConcrete) : public Base {
const char16_t* typeName() const override { return concreteTypeName; }
UniquePtr<EdgeRange> edges(JSRuntime* rt, bool wantNames) const override;
js::UniquePtr<EdgeRange> edges(JSRuntime* rt, bool wantNames) const override;
JS::Zone* zone() const override;
protected:
@@ -1077,8 +1064,7 @@ template<> struct Concrete<JSScript> : TracerConcreteWithCompartment<JSScript> {
template<>
class JS_FRIEND_API(Concrete<JSObject>) : public TracerConcreteWithCompartment<JSObject> {
const char* jsObjectClassName() const override;
bool jsObjectConstructorName(JSContext* cx,
UniquePtr<char16_t[], JS::FreePolicy>& outName) const override;
bool jsObjectConstructorName(JSContext* cx, UniqueTwoByteChars& outName) const override;
Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
bool hasAllocationStack() const override;
@@ -1113,7 +1099,7 @@ template<>
class JS_FRIEND_API(Concrete<void>) : public Base {
const char16_t* typeName() const override;
Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
UniquePtr<EdgeRange> edges(JSRuntime* rt, bool wantNames) const override;
js::UniquePtr<EdgeRange> edges(JSRuntime* rt, bool wantNames) const override;
JS::Zone* zone() const override;
JSCompartment* compartment() const override;
CoarseType coarseType() const final;
+2 -2
View File
@@ -83,7 +83,7 @@ struct JS_FRIEND_API(CountDeleter) {
void operator()(CountBase*);
};
using CountBasePtr = UniquePtr<CountBase, CountDeleter>;
using CountBasePtr = js::UniquePtr<CountBase, CountDeleter>;
// Abstract base class for CountType nodes.
struct JS_FRIEND_API(CountType) {
@@ -111,7 +111,7 @@ struct JS_FRIEND_API(CountType) {
virtual bool report(JSContext* cx, CountBase& count, MutableHandleValue report) = 0;
};
using CountTypePtr = UniquePtr<CountType, JS::DeletePolicy<CountType>>;
using CountTypePtr = js::UniquePtr<CountType>;
// An abstract base class for count tree nodes.
class JS_FRIEND_API(CountBase) {
+1 -1
View File
@@ -89,7 +89,7 @@ struct PostOrder {
mozilla::DebugOnly<bool> traversed;
private:
bool fillEdgesFromRange(EdgeVector& edges, UniquePtr<EdgeRange>& range) {
bool fillEdgesFromRange(EdgeVector& edges, js::UniquePtr<EdgeRange>& range) {
MOZ_ASSERT(range);
for ( ; !range->empty(); range->popFront()) {
if (!edges.append(mozilla::Move(range->front())))
+61
View File
@@ -0,0 +1,61 @@
/* -*- 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 js_UniquePtr_h
#define js_UniquePtr_h
#include "mozilla/UniquePtr.h"
#include "js/Utility.h"
namespace js {
// Replacement for mozilla::UniquePtr that defaults to js::DefaultDelete.
template <typename T, typename D = JS::DeletePolicy<T>>
using UniquePtr = mozilla::UniquePtr<T, D>;
namespace detail {
template<typename T>
struct UniqueSelector
{
typedef UniquePtr<T> SingleObject;
};
template<typename T>
struct UniqueSelector<T[]>
{
typedef UniquePtr<T[]> UnknownBound;
};
template<typename T, decltype(sizeof(int)) N>
struct UniqueSelector<T[N]>
{
typedef UniquePtr<T[N]> KnownBound;
};
} // namespace detail
// Replacement for mozilla::MakeUnique that correctly calls js_new and produces
// a js::UniquePtr.
template<typename T, typename... Args>
typename detail::UniqueSelector<T>::SingleObject
MakeUnique(Args&&... aArgs)
{
return UniquePtr<T>(js_new<T>(mozilla::Forward<Args>(aArgs)...));
}
template<typename T>
typename detail::UniqueSelector<T>::UnknownBound
MakeUnique(decltype(sizeof(int)) aN) = delete;
template<typename T, typename... Args>
typename detail::UniqueSelector<T>::KnownBound
MakeUnique(Args&&... aArgs) = delete;
} // namespace js
#endif /* js_UniquePtr_h */
+11 -7
View File
@@ -460,6 +460,14 @@ namespace JS {
template<typename T>
struct DeletePolicy
{
MOZ_CONSTEXPR DeletePolicy() {}
template<typename U>
MOZ_IMPLICIT DeletePolicy(DeletePolicy<U> other,
typename mozilla::EnableIf<mozilla::IsConvertible<U*, T*>::value,
int>::Type dummy = 0)
{}
void operator()(const T* ptr) {
js_delete(const_cast<T*>(ptr));
}
@@ -472,6 +480,9 @@ struct FreePolicy
}
};
typedef mozilla::UniquePtr<char[], JS::FreePolicy> UniqueChars;
typedef mozilla::UniquePtr<char16_t[], JS::FreePolicy> UniqueTwoByteChars;
} // namespace JS
namespace js {
@@ -480,13 +491,6 @@ namespace js {
typedef uint32_t HashNumber;
const unsigned HashNumberSizeBits = 32;
typedef mozilla::UniquePtr<char, JS::FreePolicy> UniqueChars;
static inline UniqueChars make_string_copy(const char* str)
{
return UniqueChars(js_strdup(str));
}
namespace detail {
/*
+6 -4
View File
@@ -13,7 +13,7 @@
// These includes are needed these for some typedefs (e.g. HandleValue) and
// functions (e.g. NullValue())...
#include "js/CallNonGenericMethod.h"
#include "js/TraceableVector.h"
#include "js/GCVector.h"
#include "js/TypeDecls.h"
#include "js/Value.h"
@@ -36,9 +36,9 @@ typedef AutoVectorRooter<jsid> AutoIdVector;
typedef AutoVectorRooter<JSObject*> AutoObjectVector;
typedef AutoVectorRooter<JSScript*> AutoVector;
using ValueVector = js::TraceableVector<JS::Value>;
using IdVector = js::TraceableVector<jsid>;
using ScriptVector = js::TraceableVector<JSScript*>;
using ValueVector = js::GCVector<JS::Value>;
using IdVector = js::GCVector<jsid>;
using ScriptVector = js::GCVector<JSScript*>;
template <typename T> class AutoVectorRooter;
template<typename K, typename V> class AutoHashMapRooter;
@@ -77,6 +77,8 @@ using JS::TwoByteChars;
using JS::TwoByteCharsZ;
using JS::UTF8Chars;
using JS::UTF8CharsZ;
using JS::UniqueChars;
using JS::UniqueTwoByteChars;
using JS::AutoVectorRooter;
typedef AutoVectorRooter<Value> AutoValueVector;
+1231 -1329
View File
File diff suppressed because it is too large Load Diff
+1 -25
View File
@@ -19,11 +19,10 @@
#ifndef asmjs_asmjs_h
#define asmjs_asmjs_h
#include "vm/NativeObject.h"
#include "NamespaceImports.h"
namespace js {
class AsmJSModule;
class ExclusiveContext;
namespace frontend {
template <typename ParseHandler> class Parser;
@@ -34,29 +33,6 @@ namespace frontend {
typedef frontend::Parser<frontend::FullParseHandler> AsmJSParser;
typedef frontend::ParseContext<frontend::FullParseHandler> AsmJSParseContext;
// An AsmJSModuleObject is an internal implementation object (i.e., not exposed
// directly to user script) which traces and owns an AsmJSModule. The
// AsmJSModuleObject is referenced by the extended slots of the content-visible
// module and export JSFunctions.
class AsmJSModuleObject : public NativeObject
{
static const unsigned MODULE_SLOT = 0;
public:
static const unsigned RESERVED_SLOTS = 1;
bool hasModule() const;
void setModule(AsmJSModule* module);
AsmJSModule& module() const;
void addSizeOfMisc(mozilla::MallocSizeOf mallocSizeOf, size_t* code, size_t* data);
static const Class class_;
};
typedef Handle<AsmJSModuleObject*> HandleAsmJSModule;
// This function takes over parsing of a function starting with "use asm". The
// return value indicates whether an error was reported which the caller should
// propagate. If no error was reported, the function may still fail to validate
+689
View File
@@ -0,0 +1,689 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
*
* Copyright 2015 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef wasm_binary_h
#define wasm_binary_h
#include "asmjs/WasmTypes.h"
namespace js {
class PropertyName;
namespace wasm {
enum class Stmt : uint8_t
{
Ret,
Block,
IfThen,
IfElse,
Switch,
While,
DoWhile,
ForInitInc,
ForInitNoInc,
ForNoInitNoInc,
ForNoInitInc,
Label,
Continue,
ContinueLabel,
Break,
BreakLabel,
CallInternal,
CallIndirect,
CallImport,
AtomicsFence,
// asm.js specific
// Expression statements (to be removed in the future)
I32Expr,
F32Expr,
F64Expr,
I32X4Expr,
F32X4Expr,
B32X4Expr,
Id,
Noop,
InterruptCheckHead,
InterruptCheckLoop,
DebugCheckPoint,
Bad
};
enum class I32 : uint8_t
{
// Common opcodes
GetLocal,
SetLocal,
GetGlobal,
SetGlobal,
CallInternal,
CallIndirect,
CallImport,
Conditional,
Comma,
Literal,
// Binary arith opcodes
Add,
Sub,
Mul,
SDiv,
SMod,
UDiv,
UMod,
Min,
Max,
// Unary arith opcodes
Not,
Neg,
// Bitwise opcodes
BitOr,
BitAnd,
BitXor,
BitNot,
Lsh,
ArithRsh,
LogicRsh,
// Conversion opcodes
FromF32,
FromF64,
// Math builtin opcodes
Clz,
Abs,
// Comparison opcodes
// Ordering matters (EmitComparison expects signed opcodes to be placed
// before unsigned opcodes)
EqI32,
NeI32,
SLtI32,
SLeI32,
SGtI32,
SGeI32,
ULtI32,
ULeI32,
UGtI32,
UGeI32,
EqF32,
NeF32,
LtF32,
LeF32,
GtF32,
GeF32,
EqF64,
NeF64,
LtF64,
LeF64,
GtF64,
GeF64,
// Heap accesses opcodes
SLoad8,
SLoad16,
SLoad32,
ULoad8,
ULoad16,
ULoad32,
Store8,
Store16,
Store32,
// Atomics opcodes
AtomicsCompareExchange,
AtomicsExchange,
AtomicsLoad,
AtomicsStore,
AtomicsBinOp,
// SIMD opcodes
I32X4ExtractLane,
B32X4ExtractLane,
B32X4AllTrue,
B32X4AnyTrue,
// Specific to AsmJS
Id,
Bad
};
enum class F32 : uint8_t
{
// Common opcodes
GetLocal,
SetLocal,
GetGlobal,
SetGlobal,
CallInternal,
CallIndirect,
CallImport,
Conditional,
Comma,
Literal,
// Binary arith opcodes
Add,
Sub,
Mul,
Div,
Min,
Max,
Neg,
// Math builtin opcodes
Abs,
Sqrt,
Ceil,
Floor,
// Conversion opcodes
FromF64,
FromS32,
FromU32,
// Heap accesses opcodes
Load,
StoreF32,
StoreF64,
// SIMD opcodes
F32X4ExtractLane,
// asm.js specific
Id,
Bad
};
enum class F64 : uint8_t
{
// Common opcodes
GetLocal,
SetLocal,
GetGlobal,
SetGlobal,
CallInternal,
CallIndirect,
CallImport,
Conditional,
Comma,
Literal,
// Binary arith opcodes
Add,
Sub,
Mul,
Div,
Min,
Max,
Mod,
Neg,
// Math builtin opcodes
Abs,
Sqrt,
Ceil,
Floor,
Sin,
Cos,
Tan,
Asin,
Acos,
Atan,
Exp,
Log,
Pow,
Atan2,
// Conversions opcodes
FromF32,
FromS32,
FromU32,
// Heap accesses opcodes
Load,
StoreF32,
StoreF64,
// asm.js specific
Id,
Bad
};
enum class I32X4 : uint8_t
{
// Common opcodes
GetLocal,
SetLocal,
GetGlobal,
SetGlobal,
CallInternal,
CallIndirect,
CallImport,
Conditional,
Comma,
Literal,
// Specific opcodes
Ctor,
Unary,
Binary,
BinaryBitwise,
BinaryShift,
ReplaceLane,
FromF32X4,
FromF32X4Bits,
Swizzle,
Shuffle,
Select,
Splat,
Load,
Store,
// asm.js specific
Id,
Bad
};
enum class F32X4 : uint8_t
{
// Common opcodes
GetLocal,
SetLocal,
GetGlobal,
SetGlobal,
CallInternal,
CallIndirect,
CallImport,
Conditional,
Comma,
Literal,
// Specific opcodes
Ctor,
Unary,
Binary,
ReplaceLane,
FromI32X4,
FromI32X4Bits,
Swizzle,
Shuffle,
Select,
Splat,
Load,
Store,
// asm.js specific
Id,
Bad
};
enum class B32X4 : uint8_t
{
// Common opcodes
GetLocal,
SetLocal,
GetGlobal,
SetGlobal,
CallInternal,
CallIndirect,
CallImport,
Conditional,
Comma,
Literal,
// Specific opcodes
Ctor,
Unary,
Binary,
BinaryCompI32X4,
BinaryCompF32X4,
BinaryBitwise,
ReplaceLane,
Splat,
// asm.js specific
Id,
Bad
};
enum NeedsBoundsCheck : uint8_t
{
NO_BOUNDS_CHECK,
NEEDS_BOUNDS_CHECK
};
typedef Vector<uint8_t, 0, SystemAllocPolicy> Bytecode;
typedef UniquePtr<Bytecode> UniqueBytecode;
// The Encoder class recycles (through its constructor) or creates a new Bytecode (through its
// init() method). Its Bytecode is released when it's done building the wasm IR in finish().
class Encoder
{
UniqueBytecode bytecode_;
mozilla::DebugOnly<bool> done_;
template<class T>
MOZ_WARN_UNUSED_RESULT
bool write(T v, size_t* offset) {
if (offset)
*offset = bytecode_->length();
return bytecode_->append(reinterpret_cast<uint8_t*>(&v), sizeof(T));
}
public:
Encoder()
: bytecode_(nullptr),
done_(false)
{}
bool init(UniqueBytecode bytecode) {
if (bytecode) {
bytecode_ = mozilla::Move(bytecode);
bytecode_->clear();
return true;
}
bytecode_ = MakeUnique<Bytecode>();
return !!bytecode_;
}
size_t bytecodeOffset() const { return bytecode_->length(); }
bool empty() const { return bytecodeOffset() == 0; }
UniqueBytecode finish() {
MOZ_ASSERT(!done_);
done_ = true;
return mozilla::Move(bytecode_);
}
MOZ_WARN_UNUSED_RESULT bool
writeU8(uint8_t i, size_t* offset = nullptr) { return write<uint8_t>(i, offset); }
MOZ_WARN_UNUSED_RESULT bool
writeI32(int32_t i, size_t* offset = nullptr) { return write<int32_t>(i, offset); }
MOZ_WARN_UNUSED_RESULT bool
writeU32(uint32_t i, size_t* offset = nullptr) { return write<uint32_t>(i, offset); }
MOZ_WARN_UNUSED_RESULT bool
writeF32(float f, size_t* offset = nullptr) { return write<float>(f, offset); }
MOZ_WARN_UNUSED_RESULT bool
writeF64(double d, size_t* offset = nullptr) { return write<double>(d, offset); }
MOZ_WARN_UNUSED_RESULT bool
writeI32X4(const int32_t* i4, size_t* offset = nullptr) {
if (!writeI32(i4[0], offset))
return false;
for (size_t i = 1; i < 4; i++) {
if (!writeI32(i4[i]))
return false;
}
return true;
}
MOZ_WARN_UNUSED_RESULT bool
writeF32X4(const float* f4, size_t* offset = nullptr) {
if (!writeF32(f4[0], offset))
return false;
for (size_t i = 1; i < 4; i++) {
if (!writeF32(f4[i]))
return false;
}
return true;
}
#ifdef DEBUG
bool pcIsPatchable(size_t pc, unsigned size) const {
bool patchable = true;
for (unsigned i = 0; patchable && i < size; i++)
patchable &= Stmt((*bytecode_)[pc]) == Stmt::Bad;
return patchable;
}
#endif
void patchU8(size_t pc, uint8_t i) {
MOZ_ASSERT(pcIsPatchable(pc, sizeof(uint8_t)));
(*bytecode_)[pc] = i;
}
template<class T>
void patch32(size_t pc, T i) {
static_assert(sizeof(T) == sizeof(uint32_t),
"patch32 must be used with 32-bits wide types");
MOZ_ASSERT(pcIsPatchable(pc, sizeof(uint32_t)));
memcpy(&(*bytecode_)[pc], &i, sizeof(uint32_t));
}
void patchSig(size_t pc, const LifoSig* ptr) {
MOZ_ASSERT(pcIsPatchable(pc, sizeof(LifoSig*)));
memcpy(&(*bytecode_)[pc], &ptr, sizeof(LifoSig*));
}
};
class Decoder
{
const Bytecode& bytecode_;
size_t cur_;
template<class T>
MOZ_WARN_UNUSED_RESULT
bool read(T* out) {
if (uintptr_t(bytecode_.length() - cur_) < sizeof(T))
return false;
memcpy((void*)out, &bytecode_[cur_], sizeof(T));
cur_ += sizeof(T);
return true;
}
template<class T>
T uncheckedRead() {
MOZ_ASSERT(uintptr_t(bytecode_.length() - cur_) >= sizeof(T));
T ret;
memcpy(&ret, &bytecode_[cur_], sizeof(T));
cur_ += sizeof(T);
return ret;
}
public:
explicit Decoder(const Bytecode& bytecode)
: bytecode_(bytecode),
cur_(0)
{}
bool done() const { return cur_ == bytecode_.length(); }
void assertCurrentIs(const DebugOnly<size_t> offset) const {
MOZ_ASSERT(offset == cur_);
}
// The fallible unpacking API should be used when we're not assuming
// anything about the bytecode, in particular if it is well-formed.
MOZ_WARN_UNUSED_RESULT bool readU8 (uint8_t* i) { return read(i); }
MOZ_WARN_UNUSED_RESULT bool readI32(int32_t* i) { return read(i); }
MOZ_WARN_UNUSED_RESULT bool readF32(float* f) { return read(f); }
MOZ_WARN_UNUSED_RESULT bool readU32(uint32_t* u) { return read(u); }
MOZ_WARN_UNUSED_RESULT bool readF64(double* d) { return read(d); }
MOZ_WARN_UNUSED_RESULT bool readSig(const LifoSig* sig) { return read(sig); }
MOZ_WARN_UNUSED_RESULT bool readI32X4(jit::SimdConstant* c) {
int32_t v[4] = { 0, 0, 0, 0 };
for (size_t i = 0; i < 4; i++) {
if (!readI32(&v[i]))
return false;
}
*c = jit::SimdConstant::CreateX4(v[0], v[1], v[2], v[3]);
return true;
}
MOZ_WARN_UNUSED_RESULT bool readF32X4(jit::SimdConstant* c) {
float v[4] = { 0., 0., 0., 0. };
for (size_t i = 0; i < 4; i++) {
if (!readF32(&v[i]))
return false;
}
*c = jit::SimdConstant::CreateX4(v[0], v[1], v[2], v[3]);
return true;
}
// The unfallible unpacking API should be used when we are sure that the
// bytecode is well-formed.
uint8_t uncheckedReadU8 () { return uncheckedRead<uint8_t>(); }
int32_t uncheckedReadI32() { return uncheckedRead<int32_t>(); }
float uncheckedReadF32() { return uncheckedRead<float>(); }
uint32_t uncheckedReadU32() { return uncheckedRead<uint32_t>(); }
double uncheckedReadF64() { return uncheckedRead<double>(); }
const LifoSig* uncheckedReadSig() { return uncheckedRead<const LifoSig*>(); }
jit::SimdConstant uncheckedReadI32X4() {
int32_t v[4] = { 0, 0, 0, 0 };
for (size_t i = 0; i < 4; i++)
v[i] = uncheckedReadI32();
return jit::SimdConstant::CreateX4(v[0], v[1], v[2], v[3]);
}
jit::SimdConstant uncheckedReadF32X4() {
float v[4] = { 0., 0., 0., 0. };
for (size_t i = 0; i < 4; i++)
v[i] = uncheckedReadF32();
return jit::SimdConstant::CreateX4(v[0], v[1], v[2], v[3]);
}
};
// Source coordinates for a call site. As they're read sequentially, we
// don't need to store the call's bytecode offset, unless we want to
// check its correctness in debug mode.
struct SourceCoords {
DebugOnly<size_t> offset; // after call opcode
uint32_t line;
uint32_t column;
};
typedef Vector<SourceCoords, 0, SystemAllocPolicy> SourceCoordsVector;
typedef Vector<ValType, 0, SystemAllocPolicy> ValTypeVector;
// The FuncBytecode class contains the intermediate representation of a
// parsed/decoded and validated asm.js/WebAssembly function. The FuncBytecode
// lives only until it is fully compiled.
class FuncBytecode
{
// Note: this unrooted field assumes AutoKeepAtoms via TokenStream via
// asm.js compilation.
PropertyName* name_;
unsigned line_;
unsigned column_;
SourceCoordsVector callSourceCoords_;
uint32_t index_;
const LifoSig& sig_;
UniqueBytecode bytecode_;
ValTypeVector localVars_;
unsigned generateTime_;
public:
FuncBytecode(PropertyName* name,
unsigned line,
unsigned column,
SourceCoordsVector&& sourceCoords,
uint32_t index,
const LifoSig& sig,
UniqueBytecode bytecode,
ValTypeVector&& localVars,
unsigned generateTime)
: name_(name),
line_(line),
column_(column),
callSourceCoords_(mozilla::Move(sourceCoords)),
index_(index),
sig_(sig),
bytecode_(mozilla::Move(bytecode)),
localVars_(mozilla::Move(localVars)),
generateTime_(generateTime)
{}
UniqueBytecode recycleBytecode() { return mozilla::Move(bytecode_); }
PropertyName* name() const { return name_; }
unsigned line() const { return line_; }
unsigned column() const { return column_; }
const SourceCoords& sourceCoords(size_t i) const { return callSourceCoords_[i]; }
uint32_t index() const { return index_; }
const LifoSig& sig() const { return sig_; }
const Bytecode& bytecode() const { return *bytecode_; }
size_t numLocalVars() const { return localVars_.length(); }
ValType localVarType(size_t i) const { return localVars_[i]; }
size_t numLocals() const { return sig_.args().length() + numLocalVars(); }
unsigned generateTime() const { return generateTime_; }
};
typedef UniquePtr<FuncBytecode> UniqueFuncBytecode;
} // namespace wasm
} // namespace js
#endif // wasm_binary_h
+1 -12
View File
@@ -18,8 +18,6 @@
#include "asmjs/WasmFrameIterator.h"
#include "jsatom.h"
#include "asmjs/WasmModule.h"
#include "jit/MacroAssembler-inl.h"
@@ -109,16 +107,7 @@ FrameIterator::functionDisplayAtom() const
MOZ_ASSERT(!done());
const char* chars = module_->functionName(codeRange_->funcNameIndex());
UTF8Chars utf8(chars, strlen(chars));
size_t twoByteLength;
UniquePtr<char16_t> twoByte(JS::UTF8CharsToNewTwoByteCharsZ(cx_, utf8, &twoByteLength).get());
if (!twoByte) {
cx_->clearPendingException();
return cx_->names().empty;
}
JSAtom* atom = AtomizeChars(cx_, twoByte.get(), twoByteLength);
JSAtom* atom = AtomizeUTF8Chars(cx_, chars, strlen(chars));
if (!atom) {
cx_->clearPendingException();
return cx_->names().empty;
+120 -99
View File
@@ -35,21 +35,19 @@ static const unsigned COMPILATION_LIFO_DEFAULT_CHUNK_SIZE = 64 * 1024;
ModuleGenerator::ModuleGenerator(ExclusiveContext* cx)
: cx_(cx),
args_(cx),
globalBytes_(InitialGlobalDataBytes),
slowFuncs_(cx),
lifo_(GENERATOR_LIFO_DEFAULT_CHUNK_SIZE),
jcx_(CompileRuntime::get(cx->compartment()->runtimeFromAnyThread())),
alloc_(&lifo_),
masm_(MacroAssembler::AsmJSToken(), alloc_),
sigs_(cx),
funcEntryOffsets_(cx),
exportFuncIndices_(cx),
funcIndexToExport_(cx),
parallel_(false),
outstanding_(0),
tasks_(cx),
freeTasks_(cx),
funcBytes_(0),
funcEntryOffsets_(cx),
exportFuncIndices_(cx),
activeFunc_(nullptr),
finishedFuncs_(false)
{
@@ -109,11 +107,18 @@ ParallelCompilationEnabled(ExclusiveContext* cx)
bool
ModuleGenerator::init()
{
staticLinkData_ = cx_->make_unique<StaticLinkData>();
if (!staticLinkData_)
module_ = cx_->make_unique<ModuleData>();
if (!module_)
return false;
if (!sigs_.init())
module_->globalBytes = InitialGlobalDataBytes;
module_->compileArgs = CompileArgs(cx_);
link_ = cx_->make_unique<StaticLinkData>();
if (!link_)
return false;
if (!sigs_.init() || !funcIndexToExport_.init())
return false;
uint32_t numTasks;
@@ -139,7 +144,7 @@ ModuleGenerator::init()
return false;
JSRuntime* runtime = cx_->compartment()->runtimeFromAnyThread();
for (size_t i = 0; i < numTasks; i++)
tasks_.infallibleEmplaceBack(runtime, args_, COMPILATION_LIFO_DEFAULT_CHUNK_SIZE);
tasks_.infallibleEmplaceBack(runtime, args(), COMPILATION_LIFO_DEFAULT_CHUNK_SIZE);
if (!freeTasks_.reserve(numTasks))
return false;
@@ -152,13 +157,17 @@ ModuleGenerator::init()
bool
ModuleGenerator::allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* globalDataOffset)
{
uint32_t pad = ComputeByteAlignment(globalBytes_, align);
if (UINT32_MAX - globalBytes_ < pad + bytes)
uint32_t globalBytes = module_->globalBytes;
uint32_t pad = ComputeByteAlignment(globalBytes, align);
if (UINT32_MAX - globalBytes < pad + bytes)
return false;
globalBytes_ += pad;
*globalDataOffset = globalBytes_;
globalBytes_ += bytes;
globalBytes += pad;
*globalDataOffset = globalBytes;
globalBytes += bytes;
module_->globalBytes = globalBytes;
return true;
}
@@ -192,7 +201,7 @@ ModuleGenerator::finishOutstandingTask()
bool
ModuleGenerator::finishTask(IonCompileTask* task)
{
const FuncIR& func = task->func();
const FuncBytecode& func = task->func();
FuncCompileResults& results = task->results();
// Offset the recorded FuncOffsets by the offset of the function in the
@@ -217,10 +226,10 @@ ModuleGenerator::finishTask(IonCompileTask* task)
CacheableChars funcName = StringToNewUTF8CharsZ(cx_, *func.name());
if (!funcName)
return false;
uint32_t nameIndex = funcNames_.length();
if (!funcNames_.emplaceBack(Move(funcName)))
uint32_t nameIndex = module_->funcNames.length();
if (!module_->funcNames.emplaceBack(Move(funcName)))
return false;
if (!codeRanges_.emplaceBack(nameIndex, func.line(), results.offsets()))
if (!module_->codeRanges.emplaceBack(nameIndex, func.line(), results.offsets()))
return false;
// Keep a record of slow functions for printing in the final console message.
@@ -230,7 +239,6 @@ ModuleGenerator::finishTask(IonCompileTask* task)
return false;
}
task->reset();
freeTasks_.infallibleAppend(task);
return true;
}
@@ -280,42 +288,50 @@ ModuleGenerator::declareImport(MallocSig&& sig, unsigned* index)
if (!allocateGlobalBytes(Module::SizeOfImportExit, sizeof(void*), &globalDataOffset))
return false;
*index = unsigned(imports_.length());
return imports_.emplaceBack(Move(sig), globalDataOffset);
*index = unsigned(module_->imports.length());
return module_->imports.emplaceBack(Move(sig), globalDataOffset);
}
uint32_t
ModuleGenerator::numDeclaredImports() const
ModuleGenerator::numImports() const
{
return imports_.length();
return module_->imports.length();
}
uint32_t
ModuleGenerator::importExitGlobalDataOffset(uint32_t index) const
{
return imports_[index].exitGlobalDataOffset();
return module_->imports[index].exitGlobalDataOffset();
}
const MallocSig&
ModuleGenerator::importSig(uint32_t index) const
{
return imports_[index].sig();
return module_->imports[index].sig();
}
bool
ModuleGenerator::defineImport(uint32_t index, ProfilingOffsets interpExit, ProfilingOffsets jitExit)
{
Import& import = imports_[index];
Import& import = module_->imports[index];
import.initInterpExitOffset(interpExit.begin);
import.initJitExitOffset(jitExit.begin);
return codeRanges_.emplaceBack(CodeRange::ImportInterpExit, interpExit) &&
codeRanges_.emplaceBack(CodeRange::ImportJitExit, jitExit);
return module_->codeRanges.emplaceBack(CodeRange::ImportInterpExit, interpExit) &&
module_->codeRanges.emplaceBack(CodeRange::ImportJitExit, jitExit);
}
bool
ModuleGenerator::declareExport(MallocSig&& sig, uint32_t funcIndex)
ModuleGenerator::declareExport(MallocSig&& sig, uint32_t funcIndex, uint32_t* exportIndex)
{
return exports_.emplaceBack(Move(sig)) &&
FuncIndexMap::AddPtr p = funcIndexToExport_.lookupForAdd(funcIndex);
if (p) {
*exportIndex = p->value();
return true;
}
*exportIndex = module_->exports.length();
return funcIndexToExport_.add(p, funcIndex, *exportIndex) &&
module_->exports.append(Move(sig)) &&
exportFuncIndices_.append(funcIndex);
}
@@ -328,25 +344,25 @@ ModuleGenerator::exportFuncIndex(uint32_t index) const
const MallocSig&
ModuleGenerator::exportSig(uint32_t index) const
{
return exports_[index].sig();
return module_->exports[index].sig();
}
uint32_t
ModuleGenerator::numDeclaredExports() const
ModuleGenerator::numExports() const
{
return exports_.length();
return module_->exports.length();
}
bool
ModuleGenerator::defineExport(uint32_t index, Offsets offsets)
{
exports_[index].initStubOffset(offsets.begin);
return codeRanges_.emplaceBack(CodeRange::Entry, offsets);
module_->exports[index].initStubOffset(offsets.begin);
return module_->codeRanges.emplaceBack(CodeRange::Entry, offsets);
}
bool
ModuleGenerator::startFunc(PropertyName* name, unsigned line, unsigned column,
FunctionGenerator* fg)
UniqueBytecode* recycled, FunctionGenerator* fg)
{
MOZ_ASSERT(!activeFunc_);
MOZ_ASSERT(!finishedFuncs_);
@@ -355,25 +371,38 @@ ModuleGenerator::startFunc(PropertyName* name, unsigned line, unsigned column,
return false;
IonCompileTask* task = freeTasks_.popCopy();
FuncIR* func = task->lifo().new_<FuncIR>(task->lifo(), name, line, column);
if (!func)
return false;
task->init(*func);
task->reset(recycled);
fg->name_= name;
fg->line_ = line;
fg->column_ = column;
fg->m_ = this;
fg->task_ = task;
fg->func_ = func;
activeFunc_ = fg;
return true;
}
bool
ModuleGenerator::finishFunc(uint32_t funcIndex, const LifoSig& sig, unsigned generateTime,
FunctionGenerator* fg)
ModuleGenerator::finishFunc(uint32_t funcIndex, const LifoSig& sig, UniqueBytecode bytecode,
unsigned generateTime, FunctionGenerator* fg)
{
MOZ_ASSERT(activeFunc_ == fg);
fg->func_->finish(funcIndex, sig, generateTime);
UniqueFuncBytecode func = cx_->make_unique<FuncBytecode>(fg->name_,
fg->line_,
fg->column_,
Move(fg->callSourceCoords_),
funcIndex,
sig,
Move(bytecode),
Move(fg->localVars_),
generateTime
);
if (!func)
return false;
fg->task_->init(Move(func));
if (parallel_) {
if (!StartOffThreadWasmCompile(cx_, fg->task_))
@@ -388,7 +417,6 @@ ModuleGenerator::finishFunc(uint32_t funcIndex, const LifoSig& sig, unsigned gen
fg->m_ = nullptr;
fg->task_ = nullptr;
fg->func_ = nullptr;
activeFunc_ = nullptr;
return true;
}
@@ -419,7 +447,7 @@ ModuleGenerator::finishFuncs()
masm_.patchCall(callerOffset, calleeOffset);
}
funcBytes_ = masm_.size();
module_->functionBytes = masm_.size();
finishedFuncs_ = true;
return true;
}
@@ -439,7 +467,7 @@ ModuleGenerator::declareFuncPtrTable(uint32_t numElems, uint32_t* index)
if (!allocateGlobalBytes(numElems * sizeof(void*), sizeof(void*), &globalDataOffset))
return false;
StaticLinkData::FuncPtrTableVector& tables = staticLinkData_->funcPtrTables;
StaticLinkData::FuncPtrTableVector& tables = link_->funcPtrTables;
*index = tables.length();
if (!tables.emplaceBack(globalDataOffset))
@@ -454,7 +482,7 @@ ModuleGenerator::declareFuncPtrTable(uint32_t numElems, uint32_t* index)
uint32_t
ModuleGenerator::funcPtrTableGlobalDataOffset(uint32_t index) const
{
return staticLinkData_->funcPtrTables[index].globalDataOffset;
return link_->funcPtrTables[index].globalDataOffset;
}
void
@@ -462,7 +490,7 @@ ModuleGenerator::defineFuncPtrTable(uint32_t index, const Vector<uint32_t>& elem
{
MOZ_ASSERT(finishedFuncs_);
StaticLinkData::FuncPtrTable& table = staticLinkData_->funcPtrTables[index];
StaticLinkData::FuncPtrTable& table = link_->funcPtrTables[index];
MOZ_ASSERT(table.elemOffsets.length() == elemFuncIndices.length());
for (size_t i = 0; i < elemFuncIndices.length(); i++)
@@ -473,69 +501,74 @@ bool
ModuleGenerator::defineInlineStub(Offsets offsets)
{
MOZ_ASSERT(finishedFuncs_);
return codeRanges_.emplaceBack(CodeRange::Inline, offsets);
return module_->codeRanges.emplaceBack(CodeRange::Inline, offsets);
}
bool
ModuleGenerator::defineSyncInterruptStub(ProfilingOffsets offsets)
{
MOZ_ASSERT(finishedFuncs_);
return codeRanges_.emplaceBack(CodeRange::Interrupt, offsets);
return module_->codeRanges.emplaceBack(CodeRange::Interrupt, offsets);
}
bool
ModuleGenerator::defineAsyncInterruptStub(Offsets offsets)
{
MOZ_ASSERT(finishedFuncs_);
staticLinkData_->pod.interruptOffset = offsets.begin;
return codeRanges_.emplaceBack(CodeRange::Inline, offsets);
link_->pod.interruptOffset = offsets.begin;
return module_->codeRanges.emplaceBack(CodeRange::Inline, offsets);
}
bool
ModuleGenerator::defineOutOfBoundsStub(Offsets offsets)
{
MOZ_ASSERT(finishedFuncs_);
staticLinkData_->pod.outOfBoundsOffset = offsets.begin;
return codeRanges_.emplaceBack(CodeRange::Inline, offsets);
link_->pod.outOfBoundsOffset = offsets.begin;
return module_->codeRanges.emplaceBack(CodeRange::Inline, offsets);
}
Module*
bool
ModuleGenerator::finish(HeapUsage heapUsage,
Module::MutedBool mutedErrors,
MutedErrorsBool mutedErrors,
CacheableChars filename,
CacheableTwoByteChars displayURL,
UniqueStaticLinkData* staticLinkData,
UniqueModuleData* module,
UniqueStaticLinkData* linkData,
SlowFunctionVector* slowFuncs)
{
MOZ_ASSERT(!activeFunc_);
MOZ_ASSERT(finishedFuncs_);
module_->heapUsage = heapUsage;
module_->mutedErrors = mutedErrors;
module_->filename = Move(filename);
if (!GenerateStubs(*this, UsesHeap(heapUsage)))
return nullptr;
return false;
masm_.finish();
if (masm_.oom())
return nullptr;
return false;
// Start global data on a new page so JIT code may be given independent
// protection flags. Note assumption that global data starts right after
// code below.
uint32_t codeBytes = AlignBytes(masm_.bytesNeeded(), AsmJSPageSize);
module_->codeBytes = AlignBytes(masm_.bytesNeeded(), AsmJSPageSize);
// Inflate the global bytes up to page size so that the total bytes are a
// page size (as required by the allocator functions).
globalBytes_ = AlignBytes(globalBytes_, AsmJSPageSize);
uint32_t totalBytes = codeBytes + globalBytes_;
module_->globalBytes = AlignBytes(module_->globalBytes, AsmJSPageSize);
// Allocate the code (guarded by a UniquePtr until it is given to the Module).
UniqueCodePtr code = AllocateCode(cx_, totalBytes);
if (!code)
return nullptr;
module_->code = AllocateCode(cx_, module_->totalBytes());
if (!module_->code)
return false;
// Delay flushing until Module::dynamicallyLink. The flush-inhibited range
// is set by executableCopy.
AutoFlushICache afc("ModuleGenerator::finish", /* inhibit = */ true);
masm_.executableCopy(code.get());
uint8_t* code = module_->code.get();
masm_.executableCopy(code);
// c.f. JitCode::copyFrom
MOZ_ASSERT(masm_.jumpRelocationTableBytes() == 0);
@@ -545,16 +578,18 @@ ModuleGenerator::finish(HeapUsage heapUsage,
// Convert the CallSiteAndTargetVector (needed during generation) to a
// CallSiteVector (what is stored in the Module).
CallSiteVector callSites;
if (!callSites.appendAll(masm_.callSites()))
return nullptr;
if (!module_->callSites.appendAll(masm_.callSites()))
return false;
// The MacroAssembler has accumulated all the heap accesses during codegen.
module_->heapAccesses = masm_.extractHeapAccesses();
// Add links to absolute addresses identified symbolically.
StaticLinkData::SymbolicLinkArray& symbolicLinks = staticLinkData_->symbolicLinks;
StaticLinkData::SymbolicLinkArray& symbolicLinks = link_->symbolicLinks;
for (size_t i = 0; i < masm_.numAsmJSAbsoluteAddresses(); i++) {
AsmJSAbsoluteAddress src = masm_.asmJSAbsoluteAddress(i);
if (!symbolicLinks[src.target].append(src.patchAt.offset()))
return nullptr;
return false;
}
// Relative link metadata: absolute addresses that refer to another point within
@@ -567,8 +602,8 @@ ModuleGenerator::finish(HeapUsage heapUsage,
StaticLinkData::InternalLink link(StaticLinkData::InternalLink::CodeLabel);
link.patchAtOffset = masm_.labelToPatchOffset(*cl.patchAt());
link.targetOffset = cl.target()->offset();
if (!staticLinkData_->internalLinks.append(link))
return nullptr;
if (!link_->internalLinks.append(link))
return false;
}
#if defined(JS_CODEGEN_X86)
@@ -579,9 +614,9 @@ ModuleGenerator::finish(HeapUsage heapUsage,
AsmJSGlobalAccess a = masm_.asmJSGlobalAccess(i);
StaticLinkData::InternalLink link(StaticLinkData::InternalLink::RawPointer);
link.patchAtOffset = masm_.labelToPatchOffset(a.patchAt);
link.targetOffset = codeBytes + a.globalDataOffset;
if (!staticLinkData_->internalLinks.append(link))
return nullptr;
link.targetOffset = module_->codeBytes + a.globalDataOffset;
if (!link_->internalLinks.append(link))
return false;
}
#endif
@@ -593,38 +628,24 @@ ModuleGenerator::finish(HeapUsage heapUsage,
size_t off = masm_.longJump(i);
StaticLinkData::InternalLink link(StaticLinkData::InternalLink::InstructionImmediate);
link.patchAtOffset = off;
link.targetOffset = Assembler::ExtractInstructionImmediate(code.get() + off) -
uintptr_t(code.get());
if (!staticLinkData_->internalLinks.append(link))
return nullptr;
link.targetOffset = Assembler::ExtractInstructionImmediate(code + off) - uintptr_t(code);
if (!link_->internalLinks.append(link))
return false;
}
#endif
#if defined(JS_CODEGEN_X64)
// Global data accesses on x64 use rip-relative addressing and thus do
// not need patching after deserialization.
uint8_t* globalData = code.get() + codeBytes;
uint8_t* globalData = code + module_->codeBytes;
for (size_t i = 0; i < masm_.numAsmJSGlobalAccesses(); i++) {
AsmJSGlobalAccess a = masm_.asmJSGlobalAccess(i);
masm_.patchAsmJSGlobalAccess(a.patchAt, code.get(), globalData, a.globalDataOffset);
masm_.patchAsmJSGlobalAccess(a.patchAt, code, globalData, a.globalDataOffset);
}
#endif
*staticLinkData = Move(staticLinkData_);
*module = Move(module_);
*linkData = Move(link_);
*slowFuncs = Move(slowFuncs_);
return cx_->new_<Module>(args_,
funcBytes_,
codeBytes,
globalBytes_,
heapUsage,
mutedErrors,
Move(code),
Move(imports_),
Move(exports_),
masm_.extractHeapAccesses(),
Move(codeRanges_),
Move(callSites),
Move(funcNames_),
Move(filename),
Move(displayURL));
return true;
}
+54 -33
View File
@@ -19,8 +19,8 @@
#ifndef wasm_generator_h
#define wasm_generator_h
#include "asmjs/WasmBinary.h"
#include "asmjs/WasmIonCompile.h"
#include "asmjs/WasmIR.h"
#include "asmjs/WasmModule.h"
#include "jit/MacroAssembler.h"
@@ -55,6 +55,7 @@ class MOZ_STACK_CLASS ModuleGenerator
{
typedef Vector<uint32_t> FuncOffsetVector;
typedef Vector<uint32_t> FuncIndexVector;
typedef HashMap<uint32_t, uint32_t> FuncIndexMap;
struct SigHashPolicy
{
@@ -65,17 +66,10 @@ class MOZ_STACK_CLASS ModuleGenerator
typedef HashSet<const LifoSig*, SigHashPolicy> SigSet;
ExclusiveContext* cx_;
CompileArgs args_;
// Data handed over to the Module in finish()
uint32_t globalBytes_;
ImportVector imports_;
ExportVector exports_;
CodeRangeVector codeRanges_;
CacheableCharsVector funcNames_;
// Data handed back to the caller in finish()
UniqueStaticLinkData staticLinkData_;
UniqueModuleData module_;
UniqueStaticLinkData link_;
SlowFunctionVector slowFuncs_;
// Data scoped to the ModuleGenerator's lifetime
@@ -84,6 +78,9 @@ class MOZ_STACK_CLASS ModuleGenerator
jit::TempAllocator alloc_;
jit::MacroAssembler masm_;
SigSet sigs_;
FuncOffsetVector funcEntryOffsets_;
FuncIndexVector exportFuncIndices_;
FuncIndexMap funcIndexToExport_;
// Parallel compilation
bool parallel_;
@@ -91,10 +88,7 @@ class MOZ_STACK_CLASS ModuleGenerator
Vector<IonCompileTask> tasks_;
Vector<IonCompileTask*> freeTasks_;
// Function compilation
uint32_t funcBytes_;
FuncOffsetVector funcEntryOffsets_;
FuncIndexVector exportFuncIndices_;
// Assertions
DebugOnly<FunctionGenerator*> activeFunc_;
DebugOnly<bool> finishedFuncs_;
@@ -108,7 +102,7 @@ class MOZ_STACK_CLASS ModuleGenerator
bool init();
CompileArgs args() const { return args_; }
CompileArgs args() const { return module_->compileArgs; }
jit::MacroAssembler& masm() { return masm_; }
const FuncOffsetVector& funcEntryOffsets() const { return funcEntryOffsets_; }
@@ -119,21 +113,23 @@ class MOZ_STACK_CLASS ModuleGenerator
// Imports:
bool declareImport(MallocSig&& sig, uint32_t* index);
uint32_t numDeclaredImports() const;
uint32_t numImports() const;
uint32_t importExitGlobalDataOffset(uint32_t index) const;
const MallocSig& importSig(uint32_t index) const;
bool defineImport(uint32_t index, ProfilingOffsets interpExit, ProfilingOffsets jitExit);
// Exports:
bool declareExport(MallocSig&& sig, uint32_t funcIndex);
uint32_t numDeclaredExports() const;
bool declareExport(MallocSig&& sig, uint32_t funcIndex, uint32_t* exportIndex);
uint32_t numExports() const;
uint32_t exportFuncIndex(uint32_t index) const;
const MallocSig& exportSig(uint32_t index) const;
bool defineExport(uint32_t index, Offsets offsets);
// Functions:
bool startFunc(PropertyName* name, unsigned line, unsigned column, FunctionGenerator* fg);
bool finishFunc(uint32_t funcIndex, const LifoSig& sig, unsigned generateTime, FunctionGenerator* fg);
bool startFunc(PropertyName* name, unsigned line, unsigned column, UniqueBytecode* recycled,
FunctionGenerator* fg);
bool finishFunc(uint32_t funcIndex, const LifoSig& sig, UniqueBytecode bytecode,
unsigned generateTime, FunctionGenerator* fg);
bool finishFuncs();
// Function-pointer tables:
@@ -147,14 +143,16 @@ class MOZ_STACK_CLASS ModuleGenerator
bool defineAsyncInterruptStub(Offsets offsets);
bool defineOutOfBoundsStub(Offsets offsets);
// Null return indicates failure. The caller must immediately root a
// non-null return value.
Module* finish(HeapUsage heapUsage,
Module::MutedBool mutedErrors,
CacheableChars filename,
CacheableTwoByteChars displayURL,
UniqueStaticLinkData* staticLinkData,
SlowFunctionVector* slowFuncs);
// Return a ModuleData object which may be used to construct a Module, the
// StaticLinkData required to call Module::staticallyLink, and the list of
// functions that took a long time to compile.
bool finish(HeapUsage heapUsage,
MutedErrorsBool mutedErrors,
CacheableChars filename,
CacheableTwoByteChars displayURL,
UniqueModuleData* module,
UniqueStaticLinkData* staticLinkData,
SlowFunctionVector* slowFuncs);
};
// A FunctionGenerator encapsulates the generation of a single function body.
@@ -166,13 +164,36 @@ class MOZ_STACK_CLASS FunctionGenerator
{
friend class ModuleGenerator;
ModuleGenerator* m_;
IonCompileTask* task_;
FuncIR* func_;
ModuleGenerator* m_;
IonCompileTask* task_;
// Function metadata created during function generation, then handed over
// to the FuncBytecode in ModuleGenerator::finishFunc().
SourceCoordsVector callSourceCoords_;
ValTypeVector localVars_;
// Note: this unrooted field assumes AutoKeepAtoms via TokenStream via
// asm.js compilation.
PropertyName* name_;
unsigned line_;
unsigned column_;
public:
FunctionGenerator() : m_(nullptr), task_(nullptr), func_(nullptr) {}
FuncIR& func() const { MOZ_ASSERT(func_); return *func_; }
FunctionGenerator()
: m_(nullptr),
task_(nullptr),
name_(nullptr),
line_(0),
column_(0)
{}
bool addSourceCoords(size_t byteOffset, uint32_t line, uint32_t column) {
SourceCoords sc = { byteOffset, line, column };
return callSourceCoords_.append(sc);
}
bool addVariable(ValType v) {
return localVars_.append(v);
}
};
} // namespace wasm
-594
View File
@@ -1,594 +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:
*
* Copyright 2015 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef wasm_ir_h
#define wasm_ir_h
#include "asmjs/WasmTypes.h"
namespace js {
class PropertyName;
namespace wasm {
enum class Stmt : uint8_t
{
Ret,
Block,
IfThen,
IfElse,
Switch,
While,
DoWhile,
ForInitInc,
ForInitNoInc,
ForNoInitNoInc,
ForNoInitInc,
Label,
Continue,
ContinueLabel,
Break,
BreakLabel,
CallInternal,
CallIndirect,
CallImport,
AtomicsFence,
// asm.js specific
// Expression statements (to be removed in the future)
I32Expr,
F32Expr,
F64Expr,
I32X4Expr,
F32X4Expr,
B32X4Expr,
Id,
Noop,
InterruptCheckHead,
InterruptCheckLoop,
DebugCheckPoint,
Bad
};
enum class I32 : uint8_t
{
// Common opcodes
GetLocal,
SetLocal,
GetGlobal,
SetGlobal,
CallInternal,
CallIndirect,
CallImport,
Conditional,
Comma,
Literal,
// Binary arith opcodes
Add,
Sub,
Mul,
SDiv,
SMod,
UDiv,
UMod,
Min,
Max,
// Unary arith opcodes
Not,
Neg,
// Bitwise opcodes
BitOr,
BitAnd,
BitXor,
BitNot,
Lsh,
ArithRsh,
LogicRsh,
// Conversion opcodes
FromF32,
FromF64,
// Math builtin opcodes
Clz,
Abs,
// Comparison opcodes
// Ordering matters (EmitComparison expects signed opcodes to be placed
// before unsigned opcodes)
EqI32,
NeI32,
SLtI32,
SLeI32,
SGtI32,
SGeI32,
ULtI32,
ULeI32,
UGtI32,
UGeI32,
EqF32,
NeF32,
LtF32,
LeF32,
GtF32,
GeF32,
EqF64,
NeF64,
LtF64,
LeF64,
GtF64,
GeF64,
// Heap accesses opcodes
SLoad8,
SLoad16,
SLoad32,
ULoad8,
ULoad16,
ULoad32,
Store8,
Store16,
Store32,
// Atomics opcodes
AtomicsCompareExchange,
AtomicsExchange,
AtomicsLoad,
AtomicsStore,
AtomicsBinOp,
// SIMD opcodes
I32X4ExtractLane,
B32X4ExtractLane,
B32X4AllTrue,
B32X4AnyTrue,
// Specific to AsmJS
Id,
Bad
};
enum class F32 : uint8_t
{
// Common opcodes
GetLocal,
SetLocal,
GetGlobal,
SetGlobal,
CallInternal,
CallIndirect,
CallImport,
Conditional,
Comma,
Literal,
// Binary arith opcodes
Add,
Sub,
Mul,
Div,
Min,
Max,
Neg,
// Math builtin opcodes
Abs,
Sqrt,
Ceil,
Floor,
// Conversion opcodes
FromF64,
FromS32,
FromU32,
// Heap accesses opcodes
Load,
StoreF32,
StoreF64,
// SIMD opcodes
F32X4ExtractLane,
// asm.js specific
Id,
Bad
};
enum class F64 : uint8_t
{
// Common opcodes
GetLocal,
SetLocal,
GetGlobal,
SetGlobal,
CallInternal,
CallIndirect,
CallImport,
Conditional,
Comma,
Literal,
// Binary arith opcodes
Add,
Sub,
Mul,
Div,
Min,
Max,
Mod,
Neg,
// Math builtin opcodes
Abs,
Sqrt,
Ceil,
Floor,
Sin,
Cos,
Tan,
Asin,
Acos,
Atan,
Exp,
Log,
Pow,
Atan2,
// Conversions opcodes
FromF32,
FromS32,
FromU32,
// Heap accesses opcodes
Load,
StoreF32,
StoreF64,
// asm.js specific
Id,
Bad
};
enum class I32X4 : uint8_t
{
// Common opcodes
GetLocal,
SetLocal,
GetGlobal,
SetGlobal,
CallInternal,
CallIndirect,
CallImport,
Conditional,
Comma,
Literal,
// Specific opcodes
Ctor,
Unary,
Binary,
BinaryBitwise,
BinaryShift,
ReplaceLane,
FromF32X4,
FromF32X4Bits,
Swizzle,
Shuffle,
Select,
Splat,
Load,
Store,
// asm.js specific
Id,
Bad
};
enum class F32X4 : uint8_t
{
// Common opcodes
GetLocal,
SetLocal,
GetGlobal,
SetGlobal,
CallInternal,
CallIndirect,
CallImport,
Conditional,
Comma,
Literal,
// Specific opcodes
Ctor,
Unary,
Binary,
ReplaceLane,
FromI32X4,
FromI32X4Bits,
Swizzle,
Shuffle,
Select,
Splat,
Load,
Store,
// asm.js specific
Id,
Bad
};
enum class B32X4 : uint8_t
{
// Common opcodes
GetLocal,
SetLocal,
GetGlobal,
SetGlobal,
CallInternal,
CallIndirect,
CallImport,
Conditional,
Comma,
Literal,
// Specific opcodes
Ctor,
Unary,
Binary,
BinaryCompI32X4,
BinaryCompF32X4,
BinaryBitwise,
ReplaceLane,
Splat,
// asm.js specific
Id,
Bad
};
enum NeedsBoundsCheck : uint8_t
{
NO_BOUNDS_CHECK,
NEEDS_BOUNDS_CHECK
};
// The FuncIR class contains the intermediate representation of a parsed/decoded
// and validated asm.js/WebAssembly function. The FuncIR lives only until it
// is fully compiled. Its contents are assumed to be well-formed; all validation
// of untrusted content must happen before FuncIR generation. A FuncIR object is
// associated with a LifoAlloc allocation which contains all the memory
// referenced by the FuncIR.
class FuncIR
{
typedef Vector<ValType, 4, LifoAllocPolicy<Fallible>> ValTypeVector;
typedef Vector<uint8_t, 4096, LifoAllocPolicy<Fallible>> Bytecode;
public:
// Source coordinates for a call site. As they're read sequentially, we
// don't need to store the call's bytecode offset, unless we want to
// check its consistency in debug mode.
struct SourceCoords {
DebugOnly<uint32_t> offset; // after call opcode
uint32_t line;
uint32_t column;
};
private:
typedef Vector<SourceCoords, 4, LifoAllocPolicy<Fallible>> SourceCoordsVector;
// Note: this unrooted field assumes AutoKeepAtoms via TokenStream via
// asm.js compilation.
PropertyName* name_;
unsigned line_;
unsigned column_;
uint32_t index_;
const LifoSig* sig_;
ValTypeVector localVars_;
SourceCoordsVector callSourceCoords_;
Bytecode bytecode_;
unsigned generateTime_;
public:
FuncIR(LifoAlloc& alloc, PropertyName* name, unsigned line, unsigned column)
: name_(name),
line_(line),
column_(column),
index_(UINT_MAX),
sig_(nullptr),
localVars_(alloc),
callSourceCoords_(alloc),
bytecode_(alloc),
generateTime_(UINT_MAX)
{}
bool addVariable(ValType v) {
return localVars_.append(v);
}
bool addSourceCoords(uint32_t line, uint32_t column) {
SourceCoords sc = { bytecode_.length(), line, column };
return callSourceCoords_.append(sc);
}
void finish(uint32_t funcIndex, const LifoSig& sig, unsigned generateTime) {
MOZ_ASSERT(index_ == UINT_MAX);
MOZ_ASSERT(!sig_);
MOZ_ASSERT(generateTime_ == UINT_MAX);
index_ = funcIndex;
sig_ = &sig;
generateTime_ = generateTime;
}
private:
template<class T> size_t writePrimitive(T v) {
size_t writeAt = bytecode_.length();
if (!bytecode_.append(reinterpret_cast<uint8_t*>(&v), sizeof(T)))
return -1;
return writeAt;
}
template<class T> T readPrimitive(size_t* pc) const {
MOZ_ASSERT(*pc + sizeof(T) <= bytecode_.length());
T ret;
memcpy(&ret, &bytecode_[*pc], sizeof(T));
*pc += sizeof(T);
return ret;
}
public:
size_t writeU8(uint8_t i) { return writePrimitive<uint8_t>(i); }
size_t writeI32(int32_t i) { return writePrimitive<int32_t>(i); }
size_t writeU32(uint32_t i) { return writePrimitive<uint32_t>(i); }
size_t writeF32(float f) { return writePrimitive<float>(f); }
size_t writeF64(double d) { return writePrimitive<double>(d); }
size_t writeI32X4(const int32_t* i4) {
size_t pos = bytecode_.length();
for (size_t i = 0; i < 4; i++)
writePrimitive<int32_t>(i4[i]);
return pos;
}
size_t writeF32X4(const float* f4) {
size_t pos = bytecode_.length();
for (size_t i = 0; i < 4; i++)
writePrimitive<float>(f4[i]);
return pos;
}
uint8_t readU8 (size_t* pc) const { return readPrimitive<uint8_t>(pc); }
int32_t readI32(size_t* pc) const { return readPrimitive<int32_t>(pc); }
float readF32(size_t* pc) const { return readPrimitive<float>(pc); }
uint32_t readU32(size_t* pc) const { return readPrimitive<uint32_t>(pc); }
double readF64(size_t* pc) const { return readPrimitive<double>(pc); }
const LifoSig* readSig(size_t* pc) const { return readPrimitive<LifoSig*>(pc); }
jit::SimdConstant readI32X4(size_t* pc) const {
int32_t x = readI32(pc);
int32_t y = readI32(pc);
int32_t z = readI32(pc);
int32_t w = readI32(pc);
return jit::SimdConstant::CreateX4(x, y, z, w);
}
jit::SimdConstant readF32X4(size_t* pc) const {
float x = readF32(pc);
float y = readF32(pc);
float z = readF32(pc);
float w = readF32(pc);
return jit::SimdConstant::CreateX4(x, y, z, w);
}
#ifdef DEBUG
bool pcIsPatchable(size_t pc, unsigned size) const {
bool patchable = true;
for (unsigned i = 0; patchable && i < size; i++)
patchable &= Stmt(bytecode_[pc]) == Stmt::Bad;
return patchable;
}
#endif
void patchU8(size_t pc, uint8_t i) {
MOZ_ASSERT(pcIsPatchable(pc, sizeof(uint8_t)));
bytecode_[pc] = i;
}
template<class T>
void patch32(size_t pc, T i) {
static_assert(sizeof(T) == sizeof(uint32_t),
"patch32 must be used with 32-bits wide types");
MOZ_ASSERT(pcIsPatchable(pc, sizeof(uint32_t)));
memcpy(&bytecode_[pc], &i, sizeof(uint32_t));
}
void patchSig(size_t pc, const LifoSig* ptr) {
MOZ_ASSERT(pcIsPatchable(pc, sizeof(LifoSig*)));
memcpy(&bytecode_[pc], &ptr, sizeof(LifoSig*));
}
// Read-only interface
PropertyName* name() const { return name_; }
unsigned line() const { return line_; }
unsigned column() const { return column_; }
uint32_t index() const { MOZ_ASSERT(index_ != UINT32_MAX); return index_; }
size_t size() const { return bytecode_.length(); }
const LifoSig& sig() const { MOZ_ASSERT(sig_); return *sig_; }
size_t numLocalVars() const { return localVars_.length(); }
ValType localVarType(size_t i) const { return localVars_[i]; }
size_t numLocals() const { return sig_->args().length() + numLocalVars(); }
unsigned generateTime() const { MOZ_ASSERT(generateTime_ != UINT_MAX); return generateTime_; }
const SourceCoords& sourceCoords(size_t i) const { return callSourceCoords_[i]; }
};
} // namespace wasm
} // namespace js
#endif // wasm_ir_h
+55 -47
View File
@@ -39,8 +39,9 @@ class FunctionCompiler
typedef HashMap<size_t, BlockVector, DefaultHasher<uint32_t>, SystemAllocPolicy> UnlabeledBlockMap;
typedef Vector<size_t, 4, SystemAllocPolicy> PositionStack;
const FuncIR& func_;
size_t pc_;
const FuncBytecode& func_;
Decoder decoder_;
size_t nextId_;
size_t lastReadCallSite_;
TempAllocator& alloc_;
@@ -60,9 +61,10 @@ class FunctionCompiler
FuncCompileResults& compileResults_;
public:
FunctionCompiler(const FuncIR& func, MIRGenerator& mirGen, FuncCompileResults& compileResults)
FunctionCompiler(const FuncBytecode& func, MIRGenerator& mirGen, FuncCompileResults& compileResults)
: func_(func),
pc_(0),
decoder_(func.bytecode()),
nextId_(0),
lastReadCallSite_(0),
alloc_(mirGen.alloc()),
graph_(mirGen.graph()),
@@ -91,6 +93,8 @@ class FunctionCompiler
const LifoSig::ArgVector& args = func_.sig().args();
unsigned firstVarSlot = args.length();
if (!mirGen_.ensureBallast())
return false;
if (!newBlock(/* pred = */ nullptr, &curBlock_))
return false;
@@ -145,7 +149,7 @@ class FunctionCompiler
MOZ_ASSERT(labeledBreaks_.empty());
MOZ_ASSERT(labeledContinues_.empty());
MOZ_ASSERT(inDeadCode());
MOZ_ASSERT(pc_ == func_.size(), "all bytecode must be consumed");
MOZ_ASSERT(decoder_.done(), "all bytecode must be consumed");
}
/************************* Read-only interface (after local scope setup) */
@@ -889,9 +893,9 @@ class FunctionCompiler
return curBlock_->pop();
}
bool startPendingLoop(size_t pos, MBasicBlock** loopEntry)
bool startPendingLoop(size_t id, MBasicBlock** loopEntry)
{
if (!loopStack_.append(pos) || !breakableStack_.append(pos))
if (!loopStack_.append(id) || !breakableStack_.append(id))
return false;
if (inDeadCode()) {
*loopEntry = nullptr;
@@ -934,10 +938,10 @@ class FunctionCompiler
private:
size_t popLoop()
{
size_t pos = loopStack_.popCopy();
MOZ_ASSERT(!unlabeledContinues_.has(pos));
size_t id = loopStack_.popCopy();
MOZ_ASSERT(!unlabeledContinues_.has(id));
breakableStack_.popBack();
return pos;
return id;
}
void fixupRedundantPhis(MBasicBlock* b)
@@ -998,11 +1002,11 @@ class FunctionCompiler
public:
bool closeLoop(MBasicBlock* loopEntry, MBasicBlock* afterLoop)
{
size_t pos = popLoop();
size_t id = popLoop();
if (!loopEntry) {
MOZ_ASSERT(!afterLoop);
MOZ_ASSERT(inDeadCode());
MOZ_ASSERT(!unlabeledBreaks_.has(pos));
MOZ_ASSERT(!unlabeledBreaks_.has(id));
return true;
}
MOZ_ASSERT(loopEntry->loopDepth() == loopStack_.length() + 1);
@@ -1016,15 +1020,15 @@ class FunctionCompiler
curBlock_ = afterLoop;
if (curBlock_)
mirGraph().moveBlockToEnd(curBlock_);
return bindUnlabeledBreaks(pos);
return bindUnlabeledBreaks(id);
}
bool branchAndCloseDoWhileLoop(MDefinition* cond, MBasicBlock* loopEntry)
{
size_t pos = popLoop();
size_t id = popLoop();
if (!loopEntry) {
MOZ_ASSERT(inDeadCode());
MOZ_ASSERT(!unlabeledBreaks_.has(pos));
MOZ_ASSERT(!unlabeledBreaks_.has(id));
return true;
}
MOZ_ASSERT(loopEntry->loopDepth() == loopStack_.length() + 1);
@@ -1053,13 +1057,13 @@ class FunctionCompiler
curBlock_ = afterLoop;
}
}
return bindUnlabeledBreaks(pos);
return bindUnlabeledBreaks(id);
}
bool bindContinues(size_t pos, const LabelVector* maybeLabels)
bool bindContinues(size_t id, const LabelVector* maybeLabels)
{
bool createdJoinBlock = false;
if (UnlabeledBlockMap::Ptr p = unlabeledContinues_.lookup(pos)) {
if (UnlabeledBlockMap::Ptr p = unlabeledContinues_.lookup(id)) {
if (!bindBreaksOrContinues(&p->value(), &createdJoinBlock))
return false;
unlabeledContinues_.remove(p);
@@ -1085,10 +1089,10 @@ class FunctionCompiler
return addBreakOrContinue(loopStack_.back(), &unlabeledContinues_);
}
bool startSwitch(size_t pos, MDefinition* expr, int32_t low, int32_t high,
bool startSwitch(size_t id, MDefinition* expr, int32_t low, int32_t high,
MBasicBlock** switchBlock)
{
if (!breakableStack_.append(pos))
if (!breakableStack_.append(id))
return false;
if (inDeadCode()) {
*switchBlock = nullptr;
@@ -1129,7 +1133,7 @@ class FunctionCompiler
bool joinSwitch(MBasicBlock* switchBlock, const BlockVector& cases, MBasicBlock* defaultBlock)
{
size_t pos = breakableStack_.popCopy();
size_t id = breakableStack_.popCopy();
if (!switchBlock)
return true;
MTableSwitch* mir = switchBlock->lastIns()->toTableSwitch();
@@ -1155,24 +1159,29 @@ class FunctionCompiler
curBlock_->end(MGoto::New(alloc(), next));
curBlock_ = next;
}
return bindUnlabeledBreaks(pos);
return bindUnlabeledBreaks(id);
}
// Provides unique identifiers for internal uses in the control flow stacks;
// these ids have to grow monotonically.
unsigned nextId() { return nextId_++; }
/************************************************************ DECODING ***/
uint8_t readU8() { return func_.readU8(&pc_); }
uint32_t readU32() { return func_.readU32(&pc_); }
int32_t readI32() { return func_.readI32(&pc_); }
float readF32() { return func_.readF32(&pc_); }
double readF64() { return func_.readF64(&pc_); }
const LifoSig* readSig() { return func_.readSig(&pc_); }
SimdConstant readI32X4() { return func_.readI32X4(&pc_); }
SimdConstant readF32X4() { return func_.readF32X4(&pc_); }
uint8_t readU8() { return decoder_.uncheckedReadU8(); }
uint32_t readU32() { return decoder_.uncheckedReadU32(); }
int32_t readI32() { return decoder_.uncheckedReadI32(); }
float readF32() { return decoder_.uncheckedReadF32(); }
double readF64() { return decoder_.uncheckedReadF64(); }
const LifoSig* readSig() { return decoder_.uncheckedReadSig(); }
SimdConstant readI32X4() { return decoder_.uncheckedReadI32X4(); }
SimdConstant readF32X4() { return decoder_.uncheckedReadF32X4(); }
Stmt readStmtOp() { return Stmt(readU8()); }
void readCallLineCol(uint32_t* line, uint32_t* column) {
const FuncIR::SourceCoords& sc = func_.sourceCoords(lastReadCallSite_++);
MOZ_ASSERT(pc_ == sc.offset);
const SourceCoords& sc = func_.sourceCoords(lastReadCallSite_++);
decoder_.assertCurrentIs(sc.offset);
*line = sc.line;
*column = sc.column;
}
@@ -1181,8 +1190,7 @@ class FunctionCompiler
MOZ_ASSERT(Stmt(readU8()) == Stmt::DebugCheckPoint);
}
bool done() const { return pc_ == func_.size(); }
size_t pc() const { return pc_; }
bool done() const { return decoder_.done(); }
/*************************************************************************/
private:
@@ -1265,10 +1273,10 @@ class FunctionCompiler
return true;
}
bool bindUnlabeledBreaks(size_t pos)
bool bindUnlabeledBreaks(size_t id)
{
bool createdJoinBlock = false;
if (UnlabeledBlockMap::Ptr p = unlabeledBreaks_.lookup(pos)) {
if (UnlabeledBlockMap::Ptr p = unlabeledBreaks_.lookup(id)) {
if (!bindBreaksOrContinues(&p->value(), &createdJoinBlock))
return false;
unlabeledBreaks_.remove(p);
@@ -2286,10 +2294,10 @@ EmitInterruptCheckLoop(FunctionCompiler& f)
static bool
EmitWhile(FunctionCompiler& f, const LabelVector* maybeLabels)
{
size_t headPc = f.pc();
size_t headId = f.nextId();
MBasicBlock* loopEntry;
if (!f.startPendingLoop(headPc, &loopEntry))
if (!f.startPendingLoop(headId, &loopEntry))
return false;
MDefinition* condDef;
@@ -2303,7 +2311,7 @@ EmitWhile(FunctionCompiler& f, const LabelVector* maybeLabels)
if (!EmitStatement(f))
return false;
if (!f.bindContinues(headPc, maybeLabels))
if (!f.bindContinues(headId, maybeLabels))
return false;
return f.closeLoop(loopEntry, afterLoop);
@@ -2314,7 +2322,7 @@ EmitFor(FunctionCompiler& f, Stmt stmt, const LabelVector* maybeLabels)
{
MOZ_ASSERT(stmt == Stmt::ForInitInc || stmt == Stmt::ForInitNoInc ||
stmt == Stmt::ForNoInitInc || stmt == Stmt::ForNoInitNoInc);
size_t headPc = f.pc();
size_t headId = f.nextId();
if (stmt == Stmt::ForInitInc || stmt == Stmt::ForInitNoInc) {
if (!EmitStatement(f))
@@ -2322,7 +2330,7 @@ EmitFor(FunctionCompiler& f, Stmt stmt, const LabelVector* maybeLabels)
}
MBasicBlock* loopEntry;
if (!f.startPendingLoop(headPc, &loopEntry))
if (!f.startPendingLoop(headId, &loopEntry))
return false;
MDefinition* condDef;
@@ -2336,7 +2344,7 @@ EmitFor(FunctionCompiler& f, Stmt stmt, const LabelVector* maybeLabels)
if (!EmitStatement(f))
return false;
if (!f.bindContinues(headPc, maybeLabels))
if (!f.bindContinues(headId, maybeLabels))
return false;
if (stmt == Stmt::ForInitInc || stmt == Stmt::ForNoInitInc) {
@@ -2352,16 +2360,16 @@ EmitFor(FunctionCompiler& f, Stmt stmt, const LabelVector* maybeLabels)
static bool
EmitDoWhile(FunctionCompiler& f, const LabelVector* maybeLabels)
{
size_t headPc = f.pc();
size_t headId = f.nextId();
MBasicBlock* loopEntry;
if (!f.startPendingLoop(headPc, &loopEntry))
if (!f.startPendingLoop(headId, &loopEntry))
return false;
if (!EmitStatement(f))
return false;
if (!f.bindContinues(headPc, maybeLabels))
if (!f.bindContinues(headId, maybeLabels))
return false;
MDefinition* condDef;
@@ -2464,7 +2472,7 @@ EmitSwitch(FunctionCompiler& f)
return false;
MBasicBlock* switchBlock;
if (!f.startSwitch(f.pc(), exprDef, low, high, &switchBlock))
if (!f.startSwitch(f.nextId(), exprDef, low, high, &switchBlock))
return false;
while (numCases--) {
@@ -3039,7 +3047,7 @@ wasm::IonCompileFunction(IonCompileTask* task)
{
int64_t before = PRMJ_Now();
const FuncIR& func = task->func();
const FuncBytecode& func = task->func();
FuncCompileResults& results = task->results();
JitContext jitContext(CompileRuntime::get(task->runtime()), &results.alloc());
+10 -7
View File
@@ -19,7 +19,7 @@
#ifndef wasm_ion_compile_h
#define wasm_ion_compile_h
#include "asmjs/WasmIR.h"
#include "asmjs/WasmBinary.h"
#include "jit/MacroAssembler.h"
namespace js {
@@ -63,7 +63,7 @@ class IonCompileTask
JSRuntime* const runtime_;
const CompileArgs args_;
LifoAlloc lifo_;
const FuncIR* func_;
UniqueFuncBytecode func_;
mozilla::Maybe<FuncCompileResults> results_;
IonCompileTask(const IonCompileTask&) = delete;
@@ -85,19 +85,22 @@ class IonCompileTask
CompileArgs args() const {
return args_;
}
void init(const FuncIR& func) {
func_ = &func;
void init(UniqueFuncBytecode func) {
MOZ_ASSERT(!func_);
func_ = mozilla::Move(func);
results_.emplace(lifo_);
}
const FuncIR& func() const {
const FuncBytecode& func() const {
MOZ_ASSERT(func_);
return *func_;
}
FuncCompileResults& results() {
return *results_;
}
void reset() {
func_ = nullptr;
void reset(UniqueBytecode* recycled) {
if (func_)
*recycled = func_->recycleBytecode();
func_.reset(nullptr);
results_.reset();
lifo_.releaseAll();
}
+399 -345
View File
@@ -76,6 +76,7 @@ wasm::AllocateCode(ExclusiveContext* cx, size_t bytes)
void
CodeDeleter::operator()(uint8_t* p)
{
MOZ_ASSERT(bytes_ != 0);
DeallocateExecutableMemory(p, bytes_, AsmJSPageSize);
}
@@ -462,6 +463,13 @@ CacheableUniquePtr<CharT>::clone(JSContext* cx, CacheableUniquePtr* out) const
return true;
}
template <class CharT>
size_t
CacheableUniquePtr<CharT>::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
{
return mallocSizeOf(this->get());
}
namespace js {
namespace wasm {
template struct CacheableUniquePtr<char>;
@@ -469,24 +477,132 @@ template struct CacheableUniquePtr<char16_t>;
}
}
class Module::AutoMutateCode
size_t
ExportMap::serializedSize() const
{
AutoWritableJitCode awjc_;
AutoFlushICache afc_;
return SerializedVectorSize(exportNames) +
SerializedVectorSize(fieldNames) +
SerializedPodVectorSize(fieldsToExports);
}
public:
AutoMutateCode(JSContext* cx, Module& module, const char* name)
: awjc_(cx->runtime(), module.code(), module.pod.codeBytes_),
afc_(name)
{
AutoFlushICache::setRange(uintptr_t(module.code()), module.pod.codeBytes_);
}
};
uint32_t
Module::totalBytes() const
uint8_t*
ExportMap::serialize(uint8_t* cursor) const
{
return pod.codeBytes_ + pod.globalBytes_;
cursor = SerializeVector(cursor, exportNames);
cursor = SerializeVector(cursor, fieldNames);
cursor = SerializePodVector(cursor, fieldsToExports);
return cursor;
}
const uint8_t*
ExportMap::deserialize(ExclusiveContext* cx, const uint8_t* cursor)
{
(cursor = DeserializeVector(cx, cursor, &exportNames)) &&
(cursor = DeserializeVector(cx, cursor, &fieldNames)) &&
(cursor = DeserializePodVector(cx, cursor, &fieldsToExports));
return cursor;
}
bool
ExportMap::clone(JSContext* cx, ExportMap* map) const
{
return CloneVector(cx, exportNames, &map->exportNames) &&
CloneVector(cx, fieldNames, &map->fieldNames) &&
ClonePodVector(cx, fieldsToExports, &map->fieldsToExports);
}
size_t
ExportMap::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
{
return SizeOfVectorExcludingThis(exportNames, mallocSizeOf) &&
SizeOfVectorExcludingThis(fieldNames, mallocSizeOf) &&
fieldsToExports.sizeOfExcludingThis(mallocSizeOf);
}
size_t
ModuleData::serializedSize() const
{
return sizeof(pod()) +
codeBytes +
SerializedVectorSize(imports) +
SerializedVectorSize(exports) +
SerializedPodVectorSize(heapAccesses) +
SerializedPodVectorSize(codeRanges) +
SerializedPodVectorSize(callSites) +
SerializedVectorSize(funcNames) +
filename.serializedSize() +
displayURL.serializedSize();
}
uint8_t*
ModuleData::serialize(uint8_t* cursor) const
{
cursor = WriteBytes(cursor, &pod(), sizeof(pod()));
cursor = WriteBytes(cursor, code.get(), codeBytes);
cursor = SerializeVector(cursor, imports);
cursor = SerializeVector(cursor, exports);
cursor = SerializePodVector(cursor, heapAccesses);
cursor = SerializePodVector(cursor, codeRanges);
cursor = SerializePodVector(cursor, callSites);
cursor = SerializeVector(cursor, funcNames);
cursor = filename.serialize(cursor);
cursor = displayURL.serialize(cursor);
return cursor;
}
/* static */ const uint8_t*
ModuleData::deserialize(ExclusiveContext* cx, const uint8_t* cursor)
{
cursor = ReadBytes(cursor, &pod(), sizeof(pod()));
code = AllocateCode(cx, totalBytes());
if (!code)
return nullptr;
cursor = ReadBytes(cursor, code.get(), codeBytes);
(cursor = DeserializeVector(cx, cursor, &imports)) &&
(cursor = DeserializeVector(cx, cursor, &exports)) &&
(cursor = DeserializePodVector(cx, cursor, &heapAccesses)) &&
(cursor = DeserializePodVector(cx, cursor, &codeRanges)) &&
(cursor = DeserializePodVector(cx, cursor, &callSites)) &&
(cursor = DeserializeVector(cx, cursor, &funcNames)) &&
(cursor = filename.deserialize(cx, cursor)) &&
(cursor = displayURL.deserialize(cx, cursor));
return cursor;
}
bool
ModuleData::clone(JSContext* cx, ModuleData* out) const
{
out->pod() = pod();
out->code = AllocateCode(cx, totalBytes());
if (!out->code)
return false;
memcpy(out->code.get(), code.get(), codeBytes);
return CloneVector(cx, imports, &out->imports) &&
CloneVector(cx, exports, &out->exports) &&
ClonePodVector(cx, heapAccesses, &out->heapAccesses) &&
ClonePodVector(cx, codeRanges, &out->codeRanges) &&
ClonePodVector(cx, callSites, &out->callSites) &&
CloneVector(cx, funcNames, &out->funcNames) &&
filename.clone(cx, &out->filename) &&
displayURL.clone(cx, &out->displayURL);
}
size_t
ModuleData::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
{
// Module::addSizeOfMisc takes care of code and global memory.
return SizeOfVectorExcludingThis(imports, mallocSizeOf) +
SizeOfVectorExcludingThis(exports, mallocSizeOf) +
heapAccesses.sizeOfExcludingThis(mallocSizeOf) +
codeRanges.sizeOfExcludingThis(mallocSizeOf) +
callSites.sizeOfExcludingThis(mallocSizeOf) +
funcNames.sizeOfExcludingThis(mallocSizeOf) +
filename.sizeOfExcludingThis(mallocSizeOf) +
displayURL.sizeOfExcludingThis(mallocSizeOf);
}
uint8_t*
@@ -524,7 +640,7 @@ Module::specializeToHeap(ArrayBufferObjectMaybeShared* heap)
// i.e. ptr > heapLength - data-type-byte-size - offset. data-type-byte-size
// and offset are already included in the addend so we
// just have to add the heap length here.
for (const HeapAccess& access : heapAccesses_) {
for (const HeapAccess& access : module_->heapAccesses) {
if (access.hasLengthCheck())
X86Encoding::AddInt32(access.patchLengthAt(code()), heapLength);
void* addr = access.patchHeapPtrImmAt(code());
@@ -540,14 +656,14 @@ Module::specializeToHeap(ArrayBufferObjectMaybeShared* heap)
// checks at the right places. All accesses that have been recorded are the
// only ones that need bound checks (see also
// CodeGeneratorX64::visitAsmJS{Load,Store,CompareExchange,Exchange,AtomicBinop}Heap)
for (const HeapAccess& access : heapAccesses_) {
for (const HeapAccess& access : module_->heapAccesses) {
// See comment above for x86 codegen.
if (access.hasLengthCheck())
X86Encoding::AddInt32(access.patchLengthAt(code()), heapLength);
}
#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \
defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
for (const HeapAccess& access : heapAccesses_)
for (const HeapAccess& access : module_->heapAccesses)
Assembler::UpdateBoundsCheck(heapLength, (Instruction*)(access.insnOffset() + code()));
#endif
@@ -567,8 +683,8 @@ Module::despecializeFromHeap(ArrayBufferObjectMaybeShared* heap)
#if defined(JS_CODEGEN_X86)
uint32_t heapLength = heap->byteLength();
uint8_t* ptrBase = heap->dataPointerEither().unwrap(/*safe - used for value*/);
for (unsigned i = 0; i < heapAccesses_.length(); i++) {
const HeapAccess& access = heapAccesses_[i];
for (unsigned i = 0; i < module_->heapAccesses.length(); i++) {
const HeapAccess& access = module_->heapAccesses[i];
if (access.hasLengthCheck())
X86Encoding::AddInt32(access.patchLengthAt(code()), -heapLength);
void* addr = access.patchHeapPtrImmAt(code());
@@ -578,8 +694,8 @@ Module::despecializeFromHeap(ArrayBufferObjectMaybeShared* heap)
}
#elif defined(JS_CODEGEN_X64)
uint32_t heapLength = heap->byteLength();
for (unsigned i = 0; i < heapAccesses_.length(); i++) {
const HeapAccess& access = heapAccesses_[i];
for (unsigned i = 0; i < module_->heapAccesses.length(); i++) {
const HeapAccess& access = module_->heapAccesses[i];
if (access.hasLengthCheck())
X86Encoding::AddInt32(access.patchLengthAt(code()), -heapLength);
}
@@ -594,17 +710,17 @@ Module::sendCodeRangesToProfiler(JSContext* cx)
{
#ifdef JS_ION_PERF
if (PerfFuncEnabled()) {
for (const CodeRange& codeRange : codeRanges_) {
for (const CodeRange& codeRange : module_->codeRanges) {
if (!codeRange.isFunction())
continue;
uintptr_t start = uintptr_t(code() + codeRange.begin());
uintptr_t end = uintptr_t(code() + codeRange.end());
uintptr_t size = end - start;
const char* file = filename_.get();
const char* file = module_->filename.get();
unsigned line = codeRange.funcLineNumber();
unsigned column = 0;
const char* name = funcNames_[codeRange.funcNameIndex()].get();
const char* name = module_->funcNames[codeRange.funcNameIndex()].get();
writePerfSpewerAsmJSFunctionMap(start, size, file, line, column, name);
}
@@ -612,14 +728,14 @@ Module::sendCodeRangesToProfiler(JSContext* cx)
#endif
#ifdef MOZ_VTUNE
if (IsVTuneProfilingActive()) {
for (const CodeRange& codeRange : codeRanges_) {
for (const CodeRange& codeRange : module_->codeRanges) {
if (!codeRange.isFunction())
continue;
uintptr_t start = uintptr_t(code() + codeRange.begin());
uintptr_t end = uintptr_t(code() + codeRange.end());
uintptr_t size = end - start;
const char* name = funcNames_[codeRange.funcNameIndex()].get();
const char* name = module_->funcNames[codeRange.funcNameIndex()].get();
unsigned method_id = iJIT_GetNewMethodID();
if (method_id == 0)
@@ -654,16 +770,16 @@ Module::setProfilingEnabled(JSContext* cx, bool enabled)
// do it now since, once we start sampling, we'll be in a signal-handing
// context where we cannot malloc.
if (enabled) {
if (!funcLabels_.resize(funcNames_.length())) {
if (!funcLabels_.resize(module_->funcNames.length())) {
ReportOutOfMemory(cx);
return false;
}
for (const CodeRange& codeRange : codeRanges_) {
for (const CodeRange& codeRange : module_->codeRanges) {
if (!codeRange.isFunction())
continue;
unsigned lineno = codeRange.funcLineNumber();
const char* name = funcNames_[codeRange.funcNameIndex()].get();
UniqueChars label(JS_smprintf("%s (%s:%u)", name, filename_.get(), lineno));
const char* name = module_->funcNames[codeRange.funcNameIndex()].get();
UniqueChars label(JS_smprintf("%s (%s:%u)", name, module_->filename.get(), lineno));
if (!label) {
ReportOutOfMemory(cx);
return false;
@@ -674,14 +790,16 @@ Module::setProfilingEnabled(JSContext* cx, bool enabled)
funcLabels_.clear();
}
// Patch callsites and returns to execute profiling prologues/epililogues.
// Patch callsites and returns to execute profiling prologues/epilogues.
{
AutoMutateCode amc(cx, *this, "Module::setProfilingEnabled");
AutoWritableJitCode awjc(cx->runtime(), code(), codeBytes());
AutoFlushICache afc("Module::setProfilingEnabled");
AutoFlushICache::setRange(uintptr_t(code()), codeBytes());
for (const CallSite& callSite : callSites_)
for (const CallSite& callSite : module_->callSites)
EnableProfilingPrologue(*this, callSite, enabled);
for (const CodeRange& codeRange : codeRanges_)
for (const CodeRange& codeRange : module_->codeRanges)
EnableProfilingEpilogue(*this, codeRange, enabled);
}
@@ -709,114 +827,70 @@ Module::importToExit(const Import& import)
return *reinterpret_cast<ImportExit*>(globalData() + import.exitGlobalDataOffset());
}
/* static */ Module::CacheablePod
Module::zeroPod()
bool
Module::clone(JSContext* cx, const StaticLinkData& link, Module* out) const
{
CacheablePod pod = {0, 0, 0, HeapUsage::None, false, false, false};
return pod;
MOZ_ASSERT(dynamicallyLinked_);
// The out->module_ field was already cloned and initialized when 'out' was
// constructed. This function should clone the rest.
MOZ_ASSERT(out->module_);
out->isAsmJS_ = isAsmJS_;
out->profilingEnabled_ = profilingEnabled_;
if (!CloneVector(cx, funcLabels_, &out->funcLabels_))
return false;
#ifdef DEBUG
// Put the symbolic links back to -1 so PatchDataWithValueCheck assertions
// in Module::staticallyLink are valid.
for (auto imm : MakeEnumeratedRange(SymbolicAddress::Limit)) {
void* callee = AddressOf(imm, cx);
const StaticLinkData::OffsetVector& offsets = link.symbolicLinks[imm];
for (uint32_t offset : offsets) {
jit::Assembler::PatchDataWithValueCheck(jit::CodeLocationLabel(out->code() + offset),
jit::PatchedImmPtr((void*)-1),
jit::PatchedImmPtr(callee));
}
}
#endif
// If the copied machine code has been specialized to the heap, it must be
// unspecialized in the copy.
if (usesHeap())
out->despecializeFromHeap(heap_);
return true;
}
void
Module::init()
{
staticallyLinked_ = false;
interrupt_ = nullptr;
outOfBounds_ = nullptr;
dynamicallyLinked_ = false;
Module::Module(UniqueModuleData module, AsmJSBool isAsmJS)
: module_(Move(module)),
isAsmJS_(bool(isAsmJS)),
staticallyLinked_(false),
interrupt_(nullptr),
outOfBounds_(nullptr),
dynamicallyLinked_(false),
profilingEnabled_(false)
{
*(double*)(globalData() + NaN64GlobalDataOffset) = GenericNaN();
*(float*)(globalData() + NaN32GlobalDataOffset) = GenericNaN();
}
// Private constructor used for deserialization and cloning.
Module::Module(const CacheablePod& pod,
UniqueCodePtr code,
ImportVector&& imports,
ExportVector&& exports,
HeapAccessVector&& heapAccesses,
CodeRangeVector&& codeRanges,
CallSiteVector&& callSites,
CacheableCharsVector&& funcNames,
CacheableChars filename,
CacheableTwoByteChars displayURL,
CacheBool loadedFromCache,
ProfilingBool profilingEnabled,
FuncLabelVector&& funcLabels)
: pod(pod),
code_(Move(code)),
imports_(Move(imports)),
exports_(Move(exports)),
heapAccesses_(Move(heapAccesses)),
codeRanges_(Move(codeRanges)),
callSites_(Move(callSites)),
funcNames_(Move(funcNames)),
filename_(Move(filename)),
displayURL_(Move(displayURL)),
loadedFromCache_(loadedFromCache),
profilingEnabled_(profilingEnabled),
funcLabels_(Move(funcLabels))
{
MOZ_ASSERT_IF(!profilingEnabled, funcLabels_.empty());
MOZ_ASSERT_IF(profilingEnabled, funcNames_.length() == funcLabels_.length());
init();
}
// Public constructor for compilation.
Module::Module(CompileArgs args,
uint32_t functionBytes,
uint32_t codeBytes,
uint32_t globalBytes,
HeapUsage heapUsage,
MutedBool mutedErrors,
UniqueCodePtr code,
ImportVector&& imports,
ExportVector&& exports,
HeapAccessVector&& heapAccesses,
CodeRangeVector&& codeRanges,
CallSiteVector&& callSites,
CacheableCharsVector&& funcNames,
CacheableChars filename,
CacheableTwoByteChars displayURL)
: pod(zeroPod()),
code_(Move(code)),
imports_(Move(imports)),
exports_(Move(exports)),
heapAccesses_(Move(heapAccesses)),
codeRanges_(Move(codeRanges)),
callSites_(Move(callSites)),
funcNames_(Move(funcNames)),
filename_(Move(filename)),
displayURL_(Move(displayURL)),
loadedFromCache_(false),
profilingEnabled_(false)
{
// Work around MSVC 2013 bug around {} member initialization.
const_cast<uint32_t&>(pod.functionBytes_) = functionBytes;
const_cast<uint32_t&>(pod.codeBytes_) = codeBytes;
const_cast<uint32_t&>(pod.globalBytes_) = globalBytes;
const_cast<HeapUsage&>(pod.heapUsage_) = heapUsage;
const_cast<bool&>(pod.mutedErrors_) = bool(mutedErrors);
const_cast<bool&>(pod.usesSignalHandlersForOOB_) = args.useSignalHandlersForOOB;
const_cast<bool&>(pod.usesSignalHandlersForInterrupt_) = args.useSignalHandlersForInterrupt;
init();
}
Module::~Module()
{
if (code_) {
for (unsigned i = 0; i < imports_.length(); i++) {
ImportExit& exit = importToExit(imports_[i]);
if (exit.baselineScript)
exit.baselineScript->removeDependentWasmModule(*this, i);
}
for (unsigned i = 0; i < imports().length(); i++) {
ImportExit& exit = importToExit(imports()[i]);
if (exit.baselineScript)
exit.baselineScript->removeDependentWasmModule(*this, i);
}
}
void
Module::trace(JSTracer* trc)
{
for (const Import& import : imports_) {
for (const Import& import : imports()) {
if (importToExit(import).fun)
TraceEdge(trc, &importToExit(import).fun, "wasm function import");
}
@@ -825,25 +899,16 @@ Module::trace(JSTracer* trc)
TraceEdge(trc, &heap_, "wasm buffer");
}
CompileArgs
Module::compileArgs() const
{
CompileArgs args;
args.useSignalHandlersForOOB = pod.usesSignalHandlersForOOB_;
args.useSignalHandlersForInterrupt = pod.usesSignalHandlersForInterrupt_;
return args;
}
bool
Module::containsFunctionPC(void* pc) const
{
return pc >= code() && pc < (code() + pod.functionBytes_);
return pc >= code() && pc < (code() + module_->functionBytes);
}
bool
Module::containsCodePC(void* pc) const
{
return pc >= code() && pc < (code() + pod.codeBytes_);
return pc >= code() && pc < (code() + codeBytes());
}
struct CallSiteRetAddrOffset
@@ -860,13 +925,13 @@ Module::lookupCallSite(void* returnAddress) const
{
uint32_t target = ((uint8_t*)returnAddress) - code();
size_t lowerBound = 0;
size_t upperBound = callSites_.length();
size_t upperBound = module_->callSites.length();
size_t match;
if (!BinarySearch(CallSiteRetAddrOffset(callSites_), lowerBound, upperBound, target, &match))
if (!BinarySearch(CallSiteRetAddrOffset(module_->callSites), lowerBound, upperBound, target, &match))
return nullptr;
return &callSites_[match];
return &module_->callSites[match];
}
const CodeRange*
@@ -874,13 +939,13 @@ Module::lookupCodeRange(void* pc) const
{
CodeRange::PC target((uint8_t*)pc - code());
size_t lowerBound = 0;
size_t upperBound = codeRanges_.length();
size_t upperBound = module_->codeRanges.length();
size_t match;
if (!BinarySearch(codeRanges_, lowerBound, upperBound, target, &match))
if (!BinarySearch(module_->codeRanges, lowerBound, upperBound, target, &match))
return nullptr;
return &codeRanges_[match];
return &module_->codeRanges[match];
}
struct HeapAccessOffset
@@ -899,13 +964,13 @@ Module::lookupHeapAccess(void* pc) const
uint32_t target = ((uint8_t*)pc) - code();
size_t lowerBound = 0;
size_t upperBound = heapAccesses_.length();
size_t upperBound = module_->heapAccesses.length();
size_t match;
if (!BinarySearch(HeapAccessOffset(heapAccesses_), lowerBound, upperBound, target, &match))
if (!BinarySearch(HeapAccessOffset(module_->heapAccesses), lowerBound, upperBound, target, &match))
return nullptr;
return &heapAccesses_[match];
return &module_->heapAccesses[match];
}
bool
@@ -920,7 +985,7 @@ Module::staticallyLink(ExclusiveContext* cx, const StaticLinkData& linkData)
JitContext jcx(CompileRuntime::get(cx->compartment()->runtimeFromAnyThread()));
MOZ_ASSERT(IsCompilingAsmJS());
AutoFlushICache afc("Module::staticallyLink", /* inhibit = */ true);
AutoFlushICache::setRange(uintptr_t(code()), pod.codeBytes_);
AutoFlushICache::setRange(uintptr_t(code()), codeBytes());
interrupt_ = code() + linkData.pod.interruptOffset;
outOfBounds_ = code() + linkData.pod.outOfBoundsOffset;
@@ -983,7 +1048,7 @@ Module::staticallyLink(ExclusiveContext* cx, const StaticLinkData& linkData)
bool
Module::dynamicallyLink(JSContext* cx, Handle<ArrayBufferObjectMaybeShared*> heap,
const AutoVectorRooter<JSFunction*>& imports)
Handle<FunctionVector> importArgs)
{
MOZ_ASSERT(staticallyLinked_);
MOZ_ASSERT(!dynamicallyLinked_);
@@ -994,15 +1059,15 @@ Module::dynamicallyLink(JSContext* cx, Handle<ArrayBufferObjectMaybeShared*> hea
JitContext jcx(CompileRuntime::get(cx->compartment()->runtimeFromAnyThread()));
MOZ_ASSERT(IsCompilingAsmJS());
AutoFlushICache afc("Module::dynamicallyLink");
AutoFlushICache::setRange(uintptr_t(code()), pod.codeBytes_);
AutoFlushICache::setRange(uintptr_t(code()), codeBytes());
// Initialize imports with actual imported values.
MOZ_ASSERT(imports.length() == imports_.length());
for (size_t i = 0; i < imports_.length(); i++) {
const Import& import = imports_[i];
MOZ_ASSERT(importArgs.length() == imports().length());
for (size_t i = 0; i < imports().length(); i++) {
const Import& import = imports()[i];
ImportExit& exit = importToExit(import);
exit.code = code() + import.interpExitCodeOffset();
exit.fun = imports[i];
exit.fun = importArgs[i];
exit.baselineScript = nullptr;
}
@@ -1011,7 +1076,7 @@ Module::dynamicallyLink(JSContext* cx, Handle<ArrayBufferObjectMaybeShared*> hea
specializeToHeap(heap);
// See AllocateCode comment above.
if (!ExecutableAllocator::makeExecutable(code(), pod.codeBytes_)) {
if (!ExecutableAllocator::makeExecutable(code(), codeBytes())) {
ReportOutOfMemory(cx);
return false;
}
@@ -1020,6 +1085,92 @@ Module::dynamicallyLink(JSContext* cx, Handle<ArrayBufferObjectMaybeShared*> hea
return true;
}
static bool
WasmCall(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
RootedFunction callee(cx, &args.callee().as<JSFunction>());
Module& module = ExportedFunctionToModuleObject(callee)->module();
uint32_t exportIndex = ExportedFunctionToIndex(callee);
return module.callExport(cx, exportIndex, args);
}
static JSFunction*
NewExportedFunction(JSContext* cx, Handle<WasmModuleObject*> moduleObj, const ExportMap& map,
uint32_t exportIndex)
{
unsigned numArgs = moduleObj->module().exports()[exportIndex].sig().args().length();
const char* chars = map.exportNames[exportIndex].get();
RootedAtom name(cx, AtomizeUTF8Chars(cx, chars, strlen(chars)));
if (!name)
return nullptr;
JSFunction* fun = NewNativeConstructor(cx, WasmCall, numArgs, name,
gc::AllocKind::FUNCTION_EXTENDED, GenericObject,
JSFunction::ASMJS_CTOR);
if (!fun)
return nullptr;
fun->setExtendedSlot(FunctionExtended::WASM_MODULE_SLOT, ObjectValue(*moduleObj));
fun->setExtendedSlot(FunctionExtended::WASM_EXPORT_INDEX_SLOT, Int32Value(exportIndex));
return fun;
}
bool
Module::createExportObject(JSContext* cx, Handle<WasmModuleObject*> moduleObj,
const ExportMap& map, MutableHandleObject exportObj)
{
MOZ_ASSERT(this == &moduleObj->module());
MOZ_ASSERT(map.exportNames.length() == exports().length());
MOZ_ASSERT(map.fieldNames.length() == map.fieldsToExports.length());
for (size_t fieldIndex = 0; fieldIndex < map.fieldNames.length(); fieldIndex++) {
const char* fieldName = map.fieldNames[fieldIndex].get();
if (!*fieldName) {
MOZ_ASSERT_IF(isAsmJS(), exports().length() == 1);
MOZ_ASSERT(!exportObj);
uint32_t exportIndex = map.fieldsToExports[fieldIndex];
exportObj.set(NewExportedFunction(cx, moduleObj, map, exportIndex));
if (!exportObj)
return false;
break;
}
}
Rooted<ValueVector> vals(cx, ValueVector(cx));
for (size_t exportIndex = 0; exportIndex < exports().length(); exportIndex++) {
JSFunction* fun = NewExportedFunction(cx, moduleObj, map, exportIndex);
if (!fun || !vals.append(ObjectValue(*fun)))
return false;
}
if (!exportObj) {
exportObj.set(JS_NewPlainObject(cx));
if (!exportObj)
return false;
}
for (size_t fieldIndex = 0; fieldIndex < map.fieldNames.length(); fieldIndex++) {
const char* fieldName = map.fieldNames[fieldIndex].get();
if (!*fieldName)
continue;
JSAtom* atom = AtomizeUTF8Chars(cx, fieldName, strlen(fieldName));
if (!atom)
return false;
RootedId id(cx, AtomToId(atom));
HandleValue val = vals[map.fieldsToExports[fieldIndex]];
if (!JS_DefinePropertyById(cx, exportObj, id, val, JSPROP_ENUMERATE))
return false;
}
return true;
}
SharedMem<uint8_t*>
Module::heap() const
{
@@ -1043,7 +1194,7 @@ void
Module::deoptimizeImportExit(uint32_t importIndex)
{
MOZ_ASSERT(dynamicallyLinked_);
const Import& import = imports_[importIndex];
const Import& import = imports()[importIndex];
ImportExit& exit = importToExit(import);
exit.code = code() + import.interpExitCodeOffset();
exit.baselineScript = nullptr;
@@ -1054,7 +1205,7 @@ Module::callExport(JSContext* cx, uint32_t exportIndex, CallArgs args)
{
MOZ_ASSERT(dynamicallyLinked_);
const Export& exp = exports_[exportIndex];
const Export& exp = exports()[exportIndex];
// Enable/disable profiling in the Module to match the current global
// profiling state. Don't do this if the Module is already active on the
@@ -1190,7 +1341,7 @@ Module::callImport(JSContext* cx, uint32_t importIndex, unsigned argc, const Val
{
MOZ_ASSERT(dynamicallyLinked_);
const Import& import = imports_[importIndex];
const Import& import = imports()[importIndex];
RootedValue fval(cx, ObjectValue(*importToExit(import).fun));
if (!Invoke(cx, UndefinedValue(), fval, argc, argv, rval))
@@ -1264,211 +1415,114 @@ Module::profilingLabel(uint32_t funcIndex) const
return funcLabels_[funcIndex].get();
}
size_t
Module::serializedSize() const
void
Module::addSizeOfMisc(MallocSizeOf mallocSizeOf, size_t* code, size_t* data)
{
return sizeof(pod) +
pod.codeBytes_ +
SerializedVectorSize(imports_) +
SerializedVectorSize(exports_) +
SerializedPodVectorSize(heapAccesses_) +
SerializedPodVectorSize(codeRanges_) +
SerializedPodVectorSize(callSites_) +
SerializedVectorSize(funcNames_) +
filename_.serializedSize() +
displayURL_.serializedSize();
*code += codeBytes();
*data += mallocSizeOf(this) +
globalBytes() +
mallocSizeOf(module_.get()) +
module_->sizeOfExcludingThis(mallocSizeOf) +
funcPtrTables_.sizeOfExcludingThis(mallocSizeOf) +
SizeOfVectorExcludingThis(funcLabels_, mallocSizeOf);
}
uint8_t*
Module::serialize(uint8_t* cursor) const
{
MOZ_ASSERT(!profilingEnabled_, "assumed by Module::deserialize");
const Class WasmModuleObject::class_ = {
"WasmModuleObject",
JSCLASS_IS_ANONYMOUS | JSCLASS_DELAY_METADATA_CALLBACK |
JSCLASS_HAS_RESERVED_SLOTS(WasmModuleObject::RESERVED_SLOTS),
nullptr, /* addProperty */
nullptr, /* delProperty */
nullptr, /* getProperty */
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
WasmModuleObject::finalize,
nullptr, /* call */
nullptr, /* hasInstance */
nullptr, /* construct */
WasmModuleObject::trace
};
cursor = WriteBytes(cursor, &pod, sizeof(pod));
cursor = WriteBytes(cursor, code(), pod.codeBytes_);
cursor = SerializeVector(cursor, imports_);
cursor = SerializeVector(cursor, exports_);
cursor = SerializePodVector(cursor, heapAccesses_);
cursor = SerializePodVector(cursor, codeRanges_);
cursor = SerializePodVector(cursor, callSites_);
cursor = SerializeVector(cursor, funcNames_);
cursor = filename_.serialize(cursor);
cursor = displayURL_.serialize(cursor);
return cursor;
bool
WasmModuleObject::hasModule() const
{
MOZ_ASSERT(is<WasmModuleObject>());
return !getReservedSlot(MODULE_SLOT).isUndefined();
}
/* static */ const uint8_t*
Module::deserialize(ExclusiveContext* cx, const uint8_t* cursor, UniqueModule* out)
/* static */ void
WasmModuleObject::finalize(FreeOp* fop, JSObject* obj)
{
CacheablePod pod = zeroPod();
cursor = ReadBytes(cursor, &pod, sizeof(pod));
if (!cursor)
return nullptr;
UniqueCodePtr code = AllocateCode(cx, pod.codeBytes_ + pod.globalBytes_);
if (!code)
return nullptr;
cursor = ReadBytes(cursor, code.get(), pod.codeBytes_);
ImportVector imports;
cursor = DeserializeVector(cx, cursor, &imports);
if (!cursor)
return nullptr;
ExportVector exports;
cursor = DeserializeVector(cx, cursor, &exports);
if (!cursor)
return nullptr;
HeapAccessVector heapAccesses;
cursor = DeserializePodVector(cx, cursor, &heapAccesses);
if (!cursor)
return nullptr;
CodeRangeVector codeRanges;
cursor = DeserializePodVector(cx, cursor, &codeRanges);
if (!cursor)
return nullptr;
CallSiteVector callSites;
cursor = DeserializePodVector(cx, cursor, &callSites);
if (!cursor)
return nullptr;
CacheableCharsVector funcNames;
cursor = DeserializeVector(cx, cursor, &funcNames);
if (!cursor)
return nullptr;
CacheableChars filename;
cursor = filename.deserialize(cx, cursor);
if (!cursor)
return nullptr;
CacheableTwoByteChars displayURL;
cursor = displayURL.deserialize(cx, cursor);
if (!cursor)
return nullptr;
*out = cx->make_unique<Module>(pod,
Move(code),
Move(imports),
Move(exports),
Move(heapAccesses),
Move(codeRanges),
Move(callSites),
Move(funcNames),
Move(filename),
Move(displayURL),
Module::LoadedFromCache,
Module::ProfilingDisabled,
FuncLabelVector());
return cursor;
WasmModuleObject& moduleObj = obj->as<WasmModuleObject>();
if (moduleObj.hasModule())
fop->delete_(&moduleObj.module());
}
Module::UniqueModule
Module::clone(JSContext* cx, const StaticLinkData& linkData) const
/* static */ void
WasmModuleObject::trace(JSTracer* trc, JSObject* obj)
{
MOZ_ASSERT(dynamicallyLinked_);
WasmModuleObject& moduleObj = obj->as<WasmModuleObject>();
if (moduleObj.hasModule())
moduleObj.module().trace(trc);
}
UniqueCodePtr code = AllocateCode(cx, totalBytes());
if (!code)
/* static */ WasmModuleObject*
WasmModuleObject::create(ExclusiveContext* cx)
{
AutoSetNewObjectMetadata metadata(cx);
JSObject* obj = NewObjectWithGivenProto(cx, &WasmModuleObject::class_, nullptr);
if (!obj)
return nullptr;
memcpy(code.get(), this->code(), pod.codeBytes_);
return &obj->as<WasmModuleObject>();
}
#ifdef DEBUG
// Put the symbolic links back to -1 so PatchDataWithValueCheck assertions
// in Module::staticallyLink are valid.
for (auto imm : MakeEnumeratedRange(SymbolicAddress::Limit)) {
void* callee = AddressOf(imm, cx);
const StaticLinkData::OffsetVector& offsets = linkData.symbolicLinks[imm];
for (uint32_t offset : offsets) {
jit::Assembler::PatchDataWithValueCheck(jit::CodeLocationLabel(code.get() + offset),
jit::PatchedImmPtr((void*)-1),
jit::PatchedImmPtr(callee));
}
}
#endif
bool
WasmModuleObject::init(Module* module)
{
MOZ_ASSERT(is<WasmModuleObject>());
MOZ_ASSERT(!hasModule());
if (!module)
return false;
setReservedSlot(MODULE_SLOT, PrivateValue(module));
return true;
}
ImportVector imports;
if (!CloneVector(cx, imports_, &imports))
return nullptr;
ExportVector exports;
if (!CloneVector(cx, exports_, &exports))
return nullptr;
HeapAccessVector heapAccesses;
if (!ClonePodVector(cx, heapAccesses_, &heapAccesses))
return nullptr;
CodeRangeVector codeRanges;
if (!ClonePodVector(cx, codeRanges_, &codeRanges))
return nullptr;
CallSiteVector callSites;
if (!ClonePodVector(cx, callSites_, &callSites))
return nullptr;
CacheableCharsVector funcNames;
if (!CloneVector(cx, funcNames_, &funcNames))
return nullptr;
CacheableChars filename;
if (!filename_.clone(cx, &filename))
return nullptr;
CacheableTwoByteChars displayURL;
if (!displayURL_.clone(cx, &displayURL))
return nullptr;
FuncLabelVector funcLabels;
if (!CloneVector(cx, funcLabels_, &funcLabels))
return nullptr;
// Must not GC between Module allocation and (successful) return.
auto out = cx->make_unique<Module>(pod,
Move(code),
Move(imports),
Move(exports),
Move(heapAccesses),
Move(codeRanges),
Move(callSites),
Move(funcNames),
Move(filename),
Move(displayURL),
CacheBool::NotLoadedFromCache,
ProfilingBool(profilingEnabled_),
Move(funcLabels));
if (!out)
return nullptr;
// If the copied machine code has been specialized to the heap, it must be
// unspecialized in the copy.
if (usesHeap())
out->despecializeFromHeap(heap_);
if (!out->staticallyLink(cx, linkData))
return nullptr;
return Move(out);
Module&
WasmModuleObject::module() const
{
MOZ_ASSERT(is<WasmModuleObject>());
MOZ_ASSERT(hasModule());
return *(Module*)getReservedSlot(MODULE_SLOT).toPrivate();
}
void
Module::addSizeOfMisc(MallocSizeOf mallocSizeOf, size_t* asmJSModuleCode, size_t* asmJSModuleData)
WasmModuleObject::addSizeOfMisc(MallocSizeOf mallocSizeOf, size_t* code, size_t* data)
{
*asmJSModuleCode += pod.codeBytes_;
*asmJSModuleData += mallocSizeOf(this) +
pod.globalBytes_ +
SizeOfVectorExcludingThis(imports_, mallocSizeOf) +
SizeOfVectorExcludingThis(exports_, mallocSizeOf) +
heapAccesses_.sizeOfExcludingThis(mallocSizeOf) +
codeRanges_.sizeOfExcludingThis(mallocSizeOf) +
callSites_.sizeOfExcludingThis(mallocSizeOf) +
funcNames_.sizeOfExcludingThis(mallocSizeOf) +
funcPtrTables_.sizeOfExcludingThis(mallocSizeOf);
if (hasModule())
module().addSizeOfMisc(mallocSizeOf, code, data);
}
bool
wasm::IsExportedFunction(JSFunction* fun)
{
return fun->maybeNative() == WasmCall;
}
WasmModuleObject*
wasm::ExportedFunctionToModuleObject(JSFunction* fun)
{
MOZ_ASSERT(IsExportedFunction(fun));
const Value& v = fun->getExtendedSlot(FunctionExtended::WASM_MODULE_SLOT);
return &v.toObject().as<WasmModuleObject>();
}
uint32_t
wasm::ExportedFunctionToIndex(JSFunction* fun)
{
MOZ_ASSERT(IsExportedFunction(fun));
const Value& v = fun->getExtendedSlot(FunctionExtended::WASM_EXPORT_INDEX_SLOT);
return v.toInt32();
}
+153 -95
View File
@@ -26,7 +26,9 @@
namespace js {
class AsmJSModule;
class WasmActivation;
class WasmModuleObject;
namespace jit { struct BaselineScript; }
namespace wasm {
@@ -35,8 +37,7 @@ namespace wasm {
// deserialization and cloning. Some data can be simply copied as raw bytes and,
// as a convention, is stored in an inline CacheablePod struct. Everything else
// should implement the below methods which are called recusively by the
// containing Module. The implementation of all these methods are grouped
// together in WasmSerialize.cpp.
// containing Module. See comments for these methods in wasm::Module.
#define WASM_DECLARE_SERIALIZABLE(Type) \
size_t serializedSize() const; \
@@ -95,10 +96,10 @@ struct StaticLinkData
WASM_DECLARE_SERIALIZABLE(StaticLinkData)
};
typedef UniquePtr<StaticLinkData, JS::DeletePolicy<StaticLinkData>> UniqueStaticLinkData;
typedef UniquePtr<StaticLinkData> UniqueStaticLinkData;
// An Export describes an export from a wasm module. Currently only functions
// can be exported.
// An Export represents a single function inside a wasm Module that has been
// exported one or more times.
class Export
{
@@ -195,6 +196,7 @@ typedef Vector<Import, 0, SystemAllocPolicy> ImportVector;
class CodeRange
{
// All fields are treated as cacheable POD:
uint32_t nameIndex_;
uint32_t lineNumber_;
uint32_t begin_;
@@ -291,9 +293,9 @@ typedef Vector<CodeRange, 0, SystemAllocPolicy> CodeRangeVector;
// A CacheableUniquePtr is used to cacheably store strings in Module.
template <class CharT>
struct CacheableUniquePtr : public UniquePtr<CharT, JS::FreePolicy>
struct CacheableUniquePtr : public UniquePtr<CharT[], JS::FreePolicy>
{
typedef UniquePtr<CharT, JS::FreePolicy> UPtr;
typedef UniquePtr<CharT[], JS::FreePolicy> UPtr;
explicit CacheableUniquePtr(CharT* ptr) : UPtr(ptr) {}
MOZ_IMPLICIT CacheableUniquePtr(UPtr&& rhs) : UPtr(Move(rhs)) {}
CacheableUniquePtr() = default;
@@ -306,6 +308,20 @@ typedef CacheableUniquePtr<char> CacheableChars;
typedef CacheableUniquePtr<char16_t> CacheableTwoByteChars;
typedef Vector<CacheableChars, 0, SystemAllocPolicy> CacheableCharsVector;
// The ExportMap describes how Exports are mapped to the fields of the export
// object. This allows a single Export to be used in multiple fields.
struct ExportMap
{
typedef Vector<uint32_t, 0, SystemAllocPolicy> FieldToExportVector;
CacheableCharsVector exportNames;
CacheableCharsVector fieldNames;
FieldToExportVector fieldsToExports;
WASM_DECLARE_SERIALIZABLE(ExportMap)
};
// A UniqueCodePtr owns allocated executable code. Code passed to the Module
// constructor must be allocated via AllocateCode.
@@ -313,10 +329,11 @@ class CodeDeleter
{
uint32_t bytes_;
public:
CodeDeleter() : bytes_(0) {}
explicit CodeDeleter(uint32_t bytes) : bytes_(bytes) {}
void operator()(uint8_t* p);
};
typedef JS::UniquePtr<uint8_t, CodeDeleter> UniqueCodePtr;
typedef UniquePtr<uint8_t, CodeDeleter> UniqueCodePtr;
UniqueCodePtr
AllocateCode(ExclusiveContext* cx, size_t bytes);
@@ -337,6 +354,55 @@ UsesHeap(HeapUsage heapUsage)
return bool(heapUsage);
}
// See mutedErrors comment in jsapi.h.
enum class MutedErrorsBool
{
DontMuteErrors = false,
MuteErrors = true
};
// ModuleCacheablePod holds the trivially-memcpy()able serializable portion of
// ModuleData.
struct ModuleCacheablePod
{
uint32_t functionBytes;
uint32_t codeBytes;
uint32_t globalBytes;
HeapUsage heapUsage;
MutedErrorsBool mutedErrors;
CompileArgs compileArgs;
uint32_t totalBytes() const { return codeBytes + globalBytes; }
};
// ModuleData holds the guts of a Module. ModuleData is mutably built up by
// ModuleGenerator and then handed over to the Module constructor in finish(),
// where it is stored immutably.
struct ModuleData : ModuleCacheablePod
{
ModuleData() : loadedFromCache(false) { mozilla::PodZero(&pod()); }
ModuleCacheablePod& pod() { return *this; }
const ModuleCacheablePod& pod() const { return *this; }
UniqueCodePtr code;
ImportVector imports;
ExportVector exports;
HeapAccessVector heapAccesses;
CodeRangeVector codeRanges;
CallSiteVector callSites;
CacheableCharsVector funcNames;
CacheableChars filename;
CacheableTwoByteChars displayURL;
bool loadedFromCache;
WASM_DECLARE_SERIALIZABLE(ModuleData);
};
typedef UniquePtr<ModuleData> UniqueModuleData;
// Module represents a compiled WebAssembly module which lives until the last
// reference to any exported functions is dropped. Modules must be wrapped by a
// rooted JSObject immediately after creation so that Module::trace() is called
@@ -359,6 +425,7 @@ UsesHeap(HeapUsage heapUsage)
class Module
{
typedef UniquePtr<const ModuleData> UniqueConstModuleData;
struct ImportExit {
void* code;
jit::BaselineScript* baselineScript;
@@ -383,25 +450,8 @@ class Module
typedef RelocatablePtrArrayBufferObjectMaybeShared BufferPtr;
// Initialized when constructed:
struct CacheablePod {
const uint32_t functionBytes_;
const uint32_t codeBytes_;
const uint32_t globalBytes_;
const HeapUsage heapUsage_;
const bool mutedErrors_;
const bool usesSignalHandlersForOOB_;
const bool usesSignalHandlersForInterrupt_;
} pod;
const UniqueCodePtr code_;
const ImportVector imports_;
const ExportVector exports_;
const HeapAccessVector heapAccesses_;
const CodeRangeVector codeRanges_;
const CallSiteVector callSites_;
const CacheableCharsVector funcNames_;
const CacheableChars filename_;
const CacheableTwoByteChars displayURL_;
const bool loadedFromCache_;
const UniqueConstModuleData module_;
bool isAsmJS_;
// Initialized during staticallyLink:
bool staticallyLinked_;
@@ -417,9 +467,6 @@ class Module
bool profilingEnabled_;
FuncLabelVector funcLabels_;
class AutoMutateCode;
uint32_t totalBytes() const;
uint8_t* rawHeapPtr() const;
uint8_t*& rawHeapPtr();
WasmActivation*& activation();
@@ -429,70 +476,50 @@ class Module
MOZ_WARN_UNUSED_RESULT bool setProfilingEnabled(JSContext* cx, bool enabled);
ImportExit& importToExit(const Import& import);
enum CacheBool { NotLoadedFromCache = false, LoadedFromCache = true };
enum ProfilingBool { ProfilingDisabled = false, ProfilingEnabled = true };
static CacheablePod zeroPod();
void init();
Module(const CacheablePod& pod,
UniqueCodePtr code,
ImportVector&& imports,
ExportVector&& exports,
HeapAccessVector&& heapAccesses,
CodeRangeVector&& codeRanges,
CallSiteVector&& callSites,
CacheableCharsVector&& funcNames,
CacheableChars filename,
CacheableTwoByteChars displayURL,
CacheBool loadedFromCache,
ProfilingBool profilingEnabled,
FuncLabelVector&& funcLabels);
template <class> friend struct js::MallocProvider;
friend class js::WasmActivation;
protected:
enum AsmJSBool { NotAsmJS = false, IsAsmJS = true };
const ModuleData& base() const { return *module_; }
bool clone(JSContext* cx, const StaticLinkData& link, Module* clone) const;
public:
static const unsigned SizeOfImportExit = sizeof(ImportExit);
static const unsigned OffsetOfImportExitFun = offsetof(ImportExit, fun);
static const unsigned SizeOfEntryArg = sizeof(EntryArg);
enum MutedBool { DontMuteErrors = false, MuteErrors = true };
explicit Module(UniqueModuleData module, AsmJSBool = NotAsmJS);
virtual ~Module();
virtual void trace(JSTracer* trc);
virtual void addSizeOfMisc(MallocSizeOf mallocSizeOf, size_t* code, size_t* data);
Module(CompileArgs args,
uint32_t functionBytes,
uint32_t codeBytes,
uint32_t globalBytes,
HeapUsage heapUsage,
MutedBool mutedErrors,
UniqueCodePtr code,
ImportVector&& imports,
ExportVector&& exports,
HeapAccessVector&& heapAccesses,
CodeRangeVector&& codeRanges,
CallSiteVector&& callSites,
CacheableCharsVector&& funcNames,
CacheableChars filename,
CacheableTwoByteChars displayURL);
~Module();
void trace(JSTracer* trc);
uint8_t* code() const { return code_.get(); }
uint8_t* globalData() const { return code() + pod.codeBytes_; }
uint32_t globalBytes() const { return pod.globalBytes_; }
HeapUsage heapUsage() const { return pod.heapUsage_; }
bool usesHeap() const { return UsesHeap(pod.heapUsage_); }
bool hasSharedHeap() const { return pod.heapUsage_ == HeapUsage::Shared; }
bool mutedErrors() const { return pod.mutedErrors_; }
CompileArgs compileArgs() const;
const ImportVector& imports() const { return imports_; }
const ExportVector& exports() const { return exports_; }
const char* functionName(uint32_t i) const { return funcNames_[i].get(); }
const char* filename() const { return filename_.get(); }
const char16_t* displayURL() const { return displayURL_.get(); }
bool loadedFromCache() const { return loadedFromCache_; }
uint8_t* code() const { return module_->code.get(); }
uint32_t codeBytes() const { return module_->codeBytes; }
uint8_t* globalData() const { return code() + module_->codeBytes; }
uint32_t globalBytes() const { return module_->globalBytes; }
HeapUsage heapUsage() const { return module_->heapUsage; }
bool usesHeap() const { return UsesHeap(module_->heapUsage); }
bool hasSharedHeap() const { return module_->heapUsage == HeapUsage::Shared; }
bool mutedErrors() const { return bool(module_->mutedErrors); }
CompileArgs compileArgs() const { return module_->compileArgs; }
const ImportVector& imports() const { return module_->imports; }
const ExportVector& exports() const { return module_->exports; }
const char* functionName(uint32_t i) const { return module_->funcNames[i].get(); }
const char* filename() const { return module_->filename.get(); }
const char16_t* displayURL() const { return module_->displayURL.get(); }
bool loadedFromCache() const { return module_->loadedFromCache; }
bool staticallyLinked() const { return staticallyLinked_; }
bool dynamicallyLinked() const { return dynamicallyLinked_; }
// Some wasm::Module's have the most-derived type AsmJSModule. The
// AsmJSModule stores the extra metadata necessary to implement asm.js (JS)
// semantics. The asAsmJS() member may be used as a checked downcast when
// isAsmJS() is true.
bool isAsmJS() const { return isAsmJS_; }
AsmJSModule& asAsmJS() { MOZ_ASSERT(isAsmJS_); return *(AsmJSModule*)this; }
const AsmJSModule& asAsmJS() const { MOZ_ASSERT(isAsmJS_); return *(const AsmJSModule*)this; }
// The range [0, functionBytes) is a subrange of [0, codeBytes) that
// contains only function body code, not the stub code. This distinction is
// used by the async interrupt handler to only interrupt when the pc is in
@@ -509,7 +536,7 @@ class Module
// statically-linked state. The given StaticLinkData must have come from the
// compilation of this module.
bool staticallyLink(ExclusiveContext* cx, const StaticLinkData& linkData);
bool staticallyLink(ExclusiveContext* cx, const StaticLinkData& link);
// This function transitions the module from a statically-linked state to a
// dynamically-linked state. If this module usesHeap(), a non-null heap
@@ -517,7 +544,13 @@ class Module
// ImportVector.
bool dynamicallyLink(JSContext* cx, Handle<ArrayBufferObjectMaybeShared*> heap,
const AutoVectorRooter<JSFunction*>& imports);
Handle<FunctionVector> imports);
// This function creates and returns a new export object for this module.
// The lengths of exports() and map.exportNames must be the same.
bool createExportObject(JSContext* cx, Handle<WasmModuleObject*> moduleObj,
const ExportMap& map, MutableHandleObject exportObj);
// The wasm heap, established by dynamicallyLink.
@@ -554,19 +587,44 @@ class Module
bool profilingEnabled() const { return profilingEnabled_; }
const char* profilingLabel(uint32_t funcIndex) const;
};
// See WASM_DECLARE_SERIALIZABLE.
size_t serializedSize() const;
uint8_t* serialize(uint8_t* cursor) const;
typedef UniquePtr<Module, JS::DeletePolicy<Module>> UniqueModule;
static const uint8_t* deserialize(ExclusiveContext* cx, const uint8_t* cursor,
UniqueModule* out);
UniqueModule clone(JSContext* cx, const StaticLinkData& linkData) const;
void addSizeOfMisc(MallocSizeOf mallocSizeOf, size_t* asmJSModuleCode,
size_t* asmJSModuleData);
typedef UniquePtr<Module> UniqueModule;
// Tests to query and access the exported JS functions produced by
// Module::createExportObject.
extern bool
IsExportedFunction(JSFunction* fun);
extern WasmModuleObject*
ExportedFunctionToModuleObject(JSFunction* fun);
extern uint32_t
ExportedFunctionToIndex(JSFunction* fun);
} // namespace wasm
// An WasmModuleObject is an internal object (i.e., not exposed directly to user
// code) which traces and owns a wasm::Module. The WasmModuleObject is
// referenced by the extended slots of exported JSFunctions and serves to keep
// the wasm::Module alive until its last GC reference is dead.
class WasmModuleObject : public NativeObject
{
static const unsigned MODULE_SLOT = 0;
bool hasModule() const;
static void finalize(FreeOp* fop, JSObject* obj);
static void trace(JSTracer* trc, JSObject* obj);
public:
static const unsigned RESERVED_SLOTS = 1;
static WasmModuleObject* create(ExclusiveContext* cx);
bool init(wasm::Module* module);
wasm::Module& module() const;
void addSizeOfMisc(mozilla::MallocSizeOf mallocSizeOf, size_t* code, size_t* data);
static const Class class_;
};
} // namespace js
} // namespace wasm
#endif // wasm_module_h
+3 -3
View File
@@ -262,7 +262,7 @@ GenerateEntry(ModuleGenerator& mg, unsigned exportIndex, bool usesHeap)
MOZ_CRASH("no int64 in asm.js");
case ExprType::F32:
masm.convertFloat32ToDouble(ReturnFloat32Reg, ReturnDoubleReg);
// Fall through as ReturnDoubleReg now contains a Double
MOZ_FALLTHROUGH; // as ReturnDoubleReg now contains a Double
case ExprType::F64:
masm.canonicalizeDouble(ReturnDoubleReg);
masm.storeDouble(ReturnDoubleReg, Address(argv, 0));
@@ -1074,14 +1074,14 @@ GenerateThrowStub(ModuleGenerator& mg, Label* throwLabel)
bool
wasm::GenerateStubs(ModuleGenerator& mg, bool usesHeap)
{
for (unsigned i = 0; i < mg.numDeclaredExports(); i++) {
for (unsigned i = 0; i < mg.numExports(); i++) {
if (!GenerateEntry(mg, i, usesHeap))
return false;
}
Label onThrow;
for (size_t i = 0; i < mg.numDeclaredImports(); i++) {
for (size_t i = 0; i < mg.numImports(); i++) {
ProfilingOffsets interp;
if (!GenerateInterpExitStub(mg, i, &onThrow, &interp))
return false;
+3 -2
View File
@@ -22,10 +22,12 @@
#include "mozilla/DebugOnly.h"
#include "mozilla/HashFunctions.h"
#include "mozilla/Move.h"
#include "mozilla/UniquePtr.h"
#include "NamespaceImports.h"
#include "ds/LifoAlloc.h"
#include "jit/IonTypes.h"
#include "js/UniquePtr.h"
#include "js/Utility.h"
#include "js/Vector.h"
@@ -37,7 +39,6 @@ namespace wasm {
using mozilla::Move;
using mozilla::DebugOnly;
using mozilla::UniquePtr;
using mozilla::MallocSizeOf;
// The ValType enum represents the WebAssembly "value type", which are used to
+1 -1
View File
@@ -1166,7 +1166,7 @@ MakeElementValue(JSObject *object)
}
template <typename T>
ArrayObject* ModuleBuilder::createArray(const TraceableVector<T>& vector)
ArrayObject* ModuleBuilder::createArray(const GCVector<T>& vector)
{
uint32_t length = vector.length();
RootedArrayObject array(cx_, NewDenseFullyAllocatedArray(cx_, length));
+6 -6
View File
@@ -12,7 +12,7 @@
#include "gc/Zone.h"
#include "js/TraceableVector.h"
#include "js/GCVector.h"
#include "vm/NativeObject.h"
#include "vm/ProxyObject.h"
@@ -196,7 +196,7 @@ struct FunctionDeclaration
RelocatablePtrFunction fun;
};
using FunctionDeclarationVector = TraceableVector<FunctionDeclaration, 0, ZoneAllocPolicy>;
using FunctionDeclarationVector = GCVector<FunctionDeclaration, 0, ZoneAllocPolicy>;
class ModuleObject : public NativeObject
{
@@ -282,7 +282,7 @@ class MOZ_STACK_CLASS ModuleBuilder
bool hasExportedName(JSAtom* name) const;
using ExportEntryVector = TraceableVector<ExportEntryObject*>;
using ExportEntryVector = GCVector<ExportEntryObject*>;
const ExportEntryVector& localExportEntries() const {
return localExportEntries_;
}
@@ -291,9 +291,9 @@ class MOZ_STACK_CLASS ModuleBuilder
bool initModule();
private:
using AtomVector = TraceableVector<JSAtom*>;
using AtomVector = GCVector<JSAtom*>;
using RootedAtomVector = JS::Rooted<AtomVector>;
using ImportEntryVector = TraceableVector<ImportEntryObject*>;
using ImportEntryVector = GCVector<ImportEntryObject*>;
using RootedImportEntryVector = JS::Rooted<ImportEntryVector>;
using RootedExportEntryVector = JS::Rooted<ExportEntryVector>;
@@ -316,7 +316,7 @@ class MOZ_STACK_CLASS ModuleBuilder
bool maybeAppendRequestedModule(HandleAtom module);
template <typename T>
ArrayObject* createArray(const TraceableVector<T>& vector);
ArrayObject* createArray(const GCVector<T>& vector);
};
bool InitModuleClasses(JSContext* cx, HandleObject obj);
+2 -4
View File
@@ -7,13 +7,13 @@
#include "builtin/Object.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/UniquePtr.h"
#include "jscntxt.h"
#include "builtin/Eval.h"
#include "frontend/BytecodeCompiler.h"
#include "jit/InlinableNatives.h"
#include "js/UniquePtr.h"
#include "vm/StringBuffer.h"
#include "jsobjinlines.h"
@@ -25,7 +25,6 @@ using namespace js;
using js::frontend::IsIdentifier;
using mozilla::ArrayLength;
using mozilla::UniquePtr;
bool
js::obj_construct(JSContext* cx, unsigned argc, Value* vp)
@@ -631,8 +630,7 @@ js::obj_create(JSContext* cx, unsigned argc, Value* vp)
if (!args[0].isObjectOrNull()) {
RootedValue v(cx, args[0]);
UniquePtr<char[], JS::FreePolicy> bytes =
DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, nullptr);
UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, nullptr);
if (!bytes)
return false;
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_UNEXPECTED_TYPE,
+1 -1
View File
@@ -2448,7 +2448,7 @@ ASTSerializer::statement(ParseNode* pn, MutableHandleValue dst)
pn = pn->pn_expr;
if (!pn->isKind(PNK_STATEMENTLIST))
return statement(pn, dst);
/* FALL THROUGH */
MOZ_FALLTHROUGH;
case PNK_STATEMENTLIST:
return blockStatement(pn, dst);
+58 -59
View File
@@ -7,7 +7,8 @@
#include "builtin/TestingFunctions.h"
#include "mozilla/Move.h"
#include "mozilla/UniquePtr.h"
#include <cmath>
#include "jsapi.h"
#include "jscntxt.h"
@@ -25,6 +26,7 @@
#include "js/StructuredClone.h"
#include "js/UbiNode.h"
#include "js/UbiNodeBreadthFirst.h"
#include "js/UniquePtr.h"
#include "js/Vector.h"
#include "vm/GlobalObject.h"
#include "vm/Interpreter.h"
@@ -43,7 +45,6 @@ using namespace js;
using mozilla::ArrayLength;
using mozilla::Move;
using mozilla::UniquePtr;
// If fuzzingSafe is set, remove functionality that could cause problems with
// fuzzers. Set this via the environment variable MOZ_FUZZING_SAFE.
@@ -320,22 +321,45 @@ MinorGC(JSContext* cx, unsigned argc, Value* vp)
return true;
}
static const struct ParamPair {
#define FOR_EACH_GC_PARAM(_) \
_("maxBytes", JSGC_MAX_BYTES, true, false) \
_("maxMallocBytes", JSGC_MAX_MALLOC_BYTES, true, false) \
_("gcBytes", JSGC_BYTES, false, false) \
_("gcNumber", JSGC_NUMBER, false, false) \
_("mode", JSGC_MODE, true, true) \
_("unusedChunks", JSGC_UNUSED_CHUNKS, false, false) \
_("totalChunks", JSGC_TOTAL_CHUNKS, false, false) \
_("sliceTimeBudget", JSGC_SLICE_TIME_BUDGET, true, false) \
_("markStackLimit", JSGC_MARK_STACK_LIMIT, true, false) \
_("highFrequencyTimeLimit", JSGC_HIGH_FREQUENCY_TIME_LIMIT, true, false) \
_("highFrequencyLowLimit", JSGC_HIGH_FREQUENCY_LOW_LIMIT, true, false) \
_("highFrequencyHighLimit", JSGC_HIGH_FREQUENCY_HIGH_LIMIT, true, false) \
_("highFrequencyHeapGrowthMax", JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX, true, false) \
_("highFrequencyHeapGrowthMin", JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN, true, false) \
_("lowFrequencyHeapGrowth", JSGC_LOW_FREQUENCY_HEAP_GROWTH, true, false) \
_("dynamicHeapGrowth", JSGC_DYNAMIC_HEAP_GROWTH, true, true) \
_("dynamicMarkSlice", JSGC_DYNAMIC_MARK_SLICE, true, true) \
_("allocationThreshold", JSGC_ALLOCATION_THRESHOLD, true, false) \
_("decommitThreshold", JSGC_DECOMMIT_THRESHOLD, true, false) \
_("minEmptyChunkCount", JSGC_MIN_EMPTY_CHUNK_COUNT, true, true) \
_("maxEmptyChunkCount", JSGC_MAX_EMPTY_CHUNK_COUNT, true, true) \
_("compactingEnabled", JSGC_COMPACTING_ENABLED, true, true)
static const struct ParamInfo {
const char* name;
JSGCParamKey param;
bool writable;
bool allowZero;
} paramMap[] = {
{"maxBytes", JSGC_MAX_BYTES },
{"maxMallocBytes", JSGC_MAX_MALLOC_BYTES},
{"gcBytes", JSGC_BYTES},
{"gcNumber", JSGC_NUMBER},
{"sliceTimeBudget", JSGC_SLICE_TIME_BUDGET},
{"markStackLimit", JSGC_MARK_STACK_LIMIT},
{"minEmptyChunkCount", JSGC_MIN_EMPTY_CHUNK_COUNT},
{"maxEmptyChunkCount", JSGC_MAX_EMPTY_CHUNK_COUNT}
#define DEFINE_PARAM_INFO(name, key, writable, allowZero) \
{name, key, writable, allowZero},
FOR_EACH_GC_PARAM(DEFINE_PARAM_INFO)
#undef DEFINE_PARAM_INFO
};
// Keep this in sync with above params.
#define GC_PARAMETER_ARGS_LIST "maxBytes, maxMallocBytes, gcBytes, gcNumber, sliceTimeBudget, markStackLimit, minEmptyChunkCount or maxEmptyChunkCount"
#define PARAM_NAME_LIST_ENTRY(name, key, writable, allowZero) \
" " name
#define GC_PARAMETER_ARGS_LIST FOR_EACH_GC_PARAM(PARAM_NAME_LIST_ENTRY)
static bool
GCParameter(JSContext* cx, unsigned argc, Value* vp)
@@ -354,13 +378,14 @@ GCParameter(JSContext* cx, unsigned argc, Value* vp)
for (;; paramIndex++) {
if (paramIndex == ArrayLength(paramMap)) {
JS_ReportError(cx,
"the first argument must be one of " GC_PARAMETER_ARGS_LIST);
"the first argument must be one of:" GC_PARAMETER_ARGS_LIST);
return false;
}
if (JS_FlatStringEqualsAscii(flatStr, paramMap[paramIndex].name))
break;
}
JSGCParamKey param = paramMap[paramIndex].param;
const ParamInfo& info = paramMap[paramIndex];
JSGCParamKey param = info.param;
// Request mode.
if (args.length() == 1) {
@@ -369,9 +394,8 @@ GCParameter(JSContext* cx, unsigned argc, Value* vp)
return true;
}
if (param == JSGC_NUMBER || param == JSGC_BYTES) {
JS_ReportError(cx, "Attempt to change read-only parameter %s",
paramMap[paramIndex].name);
if (!info.writable) {
JS_ReportError(cx, "Attempt to change read-only parameter %s", info.name);
return false;
}
@@ -380,11 +404,17 @@ GCParameter(JSContext* cx, unsigned argc, Value* vp)
return true;
}
uint32_t value;
if (!ToUint32(cx, args[1], &value))
double d;
if (!ToNumber(cx, args[1], &d))
return false;
if (!value) {
if (d < 0 || d > UINT32_MAX) {
JS_ReportError(cx, "Parameter value out of range");
return false;
}
uint32_t value = floor(d);
if (!info.allowZero && value == 0) {
JS_ReportError(cx, "the second argument must be convertable to uint32_t "
"with non-zero value");
return false;
@@ -479,7 +509,7 @@ IsRelazifiableFunction(JSContext* cx, unsigned argc, Value* vp)
!args[0].toObject().is<JSFunction>())
{
JS_ReportError(cx, "The first argument should be a function.");
return true;
return false;
}
JSFunction* fun = &args[0].toObject().as<JSFunction>();
@@ -2266,7 +2296,7 @@ ReportLargeAllocationFailure(JSContext* cx, unsigned argc, Value* vp)
namespace heaptools {
typedef UniquePtr<char16_t[], JS::FreePolicy> EdgeName;
typedef UniqueTwoByteChars EdgeName;
// An edge to a node from its predecessor in a path through the graph.
class BackEdge {
@@ -2505,10 +2535,10 @@ EvalReturningScope(JSContext* cx, unsigned argc, Value* vp)
size_t srclen = chars.length();
const char16_t* src = chars.start().get();
JS::AutoFilename filename;
JS::UniqueChars filename;
unsigned lineno;
DescribeScriptedCaller(cx, &filename, &lineno);
JS::DescribeScriptedCaller(cx, &filename, &lineno);
JS::CompileOptions options(cx);
options.setFileAndLine(filename.get(), lineno);
@@ -2591,10 +2621,10 @@ ShellCloneAndExecuteScript(JSContext* cx, unsigned argc, Value* vp)
size_t srclen = chars.length();
const char16_t* src = chars.start().get();
JS::AutoFilename filename;
JS::UniqueChars filename;
unsigned lineno;
DescribeScriptedCaller(cx, &filename, &lineno);
JS::DescribeScriptedCaller(cx, &filename, &lineno);
JS::CompileOptions options(cx);
options.setFileAndLine(filename.get(), lineno);
@@ -2958,32 +2988,6 @@ SetGCCallback(JSContext* cx, unsigned argc, Value* vp)
return true;
}
static bool
SetARMHwCapFlags(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() != 1) {
JS_ReportError(cx, "Wrong number of arguments");
return false;
}
RootedString flagsListString(cx, JS::ToString(cx, args.get(0)));
if (!flagsListString)
return false;
#if defined(JS_CODEGEN_ARM)
JSAutoByteString flagsList(cx, flagsListString);
if (!flagsList)
return false;
jit::ParseARMHwCapFlags(flagsList.ptr());
#endif
args.rval().setUndefined();
return true;
}
static bool
GetLcovInfo(JSContext* cx, unsigned argc, Value* vp)
{
@@ -3165,7 +3169,7 @@ static const JSFunctionSpecWithHelp TestingFunctions[] = {
JS_FN_HELP("gcparam", GCParameter, 2, 0,
"gcparam(name [, value])",
" Wrapper for JS_[GS]etGCParameter. The name is one of " GC_PARAMETER_ARGS_LIST),
" Wrapper for JS_[GS]etGCParameter. The name is one of:" GC_PARAMETER_ARGS_LIST),
JS_FN_HELP("relazifyFunctions", RelazifyFunctions, 0, 0,
"relazifyFunctions(...)",
@@ -3616,11 +3620,6 @@ gc::ZealModeHelpText),
" 'minorGC' - run a nursery collection\n"
" 'majorGC' - run a major collection, nesting up to a given 'depth'\n"),
JS_FN_HELP("setARMHwCapFlags", SetARMHwCapFlags, 1, 0,
"setARMHwCapFlags(\"flag1,flag2 flag3\")",
" On non-ARM, no-op. On ARM, set the hardware capabilities. The list of \n"
" flags is available by calling this function with \"help\" as the flag's name"),
JS_FN_HELP("getLcovInfo", GetLcovInfo, 1, 0,
"getLcovInfo(global)",
" Generate LCOV tracefile for the given compartment. If no global are provided then\n"
+2 -5
View File
@@ -14,8 +14,6 @@
using namespace js;
using namespace js::gc;
using mozilla::UniquePtr;
MOZ_ALWAYS_INLINE bool
IsWeakMap(HandleValue v)
{
@@ -191,8 +189,7 @@ WeakMap_set_impl(JSContext* cx, const CallArgs& args)
MOZ_ASSERT(IsWeakMap(args.thisv()));
if (!args.get(0).isObject()) {
UniquePtr<char[], JS::FreePolicy> bytes =
DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, args.get(0), nullptr);
UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, args.get(0), nullptr);
if (!bytes)
return false;
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, bytes.get());
@@ -377,7 +374,7 @@ WeakMap_construct(JSContext* cx, unsigned argc, Value* vp)
// Steps 12k-l.
if (isOriginalAdder) {
if (keyVal.isPrimitive()) {
UniquePtr<char[], JS::FreePolicy> bytes =
UniqueChars bytes =
DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, keyVal, nullptr);
if (!bytes)
return false;
+1 -3
View File
@@ -22,8 +22,6 @@
using namespace js;
using mozilla::UniquePtr;
const Class WeakSetObject::class_ = {
"WeakSet",
JSCLASS_HAS_CACHED_PROTO(JSProto_WeakSet) |
@@ -127,7 +125,7 @@ WeakSetObject::construct(JSContext* cx, unsigned argc, Value* vp)
if (isOriginalAdder) {
if (keyVal.isPrimitive()) {
UniquePtr<char[], JS::FreePolicy> bytes =
UniqueChars bytes =
DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, keyVal, nullptr);
if (!bytes)
return false;
+3 -2
View File
@@ -4093,7 +4093,8 @@ CType::Finalize(JSFreeOp* fop, JSObject* obj)
}
}
// Fall through.
MOZ_FALLTHROUGH;
case TYPE_array: {
// Free the ffi_type info.
slot = JS_GetReservedSlot(obj, SLOT_FFITYPE);
@@ -6872,7 +6873,7 @@ CClosure::Create(JSContext* cx,
// we might be unable to convert the value to the proper type. If so, we want
// the caller to know about it _now_, rather than some uncertain time in the
// future when the error sentinel is actually needed.
mozilla::UniquePtr<uint8_t[], JS::FreePolicy> errResult;
UniquePtr<uint8_t[], JS::FreePolicy> errResult;
if (!errVal.isUndefined()) {
// Make sure the callback returns something.
+2 -2
View File
@@ -6,7 +6,6 @@
#ifndef ctypes_CTypes_h
#define ctypes_CTypes_h
#include "mozilla/UniquePtr.h"
#include "mozilla/Vector.h"
#include "ffi.h"
@@ -16,6 +15,7 @@
#include "ctypes/typedefs.h"
#include "js/GCHashTable.h"
#include "js/UniquePtr.h"
#include "js/Vector.h"
#include "vm/String.h"
@@ -467,7 +467,7 @@ namespace PointerType {
JSObject* GetBaseType(JSObject* obj);
} // namespace PointerType
typedef mozilla::UniquePtr<ffi_type, JS::DeletePolicy<ffi_type>> UniquePtrFFIType;
typedef UniquePtr<ffi_type> UniquePtrFFIType;
namespace ArrayType {
JSObject* CreateInternal(JSContext* cx, HandleObject baseType, size_t length,
+2 -2
View File
@@ -11,8 +11,8 @@
#include "NamespaceImports.h"
#include "gc/Tracer.h"
#include "js/GCVector.h"
#include "js/Id.h"
#include "js/TraceableVector.h"
namespace js {
@@ -37,7 +37,7 @@ struct IdValuePair
}
};
using IdValueVector = TraceableVector<IdValuePair>;
using IdValueVector = GCVector<IdValuePair>;
} /* namespace js */
+84 -4
View File
@@ -15,7 +15,6 @@
#include "mozilla/FloatingPoint.h"
#include "mozilla/Maybe.h"
#include "mozilla/PodOperations.h"
#include "mozilla/UniquePtr.h"
#include <string.h>
@@ -54,7 +53,6 @@ using mozilla::Some;
using mozilla::DebugOnly;
using mozilla::NumberIsInt32;
using mozilla::PodCopy;
using mozilla::UniquePtr;
struct frontend::StmtInfoBCE : public StmtInfoBase
{
@@ -2109,6 +2107,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
// Any subexpression of a comma expression could be effectful.
case PNK_COMMA:
MOZ_ASSERT(pn->pn_count > 0);
MOZ_FALLTHROUGH;
// Subcomponents of a literal may be effectful.
case PNK_ARRAY:
case PNK_OBJECT:
@@ -7284,6 +7283,76 @@ BytecodeEmitter::emitSelfHostedAllowContentSpread(ParseNode* pn)
return emitTree(pn->pn_head->pn_next);
}
bool
BytecodeEmitter::isRestParameter(ParseNode* pn, bool* result)
{
if (!sc->isFunctionBox()) {
*result = false;
return true;
}
RootedFunction fun(cx, sc->asFunctionBox()->function());
if (!fun->hasRest()) {
*result = false;
return true;
}
if (!pn->isKind(PNK_NAME)) {
if (emitterMode == BytecodeEmitter::SelfHosting && pn->isKind(PNK_CALL)) {
ParseNode* pn2 = pn->pn_head;
if (pn2->getKind() == PNK_NAME && pn2->name() == cx->names().allowContentSpread)
return isRestParameter(pn2->pn_next, result);
}
*result = false;
return true;
}
if (!bindNameToSlot(pn))
return false;
*result = pn->getOp() == JSOP_GETARG && pn->pn_scopecoord.slot() == fun->nargs() - 1;
return true;
}
bool
BytecodeEmitter::emitOptimizeSpread(ParseNode* arg0, ptrdiff_t* jmp, bool* emitted)
{
// Emit a pereparation code to optimize the spread call with a rest
// parameter:
//
// function f(...args) {
// g(...args);
// }
//
// If the spread operand is a rest parameter and it's optimizable array,
// skip spread operation and pass it directly to spread call operation.
// See the comment in OptimizeSpreadCall in Interpreter.cpp for the
// optimizable conditons.
bool result = false;
if (!isRestParameter(arg0, &result))
return false;
if (!result) {
*emitted = false;
return true;
}
if (!emitTree(arg0))
return false;
if (!emit1(JSOP_OPTIMIZE_SPREADCALL))
return false;
if (!emitJump(JSOP_IFNE, 0, jmp))
return false;
if (!emit1(JSOP_POP))
return false;
*emitted = true;
return true;
}
bool
BytecodeEmitter::emitCallOrNew(ParseNode* pn)
{
@@ -7436,9 +7505,20 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn)
}
}
} else {
if (!emitArray(pn2->pn_next, argc, JSOP_SPREADCALLARRAY))
ParseNode* args = pn2->pn_next;
ptrdiff_t jmp;
bool optCodeEmitted = false;
if (argc == 1) {
if (!emitOptimizeSpread(args->pn_kid, &jmp, &optCodeEmitted))
return false;
}
if (!emitArray(args, argc, JSOP_SPREADCALLARRAY))
return false;
if (optCodeEmitted)
setJumpOffsetAt(jmp);
if (isNewOp) {
if (pn->isKind(PNK_SUPERCALL)) {
if (!emit1(JSOP_NEWTARGET))
@@ -8805,7 +8885,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote)
break;
case PNK_POSHOLDER:
MOZ_ASSERT_UNREACHABLE("Should never try to emit PNK_POSHOLDER");
MOZ_FALLTHROUGH_ASSERT("Should never try to emit PNK_POSHOLDER");
default:
MOZ_ASSERT(0);
+3
View File
@@ -607,6 +607,9 @@ struct BytecodeEmitter
bool emitConditionalExpression(ConditionalExpression& conditional);
bool isRestParameter(ParseNode* pn, bool* result);
bool emitOptimizeSpread(ParseNode* arg0, ptrdiff_t* jmp, bool* emitted);
bool emitCallOrNew(ParseNode* pn);
bool emitDebugOnlyCheckSelfHosted();
bool emitSelfHostedCallFunction(ParseNode* pn);
+2 -2
View File
@@ -156,7 +156,7 @@ class NameResolver
* flagged as a contributor.
*/
pos--;
/* fallthrough */
MOZ_FALLTHROUGH;
default:
/* Save any other nodes we encounter on the way up. */
@@ -727,8 +727,8 @@ class NameResolver
// Import/export spec lists contain import/export specs containing
// only pairs of names. Alternatively, an export spec lists may
// contain a single export batch specifier.
case PNK_IMPORT_SPEC_LIST: {
case PNK_EXPORT_SPEC_LIST:
case PNK_IMPORT_SPEC_LIST: {
MOZ_ASSERT(cur->isArity(PN_LIST));
#ifdef DEBUG
bool isImport = cur->isKind(PNK_IMPORT_SPEC_LIST);
+4 -4
View File
@@ -6300,7 +6300,7 @@ Parser<ParseHandler>::yieldExpression(InHandling inHandling)
case TOK_MUL:
kind = PNK_YIELD_STAR;
tokenStream.consumeKnownToken(TOK_MUL, TokenStream::Operand);
// Fall through.
MOZ_FALLTHROUGH;
default:
exprNode = assignExpr(inHandling, YieldIsKeyword, TripledotProhibited);
if (!exprNode)
@@ -6331,7 +6331,7 @@ Parser<ParseHandler>::yieldExpression(InHandling inHandling)
JSMSG_BAD_ANON_GENERATOR_RETURN);
return null();
}
// Fall through.
MOZ_FALLTHROUGH;
case LegacyGenerator:
{
@@ -6602,7 +6602,7 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
// check its validity for legacy generators.
if (!checkYieldNameValidity())
return null();
// Fall through.
MOZ_FALLTHROUGH;
case TOK_NAME:
{
RootedPropertyName label(context, tokenStream.currentName());
@@ -9717,7 +9717,7 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
case TOK_YIELD:
if (!checkYieldNameValidity())
return null();
// Fall through.
MOZ_FALLTHROUGH;
case TOK_NAME:
return identifierName(yieldHandling);
+2 -2
View File
@@ -236,7 +236,7 @@ struct MOZ_STACK_CLASS ParseContext : public GenericParseContext
OwnedAtomDefnMapPtr lexdeps; /* unresolved lexical name dependencies */
// All inner functions in this context. Only filled in when parsing syntax.
Rooted<TraceableVector<JSFunction*>> innerFunctions;
Rooted<GCVector<JSFunction*>> innerFunctions;
// In a function context, points to a Directive struct that can be updated
// to reflect new directives encountered in the Directive Prologue that
@@ -272,7 +272,7 @@ struct MOZ_STACK_CLASS ParseContext : public GenericParseContext
parserPC(&prs->pc),
oldpc(prs->pc),
lexdeps(prs->context),
innerFunctions(prs->context, TraceableVector<JSFunction*>(prs->context)),
innerFunctions(prs->context, GCVector<JSFunction*>(prs->context)),
newDirectives(newDirectives),
inDeclDestructuring(false)
{
+6 -4
View File
@@ -10,7 +10,6 @@
#include "mozilla/IntegerTypeTraits.h"
#include "mozilla/PodOperations.h"
#include "mozilla/UniquePtr.h"
#include <ctype.h>
#include <stdarg.h>
@@ -25,6 +24,7 @@
#include "frontend/BytecodeCompiler.h"
#include "js/CharacterEncoding.h"
#include "js/UniquePtr.h"
#include "vm/HelperThreads.h"
#include "vm/Keywords.h"
#include "vm/StringBuffer.h"
@@ -37,7 +37,6 @@ using mozilla::Maybe;
using mozilla::PodAssign;
using mozilla::PodCopy;
using mozilla::PodZero;
using mozilla::UniquePtr;
struct KeywordInfo {
const char* chars; // C string with keyword text
@@ -617,7 +616,10 @@ TokenStream::reportCompileErrorNumberVA(uint32_t offset, unsigned flags, unsigne
// On the main thread, report the error immediately. When compiling off
// thread, save the error so that the main thread can report it later.
CompileError tempErr;
CompileError& err = cx->isJSContext() ? tempErr : cx->addPendingCompileError();
CompileError* tempErrPtr = &tempErr;
if (!cx->isJSContext() && !cx->addPendingCompileError(&tempErrPtr))
return false;
CompileError& err = *tempErrPtr;
err.report.flags = flags;
err.report.errorNumber = errorNumber;
@@ -854,7 +856,7 @@ bool
TokenStream::getDirective(bool isMultiline, bool shouldWarnDeprecated,
const char* directive, int directiveLength,
const char* errorMsgPragma,
UniquePtr<char16_t[], JS::FreePolicy>* destination)
UniqueTwoByteChars* destination)
{
MOZ_ASSERT(directiveLength <= 18);
char16_t peeked[18];
+5 -5
View File
@@ -14,7 +14,6 @@
#include "mozilla/Attributes.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/PodOperations.h"
#include "mozilla/UniquePtr.h"
#include <stdarg.h>
#include <stddef.h>
@@ -24,6 +23,7 @@
#include "jspubtd.h"
#include "frontend/TokenKind.h"
#include "js/UniquePtr.h"
#include "js/Vector.h"
#include "vm/RegExpObject.h"
@@ -976,7 +976,7 @@ class MOZ_STACK_CLASS TokenStream
bool getDirective(bool isMultiline, bool shouldWarnDeprecated,
const char* directive, int directiveLength,
const char* errorMsgPragma,
mozilla::UniquePtr<char16_t[], JS::FreePolicy>* destination);
UniquePtr<char16_t[], JS::FreePolicy>* destination);
bool getDisplayURL(bool isMultiline, bool shouldWarnDeprecated);
bool getSourceMappingURL(bool isMultiline, bool shouldWarnDeprecated);
@@ -1024,9 +1024,9 @@ class MOZ_STACK_CLASS TokenStream
size_t linebase; // start of current line
size_t prevLinebase; // start of previous line; size_t(-1) if on the first line
TokenBuf userbuf; // user input buffer
const char* filename; // input filename or null
mozilla::UniquePtr<char16_t[], JS::FreePolicy> displayURL_; // the user's requested source URL or null
mozilla::UniquePtr<char16_t[], JS::FreePolicy> sourceMapURL_; // source map's filename or null
const char* filename; // input filename or null
UniqueTwoByteChars displayURL_; // the user's requested source URL or null
UniqueTwoByteChars sourceMapURL_; // source map's filename or null
CharBuffer tokenbuf; // current token string buffer
uint8_t isExprEnding[TOK_LIMIT];// which tokens definitely terminate exprs?
ExclusiveContext* const cx;
+3 -2
View File
@@ -471,13 +471,14 @@ struct DefaultGCPolicy<T*>
static void trace(JSTracer* trc, T** thingp, const char* name) {
// If linking is failing here, it likely means that you need to define
// or use a non-default GC policy for your non-gc-pointer type.
TraceManuallyBarrieredEdge(trc, thingp, name);
if (*thingp)
TraceManuallyBarrieredEdge(trc, thingp, name);
}
static bool needsSweep(T** thingp) {
// If linking is failing here, it likely means that you need to define
// or use a non-default GC policy for your non-gc-pointer type.
return gc::IsAboutToBeFinalizedUnbarriered(thingp);
return *thingp && gc::IsAboutToBeFinalizedUnbarriered(thingp);
}
};
+5
View File
@@ -55,6 +55,11 @@ typedef JS::Rooted<PlainObject*> RootedPlainObject;
typedef JS::Rooted<SavedFrame*> RootedSavedFrame;
typedef JS::Rooted<ScriptSourceObject*> RootedScriptSource;
typedef GCVector<JSFunction*> FunctionVector;
typedef GCVector<PropertyName*> PropertyNameVector;
typedef GCVector<Shape*> ShapeVector;
typedef GCVector<JSString*> StringVector;
} /* namespace js */
#endif /* gc_Rooting_h */
+23 -24
View File
@@ -9,7 +9,6 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/IntegerRange.h"
#include "mozilla/PodOperations.h"
#include "mozilla/UniquePtr.h"
#include <ctype.h>
#include <stdarg.h>
@@ -342,7 +341,7 @@ Statistics::formatCompactSliceMessage() const
slice.resetReason ? "yes - " : "no", slice.resetReason ? slice.resetReason : "");
FragmentVector fragments;
if (!fragments.append(make_string_copy(buffer)) ||
if (!fragments.append(DuplicateString(buffer)) ||
!fragments.append(formatCompactSlicePhaseTimes(slices[index].phaseTimes)))
{
return UniqueChars(nullptr);
@@ -356,7 +355,7 @@ Statistics::formatCompactSummaryMessage() const
const double bytesPerMiB = 1024 * 1024;
FragmentVector fragments;
if (!fragments.append(make_string_copy("Summary - ")))
if (!fragments.append(DuplicateString("Summary - ")))
return UniqueChars(nullptr);
int64_t total, longest;
@@ -374,7 +373,7 @@ Statistics::formatCompactSummaryMessage() const
JS_snprintf(buffer, sizeof(buffer), "Non-Incremental: %.3fms (%s); ",
t(total), nonincrementalReason_);
}
if (!fragments.append(make_string_copy(buffer)))
if (!fragments.append(DuplicateString(buffer)))
return UniqueChars(nullptr);
JS_snprintf(buffer, sizeof(buffer),
@@ -385,7 +384,7 @@ Statistics::formatCompactSummaryMessage() const
double(preBytes) / bytesPerMiB,
counts[STAT_NEW_CHUNK] - counts[STAT_DESTROY_CHUNK],
counts[STAT_NEW_CHUNK] + counts[STAT_DESTROY_CHUNK]);
if (!fragments.append(make_string_copy(buffer)))
if (!fragments.append(DuplicateString(buffer)))
return UniqueChars(nullptr);
MOZ_ASSERT_IF(counts[STAT_ARENA_RELOCATED], gckind == GC_SHRINK);
@@ -394,7 +393,7 @@ Statistics::formatCompactSummaryMessage() const
"Kind: %s; Relocated: %.3f MiB; ",
ExplainInvocationKind(gckind),
double(ArenaSize * counts[STAT_ARENA_RELOCATED]) / bytesPerMiB);
if (!fragments.append(make_string_copy(buffer)))
if (!fragments.append(DuplicateString(buffer)))
return UniqueChars(nullptr);
}
@@ -419,13 +418,13 @@ Statistics::formatCompactSlicePhaseTimes(const PhaseTimeTable phaseTimes) const
int64_t childTime = SumChildTimes(dagSlot, phase, phaseTimes);
if (ownTime > MaxUnaccountedTimeUS) {
JS_snprintf(buffer, sizeof(buffer), "%s: %.3fms", phases[phase].name, t(ownTime));
if (!fragments.append(make_string_copy(buffer)))
if (!fragments.append(DuplicateString(buffer)))
return UniqueChars(nullptr);
if (childTime && (ownTime - childTime) > MaxUnaccountedTimeUS) {
MOZ_ASSERT(level < 3);
JS_snprintf(buffer, sizeof(buffer), "%s: %.3fms", "Other", t(ownTime - childTime));
if (!fragments.append(make_string_copy(buffer)))
if (!fragments.append(DuplicateString(buffer)))
return UniqueChars(nullptr);
}
}
@@ -500,7 +499,7 @@ Statistics::formatDetailedDescription()
counts[STAT_NEW_CHUNK] - counts[STAT_DESTROY_CHUNK], counts[STAT_NEW_CHUNK] +
counts[STAT_DESTROY_CHUNK],
double(ArenaSize * counts[STAT_ARENA_RELOCATED]) / bytesPerMiB);
return make_string_copy(buffer);
return DuplicateString(buffer);
}
UniqueChars
@@ -524,7 +523,7 @@ Statistics::formatDetailedSliceDescription(unsigned i, const SliceData& slice)
slice.resetReason ? "yes - " : "no", slice.resetReason ? slice.resetReason : "",
uint64_t(slice.endFaults - slice.startFaults),
t(slice.duration()), budgetDescription, t(slice.start - slices[0].start));
return make_string_copy(buffer);
return DuplicateString(buffer);
}
UniqueChars
@@ -547,14 +546,14 @@ Statistics::formatDetailedPhaseTimes(const PhaseTimeTable phaseTimes)
if (ownTime > 0) {
JS_snprintf(buffer, sizeof(buffer), " %s%s: %.3fms\n",
LevelToIndent[level], phases[phase].name, t(ownTime));
if (!fragments.append(make_string_copy(buffer)))
if (!fragments.append(DuplicateString(buffer)))
return UniqueChars(nullptr);
if (childTime && (ownTime - childTime) > MaxUnaccountedChildTimeUS) {
MOZ_ASSERT(level < 3);
JS_snprintf(buffer, sizeof(buffer), " %s%s: %.3fms\n",
LevelToIndent[level + 1], "Other", t(ownTime - childTime));
if (!fragments.append(make_string_copy(buffer)))
if (!fragments.append(DuplicateString(buffer)))
return UniqueChars(nullptr);
}
}
@@ -577,7 +576,7 @@ Statistics::formatDetailedTotals()
char buffer[1024];
memset(buffer, 0, sizeof(buffer));
JS_snprintf(buffer, sizeof(buffer), format, t(total), t(longest));
return make_string_copy(buffer);
return DuplicateString(buffer);
}
UniqueChars
@@ -587,28 +586,28 @@ Statistics::formatJsonMessage(uint64_t timestamp)
FragmentVector fragments;
if (!fragments.append(make_string_copy("{")) ||
if (!fragments.append(DuplicateString("{")) ||
!fragments.append(formatJsonDescription(timestamp)) ||
!fragments.append(make_string_copy("\"slices\":[")))
!fragments.append(DuplicateString("\"slices\":[")))
{
return UniqueChars(nullptr);
}
for (unsigned i = 0; i < slices.length(); i++) {
if (!fragments.append(make_string_copy("{")) ||
if (!fragments.append(DuplicateString("{")) ||
!fragments.append(formatJsonSliceDescription(i, slices[i])) ||
!fragments.append(make_string_copy("\"times\":{")) ||
!fragments.append(DuplicateString("\"times\":{")) ||
!fragments.append(formatJsonPhaseTimes(slices[i].phaseTimes)) ||
!fragments.append(make_string_copy("}}")) ||
(i < (slices.length() - 1) && !fragments.append(make_string_copy(","))))
!fragments.append(DuplicateString("}}")) ||
(i < (slices.length() - 1) && !fragments.append(DuplicateString(","))))
{
return UniqueChars(nullptr);
}
}
if (!fragments.append(make_string_copy("],\"totals\":{")) ||
if (!fragments.append(DuplicateString("],\"totals\":{")) ||
!fragments.append(formatJsonPhaseTimes(phaseTimes)) ||
!fragments.append(make_string_copy("}}")))
!fragments.append(DuplicateString("}}")))
{
return UniqueChars(nullptr);
}
@@ -664,7 +663,7 @@ Statistics::formatJsonDescription(uint64_t timestamp)
unsigned(preBytes / 1024 / 1024),
counts[STAT_NEW_CHUNK],
counts[STAT_DESTROY_CHUNK]);
return make_string_copy(buffer);
return DuplicateString(buffer);
}
UniqueChars
@@ -696,7 +695,7 @@ Statistics::formatJsonSliceDescription(unsigned i, const SliceData& slice)
pageFaults,
slices[i].start,
slices[i].end);
return make_string_copy(buffer);
return DuplicateString(buffer);
}
UniqueChars
@@ -729,7 +728,7 @@ Statistics::formatJsonPhaseTimes(const PhaseTimeTable phaseTimes)
JS_snprintf(buffer, sizeof(buffer), "\"%s\":%llu.%03llu",
name.get(), ownTime / 1000, ownTime % 1000);
if (!fragments.append(make_string_copy(buffer)))
if (!fragments.append(DuplicateString(buffer)))
return UniqueChars(nullptr);
}
return Join(fragments, ",");
-1
View File
@@ -10,7 +10,6 @@
#include "mozilla/DebugOnly.h"
#include "mozilla/IntegerRange.h"
#include "mozilla/PodOperations.h"
#include "mozilla/UniquePtr.h"
#include "jsalloc.h"
#include "jsgc.h"
+1 -1
View File
@@ -3815,7 +3815,7 @@ EmitAtomLetter(RegExpCompiler* compiler,
}
case 4:
macro_assembler->CheckCharacter(chars[3], &ok);
// Fall through!
MOZ_FALLTHROUGH;
case 3:
macro_assembler->CheckCharacter(chars[0], &ok);
macro_assembler->CheckCharacter(chars[1], &ok);
+3 -3
View File
@@ -1563,7 +1563,7 @@ RegExpParser<CharT>::ParseDisjunction()
Advance();
break;
}
// Fall through
MOZ_FALLTHROUGH;
case 'd': case 's': case 'w': {
widechar c = Next();
Advance(2);
@@ -1605,8 +1605,8 @@ RegExpParser<CharT>::ParseDisjunction()
Advance(2);
break;
}
MOZ_FALLTHROUGH;
}
// FALLTHROUGH
case '0': {
if (unicode_) {
Advance(2);
@@ -1735,7 +1735,7 @@ RegExpParser<CharT>::ParseDisjunction()
int dummy;
if (ParseIntervalQuantifier(&dummy, &dummy))
return ReportError(JSMSG_NOTHING_TO_REPEAT);
// fallthrough
MOZ_FALLTHROUGH;
}
default:
if (unicode_) {
@@ -97,6 +97,12 @@ var exp = asmLink(asmCompile(USE_ASM + "function f() { return 3 } return {f:f,f:
assertEq(exp.f(), 3);
assertEq(Object.keys(exp).join(), 'f');
var exp = asmLink(asmCompile(USE_ASM + "function f() { return 4 } return {f1:f,f2:f}"));
assertEq(exp.f1(), 4);
assertEq(exp.f2(), 4);
assertEq(Object.keys(exp).sort().join(), 'f1,f2');
assertEq(exp.f1, exp.f2);
assertAsmTypeFail(USE_ASM + "function f() { return 3 } return {1:f}");
assertAsmTypeFail(USE_ASM + "function f() { return 3 } return {__proto__:f}");
assertAsmTypeFail(USE_ASM + "function f() { return 3 } return {get x() {} }");
@@ -0,0 +1,3 @@
g = newGlobal();
Debugger(g).memory.trackingAllocationSites = true;
evaluate("function h() { 'use asm'; return {}}", { global: g });
+16
View File
@@ -0,0 +1,16 @@
// |jit-test| allow-oom; allow-unhandlable-oom
// 1236476
if (typeof oomTest !== 'function' ||
typeof offThreadCompileScript !== 'function' ||
typeof runOffThreadScript !== 'function')
quit();
oomTest(() => {
offThreadCompileScript(`
"use asm";
return assertEq;
`);
runOffThreadScript();
});
@@ -0,0 +1,73 @@
// bug 1235092
// Optimize spread call with rest parameter.
load(libdir + "asserts.js");
function makeArray(...args) {
return args;
}
// Optimizable Case.
function test(...args) {
return makeArray(...args);
}
assertDeepEq(test(1, 2, 3), [1, 2, 3]);
// Not optimizable case 1: the array has hole.
function hole1(...args) {
args[4] = 5;
return makeArray(...args);
}
assertDeepEq(hole1(1, 2, 3), [1, 2, 3, undefined, 5]);
function hole2(...args) {
args.length = 5;
return makeArray(...args);
}
assertDeepEq(hole2(1, 2, 3), [1, 2, 3, undefined, undefined]);
function hole3(...args) {
delete args[1];
return makeArray(...args);
}
assertDeepEq(hole3(1, 2, 3), [1, undefined, 3]);
// Not optimizable case 2: array[@@iterator] is modified.
function modifiedIterator(...args) {
args[Symbol.iterator] = function*() {
for (let i = 0; i < this.length; i++)
yield this[i] * 10;
};
return makeArray(...args);
}
assertDeepEq(modifiedIterator(1, 2, 3), [10, 20, 30]);
// Not optimizable case 3: the array's prototype is modified.
function modifiedProto(...args) {
args.__proto__ = {
__proto__: Array.prototype,
*[Symbol.iterator]() {
for (let i = 0; i < this.length; i++)
yield this[i] * 10;
}
};
return makeArray(...args);
}
assertDeepEq(modifiedProto(1, 2, 3), [10, 20, 30]);
// Not optimizable case 4: Array.prototype[@@iterator] is modified.
let ArrayValues = Array.prototype[Symbol.iterator];
Array.prototype[Symbol.iterator] = function*() {
for (let i = 0; i < this.length; i++)
yield this[i] * 10;
};
assertDeepEq(test(1, 2, 3), [10, 20, 30]);
Array.prototype[Symbol.iterator] = ArrayValues;
// Not optimizable case 5: %ArrayIteratorPrototype%.next is modified.
let ArrayIteratorPrototype = Object.getPrototypeOf(Array.prototype[Symbol.iterator]());
let i = 1;
ArrayIteratorPrototype.next = function() {
return { done: i % 4 == 0, value: 10 * i++ };
};
assertDeepEq(test(1, 2, 3), [10, 20, 30]);
@@ -0,0 +1 @@
evaluate('evalcx("1")', { fileName: null });
+2
View File
@@ -0,0 +1,2 @@
// |jit-test| error: Error
gcparam("sliceTimeBudget", -1);
+4
View File
@@ -0,0 +1,4 @@
if (!('oomTest' in this))
quit();
oomTest(() => { let a = [2147483651]; [a[0], a[undefined]].sort(); });
+47
View File
@@ -0,0 +1,47 @@
function testGetParam(key) {
gcparam(key);
}
function testChangeParam(key) {
let prev = gcparam(key);
let value = prev - 1;
gcparam(key, value);
assertEq(gcparam(key), value);
gcparam(key, prev);
}
function testLargeParamValue(key) {
let prev = gcparam(key);
const value = 1000000;
gcparam(key, value);
assertEq(gcparam(key), value);
gcparam(key, prev);
}
testGetParam("gcBytes");
testGetParam("gcNumber");
testGetParam("unusedChunks");
testGetParam("totalChunks");
testChangeParam("maxBytes");
testChangeParam("maxMallocBytes");
testChangeParam("mode");
testChangeParam("sliceTimeBudget");
testChangeParam("markStackLimit");
testChangeParam("highFrequencyTimeLimit");
testChangeParam("highFrequencyLowLimit");
testChangeParam("highFrequencyHighLimit");
testChangeParam("highFrequencyHeapGrowthMax");
testChangeParam("highFrequencyHeapGrowthMin");
testChangeParam("lowFrequencyHeapGrowth");
testChangeParam("dynamicHeapGrowth");
testChangeParam("dynamicMarkSlice");
testChangeParam("allocationThreshold");
testChangeParam("decommitThreshold");
testChangeParam("minEmptyChunkCount");
testChangeParam("maxEmptyChunkCount");
testChangeParam("compactingEnabled");
testLargeParamValue("highFrequencyLowLimit");
testLargeParamValue("highFrequencyHighLimit");
testLargeParamValue("decommitThreshold");
@@ -0,0 +1,12 @@
try {
var x = ["a", {toString() { s = x.join("-"); }}];
var a = x.join("a");
var b = x.join("b");
assertEq(a, b);
} catch (e) {
// Using assertion does not work.
quit(0);
}
quit(3);
@@ -0,0 +1,9 @@
function f() {
var x = 0;
var a = [{toString: () => x++}];
for (var i=0; i<10000; i++)
a.join("");
assertEq(x, 10000);
}
f();
@@ -0,0 +1,3 @@
// |jit-test| error: Error: The first argument should be a function.
isRelazifiableFunction(new Array());
+1
View File
@@ -2481,6 +2481,7 @@ BacktrackingAllocator::computeSpillWeight(LiveBundle* bundle)
case LUse::FIXED:
fixed = true;
MOZ_FALLTHROUGH;
case LUse::REGISTER:
usesTotal += 2000;
break;
+1 -1
View File
@@ -1913,7 +1913,7 @@ jit::FinishBailoutToBaseline(BaselineBailoutInfo* bailoutInfo)
// Invalid assumption based on baseline code.
case Bailout_OverflowInvalidate:
outerScript->setHadOverflowBailout();
// FALL THROUGH
MOZ_FALLTHROUGH;
case Bailout_NonStringInputInvalidate:
case Bailout_DoubleOutput:
case Bailout_ObjectIdentityOrTypeGuard:
+24 -2
View File
@@ -7,7 +7,6 @@
#include "jit/BaselineCompiler.h"
#include "mozilla/Casting.h"
#include "mozilla/UniquePtr.h"
#include "jit/BaselineIC.h"
#include "jit/BaselineJIT.h"
@@ -21,6 +20,8 @@
#endif
#include "jit/SharedICHelpers.h"
#include "jit/VMFunctions.h"
#include "js/UniquePtr.h"
#include "vm/Interpreter.h"
#include "vm/ScopeObject.h"
#include "vm/TraceLogging.h"
@@ -195,7 +196,7 @@ BaselineCompiler::compile()
// Note: There is an extra entry in the bytecode type map for the search hint, see below.
size_t bytecodeTypeMapEntries = script->nTypeSets() + 1;
mozilla::UniquePtr<BaselineScript, JS::DeletePolicy<BaselineScript> > baselineScript(
UniquePtr<BaselineScript> baselineScript(
BaselineScript::New(script, prologueOffset_.offset(),
epilogueOffset_.offset(),
profilerEnterFrameToggleOffset_.offset(),
@@ -3184,6 +3185,27 @@ BaselineCompiler::emit_JSOP_STRICTSPREADEVAL()
return emitSpreadCall();
}
typedef bool (*OptimizeSpreadCallFn)(JSContext*, HandleValue, bool*);
static const VMFunction OptimizeSpreadCallInfo =
FunctionInfo<OptimizeSpreadCallFn>(OptimizeSpreadCall);
bool
BaselineCompiler::emit_JSOP_OPTIMIZE_SPREADCALL()
{
frame.syncStack(0);
masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
prepareVMCall();
pushArg(R0);
if (!callVM(OptimizeSpreadCallInfo))
return false;
masm.boxNonDouble(JSVAL_TYPE_BOOLEAN, ReturnReg, R0);
frame.push(R0);
return true;
}
typedef bool (*ImplicitThisFn)(JSContext*, HandleObject, HandlePropertyName,
MutableHandleValue);
static const VMFunction ImplicitThisInfo = FunctionInfo<ImplicitThisFn>(ImplicitThisOperation);
+1
View File
@@ -167,6 +167,7 @@ namespace jit {
_(JSOP_SPREADNEW) \
_(JSOP_SPREADEVAL) \
_(JSOP_STRICTSPREADEVAL) \
_(JSOP_OPTIMIZE_SPREADCALL)\
_(JSOP_IMPLICITTHIS) \
_(JSOP_GIMPLICITTHIS) \
_(JSOP_INSTANCEOF) \
+2 -1
View File
@@ -26,7 +26,7 @@
#include "jit/SharedICHelpers.h"
#include "jit/VMFunctions.h"
#include "js/Conversions.h"
#include "js/TraceableVector.h"
#include "js/GCVector.h"
#include "vm/Opcodes.h"
#include "vm/TypedArrayCommon.h"
@@ -1181,6 +1181,7 @@ RemoveExistingGetElemNativeStubs(JSContext* cx, ICGetElem_Fallback* stub, Handle
case ICStub::GetElem_NativeSlotSymbol:
if (indirect)
continue;
MOZ_FALLTHROUGH;
case ICStub::GetElem_NativePrototypeSlotName:
case ICStub::GetElem_NativePrototypeSlotSymbol:
case ICStub::GetElem_NativePrototypeCallNativeName:
+1 -1
View File
@@ -19,7 +19,7 @@
#include "jit/BaselineJIT.h"
#include "jit/SharedIC.h"
#include "jit/SharedICRegisters.h"
#include "js/TraceableVector.h"
#include "js/GCVector.h"
#include "vm/ArrayObject.h"
#include "vm/UnboxedObject.h"
-1
View File
@@ -55,7 +55,6 @@ using mozilla::FloatingPoint;
using mozilla::Maybe;
using mozilla::NegativeInfinity;
using mozilla::PositiveInfinity;
using mozilla::UniquePtr;
using JS::GenericNaN;
namespace js {
+1
View File
@@ -10,6 +10,7 @@
#define INLINABLE_NATIVE_LIST(_) \
_(Array) \
_(ArrayIsArray) \
_(ArrayJoin) \
_(ArrayPop) \
_(ArrayShift) \
_(ArrayPush) \
+3 -1
View File
@@ -724,6 +724,7 @@ IonBuilder::analyzeNewLoopTypes(MBasicBlock* entry, jsbytecode* start, jsbytecod
case JSOP_MOD:
case JSOP_NEG:
type = inspector->expectedResultType(last);
break;
default:
break;
}
@@ -1556,7 +1557,7 @@ IonBuilder::traverseBytecode()
MOZ_ASSERT(i == 0);
if (current->peek(-1) == popped[0])
break;
// FALL THROUGH
MOZ_FALLTHROUGH;
default:
MOZ_ASSERT(popped[i]->isImplicitlyUsed() ||
@@ -1947,6 +1948,7 @@ IonBuilder::inspectOpcode(JSOp op)
return pushConstant(ObjectValue(*scope));
}
// Fall through to JSOP_BINDNAME
MOZ_FALLTHROUGH;
case JSOP_BINDNAME:
return jsop_bindname(info().getName(pc));
+6 -6
View File
@@ -853,10 +853,10 @@ class IonBuilder
// SIMD intrinsics and natives.
InliningStatus inlineConstructSimdObject(CallInfo& callInfo, SimdTypeDescr* target);
// helpers
// SIMD helpers
static MIRType SimdTypeDescrToMIRType(SimdTypeDescr::Type type);
bool checkInlineSimd(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type,
unsigned numArgs, InlineTypedObject** templateObj);
bool canInlineSimd(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type,
unsigned numArgs, InlineTypedObject** templateObj);
IonBuilder::InliningStatus boxSimd(CallInfo& callInfo, MInstruction* ins,
InlineTypedObject* templateObj);
MDefinition* convertToBooleanSimdLane(MDefinition* scalar);
@@ -866,11 +866,11 @@ class IonBuilder
InliningStatus inlineSimdBool32x4(CallInfo& callInfo, JSNative native);
template <typename T>
InliningStatus inlineBinarySimd(CallInfo& callInfo, JSNative native,
InliningStatus inlineSimdBinary(CallInfo& callInfo, JSNative native,
typename T::Operation op, SimdTypeDescr::Type type);
InliningStatus inlineCompSimd(CallInfo& callInfo, JSNative native,
InliningStatus inlineSimdComp(CallInfo& callInfo, JSNative native,
MSimdBinaryComp::Operation op, SimdTypeDescr::Type compType);
InliningStatus inlineUnarySimd(CallInfo& callInfo, JSNative native,
InliningStatus inlineSimdUnary(CallInfo& callInfo, JSNative native,
MSimdUnaryArith::Operation op, SimdTypeDescr::Type type);
InliningStatus inlineSimdExtractLane(CallInfo& callInfo, JSNative native,
SimdTypeDescr::Type type);
+1 -1
View File
@@ -320,7 +320,7 @@ class RInstructionResults
{
// Vector of results of recover instructions.
typedef mozilla::Vector<RelocatableValue, 1, SystemAllocPolicy> Values;
mozilla::UniquePtr<Values, JS::DeletePolicy<Values> > results_;
UniquePtr<Values> results_;
// The frame pointer is used as a key to check if the current frame already
// bailed out.
-1
View File
@@ -10,7 +10,6 @@
#include "mozilla/MathAlgorithms.h"
#include "mozilla/Maybe.h"
#include "mozilla/SizePrintfMacros.h"
#include "mozilla/UniquePtr.h"
#include "jsprf.h"
+2
View File
@@ -923,6 +923,7 @@ class JitcodeGlobalEntry
break;
case IonCache:
markedAny |= ionCacheEntry().mark<ShouldMarkProvider>(trc);
break;
case Dummy:
break;
default:
@@ -941,6 +942,7 @@ class JitcodeGlobalEntry
break;
case IonCache:
ionCacheEntry().sweepChildren(rt);
break;
case Dummy:
break;
default:
+2 -2
View File
@@ -1815,7 +1815,7 @@ LIRGenerator::visitToDouble(MToDouble* convert)
case MIRType_Boolean:
MOZ_ASSERT(conversion != MToFPInstruction::NumbersOnly);
/* FALLTHROUGH */
MOZ_FALLTHROUGH;
case MIRType_Int32:
{
@@ -1871,7 +1871,7 @@ LIRGenerator::visitToFloat32(MToFloat32* convert)
case MIRType_Boolean:
MOZ_ASSERT(conversion != MToFPInstruction::NumbersOnly);
/* FALLTHROUGH */
MOZ_FALLTHROUGH;
case MIRType_Int32:
{
+40 -36
View File
@@ -68,6 +68,8 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target)
return inlineArray(callInfo);
case InlinableNative::ArrayIsArray:
return inlineArrayIsArray(callInfo);
case InlinableNative::ArrayJoin:
return inlineArrayJoin(callInfo);
case InlinableNative::ArrayPop:
return inlineArrayPopShift(callInfo, MArrayPopShift::Pop);
case InlinableNative::ArrayShift:
@@ -645,6 +647,8 @@ IonBuilder::inlineArrayJoin(CallInfo& callInfo)
current->add(ins);
current->push(ins);
if (!resumeAfter(ins))
return InliningStatus_Error;
return InliningStatus_Inlined;
}
@@ -3041,7 +3045,7 @@ IonBuilder::inlineSimdBool32x4(CallInfo& callInfo, JSNative native)
{
#define INLINE_SIMD_BITWISE_(OP) \
if (native == js::simd_bool32x4_##OP) \
return inlineBinarySimd<MSimdBinaryBitwise>(callInfo, native, MSimdBinaryBitwise::OP##_, \
return inlineSimdBinary<MSimdBinaryBitwise>(callInfo, native, MSimdBinaryBitwise::OP##_, \
SimdTypeDescr::Bool32x4);
FOREACH_BITWISE_SIMD_BINOP(INLINE_SIMD_BITWISE_)
@@ -3053,7 +3057,7 @@ IonBuilder::inlineSimdBool32x4(CallInfo& callInfo, JSNative native)
return inlineSimdReplaceLane(callInfo, native, SimdTypeDescr::Bool32x4);
if (native == js::simd_bool32x4_not)
return inlineUnarySimd(callInfo, native, MSimdUnaryArith::not_, SimdTypeDescr::Bool32x4);
return inlineSimdUnary(callInfo, native, MSimdUnaryArith::not_, SimdTypeDescr::Bool32x4);
if (native == js::simd_bool32x4_splat)
return inlineSimdSplat(callInfo, native, SimdTypeDescr::Bool32x4);
@@ -3073,7 +3077,7 @@ IonBuilder::inlineSimdInt32x4(CallInfo& callInfo, JSNative native)
{
#define INLINE_INT32X4_SIMD_ARITH_(OP) \
if (native == js::simd_int32x4_##OP) \
return inlineBinarySimd<MSimdBinaryArith>(callInfo, native, MSimdBinaryArith::Op_##OP, \
return inlineSimdBinary<MSimdBinaryArith>(callInfo, native, MSimdBinaryArith::Op_##OP, \
SimdTypeDescr::Int32x4);
FOREACH_NUMERIC_SIMD_BINOP(INLINE_INT32X4_SIMD_ARITH_)
@@ -3081,24 +3085,24 @@ IonBuilder::inlineSimdInt32x4(CallInfo& callInfo, JSNative native)
#define INLINE_SIMD_BITWISE_(OP) \
if (native == js::simd_int32x4_##OP) \
return inlineBinarySimd<MSimdBinaryBitwise>(callInfo, native, MSimdBinaryBitwise::OP##_, \
return inlineSimdBinary<MSimdBinaryBitwise>(callInfo, native, MSimdBinaryBitwise::OP##_, \
SimdTypeDescr::Int32x4);
FOREACH_BITWISE_SIMD_BINOP(INLINE_SIMD_BITWISE_)
#undef INLINE_SIMD_BITWISE_
if (native == js::simd_int32x4_shiftLeftByScalar)
return inlineBinarySimd<MSimdShift>(callInfo, native, MSimdShift::lsh, SimdTypeDescr::Int32x4);
return inlineSimdBinary<MSimdShift>(callInfo, native, MSimdShift::lsh, SimdTypeDescr::Int32x4);
if (native == js::simd_int32x4_shiftRightArithmeticByScalar ||
native == js::simd_int32x4_shiftRightByScalar) {
return inlineBinarySimd<MSimdShift>(callInfo, native, MSimdShift::rsh, SimdTypeDescr::Int32x4);
return inlineSimdBinary<MSimdShift>(callInfo, native, MSimdShift::rsh, SimdTypeDescr::Int32x4);
}
if (native == js::simd_int32x4_shiftRightLogicalByScalar)
return inlineBinarySimd<MSimdShift>(callInfo, native, MSimdShift::ursh, SimdTypeDescr::Int32x4);
return inlineSimdBinary<MSimdShift>(callInfo, native, MSimdShift::ursh, SimdTypeDescr::Int32x4);
#define INLINE_SIMD_COMPARISON_(OP) \
if (native == js::simd_int32x4_##OP) \
return inlineCompSimd(callInfo, native, MSimdBinaryComp::OP, SimdTypeDescr::Int32x4);
return inlineSimdComp(callInfo, native, MSimdBinaryComp::OP, SimdTypeDescr::Int32x4);
FOREACH_COMP_SIMD_OP(INLINE_SIMD_COMPARISON_)
#undef INLINE_SIMD_COMPARISON_
@@ -3109,9 +3113,9 @@ IonBuilder::inlineSimdInt32x4(CallInfo& callInfo, JSNative native)
return inlineSimdReplaceLane(callInfo, native, SimdTypeDescr::Int32x4);
if (native == js::simd_int32x4_not)
return inlineUnarySimd(callInfo, native, MSimdUnaryArith::not_, SimdTypeDescr::Int32x4);
return inlineSimdUnary(callInfo, native, MSimdUnaryArith::not_, SimdTypeDescr::Int32x4);
if (native == js::simd_int32x4_neg)
return inlineUnarySimd(callInfo, native, MSimdUnaryArith::neg, SimdTypeDescr::Int32x4);
return inlineSimdUnary(callInfo, native, MSimdUnaryArith::neg, SimdTypeDescr::Int32x4);
typedef bool IsCast;
if (native == js::simd_int32x4_fromFloat32x4)
@@ -3160,7 +3164,7 @@ IonBuilder::inlineSimdFloat32x4(CallInfo& callInfo, JSNative native)
// Simd functions
#define INLINE_FLOAT32X4_SIMD_ARITH_(OP) \
if (native == js::simd_float32x4_##OP) \
return inlineBinarySimd<MSimdBinaryArith>(callInfo, native, MSimdBinaryArith::Op_##OP, \
return inlineSimdBinary<MSimdBinaryArith>(callInfo, native, MSimdBinaryArith::Op_##OP, \
SimdTypeDescr::Float32x4);
FOREACH_NUMERIC_SIMD_BINOP(INLINE_FLOAT32X4_SIMD_ARITH_)
@@ -3169,7 +3173,7 @@ IonBuilder::inlineSimdFloat32x4(CallInfo& callInfo, JSNative native)
#define INLINE_SIMD_COMPARISON_(OP) \
if (native == js::simd_float32x4_##OP) \
return inlineCompSimd(callInfo, native, MSimdBinaryComp::OP, SimdTypeDescr::Float32x4);
return inlineSimdComp(callInfo, native, MSimdBinaryComp::OP, SimdTypeDescr::Float32x4);
FOREACH_COMP_SIMD_OP(INLINE_SIMD_COMPARISON_)
#undef INLINE_SIMD_COMPARISON_
@@ -3181,7 +3185,7 @@ IonBuilder::inlineSimdFloat32x4(CallInfo& callInfo, JSNative native)
#define INLINE_SIMD_FLOAT32X4_UNARY_(OP) \
if (native == js::simd_float32x4_##OP) \
return inlineUnarySimd(callInfo, native, MSimdUnaryArith::OP, SimdTypeDescr::Float32x4);
return inlineSimdUnary(callInfo, native, MSimdUnaryArith::OP, SimdTypeDescr::Float32x4);
FOREACH_FLOAT_SIMD_UNOP(INLINE_SIMD_FLOAT32X4_UNARY_)
INLINE_SIMD_FLOAT32X4_UNARY_(neg)
@@ -3321,7 +3325,7 @@ IonBuilder::inlineConstructSimdObject(CallInfo& callInfo, SimdTypeDescr* descr)
}
bool
IonBuilder::checkInlineSimd(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type,
IonBuilder::canInlineSimd(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type,
unsigned numArgs, InlineTypedObject** templateObj)
{
if (callInfo.argc() != numArgs)
@@ -3352,11 +3356,11 @@ IonBuilder::boxSimd(CallInfo& callInfo, MInstruction* ins, InlineTypedObject* te
template<typename T>
IonBuilder::InliningStatus
IonBuilder::inlineBinarySimd(CallInfo& callInfo, JSNative native, typename T::Operation op,
IonBuilder::inlineSimdBinary(CallInfo& callInfo, JSNative native, typename T::Operation op,
SimdTypeDescr::Type type)
{
InlineTypedObject* templateObj = nullptr;
if (!checkInlineSimd(callInfo, native, type, 2, &templateObj))
if (!canInlineSimd(callInfo, native, type, 2, &templateObj))
return InliningStatus_NotInlined;
// If the type of any of the arguments is neither a SIMD type, an Object
@@ -3370,11 +3374,11 @@ IonBuilder::inlineBinarySimd(CallInfo& callInfo, JSNative native, typename T::Op
}
IonBuilder::InliningStatus
IonBuilder::inlineCompSimd(CallInfo& callInfo, JSNative native, MSimdBinaryComp::Operation op,
IonBuilder::inlineSimdComp(CallInfo& callInfo, JSNative native, MSimdBinaryComp::Operation op,
SimdTypeDescr::Type compType)
{
InlineTypedObject* templateObj = nullptr;
if (!checkInlineSimd(callInfo, native, SimdTypeDescr::Bool32x4, 2, &templateObj))
if (!canInlineSimd(callInfo, native, SimdTypeDescr::Bool32x4, 2, &templateObj))
return InliningStatus_NotInlined;
// If the type of any of the arguments is neither a SIMD type, an Object
@@ -3388,14 +3392,14 @@ IonBuilder::inlineCompSimd(CallInfo& callInfo, JSNative native, MSimdBinaryComp:
}
IonBuilder::InliningStatus
IonBuilder::inlineUnarySimd(CallInfo& callInfo, JSNative native, MSimdUnaryArith::Operation op,
IonBuilder::inlineSimdUnary(CallInfo& callInfo, JSNative native, MSimdUnaryArith::Operation op,
SimdTypeDescr::Type type)
{
InlineTypedObject* templateObj = nullptr;
if (!checkInlineSimd(callInfo, native, type, 1, &templateObj))
if (!canInlineSimd(callInfo, native, type, 1, &templateObj))
return InliningStatus_NotInlined;
// See comment in inlineBinarySimd
// See comment in inlineSimdBinary
MIRType mirType = SimdTypeDescrToMIRType(type);
MSimdUnaryArith* ins = MSimdUnaryArith::New(alloc(), callInfo.getArg(0), op, mirType);
return boxSimd(callInfo, ins, templateObj);
@@ -3405,10 +3409,10 @@ IonBuilder::InliningStatus
IonBuilder::inlineSimdSplat(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type)
{
InlineTypedObject* templateObj = nullptr;
if (!checkInlineSimd(callInfo, native, type, 1, &templateObj))
if (!canInlineSimd(callInfo, native, type, 1, &templateObj))
return InliningStatus_NotInlined;
// See comment in inlineBinarySimd
// See comment in inlineSimdBinary
MIRType mirType = SimdTypeDescrToMIRType(type);
MDefinition* arg = callInfo.getArg(0);
@@ -3424,7 +3428,7 @@ IonBuilder::InliningStatus
IonBuilder::inlineSimdExtractLane(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type)
{
InlineTypedObject* templateObj = nullptr;
if (!checkInlineSimd(callInfo, native, type, 2, &templateObj))
if (!canInlineSimd(callInfo, native, type, 2, &templateObj))
return InliningStatus_NotInlined;
MDefinition* arg = callInfo.getArg(1);
@@ -3434,7 +3438,7 @@ IonBuilder::inlineSimdExtractLane(CallInfo& callInfo, JSNative native, SimdTypeD
if (lane < 0 || lane >= 4)
return InliningStatus_NotInlined;
// See comment in inlineBinarySimd
// See comment in inlineSimdBinary
MIRType vecType = SimdTypeDescrToMIRType(type);
MIRType laneType = SimdTypeToLaneType(vecType);
MSimdExtractElement* ins = MSimdExtractElement::New(alloc(), callInfo.getArg(0),
@@ -3449,7 +3453,7 @@ IonBuilder::InliningStatus
IonBuilder::inlineSimdReplaceLane(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type)
{
InlineTypedObject* templateObj = nullptr;
if (!checkInlineSimd(callInfo, native, type, 3, &templateObj))
if (!canInlineSimd(callInfo, native, type, 3, &templateObj))
return InliningStatus_NotInlined;
MDefinition* arg = callInfo.getArg(1);
@@ -3460,7 +3464,7 @@ IonBuilder::inlineSimdReplaceLane(CallInfo& callInfo, JSNative native, SimdTypeD
if (lane < 0 || lane >= 4)
return InliningStatus_NotInlined;
// See comment in inlineBinarySimd
// See comment in inlineSimdBinary
MIRType mirType = SimdTypeDescrToMIRType(type);
// Convert to 0 / -1 before inserting a boolean lane.
@@ -3478,10 +3482,10 @@ IonBuilder::inlineSimdConvert(CallInfo& callInfo, JSNative native, bool isCast,
SimdTypeDescr::Type from, SimdTypeDescr::Type to)
{
InlineTypedObject* templateObj = nullptr;
if (!checkInlineSimd(callInfo, native, to, 1, &templateObj))
if (!canInlineSimd(callInfo, native, to, 1, &templateObj))
return InliningStatus_NotInlined;
// See comment in inlineBinarySimd
// See comment in inlineSimdBinary
MInstruction* ins;
MIRType fromType = SimdTypeDescrToMIRType(from);
MIRType toType = SimdTypeDescrToMIRType(to);
@@ -3497,10 +3501,10 @@ IonBuilder::InliningStatus
IonBuilder::inlineSimdSelect(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type)
{
InlineTypedObject* templateObj = nullptr;
if (!checkInlineSimd(callInfo, native, type, 3, &templateObj))
if (!canInlineSimd(callInfo, native, type, 3, &templateObj))
return InliningStatus_NotInlined;
// See comment in inlineBinarySimd
// See comment in inlineSimdBinary
MIRType mirType = SimdTypeDescrToMIRType(type);
MSimdSelect* ins = MSimdSelect::New(alloc(), callInfo.getArg(0), callInfo.getArg(1),
callInfo.getArg(2), mirType);
@@ -3511,7 +3515,7 @@ IonBuilder::InliningStatus
IonBuilder::inlineSimdCheck(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type)
{
InlineTypedObject* templateObj = nullptr;
if (!checkInlineSimd(callInfo, native, type, 1, &templateObj))
if (!canInlineSimd(callInfo, native, type, 1, &templateObj))
return InliningStatus_NotInlined;
MIRType mirType = SimdTypeDescrToMIRType(type);
@@ -3528,7 +3532,7 @@ IonBuilder::inlineSimdShuffle(CallInfo& callInfo, JSNative native, SimdTypeDescr
unsigned numVectors, unsigned numLanes)
{
InlineTypedObject* templateObj = nullptr;
if (!checkInlineSimd(callInfo, native, type, numVectors + numLanes, &templateObj))
if (!canInlineSimd(callInfo, native, type, numVectors + numLanes, &templateObj))
return InliningStatus_NotInlined;
MIRType mirType = SimdTypeDescrToMIRType(type);
@@ -3549,7 +3553,7 @@ IonBuilder::InliningStatus
IonBuilder::inlineSimdAnyAllTrue(CallInfo& callInfo, bool IsAllTrue, JSNative native)
{
InlineTypedObject* templateObj = nullptr;
if (!checkInlineSimd(callInfo, native, SimdTypeDescr::Bool32x4, 1, &templateObj))
if (!canInlineSimd(callInfo, native, SimdTypeDescr::Bool32x4, 1, &templateObj))
return InliningStatus_NotInlined;
MUnaryInstruction* ins;
@@ -3637,7 +3641,7 @@ IonBuilder::inlineSimdLoad(CallInfo& callInfo, JSNative native, SimdTypeDescr::T
unsigned numElems)
{
InlineTypedObject* templateObj = nullptr;
if (!checkInlineSimd(callInfo, native, type, 2, &templateObj))
if (!canInlineSimd(callInfo, native, type, 2, &templateObj))
return InliningStatus_NotInlined;
Scalar::Type simdType = SimdTypeToArrayElementType(type);
@@ -3660,7 +3664,7 @@ IonBuilder::inlineSimdStore(CallInfo& callInfo, JSNative native, SimdTypeDescr::
unsigned numElems)
{
InlineTypedObject* templateObj = nullptr;
if (!checkInlineSimd(callInfo, native, type, 3, &templateObj))
if (!canInlineSimd(callInfo, native, type, 3, &templateObj))
return InliningStatus_NotInlined;
Scalar::Type simdType = SimdTypeToArrayElementType(type);
+5 -3
View File
@@ -2226,6 +2226,7 @@ CanProduceNegativeZero(MDefinition* def) {
case MDefinition::Op_Constant:
if (def->type() == MIRType_Double && def->constantValue().toDouble() == -0.0)
return true;
MOZ_FALLTHROUGH;
case MDefinition::Op_BitAnd:
case MDefinition::Op_BitOr:
case MDefinition::Op_BitXor:
@@ -2304,7 +2305,7 @@ NeedNegativeZeroCheck(MDefinition* def)
if (rhs->id() < lhs->id() && CanProduceNegativeZero(lhs))
return true;
/* Fall through... */
MOZ_FALLTHROUGH;
}
case MDefinition::Op_StoreElement:
case MDefinition::Op_StoreElementHole:
@@ -3083,7 +3084,7 @@ MTypeOf::foldsTo(TempAllocator& alloc)
type = JSTYPE_OBJECT;
break;
}
// FALL THROUGH
MOZ_FALLTHROUGH;
default:
return this;
}
@@ -3368,9 +3369,10 @@ MToInt32::foldsTo(TempAllocator& alloc)
case MIRType_Float32:
case MIRType_Double:
int32_t ival;
// Only the value within the range of Int32 can be substitued as constant.
// Only the value within the range of Int32 can be substituted as constant.
if (mozilla::NumberEqualsInt32(val.toNumber(), &ival))
return MConstant::New(alloc, Int32Value(ival));
break;
default:
break;
}
+3 -1
View File
@@ -9537,7 +9537,9 @@ class MArrayJoin
return true;
}
virtual AliasSet getAliasSet() const override {
return AliasSet::Load(AliasSet::Element | AliasSet::ObjectFields);
// Array.join might coerce the elements of the Array to strings. This
// coercion might cause the evaluation of the some JavaScript code.
return AliasSet::Store(AliasSet::Any);
}
MDefinition* foldsTo(TempAllocator& alloc) override;
};
+1 -1
View File
@@ -457,7 +457,7 @@ MacroAssembler::loadUnboxedProperty(T address, JSValueType type, TypedOrValueReg
convertInt32ToDouble(address, output.typedReg().fpu());
break;
}
// Fallthrough.
MOZ_FALLTHROUGH;
}
case JSVAL_TYPE_BOOLEAN:
+3
View File
@@ -258,6 +258,7 @@ RangeAnalysis::addBetaNodes()
if (!compare->isNumericComparison())
continue;
// Otherwise fall through to handle JSOP_STRICTEQ the same as JSOP_EQ.
MOZ_FALLTHROUGH;
case JSOP_EQ:
comp.setDouble(bound, bound);
break;
@@ -266,6 +267,7 @@ RangeAnalysis::addBetaNodes()
if (!compare->isNumericComparison())
continue;
// Otherwise fall through to handle JSOP_STRICTNE the same as JSOP_NE.
MOZ_FALLTHROUGH;
case JSOP_NE:
// Negative zero is not not-equal to zero.
if (bound == 0) {
@@ -3004,6 +3006,7 @@ RangeAnalysis::truncate()
case MDefinition::Op_Ursh:
if (!bitops.append(static_cast<MBinaryBitwiseInstruction*>(*iter)))
return false;
break;
default:;
}
+6 -32
View File
@@ -380,41 +380,15 @@ ArrayConcatDense(JSContext* cx, HandleObject obj1, HandleObject obj2, HandleObje
JSString*
ArrayJoin(JSContext* cx, HandleObject array, HandleString sep)
{
// The annotations in this function follow the first steps of join
// specified in ES5.
// Step 1
RootedObject obj(cx, array);
if (!obj)
JS::AutoValueArray<3> argv(cx);
argv[0].setUndefined();
argv[1].setObject(*array);
argv[2].setString(sep);
if (!js::array_join(cx, 1, argv.begin()))
return nullptr;
AutoCycleDetector detector(cx, obj);
if (!detector.init())
return nullptr;
if (detector.foundCycle())
return nullptr;
// Steps 2 and 3
uint32_t length;
if (!GetLengthProperty(cx, obj, &length))
return nullptr;
// Steps 4 and 5
RootedLinearString sepstr(cx);
if (sep) {
sepstr = sep->ensureLinear(cx);
if (!sepstr)
return nullptr;
} else {
sepstr = cx->names().comma;
}
// Step 6 to 11
return js::ArrayJoin<false>(cx, obj, sepstr, length);
return argv[0].toString();
}
bool
CharCodeAt(JSContext* cx, HandleString str, int32_t index, uint32_t* code)
{
+10
View File
@@ -56,6 +56,16 @@ static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD0 = { Registers::invalid_reg }
static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD1 = { Registers::invalid_reg };
static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD2 = { Registers::invalid_reg };
static MOZ_CONSTEXPR_VAR Register RegExpTesterRegExpReg = { Registers::invalid_reg };
static MOZ_CONSTEXPR_VAR Register RegExpTesterStringReg = { Registers::invalid_reg };
static MOZ_CONSTEXPR_VAR Register RegExpTesterLastIndexReg = { Registers::invalid_reg };
static MOZ_CONSTEXPR_VAR Register RegExpTesterStickyReg = { Registers::invalid_reg };
static MOZ_CONSTEXPR_VAR Register RegExpMatcherRegExpReg = { Registers::invalid_reg };
static MOZ_CONSTEXPR_VAR Register RegExpMatcherStringReg = { Registers::invalid_reg };
static MOZ_CONSTEXPR_VAR Register RegExpMatcherLastIndexReg = { Registers::invalid_reg };
static MOZ_CONSTEXPR_VAR Register RegExpMatcherStickyReg = { Registers::invalid_reg };
static MOZ_CONSTEXPR_VAR Register JSReturnReg_Type = { Registers::invalid_reg };
static MOZ_CONSTEXPR_VAR Register JSReturnReg_Data = { Registers::invalid_reg };
static MOZ_CONSTEXPR_VAR Register JSReturnReg = { Registers::invalid_reg };
+1 -1
View File
@@ -303,7 +303,7 @@ CodeGeneratorShared::verifyHeapAccessDisassembly(uint32_t begin, uint32_t end, b
case Scalar::Int16:
if (kind == HeapAccess::Load)
kind = HeapAccess::LoadSext32;
// FALL THROUGH
MOZ_FALLTHROUGH;
case Scalar::Uint8:
case Scalar::Uint16:
case Scalar::Int32:
+7 -5
View File
@@ -7,8 +7,8 @@
#include "ds/TraceableFifo.h"
#include "js/GCHashTable.h"
#include "js/GCVector.h"
#include "js/RootingAPI.h"
#include "js/TraceableVector.h"
#include "jsapi-tests/tests.h"
@@ -203,7 +203,7 @@ BEGIN_TEST(testGCHandleHashMap)
}
END_TEST(testGCHandleHashMap)
using ShapeVec = TraceableVector<Shape*>;
using ShapeVec = GCVector<Shape*>;
BEGIN_TEST(testGCRootedVector)
{
@@ -249,7 +249,7 @@ BEGIN_TEST(testGCRootedVector)
}
bool
receiveConstRefToShapeVector(const JS::Rooted<TraceableVector<Shape*>>& rooted)
receiveConstRefToShapeVector(const JS::Rooted<GCVector<Shape*>>& rooted)
{
// Ensure range enumeration works through the reference.
for (auto shape : rooted) {
@@ -259,7 +259,7 @@ receiveConstRefToShapeVector(const JS::Rooted<TraceableVector<Shape*>>& rooted)
}
bool
receiveHandleToShapeVector(JS::Handle<TraceableVector<Shape*>> handle)
receiveHandleToShapeVector(JS::Handle<GCVector<Shape*>> handle)
{
// Ensure range enumeration works through the handle.
for (auto shape : handle) {
@@ -269,7 +269,7 @@ receiveHandleToShapeVector(JS::Handle<TraceableVector<Shape*>> handle)
}
bool
receiveMutableHandleToShapeVector(JS::MutableHandle<TraceableVector<Shape*>> handle)
receiveMutableHandleToShapeVector(JS::MutableHandle<GCVector<Shape*>> handle)
{
// Ensure range enumeration works through the handle.
for (auto shape : handle) {
@@ -318,6 +318,8 @@ BEGIN_TEST(testTraceableFifo)
}
END_TEST(testTraceableFifo)
using ShapeVec = GCVector<Shape*>;
static bool
FillVector(JSContext* cx, MutableHandle<ShapeVec> shapes)
{
+2 -1
View File
@@ -7,6 +7,7 @@
#include "gc/GCInternals.h"
#include "gc/Zone.h"
#include "js/GCVector.h"
#include "jsapi-tests/tests.h"
@@ -81,7 +82,7 @@ BEGIN_TEST(testGCUID)
// Allocate a few arenas worth of objects to ensure we get some compaction.
const static size_t N = 2049;
using ObjectVector = js::TraceableVector<JSObject*>;
using ObjectVector = js::GCVector<JSObject*>;
JS::Rooted<ObjectVector> vec(cx, ObjectVector(cx));
for (size_t i = 0; i < N; ++i) {
obj = JS_NewPlainObject(cx);
+1 -3
View File
@@ -5,8 +5,6 @@
#include "jsfriendapi.h"
#include "jsapi-tests/tests.h"
using mozilla::UniquePtr;
static bool sErrorReportMuted = false;
BEGIN_TEST(testMutedErrors)
{
@@ -47,7 +45,7 @@ bool
eval(const char* asciiChars, bool mutedErrors, JS::MutableHandleValue rval)
{
size_t len = strlen(asciiChars);
UniquePtr<char16_t[]> chars(new char16_t[len+1]);
mozilla::UniquePtr<char16_t[]> chars(new char16_t[len+1]);
for (size_t i = 0; i < len; ++i)
chars[i] = asciiChars[i];
chars[len] = 0;
+6 -7
View File
@@ -6,7 +6,6 @@
#include "jsapi-tests/tests.h"
using namespace JS;
using mozilla::UniquePtr;
struct BarkWhenTracedClass {
static int finalizeCount;
@@ -82,7 +81,7 @@ BEGIN_TEST(test_PersistentRooted)
{
BarkWhenTracedClass::reset();
UniquePtr<Kennel> kennel(Allocate(cx));
mozilla::UniquePtr<Kennel> kennel(Allocate(cx));
CHECK(kennel.get());
// GC should be able to find our barker.
@@ -118,13 +117,13 @@ BEGIN_TEST(test_PersistentRootedCopy)
{
BarkWhenTracedClass::reset();
UniquePtr<Kennel> kennel(Allocate(cx));
mozilla::UniquePtr<Kennel> kennel(Allocate(cx));
CHECK(kennel.get());
CHECK(GCFinalizesNBarkers(cx, 0));
// Copy construction! AMAZING!
UniquePtr<Kennel> newKennel(new Kennel(*kennel));
mozilla::UniquePtr<Kennel> newKennel(new Kennel(*kennel));
CHECK(GCFinalizesNBarkers(cx, 0));
@@ -148,13 +147,13 @@ BEGIN_TEST(test_PersistentRootedAssign)
{
BarkWhenTracedClass::reset();
UniquePtr<Kennel> kennel(Allocate(cx));
mozilla::UniquePtr<Kennel> kennel(Allocate(cx));
CHECK(kennel.get());
CHECK(GCFinalizesNBarkers(cx, 0));
// Allocate a new, empty kennel.
UniquePtr<Kennel> kennel2(new Kennel(cx));
mozilla::UniquePtr<Kennel> kennel2(new Kennel(cx));
// Assignment! ASTONISHING!
*kennel2 = *kennel;
@@ -168,7 +167,7 @@ BEGIN_TEST(test_PersistentRootedAssign)
CHECK(GCFinalizesNBarkers(cx, 0));
// Allocate a second barker.
kennel2 = UniquePtr<Kennel>(Allocate(cx));
kennel2 = mozilla::UniquePtr<Kennel>(Allocate(cx));
CHECK(kennel2.get());
*kennel = *kennel2;
+1 -1
View File
@@ -143,7 +143,7 @@ BEGIN_TEST(test_ubiNodeJSObjectConstructorName)
EVAL("this.Ctor = function Ctor() {}; new Ctor", &val);
CHECK(val.isObject());
mozilla::UniquePtr<char16_t[], JS::FreePolicy> ctorName;
UniqueTwoByteChars ctorName;
CHECK(JS::ubi::Node(&val.toObject()).jsObjectConstructorName(cx, ctorName));
CHECK(ctorName);
CHECK(js_strcmp(ctorName.get(), MOZ_UTF16("Ctor")) == 0);
+1 -3
View File
@@ -12,8 +12,6 @@
#include "jsscriptinlines.h"
using mozilla::UniquePtr;
static JSScript*
FreezeThaw(JSContext* cx, JS::HandleScript script)
{
@@ -132,7 +130,7 @@ BEGIN_TEST(testXDR_sourceMap)
CHECK(script);
size_t len = strlen(*sm);
UniquePtr<char16_t,JS::FreePolicy> expected_wrapper(js::InflateString(cx, *sm, &len));
UniqueTwoByteChars expected_wrapper(js::InflateString(cx, *sm, &len));
char16_t *expected = expected_wrapper.get();
CHECK(expected);
+8 -20
View File
@@ -12,7 +12,6 @@
#include "mozilla/FloatingPoint.h"
#include "mozilla/PodOperations.h"
#include "mozilla/UniquePtr.h"
#include <ctype.h>
#include <stdarg.h>
@@ -68,6 +67,7 @@
#include "js/Proxy.h"
#include "js/SliceBudget.h"
#include "js/StructuredClone.h"
#include "js/UniquePtr.h"
#include "vm/DateObject.h"
#include "vm/Debugger.h"
#include "vm/ErrorObject.h"
@@ -100,7 +100,6 @@ using namespace js::gc;
using mozilla::Maybe;
using mozilla::PodCopy;
using mozilla::PodZero;
using mozilla::UniquePtr;
using JS::AutoGCRooter;
using JS::ToInt32;
@@ -1483,19 +1482,6 @@ JS_GetGCParameter(JSRuntime* rt, JSGCParamKey key)
return rt->gc.getParameter(key, lock);
}
JS_PUBLIC_API(void)
JS_SetGCParameterForThread(JSContext* cx, JSGCParamKey key, uint32_t value)
{
MOZ_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES);
}
JS_PUBLIC_API(uint32_t)
JS_GetGCParameterForThread(JSContext* cx, JSGCParamKey key)
{
MOZ_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES);
return 0;
}
static const size_t NumGCConfigs = 14;
struct JSGCConfig {
JSGCParamKey key;
@@ -3888,7 +3874,7 @@ JS::OwningCompileOptions::setFileAndLine(JSContext* cx, const char* f, unsigned
bool
JS::OwningCompileOptions::setSourceMapURL(JSContext* cx, const char16_t* s)
{
UniquePtr<char16_t[], JS::FreePolicy> copy;
UniqueTwoByteChars copy;
if (s) {
copy = DuplicateString(cx, s);
if (!copy)
@@ -3973,7 +3959,7 @@ static bool
Compile(JSContext* cx, const ReadOnlyCompileOptions& options, SyntacticScopeOption scopeOption,
const char* bytes, size_t length, MutableHandleScript script)
{
mozilla::UniquePtr<char16_t, JS::FreePolicy> chars;
UniqueTwoByteChars chars;
if (options.utf8)
chars.reset(UTF8CharsToNewTwoByteCharsZ(cx, UTF8Chars(bytes, length), &length).get());
else
@@ -4302,7 +4288,7 @@ JS::CompileFunction(JSContext* cx, AutoObjectVector& scopeChain,
const char* name, unsigned nargs, const char* const* argnames,
const char* bytes, size_t length, MutableHandleFunction fun)
{
mozilla::UniquePtr<char16_t, JS::FreePolicy> chars;
UniqueTwoByteChars chars;
if (options.utf8)
chars.reset(UTF8CharsToNewTwoByteCharsZ(cx, UTF8Chars(bytes, length), &length).get());
else
@@ -5947,6 +5933,8 @@ JS_PUBLIC_API(bool)
DescribeScriptedCaller(JSContext* cx, UniqueChars* filename, unsigned* lineno,
unsigned* column)
{
if (filename)
filename->reset();
if (lineno)
*lineno = 0;
if (column)
@@ -5961,8 +5949,8 @@ DescribeScriptedCaller(JSContext* cx, UniqueChars* filename, unsigned* lineno,
if (i.activation()->scriptedCallerIsHidden())
return false;
if (filename) {
UniqueChars copy = make_string_copy(i.filename());
if (filename && i.filename()) {
UniqueChars copy = DuplicateString(i.filename());
if (!copy)
return false;
*filename = Move(copy);
+6 -17
View File
@@ -26,11 +26,11 @@
#include "js/CallArgs.h"
#include "js/Class.h"
#include "js/GCVector.h"
#include "js/HashTable.h"
#include "js/Id.h"
#include "js/Principals.h"
#include "js/RootingAPI.h"
#include "js/TraceableVector.h"
#include "js/TracingAPI.h"
#include "js/Utility.h"
#include "js/Value.h"
@@ -218,9 +218,9 @@ typedef AutoVectorRooter<Value> AutoValueVector;
typedef AutoVectorRooter<jsid> AutoIdVector;
typedef AutoVectorRooter<JSObject*> AutoObjectVector;
using ValueVector = js::TraceableVector<JS::Value>;
using IdVector = js::TraceableVector<jsid>;
using ScriptVector = js::TraceableVector<JSScript*>;
using ValueVector = js::GCVector<JS::Value>;
using IdVector = js::GCVector<jsid>;
using ScriptVector = js::GCVector<JSScript*>;
template<class Key, class Value>
class MOZ_RAII AutoHashMapRooter : protected AutoGCRooter
@@ -1737,9 +1737,6 @@ typedef enum JSGCParamKey {
/** Number of times GC has been invoked. Includes both major and minor GC. */
JSGC_NUMBER = 4,
/** Max size of the code cache in bytes. */
JSGC_MAX_CODE_CACHE_BYTES = 5,
/** Select GC mode. */
JSGC_MODE = 6,
@@ -1805,7 +1802,7 @@ typedef enum JSGCParamKey {
JSGC_MAX_EMPTY_CHUNK_COUNT = 22,
/** Whether compacting GC is enabled. */
JSGC_COMPACTING_ENABLED = 23
JSGC_COMPACTING_ENABLED = 23,
} JSGCParamKey;
extern JS_PUBLIC_API(void)
@@ -1817,12 +1814,6 @@ JS_SetGGCMode(JSRuntime* rt, bool enabled);
extern JS_PUBLIC_API(uint32_t)
JS_GetGCParameter(JSRuntime* rt, JSGCParamKey key);
extern JS_PUBLIC_API(void)
JS_SetGCParameterForThread(JSContext* cx, JSGCParamKey key, uint32_t value);
extern JS_PUBLIC_API(uint32_t)
JS_GetGCParameterForThread(JSContext* cx, JSGCParamKey key);
extern JS_PUBLIC_API(void)
JS_SetGCParametersBasedOnAvailableMemory(JSRuntime* rt, uint32_t availMem);
@@ -5328,8 +5319,6 @@ JS_IsIdentifier(const char16_t* chars, size_t length);
namespace JS {
typedef js::UniqueChars AutoFilename;
/**
* Return the current filename, line number and column number of the most
* currently running frame. Returns true if a scripted frame was found, false
@@ -5339,7 +5328,7 @@ typedef js::UniqueChars AutoFilename;
* record, this will also return false.
*/
extern JS_PUBLIC_API(bool)
DescribeScriptedCaller(JSContext* cx, AutoFilename* filename = nullptr,
DescribeScriptedCaller(JSContext* cx, UniqueChars* filename = nullptr,
unsigned* lineno = nullptr, unsigned* column = nullptr);
extern JS_PUBLIC_API(JSObject*)
+64 -82
View File
@@ -54,7 +54,6 @@ using mozilla::CeilingLog2;
using mozilla::CheckedInt;
using mozilla::DebugOnly;
using mozilla::IsNaN;
using mozilla::UniquePtr;
using JS::AutoCheckCannotGC;
using JS::IsArrayAnswer;
@@ -1080,72 +1079,13 @@ ArrayJoinKernel(JSContext* cx, SeparatorOp sepOp, HandleObject obj, uint32_t len
}
template <bool Locale>
JSString*
js::ArrayJoin(JSContext* cx, HandleObject obj, HandleLinearString sepstr, uint32_t length)
bool
ArrayJoin(JSContext* cx, CallArgs& args)
{
// This method is shared by Array.prototype.join and
// Array.prototype.toLocaleString. The steps in ES5 are nearly the same, so
// the annotations in this function apply to both toLocaleString and join.
// Steps 1 to 6, should be done by the caller.
// Step 6 is implicit in the loops below.
// 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 && !Locale && GetAnyBoxedOrUnboxedInitializedLength(obj) == 1) {
Value elem0 = GetAnyBoxedOrUnboxedDenseElement(obj, 0);
if (elem0.isString())
return elem0.toString();
}
StringBuffer sb(cx);
if (sepstr->hasTwoByteChars() && !sb.ensureTwoByteChars())
return nullptr;
// The separator will be added |length - 1| times, reserve space for that
// so that we don't have to unnecessarily grow the buffer.
size_t seplen = sepstr->length();
CheckedInt<uint32_t> res = CheckedInt<uint32_t>(seplen) * (length - 1);
if (length > 0 && !res.isValid()) {
ReportAllocationOverflow(cx);
return nullptr;
}
if (length > 0 && !sb.reserve(res.value()))
return nullptr;
// Various optimized versions of steps 7-10.
if (seplen == 0) {
EmptySeparatorOp op;
if (!ArrayJoinKernel<Locale>(cx, op, obj, length, sb))
return nullptr;
} else if (seplen == 1) {
char16_t c = sepstr->latin1OrTwoByteChar(0);
if (c <= JSString::MAX_LATIN1_CHAR) {
CharSeparatorOp<Latin1Char> op(c);
if (!ArrayJoinKernel<Locale>(cx, op, obj, length, sb))
return nullptr;
} else {
CharSeparatorOp<char16_t> op(c);
if (!ArrayJoinKernel<Locale>(cx, op, obj, length, sb))
return nullptr;
}
} else {
StringSeparatorOp op(sepstr);
if (!ArrayJoinKernel<Locale>(cx, op, obj, length, sb))
return nullptr;
}
// Step 11
return sb.finishString();
}
template <bool Locale>
bool
ArrayJoin(JSContext* cx, CallArgs& args)
{
// Step 1
RootedObject obj(cx, ToObject(cx, args.thisv()));
if (!obj)
@@ -1168,7 +1108,7 @@ ArrayJoin(JSContext* cx, CallArgs& args)
// Steps 4 and 5
RootedLinearString sepstr(cx);
if (!Locale && args.hasDefined(0)) {
JSString* s = ToString<CanGC>(cx, args[0]);
JSString *s = ToString<CanGC>(cx, args[0]);
if (!s)
return false;
sepstr = s->ensureLinear(cx);
@@ -1178,12 +1118,63 @@ ArrayJoin(JSContext* cx, CallArgs& args)
sepstr = cx->names().comma;
}
// Step 6 to 11
JSString* res = js::ArrayJoin<Locale>(cx, obj, sepstr, length);
if (!res)
// Step 6 is implicit in the loops below.
// 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 && !Locale && GetAnyBoxedOrUnboxedInitializedLength(obj) == 1) {
Value elem0 = GetAnyBoxedOrUnboxedDenseElement(obj, 0);
if (elem0.isString()) {
args.rval().set(elem0);
return true;
}
}
StringBuffer sb(cx);
if (sepstr->hasTwoByteChars() && !sb.ensureTwoByteChars())
return false;
args.rval().setString(res);
// The separator will be added |length - 1| times, reserve space for that
// so that we don't have to unnecessarily grow the buffer.
size_t seplen = sepstr->length();
CheckedInt<uint32_t> res = CheckedInt<uint32_t>(seplen) * (length - 1);
if (length > 0 && !res.isValid()) {
ReportAllocationOverflow(cx);
return false;
}
if (length > 0 && !sb.reserve(res.value()))
return false;
// Various optimized versions of steps 7-10.
if (seplen == 0) {
EmptySeparatorOp op;
if (!ArrayJoinKernel<Locale>(cx, op, obj, length, sb))
return false;
} else if (seplen == 1) {
char16_t c = sepstr->latin1OrTwoByteChar(0);
if (c <= JSString::MAX_LATIN1_CHAR) {
CharSeparatorOp<Latin1Char> op(c);
if (!ArrayJoinKernel<Locale>(cx, op, obj, length, sb))
return false;
} else {
CharSeparatorOp<char16_t> op(c);
if (!ArrayJoinKernel<Locale>(cx, op, obj, length, sb))
return false;
}
} else {
StringSeparatorOp op(sepstr);
if (!ArrayJoinKernel<Locale>(cx, op, obj, length, sb))
return false;
}
// Step 11
JSString *str = sb.finishString();
if (!str)
return false;
args.rval().setString(str);
return true;
}
@@ -1749,7 +1740,7 @@ SortLexicographically(JSContext* cx, AutoValueVector* vec, size_t len)
Vector<StringifiedElement, 0, TempAllocPolicy> strElements(cx);
/* MergeSort uses the upper half as scratch space. */
if (!strElements.reserve(2 * len))
if (!strElements.resize(2 * len))
return false;
/* Convert Values to strings. */
@@ -1761,14 +1752,10 @@ SortLexicographically(JSContext* cx, AutoValueVector* vec, size_t len)
if (!ValueToStringBuffer(cx, (*vec)[i], sb))
return false;
StringifiedElement el = { cursor, sb.length(), i };
strElements.infallibleAppend(el);
strElements[i] = { cursor, sb.length(), i };
cursor = sb.length();
}
/* Resize strElements so we can perform MergeSort. */
JS_ALWAYS_TRUE(strElements.resize(2 * len));
/* Sort Values in vec alphabetically. */
return MergeSortByKey(strElements.begin(), len, strElements.begin() + len,
SortComparatorStringifiedElements(cx, sb), vec);
@@ -1788,7 +1775,7 @@ SortNumerically(JSContext* cx, AutoValueVector* vec, size_t len, ComparatorMatch
Vector<NumericElement, 0, TempAllocPolicy> numElements(cx);
/* MergeSort uses the upper half as scratch space. */
if (!numElements.reserve(2 * len))
if (!numElements.resize(2 * len))
return false;
/* Convert Values to numerics. */
@@ -1800,13 +1787,9 @@ SortNumerically(JSContext* cx, AutoValueVector* vec, size_t len, ComparatorMatch
if (!ToNumber(cx, (*vec)[i], &dv))
return false;
NumericElement el = { dv, i };
numElements.infallibleAppend(el);
numElements[i] = { dv, i };
}
/* Resize strElements so we can perform MergeSort. */
JS_ALWAYS_TRUE(numElements.resize(2 * len));
/* Sort Values in vec numerically. */
return MergeSortByKey(numElements.begin(), len, numElements.begin() + len,
SortComparatorNumerics[comp], vec);
@@ -3127,7 +3110,7 @@ static const JSFunctionSpec array_methods[] = {
JS_FN(js_toLocaleString_str, array_toLocaleString, 0,0),
/* Perl-ish methods. */
JS_FN("join", array_join, 1,JSFUN_GENERIC_NATIVE),
JS_INLINABLE_FN("join", array_join, 1,JSFUN_GENERIC_NATIVE, ArrayJoin),
JS_FN("reverse", array_reverse, 0,JSFUN_GENERIC_NATIVE),
JS_FN("sort", array_sort, 1,JSFUN_GENERIC_NATIVE),
JS_INLINABLE_FN("push", array_push, 1,JSFUN_GENERIC_NATIVE, ArrayPush),
@@ -3706,8 +3689,7 @@ js::ArrayInfo(JSContext* cx, unsigned argc, Value* vp)
for (unsigned i = 0; i < args.length(); i++) {
HandleValue arg = args[i];
UniquePtr<char[], JS::FreePolicy> bytes =
DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, arg, nullptr);
UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, arg, nullptr);
if (!bytes)
return false;
if (arg.isPrimitive() ||
-7
View File
@@ -169,10 +169,6 @@ array_splice_impl(JSContext* cx, unsigned argc, js::Value* vp, bool pop);
extern bool
array_concat(JSContext* cx, unsigned argc, js::Value* vp);
template <bool Locale>
JSString*
ArrayJoin(JSContext* cx, HandleObject obj, HandleLinearString sepstr, uint32_t length);
extern bool
array_concat_dense(JSContext* cx, HandleObject arr1, HandleObject arr2,
HandleObject result);
@@ -180,9 +176,6 @@ array_concat_dense(JSContext* cx, HandleObject arr1, HandleObject arr2,
extern bool
array_join(JSContext* cx, unsigned argc, js::Value* vp);
extern JSString*
array_join_impl(JSContext* cx, HandleValue array, HandleString sep);
extern void
ArrayShiftMoveElements(JSObject* obj);
+17
View File
@@ -427,6 +427,23 @@ js::AtomizeChars(ExclusiveContext* cx, const Latin1Char* chars, size_t length, P
template JSAtom*
js::AtomizeChars(ExclusiveContext* cx, const char16_t* chars, size_t length, PinningBehavior pin);
JSAtom*
js::AtomizeUTF8Chars(JSContext* cx, const char* utf8Chars, size_t utf8ByteLength)
{
// This could be optimized to hand the char16_t's directly to the JSAtom
// instead of making a copy. UTF8CharsToNewTwoByteCharsZ should be
// refactored to take an ExclusiveContext so that this function could also.
UTF8Chars utf8(utf8Chars, utf8ByteLength);
size_t length;
UniquePtr<char16_t> chars(JS::UTF8CharsToNewTwoByteCharsZ(cx, utf8, &length).get());
if (!chars)
return nullptr;
return AtomizeChars(cx, chars.get(), length);
}
bool
js::IndexToIdSlow(ExclusiveContext* cx, uint32_t index, MutableHandleId idp)
{
+3
View File
@@ -230,6 +230,9 @@ extern JSAtom*
AtomizeChars(ExclusiveContext* cx, const CharT* chars, size_t length,
js::PinningBehavior pin = js::DoNotPinAtom);
extern JSAtom*
AtomizeUTF8Chars(JSContext* cx, const char* utf8Chars, size_t utf8ByteLength);
extern JSAtom*
AtomizeString(ExclusiveContext* cx, JSString* str, js::PinningBehavior pin = js::DoNotPinAtom);

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