1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jit/AsmJSModule.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,958 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef jit_AsmJSModule_h 1.11 +#define jit_AsmJSModule_h 1.12 + 1.13 +#ifdef JS_ION 1.14 + 1.15 +#include "mozilla/Move.h" 1.16 +#include "mozilla/PodOperations.h" 1.17 + 1.18 +#include "jsscript.h" 1.19 + 1.20 +#include "gc/Marking.h" 1.21 +#include "jit/AsmJS.h" 1.22 +#include "jit/IonMacroAssembler.h" 1.23 +#ifdef JS_ION_PERF 1.24 +# include "jit/PerfSpewer.h" 1.25 +#endif 1.26 +#include "jit/RegisterSets.h" 1.27 +#include "vm/TypedArrayObject.h" 1.28 + 1.29 +namespace js { 1.30 + 1.31 +// These EcmaScript-defined coercions form the basis of the asm.js type system. 1.32 +enum AsmJSCoercion 1.33 +{ 1.34 + AsmJS_ToInt32, 1.35 + AsmJS_ToNumber, 1.36 + AsmJS_FRound 1.37 +}; 1.38 + 1.39 +// The asm.js spec recognizes this set of builtin Math functions. 1.40 +enum AsmJSMathBuiltinFunction 1.41 +{ 1.42 + AsmJSMathBuiltin_sin, AsmJSMathBuiltin_cos, AsmJSMathBuiltin_tan, 1.43 + AsmJSMathBuiltin_asin, AsmJSMathBuiltin_acos, AsmJSMathBuiltin_atan, 1.44 + AsmJSMathBuiltin_ceil, AsmJSMathBuiltin_floor, AsmJSMathBuiltin_exp, 1.45 + AsmJSMathBuiltin_log, AsmJSMathBuiltin_pow, AsmJSMathBuiltin_sqrt, 1.46 + AsmJSMathBuiltin_abs, AsmJSMathBuiltin_atan2, AsmJSMathBuiltin_imul, 1.47 + AsmJSMathBuiltin_fround, AsmJSMathBuiltin_min, AsmJSMathBuiltin_max 1.48 +}; 1.49 + 1.50 +// An asm.js module represents the collection of functions nested inside a 1.51 +// single outer "use asm" function. For example, this asm.js module: 1.52 +// function() { "use asm"; function f() {} function g() {} return f } 1.53 +// contains the functions 'f' and 'g'. 1.54 +// 1.55 +// An asm.js module contains both the jit-code produced by compiling all the 1.56 +// functions in the module as well all the data required to perform the 1.57 +// link-time validation step in the asm.js spec. 1.58 +// 1.59 +// NB: this means that AsmJSModule must be GC-safe. 1.60 +class AsmJSModule 1.61 +{ 1.62 + public: 1.63 + class Global 1.64 + { 1.65 + public: 1.66 + enum Which { Variable, FFI, ArrayView, MathBuiltinFunction, Constant }; 1.67 + enum VarInitKind { InitConstant, InitImport }; 1.68 + enum ConstantKind { GlobalConstant, MathConstant }; 1.69 + 1.70 + private: 1.71 + struct Pod { 1.72 + Which which_; 1.73 + union { 1.74 + struct { 1.75 + uint32_t index_; 1.76 + VarInitKind initKind_; 1.77 + AsmJSCoercion coercion_; 1.78 + union { 1.79 + Value constant_; // will only contain int32/double 1.80 + } init; 1.81 + } var; 1.82 + uint32_t ffiIndex_; 1.83 + ArrayBufferView::ViewType viewType_; 1.84 + AsmJSMathBuiltinFunction mathBuiltinFunc_; 1.85 + struct { 1.86 + ConstantKind kind_; 1.87 + double value_; 1.88 + } constant; 1.89 + } u; 1.90 + } pod; 1.91 + PropertyName *name_; 1.92 + 1.93 + friend class AsmJSModule; 1.94 + 1.95 + Global(Which which, PropertyName *name) { 1.96 + pod.which_ = which; 1.97 + name_ = name; 1.98 + JS_ASSERT_IF(name_, name_->isTenured()); 1.99 + } 1.100 + 1.101 + void trace(JSTracer *trc) { 1.102 + if (name_) 1.103 + MarkStringUnbarriered(trc, &name_, "asm.js global name"); 1.104 + JS_ASSERT_IF(pod.which_ == Variable && pod.u.var.initKind_ == InitConstant, 1.105 + !pod.u.var.init.constant_.isMarkable()); 1.106 + } 1.107 + 1.108 + public: 1.109 + Global() {} 1.110 + Which which() const { 1.111 + return pod.which_; 1.112 + } 1.113 + uint32_t varIndex() const { 1.114 + JS_ASSERT(pod.which_ == Variable); 1.115 + return pod.u.var.index_; 1.116 + } 1.117 + VarInitKind varInitKind() const { 1.118 + JS_ASSERT(pod.which_ == Variable); 1.119 + return pod.u.var.initKind_; 1.120 + } 1.121 + const Value &varInitConstant() const { 1.122 + JS_ASSERT(pod.which_ == Variable); 1.123 + JS_ASSERT(pod.u.var.initKind_ == InitConstant); 1.124 + return pod.u.var.init.constant_; 1.125 + } 1.126 + AsmJSCoercion varInitCoercion() const { 1.127 + JS_ASSERT(pod.which_ == Variable); 1.128 + return pod.u.var.coercion_; 1.129 + } 1.130 + PropertyName *varImportField() const { 1.131 + JS_ASSERT(pod.which_ == Variable); 1.132 + JS_ASSERT(pod.u.var.initKind_ == InitImport); 1.133 + return name_; 1.134 + } 1.135 + PropertyName *ffiField() const { 1.136 + JS_ASSERT(pod.which_ == FFI); 1.137 + return name_; 1.138 + } 1.139 + uint32_t ffiIndex() const { 1.140 + JS_ASSERT(pod.which_ == FFI); 1.141 + return pod.u.ffiIndex_; 1.142 + } 1.143 + PropertyName *viewName() const { 1.144 + JS_ASSERT(pod.which_ == ArrayView); 1.145 + return name_; 1.146 + } 1.147 + ArrayBufferView::ViewType viewType() const { 1.148 + JS_ASSERT(pod.which_ == ArrayView); 1.149 + return pod.u.viewType_; 1.150 + } 1.151 + PropertyName *mathName() const { 1.152 + JS_ASSERT(pod.which_ == MathBuiltinFunction); 1.153 + return name_; 1.154 + } 1.155 + AsmJSMathBuiltinFunction mathBuiltinFunction() const { 1.156 + JS_ASSERT(pod.which_ == MathBuiltinFunction); 1.157 + return pod.u.mathBuiltinFunc_; 1.158 + } 1.159 + PropertyName *constantName() const { 1.160 + JS_ASSERT(pod.which_ == Constant); 1.161 + return name_; 1.162 + } 1.163 + ConstantKind constantKind() const { 1.164 + JS_ASSERT(pod.which_ == Constant); 1.165 + return pod.u.constant.kind_; 1.166 + } 1.167 + double constantValue() const { 1.168 + JS_ASSERT(pod.which_ == Constant); 1.169 + return pod.u.constant.value_; 1.170 + } 1.171 + 1.172 + size_t serializedSize() const; 1.173 + uint8_t *serialize(uint8_t *cursor) const; 1.174 + const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor); 1.175 + bool clone(ExclusiveContext *cx, Global *out) const; 1.176 + }; 1.177 + 1.178 + class Exit 1.179 + { 1.180 + unsigned ffiIndex_; 1.181 + unsigned globalDataOffset_; 1.182 + unsigned interpCodeOffset_; 1.183 + unsigned ionCodeOffset_; 1.184 + 1.185 + friend class AsmJSModule; 1.186 + 1.187 + public: 1.188 + Exit() {} 1.189 + Exit(unsigned ffiIndex, unsigned globalDataOffset) 1.190 + : ffiIndex_(ffiIndex), globalDataOffset_(globalDataOffset), 1.191 + interpCodeOffset_(0), ionCodeOffset_(0) 1.192 + {} 1.193 + unsigned ffiIndex() const { 1.194 + return ffiIndex_; 1.195 + } 1.196 + unsigned globalDataOffset() const { 1.197 + return globalDataOffset_; 1.198 + } 1.199 + void initInterpOffset(unsigned off) { 1.200 + JS_ASSERT(!interpCodeOffset_); 1.201 + interpCodeOffset_ = off; 1.202 + } 1.203 + void initIonOffset(unsigned off) { 1.204 + JS_ASSERT(!ionCodeOffset_); 1.205 + ionCodeOffset_ = off; 1.206 + } 1.207 + void updateOffsets(jit::MacroAssembler &masm) { 1.208 + interpCodeOffset_ = masm.actualOffset(interpCodeOffset_); 1.209 + ionCodeOffset_ = masm.actualOffset(ionCodeOffset_); 1.210 + } 1.211 + 1.212 + size_t serializedSize() const; 1.213 + uint8_t *serialize(uint8_t *cursor) const; 1.214 + const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor); 1.215 + bool clone(ExclusiveContext *cx, Exit *out) const; 1.216 + }; 1.217 + typedef int32_t (*CodePtr)(uint64_t *args, uint8_t *global); 1.218 + 1.219 + typedef Vector<AsmJSCoercion, 0, SystemAllocPolicy> ArgCoercionVector; 1.220 + 1.221 + enum ReturnType { Return_Int32, Return_Double, Return_Void }; 1.222 + 1.223 + class ExportedFunction 1.224 + { 1.225 + PropertyName *name_; 1.226 + PropertyName *maybeFieldName_; 1.227 + ArgCoercionVector argCoercions_; 1.228 + struct Pod { 1.229 + ReturnType returnType_; 1.230 + uint32_t codeOffset_; 1.231 + // These two fields are offsets to the beginning of the ScriptSource 1.232 + // of the module, and thus invariant under serialization (unlike 1.233 + // absolute offsets into ScriptSource). 1.234 + uint32_t startOffsetInModule_; 1.235 + uint32_t endOffsetInModule_; 1.236 + } pod; 1.237 + 1.238 + friend class AsmJSModule; 1.239 + 1.240 + ExportedFunction(PropertyName *name, 1.241 + uint32_t startOffsetInModule, uint32_t endOffsetInModule, 1.242 + PropertyName *maybeFieldName, 1.243 + ArgCoercionVector &&argCoercions, 1.244 + ReturnType returnType) 1.245 + { 1.246 + name_ = name; 1.247 + maybeFieldName_ = maybeFieldName; 1.248 + argCoercions_ = mozilla::Move(argCoercions); 1.249 + pod.returnType_ = returnType; 1.250 + pod.codeOffset_ = UINT32_MAX; 1.251 + pod.startOffsetInModule_ = startOffsetInModule; 1.252 + pod.endOffsetInModule_ = endOffsetInModule; 1.253 + JS_ASSERT_IF(maybeFieldName_, name_->isTenured()); 1.254 + } 1.255 + 1.256 + void trace(JSTracer *trc) { 1.257 + MarkStringUnbarriered(trc, &name_, "asm.js export name"); 1.258 + if (maybeFieldName_) 1.259 + MarkStringUnbarriered(trc, &maybeFieldName_, "asm.js export field"); 1.260 + } 1.261 + 1.262 + public: 1.263 + ExportedFunction() {} 1.264 + ExportedFunction(ExportedFunction &&rhs) { 1.265 + name_ = rhs.name_; 1.266 + maybeFieldName_ = rhs.maybeFieldName_; 1.267 + argCoercions_ = mozilla::Move(rhs.argCoercions_); 1.268 + pod = rhs.pod; 1.269 + } 1.270 + void updateCodeOffset(jit::MacroAssembler &masm) { 1.271 + pod.codeOffset_ = masm.actualOffset(pod.codeOffset_); 1.272 + } 1.273 + 1.274 + void initCodeOffset(unsigned off) { 1.275 + JS_ASSERT(pod.codeOffset_ == UINT32_MAX); 1.276 + pod.codeOffset_ = off; 1.277 + } 1.278 + 1.279 + PropertyName *name() const { 1.280 + return name_; 1.281 + } 1.282 + uint32_t startOffsetInModule() const { 1.283 + return pod.startOffsetInModule_; 1.284 + } 1.285 + uint32_t endOffsetInModule() const { 1.286 + return pod.endOffsetInModule_; 1.287 + } 1.288 + PropertyName *maybeFieldName() const { 1.289 + return maybeFieldName_; 1.290 + } 1.291 + unsigned numArgs() const { 1.292 + return argCoercions_.length(); 1.293 + } 1.294 + AsmJSCoercion argCoercion(unsigned i) const { 1.295 + return argCoercions_[i]; 1.296 + } 1.297 + ReturnType returnType() const { 1.298 + return pod.returnType_; 1.299 + } 1.300 + 1.301 + size_t serializedSize() const; 1.302 + uint8_t *serialize(uint8_t *cursor) const; 1.303 + const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor); 1.304 + bool clone(ExclusiveContext *cx, ExportedFunction *out) const; 1.305 + }; 1.306 + 1.307 + class Name 1.308 + { 1.309 + PropertyName *name_; 1.310 + public: 1.311 + Name() : name_(nullptr) {} 1.312 + Name(PropertyName *name) : name_(name) {} 1.313 + PropertyName *name() const { return name_; } 1.314 + PropertyName *&name() { return name_; } 1.315 + size_t serializedSize() const; 1.316 + uint8_t *serialize(uint8_t *cursor) const; 1.317 + const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor); 1.318 + bool clone(ExclusiveContext *cx, Name *out) const; 1.319 + }; 1.320 + 1.321 +#if defined(MOZ_VTUNE) || defined(JS_ION_PERF) 1.322 + // Function information to add to the VTune JIT profiler following linking. 1.323 + struct ProfiledFunction 1.324 + { 1.325 + PropertyName *name; 1.326 + struct Pod { 1.327 + unsigned startCodeOffset; 1.328 + unsigned endCodeOffset; 1.329 + unsigned lineno; 1.330 + unsigned columnIndex; 1.331 + } pod; 1.332 + 1.333 + explicit ProfiledFunction() 1.334 + : name(nullptr) 1.335 + { } 1.336 + 1.337 + ProfiledFunction(PropertyName *name, unsigned start, unsigned end, 1.338 + unsigned line = 0, unsigned column = 0) 1.339 + : name(name) 1.340 + { 1.341 + JS_ASSERT(name->isTenured()); 1.342 + 1.343 + pod.startCodeOffset = start; 1.344 + pod.endCodeOffset = end; 1.345 + pod.lineno = line; 1.346 + pod.columnIndex = column; 1.347 + } 1.348 + 1.349 + void trace(JSTracer *trc) { 1.350 + if (name) 1.351 + MarkStringUnbarriered(trc, &name, "asm.js profiled function name"); 1.352 + } 1.353 + 1.354 + size_t serializedSize() const; 1.355 + uint8_t *serialize(uint8_t *cursor) const; 1.356 + const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor); 1.357 + }; 1.358 +#endif 1.359 + 1.360 +#if defined(JS_ION_PERF) 1.361 + struct ProfiledBlocksFunction : public ProfiledFunction 1.362 + { 1.363 + unsigned endInlineCodeOffset; 1.364 + jit::BasicBlocksVector blocks; 1.365 + 1.366 + ProfiledBlocksFunction(PropertyName *name, unsigned start, unsigned endInline, unsigned end, 1.367 + jit::BasicBlocksVector &blocksVector) 1.368 + : ProfiledFunction(name, start, end), endInlineCodeOffset(endInline), 1.369 + blocks(mozilla::Move(blocksVector)) 1.370 + { 1.371 + JS_ASSERT(name->isTenured()); 1.372 + } 1.373 + 1.374 + ProfiledBlocksFunction(ProfiledBlocksFunction &©) 1.375 + : ProfiledFunction(copy.name, copy.pod.startCodeOffset, copy.pod.endCodeOffset), 1.376 + endInlineCodeOffset(copy.endInlineCodeOffset), blocks(mozilla::Move(copy.blocks)) 1.377 + { } 1.378 + }; 1.379 +#endif 1.380 + 1.381 + struct RelativeLink 1.382 + { 1.383 + uint32_t patchAtOffset; 1.384 + uint32_t targetOffset; 1.385 + }; 1.386 + 1.387 + typedef Vector<RelativeLink, 0, SystemAllocPolicy> RelativeLinkVector; 1.388 + 1.389 + struct AbsoluteLink 1.390 + { 1.391 + jit::CodeOffsetLabel patchAt; 1.392 + jit::AsmJSImmKind target; 1.393 + }; 1.394 + 1.395 + typedef Vector<AbsoluteLink, 0, SystemAllocPolicy> AbsoluteLinkVector; 1.396 + 1.397 + // Static-link data is used to patch a module either after it has been 1.398 + // compiled or deserialized with various absolute addresses (of code or 1.399 + // data in the process) or relative addresses (of code or data in the same 1.400 + // AsmJSModule). 1.401 + struct StaticLinkData 1.402 + { 1.403 + uint32_t interruptExitOffset; 1.404 + RelativeLinkVector relativeLinks; 1.405 + AbsoluteLinkVector absoluteLinks; 1.406 + 1.407 + size_t serializedSize() const; 1.408 + uint8_t *serialize(uint8_t *cursor) const; 1.409 + const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor); 1.410 + bool clone(ExclusiveContext *cx, StaticLinkData *out) const; 1.411 + 1.412 + size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const; 1.413 + }; 1.414 + 1.415 + private: 1.416 + typedef Vector<Global, 0, SystemAllocPolicy> GlobalVector; 1.417 + typedef Vector<Exit, 0, SystemAllocPolicy> ExitVector; 1.418 + typedef Vector<ExportedFunction, 0, SystemAllocPolicy> ExportedFunctionVector; 1.419 + typedef Vector<jit::CallSite, 0, SystemAllocPolicy> CallSiteVector; 1.420 + typedef Vector<Name, 0, SystemAllocPolicy> FunctionNameVector; 1.421 + typedef Vector<jit::AsmJSHeapAccess, 0, SystemAllocPolicy> HeapAccessVector; 1.422 + typedef Vector<jit::IonScriptCounts *, 0, SystemAllocPolicy> FunctionCountsVector; 1.423 +#if defined(MOZ_VTUNE) || defined(JS_ION_PERF) 1.424 + typedef Vector<ProfiledFunction, 0, SystemAllocPolicy> ProfiledFunctionVector; 1.425 +#endif 1.426 +#if defined(JS_ION_PERF) 1.427 + typedef Vector<ProfiledBlocksFunction, 0, SystemAllocPolicy> ProfiledBlocksFunctionVector; 1.428 +#endif 1.429 + 1.430 + private: 1.431 + PropertyName * globalArgumentName_; 1.432 + PropertyName * importArgumentName_; 1.433 + PropertyName * bufferArgumentName_; 1.434 + 1.435 + GlobalVector globals_; 1.436 + ExitVector exits_; 1.437 + ExportedFunctionVector exports_; 1.438 + CallSiteVector callSites_; 1.439 + FunctionNameVector functionNames_; 1.440 + HeapAccessVector heapAccesses_; 1.441 +#if defined(MOZ_VTUNE) || defined(JS_ION_PERF) 1.442 + ProfiledFunctionVector profiledFunctions_; 1.443 +#endif 1.444 +#if defined(JS_ION_PERF) 1.445 + ProfiledBlocksFunctionVector perfProfiledBlocksFunctions_; 1.446 +#endif 1.447 + 1.448 + struct Pod { 1.449 + uint32_t funcLength_; 1.450 + uint32_t funcLengthWithRightBrace_; 1.451 + bool strict_; 1.452 + uint32_t numGlobalVars_; 1.453 + uint32_t numFFIs_; 1.454 + size_t funcPtrTableAndExitBytes_; 1.455 + bool hasArrayView_; 1.456 + size_t functionBytes_; // just the function bodies, no stubs 1.457 + size_t codeBytes_; // function bodies and stubs 1.458 + size_t totalBytes_; // function bodies, stubs, and global data 1.459 + uint32_t minHeapLength_; 1.460 + } pod; 1.461 + 1.462 + uint8_t * code_; 1.463 + uint8_t * interruptExit_; 1.464 + 1.465 + StaticLinkData staticLinkData_; 1.466 + bool dynamicallyLinked_; 1.467 + bool loadedFromCache_; 1.468 + HeapPtr<ArrayBufferObject> maybeHeap_; 1.469 + 1.470 + // The next two fields need to be kept out of the Pod as they depend on the 1.471 + // position of the module within the ScriptSource and thus aren't invariant 1.472 + // with caching. 1.473 + uint32_t funcStart_; 1.474 + uint32_t offsetToEndOfUseAsm_; 1.475 + 1.476 + ScriptSource * scriptSource_; 1.477 + 1.478 + // This field is accessed concurrently when requesting an interrupt. 1.479 + // Access must be synchronized via the runtime's interrupt lock. 1.480 + mutable bool codeIsProtected_; 1.481 + 1.482 + public: 1.483 + explicit AsmJSModule(ScriptSource *scriptSource, uint32_t functStart, 1.484 + uint32_t offsetToEndOfUseAsm, bool strict); 1.485 + ~AsmJSModule(); 1.486 + 1.487 + void trace(JSTracer *trc) { 1.488 + for (unsigned i = 0; i < globals_.length(); i++) 1.489 + globals_[i].trace(trc); 1.490 + for (unsigned i = 0; i < exports_.length(); i++) 1.491 + exports_[i].trace(trc); 1.492 + for (unsigned i = 0; i < exits_.length(); i++) { 1.493 + if (exitIndexToGlobalDatum(i).fun) 1.494 + MarkObject(trc, &exitIndexToGlobalDatum(i).fun, "asm.js imported function"); 1.495 + } 1.496 + for (unsigned i = 0; i < functionNames_.length(); i++) 1.497 + MarkStringUnbarriered(trc, &functionNames_[i].name(), "asm.js module function name"); 1.498 +#if defined(MOZ_VTUNE) || defined(JS_ION_PERF) 1.499 + for (unsigned i = 0; i < profiledFunctions_.length(); i++) 1.500 + profiledFunctions_[i].trace(trc); 1.501 +#endif 1.502 +#if defined(JS_ION_PERF) 1.503 + for (unsigned i = 0; i < perfProfiledBlocksFunctions_.length(); i++) 1.504 + perfProfiledBlocksFunctions_[i].trace(trc); 1.505 +#endif 1.506 + if (maybeHeap_) 1.507 + gc::MarkObject(trc, &maybeHeap_, "asm.js heap"); 1.508 + 1.509 + if (globalArgumentName_) 1.510 + MarkStringUnbarriered(trc, &globalArgumentName_, "asm.js global argument name"); 1.511 + if (importArgumentName_) 1.512 + MarkStringUnbarriered(trc, &importArgumentName_, "asm.js import argument name"); 1.513 + if (bufferArgumentName_) 1.514 + MarkStringUnbarriered(trc, &bufferArgumentName_, "asm.js buffer argument name"); 1.515 + } 1.516 + 1.517 + ScriptSource *scriptSource() const { 1.518 + JS_ASSERT(scriptSource_ != nullptr); 1.519 + return scriptSource_; 1.520 + } 1.521 + 1.522 + /* 1.523 + * funcStart() refers to the offset in the ScriptSource to the beginning 1.524 + * of the function. If the function has been created with the Function 1.525 + * constructor, this will be the first character in the function source. 1.526 + * Otherwise, it will be the opening parenthesis of the arguments list. 1.527 + */ 1.528 + uint32_t funcStart() const { 1.529 + return funcStart_; 1.530 + } 1.531 + uint32_t offsetToEndOfUseAsm() const { 1.532 + return offsetToEndOfUseAsm_; 1.533 + } 1.534 + void initFuncEnd(uint32_t endBeforeCurly, uint32_t endAfterCurly) { 1.535 + JS_ASSERT(endBeforeCurly >= offsetToEndOfUseAsm_); 1.536 + JS_ASSERT(endAfterCurly >= offsetToEndOfUseAsm_); 1.537 + pod.funcLength_ = endBeforeCurly - funcStart_; 1.538 + pod.funcLengthWithRightBrace_ = endAfterCurly - funcStart_; 1.539 + } 1.540 + uint32_t funcEndBeforeCurly() const { 1.541 + return funcStart_ + pod.funcLength_; 1.542 + } 1.543 + uint32_t funcEndAfterCurly() const { 1.544 + return funcStart_ + pod.funcLengthWithRightBrace_; 1.545 + } 1.546 + bool strict() const { 1.547 + return pod.strict_; 1.548 + } 1.549 + 1.550 + bool addGlobalVarInit(const Value &v, AsmJSCoercion coercion, uint32_t *globalIndex) { 1.551 + JS_ASSERT(pod.funcPtrTableAndExitBytes_ == 0); 1.552 + if (pod.numGlobalVars_ == UINT32_MAX) 1.553 + return false; 1.554 + Global g(Global::Variable, nullptr); 1.555 + g.pod.u.var.initKind_ = Global::InitConstant; 1.556 + g.pod.u.var.init.constant_ = v; 1.557 + g.pod.u.var.coercion_ = coercion; 1.558 + g.pod.u.var.index_ = *globalIndex = pod.numGlobalVars_++; 1.559 + return globals_.append(g); 1.560 + } 1.561 + bool addGlobalVarImport(PropertyName *name, AsmJSCoercion coercion, uint32_t *globalIndex) { 1.562 + JS_ASSERT(pod.funcPtrTableAndExitBytes_ == 0); 1.563 + Global g(Global::Variable, name); 1.564 + g.pod.u.var.initKind_ = Global::InitImport; 1.565 + g.pod.u.var.coercion_ = coercion; 1.566 + g.pod.u.var.index_ = *globalIndex = pod.numGlobalVars_++; 1.567 + return globals_.append(g); 1.568 + } 1.569 + bool addFFI(PropertyName *field, uint32_t *ffiIndex) { 1.570 + if (pod.numFFIs_ == UINT32_MAX) 1.571 + return false; 1.572 + Global g(Global::FFI, field); 1.573 + g.pod.u.ffiIndex_ = *ffiIndex = pod.numFFIs_++; 1.574 + return globals_.append(g); 1.575 + } 1.576 + bool addArrayView(ArrayBufferView::ViewType vt, PropertyName *field) { 1.577 + pod.hasArrayView_ = true; 1.578 + Global g(Global::ArrayView, field); 1.579 + g.pod.u.viewType_ = vt; 1.580 + return globals_.append(g); 1.581 + } 1.582 + bool addMathBuiltinFunction(AsmJSMathBuiltinFunction func, PropertyName *field) { 1.583 + Global g(Global::MathBuiltinFunction, field); 1.584 + g.pod.u.mathBuiltinFunc_ = func; 1.585 + return globals_.append(g); 1.586 + } 1.587 + bool addMathBuiltinConstant(double value, PropertyName *field) { 1.588 + Global g(Global::Constant, field); 1.589 + g.pod.u.constant.value_ = value; 1.590 + g.pod.u.constant.kind_ = Global::MathConstant; 1.591 + return globals_.append(g); 1.592 + } 1.593 + bool addGlobalConstant(double value, PropertyName *name) { 1.594 + Global g(Global::Constant, name); 1.595 + g.pod.u.constant.value_ = value; 1.596 + g.pod.u.constant.kind_ = Global::GlobalConstant; 1.597 + return globals_.append(g); 1.598 + } 1.599 + bool addFuncPtrTable(unsigned numElems, uint32_t *globalDataOffset) { 1.600 + JS_ASSERT(IsPowerOfTwo(numElems)); 1.601 + if (SIZE_MAX - pod.funcPtrTableAndExitBytes_ < numElems * sizeof(void*)) 1.602 + return false; 1.603 + *globalDataOffset = globalDataBytes(); 1.604 + pod.funcPtrTableAndExitBytes_ += numElems * sizeof(void*); 1.605 + return true; 1.606 + } 1.607 + bool addExit(unsigned ffiIndex, unsigned *exitIndex) { 1.608 + if (SIZE_MAX - pod.funcPtrTableAndExitBytes_ < sizeof(ExitDatum)) 1.609 + return false; 1.610 + uint32_t globalDataOffset = globalDataBytes(); 1.611 + JS_STATIC_ASSERT(sizeof(ExitDatum) % sizeof(void*) == 0); 1.612 + pod.funcPtrTableAndExitBytes_ += sizeof(ExitDatum); 1.613 + *exitIndex = unsigned(exits_.length()); 1.614 + return exits_.append(Exit(ffiIndex, globalDataOffset)); 1.615 + } 1.616 + 1.617 + bool addExportedFunction(PropertyName *name, uint32_t srcStart, uint32_t srcEnd, 1.618 + PropertyName *maybeFieldName, 1.619 + ArgCoercionVector &&argCoercions, 1.620 + ReturnType returnType) 1.621 + { 1.622 + ExportedFunction func(name, srcStart, srcEnd, maybeFieldName, 1.623 + mozilla::Move(argCoercions), returnType); 1.624 + if (exports_.length() >= UINT32_MAX) 1.625 + return false; 1.626 + return exports_.append(mozilla::Move(func)); 1.627 + } 1.628 + unsigned numExportedFunctions() const { 1.629 + return exports_.length(); 1.630 + } 1.631 + const ExportedFunction &exportedFunction(unsigned i) const { 1.632 + return exports_[i]; 1.633 + } 1.634 + ExportedFunction &exportedFunction(unsigned i) { 1.635 + return exports_[i]; 1.636 + } 1.637 + CodePtr entryTrampoline(const ExportedFunction &func) const { 1.638 + JS_ASSERT(func.pod.codeOffset_ != UINT32_MAX); 1.639 + return JS_DATA_TO_FUNC_PTR(CodePtr, code_ + func.pod.codeOffset_); 1.640 + } 1.641 + 1.642 + bool addFunctionName(PropertyName *name, uint32_t *nameIndex) { 1.643 + JS_ASSERT(name->isTenured()); 1.644 + if (functionNames_.length() > jit::CallSiteDesc::FUNCTION_NAME_INDEX_MAX) 1.645 + return false; 1.646 + *nameIndex = functionNames_.length(); 1.647 + return functionNames_.append(name); 1.648 + } 1.649 + PropertyName *functionName(uint32_t i) const { 1.650 + return functionNames_[i].name(); 1.651 + } 1.652 + 1.653 +#if defined(MOZ_VTUNE) || defined(JS_ION_PERF) 1.654 + bool trackProfiledFunction(PropertyName *name, unsigned startCodeOffset, unsigned endCodeOffset, 1.655 + unsigned line, unsigned column) 1.656 + { 1.657 + ProfiledFunction func(name, startCodeOffset, endCodeOffset, line, column); 1.658 + return profiledFunctions_.append(func); 1.659 + } 1.660 + unsigned numProfiledFunctions() const { 1.661 + return profiledFunctions_.length(); 1.662 + } 1.663 + ProfiledFunction &profiledFunction(unsigned i) { 1.664 + return profiledFunctions_[i]; 1.665 + } 1.666 +#endif 1.667 + 1.668 +#ifdef JS_ION_PERF 1.669 + bool trackPerfProfiledBlocks(PropertyName *name, unsigned startCodeOffset, unsigned endInlineCodeOffset, 1.670 + unsigned endCodeOffset, jit::BasicBlocksVector &basicBlocks) { 1.671 + ProfiledBlocksFunction func(name, startCodeOffset, endInlineCodeOffset, endCodeOffset, basicBlocks); 1.672 + return perfProfiledBlocksFunctions_.append(mozilla::Move(func)); 1.673 + } 1.674 + unsigned numPerfBlocksFunctions() const { 1.675 + return perfProfiledBlocksFunctions_.length(); 1.676 + } 1.677 + ProfiledBlocksFunction &perfProfiledBlocksFunction(unsigned i) { 1.678 + return perfProfiledBlocksFunctions_[i]; 1.679 + } 1.680 +#endif 1.681 + 1.682 + bool hasArrayView() const { 1.683 + return pod.hasArrayView_; 1.684 + } 1.685 + unsigned numFFIs() const { 1.686 + return pod.numFFIs_; 1.687 + } 1.688 + unsigned numGlobalVars() const { 1.689 + return pod.numGlobalVars_; 1.690 + } 1.691 + unsigned numGlobals() const { 1.692 + return globals_.length(); 1.693 + } 1.694 + Global &global(unsigned i) { 1.695 + return globals_[i]; 1.696 + } 1.697 + unsigned numExits() const { 1.698 + return exits_.length(); 1.699 + } 1.700 + Exit &exit(unsigned i) { 1.701 + return exits_[i]; 1.702 + } 1.703 + const Exit &exit(unsigned i) const { 1.704 + return exits_[i]; 1.705 + } 1.706 + uint8_t *interpExitTrampoline(const Exit &exit) const { 1.707 + JS_ASSERT(exit.interpCodeOffset_); 1.708 + return code_ + exit.interpCodeOffset_; 1.709 + } 1.710 + uint8_t *ionExitTrampoline(const Exit &exit) const { 1.711 + JS_ASSERT(exit.ionCodeOffset_); 1.712 + return code_ + exit.ionCodeOffset_; 1.713 + } 1.714 + 1.715 + // An Exit holds bookkeeping information about an exit; the ExitDatum 1.716 + // struct overlays the actual runtime data stored in the global data 1.717 + // section. 1.718 + struct ExitDatum 1.719 + { 1.720 + uint8_t *exit; 1.721 + HeapPtrFunction fun; 1.722 + }; 1.723 + 1.724 + // Global data section 1.725 + // 1.726 + // The global data section is placed after the executable code (i.e., at 1.727 + // offset codeBytes_) in the module's linear allocation. The global data 1.728 + // are laid out in this order: 1.729 + // 0. a pointer/descriptor for the heap that was linked to the module 1.730 + // 1. global variable state (elements are sizeof(uint64_t)) 1.731 + // 2. interleaved function-pointer tables and exits. These are allocated 1.732 + // while type checking function bodies (as exits and uses of 1.733 + // function-pointer tables are encountered). 1.734 + size_t offsetOfGlobalData() const { 1.735 + JS_ASSERT(code_); 1.736 + return pod.codeBytes_; 1.737 + } 1.738 + uint8_t *globalData() const { 1.739 + return code_ + offsetOfGlobalData(); 1.740 + } 1.741 + size_t globalDataBytes() const { 1.742 + return sizeof(void*) + 1.743 + pod.numGlobalVars_ * sizeof(uint64_t) + 1.744 + pod.funcPtrTableAndExitBytes_; 1.745 + } 1.746 + unsigned heapOffset() const { 1.747 + return 0; 1.748 + } 1.749 + uint8_t *&heapDatum() const { 1.750 + return *(uint8_t**)(globalData() + heapOffset()); 1.751 + } 1.752 + unsigned globalVarIndexToGlobalDataOffset(unsigned i) const { 1.753 + JS_ASSERT(i < pod.numGlobalVars_); 1.754 + return sizeof(void*) + 1.755 + i * sizeof(uint64_t); 1.756 + } 1.757 + void *globalVarIndexToGlobalDatum(unsigned i) const { 1.758 + return (void *)(globalData() + globalVarIndexToGlobalDataOffset(i)); 1.759 + } 1.760 + uint8_t **globalDataOffsetToFuncPtrTable(unsigned globalDataOffset) const { 1.761 + JS_ASSERT(globalDataOffset < globalDataBytes()); 1.762 + return (uint8_t **)(globalData() + globalDataOffset); 1.763 + } 1.764 + unsigned exitIndexToGlobalDataOffset(unsigned exitIndex) const { 1.765 + return exits_[exitIndex].globalDataOffset(); 1.766 + } 1.767 + ExitDatum &exitIndexToGlobalDatum(unsigned exitIndex) const { 1.768 + return *(ExitDatum *)(globalData() + exitIndexToGlobalDataOffset(exitIndex)); 1.769 + } 1.770 + 1.771 + void initFunctionBytes(size_t functionBytes) { 1.772 + JS_ASSERT(pod.functionBytes_ == 0); 1.773 + pod.functionBytes_ = functionBytes; 1.774 + } 1.775 + void updateFunctionBytes(jit::MacroAssembler &masm) { 1.776 + pod.functionBytes_ = masm.actualOffset(pod.functionBytes_); 1.777 + JS_ASSERT(pod.functionBytes_ % AsmJSPageSize == 0); 1.778 + } 1.779 + size_t functionBytes() const { 1.780 + JS_ASSERT(pod.functionBytes_); 1.781 + JS_ASSERT(pod.functionBytes_ % AsmJSPageSize == 0); 1.782 + return pod.functionBytes_; 1.783 + } 1.784 + bool containsPC(void *pc) const { 1.785 + return pc >= code_ && pc < (code_ + functionBytes()); 1.786 + } 1.787 + 1.788 + void assignHeapAccesses(jit::AsmJSHeapAccessVector &&accesses) { 1.789 + heapAccesses_ = Move(accesses); 1.790 + } 1.791 + unsigned numHeapAccesses() const { 1.792 + return heapAccesses_.length(); 1.793 + } 1.794 + const jit::AsmJSHeapAccess &heapAccess(unsigned i) const { 1.795 + return heapAccesses_[i]; 1.796 + } 1.797 + jit::AsmJSHeapAccess &heapAccess(unsigned i) { 1.798 + return heapAccesses_[i]; 1.799 + } 1.800 + 1.801 + void assignCallSites(jit::CallSiteVector &&callsites) { 1.802 + callSites_ = Move(callsites); 1.803 + } 1.804 + unsigned numCallSites() const { 1.805 + return callSites_.length(); 1.806 + } 1.807 + const jit::CallSite &callSite(unsigned i) const { 1.808 + return callSites_[i]; 1.809 + } 1.810 + jit::CallSite &callSite(unsigned i) { 1.811 + return callSites_[i]; 1.812 + } 1.813 + 1.814 + void initHeap(Handle<ArrayBufferObject*> heap, JSContext *cx); 1.815 + 1.816 + void requireHeapLengthToBeAtLeast(uint32_t len) { 1.817 + if (len > pod.minHeapLength_) 1.818 + pod.minHeapLength_ = len; 1.819 + } 1.820 + uint32_t minHeapLength() const { 1.821 + return pod.minHeapLength_; 1.822 + } 1.823 + 1.824 + bool allocateAndCopyCode(ExclusiveContext *cx, jit::MacroAssembler &masm); 1.825 + 1.826 + // StaticLinkData setters (called after finishing compilation, before 1.827 + // staticLink). 1.828 + bool addRelativeLink(RelativeLink link) { 1.829 + return staticLinkData_.relativeLinks.append(link); 1.830 + } 1.831 + bool addAbsoluteLink(AbsoluteLink link) { 1.832 + return staticLinkData_.absoluteLinks.append(link); 1.833 + } 1.834 + void setInterruptOffset(uint32_t offset) { 1.835 + staticLinkData_.interruptExitOffset = offset; 1.836 + } 1.837 + 1.838 + void restoreToInitialState(ArrayBufferObject *maybePrevBuffer, ExclusiveContext *cx); 1.839 + void setAutoFlushICacheRange(); 1.840 + void staticallyLink(ExclusiveContext *cx); 1.841 + 1.842 + uint8_t *codeBase() const { 1.843 + JS_ASSERT(code_); 1.844 + JS_ASSERT(uintptr_t(code_) % AsmJSPageSize == 0); 1.845 + return code_; 1.846 + } 1.847 + 1.848 + uint8_t *interruptExit() const { 1.849 + return interruptExit_; 1.850 + } 1.851 + 1.852 + void setIsDynamicallyLinked() { 1.853 + JS_ASSERT(!dynamicallyLinked_); 1.854 + dynamicallyLinked_ = true; 1.855 + } 1.856 + bool isDynamicallyLinked() const { 1.857 + return dynamicallyLinked_; 1.858 + } 1.859 + uint8_t *maybeHeap() const { 1.860 + JS_ASSERT(dynamicallyLinked_); 1.861 + return heapDatum(); 1.862 + } 1.863 + ArrayBufferObject *maybeHeapBufferObject() const { 1.864 + JS_ASSERT(dynamicallyLinked_); 1.865 + return maybeHeap_; 1.866 + } 1.867 + size_t heapLength() const { 1.868 + JS_ASSERT(dynamicallyLinked_); 1.869 + return maybeHeap_ ? maybeHeap_->byteLength() : 0; 1.870 + } 1.871 + 1.872 + void initGlobalArgumentName(PropertyName *n) { 1.873 + JS_ASSERT_IF(n, n->isTenured()); 1.874 + globalArgumentName_ = n; 1.875 + } 1.876 + void initImportArgumentName(PropertyName *n) { 1.877 + JS_ASSERT_IF(n, n->isTenured()); 1.878 + importArgumentName_ = n; 1.879 + } 1.880 + void initBufferArgumentName(PropertyName *n) { 1.881 + JS_ASSERT_IF(n, n->isTenured()); 1.882 + bufferArgumentName_ = n; 1.883 + } 1.884 + 1.885 + PropertyName *globalArgumentName() const { 1.886 + return globalArgumentName_; 1.887 + } 1.888 + PropertyName *importArgumentName() const { 1.889 + return importArgumentName_; 1.890 + } 1.891 + PropertyName *bufferArgumentName() const { 1.892 + return bufferArgumentName_; 1.893 + } 1.894 + 1.895 + void detachIonCompilation(size_t exitIndex) const { 1.896 + exitIndexToGlobalDatum(exitIndex).exit = interpExitTrampoline(exit(exitIndex)); 1.897 + } 1.898 + 1.899 + void addSizeOfMisc(mozilla::MallocSizeOf mallocSizeOf, size_t *asmJSModuleCode, 1.900 + size_t *asmJSModuleData); 1.901 + 1.902 + size_t serializedSize() const; 1.903 + uint8_t *serialize(uint8_t *cursor) const; 1.904 + const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor); 1.905 + bool loadedFromCache() const { return loadedFromCache_; } 1.906 + 1.907 + bool clone(JSContext *cx, ScopedJSDeletePtr<AsmJSModule> *moduleOut) const; 1.908 + 1.909 + // These methods may only be called while holding the Runtime's interrupt 1.910 + // lock. 1.911 + void protectCode(JSRuntime *rt) const; 1.912 + void unprotectCode(JSRuntime *rt) const; 1.913 + bool codeIsProtected(JSRuntime *rt) const; 1.914 +}; 1.915 + 1.916 +// Store the just-parsed module in the cache using AsmJSCacheOps. 1.917 +extern bool 1.918 +StoreAsmJSModuleInCache(AsmJSParser &parser, 1.919 + const AsmJSModule &module, 1.920 + ExclusiveContext *cx); 1.921 + 1.922 +// Attempt to load the asm.js module that is about to be parsed from the cache 1.923 +// using AsmJSCacheOps. On cache hit, *module will be non-null. Note: the 1.924 +// return value indicates whether or not an error was encountered, not whether 1.925 +// there was a cache hit. 1.926 +extern bool 1.927 +LookupAsmJSModuleInCache(ExclusiveContext *cx, 1.928 + AsmJSParser &parser, 1.929 + ScopedJSDeletePtr<AsmJSModule> *module, 1.930 + ScopedJSFreePtr<char> *compilationTimeReport); 1.931 + 1.932 +// An AsmJSModuleObject is an internal implementation object (i.e., not exposed 1.933 +// directly to user script) which manages the lifetime of an AsmJSModule. A 1.934 +// JSObject is necessary since we want LinkAsmJS/CallAsmJS JSFunctions to be 1.935 +// able to point to their module via their extended slots. 1.936 +class AsmJSModuleObject : public JSObject 1.937 +{ 1.938 + static const unsigned MODULE_SLOT = 0; 1.939 + 1.940 + public: 1.941 + static const unsigned RESERVED_SLOTS = 1; 1.942 + 1.943 + // On success, return an AsmJSModuleClass JSObject that has taken ownership 1.944 + // (and release()ed) the given module. 1.945 + static AsmJSModuleObject *create(ExclusiveContext *cx, ScopedJSDeletePtr<AsmJSModule> *module); 1.946 + 1.947 + AsmJSModule &module() const; 1.948 + 1.949 + void addSizeOfMisc(mozilla::MallocSizeOf mallocSizeOf, size_t *asmJSModuleCode, 1.950 + size_t *asmJSModuleData) { 1.951 + module().addSizeOfMisc(mallocSizeOf, asmJSModuleCode, asmJSModuleData); 1.952 + } 1.953 + 1.954 + static const Class class_; 1.955 +}; 1.956 + 1.957 +} // namespace js 1.958 + 1.959 +#endif // JS_ION 1.960 + 1.961 +#endif /* jit_AsmJSModule_h */