mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:30:27 +00:00
import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 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:
@@ -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);
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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())))
|
||||
|
||||
@@ -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
@@ -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 {
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+1
-25
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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());
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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
@@ -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, ",");
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 });
|
||||
@@ -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 });
|
||||
@@ -0,0 +1,2 @@
|
||||
// |jit-test| error: Error
|
||||
gcparam("sliceTimeBudget", -1);
|
||||
@@ -0,0 +1,4 @@
|
||||
if (!('oomTest' in this))
|
||||
quit();
|
||||
|
||||
oomTest(() => { let a = [2147483651]; [a[0], a[undefined]].sort(); });
|
||||
@@ -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());
|
||||
@@ -2481,6 +2481,7 @@ BacktrackingAllocator::computeSpillWeight(LiveBundle* bundle)
|
||||
|
||||
case LUse::FIXED:
|
||||
fixed = true;
|
||||
MOZ_FALLTHROUGH;
|
||||
case LUse::REGISTER:
|
||||
usesTotal += 2000;
|
||||
break;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -167,6 +167,7 @@ namespace jit {
|
||||
_(JSOP_SPREADNEW) \
|
||||
_(JSOP_SPREADEVAL) \
|
||||
_(JSOP_STRICTSPREADEVAL) \
|
||||
_(JSOP_OPTIMIZE_SPREADCALL)\
|
||||
_(JSOP_IMPLICITTHIS) \
|
||||
_(JSOP_GIMPLICITTHIS) \
|
||||
_(JSOP_INSTANCEOF) \
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -55,7 +55,6 @@ using mozilla::FloatingPoint;
|
||||
using mozilla::Maybe;
|
||||
using mozilla::NegativeInfinity;
|
||||
using mozilla::PositiveInfinity;
|
||||
using mozilla::UniquePtr;
|
||||
using JS::GenericNaN;
|
||||
|
||||
namespace js {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#define INLINABLE_NATIVE_LIST(_) \
|
||||
_(Array) \
|
||||
_(ArrayIsArray) \
|
||||
_(ArrayJoin) \
|
||||
_(ArrayPop) \
|
||||
_(ArrayShift) \
|
||||
_(ArrayPush) \
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/SizePrintfMacros.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
#include "jsprf.h"
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
{
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
};
|
||||
|
||||
@@ -457,7 +457,7 @@ MacroAssembler::loadUnboxedProperty(T address, JSValueType type, TypedOrValueReg
|
||||
convertInt32ToDouble(address, output.typedReg().fpu());
|
||||
break;
|
||||
}
|
||||
// Fallthrough.
|
||||
MOZ_FALLTHROUGH;
|
||||
}
|
||||
|
||||
case JSVAL_TYPE_BOOLEAN:
|
||||
|
||||
@@ -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:;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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,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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 +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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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() ||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user