Sat, 03 Jan 2015 20:18:00 +0100
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 &©)
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 */