Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
2 /* vim: set ts=2 sw=2 et tw=79: */
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 file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /**
8 * Conversions from jsval to primitive values
9 */
11 #ifndef mozilla_dom_PrimitiveConversions_h
12 #define mozilla_dom_PrimitiveConversions_h
14 #include <limits>
15 #include <math.h>
16 #include <stdint.h>
18 #include "jsapi.h"
19 #include "mozilla/Assertions.h"
20 #include "mozilla/ErrorResult.h"
21 #include "mozilla/FloatingPoint.h"
23 namespace mozilla {
24 namespace dom {
26 template<typename T>
27 struct TypeName {
28 };
30 template<>
31 struct TypeName<int8_t> {
32 static const char* value() {
33 return "byte";
34 }
35 };
36 template<>
37 struct TypeName<uint8_t> {
38 static const char* value() {
39 return "octet";
40 }
41 };
42 template<>
43 struct TypeName<int16_t> {
44 static const char* value() {
45 return "short";
46 }
47 };
48 template<>
49 struct TypeName<uint16_t> {
50 static const char* value() {
51 return "unsigned short";
52 }
53 };
54 template<>
55 struct TypeName<int32_t> {
56 static const char* value() {
57 return "long";
58 }
59 };
60 template<>
61 struct TypeName<uint32_t> {
62 static const char* value() {
63 return "unsigned long";
64 }
65 };
66 template<>
67 struct TypeName<int64_t> {
68 static const char* value() {
69 return "long long";
70 }
71 };
72 template<>
73 struct TypeName<uint64_t> {
74 static const char* value() {
75 return "unsigned long long";
76 }
77 };
80 enum ConversionBehavior {
81 eDefault,
82 eEnforceRange,
83 eClamp
84 };
86 template<typename T, ConversionBehavior B>
87 struct PrimitiveConversionTraits {
88 };
90 template<typename T>
91 struct DisallowedConversion {
92 typedef int jstype;
93 typedef int intermediateType;
95 private:
96 static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v,
97 jstype* retval) {
98 MOZ_CRASH("This should never be instantiated!");
99 }
100 };
102 struct PrimitiveConversionTraits_smallInt {
103 // The output of JS::ToInt32 is determined as follows:
104 // 1) The value is converted to a double
105 // 2) Anything that's not a finite double returns 0
106 // 3) The double is rounded towards zero to the nearest integer
107 // 4) The resulting integer is reduced mod 2^32. The output of this
108 // operation is an integer in the range [0, 2^32).
109 // 5) If the resulting number is >= 2^31, 2^32 is subtracted from it.
110 //
111 // The result of all this is a number in the range [-2^31, 2^31)
112 //
113 // WebIDL conversions for the 8-bit, 16-bit, and 32-bit integer types
114 // are defined in the same way, except that step 4 uses reduction mod
115 // 2^8 and 2^16 for the 8-bit and 16-bit types respectively, and step 5
116 // is only done for the signed types.
117 //
118 // C/C++ define integer conversion semantics to unsigned types as taking
119 // your input integer mod (1 + largest value representable in the
120 // unsigned type). Since 2^32 is zero mod 2^8, 2^16, and 2^32,
121 // converting to the unsigned int of the relevant width will correctly
122 // perform step 4; in particular, the 2^32 possibly subtracted in step 5
123 // will become 0.
124 //
125 // Once we have step 4 done, we're just going to assume 2s-complement
126 // representation and cast directly to the type we really want.
127 //
128 // So we can cast directly for all unsigned types and for int32_t; for
129 // the smaller-width signed types we need to cast through the
130 // corresponding unsigned type.
131 typedef int32_t jstype;
132 typedef int32_t intermediateType;
133 static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v,
134 jstype* retval) {
135 return JS::ToInt32(cx, v, retval);
136 }
137 };
138 template<>
139 struct PrimitiveConversionTraits<int8_t, eDefault> : PrimitiveConversionTraits_smallInt {
140 typedef uint8_t intermediateType;
141 };
142 template<>
143 struct PrimitiveConversionTraits<uint8_t, eDefault> : PrimitiveConversionTraits_smallInt {
144 };
145 template<>
146 struct PrimitiveConversionTraits<int16_t, eDefault> : PrimitiveConversionTraits_smallInt {
147 typedef uint16_t intermediateType;
148 };
149 template<>
150 struct PrimitiveConversionTraits<uint16_t, eDefault> : PrimitiveConversionTraits_smallInt {
151 };
152 template<>
153 struct PrimitiveConversionTraits<int32_t, eDefault> : PrimitiveConversionTraits_smallInt {
154 };
155 template<>
156 struct PrimitiveConversionTraits<uint32_t, eDefault> : PrimitiveConversionTraits_smallInt {
157 };
159 template<>
160 struct PrimitiveConversionTraits<int64_t, eDefault> {
161 typedef int64_t jstype;
162 typedef int64_t intermediateType;
163 static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v,
164 jstype* retval) {
165 return JS::ToInt64(cx, v, retval);
166 }
167 };
169 template<>
170 struct PrimitiveConversionTraits<uint64_t, eDefault> {
171 typedef uint64_t jstype;
172 typedef uint64_t intermediateType;
173 static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v,
174 jstype* retval) {
175 return JS::ToUint64(cx, v, retval);
176 }
177 };
179 template<typename T>
180 struct PrimitiveConversionTraits_Limits {
181 static inline T min() {
182 return std::numeric_limits<T>::min();
183 }
184 static inline T max() {
185 return std::numeric_limits<T>::max();
186 }
187 };
189 template<>
190 struct PrimitiveConversionTraits_Limits<int64_t> {
191 static inline int64_t min() {
192 return -(1LL << 53);
193 }
194 static inline int64_t max() {
195 return (1LL << 53);
196 }
197 };
199 template<>
200 struct PrimitiveConversionTraits_Limits<uint64_t> {
201 static inline uint64_t min() {
202 return 0;
203 }
204 static inline uint64_t max() {
205 return (1LL << 53);
206 }
207 };
209 template<typename T, bool (*Enforce)(JSContext* cx, const double& d, T* retval)>
210 struct PrimitiveConversionTraits_ToCheckedIntHelper {
211 typedef T jstype;
212 typedef T intermediateType;
214 static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v,
215 jstype* retval) {
216 double intermediate;
217 if (!JS::ToNumber(cx, v, &intermediate)) {
218 return false;
219 }
221 return Enforce(cx, intermediate, retval);
222 }
223 };
225 template<typename T>
226 inline bool
227 PrimitiveConversionTraits_EnforceRange(JSContext* cx, const double& d, T* retval)
228 {
229 static_assert(std::numeric_limits<T>::is_integer,
230 "This can only be applied to integers!");
232 if (!mozilla::IsFinite(d)) {
233 return ThrowErrorMessage(cx, MSG_ENFORCE_RANGE_NON_FINITE, TypeName<T>::value());
234 }
236 bool neg = (d < 0);
237 double rounded = floor(neg ? -d : d);
238 rounded = neg ? -rounded : rounded;
239 if (rounded < PrimitiveConversionTraits_Limits<T>::min() ||
240 rounded > PrimitiveConversionTraits_Limits<T>::max()) {
241 return ThrowErrorMessage(cx, MSG_ENFORCE_RANGE_OUT_OF_RANGE, TypeName<T>::value());
242 }
244 *retval = static_cast<T>(rounded);
245 return true;
246 }
248 template<typename T>
249 struct PrimitiveConversionTraits<T, eEnforceRange> :
250 public PrimitiveConversionTraits_ToCheckedIntHelper<T, PrimitiveConversionTraits_EnforceRange<T> > {
251 };
253 template<typename T>
254 inline bool
255 PrimitiveConversionTraits_Clamp(JSContext* cx, const double& d, T* retval)
256 {
257 static_assert(std::numeric_limits<T>::is_integer,
258 "This can only be applied to integers!");
260 if (mozilla::IsNaN(d)) {
261 *retval = 0;
262 return true;
263 }
264 if (d >= PrimitiveConversionTraits_Limits<T>::max()) {
265 *retval = PrimitiveConversionTraits_Limits<T>::max();
266 return true;
267 }
268 if (d <= PrimitiveConversionTraits_Limits<T>::min()) {
269 *retval = PrimitiveConversionTraits_Limits<T>::min();
270 return true;
271 }
273 MOZ_ASSERT(mozilla::IsFinite(d));
275 // Banker's rounding (round ties towards even).
276 // We move away from 0 by 0.5f and then truncate. That gets us the right
277 // answer for any starting value except plus or minus N.5. With a starting
278 // value of that form, we now have plus or minus N+1. If N is odd, this is
279 // the correct result. If N is even, plus or minus N is the correct result.
280 double toTruncate = (d < 0) ? d - 0.5 : d + 0.5;
282 T truncated = static_cast<T>(toTruncate);
284 if (truncated == toTruncate) {
285 /*
286 * It was a tie (since moving away from 0 by 0.5 gave us the exact integer
287 * we want). Since we rounded away from 0, we either already have an even
288 * number or we have an odd number but the number we want is one closer to
289 * 0. So just unconditionally masking out the ones bit should do the trick
290 * to get us the value we want.
291 */
292 truncated &= ~1;
293 }
295 *retval = truncated;
296 return true;
297 }
299 template<typename T>
300 struct PrimitiveConversionTraits<T, eClamp> :
301 public PrimitiveConversionTraits_ToCheckedIntHelper<T, PrimitiveConversionTraits_Clamp<T> > {
302 };
305 template<ConversionBehavior B>
306 struct PrimitiveConversionTraits<bool, B> : public DisallowedConversion<bool> {};
308 template<>
309 struct PrimitiveConversionTraits<bool, eDefault> {
310 typedef bool jstype;
311 typedef bool intermediateType;
312 static inline bool converter(JSContext* /* unused */, JS::Handle<JS::Value> v,
313 jstype* retval) {
314 *retval = JS::ToBoolean(v);
315 return true;
316 }
317 };
320 template<ConversionBehavior B>
321 struct PrimitiveConversionTraits<float, B> : public DisallowedConversion<float> {};
323 template<ConversionBehavior B>
324 struct PrimitiveConversionTraits<double, B> : public DisallowedConversion<double> {};
326 struct PrimitiveConversionTraits_float {
327 typedef double jstype;
328 typedef double intermediateType;
329 static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v,
330 jstype* retval) {
331 return JS::ToNumber(cx, v, retval);
332 }
333 };
335 template<>
336 struct PrimitiveConversionTraits<float, eDefault> : PrimitiveConversionTraits_float {
337 };
338 template<>
339 struct PrimitiveConversionTraits<double, eDefault> : PrimitiveConversionTraits_float {
340 };
343 template<typename T, ConversionBehavior B>
344 bool ValueToPrimitive(JSContext* cx, JS::Handle<JS::Value> v, T* retval)
345 {
346 typename PrimitiveConversionTraits<T, B>::jstype t;
347 if (!PrimitiveConversionTraits<T, B>::converter(cx, v, &t))
348 return false;
350 *retval = static_cast<T>(
351 static_cast<typename PrimitiveConversionTraits<T, B>::intermediateType>(t));
352 return true;
353 }
355 } // namespace dom
356 } // namespace mozilla
358 #endif /* mozilla_dom_PrimitiveConversions_h */