js/src/jit/AsmJSModule.h

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #ifndef jit_AsmJSModule_h
     8 #define jit_AsmJSModule_h
    10 #ifdef JS_ION
    12 #include "mozilla/Move.h"
    13 #include "mozilla/PodOperations.h"
    15 #include "jsscript.h"
    17 #include "gc/Marking.h"
    18 #include "jit/AsmJS.h"
    19 #include "jit/IonMacroAssembler.h"
    20 #ifdef JS_ION_PERF
    21 # include "jit/PerfSpewer.h"
    22 #endif
    23 #include "jit/RegisterSets.h"
    24 #include "vm/TypedArrayObject.h"
    26 namespace js {
    28 // These EcmaScript-defined coercions form the basis of the asm.js type system.
    29 enum AsmJSCoercion
    30 {
    31     AsmJS_ToInt32,
    32     AsmJS_ToNumber,
    33     AsmJS_FRound
    34 };
    36 // The asm.js spec recognizes this set of builtin Math functions.
    37 enum AsmJSMathBuiltinFunction
    38 {
    39     AsmJSMathBuiltin_sin, AsmJSMathBuiltin_cos, AsmJSMathBuiltin_tan,
    40     AsmJSMathBuiltin_asin, AsmJSMathBuiltin_acos, AsmJSMathBuiltin_atan,
    41     AsmJSMathBuiltin_ceil, AsmJSMathBuiltin_floor, AsmJSMathBuiltin_exp,
    42     AsmJSMathBuiltin_log, AsmJSMathBuiltin_pow, AsmJSMathBuiltin_sqrt,
    43     AsmJSMathBuiltin_abs, AsmJSMathBuiltin_atan2, AsmJSMathBuiltin_imul,
    44     AsmJSMathBuiltin_fround, AsmJSMathBuiltin_min, AsmJSMathBuiltin_max
    45 };
    47 // An asm.js module represents the collection of functions nested inside a
    48 // single outer "use asm" function. For example, this asm.js module:
    49 //   function() { "use asm"; function f() {} function g() {} return f }
    50 // contains the functions 'f' and 'g'.
    51 //
    52 // An asm.js module contains both the jit-code produced by compiling all the
    53 // functions in the module as well all the data required to perform the
    54 // link-time validation step in the asm.js spec.
    55 //
    56 // NB: this means that AsmJSModule must be GC-safe.
    57 class AsmJSModule
    58 {
    59   public:
    60     class Global
    61     {
    62       public:
    63         enum Which { Variable, FFI, ArrayView, MathBuiltinFunction, Constant };
    64         enum VarInitKind { InitConstant, InitImport };
    65         enum ConstantKind { GlobalConstant, MathConstant };
    67       private:
    68         struct Pod {
    69             Which which_;
    70             union {
    71                 struct {
    72                     uint32_t index_;
    73                     VarInitKind initKind_;
    74                     AsmJSCoercion coercion_;
    75                     union {
    76                         Value constant_; // will only contain int32/double
    77                     } init;
    78                 } var;
    79                 uint32_t ffiIndex_;
    80                 ArrayBufferView::ViewType viewType_;
    81                 AsmJSMathBuiltinFunction mathBuiltinFunc_;
    82                 struct {
    83                     ConstantKind kind_;
    84                     double value_;
    85                 } constant;
    86             } u;
    87         } pod;
    88         PropertyName *name_;
    90         friend class AsmJSModule;
    92         Global(Which which, PropertyName *name) {
    93             pod.which_ = which;
    94             name_ = name;
    95             JS_ASSERT_IF(name_, name_->isTenured());
    96         }
    98         void trace(JSTracer *trc) {
    99             if (name_)
   100                 MarkStringUnbarriered(trc, &name_, "asm.js global name");
   101             JS_ASSERT_IF(pod.which_ == Variable && pod.u.var.initKind_ == InitConstant,
   102                          !pod.u.var.init.constant_.isMarkable());
   103         }
   105       public:
   106         Global() {}
   107         Which which() const {
   108             return pod.which_;
   109         }
   110         uint32_t varIndex() const {
   111             JS_ASSERT(pod.which_ == Variable);
   112             return pod.u.var.index_;
   113         }
   114         VarInitKind varInitKind() const {
   115             JS_ASSERT(pod.which_ == Variable);
   116             return pod.u.var.initKind_;
   117         }
   118         const Value &varInitConstant() const {
   119             JS_ASSERT(pod.which_ == Variable);
   120             JS_ASSERT(pod.u.var.initKind_ == InitConstant);
   121             return pod.u.var.init.constant_;
   122         }
   123         AsmJSCoercion varInitCoercion() const {
   124             JS_ASSERT(pod.which_ == Variable);
   125             return pod.u.var.coercion_;
   126         }
   127         PropertyName *varImportField() const {
   128             JS_ASSERT(pod.which_ == Variable);
   129             JS_ASSERT(pod.u.var.initKind_ == InitImport);
   130             return name_;
   131         }
   132         PropertyName *ffiField() const {
   133             JS_ASSERT(pod.which_ == FFI);
   134             return name_;
   135         }
   136         uint32_t ffiIndex() const {
   137             JS_ASSERT(pod.which_ == FFI);
   138             return pod.u.ffiIndex_;
   139         }
   140         PropertyName *viewName() const {
   141             JS_ASSERT(pod.which_ == ArrayView);
   142             return name_;
   143         }
   144         ArrayBufferView::ViewType viewType() const {
   145             JS_ASSERT(pod.which_ == ArrayView);
   146             return pod.u.viewType_;
   147         }
   148         PropertyName *mathName() const {
   149             JS_ASSERT(pod.which_ == MathBuiltinFunction);
   150             return name_;
   151         }
   152         AsmJSMathBuiltinFunction mathBuiltinFunction() const {
   153             JS_ASSERT(pod.which_ == MathBuiltinFunction);
   154             return pod.u.mathBuiltinFunc_;
   155         }
   156         PropertyName *constantName() const {
   157             JS_ASSERT(pod.which_ == Constant);
   158             return name_;
   159         }
   160         ConstantKind constantKind() const {
   161             JS_ASSERT(pod.which_ == Constant);
   162             return pod.u.constant.kind_;
   163         }
   164         double constantValue() const {
   165             JS_ASSERT(pod.which_ == Constant);
   166             return pod.u.constant.value_;
   167         }
   169         size_t serializedSize() const;
   170         uint8_t *serialize(uint8_t *cursor) const;
   171         const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor);
   172         bool clone(ExclusiveContext *cx, Global *out) const;
   173     };
   175     class Exit
   176     {
   177         unsigned ffiIndex_;
   178         unsigned globalDataOffset_;
   179         unsigned interpCodeOffset_;
   180         unsigned ionCodeOffset_;
   182         friend class AsmJSModule;
   184       public:
   185         Exit() {}
   186         Exit(unsigned ffiIndex, unsigned globalDataOffset)
   187           : ffiIndex_(ffiIndex), globalDataOffset_(globalDataOffset),
   188             interpCodeOffset_(0), ionCodeOffset_(0)
   189         {}
   190         unsigned ffiIndex() const {
   191             return ffiIndex_;
   192         }
   193         unsigned globalDataOffset() const {
   194             return globalDataOffset_;
   195         }
   196         void initInterpOffset(unsigned off) {
   197             JS_ASSERT(!interpCodeOffset_);
   198             interpCodeOffset_ = off;
   199         }
   200         void initIonOffset(unsigned off) {
   201             JS_ASSERT(!ionCodeOffset_);
   202             ionCodeOffset_ = off;
   203         }
   204         void updateOffsets(jit::MacroAssembler &masm) {
   205             interpCodeOffset_ = masm.actualOffset(interpCodeOffset_);
   206             ionCodeOffset_ = masm.actualOffset(ionCodeOffset_);
   207         }
   209         size_t serializedSize() const;
   210         uint8_t *serialize(uint8_t *cursor) const;
   211         const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor);
   212         bool clone(ExclusiveContext *cx, Exit *out) const;
   213     };
   214     typedef int32_t (*CodePtr)(uint64_t *args, uint8_t *global);
   216     typedef Vector<AsmJSCoercion, 0, SystemAllocPolicy> ArgCoercionVector;
   218     enum ReturnType { Return_Int32, Return_Double, Return_Void };
   220     class ExportedFunction
   221     {
   222         PropertyName *name_;
   223         PropertyName *maybeFieldName_;
   224         ArgCoercionVector argCoercions_;
   225         struct Pod {
   226             ReturnType returnType_;
   227             uint32_t codeOffset_;
   228             // These two fields are offsets to the beginning of the ScriptSource
   229             // of the module, and thus invariant under serialization (unlike
   230             // absolute offsets into ScriptSource).
   231             uint32_t startOffsetInModule_;
   232             uint32_t endOffsetInModule_;
   233         } pod;
   235         friend class AsmJSModule;
   237         ExportedFunction(PropertyName *name,
   238                          uint32_t startOffsetInModule, uint32_t endOffsetInModule,
   239                          PropertyName *maybeFieldName,
   240                          ArgCoercionVector &&argCoercions,
   241                          ReturnType returnType)
   242         {
   243             name_ = name;
   244             maybeFieldName_ = maybeFieldName;
   245             argCoercions_ = mozilla::Move(argCoercions);
   246             pod.returnType_ = returnType;
   247             pod.codeOffset_ = UINT32_MAX;
   248             pod.startOffsetInModule_ = startOffsetInModule;
   249             pod.endOffsetInModule_ = endOffsetInModule;
   250             JS_ASSERT_IF(maybeFieldName_, name_->isTenured());
   251         }
   253         void trace(JSTracer *trc) {
   254             MarkStringUnbarriered(trc, &name_, "asm.js export name");
   255             if (maybeFieldName_)
   256                 MarkStringUnbarriered(trc, &maybeFieldName_, "asm.js export field");
   257         }
   259       public:
   260         ExportedFunction() {}
   261         ExportedFunction(ExportedFunction &&rhs) {
   262             name_ = rhs.name_;
   263             maybeFieldName_ = rhs.maybeFieldName_;
   264             argCoercions_ = mozilla::Move(rhs.argCoercions_);
   265             pod = rhs.pod;
   266         }
   267         void updateCodeOffset(jit::MacroAssembler &masm) {
   268             pod.codeOffset_ = masm.actualOffset(pod.codeOffset_);
   269         }
   271         void initCodeOffset(unsigned off) {
   272             JS_ASSERT(pod.codeOffset_ == UINT32_MAX);
   273             pod.codeOffset_ = off;
   274         }
   276         PropertyName *name() const {
   277             return name_;
   278         }
   279         uint32_t startOffsetInModule() const {
   280             return pod.startOffsetInModule_;
   281         }
   282         uint32_t endOffsetInModule() const {
   283             return pod.endOffsetInModule_;
   284         }
   285         PropertyName *maybeFieldName() const {
   286             return maybeFieldName_;
   287         }
   288         unsigned numArgs() const {
   289             return argCoercions_.length();
   290         }
   291         AsmJSCoercion argCoercion(unsigned i) const {
   292             return argCoercions_[i];
   293         }
   294         ReturnType returnType() const {
   295             return pod.returnType_;
   296         }
   298         size_t serializedSize() const;
   299         uint8_t *serialize(uint8_t *cursor) const;
   300         const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor);
   301         bool clone(ExclusiveContext *cx, ExportedFunction *out) const;
   302     };
   304     class Name
   305     {
   306         PropertyName *name_;
   307       public:
   308         Name() : name_(nullptr) {}
   309         Name(PropertyName *name) : name_(name) {}
   310         PropertyName *name() const { return name_; }
   311         PropertyName *&name() { return name_; }
   312         size_t serializedSize() const;
   313         uint8_t *serialize(uint8_t *cursor) const;
   314         const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor);
   315         bool clone(ExclusiveContext *cx, Name *out) const;
   316     };
   318 #if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
   319     // Function information to add to the VTune JIT profiler following linking.
   320     struct ProfiledFunction
   321     {
   322         PropertyName *name;
   323         struct Pod {
   324             unsigned startCodeOffset;
   325             unsigned endCodeOffset;
   326             unsigned lineno;
   327             unsigned columnIndex;
   328         } pod;
   330         explicit ProfiledFunction()
   331           : name(nullptr)
   332         { }
   334         ProfiledFunction(PropertyName *name, unsigned start, unsigned end,
   335                          unsigned line = 0, unsigned column = 0)
   336           : name(name)
   337         {
   338             JS_ASSERT(name->isTenured());
   340             pod.startCodeOffset = start;
   341             pod.endCodeOffset = end;
   342             pod.lineno = line;
   343             pod.columnIndex = column;
   344         }
   346         void trace(JSTracer *trc) {
   347             if (name)
   348                 MarkStringUnbarriered(trc, &name, "asm.js profiled function name");
   349         }
   351         size_t serializedSize() const;
   352         uint8_t *serialize(uint8_t *cursor) const;
   353         const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor);
   354     };
   355 #endif
   357 #if defined(JS_ION_PERF)
   358     struct ProfiledBlocksFunction : public ProfiledFunction
   359     {
   360         unsigned endInlineCodeOffset;
   361         jit::BasicBlocksVector blocks;
   363         ProfiledBlocksFunction(PropertyName *name, unsigned start, unsigned endInline, unsigned end,
   364                                jit::BasicBlocksVector &blocksVector)
   365           : ProfiledFunction(name, start, end), endInlineCodeOffset(endInline),
   366             blocks(mozilla::Move(blocksVector))
   367         {
   368             JS_ASSERT(name->isTenured());
   369         }
   371         ProfiledBlocksFunction(ProfiledBlocksFunction &&copy)
   372           : ProfiledFunction(copy.name, copy.pod.startCodeOffset, copy.pod.endCodeOffset),
   373             endInlineCodeOffset(copy.endInlineCodeOffset), blocks(mozilla::Move(copy.blocks))
   374         { }
   375     };
   376 #endif
   378     struct RelativeLink
   379     {
   380         uint32_t patchAtOffset;
   381         uint32_t targetOffset;
   382     };
   384     typedef Vector<RelativeLink, 0, SystemAllocPolicy> RelativeLinkVector;
   386     struct AbsoluteLink
   387     {
   388         jit::CodeOffsetLabel patchAt;
   389         jit::AsmJSImmKind target;
   390     };
   392     typedef Vector<AbsoluteLink, 0, SystemAllocPolicy> AbsoluteLinkVector;
   394     // Static-link data is used to patch a module either after it has been
   395     // compiled or deserialized with various absolute addresses (of code or
   396     // data in the process) or relative addresses (of code or data in the same
   397     // AsmJSModule).
   398     struct StaticLinkData
   399     {
   400         uint32_t interruptExitOffset;
   401         RelativeLinkVector relativeLinks;
   402         AbsoluteLinkVector absoluteLinks;
   404         size_t serializedSize() const;
   405         uint8_t *serialize(uint8_t *cursor) const;
   406         const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor);
   407         bool clone(ExclusiveContext *cx, StaticLinkData *out) const;
   409         size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
   410     };
   412   private:
   413     typedef Vector<Global, 0, SystemAllocPolicy> GlobalVector;
   414     typedef Vector<Exit, 0, SystemAllocPolicy> ExitVector;
   415     typedef Vector<ExportedFunction, 0, SystemAllocPolicy> ExportedFunctionVector;
   416     typedef Vector<jit::CallSite, 0, SystemAllocPolicy> CallSiteVector;
   417     typedef Vector<Name, 0, SystemAllocPolicy> FunctionNameVector;
   418     typedef Vector<jit::AsmJSHeapAccess, 0, SystemAllocPolicy> HeapAccessVector;
   419     typedef Vector<jit::IonScriptCounts *, 0, SystemAllocPolicy> FunctionCountsVector;
   420 #if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
   421     typedef Vector<ProfiledFunction, 0, SystemAllocPolicy> ProfiledFunctionVector;
   422 #endif
   423 #if defined(JS_ION_PERF)
   424     typedef Vector<ProfiledBlocksFunction, 0, SystemAllocPolicy> ProfiledBlocksFunctionVector;
   425 #endif
   427   private:
   428     PropertyName *                        globalArgumentName_;
   429     PropertyName *                        importArgumentName_;
   430     PropertyName *                        bufferArgumentName_;
   432     GlobalVector                          globals_;
   433     ExitVector                            exits_;
   434     ExportedFunctionVector                exports_;
   435     CallSiteVector                        callSites_;
   436     FunctionNameVector                    functionNames_;
   437     HeapAccessVector                      heapAccesses_;
   438 #if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
   439     ProfiledFunctionVector                profiledFunctions_;
   440 #endif
   441 #if defined(JS_ION_PERF)
   442     ProfiledBlocksFunctionVector          perfProfiledBlocksFunctions_;
   443 #endif
   445     struct Pod {
   446         uint32_t                          funcLength_;
   447         uint32_t                          funcLengthWithRightBrace_;
   448         bool                              strict_;
   449         uint32_t                          numGlobalVars_;
   450         uint32_t                          numFFIs_;
   451         size_t                            funcPtrTableAndExitBytes_;
   452         bool                              hasArrayView_;
   453         size_t                            functionBytes_; // just the function bodies, no stubs
   454         size_t                            codeBytes_;     // function bodies and stubs
   455         size_t                            totalBytes_;    // function bodies, stubs, and global data
   456         uint32_t                          minHeapLength_;
   457     } pod;
   459     uint8_t *                             code_;
   460     uint8_t *                             interruptExit_;
   462     StaticLinkData                        staticLinkData_;
   463     bool                                  dynamicallyLinked_;
   464     bool                                  loadedFromCache_;
   465     HeapPtr<ArrayBufferObject>            maybeHeap_;
   467     // The next two fields need to be kept out of the Pod as they depend on the
   468     // position of the module within the ScriptSource and thus aren't invariant
   469     // with caching.
   470     uint32_t                              funcStart_;
   471     uint32_t                              offsetToEndOfUseAsm_;
   473     ScriptSource *                        scriptSource_;
   475     // This field is accessed concurrently when requesting an interrupt.
   476     // Access must be synchronized via the runtime's interrupt lock.
   477     mutable bool                          codeIsProtected_;
   479   public:
   480     explicit AsmJSModule(ScriptSource *scriptSource, uint32_t functStart,
   481                          uint32_t offsetToEndOfUseAsm, bool strict);
   482     ~AsmJSModule();
   484     void trace(JSTracer *trc) {
   485         for (unsigned i = 0; i < globals_.length(); i++)
   486             globals_[i].trace(trc);
   487         for (unsigned i = 0; i < exports_.length(); i++)
   488             exports_[i].trace(trc);
   489         for (unsigned i = 0; i < exits_.length(); i++) {
   490             if (exitIndexToGlobalDatum(i).fun)
   491                 MarkObject(trc, &exitIndexToGlobalDatum(i).fun, "asm.js imported function");
   492         }
   493         for (unsigned i = 0; i < functionNames_.length(); i++)
   494             MarkStringUnbarriered(trc, &functionNames_[i].name(), "asm.js module function name");
   495 #if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
   496         for (unsigned i = 0; i < profiledFunctions_.length(); i++)
   497             profiledFunctions_[i].trace(trc);
   498 #endif
   499 #if defined(JS_ION_PERF)
   500         for (unsigned i = 0; i < perfProfiledBlocksFunctions_.length(); i++)
   501             perfProfiledBlocksFunctions_[i].trace(trc);
   502 #endif
   503         if (maybeHeap_)
   504             gc::MarkObject(trc, &maybeHeap_, "asm.js heap");
   506         if (globalArgumentName_)
   507             MarkStringUnbarriered(trc, &globalArgumentName_, "asm.js global argument name");
   508         if (importArgumentName_)
   509             MarkStringUnbarriered(trc, &importArgumentName_, "asm.js import argument name");
   510         if (bufferArgumentName_)
   511             MarkStringUnbarriered(trc, &bufferArgumentName_, "asm.js buffer argument name");
   512     }
   514     ScriptSource *scriptSource() const {
   515         JS_ASSERT(scriptSource_ != nullptr);
   516         return scriptSource_;
   517     }
   519     /*
   520      * funcStart() refers to the offset in the ScriptSource to the beginning
   521      * of the function. If the function has been created with the Function
   522      * constructor, this will be the first character in the function source.
   523      * Otherwise, it will be the opening parenthesis of the arguments list.
   524      */
   525     uint32_t funcStart() const {
   526         return funcStart_;
   527     }
   528     uint32_t offsetToEndOfUseAsm() const {
   529         return offsetToEndOfUseAsm_;
   530     }
   531     void initFuncEnd(uint32_t endBeforeCurly, uint32_t endAfterCurly) {
   532         JS_ASSERT(endBeforeCurly >= offsetToEndOfUseAsm_);
   533         JS_ASSERT(endAfterCurly >= offsetToEndOfUseAsm_);
   534         pod.funcLength_ = endBeforeCurly - funcStart_;
   535         pod.funcLengthWithRightBrace_ = endAfterCurly - funcStart_;
   536     }
   537     uint32_t funcEndBeforeCurly() const {
   538         return funcStart_ + pod.funcLength_;
   539     }
   540     uint32_t funcEndAfterCurly() const {
   541         return funcStart_ + pod.funcLengthWithRightBrace_;
   542     }
   543     bool strict() const {
   544         return pod.strict_;
   545     }
   547     bool addGlobalVarInit(const Value &v, AsmJSCoercion coercion, uint32_t *globalIndex) {
   548         JS_ASSERT(pod.funcPtrTableAndExitBytes_ == 0);
   549         if (pod.numGlobalVars_ == UINT32_MAX)
   550             return false;
   551         Global g(Global::Variable, nullptr);
   552         g.pod.u.var.initKind_ = Global::InitConstant;
   553         g.pod.u.var.init.constant_ = v;
   554         g.pod.u.var.coercion_ = coercion;
   555         g.pod.u.var.index_ = *globalIndex = pod.numGlobalVars_++;
   556         return globals_.append(g);
   557     }
   558     bool addGlobalVarImport(PropertyName *name, AsmJSCoercion coercion, uint32_t *globalIndex) {
   559         JS_ASSERT(pod.funcPtrTableAndExitBytes_ == 0);
   560         Global g(Global::Variable, name);
   561         g.pod.u.var.initKind_ = Global::InitImport;
   562         g.pod.u.var.coercion_ = coercion;
   563         g.pod.u.var.index_ = *globalIndex = pod.numGlobalVars_++;
   564         return globals_.append(g);
   565     }
   566     bool addFFI(PropertyName *field, uint32_t *ffiIndex) {
   567         if (pod.numFFIs_ == UINT32_MAX)
   568             return false;
   569         Global g(Global::FFI, field);
   570         g.pod.u.ffiIndex_ = *ffiIndex = pod.numFFIs_++;
   571         return globals_.append(g);
   572     }
   573     bool addArrayView(ArrayBufferView::ViewType vt, PropertyName *field) {
   574         pod.hasArrayView_ = true;
   575         Global g(Global::ArrayView, field);
   576         g.pod.u.viewType_ = vt;
   577         return globals_.append(g);
   578     }
   579     bool addMathBuiltinFunction(AsmJSMathBuiltinFunction func, PropertyName *field) {
   580         Global g(Global::MathBuiltinFunction, field);
   581         g.pod.u.mathBuiltinFunc_ = func;
   582         return globals_.append(g);
   583     }
   584     bool addMathBuiltinConstant(double value, PropertyName *field) {
   585         Global g(Global::Constant, field);
   586         g.pod.u.constant.value_ = value;
   587         g.pod.u.constant.kind_ = Global::MathConstant;
   588         return globals_.append(g);
   589     }
   590     bool addGlobalConstant(double value, PropertyName *name) {
   591         Global g(Global::Constant, name);
   592         g.pod.u.constant.value_ = value;
   593         g.pod.u.constant.kind_ = Global::GlobalConstant;
   594         return globals_.append(g);
   595     }
   596     bool addFuncPtrTable(unsigned numElems, uint32_t *globalDataOffset) {
   597         JS_ASSERT(IsPowerOfTwo(numElems));
   598         if (SIZE_MAX - pod.funcPtrTableAndExitBytes_ < numElems * sizeof(void*))
   599             return false;
   600         *globalDataOffset = globalDataBytes();
   601         pod.funcPtrTableAndExitBytes_ += numElems * sizeof(void*);
   602         return true;
   603     }
   604     bool addExit(unsigned ffiIndex, unsigned *exitIndex) {
   605         if (SIZE_MAX - pod.funcPtrTableAndExitBytes_ < sizeof(ExitDatum))
   606             return false;
   607         uint32_t globalDataOffset = globalDataBytes();
   608         JS_STATIC_ASSERT(sizeof(ExitDatum) % sizeof(void*) == 0);
   609         pod.funcPtrTableAndExitBytes_ += sizeof(ExitDatum);
   610         *exitIndex = unsigned(exits_.length());
   611         return exits_.append(Exit(ffiIndex, globalDataOffset));
   612     }
   614     bool addExportedFunction(PropertyName *name, uint32_t srcStart, uint32_t srcEnd,
   615                              PropertyName *maybeFieldName,
   616                              ArgCoercionVector &&argCoercions,
   617                              ReturnType returnType)
   618     {
   619         ExportedFunction func(name, srcStart, srcEnd, maybeFieldName,
   620                               mozilla::Move(argCoercions), returnType);
   621         if (exports_.length() >= UINT32_MAX)
   622             return false;
   623         return exports_.append(mozilla::Move(func));
   624     }
   625     unsigned numExportedFunctions() const {
   626         return exports_.length();
   627     }
   628     const ExportedFunction &exportedFunction(unsigned i) const {
   629         return exports_[i];
   630     }
   631     ExportedFunction &exportedFunction(unsigned i) {
   632         return exports_[i];
   633     }
   634     CodePtr entryTrampoline(const ExportedFunction &func) const {
   635         JS_ASSERT(func.pod.codeOffset_ != UINT32_MAX);
   636         return JS_DATA_TO_FUNC_PTR(CodePtr, code_ + func.pod.codeOffset_);
   637     }
   639     bool addFunctionName(PropertyName *name, uint32_t *nameIndex) {
   640         JS_ASSERT(name->isTenured());
   641         if (functionNames_.length() > jit::CallSiteDesc::FUNCTION_NAME_INDEX_MAX)
   642             return false;
   643         *nameIndex = functionNames_.length();
   644         return functionNames_.append(name);
   645     }
   646     PropertyName *functionName(uint32_t i) const {
   647         return functionNames_[i].name();
   648     }
   650 #if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
   651     bool trackProfiledFunction(PropertyName *name, unsigned startCodeOffset, unsigned endCodeOffset,
   652                                unsigned line, unsigned column)
   653     {
   654         ProfiledFunction func(name, startCodeOffset, endCodeOffset, line, column);
   655         return profiledFunctions_.append(func);
   656     }
   657     unsigned numProfiledFunctions() const {
   658         return profiledFunctions_.length();
   659     }
   660     ProfiledFunction &profiledFunction(unsigned i) {
   661         return profiledFunctions_[i];
   662     }
   663 #endif
   665 #ifdef JS_ION_PERF
   666     bool trackPerfProfiledBlocks(PropertyName *name, unsigned startCodeOffset, unsigned endInlineCodeOffset,
   667                                  unsigned endCodeOffset, jit::BasicBlocksVector &basicBlocks) {
   668         ProfiledBlocksFunction func(name, startCodeOffset, endInlineCodeOffset, endCodeOffset, basicBlocks);
   669         return perfProfiledBlocksFunctions_.append(mozilla::Move(func));
   670     }
   671     unsigned numPerfBlocksFunctions() const {
   672         return perfProfiledBlocksFunctions_.length();
   673     }
   674     ProfiledBlocksFunction &perfProfiledBlocksFunction(unsigned i) {
   675         return perfProfiledBlocksFunctions_[i];
   676     }
   677 #endif
   679     bool hasArrayView() const {
   680         return pod.hasArrayView_;
   681     }
   682     unsigned numFFIs() const {
   683         return pod.numFFIs_;
   684     }
   685     unsigned numGlobalVars() const {
   686         return pod.numGlobalVars_;
   687     }
   688     unsigned numGlobals() const {
   689         return globals_.length();
   690     }
   691     Global &global(unsigned i) {
   692         return globals_[i];
   693     }
   694     unsigned numExits() const {
   695         return exits_.length();
   696     }
   697     Exit &exit(unsigned i) {
   698         return exits_[i];
   699     }
   700     const Exit &exit(unsigned i) const {
   701         return exits_[i];
   702     }
   703     uint8_t *interpExitTrampoline(const Exit &exit) const {
   704         JS_ASSERT(exit.interpCodeOffset_);
   705         return code_ + exit.interpCodeOffset_;
   706     }
   707     uint8_t *ionExitTrampoline(const Exit &exit) const {
   708         JS_ASSERT(exit.ionCodeOffset_);
   709         return code_ + exit.ionCodeOffset_;
   710     }
   712     // An Exit holds bookkeeping information about an exit; the ExitDatum
   713     // struct overlays the actual runtime data stored in the global data
   714     // section.
   715     struct ExitDatum
   716     {
   717         uint8_t *exit;
   718         HeapPtrFunction fun;
   719     };
   721     // Global data section
   722     //
   723     // The global data section is placed after the executable code (i.e., at
   724     // offset codeBytes_) in the module's linear allocation. The global data
   725     // are laid out in this order:
   726     //   0. a pointer/descriptor for the heap that was linked to the module
   727     //   1. global variable state (elements are sizeof(uint64_t))
   728     //   2. interleaved function-pointer tables and exits. These are allocated
   729     //      while type checking function bodies (as exits and uses of
   730     //      function-pointer tables are encountered).
   731     size_t offsetOfGlobalData() const {
   732         JS_ASSERT(code_);
   733         return pod.codeBytes_;
   734     }
   735     uint8_t *globalData() const {
   736         return code_ + offsetOfGlobalData();
   737     }
   738     size_t globalDataBytes() const {
   739         return sizeof(void*) +
   740                pod.numGlobalVars_ * sizeof(uint64_t) +
   741                pod.funcPtrTableAndExitBytes_;
   742     }
   743     unsigned heapOffset() const {
   744         return 0;
   745     }
   746     uint8_t *&heapDatum() const {
   747         return *(uint8_t**)(globalData() + heapOffset());
   748     }
   749     unsigned globalVarIndexToGlobalDataOffset(unsigned i) const {
   750         JS_ASSERT(i < pod.numGlobalVars_);
   751         return sizeof(void*) +
   752                i * sizeof(uint64_t);
   753     }
   754     void *globalVarIndexToGlobalDatum(unsigned i) const {
   755         return (void *)(globalData() + globalVarIndexToGlobalDataOffset(i));
   756     }
   757     uint8_t **globalDataOffsetToFuncPtrTable(unsigned globalDataOffset) const {
   758         JS_ASSERT(globalDataOffset < globalDataBytes());
   759         return (uint8_t **)(globalData() + globalDataOffset);
   760     }
   761     unsigned exitIndexToGlobalDataOffset(unsigned exitIndex) const {
   762         return exits_[exitIndex].globalDataOffset();
   763     }
   764     ExitDatum &exitIndexToGlobalDatum(unsigned exitIndex) const {
   765         return *(ExitDatum *)(globalData() + exitIndexToGlobalDataOffset(exitIndex));
   766     }
   768     void initFunctionBytes(size_t functionBytes) {
   769         JS_ASSERT(pod.functionBytes_ == 0);
   770         pod.functionBytes_ = functionBytes;
   771     }
   772     void updateFunctionBytes(jit::MacroAssembler &masm) {
   773         pod.functionBytes_ = masm.actualOffset(pod.functionBytes_);
   774         JS_ASSERT(pod.functionBytes_ % AsmJSPageSize == 0);
   775     }
   776     size_t functionBytes() const {
   777         JS_ASSERT(pod.functionBytes_);
   778         JS_ASSERT(pod.functionBytes_ % AsmJSPageSize == 0);
   779         return pod.functionBytes_;
   780     }
   781     bool containsPC(void *pc) const {
   782         return pc >= code_ && pc < (code_ + functionBytes());
   783     }
   785     void assignHeapAccesses(jit::AsmJSHeapAccessVector &&accesses) {
   786         heapAccesses_ = Move(accesses);
   787     }
   788     unsigned numHeapAccesses() const {
   789         return heapAccesses_.length();
   790     }
   791     const jit::AsmJSHeapAccess &heapAccess(unsigned i) const {
   792         return heapAccesses_[i];
   793     }
   794     jit::AsmJSHeapAccess &heapAccess(unsigned i) {
   795         return heapAccesses_[i];
   796     }
   798     void assignCallSites(jit::CallSiteVector &&callsites) {
   799         callSites_ = Move(callsites);
   800     }
   801     unsigned numCallSites() const {
   802         return callSites_.length();
   803     }
   804     const jit::CallSite &callSite(unsigned i) const {
   805         return callSites_[i];
   806     }
   807     jit::CallSite &callSite(unsigned i) {
   808         return callSites_[i];
   809     }
   811     void initHeap(Handle<ArrayBufferObject*> heap, JSContext *cx);
   813     void requireHeapLengthToBeAtLeast(uint32_t len) {
   814         if (len > pod.minHeapLength_)
   815             pod.minHeapLength_ = len;
   816     }
   817     uint32_t minHeapLength() const {
   818         return pod.minHeapLength_;
   819     }
   821     bool allocateAndCopyCode(ExclusiveContext *cx, jit::MacroAssembler &masm);
   823     // StaticLinkData setters (called after finishing compilation, before
   824     // staticLink).
   825     bool addRelativeLink(RelativeLink link) {
   826         return staticLinkData_.relativeLinks.append(link);
   827     }
   828     bool addAbsoluteLink(AbsoluteLink link) {
   829         return staticLinkData_.absoluteLinks.append(link);
   830     }
   831     void setInterruptOffset(uint32_t offset) {
   832         staticLinkData_.interruptExitOffset = offset;
   833     }
   835     void restoreToInitialState(ArrayBufferObject *maybePrevBuffer, ExclusiveContext *cx);
   836     void setAutoFlushICacheRange();
   837     void staticallyLink(ExclusiveContext *cx);
   839     uint8_t *codeBase() const {
   840         JS_ASSERT(code_);
   841         JS_ASSERT(uintptr_t(code_) % AsmJSPageSize == 0);
   842         return code_;
   843     }
   845     uint8_t *interruptExit() const {
   846         return interruptExit_;
   847     }
   849     void setIsDynamicallyLinked() {
   850         JS_ASSERT(!dynamicallyLinked_);
   851         dynamicallyLinked_ = true;
   852     }
   853     bool isDynamicallyLinked() const {
   854         return dynamicallyLinked_;
   855     }
   856     uint8_t *maybeHeap() const {
   857         JS_ASSERT(dynamicallyLinked_);
   858         return heapDatum();
   859     }
   860     ArrayBufferObject *maybeHeapBufferObject() const {
   861         JS_ASSERT(dynamicallyLinked_);
   862         return maybeHeap_;
   863     }
   864     size_t heapLength() const {
   865         JS_ASSERT(dynamicallyLinked_);
   866         return maybeHeap_ ? maybeHeap_->byteLength() : 0;
   867     }
   869     void initGlobalArgumentName(PropertyName *n) {
   870         JS_ASSERT_IF(n, n->isTenured());
   871         globalArgumentName_ = n;
   872     }
   873     void initImportArgumentName(PropertyName *n) {
   874         JS_ASSERT_IF(n, n->isTenured());
   875         importArgumentName_ = n;
   876     }
   877     void initBufferArgumentName(PropertyName *n) {
   878         JS_ASSERT_IF(n, n->isTenured());
   879         bufferArgumentName_ = n;
   880     }
   882     PropertyName *globalArgumentName() const {
   883         return globalArgumentName_;
   884     }
   885     PropertyName *importArgumentName() const {
   886         return importArgumentName_;
   887     }
   888     PropertyName *bufferArgumentName() const {
   889         return bufferArgumentName_;
   890     }
   892     void detachIonCompilation(size_t exitIndex) const {
   893         exitIndexToGlobalDatum(exitIndex).exit = interpExitTrampoline(exit(exitIndex));
   894     }
   896     void addSizeOfMisc(mozilla::MallocSizeOf mallocSizeOf, size_t *asmJSModuleCode,
   897                        size_t *asmJSModuleData);
   899     size_t serializedSize() const;
   900     uint8_t *serialize(uint8_t *cursor) const;
   901     const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor);
   902     bool loadedFromCache() const { return loadedFromCache_; }
   904     bool clone(JSContext *cx, ScopedJSDeletePtr<AsmJSModule> *moduleOut) const;
   906     // These methods may only be called while holding the Runtime's interrupt
   907     // lock.
   908     void protectCode(JSRuntime *rt) const;
   909     void unprotectCode(JSRuntime *rt) const;
   910     bool codeIsProtected(JSRuntime *rt) const;
   911 };
   913 // Store the just-parsed module in the cache using AsmJSCacheOps.
   914 extern bool
   915 StoreAsmJSModuleInCache(AsmJSParser &parser,
   916                         const AsmJSModule &module,
   917                         ExclusiveContext *cx);
   919 // Attempt to load the asm.js module that is about to be parsed from the cache
   920 // using AsmJSCacheOps. On cache hit, *module will be non-null. Note: the
   921 // return value indicates whether or not an error was encountered, not whether
   922 // there was a cache hit.
   923 extern bool
   924 LookupAsmJSModuleInCache(ExclusiveContext *cx,
   925                          AsmJSParser &parser,
   926                          ScopedJSDeletePtr<AsmJSModule> *module,
   927                          ScopedJSFreePtr<char> *compilationTimeReport);
   929 // An AsmJSModuleObject is an internal implementation object (i.e., not exposed
   930 // directly to user script) which manages the lifetime of an AsmJSModule. A
   931 // JSObject is necessary since we want LinkAsmJS/CallAsmJS JSFunctions to be
   932 // able to point to their module via their extended slots.
   933 class AsmJSModuleObject : public JSObject
   934 {
   935     static const unsigned MODULE_SLOT = 0;
   937   public:
   938     static const unsigned RESERVED_SLOTS = 1;
   940     // On success, return an AsmJSModuleClass JSObject that has taken ownership
   941     // (and release()ed) the given module.
   942     static AsmJSModuleObject *create(ExclusiveContext *cx, ScopedJSDeletePtr<AsmJSModule> *module);
   944     AsmJSModule &module() const;
   946     void addSizeOfMisc(mozilla::MallocSizeOf mallocSizeOf, size_t *asmJSModuleCode,
   947                        size_t *asmJSModuleData) {
   948         module().addSizeOfMisc(mallocSizeOf, asmJSModuleCode, asmJSModuleData);
   949     }
   951     static const Class class_;
   952 };
   954 }  // namespace js
   956 #endif  // JS_ION
   958 #endif /* jit_AsmJSModule_h */

mercurial