1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jit/AsmJS.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,166 @@ 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_AsmJS_h 1.11 +#define jit_AsmJS_h 1.12 + 1.13 +#include <stddef.h> 1.14 + 1.15 +#include "js/TypeDecls.h" 1.16 +#include "vm/ObjectImpl.h" 1.17 + 1.18 +namespace js { 1.19 + 1.20 +class ExclusiveContext; 1.21 +namespace frontend { 1.22 + template <typename ParseHandler> struct Parser; 1.23 + template <typename ParseHandler> struct ParseContext; 1.24 + class FullParseHandler; 1.25 + struct ParseNode; 1.26 +} 1.27 + 1.28 +typedef frontend::Parser<frontend::FullParseHandler> AsmJSParser; 1.29 +typedef frontend::ParseContext<frontend::FullParseHandler> AsmJSParseContext; 1.30 + 1.31 +// Takes over parsing of a function starting with "use asm". The return value 1.32 +// indicates whether an error was reported which the caller should propagate. 1.33 +// If no error was reported, the function may still fail to validate as asm.js. 1.34 +// In this case, the parser.tokenStream has been advanced an indeterminate 1.35 +// amount and the entire function should be reparsed from the beginning. 1.36 +extern bool 1.37 +CompileAsmJS(ExclusiveContext *cx, AsmJSParser &parser, frontend::ParseNode *stmtList, 1.38 + bool *validated); 1.39 + 1.40 +// The assumed page size; dynamically checked in CompileAsmJS. 1.41 +const size_t AsmJSPageSize = 4096; 1.42 + 1.43 +// The asm.js spec requires that the ArrayBuffer's byteLength be a multiple of 4096. 1.44 +static const size_t AsmJSAllocationGranularity = 4096; 1.45 + 1.46 +#ifdef JS_CODEGEN_X64 1.47 +// On x64, the internal ArrayBuffer data array is inflated to 4GiB (only the 1.48 +// byteLength portion of which is accessible) so that out-of-bounds accesses 1.49 +// (made using a uint32 index) are guaranteed to raise a SIGSEGV. 1.50 +static const size_t AsmJSBufferProtectedSize = 4 * 1024ULL * 1024ULL * 1024ULL; 1.51 + 1.52 +// To avoid dynamically checking bounds on each load/store, asm.js code relies 1.53 +// on the SIGSEGV handler in AsmJSSignalHandlers.cpp. However, this only works 1.54 +// if we can guarantee that *any* out-of-bounds access generates a fault. This 1.55 +// isn't generally true since an out-of-bounds access could land on other 1.56 +// Mozilla data. To overcome this on x64, we reserve an entire 4GB space, 1.57 +// making only the range [0, byteLength) accessible, and use a 32-bit unsigned 1.58 +// index into this space. (x86 and ARM require different tricks.) 1.59 +// 1.60 +// One complication is that we need to put an ObjectElements struct immediately 1.61 +// before the data array (as required by the general JSObject data structure). 1.62 +// Thus, we must stick a page before the elements to hold ObjectElements. 1.63 +// 1.64 +// |<------------------------------ 4GB + 1 pages --------------------->| 1.65 +// |<--- sizeof --->|<------------------- 4GB ----------------->| 1.66 +// 1.67 +// | waste | ObjectElements | data array | inaccessible reserved memory | 1.68 +// ^ ^ ^ 1.69 +// | \ / 1.70 +// obj->elements required to be page boundaries 1.71 +// 1.72 +static const size_t AsmJSMappedSize = AsmJSPageSize + AsmJSBufferProtectedSize; 1.73 +#endif // JS_CODEGEN_X64 1.74 + 1.75 +#ifdef JS_ION 1.76 + 1.77 +// Return whether asm.js optimization is inhibitted by the platform or 1.78 +// dynamically disabled: 1.79 +extern bool 1.80 +IsAsmJSCompilationAvailable(JSContext *cx, unsigned argc, JS::Value *vp); 1.81 + 1.82 +#else // JS_ION 1.83 + 1.84 +inline bool 1.85 +IsAsmJSCompilationAvailable(JSContext *cx, unsigned argc, Value *vp) 1.86 +{ 1.87 + CallArgs args = CallArgsFromVp(argc, vp); 1.88 + args.rval().set(BooleanValue(false)); 1.89 + return true; 1.90 +} 1.91 + 1.92 +#endif // JS_ION 1.93 + 1.94 +// The Asm.js heap length is constrained by the x64 backend heap access scheme 1.95 +// to be a multiple of the page size which is 4096 bytes, and also constrained 1.96 +// by the limits of ARM backends 'cmp immediate' instruction which supports a 1.97 +// complex range for the immediate argument. 1.98 +// 1.99 +// ARMv7 mode supports the following immediate constants, and the Thumb T2 1.100 +// instruction encoding also supports the subset of immediate constants used. 1.101 +// abcdefgh 00000000 00000000 00000000 1.102 +// 00abcdef gh000000 00000000 00000000 1.103 +// 0000abcd efgh0000 00000000 00000000 1.104 +// 000000ab cdefgh00 00000000 00000000 1.105 +// 00000000 abcdefgh 00000000 00000000 1.106 +// 00000000 00abcdef gh000000 00000000 1.107 +// 00000000 0000abcd efgh0000 00000000 1.108 +// ... 1.109 +// 1.110 +// The 4096 page size constraint restricts the length to: 1.111 +// xxxxxxxx xxxxxxxx xxxx0000 00000000 1.112 +// 1.113 +// Intersecting all the above constraints gives: 1.114 +// Heap length 0x40000000 to 0xff000000 quanta 0x01000000 1.115 +// Heap length 0x10000000 to 0x3fc00000 quanta 0x00400000 1.116 +// Heap length 0x04000000 to 0x0ff00000 quanta 0x00100000 1.117 +// Heap length 0x01000000 to 0x03fc0000 quanta 0x00040000 1.118 +// Heap length 0x00400000 to 0x00ff0000 quanta 0x00010000 1.119 +// Heap length 0x00100000 to 0x003fc000 quanta 0x00004000 1.120 +// Heap length 0x00001000 to 0x000ff000 quanta 0x00001000 1.121 +// 1.122 +inline uint32_t 1.123 +RoundUpToNextValidAsmJSHeapLength(uint32_t length) 1.124 +{ 1.125 + if (length < 0x00001000u) // Minimum length is the pages size of 4096. 1.126 + return 0x1000u; 1.127 + if (length < 0x00100000u) // < 1M quanta 4K 1.128 + return (length + 0x00000fff) & ~0x00000fff; 1.129 + if (length < 0x00400000u) // < 4M quanta 16K 1.130 + return (length + 0x00003fff) & ~0x00003fff; 1.131 + if (length < 0x01000000u) // < 16M quanta 64K 1.132 + return (length + 0x0000ffff) & ~0x0000ffff; 1.133 + if (length < 0x04000000u) // < 64M quanta 256K 1.134 + return (length + 0x0003ffff) & ~0x0003ffff; 1.135 + if (length < 0x10000000u) // < 256M quanta 1M 1.136 + return (length + 0x000fffff) & ~0x000fffff; 1.137 + if (length < 0x40000000u) // < 1024M quanta 4M 1.138 + return (length + 0x003fffff) & ~0x003fffff; 1.139 + // < 4096M quanta 16M. Note zero is returned if over 0xff000000 but such 1.140 + // lengths are not currently valid. 1.141 + JS_ASSERT(length <= 0xff000000); 1.142 + return (length + 0x00ffffff) & ~0x00ffffff; 1.143 +} 1.144 + 1.145 +inline bool 1.146 +IsValidAsmJSHeapLength(uint32_t length) 1.147 +{ 1.148 + if (length < AsmJSAllocationGranularity) 1.149 + return false; 1.150 + if (length <= 0x00100000u) 1.151 + return (length & 0x00000fff) == 0; 1.152 + if (length <= 0x00400000u) 1.153 + return (length & 0x00003fff) == 0; 1.154 + if (length <= 0x01000000u) 1.155 + return (length & 0x0000ffff) == 0; 1.156 + if (length <= 0x04000000u) 1.157 + return (length & 0x0003ffff) == 0; 1.158 + if (length <= 0x10000000u) 1.159 + return (length & 0x000fffff) == 0; 1.160 + if (length <= 0x40000000u) 1.161 + return (length & 0x003fffff) == 0; 1.162 + if (length <= 0xff000000u) 1.163 + return (length & 0x00ffffff) == 0; 1.164 + return false; 1.165 +} 1.166 + 1.167 +} // namespace js 1.168 + 1.169 +#endif // jit_AsmJS_h