|
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/. */ |
|
6 |
|
7 #ifndef jit_AsmJS_h |
|
8 #define jit_AsmJS_h |
|
9 |
|
10 #include <stddef.h> |
|
11 |
|
12 #include "js/TypeDecls.h" |
|
13 #include "vm/ObjectImpl.h" |
|
14 |
|
15 namespace js { |
|
16 |
|
17 class ExclusiveContext; |
|
18 namespace frontend { |
|
19 template <typename ParseHandler> struct Parser; |
|
20 template <typename ParseHandler> struct ParseContext; |
|
21 class FullParseHandler; |
|
22 struct ParseNode; |
|
23 } |
|
24 |
|
25 typedef frontend::Parser<frontend::FullParseHandler> AsmJSParser; |
|
26 typedef frontend::ParseContext<frontend::FullParseHandler> AsmJSParseContext; |
|
27 |
|
28 // Takes over parsing of a function starting with "use asm". The return value |
|
29 // indicates whether an error was reported which the caller should propagate. |
|
30 // If no error was reported, the function may still fail to validate as asm.js. |
|
31 // In this case, the parser.tokenStream has been advanced an indeterminate |
|
32 // amount and the entire function should be reparsed from the beginning. |
|
33 extern bool |
|
34 CompileAsmJS(ExclusiveContext *cx, AsmJSParser &parser, frontend::ParseNode *stmtList, |
|
35 bool *validated); |
|
36 |
|
37 // The assumed page size; dynamically checked in CompileAsmJS. |
|
38 const size_t AsmJSPageSize = 4096; |
|
39 |
|
40 // The asm.js spec requires that the ArrayBuffer's byteLength be a multiple of 4096. |
|
41 static const size_t AsmJSAllocationGranularity = 4096; |
|
42 |
|
43 #ifdef JS_CODEGEN_X64 |
|
44 // On x64, the internal ArrayBuffer data array is inflated to 4GiB (only the |
|
45 // byteLength portion of which is accessible) so that out-of-bounds accesses |
|
46 // (made using a uint32 index) are guaranteed to raise a SIGSEGV. |
|
47 static const size_t AsmJSBufferProtectedSize = 4 * 1024ULL * 1024ULL * 1024ULL; |
|
48 |
|
49 // To avoid dynamically checking bounds on each load/store, asm.js code relies |
|
50 // on the SIGSEGV handler in AsmJSSignalHandlers.cpp. However, this only works |
|
51 // if we can guarantee that *any* out-of-bounds access generates a fault. This |
|
52 // isn't generally true since an out-of-bounds access could land on other |
|
53 // Mozilla data. To overcome this on x64, we reserve an entire 4GB space, |
|
54 // making only the range [0, byteLength) accessible, and use a 32-bit unsigned |
|
55 // index into this space. (x86 and ARM require different tricks.) |
|
56 // |
|
57 // One complication is that we need to put an ObjectElements struct immediately |
|
58 // before the data array (as required by the general JSObject data structure). |
|
59 // Thus, we must stick a page before the elements to hold ObjectElements. |
|
60 // |
|
61 // |<------------------------------ 4GB + 1 pages --------------------->| |
|
62 // |<--- sizeof --->|<------------------- 4GB ----------------->| |
|
63 // |
|
64 // | waste | ObjectElements | data array | inaccessible reserved memory | |
|
65 // ^ ^ ^ |
|
66 // | \ / |
|
67 // obj->elements required to be page boundaries |
|
68 // |
|
69 static const size_t AsmJSMappedSize = AsmJSPageSize + AsmJSBufferProtectedSize; |
|
70 #endif // JS_CODEGEN_X64 |
|
71 |
|
72 #ifdef JS_ION |
|
73 |
|
74 // Return whether asm.js optimization is inhibitted by the platform or |
|
75 // dynamically disabled: |
|
76 extern bool |
|
77 IsAsmJSCompilationAvailable(JSContext *cx, unsigned argc, JS::Value *vp); |
|
78 |
|
79 #else // JS_ION |
|
80 |
|
81 inline bool |
|
82 IsAsmJSCompilationAvailable(JSContext *cx, unsigned argc, Value *vp) |
|
83 { |
|
84 CallArgs args = CallArgsFromVp(argc, vp); |
|
85 args.rval().set(BooleanValue(false)); |
|
86 return true; |
|
87 } |
|
88 |
|
89 #endif // JS_ION |
|
90 |
|
91 // The Asm.js heap length is constrained by the x64 backend heap access scheme |
|
92 // to be a multiple of the page size which is 4096 bytes, and also constrained |
|
93 // by the limits of ARM backends 'cmp immediate' instruction which supports a |
|
94 // complex range for the immediate argument. |
|
95 // |
|
96 // ARMv7 mode supports the following immediate constants, and the Thumb T2 |
|
97 // instruction encoding also supports the subset of immediate constants used. |
|
98 // abcdefgh 00000000 00000000 00000000 |
|
99 // 00abcdef gh000000 00000000 00000000 |
|
100 // 0000abcd efgh0000 00000000 00000000 |
|
101 // 000000ab cdefgh00 00000000 00000000 |
|
102 // 00000000 abcdefgh 00000000 00000000 |
|
103 // 00000000 00abcdef gh000000 00000000 |
|
104 // 00000000 0000abcd efgh0000 00000000 |
|
105 // ... |
|
106 // |
|
107 // The 4096 page size constraint restricts the length to: |
|
108 // xxxxxxxx xxxxxxxx xxxx0000 00000000 |
|
109 // |
|
110 // Intersecting all the above constraints gives: |
|
111 // Heap length 0x40000000 to 0xff000000 quanta 0x01000000 |
|
112 // Heap length 0x10000000 to 0x3fc00000 quanta 0x00400000 |
|
113 // Heap length 0x04000000 to 0x0ff00000 quanta 0x00100000 |
|
114 // Heap length 0x01000000 to 0x03fc0000 quanta 0x00040000 |
|
115 // Heap length 0x00400000 to 0x00ff0000 quanta 0x00010000 |
|
116 // Heap length 0x00100000 to 0x003fc000 quanta 0x00004000 |
|
117 // Heap length 0x00001000 to 0x000ff000 quanta 0x00001000 |
|
118 // |
|
119 inline uint32_t |
|
120 RoundUpToNextValidAsmJSHeapLength(uint32_t length) |
|
121 { |
|
122 if (length < 0x00001000u) // Minimum length is the pages size of 4096. |
|
123 return 0x1000u; |
|
124 if (length < 0x00100000u) // < 1M quanta 4K |
|
125 return (length + 0x00000fff) & ~0x00000fff; |
|
126 if (length < 0x00400000u) // < 4M quanta 16K |
|
127 return (length + 0x00003fff) & ~0x00003fff; |
|
128 if (length < 0x01000000u) // < 16M quanta 64K |
|
129 return (length + 0x0000ffff) & ~0x0000ffff; |
|
130 if (length < 0x04000000u) // < 64M quanta 256K |
|
131 return (length + 0x0003ffff) & ~0x0003ffff; |
|
132 if (length < 0x10000000u) // < 256M quanta 1M |
|
133 return (length + 0x000fffff) & ~0x000fffff; |
|
134 if (length < 0x40000000u) // < 1024M quanta 4M |
|
135 return (length + 0x003fffff) & ~0x003fffff; |
|
136 // < 4096M quanta 16M. Note zero is returned if over 0xff000000 but such |
|
137 // lengths are not currently valid. |
|
138 JS_ASSERT(length <= 0xff000000); |
|
139 return (length + 0x00ffffff) & ~0x00ffffff; |
|
140 } |
|
141 |
|
142 inline bool |
|
143 IsValidAsmJSHeapLength(uint32_t length) |
|
144 { |
|
145 if (length < AsmJSAllocationGranularity) |
|
146 return false; |
|
147 if (length <= 0x00100000u) |
|
148 return (length & 0x00000fff) == 0; |
|
149 if (length <= 0x00400000u) |
|
150 return (length & 0x00003fff) == 0; |
|
151 if (length <= 0x01000000u) |
|
152 return (length & 0x0000ffff) == 0; |
|
153 if (length <= 0x04000000u) |
|
154 return (length & 0x0003ffff) == 0; |
|
155 if (length <= 0x10000000u) |
|
156 return (length & 0x000fffff) == 0; |
|
157 if (length <= 0x40000000u) |
|
158 return (length & 0x003fffff) == 0; |
|
159 if (length <= 0xff000000u) |
|
160 return (length & 0x00ffffff) == 0; |
|
161 return false; |
|
162 } |
|
163 |
|
164 } // namespace js |
|
165 |
|
166 #endif // jit_AsmJS_h |