|
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 /* |
|
8 * JavaScript API. |
|
9 */ |
|
10 |
|
11 #include "jsapi.h" |
|
12 |
|
13 #include "mozilla/FloatingPoint.h" |
|
14 #include "mozilla/PodOperations.h" |
|
15 |
|
16 #include <ctype.h> |
|
17 #include <stdarg.h> |
|
18 #include <string.h> |
|
19 #include <sys/stat.h> |
|
20 |
|
21 #include "jsarray.h" |
|
22 #include "jsatom.h" |
|
23 #include "jsbool.h" |
|
24 #include "jscntxt.h" |
|
25 #include "jsdate.h" |
|
26 #include "jsexn.h" |
|
27 #include "jsfun.h" |
|
28 #include "jsgc.h" |
|
29 #include "jsiter.h" |
|
30 #include "jslock.h" |
|
31 #include "jsmath.h" |
|
32 #include "jsnum.h" |
|
33 #include "jsobj.h" |
|
34 #include "json.h" |
|
35 #include "jsprf.h" |
|
36 #include "jsproxy.h" |
|
37 #include "jsscript.h" |
|
38 #include "jsstr.h" |
|
39 #include "jstypes.h" |
|
40 #include "jsutil.h" |
|
41 #include "jswatchpoint.h" |
|
42 #include "jsweakmap.h" |
|
43 #ifdef JS_THREADSAFE |
|
44 #include "jsworkers.h" |
|
45 #endif |
|
46 #include "jswrapper.h" |
|
47 #include "prmjtime.h" |
|
48 |
|
49 #if ENABLE_YARR_JIT |
|
50 #include "assembler/jit/ExecutableAllocator.h" |
|
51 #endif |
|
52 #include "builtin/Eval.h" |
|
53 #include "builtin/Intl.h" |
|
54 #include "builtin/MapObject.h" |
|
55 #include "builtin/RegExp.h" |
|
56 #ifdef ENABLE_BINARYDATA |
|
57 #include "builtin/SIMD.h" |
|
58 #include "builtin/TypedObject.h" |
|
59 #endif |
|
60 #include "frontend/BytecodeCompiler.h" |
|
61 #include "frontend/FullParseHandler.h" // for JS_BufferIsCompileableUnit |
|
62 #include "frontend/Parser.h" // for JS_BufferIsCompileableUnit |
|
63 #include "gc/Marking.h" |
|
64 #include "jit/AsmJSLink.h" |
|
65 #include "jit/JitCommon.h" |
|
66 #include "js/CharacterEncoding.h" |
|
67 #include "js/SliceBudget.h" |
|
68 #include "js/StructuredClone.h" |
|
69 #if ENABLE_INTL_API |
|
70 #include "unicode/uclean.h" |
|
71 #include "unicode/utypes.h" |
|
72 #endif // ENABLE_INTL_API |
|
73 #include "vm/DateObject.h" |
|
74 #include "vm/Debugger.h" |
|
75 #include "vm/ErrorObject.h" |
|
76 #include "vm/Interpreter.h" |
|
77 #include "vm/NumericConversions.h" |
|
78 #include "vm/RegExpStatics.h" |
|
79 #include "vm/Runtime.h" |
|
80 #include "vm/Shape.h" |
|
81 #include "vm/SharedArrayObject.h" |
|
82 #include "vm/StopIterationObject.h" |
|
83 #include "vm/StringBuffer.h" |
|
84 #include "vm/TypedArrayObject.h" |
|
85 #include "vm/WeakMapObject.h" |
|
86 #include "vm/WrapperObject.h" |
|
87 #include "vm/Xdr.h" |
|
88 #include "yarr/BumpPointerAllocator.h" |
|
89 |
|
90 #include "jsatominlines.h" |
|
91 #include "jsfuninlines.h" |
|
92 #include "jsinferinlines.h" |
|
93 #include "jsscriptinlines.h" |
|
94 |
|
95 #include "vm/Interpreter-inl.h" |
|
96 #include "vm/ObjectImpl-inl.h" |
|
97 #include "vm/String-inl.h" |
|
98 |
|
99 using namespace js; |
|
100 using namespace js::gc; |
|
101 using namespace js::types; |
|
102 |
|
103 using mozilla::Maybe; |
|
104 using mozilla::PodCopy; |
|
105 using mozilla::PodZero; |
|
106 |
|
107 using js::frontend::Parser; |
|
108 |
|
109 #ifdef HAVE_VA_LIST_AS_ARRAY |
|
110 #define JS_ADDRESSOF_VA_LIST(ap) ((va_list *)(ap)) |
|
111 #else |
|
112 #define JS_ADDRESSOF_VA_LIST(ap) (&(ap)) |
|
113 #endif |
|
114 |
|
115 /* Make sure that jschar is two bytes unsigned integer */ |
|
116 JS_STATIC_ASSERT((jschar)-1 > 0); |
|
117 JS_STATIC_ASSERT(sizeof(jschar) == 2); |
|
118 |
|
119 JS_PUBLIC_API(int64_t) |
|
120 JS_Now() |
|
121 { |
|
122 return PRMJ_Now(); |
|
123 } |
|
124 |
|
125 JS_PUBLIC_API(jsval) |
|
126 JS_GetNaNValue(JSContext *cx) |
|
127 { |
|
128 return cx->runtime()->NaNValue; |
|
129 } |
|
130 |
|
131 JS_PUBLIC_API(jsval) |
|
132 JS_GetNegativeInfinityValue(JSContext *cx) |
|
133 { |
|
134 return cx->runtime()->negativeInfinityValue; |
|
135 } |
|
136 |
|
137 JS_PUBLIC_API(jsval) |
|
138 JS_GetPositiveInfinityValue(JSContext *cx) |
|
139 { |
|
140 return cx->runtime()->positiveInfinityValue; |
|
141 } |
|
142 |
|
143 JS_PUBLIC_API(jsval) |
|
144 JS_GetEmptyStringValue(JSContext *cx) |
|
145 { |
|
146 return STRING_TO_JSVAL(cx->runtime()->emptyString); |
|
147 } |
|
148 |
|
149 JS_PUBLIC_API(JSString *) |
|
150 JS_GetEmptyString(JSRuntime *rt) |
|
151 { |
|
152 JS_ASSERT(rt->hasContexts()); |
|
153 return rt->emptyString; |
|
154 } |
|
155 |
|
156 namespace js { |
|
157 |
|
158 void |
|
159 AssertHeapIsIdle(JSRuntime *rt) |
|
160 { |
|
161 JS_ASSERT(rt->heapState == js::Idle); |
|
162 } |
|
163 |
|
164 void |
|
165 AssertHeapIsIdle(JSContext *cx) |
|
166 { |
|
167 AssertHeapIsIdle(cx->runtime()); |
|
168 } |
|
169 |
|
170 } |
|
171 |
|
172 static void |
|
173 AssertHeapIsIdleOrIterating(JSRuntime *rt) |
|
174 { |
|
175 JS_ASSERT(!rt->isHeapCollecting()); |
|
176 } |
|
177 |
|
178 static void |
|
179 AssertHeapIsIdleOrIterating(JSContext *cx) |
|
180 { |
|
181 AssertHeapIsIdleOrIterating(cx->runtime()); |
|
182 } |
|
183 |
|
184 static void |
|
185 AssertHeapIsIdleOrStringIsFlat(JSContext *cx, JSString *str) |
|
186 { |
|
187 /* |
|
188 * We allow some functions to be called during a GC as long as the argument |
|
189 * is a flat string, since that will not cause allocation. |
|
190 */ |
|
191 JS_ASSERT_IF(cx->runtime()->isHeapBusy(), str->isFlat()); |
|
192 } |
|
193 |
|
194 JS_PUBLIC_API(bool) |
|
195 JS_ConvertArguments(JSContext *cx, const CallArgs &args, const char *format, ...) |
|
196 { |
|
197 va_list ap; |
|
198 bool ok; |
|
199 |
|
200 AssertHeapIsIdle(cx); |
|
201 |
|
202 va_start(ap, format); |
|
203 ok = JS_ConvertArgumentsVA(cx, args, format, ap); |
|
204 va_end(ap); |
|
205 return ok; |
|
206 } |
|
207 |
|
208 JS_PUBLIC_API(bool) |
|
209 JS_ConvertArgumentsVA(JSContext *cx, const CallArgs &args, const char *format, va_list ap) |
|
210 { |
|
211 unsigned index = 0; |
|
212 bool required; |
|
213 char c; |
|
214 double d; |
|
215 JSString *str; |
|
216 RootedObject obj(cx); |
|
217 RootedValue val(cx); |
|
218 |
|
219 AssertHeapIsIdle(cx); |
|
220 CHECK_REQUEST(cx); |
|
221 assertSameCompartment(cx, args); |
|
222 required = true; |
|
223 while ((c = *format++) != '\0') { |
|
224 if (isspace(c)) |
|
225 continue; |
|
226 if (c == '/') { |
|
227 required = false; |
|
228 continue; |
|
229 } |
|
230 if (index == args.length()) { |
|
231 if (required) { |
|
232 if (JSFunction *fun = ReportIfNotFunction(cx, args.calleev())) { |
|
233 char numBuf[12]; |
|
234 JS_snprintf(numBuf, sizeof numBuf, "%u", args.length()); |
|
235 JSAutoByteString funNameBytes; |
|
236 if (const char *name = GetFunctionNameBytes(cx, fun, &funNameBytes)) { |
|
237 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, |
|
238 JSMSG_MORE_ARGS_NEEDED, |
|
239 name, numBuf, (args.length() == 1) ? "" : "s"); |
|
240 } |
|
241 } |
|
242 return false; |
|
243 } |
|
244 break; |
|
245 } |
|
246 MutableHandleValue arg = args[index++]; |
|
247 switch (c) { |
|
248 case 'b': |
|
249 *va_arg(ap, bool *) = ToBoolean(arg); |
|
250 break; |
|
251 case 'c': |
|
252 if (!ToUint16(cx, arg, va_arg(ap, uint16_t *))) |
|
253 return false; |
|
254 break; |
|
255 case 'i': |
|
256 case 'j': // "j" was broken, you should not use it. |
|
257 if (!ToInt32(cx, arg, va_arg(ap, int32_t *))) |
|
258 return false; |
|
259 break; |
|
260 case 'u': |
|
261 if (!ToUint32(cx, arg, va_arg(ap, uint32_t *))) |
|
262 return false; |
|
263 break; |
|
264 case 'd': |
|
265 if (!ToNumber(cx, arg, va_arg(ap, double *))) |
|
266 return false; |
|
267 break; |
|
268 case 'I': |
|
269 if (!ToNumber(cx, arg, &d)) |
|
270 return false; |
|
271 *va_arg(ap, double *) = ToInteger(d); |
|
272 break; |
|
273 case 'S': |
|
274 case 'W': |
|
275 str = ToString<CanGC>(cx, arg); |
|
276 if (!str) |
|
277 return false; |
|
278 arg.setString(str); |
|
279 if (c == 'W') { |
|
280 JSFlatString *flat = str->ensureFlat(cx); |
|
281 if (!flat) |
|
282 return false; |
|
283 *va_arg(ap, const jschar **) = flat->chars(); |
|
284 } else { |
|
285 *va_arg(ap, JSString **) = str; |
|
286 } |
|
287 break; |
|
288 case 'o': |
|
289 if (arg.isNullOrUndefined()) { |
|
290 obj = nullptr; |
|
291 } else { |
|
292 obj = ToObject(cx, arg); |
|
293 if (!obj) |
|
294 return false; |
|
295 } |
|
296 arg.setObjectOrNull(obj); |
|
297 *va_arg(ap, JSObject **) = obj; |
|
298 break; |
|
299 case 'f': |
|
300 obj = ReportIfNotFunction(cx, arg); |
|
301 if (!obj) |
|
302 return false; |
|
303 arg.setObject(*obj); |
|
304 *va_arg(ap, JSFunction **) = &obj->as<JSFunction>(); |
|
305 break; |
|
306 case 'v': |
|
307 *va_arg(ap, jsval *) = arg; |
|
308 break; |
|
309 case '*': |
|
310 break; |
|
311 default: |
|
312 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_CHAR, format); |
|
313 return false; |
|
314 } |
|
315 } |
|
316 return true; |
|
317 } |
|
318 |
|
319 JS_PUBLIC_API(bool) |
|
320 JS_ConvertValue(JSContext *cx, HandleValue value, JSType type, MutableHandleValue vp) |
|
321 { |
|
322 bool ok; |
|
323 RootedObject obj(cx); |
|
324 JSString *str; |
|
325 double d; |
|
326 |
|
327 AssertHeapIsIdle(cx); |
|
328 CHECK_REQUEST(cx); |
|
329 assertSameCompartment(cx, value); |
|
330 switch (type) { |
|
331 case JSTYPE_VOID: |
|
332 vp.setUndefined(); |
|
333 ok = true; |
|
334 break; |
|
335 case JSTYPE_OBJECT: |
|
336 if (value.isNullOrUndefined()) { |
|
337 obj.set(nullptr); |
|
338 } else { |
|
339 obj = ToObject(cx, value); |
|
340 if (!obj) |
|
341 return false; |
|
342 } |
|
343 ok = true; |
|
344 break; |
|
345 case JSTYPE_FUNCTION: |
|
346 vp.set(value); |
|
347 obj = ReportIfNotFunction(cx, vp); |
|
348 ok = (obj != nullptr); |
|
349 break; |
|
350 case JSTYPE_STRING: |
|
351 str = ToString<CanGC>(cx, value); |
|
352 ok = (str != nullptr); |
|
353 if (ok) |
|
354 vp.setString(str); |
|
355 break; |
|
356 case JSTYPE_NUMBER: |
|
357 ok = ToNumber(cx, value, &d); |
|
358 if (ok) |
|
359 vp.setDouble(d); |
|
360 break; |
|
361 case JSTYPE_BOOLEAN: |
|
362 vp.setBoolean(ToBoolean(value)); |
|
363 return true; |
|
364 default: { |
|
365 char numBuf[12]; |
|
366 JS_snprintf(numBuf, sizeof numBuf, "%d", (int)type); |
|
367 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_TYPE, numBuf); |
|
368 ok = false; |
|
369 break; |
|
370 } |
|
371 } |
|
372 return ok; |
|
373 } |
|
374 |
|
375 JS_PUBLIC_API(bool) |
|
376 JS_ValueToObject(JSContext *cx, HandleValue value, MutableHandleObject objp) |
|
377 { |
|
378 AssertHeapIsIdle(cx); |
|
379 CHECK_REQUEST(cx); |
|
380 assertSameCompartment(cx, value); |
|
381 if (value.isNullOrUndefined()) { |
|
382 objp.set(nullptr); |
|
383 return true; |
|
384 } |
|
385 JSObject *obj = ToObject(cx, value); |
|
386 if (!obj) |
|
387 return false; |
|
388 objp.set(obj); |
|
389 return true; |
|
390 } |
|
391 |
|
392 JS_PUBLIC_API(JSFunction *) |
|
393 JS_ValueToFunction(JSContext *cx, HandleValue value) |
|
394 { |
|
395 AssertHeapIsIdle(cx); |
|
396 CHECK_REQUEST(cx); |
|
397 assertSameCompartment(cx, value); |
|
398 return ReportIfNotFunction(cx, value); |
|
399 } |
|
400 |
|
401 JS_PUBLIC_API(JSFunction *) |
|
402 JS_ValueToConstructor(JSContext *cx, HandleValue value) |
|
403 { |
|
404 AssertHeapIsIdle(cx); |
|
405 CHECK_REQUEST(cx); |
|
406 assertSameCompartment(cx, value); |
|
407 return ReportIfNotFunction(cx, value); |
|
408 } |
|
409 |
|
410 JS_PUBLIC_API(JSString *) |
|
411 JS_ValueToSource(JSContext *cx, HandleValue value) |
|
412 { |
|
413 AssertHeapIsIdle(cx); |
|
414 CHECK_REQUEST(cx); |
|
415 assertSameCompartment(cx, value); |
|
416 return ValueToSource(cx, value); |
|
417 } |
|
418 |
|
419 JS_PUBLIC_API(bool) |
|
420 JS_DoubleIsInt32(double d, int32_t *ip) |
|
421 { |
|
422 return mozilla::NumberIsInt32(d, ip); |
|
423 } |
|
424 |
|
425 JS_PUBLIC_API(int32_t) |
|
426 JS_DoubleToInt32(double d) |
|
427 { |
|
428 return ToInt32(d); |
|
429 } |
|
430 |
|
431 JS_PUBLIC_API(uint32_t) |
|
432 JS_DoubleToUint32(double d) |
|
433 { |
|
434 return ToUint32(d); |
|
435 } |
|
436 |
|
437 JS_PUBLIC_API(JSType) |
|
438 JS_TypeOfValue(JSContext *cx, HandleValue value) |
|
439 { |
|
440 AssertHeapIsIdle(cx); |
|
441 CHECK_REQUEST(cx); |
|
442 assertSameCompartment(cx, value); |
|
443 return TypeOfValue(value); |
|
444 } |
|
445 |
|
446 JS_PUBLIC_API(const char *) |
|
447 JS_GetTypeName(JSContext *cx, JSType type) |
|
448 { |
|
449 if ((unsigned)type >= (unsigned)JSTYPE_LIMIT) |
|
450 return nullptr; |
|
451 return TypeStrings[type]; |
|
452 } |
|
453 |
|
454 JS_PUBLIC_API(bool) |
|
455 JS_StrictlyEqual(JSContext *cx, jsval value1, jsval value2, bool *equal) |
|
456 { |
|
457 AssertHeapIsIdle(cx); |
|
458 CHECK_REQUEST(cx); |
|
459 assertSameCompartment(cx, value1, value2); |
|
460 bool eq; |
|
461 if (!StrictlyEqual(cx, value1, value2, &eq)) |
|
462 return false; |
|
463 *equal = eq; |
|
464 return true; |
|
465 } |
|
466 |
|
467 JS_PUBLIC_API(bool) |
|
468 JS_LooselyEqual(JSContext *cx, HandleValue value1, HandleValue value2, bool *equal) |
|
469 { |
|
470 AssertHeapIsIdle(cx); |
|
471 CHECK_REQUEST(cx); |
|
472 assertSameCompartment(cx, value1, value2); |
|
473 JS_ASSERT(equal); |
|
474 return LooselyEqual(cx, value1, value2, equal); |
|
475 } |
|
476 |
|
477 JS_PUBLIC_API(bool) |
|
478 JS_SameValue(JSContext *cx, jsval value1, jsval value2, bool *same) |
|
479 { |
|
480 AssertHeapIsIdle(cx); |
|
481 CHECK_REQUEST(cx); |
|
482 assertSameCompartment(cx, value1, value2); |
|
483 bool s; |
|
484 if (!SameValue(cx, value1, value2, &s)) |
|
485 return false; |
|
486 *same = s; |
|
487 return true; |
|
488 } |
|
489 |
|
490 JS_PUBLIC_API(bool) |
|
491 JS_IsBuiltinEvalFunction(JSFunction *fun) |
|
492 { |
|
493 return IsAnyBuiltinEval(fun); |
|
494 } |
|
495 |
|
496 JS_PUBLIC_API(bool) |
|
497 JS_IsBuiltinFunctionConstructor(JSFunction *fun) |
|
498 { |
|
499 return fun->isBuiltinFunctionConstructor(); |
|
500 } |
|
501 |
|
502 /************************************************************************/ |
|
503 |
|
504 /* |
|
505 * SpiderMonkey's initialization status is tracked here, and it controls things |
|
506 * that should happen only once across all runtimes. It's an API requirement |
|
507 * that JS_Init (and JS_ShutDown, if called) be called in a thread-aware |
|
508 * manner, so this variable doesn't need to be atomic. |
|
509 * |
|
510 * The only reason at present for the restriction that you can't call |
|
511 * JS_Init/stuff/JS_ShutDown multiple times is the Windows PRMJ NowInit |
|
512 * initialization code, which uses PR_CallOnce to initialize the PRMJ_Now |
|
513 * subsystem. (For reinitialization to be permitted, we'd need to "reset" the |
|
514 * called-once status -- doable, but more trouble than it's worth now.) |
|
515 * Initializing that subsystem from JS_Init eliminates the problem, but |
|
516 * initialization can take a comparatively long time (15ms or so), so we |
|
517 * really don't want to do it in JS_Init, and we really do want to do it only |
|
518 * when PRMJ_Now is eventually called. |
|
519 */ |
|
520 enum InitState { Uninitialized, Running, ShutDown }; |
|
521 static InitState jsInitState = Uninitialized; |
|
522 |
|
523 #ifdef DEBUG |
|
524 static void |
|
525 CheckMessageNumbering() |
|
526 { |
|
527 // Assert that the numbers associated with the error names in js.msg are |
|
528 // monotonically increasing. It's not a compile-time check, but it's |
|
529 // better than nothing. |
|
530 int errorNumber = 0; |
|
531 # define MSG_DEF(name, number, count, exception, format) \ |
|
532 JS_ASSERT(name == errorNumber++); |
|
533 # include "js.msg" |
|
534 # undef MSG_DEF |
|
535 } |
|
536 |
|
537 static unsigned |
|
538 MessageParameterCount(const char *format) |
|
539 { |
|
540 unsigned numfmtspecs = 0; |
|
541 for (const char *fmt = format; *fmt != '\0'; fmt++) { |
|
542 if (*fmt == '{' && isdigit(fmt[1])) |
|
543 ++numfmtspecs; |
|
544 } |
|
545 return numfmtspecs; |
|
546 } |
|
547 |
|
548 static void |
|
549 CheckMessageParameterCounts() |
|
550 { |
|
551 // Assert that each message format has the correct number of braced |
|
552 // parameters. |
|
553 # define MSG_DEF(name, number, count, exception, format) \ |
|
554 JS_BEGIN_MACRO \ |
|
555 JS_ASSERT(MessageParameterCount(format) == count); \ |
|
556 JS_END_MACRO; |
|
557 # include "js.msg" |
|
558 # undef MSG_DEF |
|
559 } |
|
560 #endif /* DEBUG */ |
|
561 |
|
562 JS_PUBLIC_API(bool) |
|
563 JS_Init(void) |
|
564 { |
|
565 MOZ_ASSERT(jsInitState == Uninitialized, |
|
566 "must call JS_Init once before any JSAPI operation except " |
|
567 "JS_SetICUMemoryFunctions"); |
|
568 MOZ_ASSERT(!JSRuntime::hasLiveRuntimes(), |
|
569 "how do we have live runtimes before JS_Init?"); |
|
570 |
|
571 #ifdef DEBUG |
|
572 CheckMessageNumbering(); |
|
573 CheckMessageParameterCounts(); |
|
574 #endif |
|
575 |
|
576 using js::TlsPerThreadData; |
|
577 if (!TlsPerThreadData.initialized() && !TlsPerThreadData.init()) |
|
578 return false; |
|
579 |
|
580 #if defined(JS_ION) |
|
581 if (!jit::InitializeIon()) |
|
582 return false; |
|
583 #endif |
|
584 |
|
585 if (!ForkJoinContext::initialize()) |
|
586 return false; |
|
587 |
|
588 #if EXPOSE_INTL_API |
|
589 UErrorCode err = U_ZERO_ERROR; |
|
590 u_init(&err); |
|
591 if (U_FAILURE(err)) |
|
592 return false; |
|
593 #endif // EXPOSE_INTL_API |
|
594 |
|
595 jsInitState = Running; |
|
596 return true; |
|
597 } |
|
598 |
|
599 JS_PUBLIC_API(void) |
|
600 JS_ShutDown(void) |
|
601 { |
|
602 MOZ_ASSERT(jsInitState == Running, |
|
603 "JS_ShutDown must only be called after JS_Init and can't race with it"); |
|
604 #ifdef DEBUG |
|
605 if (JSRuntime::hasLiveRuntimes()) { |
|
606 // Gecko is too buggy to assert this just yet. |
|
607 fprintf(stderr, |
|
608 "WARNING: YOU ARE LEAKING THE WORLD (at least one JSRuntime " |
|
609 "and everything alive inside it, that is) AT JS_ShutDown " |
|
610 "TIME. FIX THIS!\n"); |
|
611 } |
|
612 #endif |
|
613 |
|
614 #ifdef JS_THREADSAFE |
|
615 WorkerThreadState().finish(); |
|
616 #endif |
|
617 |
|
618 PRMJ_NowShutdown(); |
|
619 |
|
620 #if EXPOSE_INTL_API |
|
621 u_cleanup(); |
|
622 #endif // EXPOSE_INTL_API |
|
623 |
|
624 jsInitState = ShutDown; |
|
625 } |
|
626 |
|
627 #ifdef DEBUG |
|
628 JS_FRIEND_API(bool) |
|
629 JS::isGCEnabled() |
|
630 { |
|
631 return !TlsPerThreadData.get()->suppressGC; |
|
632 } |
|
633 #else |
|
634 JS_FRIEND_API(bool) JS::isGCEnabled() { return true; } |
|
635 #endif |
|
636 |
|
637 JS_PUBLIC_API(JSRuntime *) |
|
638 JS_NewRuntime(uint32_t maxbytes, JSUseHelperThreads useHelperThreads, JSRuntime *parentRuntime) |
|
639 { |
|
640 MOZ_ASSERT(jsInitState == Running, |
|
641 "must call JS_Init prior to creating any JSRuntimes"); |
|
642 |
|
643 // Any parent runtime should be the topmost parent. This assert |
|
644 // isn't required for correctness, but ensuring that the parent |
|
645 // runtime is not destroyed before this one is more easily done |
|
646 // for the main runtime in the process. |
|
647 JS_ASSERT_IF(parentRuntime, !parentRuntime->parentRuntime); |
|
648 |
|
649 JSRuntime *rt = js_new<JSRuntime>(parentRuntime, useHelperThreads); |
|
650 if (!rt) |
|
651 return nullptr; |
|
652 |
|
653 if (!rt->init(maxbytes)) { |
|
654 JS_DestroyRuntime(rt); |
|
655 return nullptr; |
|
656 } |
|
657 |
|
658 return rt; |
|
659 } |
|
660 |
|
661 JS_PUBLIC_API(void) |
|
662 JS_DestroyRuntime(JSRuntime *rt) |
|
663 { |
|
664 js_delete(rt); |
|
665 } |
|
666 |
|
667 JS_PUBLIC_API(bool) |
|
668 JS_SetICUMemoryFunctions(JS_ICUAllocFn allocFn, JS_ICUReallocFn reallocFn, JS_ICUFreeFn freeFn) |
|
669 { |
|
670 MOZ_ASSERT(jsInitState == Uninitialized, |
|
671 "must call JS_SetICUMemoryFunctions before any other JSAPI " |
|
672 "operation (including JS_Init)"); |
|
673 |
|
674 #if EXPOSE_INTL_API |
|
675 UErrorCode status = U_ZERO_ERROR; |
|
676 u_setMemoryFunctions(/* context = */ nullptr, allocFn, reallocFn, freeFn, &status); |
|
677 return U_SUCCESS(status); |
|
678 #else |
|
679 return true; |
|
680 #endif |
|
681 } |
|
682 |
|
683 JS_PUBLIC_API(void *) |
|
684 JS_GetRuntimePrivate(JSRuntime *rt) |
|
685 { |
|
686 return rt->data; |
|
687 } |
|
688 |
|
689 JS_PUBLIC_API(void) |
|
690 JS_SetRuntimePrivate(JSRuntime *rt, void *data) |
|
691 { |
|
692 rt->data = data; |
|
693 } |
|
694 |
|
695 #ifdef JS_THREADSAFE |
|
696 static void |
|
697 StartRequest(JSContext *cx) |
|
698 { |
|
699 JSRuntime *rt = cx->runtime(); |
|
700 JS_ASSERT(CurrentThreadCanAccessRuntime(rt)); |
|
701 |
|
702 if (rt->requestDepth) { |
|
703 rt->requestDepth++; |
|
704 } else { |
|
705 /* Indicate that a request is running. */ |
|
706 rt->requestDepth = 1; |
|
707 rt->triggerActivityCallback(true); |
|
708 } |
|
709 } |
|
710 |
|
711 static void |
|
712 StopRequest(JSContext *cx) |
|
713 { |
|
714 JSRuntime *rt = cx->runtime(); |
|
715 JS_ASSERT(CurrentThreadCanAccessRuntime(rt)); |
|
716 |
|
717 JS_ASSERT(rt->requestDepth != 0); |
|
718 if (rt->requestDepth != 1) { |
|
719 rt->requestDepth--; |
|
720 } else { |
|
721 rt->conservativeGC.updateForRequestEnd(); |
|
722 rt->requestDepth = 0; |
|
723 rt->triggerActivityCallback(false); |
|
724 } |
|
725 } |
|
726 #endif /* JS_THREADSAFE */ |
|
727 |
|
728 JS_PUBLIC_API(void) |
|
729 JS_BeginRequest(JSContext *cx) |
|
730 { |
|
731 #ifdef JS_THREADSAFE |
|
732 cx->outstandingRequests++; |
|
733 StartRequest(cx); |
|
734 #endif |
|
735 } |
|
736 |
|
737 JS_PUBLIC_API(void) |
|
738 JS_EndRequest(JSContext *cx) |
|
739 { |
|
740 #ifdef JS_THREADSAFE |
|
741 JS_ASSERT(cx->outstandingRequests != 0); |
|
742 cx->outstandingRequests--; |
|
743 StopRequest(cx); |
|
744 #endif |
|
745 } |
|
746 |
|
747 JS_PUBLIC_API(bool) |
|
748 JS_IsInRequest(JSRuntime *rt) |
|
749 { |
|
750 #ifdef JS_THREADSAFE |
|
751 JS_ASSERT(CurrentThreadCanAccessRuntime(rt)); |
|
752 return rt->requestDepth != 0; |
|
753 #else |
|
754 return false; |
|
755 #endif |
|
756 } |
|
757 |
|
758 JS_PUBLIC_API(void) |
|
759 JS_SetContextCallback(JSRuntime *rt, JSContextCallback cxCallback, void *data) |
|
760 { |
|
761 rt->cxCallback = cxCallback; |
|
762 rt->cxCallbackData = data; |
|
763 } |
|
764 |
|
765 JS_PUBLIC_API(JSContext *) |
|
766 JS_NewContext(JSRuntime *rt, size_t stackChunkSize) |
|
767 { |
|
768 return NewContext(rt, stackChunkSize); |
|
769 } |
|
770 |
|
771 JS_PUBLIC_API(void) |
|
772 JS_DestroyContext(JSContext *cx) |
|
773 { |
|
774 JS_ASSERT(!cx->compartment()); |
|
775 DestroyContext(cx, DCM_FORCE_GC); |
|
776 } |
|
777 |
|
778 JS_PUBLIC_API(void) |
|
779 JS_DestroyContextNoGC(JSContext *cx) |
|
780 { |
|
781 JS_ASSERT(!cx->compartment()); |
|
782 DestroyContext(cx, DCM_NO_GC); |
|
783 } |
|
784 |
|
785 JS_PUBLIC_API(void *) |
|
786 JS_GetContextPrivate(JSContext *cx) |
|
787 { |
|
788 return cx->data; |
|
789 } |
|
790 |
|
791 JS_PUBLIC_API(void) |
|
792 JS_SetContextPrivate(JSContext *cx, void *data) |
|
793 { |
|
794 cx->data = data; |
|
795 } |
|
796 |
|
797 JS_PUBLIC_API(void *) |
|
798 JS_GetSecondContextPrivate(JSContext *cx) |
|
799 { |
|
800 return cx->data2; |
|
801 } |
|
802 |
|
803 JS_PUBLIC_API(void) |
|
804 JS_SetSecondContextPrivate(JSContext *cx, void *data) |
|
805 { |
|
806 cx->data2 = data; |
|
807 } |
|
808 |
|
809 JS_PUBLIC_API(JSRuntime *) |
|
810 JS_GetRuntime(JSContext *cx) |
|
811 { |
|
812 return cx->runtime(); |
|
813 } |
|
814 |
|
815 JS_PUBLIC_API(JSRuntime *) |
|
816 JS_GetParentRuntime(JSContext *cx) |
|
817 { |
|
818 JSRuntime *rt = cx->runtime(); |
|
819 return rt->parentRuntime ? rt->parentRuntime : rt; |
|
820 } |
|
821 |
|
822 JS_PUBLIC_API(JSContext *) |
|
823 JS_ContextIterator(JSRuntime *rt, JSContext **iterp) |
|
824 { |
|
825 JSContext *cx = *iterp; |
|
826 cx = cx ? cx->getNext() : rt->contextList.getFirst(); |
|
827 *iterp = cx; |
|
828 return cx; |
|
829 } |
|
830 |
|
831 JS_PUBLIC_API(JSVersion) |
|
832 JS_GetVersion(JSContext *cx) |
|
833 { |
|
834 return VersionNumber(cx->findVersion()); |
|
835 } |
|
836 |
|
837 JS_PUBLIC_API(void) |
|
838 JS_SetVersionForCompartment(JSCompartment *compartment, JSVersion version) |
|
839 { |
|
840 compartment->options().setVersion(version); |
|
841 } |
|
842 |
|
843 static const struct v2smap { |
|
844 JSVersion version; |
|
845 const char *string; |
|
846 } v2smap[] = { |
|
847 {JSVERSION_ECMA_3, "ECMAv3"}, |
|
848 {JSVERSION_1_6, "1.6"}, |
|
849 {JSVERSION_1_7, "1.7"}, |
|
850 {JSVERSION_1_8, "1.8"}, |
|
851 {JSVERSION_ECMA_5, "ECMAv5"}, |
|
852 {JSVERSION_DEFAULT, js_default_str}, |
|
853 {JSVERSION_DEFAULT, "1.0"}, |
|
854 {JSVERSION_DEFAULT, "1.1"}, |
|
855 {JSVERSION_DEFAULT, "1.2"}, |
|
856 {JSVERSION_DEFAULT, "1.3"}, |
|
857 {JSVERSION_DEFAULT, "1.4"}, |
|
858 {JSVERSION_DEFAULT, "1.5"}, |
|
859 {JSVERSION_UNKNOWN, nullptr}, /* must be last, nullptr is sentinel */ |
|
860 }; |
|
861 |
|
862 JS_PUBLIC_API(const char *) |
|
863 JS_VersionToString(JSVersion version) |
|
864 { |
|
865 int i; |
|
866 |
|
867 for (i = 0; v2smap[i].string; i++) |
|
868 if (v2smap[i].version == version) |
|
869 return v2smap[i].string; |
|
870 return "unknown"; |
|
871 } |
|
872 |
|
873 JS_PUBLIC_API(JSVersion) |
|
874 JS_StringToVersion(const char *string) |
|
875 { |
|
876 int i; |
|
877 |
|
878 for (i = 0; v2smap[i].string; i++) |
|
879 if (strcmp(v2smap[i].string, string) == 0) |
|
880 return v2smap[i].version; |
|
881 return JSVERSION_UNKNOWN; |
|
882 } |
|
883 |
|
884 JS_PUBLIC_API(JS::RuntimeOptions &) |
|
885 JS::RuntimeOptionsRef(JSRuntime *rt) |
|
886 { |
|
887 return rt->options(); |
|
888 } |
|
889 |
|
890 JS_PUBLIC_API(JS::RuntimeOptions &) |
|
891 JS::RuntimeOptionsRef(JSContext *cx) |
|
892 { |
|
893 return cx->runtime()->options(); |
|
894 } |
|
895 |
|
896 JS_PUBLIC_API(JS::ContextOptions &) |
|
897 JS::ContextOptionsRef(JSContext *cx) |
|
898 { |
|
899 return cx->options(); |
|
900 } |
|
901 |
|
902 JS_PUBLIC_API(const char *) |
|
903 JS_GetImplementationVersion(void) |
|
904 { |
|
905 return "JavaScript-C" MOZILLA_VERSION; |
|
906 } |
|
907 |
|
908 JS_PUBLIC_API(void) |
|
909 JS_SetDestroyCompartmentCallback(JSRuntime *rt, JSDestroyCompartmentCallback callback) |
|
910 { |
|
911 rt->destroyCompartmentCallback = callback; |
|
912 } |
|
913 |
|
914 JS_PUBLIC_API(void) |
|
915 JS_SetDestroyZoneCallback(JSRuntime *rt, JSZoneCallback callback) |
|
916 { |
|
917 rt->destroyZoneCallback = callback; |
|
918 } |
|
919 |
|
920 JS_PUBLIC_API(void) |
|
921 JS_SetSweepZoneCallback(JSRuntime *rt, JSZoneCallback callback) |
|
922 { |
|
923 rt->sweepZoneCallback = callback; |
|
924 } |
|
925 |
|
926 JS_PUBLIC_API(void) |
|
927 JS_SetCompartmentNameCallback(JSRuntime *rt, JSCompartmentNameCallback callback) |
|
928 { |
|
929 rt->compartmentNameCallback = callback; |
|
930 } |
|
931 |
|
932 JS_PUBLIC_API(void) |
|
933 JS_SetWrapObjectCallbacks(JSRuntime *rt, const JSWrapObjectCallbacks *callbacks) |
|
934 { |
|
935 rt->wrapObjectCallbacks = callbacks; |
|
936 } |
|
937 |
|
938 JS_PUBLIC_API(JSCompartment *) |
|
939 JS_EnterCompartment(JSContext *cx, JSObject *target) |
|
940 { |
|
941 AssertHeapIsIdle(cx); |
|
942 CHECK_REQUEST(cx); |
|
943 |
|
944 JSCompartment *oldCompartment = cx->compartment(); |
|
945 cx->enterCompartment(target->compartment()); |
|
946 return oldCompartment; |
|
947 } |
|
948 |
|
949 JS_PUBLIC_API(JSCompartment *) |
|
950 JS_EnterCompartmentOfScript(JSContext *cx, JSScript *target) |
|
951 { |
|
952 AssertHeapIsIdle(cx); |
|
953 CHECK_REQUEST(cx); |
|
954 GlobalObject &global = target->global(); |
|
955 return JS_EnterCompartment(cx, &global); |
|
956 } |
|
957 |
|
958 JS_PUBLIC_API(void) |
|
959 JS_LeaveCompartment(JSContext *cx, JSCompartment *oldCompartment) |
|
960 { |
|
961 AssertHeapIsIdle(cx); |
|
962 CHECK_REQUEST(cx); |
|
963 cx->leaveCompartment(oldCompartment); |
|
964 } |
|
965 |
|
966 JSAutoCompartment::JSAutoCompartment(JSContext *cx, JSObject *target) |
|
967 : cx_(cx), |
|
968 oldCompartment_(cx->compartment()) |
|
969 { |
|
970 AssertHeapIsIdleOrIterating(cx_); |
|
971 cx_->enterCompartment(target->compartment()); |
|
972 } |
|
973 |
|
974 JSAutoCompartment::JSAutoCompartment(JSContext *cx, JSScript *target) |
|
975 : cx_(cx), |
|
976 oldCompartment_(cx->compartment()) |
|
977 { |
|
978 AssertHeapIsIdleOrIterating(cx_); |
|
979 cx_->enterCompartment(target->compartment()); |
|
980 } |
|
981 |
|
982 JSAutoCompartment::~JSAutoCompartment() |
|
983 { |
|
984 cx_->leaveCompartment(oldCompartment_); |
|
985 } |
|
986 |
|
987 JSAutoNullCompartment::JSAutoNullCompartment(JSContext *cx) |
|
988 : cx_(cx), |
|
989 oldCompartment_(cx->compartment()) |
|
990 { |
|
991 AssertHeapIsIdleOrIterating(cx_); |
|
992 cx_->enterNullCompartment(); |
|
993 } |
|
994 |
|
995 JSAutoNullCompartment::~JSAutoNullCompartment() |
|
996 { |
|
997 cx_->leaveCompartment(oldCompartment_); |
|
998 } |
|
999 |
|
1000 JS_PUBLIC_API(void) |
|
1001 JS_SetCompartmentPrivate(JSCompartment *compartment, void *data) |
|
1002 { |
|
1003 compartment->data = data; |
|
1004 } |
|
1005 |
|
1006 JS_PUBLIC_API(void *) |
|
1007 JS_GetCompartmentPrivate(JSCompartment *compartment) |
|
1008 { |
|
1009 return compartment->data; |
|
1010 } |
|
1011 |
|
1012 JS_PUBLIC_API(void) |
|
1013 JS_SetZoneUserData(JS::Zone *zone, void *data) |
|
1014 { |
|
1015 zone->data = data; |
|
1016 } |
|
1017 |
|
1018 JS_PUBLIC_API(void *) |
|
1019 JS_GetZoneUserData(JS::Zone *zone) |
|
1020 { |
|
1021 return zone->data; |
|
1022 } |
|
1023 |
|
1024 JS_PUBLIC_API(bool) |
|
1025 JS_WrapObject(JSContext *cx, MutableHandleObject objp) |
|
1026 { |
|
1027 AssertHeapIsIdle(cx); |
|
1028 CHECK_REQUEST(cx); |
|
1029 if (objp) |
|
1030 JS::ExposeGCThingToActiveJS(objp, JSTRACE_OBJECT); |
|
1031 return cx->compartment()->wrap(cx, objp); |
|
1032 } |
|
1033 |
|
1034 JS_PUBLIC_API(bool) |
|
1035 JS_WrapValue(JSContext *cx, MutableHandleValue vp) |
|
1036 { |
|
1037 AssertHeapIsIdle(cx); |
|
1038 CHECK_REQUEST(cx); |
|
1039 JS::ExposeValueToActiveJS(vp); |
|
1040 return cx->compartment()->wrap(cx, vp); |
|
1041 } |
|
1042 |
|
1043 JS_PUBLIC_API(bool) |
|
1044 JS_WrapId(JSContext *cx, JS::MutableHandleId idp) |
|
1045 { |
|
1046 AssertHeapIsIdle(cx); |
|
1047 CHECK_REQUEST(cx); |
|
1048 jsid id = idp.get(); |
|
1049 if (JSID_IS_STRING(id)) |
|
1050 JS::ExposeGCThingToActiveJS(JSID_TO_STRING(id), JSTRACE_STRING); |
|
1051 else if (JSID_IS_OBJECT(id)) |
|
1052 JS::ExposeGCThingToActiveJS(JSID_TO_OBJECT(id), JSTRACE_OBJECT); |
|
1053 return cx->compartment()->wrapId(cx, idp.address()); |
|
1054 } |
|
1055 |
|
1056 /* |
|
1057 * Identity remapping. Not for casual consumers. |
|
1058 * |
|
1059 * Normally, an object's contents and its identity are inextricably linked. |
|
1060 * Identity is determined by the address of the JSObject* in the heap, and |
|
1061 * the contents are what is located at that address. Transplanting allows these |
|
1062 * concepts to be separated through a combination of swapping (exchanging the |
|
1063 * contents of two same-compartment objects) and remapping cross-compartment |
|
1064 * identities by altering wrappers. |
|
1065 * |
|
1066 * The |origobj| argument should be the object whose identity needs to be |
|
1067 * remapped, usually to another compartment. The contents of |origobj| are |
|
1068 * destroyed. |
|
1069 * |
|
1070 * The |target| argument serves two purposes: |
|
1071 * |
|
1072 * First, |target| serves as a hint for the new identity of the object. The new |
|
1073 * identity object will always be in the same compartment as |target|, but |
|
1074 * if that compartment already had an object representing |origobj| (either a |
|
1075 * cross-compartment wrapper for it, or |origobj| itself if the two arguments |
|
1076 * are same-compartment), the existing object is used. Otherwise, |target| |
|
1077 * itself is used. To avoid ambiguity, JS_TransplantObject always returns the |
|
1078 * new identity. |
|
1079 * |
|
1080 * Second, the new identity object's contents will be those of |target|. A swap() |
|
1081 * is used to make this happen if an object other than |target| is used. |
|
1082 * |
|
1083 * We don't have a good way to recover from failure in this function, so |
|
1084 * we intentionally crash instead. |
|
1085 */ |
|
1086 |
|
1087 JS_PUBLIC_API(JSObject *) |
|
1088 JS_TransplantObject(JSContext *cx, HandleObject origobj, HandleObject target) |
|
1089 { |
|
1090 AssertHeapIsIdle(cx); |
|
1091 JS_ASSERT(origobj != target); |
|
1092 JS_ASSERT(!origobj->is<CrossCompartmentWrapperObject>()); |
|
1093 JS_ASSERT(!target->is<CrossCompartmentWrapperObject>()); |
|
1094 |
|
1095 RootedValue origv(cx, ObjectValue(*origobj)); |
|
1096 RootedObject newIdentity(cx); |
|
1097 |
|
1098 { |
|
1099 // Scope to make ~AutoMaybeTouchDeadZones do its GC before the return value is on the stack. |
|
1100 AutoMaybeTouchDeadZones agc(cx); |
|
1101 AutoDisableProxyCheck adpc(cx->runtime()); |
|
1102 |
|
1103 JSCompartment *destination = target->compartment(); |
|
1104 |
|
1105 if (origobj->compartment() == destination) { |
|
1106 // If the original object is in the same compartment as the |
|
1107 // destination, then we know that we won't find a wrapper in the |
|
1108 // destination's cross compartment map and that the same |
|
1109 // object will continue to work. |
|
1110 if (!JSObject::swap(cx, origobj, target)) |
|
1111 MOZ_CRASH(); |
|
1112 newIdentity = origobj; |
|
1113 } else if (WrapperMap::Ptr p = destination->lookupWrapper(origv)) { |
|
1114 // There might already be a wrapper for the original object in |
|
1115 // the new compartment. If there is, we use its identity and swap |
|
1116 // in the contents of |target|. |
|
1117 newIdentity = &p->value().toObject(); |
|
1118 |
|
1119 // When we remove origv from the wrapper map, its wrapper, newIdentity, |
|
1120 // must immediately cease to be a cross-compartment wrapper. Neuter it. |
|
1121 destination->removeWrapper(p); |
|
1122 NukeCrossCompartmentWrapper(cx, newIdentity); |
|
1123 |
|
1124 if (!JSObject::swap(cx, newIdentity, target)) |
|
1125 MOZ_CRASH(); |
|
1126 } else { |
|
1127 // Otherwise, we use |target| for the new identity object. |
|
1128 newIdentity = target; |
|
1129 } |
|
1130 |
|
1131 // Now, iterate through other scopes looking for references to the |
|
1132 // old object, and update the relevant cross-compartment wrappers. |
|
1133 if (!RemapAllWrappersForObject(cx, origobj, newIdentity)) |
|
1134 MOZ_CRASH(); |
|
1135 |
|
1136 // Lastly, update the original object to point to the new one. |
|
1137 if (origobj->compartment() != destination) { |
|
1138 RootedObject newIdentityWrapper(cx, newIdentity); |
|
1139 AutoCompartment ac(cx, origobj); |
|
1140 if (!JS_WrapObject(cx, &newIdentityWrapper)) |
|
1141 MOZ_CRASH(); |
|
1142 JS_ASSERT(Wrapper::wrappedObject(newIdentityWrapper) == newIdentity); |
|
1143 if (!JSObject::swap(cx, origobj, newIdentityWrapper)) |
|
1144 MOZ_CRASH(); |
|
1145 origobj->compartment()->putWrapper(cx, ObjectValue(*newIdentity), origv); |
|
1146 } |
|
1147 } |
|
1148 |
|
1149 // The new identity object might be one of several things. Return it to avoid |
|
1150 // ambiguity. |
|
1151 return newIdentity; |
|
1152 } |
|
1153 |
|
1154 /* |
|
1155 * Recompute all cross-compartment wrappers for an object, resetting state. |
|
1156 * Gecko uses this to clear Xray wrappers when doing a navigation that reuses |
|
1157 * the inner window and global object. |
|
1158 */ |
|
1159 JS_PUBLIC_API(bool) |
|
1160 JS_RefreshCrossCompartmentWrappers(JSContext *cx, HandleObject obj) |
|
1161 { |
|
1162 return RemapAllWrappersForObject(cx, obj, obj); |
|
1163 } |
|
1164 |
|
1165 JS_PUBLIC_API(bool) |
|
1166 JS_InitStandardClasses(JSContext *cx, HandleObject obj) |
|
1167 { |
|
1168 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); |
|
1169 AssertHeapIsIdle(cx); |
|
1170 CHECK_REQUEST(cx); |
|
1171 |
|
1172 cx->setDefaultCompartmentObjectIfUnset(obj); |
|
1173 assertSameCompartment(cx, obj); |
|
1174 |
|
1175 Rooted<GlobalObject*> global(cx, &obj->global()); |
|
1176 return GlobalObject::initStandardClasses(cx, global); |
|
1177 } |
|
1178 |
|
1179 #define CLASP(name) (&name##Class) |
|
1180 #define OCLASP(name) (&name##Object::class_) |
|
1181 #define TYPED_ARRAY_CLASP(type) (&TypedArrayObject::classes[ScalarTypeDescr::type]) |
|
1182 #define EAGER_ATOM(name) NAME_OFFSET(name) |
|
1183 #define EAGER_CLASS_ATOM(name) NAME_OFFSET(name) |
|
1184 |
|
1185 static js::Class DummyClass; |
|
1186 static js::Class SentinelClass; |
|
1187 |
|
1188 typedef struct JSStdName { |
|
1189 size_t atomOffset; /* offset of atom pointer in JSAtomState */ |
|
1190 const Class *clasp; |
|
1191 bool isDummy() const { return clasp == &DummyClass; }; |
|
1192 bool isSentinel() const { return clasp == &SentinelClass; }; |
|
1193 } JSStdName; |
|
1194 |
|
1195 static const JSStdName* |
|
1196 LookupStdName(JSRuntime *rt, HandleString name, const JSStdName *table) |
|
1197 { |
|
1198 MOZ_ASSERT(name->isAtom()); |
|
1199 for (unsigned i = 0; !table[i].isSentinel(); i++) { |
|
1200 if (table[i].isDummy()) |
|
1201 continue; |
|
1202 JSAtom *atom = AtomStateOffsetToName(*rt->commonNames, table[i].atomOffset); |
|
1203 MOZ_ASSERT(atom); |
|
1204 if (name == atom) |
|
1205 return &table[i]; |
|
1206 } |
|
1207 |
|
1208 return nullptr; |
|
1209 } |
|
1210 |
|
1211 /* |
|
1212 * Table of standard classes, indexed by JSProtoKey. For entries where the |
|
1213 * JSProtoKey does not correspond to a class with a meaningful constructor, we |
|
1214 * insert a null entry into the table. |
|
1215 */ |
|
1216 #define STD_NAME_ENTRY(name, code, init, clasp) { EAGER_CLASS_ATOM(name), clasp }, |
|
1217 #define STD_DUMMY_ENTRY(name, code, init, dummy) { 0, &DummyClass }, |
|
1218 static const JSStdName standard_class_names[] = { |
|
1219 JS_FOR_PROTOTYPES(STD_NAME_ENTRY, STD_DUMMY_ENTRY) |
|
1220 { 0, &SentinelClass } |
|
1221 }; |
|
1222 |
|
1223 /* |
|
1224 * Table of top-level function and constant names and the init function of the |
|
1225 * corresponding standard class that sets them up. |
|
1226 */ |
|
1227 static const JSStdName builtin_property_names[] = { |
|
1228 { EAGER_ATOM(eval), &JSObject::class_ }, |
|
1229 |
|
1230 /* Global properties and functions defined by the Number class. */ |
|
1231 { EAGER_ATOM(NaN), OCLASP(Number) }, |
|
1232 { EAGER_ATOM(Infinity), OCLASP(Number) }, |
|
1233 { EAGER_ATOM(isNaN), OCLASP(Number) }, |
|
1234 { EAGER_ATOM(isFinite), OCLASP(Number) }, |
|
1235 { EAGER_ATOM(parseFloat), OCLASP(Number) }, |
|
1236 { EAGER_ATOM(parseInt), OCLASP(Number) }, |
|
1237 |
|
1238 /* String global functions. */ |
|
1239 { EAGER_ATOM(escape), OCLASP(String) }, |
|
1240 { EAGER_ATOM(unescape), OCLASP(String) }, |
|
1241 { EAGER_ATOM(decodeURI), OCLASP(String) }, |
|
1242 { EAGER_ATOM(encodeURI), OCLASP(String) }, |
|
1243 { EAGER_ATOM(decodeURIComponent), OCLASP(String) }, |
|
1244 { EAGER_ATOM(encodeURIComponent), OCLASP(String) }, |
|
1245 #if JS_HAS_UNEVAL |
|
1246 { EAGER_ATOM(uneval), OCLASP(String) }, |
|
1247 #endif |
|
1248 #ifdef ENABLE_BINARYDATA |
|
1249 { EAGER_ATOM(SIMD), OCLASP(SIMD) }, |
|
1250 { EAGER_ATOM(TypedObject), OCLASP(TypedObjectModule) }, |
|
1251 #endif |
|
1252 |
|
1253 { 0, &SentinelClass } |
|
1254 }; |
|
1255 |
|
1256 #undef CLASP |
|
1257 #undef TYPED_ARRAY_CLASP |
|
1258 #undef EAGER_ATOM |
|
1259 #undef EAGER_CLASS_ATOM |
|
1260 #undef EAGER_ATOM_CLASP |
|
1261 |
|
1262 JS_PUBLIC_API(bool) |
|
1263 JS_ResolveStandardClass(JSContext *cx, HandleObject obj, HandleId id, bool *resolved) |
|
1264 { |
|
1265 JSRuntime *rt; |
|
1266 const JSStdName *stdnm; |
|
1267 |
|
1268 AssertHeapIsIdle(cx); |
|
1269 CHECK_REQUEST(cx); |
|
1270 assertSameCompartment(cx, obj, id); |
|
1271 |
|
1272 Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>()); |
|
1273 *resolved = false; |
|
1274 |
|
1275 rt = cx->runtime(); |
|
1276 if (!rt->hasContexts() || !JSID_IS_ATOM(id)) |
|
1277 return true; |
|
1278 |
|
1279 RootedString idstr(cx, JSID_TO_STRING(id)); |
|
1280 |
|
1281 /* Check whether we're resolving 'undefined', and define it if so. */ |
|
1282 JSAtom *undefinedAtom = cx->names().undefined; |
|
1283 if (idstr == undefinedAtom) { |
|
1284 *resolved = true; |
|
1285 return JSObject::defineProperty(cx, obj, undefinedAtom->asPropertyName(), |
|
1286 UndefinedHandleValue, |
|
1287 JS_PropertyStub, JS_StrictPropertyStub, |
|
1288 JSPROP_PERMANENT | JSPROP_READONLY); |
|
1289 } |
|
1290 |
|
1291 /* Try for class constructors/prototypes named by well-known atoms. */ |
|
1292 stdnm = LookupStdName(rt, idstr, standard_class_names); |
|
1293 |
|
1294 /* Try less frequently used top-level functions and constants. */ |
|
1295 if (!stdnm) |
|
1296 stdnm = LookupStdName(rt, idstr, builtin_property_names); |
|
1297 |
|
1298 // If this class is anonymous, then it doesn't exist as a global |
|
1299 // property, so we won't resolve anything. |
|
1300 if (stdnm && !(stdnm->clasp->flags & JSCLASS_IS_ANONYMOUS)) { |
|
1301 JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(stdnm->clasp); |
|
1302 if (!GlobalObject::ensureConstructor(cx, global, key)) |
|
1303 return false; |
|
1304 |
|
1305 *resolved = true; |
|
1306 return true; |
|
1307 } |
|
1308 |
|
1309 // There is no such property to resolve. An ordinary resolve hook would |
|
1310 // just return true at this point. But the global object is special in one |
|
1311 // more way: its prototype chain is lazily initialized. That is, |
|
1312 // global->getProto() might be null right now because we haven't created |
|
1313 // Object.prototype yet. Force it now. |
|
1314 if (!global->getOrCreateObjectPrototype(cx)) |
|
1315 return false; |
|
1316 |
|
1317 return true; |
|
1318 } |
|
1319 |
|
1320 JS_PUBLIC_API(bool) |
|
1321 JS_EnumerateStandardClasses(JSContext *cx, HandleObject obj) |
|
1322 { |
|
1323 AssertHeapIsIdle(cx); |
|
1324 CHECK_REQUEST(cx); |
|
1325 assertSameCompartment(cx, obj); |
|
1326 MOZ_ASSERT(obj->is<GlobalObject>()); |
|
1327 Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>()); |
|
1328 return GlobalObject::initStandardClasses(cx, global); |
|
1329 } |
|
1330 |
|
1331 JS_PUBLIC_API(bool) |
|
1332 JS_GetClassObject(JSContext *cx, JSProtoKey key, MutableHandleObject objp) |
|
1333 { |
|
1334 AssertHeapIsIdle(cx); |
|
1335 CHECK_REQUEST(cx); |
|
1336 return GetBuiltinConstructor(cx, key, objp); |
|
1337 } |
|
1338 |
|
1339 JS_PUBLIC_API(bool) |
|
1340 JS_GetClassPrototype(JSContext *cx, JSProtoKey key, MutableHandleObject objp) |
|
1341 { |
|
1342 AssertHeapIsIdle(cx); |
|
1343 CHECK_REQUEST(cx); |
|
1344 return GetBuiltinPrototype(cx, key, objp); |
|
1345 } |
|
1346 |
|
1347 JS_PUBLIC_API(JSProtoKey) |
|
1348 JS_IdToProtoKey(JSContext *cx, HandleId id) |
|
1349 { |
|
1350 AssertHeapIsIdle(cx); |
|
1351 CHECK_REQUEST(cx); |
|
1352 |
|
1353 if (!JSID_IS_ATOM(id)) |
|
1354 return JSProto_Null; |
|
1355 RootedString idstr(cx, JSID_TO_STRING(id)); |
|
1356 const JSStdName *stdnm = LookupStdName(cx->runtime(), idstr, standard_class_names); |
|
1357 if (!stdnm) |
|
1358 return JSProto_Null; |
|
1359 |
|
1360 MOZ_ASSERT(MOZ_ARRAY_LENGTH(standard_class_names) == JSProto_LIMIT + 1); |
|
1361 return static_cast<JSProtoKey>(stdnm - standard_class_names); |
|
1362 } |
|
1363 |
|
1364 JS_PUBLIC_API(JSObject *) |
|
1365 JS_GetObjectPrototype(JSContext *cx, HandleObject forObj) |
|
1366 { |
|
1367 CHECK_REQUEST(cx); |
|
1368 assertSameCompartment(cx, forObj); |
|
1369 return forObj->global().getOrCreateObjectPrototype(cx); |
|
1370 } |
|
1371 |
|
1372 JS_PUBLIC_API(JSObject *) |
|
1373 JS_GetFunctionPrototype(JSContext *cx, HandleObject forObj) |
|
1374 { |
|
1375 CHECK_REQUEST(cx); |
|
1376 assertSameCompartment(cx, forObj); |
|
1377 return forObj->global().getOrCreateFunctionPrototype(cx); |
|
1378 } |
|
1379 |
|
1380 JS_PUBLIC_API(JSObject *) |
|
1381 JS_GetArrayPrototype(JSContext *cx, HandleObject forObj) |
|
1382 { |
|
1383 CHECK_REQUEST(cx); |
|
1384 assertSameCompartment(cx, forObj); |
|
1385 Rooted<GlobalObject*> global(cx, &forObj->global()); |
|
1386 return GlobalObject::getOrCreateArrayPrototype(cx, global); |
|
1387 } |
|
1388 |
|
1389 JS_PUBLIC_API(JSObject *) |
|
1390 JS_GetGlobalForObject(JSContext *cx, JSObject *obj) |
|
1391 { |
|
1392 AssertHeapIsIdle(cx); |
|
1393 assertSameCompartment(cx, obj); |
|
1394 return &obj->global(); |
|
1395 } |
|
1396 |
|
1397 extern JS_PUBLIC_API(bool) |
|
1398 JS_IsGlobalObject(JSObject *obj) |
|
1399 { |
|
1400 return obj->is<GlobalObject>(); |
|
1401 } |
|
1402 |
|
1403 JS_PUBLIC_API(JSObject *) |
|
1404 JS_GetGlobalForCompartmentOrNull(JSContext *cx, JSCompartment *c) |
|
1405 { |
|
1406 AssertHeapIsIdleOrIterating(cx); |
|
1407 assertSameCompartment(cx, c); |
|
1408 return c->maybeGlobal(); |
|
1409 } |
|
1410 |
|
1411 JS_PUBLIC_API(JSObject *) |
|
1412 JS::CurrentGlobalOrNull(JSContext *cx) |
|
1413 { |
|
1414 AssertHeapIsIdleOrIterating(cx); |
|
1415 CHECK_REQUEST(cx); |
|
1416 if (!cx->compartment()) |
|
1417 return nullptr; |
|
1418 return cx->global(); |
|
1419 } |
|
1420 |
|
1421 JS_PUBLIC_API(jsval) |
|
1422 JS_ComputeThis(JSContext *cx, jsval *vp) |
|
1423 { |
|
1424 AssertHeapIsIdle(cx); |
|
1425 assertSameCompartment(cx, JSValueArray(vp, 2)); |
|
1426 CallReceiver call = CallReceiverFromVp(vp); |
|
1427 if (!BoxNonStrictThis(cx, call)) |
|
1428 return JSVAL_NULL; |
|
1429 return call.thisv(); |
|
1430 } |
|
1431 |
|
1432 JS_PUBLIC_API(void *) |
|
1433 JS_malloc(JSContext *cx, size_t nbytes) |
|
1434 { |
|
1435 AssertHeapIsIdle(cx); |
|
1436 CHECK_REQUEST(cx); |
|
1437 return cx->malloc_(nbytes); |
|
1438 } |
|
1439 |
|
1440 JS_PUBLIC_API(void *) |
|
1441 JS_realloc(JSContext *cx, void *p, size_t nbytes) |
|
1442 { |
|
1443 AssertHeapIsIdle(cx); |
|
1444 CHECK_REQUEST(cx); |
|
1445 return cx->realloc_(p, nbytes); |
|
1446 } |
|
1447 |
|
1448 JS_PUBLIC_API(void) |
|
1449 JS_free(JSContext *cx, void *p) |
|
1450 { |
|
1451 return js_free(p); |
|
1452 } |
|
1453 |
|
1454 JS_PUBLIC_API(void) |
|
1455 JS_freeop(JSFreeOp *fop, void *p) |
|
1456 { |
|
1457 return FreeOp::get(fop)->free_(p); |
|
1458 } |
|
1459 |
|
1460 JS_PUBLIC_API(JSFreeOp *) |
|
1461 JS_GetDefaultFreeOp(JSRuntime *rt) |
|
1462 { |
|
1463 return rt->defaultFreeOp(); |
|
1464 } |
|
1465 |
|
1466 JS_PUBLIC_API(void) |
|
1467 JS_updateMallocCounter(JSContext *cx, size_t nbytes) |
|
1468 { |
|
1469 return cx->runtime()->updateMallocCounter(cx->zone(), nbytes); |
|
1470 } |
|
1471 |
|
1472 JS_PUBLIC_API(char *) |
|
1473 JS_strdup(JSContext *cx, const char *s) |
|
1474 { |
|
1475 AssertHeapIsIdle(cx); |
|
1476 return js_strdup(cx, s); |
|
1477 } |
|
1478 |
|
1479 JS_PUBLIC_API(char *) |
|
1480 JS_strdup(JSRuntime *rt, const char *s) |
|
1481 { |
|
1482 AssertHeapIsIdle(rt); |
|
1483 size_t n = strlen(s) + 1; |
|
1484 void *p = rt->malloc_(n); |
|
1485 if (!p) |
|
1486 return nullptr; |
|
1487 return static_cast<char*>(js_memcpy(p, s, n)); |
|
1488 } |
|
1489 |
|
1490 #undef JS_AddRoot |
|
1491 |
|
1492 JS_PUBLIC_API(bool) |
|
1493 JS::AddValueRoot(JSContext *cx, JS::Heap<JS::Value> *vp) |
|
1494 { |
|
1495 AssertHeapIsIdle(cx); |
|
1496 CHECK_REQUEST(cx); |
|
1497 return AddValueRoot(cx, vp->unsafeGet(), nullptr); |
|
1498 } |
|
1499 |
|
1500 JS_PUBLIC_API(bool) |
|
1501 JS::AddStringRoot(JSContext *cx, JS::Heap<JSString *> *rp) |
|
1502 { |
|
1503 AssertHeapIsIdle(cx); |
|
1504 CHECK_REQUEST(cx); |
|
1505 return AddStringRoot(cx, rp->unsafeGet(), nullptr); |
|
1506 } |
|
1507 |
|
1508 JS_PUBLIC_API(bool) |
|
1509 JS::AddObjectRoot(JSContext *cx, JS::Heap<JSObject *> *rp) |
|
1510 { |
|
1511 AssertHeapIsIdle(cx); |
|
1512 CHECK_REQUEST(cx); |
|
1513 return AddObjectRoot(cx, rp->unsafeGet(), nullptr); |
|
1514 } |
|
1515 |
|
1516 JS_PUBLIC_API(bool) |
|
1517 JS::AddNamedValueRoot(JSContext *cx, JS::Heap<JS::Value> *vp, const char *name) |
|
1518 { |
|
1519 AssertHeapIsIdle(cx); |
|
1520 CHECK_REQUEST(cx); |
|
1521 return AddValueRoot(cx, vp->unsafeGet(), name); |
|
1522 } |
|
1523 |
|
1524 JS_PUBLIC_API(bool) |
|
1525 JS::AddNamedValueRootRT(JSRuntime *rt, JS::Heap<JS::Value> *vp, const char *name) |
|
1526 { |
|
1527 return AddValueRootRT(rt, vp->unsafeGet(), name); |
|
1528 } |
|
1529 |
|
1530 JS_PUBLIC_API(bool) |
|
1531 JS::AddNamedStringRoot(JSContext *cx, JS::Heap<JSString *> *rp, const char *name) |
|
1532 { |
|
1533 AssertHeapIsIdle(cx); |
|
1534 CHECK_REQUEST(cx); |
|
1535 return AddStringRoot(cx, rp->unsafeGet(), name); |
|
1536 } |
|
1537 |
|
1538 JS_PUBLIC_API(bool) |
|
1539 JS::AddNamedObjectRoot(JSContext *cx, JS::Heap<JSObject *> *rp, const char *name) |
|
1540 { |
|
1541 AssertHeapIsIdle(cx); |
|
1542 CHECK_REQUEST(cx); |
|
1543 return AddObjectRoot(cx, rp->unsafeGet(), name); |
|
1544 } |
|
1545 |
|
1546 JS_PUBLIC_API(bool) |
|
1547 JS::AddNamedScriptRoot(JSContext *cx, JS::Heap<JSScript *> *rp, const char *name) |
|
1548 { |
|
1549 AssertHeapIsIdle(cx); |
|
1550 CHECK_REQUEST(cx); |
|
1551 return AddScriptRoot(cx, rp->unsafeGet(), name); |
|
1552 } |
|
1553 |
|
1554 /* We allow unrooting from finalizers within the GC */ |
|
1555 |
|
1556 JS_PUBLIC_API(void) |
|
1557 JS::RemoveValueRoot(JSContext *cx, JS::Heap<JS::Value> *vp) |
|
1558 { |
|
1559 CHECK_REQUEST(cx); |
|
1560 RemoveRoot(cx->runtime(), (void *)vp); |
|
1561 *vp = UndefinedValue(); |
|
1562 } |
|
1563 |
|
1564 JS_PUBLIC_API(void) |
|
1565 JS::RemoveStringRoot(JSContext *cx, JS::Heap<JSString *> *rp) |
|
1566 { |
|
1567 CHECK_REQUEST(cx); |
|
1568 RemoveRoot(cx->runtime(), (void *)rp); |
|
1569 *rp = nullptr; |
|
1570 } |
|
1571 |
|
1572 JS_PUBLIC_API(void) |
|
1573 JS::RemoveObjectRoot(JSContext *cx, JS::Heap<JSObject *> *rp) |
|
1574 { |
|
1575 CHECK_REQUEST(cx); |
|
1576 RemoveRoot(cx->runtime(), (void *)rp); |
|
1577 *rp = nullptr; |
|
1578 } |
|
1579 |
|
1580 JS_PUBLIC_API(void) |
|
1581 JS::RemoveScriptRoot(JSContext *cx, JS::Heap<JSScript *> *rp) |
|
1582 { |
|
1583 CHECK_REQUEST(cx); |
|
1584 RemoveRoot(cx->runtime(), (void *)rp); |
|
1585 *rp = nullptr; |
|
1586 } |
|
1587 |
|
1588 JS_PUBLIC_API(void) |
|
1589 JS::RemoveValueRootRT(JSRuntime *rt, JS::Heap<JS::Value> *vp) |
|
1590 { |
|
1591 RemoveRoot(rt, (void *)vp); |
|
1592 *vp = UndefinedValue(); |
|
1593 } |
|
1594 |
|
1595 JS_PUBLIC_API(void) |
|
1596 JS::RemoveStringRootRT(JSRuntime *rt, JS::Heap<JSString *> *rp) |
|
1597 { |
|
1598 RemoveRoot(rt, (void *)rp); |
|
1599 *rp = nullptr; |
|
1600 } |
|
1601 |
|
1602 JS_PUBLIC_API(void) |
|
1603 JS::RemoveObjectRootRT(JSRuntime *rt, JS::Heap<JSObject *> *rp) |
|
1604 { |
|
1605 RemoveRoot(rt, (void *)rp); |
|
1606 *rp = nullptr; |
|
1607 } |
|
1608 |
|
1609 JS_PUBLIC_API(void) |
|
1610 JS::RemoveScriptRootRT(JSRuntime *rt, JS::Heap<JSScript *> *rp) |
|
1611 { |
|
1612 RemoveRoot(rt, (void *)rp); |
|
1613 *rp = nullptr; |
|
1614 } |
|
1615 |
|
1616 JS_PUBLIC_API(bool) |
|
1617 JS_AddExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data) |
|
1618 { |
|
1619 AssertHeapIsIdle(rt); |
|
1620 return !!rt->gcBlackRootTracers.append(JSRuntime::ExtraTracer(traceOp, data)); |
|
1621 } |
|
1622 |
|
1623 JS_PUBLIC_API(void) |
|
1624 JS_RemoveExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data) |
|
1625 { |
|
1626 AssertHeapIsIdle(rt); |
|
1627 for (size_t i = 0; i < rt->gcBlackRootTracers.length(); i++) { |
|
1628 JSRuntime::ExtraTracer *e = &rt->gcBlackRootTracers[i]; |
|
1629 if (e->op == traceOp && e->data == data) { |
|
1630 rt->gcBlackRootTracers.erase(e); |
|
1631 break; |
|
1632 } |
|
1633 } |
|
1634 } |
|
1635 |
|
1636 #ifdef DEBUG |
|
1637 |
|
1638 typedef struct JSHeapDumpNode JSHeapDumpNode; |
|
1639 |
|
1640 struct JSHeapDumpNode { |
|
1641 void *thing; |
|
1642 JSGCTraceKind kind; |
|
1643 JSHeapDumpNode *next; /* next sibling */ |
|
1644 JSHeapDumpNode *parent; /* node with the thing that refer to thing |
|
1645 from this node */ |
|
1646 char edgeName[1]; /* name of the edge from parent->thing |
|
1647 into thing */ |
|
1648 }; |
|
1649 |
|
1650 typedef HashSet<void *, PointerHasher<void *, 3>, SystemAllocPolicy> VisitedSet; |
|
1651 |
|
1652 class DumpingTracer |
|
1653 { |
|
1654 public: |
|
1655 DumpingTracer(JSRuntime *rt, JSTraceCallback callback) |
|
1656 : base(rt, callback) |
|
1657 {} |
|
1658 |
|
1659 JSTracer base; |
|
1660 VisitedSet visited; |
|
1661 bool ok; |
|
1662 void *startThing; |
|
1663 void *thingToFind; |
|
1664 void *thingToIgnore; |
|
1665 JSHeapDumpNode *parentNode; |
|
1666 JSHeapDumpNode **lastNodep; |
|
1667 char buffer[200]; |
|
1668 }; |
|
1669 |
|
1670 static void |
|
1671 DumpNotify(JSTracer *trc, void **thingp, JSGCTraceKind kind) |
|
1672 { |
|
1673 JS_ASSERT(trc->callback == DumpNotify); |
|
1674 |
|
1675 DumpingTracer *dtrc = (DumpingTracer *)trc; |
|
1676 void *thing = *thingp; |
|
1677 |
|
1678 if (!dtrc->ok || thing == dtrc->thingToIgnore) |
|
1679 return; |
|
1680 |
|
1681 /* |
|
1682 * Check if we have already seen thing unless it is thingToFind to include |
|
1683 * it to the graph each time we reach it and print all live things that |
|
1684 * refer to thingToFind. |
|
1685 * |
|
1686 * This does not print all possible paths leading to thingToFind since |
|
1687 * when a thing A refers directly or indirectly to thingToFind and A is |
|
1688 * present several times in the graph, we will print only the first path |
|
1689 * leading to A and thingToFind, other ways to reach A will be ignored. |
|
1690 */ |
|
1691 if (dtrc->thingToFind != thing) { |
|
1692 /* |
|
1693 * The startThing check allows to avoid putting startThing into the |
|
1694 * hash table before tracing startThing in JS_DumpHeap. |
|
1695 */ |
|
1696 if (thing == dtrc->startThing) |
|
1697 return; |
|
1698 VisitedSet::AddPtr p = dtrc->visited.lookupForAdd(thing); |
|
1699 if (p) |
|
1700 return; |
|
1701 if (!dtrc->visited.add(p, thing)) { |
|
1702 dtrc->ok = false; |
|
1703 return; |
|
1704 } |
|
1705 } |
|
1706 |
|
1707 const char *edgeName = dtrc->base.getTracingEdgeName(dtrc->buffer, sizeof(dtrc->buffer)); |
|
1708 size_t edgeNameSize = strlen(edgeName) + 1; |
|
1709 size_t bytes = offsetof(JSHeapDumpNode, edgeName) + edgeNameSize; |
|
1710 JSHeapDumpNode *node = (JSHeapDumpNode *) js_malloc(bytes); |
|
1711 if (!node) { |
|
1712 dtrc->ok = false; |
|
1713 return; |
|
1714 } |
|
1715 |
|
1716 node->thing = thing; |
|
1717 node->kind = kind; |
|
1718 node->next = nullptr; |
|
1719 node->parent = dtrc->parentNode; |
|
1720 js_memcpy(node->edgeName, edgeName, edgeNameSize); |
|
1721 |
|
1722 JS_ASSERT(!*dtrc->lastNodep); |
|
1723 *dtrc->lastNodep = node; |
|
1724 dtrc->lastNodep = &node->next; |
|
1725 } |
|
1726 |
|
1727 /* Dump node and the chain that leads to thing it contains. */ |
|
1728 static bool |
|
1729 DumpNode(DumpingTracer *dtrc, FILE* fp, JSHeapDumpNode *node) |
|
1730 { |
|
1731 JSHeapDumpNode *prev, *following; |
|
1732 size_t chainLimit; |
|
1733 enum { MAX_PARENTS_TO_PRINT = 10 }; |
|
1734 |
|
1735 JS_GetTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer, |
|
1736 &dtrc->base, node->thing, node->kind, true); |
|
1737 if (fprintf(fp, "%p %-22s via ", node->thing, dtrc->buffer) < 0) |
|
1738 return false; |
|
1739 |
|
1740 /* |
|
1741 * We need to print the parent chain in the reverse order. To do it in |
|
1742 * O(N) time where N is the chain length we first reverse the chain while |
|
1743 * searching for the top and then print each node while restoring the |
|
1744 * chain order. |
|
1745 */ |
|
1746 chainLimit = MAX_PARENTS_TO_PRINT; |
|
1747 prev = nullptr; |
|
1748 for (;;) { |
|
1749 following = node->parent; |
|
1750 node->parent = prev; |
|
1751 prev = node; |
|
1752 node = following; |
|
1753 if (!node) |
|
1754 break; |
|
1755 if (chainLimit == 0) { |
|
1756 if (fputs("...", fp) < 0) |
|
1757 return false; |
|
1758 break; |
|
1759 } |
|
1760 --chainLimit; |
|
1761 } |
|
1762 |
|
1763 node = prev; |
|
1764 prev = following; |
|
1765 bool ok = true; |
|
1766 do { |
|
1767 /* Loop must continue even when !ok to restore the parent chain. */ |
|
1768 if (ok) { |
|
1769 if (!prev) { |
|
1770 /* Print edge from some runtime root or startThing. */ |
|
1771 if (fputs(node->edgeName, fp) < 0) |
|
1772 ok = false; |
|
1773 } else { |
|
1774 JS_GetTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer, |
|
1775 &dtrc->base, prev->thing, prev->kind, |
|
1776 false); |
|
1777 if (fprintf(fp, "(%p %s).%s", |
|
1778 prev->thing, dtrc->buffer, node->edgeName) < 0) { |
|
1779 ok = false; |
|
1780 } |
|
1781 } |
|
1782 } |
|
1783 following = node->parent; |
|
1784 node->parent = prev; |
|
1785 prev = node; |
|
1786 node = following; |
|
1787 } while (node); |
|
1788 |
|
1789 return ok && putc('\n', fp) >= 0; |
|
1790 } |
|
1791 |
|
1792 JS_PUBLIC_API(bool) |
|
1793 JS_DumpHeap(JSRuntime *rt, FILE *fp, void* startThing, JSGCTraceKind startKind, |
|
1794 void *thingToFind, size_t maxDepth, void *thingToIgnore) |
|
1795 { |
|
1796 if (maxDepth == 0) |
|
1797 return true; |
|
1798 |
|
1799 DumpingTracer dtrc(rt, DumpNotify); |
|
1800 if (!dtrc.visited.init()) |
|
1801 return false; |
|
1802 dtrc.ok = true; |
|
1803 dtrc.startThing = startThing; |
|
1804 dtrc.thingToFind = thingToFind; |
|
1805 dtrc.thingToIgnore = thingToIgnore; |
|
1806 dtrc.parentNode = nullptr; |
|
1807 JSHeapDumpNode *node = nullptr; |
|
1808 dtrc.lastNodep = &node; |
|
1809 if (!startThing) { |
|
1810 JS_ASSERT(startKind == JSTRACE_OBJECT); |
|
1811 TraceRuntime(&dtrc.base); |
|
1812 } else { |
|
1813 JS_TraceChildren(&dtrc.base, startThing, startKind); |
|
1814 } |
|
1815 |
|
1816 if (!node) |
|
1817 return dtrc.ok; |
|
1818 |
|
1819 size_t depth = 1; |
|
1820 JSHeapDumpNode *children, *next, *parent; |
|
1821 bool thingToFindWasTraced = thingToFind && thingToFind == startThing; |
|
1822 for (;;) { |
|
1823 /* |
|
1824 * Loop must continue even when !dtrc.ok to free all nodes allocated |
|
1825 * so far. |
|
1826 */ |
|
1827 if (dtrc.ok) { |
|
1828 if (thingToFind == nullptr || thingToFind == node->thing) |
|
1829 dtrc.ok = DumpNode(&dtrc, fp, node); |
|
1830 |
|
1831 /* Descend into children. */ |
|
1832 if (dtrc.ok && |
|
1833 depth < maxDepth && |
|
1834 (thingToFind != node->thing || !thingToFindWasTraced)) { |
|
1835 dtrc.parentNode = node; |
|
1836 children = nullptr; |
|
1837 dtrc.lastNodep = &children; |
|
1838 JS_TraceChildren(&dtrc.base, node->thing, node->kind); |
|
1839 if (thingToFind == node->thing) |
|
1840 thingToFindWasTraced = true; |
|
1841 if (children != nullptr) { |
|
1842 ++depth; |
|
1843 node = children; |
|
1844 continue; |
|
1845 } |
|
1846 } |
|
1847 } |
|
1848 |
|
1849 /* Move to next or parents next and free the node. */ |
|
1850 for (;;) { |
|
1851 next = node->next; |
|
1852 parent = node->parent; |
|
1853 js_free(node); |
|
1854 node = next; |
|
1855 if (node) |
|
1856 break; |
|
1857 if (!parent) |
|
1858 return dtrc.ok; |
|
1859 JS_ASSERT(depth > 1); |
|
1860 --depth; |
|
1861 node = parent; |
|
1862 } |
|
1863 } |
|
1864 |
|
1865 JS_ASSERT(depth == 1); |
|
1866 return dtrc.ok; |
|
1867 } |
|
1868 |
|
1869 #endif /* DEBUG */ |
|
1870 |
|
1871 extern JS_PUBLIC_API(bool) |
|
1872 JS_IsGCMarkingTracer(JSTracer *trc) |
|
1873 { |
|
1874 return IS_GC_MARKING_TRACER(trc); |
|
1875 } |
|
1876 |
|
1877 #ifdef DEBUG |
|
1878 extern JS_PUBLIC_API(bool) |
|
1879 JS_IsMarkingGray(JSTracer *trc) |
|
1880 { |
|
1881 JS_ASSERT(JS_IsGCMarkingTracer(trc)); |
|
1882 return trc->callback == GCMarker::GrayCallback; |
|
1883 } |
|
1884 #endif |
|
1885 |
|
1886 JS_PUBLIC_API(void) |
|
1887 JS_GC(JSRuntime *rt) |
|
1888 { |
|
1889 AssertHeapIsIdle(rt); |
|
1890 JS::PrepareForFullGC(rt); |
|
1891 GC(rt, GC_NORMAL, JS::gcreason::API); |
|
1892 } |
|
1893 |
|
1894 JS_PUBLIC_API(void) |
|
1895 JS_MaybeGC(JSContext *cx) |
|
1896 { |
|
1897 MaybeGC(cx); |
|
1898 } |
|
1899 |
|
1900 JS_PUBLIC_API(void) |
|
1901 JS_SetGCCallback(JSRuntime *rt, JSGCCallback cb, void *data) |
|
1902 { |
|
1903 AssertHeapIsIdle(rt); |
|
1904 rt->gcCallback = cb; |
|
1905 rt->gcCallbackData = data; |
|
1906 } |
|
1907 |
|
1908 JS_PUBLIC_API(void) |
|
1909 JS_SetFinalizeCallback(JSRuntime *rt, JSFinalizeCallback cb) |
|
1910 { |
|
1911 AssertHeapIsIdle(rt); |
|
1912 rt->gcFinalizeCallback = cb; |
|
1913 } |
|
1914 |
|
1915 JS_PUBLIC_API(bool) |
|
1916 JS_IsAboutToBeFinalized(JS::Heap<JSObject *> *objp) |
|
1917 { |
|
1918 return IsObjectAboutToBeFinalized(objp->unsafeGet()); |
|
1919 } |
|
1920 |
|
1921 JS_PUBLIC_API(bool) |
|
1922 JS_IsAboutToBeFinalizedUnbarriered(JSObject **objp) |
|
1923 { |
|
1924 return IsObjectAboutToBeFinalized(objp); |
|
1925 } |
|
1926 |
|
1927 JS_PUBLIC_API(void) |
|
1928 JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32_t value) |
|
1929 { |
|
1930 switch (key) { |
|
1931 case JSGC_MAX_BYTES: { |
|
1932 JS_ASSERT(value >= rt->gcBytes); |
|
1933 rt->gcMaxBytes = value; |
|
1934 break; |
|
1935 } |
|
1936 case JSGC_MAX_MALLOC_BYTES: |
|
1937 rt->setGCMaxMallocBytes(value); |
|
1938 break; |
|
1939 case JSGC_SLICE_TIME_BUDGET: |
|
1940 rt->gcSliceBudget = SliceBudget::TimeBudget(value); |
|
1941 break; |
|
1942 case JSGC_MARK_STACK_LIMIT: |
|
1943 js::SetMarkStackLimit(rt, value); |
|
1944 break; |
|
1945 case JSGC_HIGH_FREQUENCY_TIME_LIMIT: |
|
1946 rt->gcHighFrequencyTimeThreshold = value; |
|
1947 break; |
|
1948 case JSGC_HIGH_FREQUENCY_LOW_LIMIT: |
|
1949 rt->gcHighFrequencyLowLimitBytes = value * 1024 * 1024; |
|
1950 break; |
|
1951 case JSGC_HIGH_FREQUENCY_HIGH_LIMIT: |
|
1952 rt->gcHighFrequencyHighLimitBytes = value * 1024 * 1024; |
|
1953 break; |
|
1954 case JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX: |
|
1955 rt->gcHighFrequencyHeapGrowthMax = value / 100.0; |
|
1956 MOZ_ASSERT(rt->gcHighFrequencyHeapGrowthMax / 0.85 > 1.0); |
|
1957 break; |
|
1958 case JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN: |
|
1959 rt->gcHighFrequencyHeapGrowthMin = value / 100.0; |
|
1960 MOZ_ASSERT(rt->gcHighFrequencyHeapGrowthMin / 0.85 > 1.0); |
|
1961 break; |
|
1962 case JSGC_LOW_FREQUENCY_HEAP_GROWTH: |
|
1963 rt->gcLowFrequencyHeapGrowth = value / 100.0; |
|
1964 MOZ_ASSERT(rt->gcLowFrequencyHeapGrowth / 0.9 > 1.0); |
|
1965 break; |
|
1966 case JSGC_DYNAMIC_HEAP_GROWTH: |
|
1967 rt->gcDynamicHeapGrowth = value; |
|
1968 break; |
|
1969 case JSGC_DYNAMIC_MARK_SLICE: |
|
1970 rt->gcDynamicMarkSlice = value; |
|
1971 break; |
|
1972 case JSGC_ALLOCATION_THRESHOLD: |
|
1973 rt->gcAllocationThreshold = value * 1024 * 1024; |
|
1974 break; |
|
1975 case JSGC_DECOMMIT_THRESHOLD: |
|
1976 rt->gcDecommitThreshold = value * 1024 * 1024; |
|
1977 break; |
|
1978 default: |
|
1979 JS_ASSERT(key == JSGC_MODE); |
|
1980 rt->setGCMode(JSGCMode(value)); |
|
1981 JS_ASSERT(rt->gcMode() == JSGC_MODE_GLOBAL || |
|
1982 rt->gcMode() == JSGC_MODE_COMPARTMENT || |
|
1983 rt->gcMode() == JSGC_MODE_INCREMENTAL); |
|
1984 return; |
|
1985 } |
|
1986 } |
|
1987 |
|
1988 JS_PUBLIC_API(uint32_t) |
|
1989 JS_GetGCParameter(JSRuntime *rt, JSGCParamKey key) |
|
1990 { |
|
1991 switch (key) { |
|
1992 case JSGC_MAX_BYTES: |
|
1993 return uint32_t(rt->gcMaxBytes); |
|
1994 case JSGC_MAX_MALLOC_BYTES: |
|
1995 return rt->gcMaxMallocBytes; |
|
1996 case JSGC_BYTES: |
|
1997 return uint32_t(rt->gcBytes); |
|
1998 case JSGC_MODE: |
|
1999 return uint32_t(rt->gcMode()); |
|
2000 case JSGC_UNUSED_CHUNKS: |
|
2001 return uint32_t(rt->gcChunkPool.getEmptyCount()); |
|
2002 case JSGC_TOTAL_CHUNKS: |
|
2003 return uint32_t(rt->gcChunkSet.count() + rt->gcChunkPool.getEmptyCount()); |
|
2004 case JSGC_SLICE_TIME_BUDGET: |
|
2005 return uint32_t(rt->gcSliceBudget > 0 ? rt->gcSliceBudget / PRMJ_USEC_PER_MSEC : 0); |
|
2006 case JSGC_MARK_STACK_LIMIT: |
|
2007 return rt->gcMarker.maxCapacity(); |
|
2008 case JSGC_HIGH_FREQUENCY_TIME_LIMIT: |
|
2009 return rt->gcHighFrequencyTimeThreshold; |
|
2010 case JSGC_HIGH_FREQUENCY_LOW_LIMIT: |
|
2011 return rt->gcHighFrequencyLowLimitBytes / 1024 / 1024; |
|
2012 case JSGC_HIGH_FREQUENCY_HIGH_LIMIT: |
|
2013 return rt->gcHighFrequencyHighLimitBytes / 1024 / 1024; |
|
2014 case JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX: |
|
2015 return uint32_t(rt->gcHighFrequencyHeapGrowthMax * 100); |
|
2016 case JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN: |
|
2017 return uint32_t(rt->gcHighFrequencyHeapGrowthMin * 100); |
|
2018 case JSGC_LOW_FREQUENCY_HEAP_GROWTH: |
|
2019 return uint32_t(rt->gcLowFrequencyHeapGrowth * 100); |
|
2020 case JSGC_DYNAMIC_HEAP_GROWTH: |
|
2021 return rt->gcDynamicHeapGrowth; |
|
2022 case JSGC_DYNAMIC_MARK_SLICE: |
|
2023 return rt->gcDynamicMarkSlice; |
|
2024 case JSGC_ALLOCATION_THRESHOLD: |
|
2025 return rt->gcAllocationThreshold / 1024 / 1024; |
|
2026 default: |
|
2027 JS_ASSERT(key == JSGC_NUMBER); |
|
2028 return uint32_t(rt->gcNumber); |
|
2029 } |
|
2030 } |
|
2031 |
|
2032 JS_PUBLIC_API(void) |
|
2033 JS_SetGCParameterForThread(JSContext *cx, JSGCParamKey key, uint32_t value) |
|
2034 { |
|
2035 JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES); |
|
2036 } |
|
2037 |
|
2038 JS_PUBLIC_API(uint32_t) |
|
2039 JS_GetGCParameterForThread(JSContext *cx, JSGCParamKey key) |
|
2040 { |
|
2041 JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES); |
|
2042 return 0; |
|
2043 } |
|
2044 |
|
2045 static const size_t NumGCConfigs = 14; |
|
2046 struct JSGCConfig { |
|
2047 JSGCParamKey key; |
|
2048 uint32_t value; |
|
2049 }; |
|
2050 |
|
2051 JS_PUBLIC_API(void) |
|
2052 JS_SetGCParametersBasedOnAvailableMemory(JSRuntime *rt, uint32_t availMem) |
|
2053 { |
|
2054 static const JSGCConfig minimal[NumGCConfigs] = { |
|
2055 {JSGC_MAX_MALLOC_BYTES, 6 * 1024 * 1024}, |
|
2056 {JSGC_SLICE_TIME_BUDGET, 30}, |
|
2057 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500}, |
|
2058 {JSGC_HIGH_FREQUENCY_HIGH_LIMIT, 40}, |
|
2059 {JSGC_HIGH_FREQUENCY_LOW_LIMIT, 0}, |
|
2060 {JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX, 300}, |
|
2061 {JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN, 120}, |
|
2062 {JSGC_LOW_FREQUENCY_HEAP_GROWTH, 120}, |
|
2063 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500}, |
|
2064 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500}, |
|
2065 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500}, |
|
2066 {JSGC_ALLOCATION_THRESHOLD, 1}, |
|
2067 {JSGC_DECOMMIT_THRESHOLD, 1}, |
|
2068 {JSGC_MODE, JSGC_MODE_INCREMENTAL} |
|
2069 }; |
|
2070 |
|
2071 const JSGCConfig *config = minimal; |
|
2072 if (availMem > 512) { |
|
2073 static const JSGCConfig nominal[NumGCConfigs] = { |
|
2074 {JSGC_MAX_MALLOC_BYTES, 6 * 1024 * 1024}, |
|
2075 {JSGC_SLICE_TIME_BUDGET, 30}, |
|
2076 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1000}, |
|
2077 {JSGC_HIGH_FREQUENCY_HIGH_LIMIT, 500}, |
|
2078 {JSGC_HIGH_FREQUENCY_LOW_LIMIT, 100}, |
|
2079 {JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX, 300}, |
|
2080 {JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN, 150}, |
|
2081 {JSGC_LOW_FREQUENCY_HEAP_GROWTH, 150}, |
|
2082 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500}, |
|
2083 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500}, |
|
2084 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500}, |
|
2085 {JSGC_ALLOCATION_THRESHOLD, 30}, |
|
2086 {JSGC_DECOMMIT_THRESHOLD, 32}, |
|
2087 {JSGC_MODE, JSGC_MODE_COMPARTMENT} |
|
2088 }; |
|
2089 |
|
2090 config = nominal; |
|
2091 } |
|
2092 |
|
2093 for (size_t i = 0; i < NumGCConfigs; i++) |
|
2094 JS_SetGCParameter(rt, config[i].key, config[i].value); |
|
2095 } |
|
2096 |
|
2097 |
|
2098 JS_PUBLIC_API(JSString *) |
|
2099 JS_NewExternalString(JSContext *cx, const jschar *chars, size_t length, |
|
2100 const JSStringFinalizer *fin) |
|
2101 { |
|
2102 AssertHeapIsIdle(cx); |
|
2103 CHECK_REQUEST(cx); |
|
2104 JSString *s = JSExternalString::new_(cx, chars, length, fin); |
|
2105 return s; |
|
2106 } |
|
2107 |
|
2108 extern JS_PUBLIC_API(bool) |
|
2109 JS_IsExternalString(JSString *str) |
|
2110 { |
|
2111 return str->isExternal(); |
|
2112 } |
|
2113 |
|
2114 extern JS_PUBLIC_API(const JSStringFinalizer *) |
|
2115 JS_GetExternalStringFinalizer(JSString *str) |
|
2116 { |
|
2117 return str->asExternal().externalFinalizer(); |
|
2118 } |
|
2119 |
|
2120 static void |
|
2121 SetNativeStackQuota(JSRuntime *rt, StackKind kind, size_t stackSize) |
|
2122 { |
|
2123 rt->nativeStackQuota[kind] = stackSize; |
|
2124 if (rt->nativeStackBase) |
|
2125 RecomputeStackLimit(rt, kind); |
|
2126 } |
|
2127 |
|
2128 void |
|
2129 js::RecomputeStackLimit(JSRuntime *rt, StackKind kind) |
|
2130 { |
|
2131 size_t stackSize = rt->nativeStackQuota[kind]; |
|
2132 #if JS_STACK_GROWTH_DIRECTION > 0 |
|
2133 if (stackSize == 0) { |
|
2134 rt->mainThread.nativeStackLimit[kind] = UINTPTR_MAX; |
|
2135 } else { |
|
2136 JS_ASSERT(rt->nativeStackBase <= size_t(-1) - stackSize); |
|
2137 rt->mainThread.nativeStackLimit[kind] = |
|
2138 rt->nativeStackBase + stackSize - 1; |
|
2139 } |
|
2140 #else |
|
2141 if (stackSize == 0) { |
|
2142 rt->mainThread.nativeStackLimit[kind] = 0; |
|
2143 } else { |
|
2144 JS_ASSERT(rt->nativeStackBase >= stackSize); |
|
2145 rt->mainThread.nativeStackLimit[kind] = |
|
2146 rt->nativeStackBase - (stackSize - 1); |
|
2147 } |
|
2148 #endif |
|
2149 |
|
2150 // If there's no pending interrupt request set on the runtime's main thread's |
|
2151 // jitStackLimit, then update it so that it reflects the new nativeStacklimit. |
|
2152 // |
|
2153 // Note that, for now, we use the untrusted limit for ion. This is fine, |
|
2154 // because it's the most conservative limit, and if we hit it, we'll bail |
|
2155 // out of ion into the interpeter, which will do a proper recursion check. |
|
2156 #ifdef JS_ION |
|
2157 if (kind == StackForUntrustedScript) { |
|
2158 JSRuntime::AutoLockForInterrupt lock(rt); |
|
2159 if (rt->mainThread.jitStackLimit != uintptr_t(-1)) { |
|
2160 rt->mainThread.jitStackLimit = rt->mainThread.nativeStackLimit[kind]; |
|
2161 #ifdef JS_ARM_SIMULATOR |
|
2162 rt->mainThread.jitStackLimit = jit::Simulator::StackLimit(); |
|
2163 #endif |
|
2164 } |
|
2165 } |
|
2166 #endif |
|
2167 } |
|
2168 |
|
2169 JS_PUBLIC_API(void) |
|
2170 JS_SetNativeStackQuota(JSRuntime *rt, size_t systemCodeStackSize, |
|
2171 size_t trustedScriptStackSize, |
|
2172 size_t untrustedScriptStackSize) |
|
2173 { |
|
2174 JS_ASSERT_IF(trustedScriptStackSize, |
|
2175 trustedScriptStackSize < systemCodeStackSize); |
|
2176 if (!trustedScriptStackSize) |
|
2177 trustedScriptStackSize = systemCodeStackSize; |
|
2178 JS_ASSERT_IF(untrustedScriptStackSize, |
|
2179 untrustedScriptStackSize < trustedScriptStackSize); |
|
2180 if (!untrustedScriptStackSize) |
|
2181 untrustedScriptStackSize = trustedScriptStackSize; |
|
2182 SetNativeStackQuota(rt, StackForSystemCode, systemCodeStackSize); |
|
2183 SetNativeStackQuota(rt, StackForTrustedScript, trustedScriptStackSize); |
|
2184 SetNativeStackQuota(rt, StackForUntrustedScript, untrustedScriptStackSize); |
|
2185 } |
|
2186 |
|
2187 /************************************************************************/ |
|
2188 |
|
2189 JS_PUBLIC_API(int) |
|
2190 JS_IdArrayLength(JSContext *cx, JSIdArray *ida) |
|
2191 { |
|
2192 return ida->length; |
|
2193 } |
|
2194 |
|
2195 JS_PUBLIC_API(jsid) |
|
2196 JS_IdArrayGet(JSContext *cx, JSIdArray *ida, int index) |
|
2197 { |
|
2198 JS_ASSERT(index >= 0 && index < ida->length); |
|
2199 return ida->vector[index]; |
|
2200 } |
|
2201 |
|
2202 JS_PUBLIC_API(void) |
|
2203 JS_DestroyIdArray(JSContext *cx, JSIdArray *ida) |
|
2204 { |
|
2205 cx->runtime()->defaultFreeOp()->free_(ida); |
|
2206 } |
|
2207 |
|
2208 JS_PUBLIC_API(bool) |
|
2209 JS_ValueToId(JSContext *cx, HandleValue value, MutableHandleId idp) |
|
2210 { |
|
2211 AssertHeapIsIdle(cx); |
|
2212 CHECK_REQUEST(cx); |
|
2213 assertSameCompartment(cx, value); |
|
2214 return ValueToId<CanGC>(cx, value, idp); |
|
2215 } |
|
2216 |
|
2217 JS_PUBLIC_API(bool) |
|
2218 JS_StringToId(JSContext *cx, HandleString string, MutableHandleId idp) |
|
2219 { |
|
2220 AssertHeapIsIdle(cx); |
|
2221 CHECK_REQUEST(cx); |
|
2222 assertSameCompartment(cx, string); |
|
2223 RootedValue value(cx, StringValue(string)); |
|
2224 return ValueToId<CanGC>(cx, value, idp); |
|
2225 } |
|
2226 |
|
2227 JS_PUBLIC_API(bool) |
|
2228 JS_IdToValue(JSContext *cx, jsid id, MutableHandleValue vp) |
|
2229 { |
|
2230 AssertHeapIsIdle(cx); |
|
2231 CHECK_REQUEST(cx); |
|
2232 vp.set(IdToValue(id)); |
|
2233 assertSameCompartment(cx, vp); |
|
2234 return true; |
|
2235 } |
|
2236 |
|
2237 JS_PUBLIC_API(bool) |
|
2238 JS_DefaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp) |
|
2239 { |
|
2240 AssertHeapIsIdle(cx); |
|
2241 CHECK_REQUEST(cx); |
|
2242 JS_ASSERT(obj != nullptr); |
|
2243 JS_ASSERT(hint == JSTYPE_VOID || hint == JSTYPE_STRING || hint == JSTYPE_NUMBER); |
|
2244 return JSObject::defaultValue(cx, obj, hint, vp); |
|
2245 } |
|
2246 |
|
2247 JS_PUBLIC_API(bool) |
|
2248 JS_PropertyStub(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp) |
|
2249 { |
|
2250 return true; |
|
2251 } |
|
2252 |
|
2253 JS_PUBLIC_API(bool) |
|
2254 JS_StrictPropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool strict, MutableHandleValue vp) |
|
2255 { |
|
2256 return true; |
|
2257 } |
|
2258 |
|
2259 JS_PUBLIC_API(bool) |
|
2260 JS_DeletePropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded) |
|
2261 { |
|
2262 *succeeded = true; |
|
2263 return true; |
|
2264 } |
|
2265 |
|
2266 JS_PUBLIC_API(bool) |
|
2267 JS_EnumerateStub(JSContext *cx, HandleObject obj) |
|
2268 { |
|
2269 return true; |
|
2270 } |
|
2271 |
|
2272 JS_PUBLIC_API(bool) |
|
2273 JS_ResolveStub(JSContext *cx, HandleObject obj, HandleId id) |
|
2274 { |
|
2275 return true; |
|
2276 } |
|
2277 |
|
2278 JS_PUBLIC_API(bool) |
|
2279 JS_ConvertStub(JSContext *cx, HandleObject obj, JSType type, MutableHandleValue vp) |
|
2280 { |
|
2281 JS_ASSERT(type != JSTYPE_OBJECT && type != JSTYPE_FUNCTION); |
|
2282 JS_ASSERT(obj); |
|
2283 return DefaultValue(cx, obj, type, vp); |
|
2284 } |
|
2285 |
|
2286 JS_PUBLIC_API(JSObject *) |
|
2287 JS_InitClass(JSContext *cx, HandleObject obj, HandleObject parent_proto, |
|
2288 const JSClass *clasp, JSNative constructor, unsigned nargs, |
|
2289 const JSPropertySpec *ps, const JSFunctionSpec *fs, |
|
2290 const JSPropertySpec *static_ps, const JSFunctionSpec *static_fs) |
|
2291 { |
|
2292 AssertHeapIsIdle(cx); |
|
2293 CHECK_REQUEST(cx); |
|
2294 assertSameCompartment(cx, obj, parent_proto); |
|
2295 return js_InitClass(cx, obj, parent_proto, Valueify(clasp), constructor, |
|
2296 nargs, ps, fs, static_ps, static_fs); |
|
2297 } |
|
2298 |
|
2299 JS_PUBLIC_API(bool) |
|
2300 JS_LinkConstructorAndPrototype(JSContext *cx, HandleObject ctor, HandleObject proto) |
|
2301 { |
|
2302 return LinkConstructorAndPrototype(cx, ctor, proto); |
|
2303 } |
|
2304 |
|
2305 JS_PUBLIC_API(const JSClass *) |
|
2306 JS_GetClass(JSObject *obj) |
|
2307 { |
|
2308 return obj->getJSClass(); |
|
2309 } |
|
2310 |
|
2311 JS_PUBLIC_API(bool) |
|
2312 JS_InstanceOf(JSContext *cx, HandleObject obj, const JSClass *clasp, CallArgs *args) |
|
2313 { |
|
2314 AssertHeapIsIdle(cx); |
|
2315 CHECK_REQUEST(cx); |
|
2316 #ifdef DEBUG |
|
2317 if (args) { |
|
2318 assertSameCompartment(cx, obj); |
|
2319 assertSameCompartment(cx, args->thisv(), args->calleev()); |
|
2320 } |
|
2321 #endif |
|
2322 if (!obj || obj->getJSClass() != clasp) { |
|
2323 if (args) |
|
2324 ReportIncompatibleMethod(cx, *args, Valueify(clasp)); |
|
2325 return false; |
|
2326 } |
|
2327 return true; |
|
2328 } |
|
2329 |
|
2330 JS_PUBLIC_API(bool) |
|
2331 JS_HasInstance(JSContext *cx, HandleObject obj, HandleValue value, bool *bp) |
|
2332 { |
|
2333 AssertHeapIsIdle(cx); |
|
2334 assertSameCompartment(cx, obj, value); |
|
2335 return HasInstance(cx, obj, value, bp); |
|
2336 } |
|
2337 |
|
2338 JS_PUBLIC_API(void *) |
|
2339 JS_GetPrivate(JSObject *obj) |
|
2340 { |
|
2341 /* This function can be called by a finalizer. */ |
|
2342 return obj->getPrivate(); |
|
2343 } |
|
2344 |
|
2345 JS_PUBLIC_API(void) |
|
2346 JS_SetPrivate(JSObject *obj, void *data) |
|
2347 { |
|
2348 /* This function can be called by a finalizer. */ |
|
2349 obj->setPrivate(data); |
|
2350 } |
|
2351 |
|
2352 JS_PUBLIC_API(void *) |
|
2353 JS_GetInstancePrivate(JSContext *cx, HandleObject obj, const JSClass *clasp, CallArgs *args) |
|
2354 { |
|
2355 if (!JS_InstanceOf(cx, obj, clasp, args)) |
|
2356 return nullptr; |
|
2357 return obj->getPrivate(); |
|
2358 } |
|
2359 |
|
2360 JS_PUBLIC_API(bool) |
|
2361 JS_GetPrototype(JSContext *cx, JS::Handle<JSObject*> obj, JS::MutableHandle<JSObject*> protop) |
|
2362 { |
|
2363 return JSObject::getProto(cx, obj, protop); |
|
2364 } |
|
2365 |
|
2366 JS_PUBLIC_API(bool) |
|
2367 JS_SetPrototype(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<JSObject*> proto) |
|
2368 { |
|
2369 AssertHeapIsIdle(cx); |
|
2370 CHECK_REQUEST(cx); |
|
2371 assertSameCompartment(cx, obj, proto); |
|
2372 |
|
2373 bool succeeded; |
|
2374 if (!JSObject::setProto(cx, obj, proto, &succeeded)) |
|
2375 return false; |
|
2376 |
|
2377 if (!succeeded) { |
|
2378 RootedValue val(cx, ObjectValue(*obj)); |
|
2379 js_ReportValueError(cx, JSMSG_SETPROTOTYPEOF_FAIL, JSDVG_IGNORE_STACK, val, js::NullPtr()); |
|
2380 return false; |
|
2381 } |
|
2382 |
|
2383 return true; |
|
2384 } |
|
2385 |
|
2386 JS_PUBLIC_API(JSObject *) |
|
2387 JS_GetParent(JSObject *obj) |
|
2388 { |
|
2389 JS_ASSERT(!obj->is<ScopeObject>()); |
|
2390 return obj->getParent(); |
|
2391 } |
|
2392 |
|
2393 JS_PUBLIC_API(bool) |
|
2394 JS_SetParent(JSContext *cx, HandleObject obj, HandleObject parent) |
|
2395 { |
|
2396 AssertHeapIsIdle(cx); |
|
2397 CHECK_REQUEST(cx); |
|
2398 JS_ASSERT(!obj->is<ScopeObject>()); |
|
2399 JS_ASSERT(parent || !obj->getParent()); |
|
2400 assertSameCompartment(cx, obj, parent); |
|
2401 |
|
2402 return JSObject::setParent(cx, obj, parent); |
|
2403 } |
|
2404 |
|
2405 JS_PUBLIC_API(JSObject *) |
|
2406 JS_GetConstructor(JSContext *cx, HandleObject proto) |
|
2407 { |
|
2408 AssertHeapIsIdle(cx); |
|
2409 CHECK_REQUEST(cx); |
|
2410 assertSameCompartment(cx, proto); |
|
2411 |
|
2412 RootedValue cval(cx); |
|
2413 if (!JSObject::getProperty(cx, proto, proto, cx->names().constructor, &cval)) |
|
2414 return nullptr; |
|
2415 if (!IsFunctionObject(cval)) { |
|
2416 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NO_CONSTRUCTOR, |
|
2417 proto->getClass()->name); |
|
2418 return nullptr; |
|
2419 } |
|
2420 return &cval.toObject(); |
|
2421 } |
|
2422 |
|
2423 namespace { |
|
2424 |
|
2425 class AutoCompartmentRooter : private JS::CustomAutoRooter |
|
2426 { |
|
2427 public: |
|
2428 explicit AutoCompartmentRooter(JSContext *cx, JSCompartment *comp |
|
2429 MOZ_GUARD_OBJECT_NOTIFIER_PARAM) |
|
2430 : CustomAutoRooter(cx), compartment(comp) |
|
2431 { |
|
2432 MOZ_GUARD_OBJECT_NOTIFIER_INIT; |
|
2433 } |
|
2434 |
|
2435 operator JSCompartment *() { |
|
2436 return compartment; |
|
2437 } |
|
2438 |
|
2439 JSCompartment *operator->() { |
|
2440 return compartment; |
|
2441 } |
|
2442 |
|
2443 protected: |
|
2444 virtual void trace(JSTracer *trc) |
|
2445 { |
|
2446 compartment->mark(); |
|
2447 } |
|
2448 |
|
2449 private: |
|
2450 JSCompartment *compartment; |
|
2451 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER |
|
2452 }; |
|
2453 |
|
2454 } /* anonymous namespace */ |
|
2455 |
|
2456 bool |
|
2457 JS::CompartmentOptions::cloneSingletons(JSContext *cx) const |
|
2458 { |
|
2459 return cloneSingletonsOverride_.get(cx->options().cloneSingletons()); |
|
2460 } |
|
2461 |
|
2462 JS::CompartmentOptions & |
|
2463 JS::CompartmentOptions::setZone(ZoneSpecifier spec) |
|
2464 { |
|
2465 zone_.spec = spec; |
|
2466 return *this; |
|
2467 } |
|
2468 |
|
2469 JS::CompartmentOptions & |
|
2470 JS::CompartmentOptions::setSameZoneAs(JSObject *obj) |
|
2471 { |
|
2472 zone_.pointer = static_cast<void *>(obj->zone()); |
|
2473 return *this; |
|
2474 } |
|
2475 |
|
2476 JS::CompartmentOptions & |
|
2477 JS::CompartmentOptionsRef(JSCompartment *compartment) |
|
2478 { |
|
2479 return compartment->options(); |
|
2480 } |
|
2481 |
|
2482 JS::CompartmentOptions & |
|
2483 JS::CompartmentOptionsRef(JSObject *obj) |
|
2484 { |
|
2485 return obj->compartment()->options(); |
|
2486 } |
|
2487 |
|
2488 JS::CompartmentOptions & |
|
2489 JS::CompartmentOptionsRef(JSContext *cx) |
|
2490 { |
|
2491 return cx->compartment()->options(); |
|
2492 } |
|
2493 |
|
2494 JS_PUBLIC_API(JSObject *) |
|
2495 JS_NewGlobalObject(JSContext *cx, const JSClass *clasp, JSPrincipals *principals, |
|
2496 JS::OnNewGlobalHookOption hookOption, |
|
2497 const JS::CompartmentOptions &options /* = JS::CompartmentOptions() */) |
|
2498 { |
|
2499 AssertHeapIsIdle(cx); |
|
2500 CHECK_REQUEST(cx); |
|
2501 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); |
|
2502 JS_ASSERT(!cx->isExceptionPending()); |
|
2503 |
|
2504 JSRuntime *rt = cx->runtime(); |
|
2505 |
|
2506 Zone *zone; |
|
2507 if (options.zoneSpecifier() == JS::SystemZone) |
|
2508 zone = rt->systemZone; |
|
2509 else if (options.zoneSpecifier() == JS::FreshZone) |
|
2510 zone = nullptr; |
|
2511 else |
|
2512 zone = static_cast<Zone *>(options.zonePointer()); |
|
2513 |
|
2514 AutoCompartmentRooter compartment(cx, NewCompartment(cx, zone, principals, options)); |
|
2515 if (!compartment) |
|
2516 return nullptr; |
|
2517 |
|
2518 // Lazily create the system zone. |
|
2519 if (!rt->systemZone && options.zoneSpecifier() == JS::SystemZone) { |
|
2520 rt->systemZone = compartment->zone(); |
|
2521 rt->systemZone->isSystem = true; |
|
2522 } |
|
2523 |
|
2524 Rooted<GlobalObject *> global(cx); |
|
2525 { |
|
2526 AutoCompartment ac(cx, compartment); |
|
2527 global = GlobalObject::create(cx, Valueify(clasp)); |
|
2528 } |
|
2529 |
|
2530 if (!global) |
|
2531 return nullptr; |
|
2532 |
|
2533 if (hookOption == JS::FireOnNewGlobalHook) |
|
2534 JS_FireOnNewGlobalObject(cx, global); |
|
2535 |
|
2536 return global; |
|
2537 } |
|
2538 |
|
2539 JS_PUBLIC_API(void) |
|
2540 JS_GlobalObjectTraceHook(JSTracer *trc, JSObject *global) |
|
2541 { |
|
2542 JS_ASSERT(global->is<GlobalObject>()); |
|
2543 |
|
2544 // Off thread parsing and compilation tasks create a dummy global which is then |
|
2545 // merged back into the host compartment. Since it used to be a global, it will still |
|
2546 // have this trace hook, but it does not have a meaning relative to its new compartment. |
|
2547 // We can safely skip it. |
|
2548 if (!global->isOwnGlobal()) |
|
2549 return; |
|
2550 |
|
2551 // Trace the compartment for any GC things that should only stick around if we know the |
|
2552 // compartment is live. |
|
2553 global->compartment()->trace(trc); |
|
2554 |
|
2555 JSTraceOp trace = global->compartment()->options().getTrace(); |
|
2556 if (trace) |
|
2557 trace(trc, global); |
|
2558 } |
|
2559 |
|
2560 JS_PUBLIC_API(void) |
|
2561 JS_FireOnNewGlobalObject(JSContext *cx, JS::HandleObject global) |
|
2562 { |
|
2563 // This hook is infallible, because we don't really want arbitrary script |
|
2564 // to be able to throw errors during delicate global creation routines. |
|
2565 // This infallibility will eat OOM and slow script, but if that happens |
|
2566 // we'll likely run up into them again soon in a fallible context. |
|
2567 Rooted<js::GlobalObject*> globalObject(cx, &global->as<GlobalObject>()); |
|
2568 Debugger::onNewGlobalObject(cx, globalObject); |
|
2569 } |
|
2570 |
|
2571 JS_PUBLIC_API(JSObject *) |
|
2572 JS_NewObject(JSContext *cx, const JSClass *jsclasp, HandleObject proto, HandleObject parent) |
|
2573 { |
|
2574 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); |
|
2575 AssertHeapIsIdle(cx); |
|
2576 CHECK_REQUEST(cx); |
|
2577 assertSameCompartment(cx, proto, parent); |
|
2578 |
|
2579 const Class *clasp = Valueify(jsclasp); |
|
2580 if (!clasp) |
|
2581 clasp = &JSObject::class_; /* default class is Object */ |
|
2582 |
|
2583 JS_ASSERT(clasp != &JSFunction::class_); |
|
2584 JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL)); |
|
2585 |
|
2586 JSObject *obj = NewObjectWithClassProto(cx, clasp, proto, parent); |
|
2587 JS_ASSERT_IF(obj, obj->getParent()); |
|
2588 return obj; |
|
2589 } |
|
2590 |
|
2591 JS_PUBLIC_API(JSObject *) |
|
2592 JS_NewObjectWithGivenProto(JSContext *cx, const JSClass *jsclasp, HandleObject proto, HandleObject parent) |
|
2593 { |
|
2594 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); |
|
2595 AssertHeapIsIdle(cx); |
|
2596 CHECK_REQUEST(cx); |
|
2597 assertSameCompartment(cx, proto, parent); |
|
2598 |
|
2599 const Class *clasp = Valueify(jsclasp); |
|
2600 if (!clasp) |
|
2601 clasp = &JSObject::class_; /* default class is Object */ |
|
2602 |
|
2603 JS_ASSERT(clasp != &JSFunction::class_); |
|
2604 JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL)); |
|
2605 |
|
2606 JSObject *obj = NewObjectWithGivenProto(cx, clasp, proto, parent); |
|
2607 if (obj) |
|
2608 MarkTypeObjectUnknownProperties(cx, obj->type()); |
|
2609 return obj; |
|
2610 } |
|
2611 |
|
2612 JS_PUBLIC_API(JSObject *) |
|
2613 JS_NewObjectForConstructor(JSContext *cx, const JSClass *clasp, const CallArgs& args) |
|
2614 { |
|
2615 AssertHeapIsIdle(cx); |
|
2616 CHECK_REQUEST(cx); |
|
2617 |
|
2618 Value callee = args.calleev(); |
|
2619 assertSameCompartment(cx, callee); |
|
2620 RootedObject obj(cx, &callee.toObject()); |
|
2621 return CreateThis(cx, Valueify(clasp), obj); |
|
2622 } |
|
2623 |
|
2624 JS_PUBLIC_API(bool) |
|
2625 JS_IsExtensible(JSContext *cx, HandleObject obj, bool *extensible) |
|
2626 { |
|
2627 return JSObject::isExtensible(cx, obj, extensible); |
|
2628 } |
|
2629 |
|
2630 JS_PUBLIC_API(bool) |
|
2631 JS_IsNative(JSObject *obj) |
|
2632 { |
|
2633 return obj->isNative(); |
|
2634 } |
|
2635 |
|
2636 JS_PUBLIC_API(JSRuntime *) |
|
2637 JS_GetObjectRuntime(JSObject *obj) |
|
2638 { |
|
2639 return obj->compartment()->runtimeFromMainThread(); |
|
2640 } |
|
2641 |
|
2642 JS_PUBLIC_API(bool) |
|
2643 JS_FreezeObject(JSContext *cx, HandleObject obj) |
|
2644 { |
|
2645 AssertHeapIsIdle(cx); |
|
2646 CHECK_REQUEST(cx); |
|
2647 assertSameCompartment(cx, obj); |
|
2648 return JSObject::freeze(cx, obj); |
|
2649 } |
|
2650 |
|
2651 JS_PUBLIC_API(bool) |
|
2652 JS_DeepFreezeObject(JSContext *cx, HandleObject obj) |
|
2653 { |
|
2654 AssertHeapIsIdle(cx); |
|
2655 CHECK_REQUEST(cx); |
|
2656 assertSameCompartment(cx, obj); |
|
2657 |
|
2658 /* Assume that non-extensible objects are already deep-frozen, to avoid divergence. */ |
|
2659 bool extensible; |
|
2660 if (!JSObject::isExtensible(cx, obj, &extensible)) |
|
2661 return false; |
|
2662 if (!extensible) |
|
2663 return true; |
|
2664 |
|
2665 if (!JSObject::freeze(cx, obj)) |
|
2666 return false; |
|
2667 |
|
2668 /* Walk slots in obj and if any value is a non-null object, seal it. */ |
|
2669 for (uint32_t i = 0, n = obj->slotSpan(); i < n; ++i) { |
|
2670 const Value &v = obj->getSlot(i); |
|
2671 if (v.isPrimitive()) |
|
2672 continue; |
|
2673 RootedObject obj(cx, &v.toObject()); |
|
2674 if (!JS_DeepFreezeObject(cx, obj)) |
|
2675 return false; |
|
2676 } |
|
2677 |
|
2678 return true; |
|
2679 } |
|
2680 |
|
2681 static bool |
|
2682 LookupPropertyById(JSContext *cx, HandleObject obj, HandleId id, |
|
2683 MutableHandleObject objp, MutableHandleShape propp) |
|
2684 { |
|
2685 AssertHeapIsIdle(cx); |
|
2686 CHECK_REQUEST(cx); |
|
2687 assertSameCompartment(cx, obj, id); |
|
2688 |
|
2689 return JSObject::lookupGeneric(cx, obj, id, objp, propp); |
|
2690 } |
|
2691 |
|
2692 #define AUTO_NAMELEN(s,n) (((n) == (size_t)-1) ? js_strlen(s) : (n)) |
|
2693 |
|
2694 static bool |
|
2695 LookupResult(JSContext *cx, HandleObject obj, HandleObject obj2, HandleId id, |
|
2696 HandleShape shape, MutableHandleValue vp) |
|
2697 { |
|
2698 if (!shape) { |
|
2699 /* XXX bad API: no way to tell "not defined" from "void value" */ |
|
2700 vp.setUndefined(); |
|
2701 return true; |
|
2702 } |
|
2703 |
|
2704 if (!obj2->isNative()) { |
|
2705 if (obj2->is<ProxyObject>()) { |
|
2706 Rooted<PropertyDescriptor> desc(cx); |
|
2707 if (!Proxy::getPropertyDescriptor(cx, obj2, id, &desc)) |
|
2708 return false; |
|
2709 if (!desc.isShared()) { |
|
2710 vp.set(desc.value()); |
|
2711 return true; |
|
2712 } |
|
2713 } |
|
2714 } else if (IsImplicitDenseOrTypedArrayElement(shape)) { |
|
2715 vp.set(obj2->getDenseOrTypedArrayElement(JSID_TO_INT(id))); |
|
2716 return true; |
|
2717 } else { |
|
2718 /* Peek at the native property's slot value, without doing a Get. */ |
|
2719 if (shape->hasSlot()) { |
|
2720 vp.set(obj2->nativeGetSlot(shape->slot())); |
|
2721 return true; |
|
2722 } |
|
2723 } |
|
2724 |
|
2725 /* XXX bad API: no way to return "defined but value unknown" */ |
|
2726 vp.setBoolean(true); |
|
2727 return true; |
|
2728 } |
|
2729 |
|
2730 JS_PUBLIC_API(bool) |
|
2731 JS_LookupPropertyById(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp) |
|
2732 { |
|
2733 RootedObject obj2(cx); |
|
2734 RootedShape prop(cx); |
|
2735 |
|
2736 return LookupPropertyById(cx, obj, id, &obj2, &prop) && |
|
2737 LookupResult(cx, obj, obj2, id, prop, vp); |
|
2738 } |
|
2739 |
|
2740 JS_PUBLIC_API(bool) |
|
2741 JS_LookupElement(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleValue vp) |
|
2742 { |
|
2743 CHECK_REQUEST(cx); |
|
2744 RootedId id(cx); |
|
2745 if (!IndexToId(cx, index, &id)) |
|
2746 return false; |
|
2747 return JS_LookupPropertyById(cx, obj, id, vp); |
|
2748 } |
|
2749 |
|
2750 JS_PUBLIC_API(bool) |
|
2751 JS_LookupProperty(JSContext *cx, HandleObject objArg, const char *name, MutableHandleValue vp) |
|
2752 { |
|
2753 RootedObject obj(cx, objArg); |
|
2754 JSAtom *atom = Atomize(cx, name, strlen(name)); |
|
2755 if (!atom) |
|
2756 return false; |
|
2757 |
|
2758 RootedId id(cx, AtomToId(atom)); |
|
2759 return JS_LookupPropertyById(cx, obj, id, vp); |
|
2760 } |
|
2761 |
|
2762 JS_PUBLIC_API(bool) |
|
2763 JS_LookupUCProperty(JSContext *cx, HandleObject objArg, const jschar *name, size_t namelen, |
|
2764 MutableHandleValue vp) |
|
2765 { |
|
2766 RootedObject obj(cx, objArg); |
|
2767 JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); |
|
2768 if (!atom) |
|
2769 return false; |
|
2770 |
|
2771 RootedId id(cx, AtomToId(atom)); |
|
2772 return JS_LookupPropertyById(cx, obj, id, vp); |
|
2773 } |
|
2774 |
|
2775 JS_PUBLIC_API(bool) |
|
2776 JS_HasPropertyById(JSContext *cx, HandleObject obj, HandleId id, bool *foundp) |
|
2777 { |
|
2778 RootedObject obj2(cx); |
|
2779 RootedShape prop(cx); |
|
2780 bool ok = LookupPropertyById(cx, obj, id, &obj2, &prop); |
|
2781 *foundp = (prop != nullptr); |
|
2782 return ok; |
|
2783 } |
|
2784 |
|
2785 JS_PUBLIC_API(bool) |
|
2786 JS_HasElement(JSContext *cx, HandleObject obj, uint32_t index, bool *foundp) |
|
2787 { |
|
2788 AssertHeapIsIdle(cx); |
|
2789 CHECK_REQUEST(cx); |
|
2790 RootedId id(cx); |
|
2791 if (!IndexToId(cx, index, &id)) |
|
2792 return false; |
|
2793 return JS_HasPropertyById(cx, obj, id, foundp); |
|
2794 } |
|
2795 |
|
2796 JS_PUBLIC_API(bool) |
|
2797 JS_HasProperty(JSContext *cx, HandleObject obj, const char *name, bool *foundp) |
|
2798 { |
|
2799 JSAtom *atom = Atomize(cx, name, strlen(name)); |
|
2800 if (!atom) |
|
2801 return false; |
|
2802 RootedId id(cx, AtomToId(atom)); |
|
2803 return JS_HasPropertyById(cx, obj, id, foundp); |
|
2804 } |
|
2805 |
|
2806 JS_PUBLIC_API(bool) |
|
2807 JS_HasUCProperty(JSContext *cx, HandleObject obj, const jschar *name, size_t namelen, bool *foundp) |
|
2808 { |
|
2809 JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); |
|
2810 if (!atom) |
|
2811 return false; |
|
2812 RootedId id(cx, AtomToId(atom)); |
|
2813 return JS_HasPropertyById(cx, obj, id, foundp); |
|
2814 } |
|
2815 |
|
2816 JS_PUBLIC_API(bool) |
|
2817 JS_AlreadyHasOwnPropertyById(JSContext *cx, HandleObject obj, HandleId id, bool *foundp) |
|
2818 { |
|
2819 AssertHeapIsIdle(cx); |
|
2820 CHECK_REQUEST(cx); |
|
2821 assertSameCompartment(cx, obj, id); |
|
2822 |
|
2823 if (!obj->isNative()) { |
|
2824 RootedObject obj2(cx); |
|
2825 RootedShape prop(cx); |
|
2826 |
|
2827 if (!LookupPropertyById(cx, obj, id, &obj2, &prop)) |
|
2828 return false; |
|
2829 *foundp = (obj == obj2); |
|
2830 return true; |
|
2831 } |
|
2832 |
|
2833 // Check for an existing native property on the objct. Be careful not to |
|
2834 // call any lookup or resolve hooks. |
|
2835 |
|
2836 if (JSID_IS_INT(id)) { |
|
2837 uint32_t index = JSID_TO_INT(id); |
|
2838 |
|
2839 if (obj->containsDenseElement(index)) { |
|
2840 *foundp = true; |
|
2841 return true; |
|
2842 } |
|
2843 |
|
2844 if (obj->is<TypedArrayObject>() && index < obj->as<TypedArrayObject>().length()) { |
|
2845 *foundp = true; |
|
2846 return true; |
|
2847 } |
|
2848 } |
|
2849 |
|
2850 *foundp = obj->nativeContains(cx, id); |
|
2851 return true; |
|
2852 } |
|
2853 |
|
2854 JS_PUBLIC_API(bool) |
|
2855 JS_AlreadyHasOwnElement(JSContext *cx, HandleObject obj, uint32_t index, bool *foundp) |
|
2856 { |
|
2857 AssertHeapIsIdle(cx); |
|
2858 CHECK_REQUEST(cx); |
|
2859 RootedId id(cx); |
|
2860 if (!IndexToId(cx, index, &id)) |
|
2861 return false; |
|
2862 return JS_AlreadyHasOwnPropertyById(cx, obj, id, foundp); |
|
2863 } |
|
2864 |
|
2865 JS_PUBLIC_API(bool) |
|
2866 JS_AlreadyHasOwnProperty(JSContext *cx, HandleObject obj, const char *name, bool *foundp) |
|
2867 { |
|
2868 JSAtom *atom = Atomize(cx, name, strlen(name)); |
|
2869 if (!atom) |
|
2870 return false; |
|
2871 RootedId id(cx, AtomToId(atom)); |
|
2872 return JS_AlreadyHasOwnPropertyById(cx, obj, id, foundp); |
|
2873 } |
|
2874 |
|
2875 JS_PUBLIC_API(bool) |
|
2876 JS_AlreadyHasOwnUCProperty(JSContext *cx, HandleObject obj, const jschar *name, size_t namelen, |
|
2877 bool *foundp) |
|
2878 { |
|
2879 JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); |
|
2880 if (!atom) |
|
2881 return false; |
|
2882 RootedId id(cx, AtomToId(atom)); |
|
2883 return JS_AlreadyHasOwnPropertyById(cx, obj, id, foundp); |
|
2884 } |
|
2885 |
|
2886 /* Wrapper functions to create wrappers with no corresponding JSJitInfo from API |
|
2887 * function arguments. |
|
2888 */ |
|
2889 static JSPropertyOpWrapper |
|
2890 GetterWrapper(JSPropertyOp getter) |
|
2891 { |
|
2892 JSPropertyOpWrapper ret; |
|
2893 ret.op = getter; |
|
2894 ret.info = nullptr; |
|
2895 return ret; |
|
2896 } |
|
2897 |
|
2898 static JSStrictPropertyOpWrapper |
|
2899 SetterWrapper(JSStrictPropertyOp setter) |
|
2900 { |
|
2901 JSStrictPropertyOpWrapper ret; |
|
2902 ret.op = setter; |
|
2903 ret.info = nullptr; |
|
2904 return ret; |
|
2905 } |
|
2906 |
|
2907 static bool |
|
2908 DefinePropertyById(JSContext *cx, HandleObject obj, HandleId id, HandleValue value, |
|
2909 const JSPropertyOpWrapper &get, const JSStrictPropertyOpWrapper &set, |
|
2910 unsigned attrs, unsigned flags) |
|
2911 { |
|
2912 PropertyOp getter = get.op; |
|
2913 StrictPropertyOp setter = set.op; |
|
2914 /* |
|
2915 * JSPROP_READONLY has no meaning when accessors are involved. Ideally we'd |
|
2916 * throw if this happens, but we've accepted it for long enough that it's |
|
2917 * not worth trying to make callers change their ways. Just flip it off on |
|
2918 * its way through the API layer so that we can enforce this internally. |
|
2919 */ |
|
2920 if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) |
|
2921 attrs &= ~JSPROP_READONLY; |
|
2922 |
|
2923 /* |
|
2924 * When we use DefineProperty, we need full scriptable Function objects rather |
|
2925 * than JSNatives. However, we might be pulling this property descriptor off |
|
2926 * of something with JSNative property descriptors. If we are, wrap them in |
|
2927 * JS Function objects. |
|
2928 */ |
|
2929 if (attrs & JSPROP_NATIVE_ACCESSORS) { |
|
2930 JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER))); |
|
2931 JSFunction::Flags zeroFlags = JSAPIToJSFunctionFlags(0); |
|
2932 // We can't just use JS_NewFunctionById here because it |
|
2933 // assumes a string id. |
|
2934 RootedAtom atom(cx, JSID_IS_ATOM(id) ? JSID_TO_ATOM(id) : nullptr); |
|
2935 attrs &= ~JSPROP_NATIVE_ACCESSORS; |
|
2936 if (getter) { |
|
2937 RootedObject global(cx, (JSObject*) &obj->global()); |
|
2938 JSFunction *getobj = NewFunction(cx, NullPtr(), (Native) getter, 0, |
|
2939 zeroFlags, global, atom); |
|
2940 if (!getobj) |
|
2941 return false; |
|
2942 |
|
2943 if (get.info) |
|
2944 getobj->setJitInfo(get.info); |
|
2945 |
|
2946 getter = JS_DATA_TO_FUNC_PTR(PropertyOp, getobj); |
|
2947 attrs |= JSPROP_GETTER; |
|
2948 } |
|
2949 if (setter) { |
|
2950 // Root just the getter, since the setter is not yet a JSObject. |
|
2951 AutoRooterGetterSetter getRoot(cx, JSPROP_GETTER, &getter, nullptr); |
|
2952 RootedObject global(cx, (JSObject*) &obj->global()); |
|
2953 JSFunction *setobj = NewFunction(cx, NullPtr(), (Native) setter, 1, |
|
2954 zeroFlags, global, atom); |
|
2955 if (!setobj) |
|
2956 return false; |
|
2957 |
|
2958 if (set.info) |
|
2959 setobj->setJitInfo(set.info); |
|
2960 |
|
2961 setter = JS_DATA_TO_FUNC_PTR(StrictPropertyOp, setobj); |
|
2962 attrs |= JSPROP_SETTER; |
|
2963 } |
|
2964 } |
|
2965 |
|
2966 |
|
2967 AssertHeapIsIdle(cx); |
|
2968 CHECK_REQUEST(cx); |
|
2969 assertSameCompartment(cx, obj, id, value, |
|
2970 (attrs & JSPROP_GETTER) |
|
2971 ? JS_FUNC_TO_DATA_PTR(JSObject *, getter) |
|
2972 : nullptr, |
|
2973 (attrs & JSPROP_SETTER) |
|
2974 ? JS_FUNC_TO_DATA_PTR(JSObject *, setter) |
|
2975 : nullptr); |
|
2976 |
|
2977 return JSObject::defineGeneric(cx, obj, id, value, getter, setter, attrs); |
|
2978 } |
|
2979 |
|
2980 JS_PUBLIC_API(bool) |
|
2981 JS_DefinePropertyById(JSContext *cx, JSObject *objArg, jsid idArg, jsval valueArg, |
|
2982 JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs) |
|
2983 { |
|
2984 RootedObject obj(cx, objArg); |
|
2985 RootedId id(cx, idArg); |
|
2986 RootedValue value(cx, valueArg); |
|
2987 return DefinePropertyById(cx, obj, id, value, GetterWrapper(getter), SetterWrapper(setter), |
|
2988 attrs, 0); |
|
2989 } |
|
2990 |
|
2991 JS_PUBLIC_API(bool) |
|
2992 JS_DefineElement(JSContext *cx, JSObject *objArg, uint32_t index, jsval valueArg, |
|
2993 JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs) |
|
2994 { |
|
2995 RootedObject obj(cx, objArg); |
|
2996 RootedValue value(cx, valueArg); |
|
2997 AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter); |
|
2998 AssertHeapIsIdle(cx); |
|
2999 CHECK_REQUEST(cx); |
|
3000 RootedId id(cx); |
|
3001 if (!IndexToId(cx, index, &id)) |
|
3002 return false; |
|
3003 return DefinePropertyById(cx, obj, id, value, GetterWrapper(getter), SetterWrapper(setter), |
|
3004 attrs, 0); |
|
3005 } |
|
3006 |
|
3007 static bool |
|
3008 DefineProperty(JSContext *cx, HandleObject obj, const char *name, HandleValue value, |
|
3009 const JSPropertyOpWrapper &getter, const JSStrictPropertyOpWrapper &setter, |
|
3010 unsigned attrs, unsigned flags) |
|
3011 { |
|
3012 AutoRooterGetterSetter gsRoot(cx, attrs, const_cast<JSPropertyOp *>(&getter.op), |
|
3013 const_cast<JSStrictPropertyOp *>(&setter.op)); |
|
3014 |
|
3015 RootedId id(cx); |
|
3016 if (attrs & JSPROP_INDEX) { |
|
3017 id.set(INT_TO_JSID(intptr_t(name))); |
|
3018 attrs &= ~JSPROP_INDEX; |
|
3019 } else { |
|
3020 JSAtom *atom = Atomize(cx, name, strlen(name)); |
|
3021 if (!atom) |
|
3022 return false; |
|
3023 id = AtomToId(atom); |
|
3024 } |
|
3025 |
|
3026 return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, flags); |
|
3027 } |
|
3028 |
|
3029 |
|
3030 static bool |
|
3031 DefineSelfHostedProperty(JSContext *cx, |
|
3032 HandleObject obj, |
|
3033 const char *name, |
|
3034 const char *getterName, |
|
3035 const char *setterName, |
|
3036 unsigned attrs, |
|
3037 unsigned flags) |
|
3038 { |
|
3039 RootedAtom nameAtom(cx, Atomize(cx, name, strlen(name))); |
|
3040 if (!nameAtom) |
|
3041 return false; |
|
3042 |
|
3043 RootedAtom getterNameAtom(cx, Atomize(cx, getterName, strlen(getterName))); |
|
3044 if (!getterNameAtom) |
|
3045 return false; |
|
3046 |
|
3047 RootedValue getterValue(cx); |
|
3048 if (!cx->global()->getSelfHostedFunction(cx, getterNameAtom, nameAtom, |
|
3049 0, &getterValue)) |
|
3050 { |
|
3051 return false; |
|
3052 } |
|
3053 JS_ASSERT(getterValue.isObject() && getterValue.toObject().is<JSFunction>()); |
|
3054 RootedFunction getterFunc(cx, &getterValue.toObject().as<JSFunction>()); |
|
3055 JSPropertyOp getterOp = JS_DATA_TO_FUNC_PTR(PropertyOp, getterFunc.get()); |
|
3056 |
|
3057 RootedFunction setterFunc(cx); |
|
3058 if (setterName) { |
|
3059 RootedAtom setterNameAtom(cx, Atomize(cx, setterName, strlen(setterName))); |
|
3060 if (!setterNameAtom) |
|
3061 return false; |
|
3062 |
|
3063 RootedValue setterValue(cx); |
|
3064 if (!cx->global()->getSelfHostedFunction(cx, setterNameAtom, nameAtom, |
|
3065 0, &setterValue)) |
|
3066 { |
|
3067 return false; |
|
3068 } |
|
3069 JS_ASSERT(setterValue.isObject() && setterValue.toObject().is<JSFunction>()); |
|
3070 setterFunc = &getterValue.toObject().as<JSFunction>(); |
|
3071 } |
|
3072 JSStrictPropertyOp setterOp = JS_DATA_TO_FUNC_PTR(StrictPropertyOp, setterFunc.get()); |
|
3073 |
|
3074 return DefineProperty(cx, obj, name, JS::UndefinedHandleValue, |
|
3075 GetterWrapper(getterOp), SetterWrapper(setterOp), |
|
3076 attrs, flags); |
|
3077 } |
|
3078 |
|
3079 JS_PUBLIC_API(bool) |
|
3080 JS_DefineProperty(JSContext *cx, HandleObject obj, const char *name, HandleValue value, |
|
3081 unsigned attrs, |
|
3082 PropertyOp getter /* = nullptr */, JSStrictPropertyOp setter /* = nullptr */) |
|
3083 { |
|
3084 return DefineProperty(cx, obj, name, value, GetterWrapper(getter), SetterWrapper(setter), |
|
3085 attrs, 0); |
|
3086 } |
|
3087 |
|
3088 JS_PUBLIC_API(bool) |
|
3089 JS_DefineProperty(JSContext *cx, HandleObject obj, const char *name, HandleObject valueArg, |
|
3090 unsigned attrs, |
|
3091 PropertyOp getter /* = nullptr */, JSStrictPropertyOp setter /* = nullptr */) |
|
3092 { |
|
3093 RootedValue value(cx, ObjectValue(*valueArg)); |
|
3094 return DefineProperty(cx, obj, name, value, GetterWrapper(getter), SetterWrapper(setter), |
|
3095 attrs, 0); |
|
3096 } |
|
3097 |
|
3098 JS_PUBLIC_API(bool) |
|
3099 JS_DefineProperty(JSContext *cx, HandleObject obj, const char *name, HandleString valueArg, |
|
3100 unsigned attrs, |
|
3101 PropertyOp getter /* = nullptr */, JSStrictPropertyOp setter /* = nullptr */) |
|
3102 { |
|
3103 RootedValue value(cx, StringValue(valueArg)); |
|
3104 return DefineProperty(cx, obj, name, value, GetterWrapper(getter), SetterWrapper(setter), |
|
3105 attrs, 0); |
|
3106 } |
|
3107 |
|
3108 JS_PUBLIC_API(bool) |
|
3109 JS_DefineProperty(JSContext *cx, HandleObject obj, const char *name, int32_t valueArg, |
|
3110 unsigned attrs, |
|
3111 PropertyOp getter /* = nullptr */, JSStrictPropertyOp setter /* = nullptr */) |
|
3112 { |
|
3113 Value value = Int32Value(valueArg); |
|
3114 return DefineProperty(cx, obj, name, HandleValue::fromMarkedLocation(&value), |
|
3115 GetterWrapper(getter), SetterWrapper(setter), attrs, 0); |
|
3116 } |
|
3117 |
|
3118 JS_PUBLIC_API(bool) |
|
3119 JS_DefineProperty(JSContext *cx, HandleObject obj, const char *name, uint32_t valueArg, |
|
3120 unsigned attrs, |
|
3121 PropertyOp getter /* = nullptr */, JSStrictPropertyOp setter /* = nullptr */) |
|
3122 { |
|
3123 Value value = UINT_TO_JSVAL(valueArg); |
|
3124 return DefineProperty(cx, obj, name, HandleValue::fromMarkedLocation(&value), |
|
3125 GetterWrapper(getter), SetterWrapper(setter), attrs, 0); |
|
3126 } |
|
3127 |
|
3128 JS_PUBLIC_API(bool) |
|
3129 JS_DefineProperty(JSContext *cx, HandleObject obj, const char *name, double valueArg, |
|
3130 unsigned attrs, |
|
3131 PropertyOp getter /* = nullptr */, JSStrictPropertyOp setter /* = nullptr */) |
|
3132 { |
|
3133 Value value = NumberValue(valueArg); |
|
3134 return DefineProperty(cx, obj, name, HandleValue::fromMarkedLocation(&value), |
|
3135 GetterWrapper(getter), SetterWrapper(setter), attrs, 0); |
|
3136 } |
|
3137 |
|
3138 static bool |
|
3139 DefineUCProperty(JSContext *cx, HandleObject obj, const jschar *name, size_t namelen, |
|
3140 const Value &value_, PropertyOp getter, StrictPropertyOp setter, unsigned attrs, |
|
3141 unsigned flags) |
|
3142 { |
|
3143 RootedValue value(cx, value_); |
|
3144 AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter); |
|
3145 JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); |
|
3146 if (!atom) |
|
3147 return false; |
|
3148 RootedId id(cx, AtomToId(atom)); |
|
3149 return DefinePropertyById(cx, obj, id, value, GetterWrapper(getter), SetterWrapper(setter), |
|
3150 attrs, flags); |
|
3151 } |
|
3152 |
|
3153 JS_PUBLIC_API(bool) |
|
3154 JS_DefineUCProperty(JSContext *cx, JSObject *objArg, const jschar *name, size_t namelen, |
|
3155 jsval valueArg, JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs) |
|
3156 { |
|
3157 RootedObject obj(cx, objArg); |
|
3158 RootedValue value(cx, valueArg); |
|
3159 return DefineUCProperty(cx, obj, name, namelen, value, getter, setter, attrs, 0); |
|
3160 } |
|
3161 |
|
3162 JS_PUBLIC_API(bool) |
|
3163 JS_DefineOwnProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue descriptor, bool *bp) |
|
3164 { |
|
3165 AssertHeapIsIdle(cx); |
|
3166 CHECK_REQUEST(cx); |
|
3167 assertSameCompartment(cx, obj, id, descriptor); |
|
3168 |
|
3169 return DefineOwnProperty(cx, obj, id, descriptor, bp); |
|
3170 } |
|
3171 |
|
3172 JS_PUBLIC_API(JSObject *) |
|
3173 JS_DefineObject(JSContext *cx, JSObject *objArg, const char *name, const JSClass *jsclasp, |
|
3174 JSObject *protoArg, unsigned attrs) |
|
3175 { |
|
3176 RootedObject obj(cx, objArg); |
|
3177 RootedObject proto(cx, protoArg); |
|
3178 AssertHeapIsIdle(cx); |
|
3179 CHECK_REQUEST(cx); |
|
3180 assertSameCompartment(cx, obj, proto); |
|
3181 |
|
3182 const Class *clasp = Valueify(jsclasp); |
|
3183 if (!clasp) |
|
3184 clasp = &JSObject::class_; /* default class is Object */ |
|
3185 |
|
3186 RootedObject nobj(cx, NewObjectWithClassProto(cx, clasp, proto, obj)); |
|
3187 if (!nobj) |
|
3188 return nullptr; |
|
3189 |
|
3190 RootedValue nobjValue(cx, ObjectValue(*nobj)); |
|
3191 if (!DefineProperty(cx, obj, name, nobjValue, GetterWrapper(nullptr), SetterWrapper(nullptr), |
|
3192 attrs, 0)) { |
|
3193 return nullptr; |
|
3194 } |
|
3195 |
|
3196 return nobj; |
|
3197 } |
|
3198 |
|
3199 JS_PUBLIC_API(bool) |
|
3200 JS_DefineConstDoubles(JSContext *cx, HandleObject obj, const JSConstDoubleSpec *cds) |
|
3201 { |
|
3202 bool ok; |
|
3203 unsigned attrs; |
|
3204 |
|
3205 AssertHeapIsIdle(cx); |
|
3206 CHECK_REQUEST(cx); |
|
3207 JSPropertyOpWrapper noget = GetterWrapper(nullptr); |
|
3208 JSStrictPropertyOpWrapper noset = SetterWrapper(nullptr); |
|
3209 for (ok = true; cds->name; cds++) { |
|
3210 RootedValue value(cx, DoubleValue(cds->dval)); |
|
3211 attrs = cds->flags; |
|
3212 if (!attrs) |
|
3213 attrs = JSPROP_READONLY | JSPROP_PERMANENT; |
|
3214 ok = DefineProperty(cx, obj, cds->name, value, noget, noset, attrs, 0); |
|
3215 if (!ok) |
|
3216 break; |
|
3217 } |
|
3218 return ok; |
|
3219 } |
|
3220 |
|
3221 JS_PUBLIC_API(bool) |
|
3222 JS_DefineProperties(JSContext *cx, HandleObject obj, const JSPropertySpec *ps) |
|
3223 { |
|
3224 bool ok; |
|
3225 for (ok = true; ps->name; ps++) { |
|
3226 if (ps->flags & JSPROP_NATIVE_ACCESSORS) { |
|
3227 // If you declare native accessors, then you should have a native |
|
3228 // getter. |
|
3229 JS_ASSERT(ps->getter.propertyOp.op); |
|
3230 // If you do not have a self-hosted getter, you should not have a |
|
3231 // self-hosted setter. This is the closest approximation to that |
|
3232 // assertion we can have with our setup. |
|
3233 JS_ASSERT_IF(ps->setter.propertyOp.info, ps->setter.propertyOp.op); |
|
3234 |
|
3235 ok = DefineProperty(cx, obj, ps->name, JS::UndefinedHandleValue, |
|
3236 ps->getter.propertyOp, ps->setter.propertyOp, ps->flags, 0); |
|
3237 } else { |
|
3238 // If you have self-hosted getter/setter, you can't have a |
|
3239 // native one. |
|
3240 JS_ASSERT(!ps->getter.propertyOp.op && !ps->setter.propertyOp.op); |
|
3241 JS_ASSERT(ps->flags & JSPROP_GETTER); |
|
3242 /* |
|
3243 * During creation of the self-hosting global, we ignore all |
|
3244 * self-hosted properties, as that means we're currently setting up |
|
3245 * the global object that the self-hosted code is then compiled |
|
3246 * in. That means that Self-hosted properties can't be used in the |
|
3247 * self-hosting global itself, right now. |
|
3248 */ |
|
3249 if (cx->runtime()->isSelfHostingGlobal(cx->global())) |
|
3250 continue; |
|
3251 |
|
3252 ok = DefineSelfHostedProperty(cx, obj, ps->name, |
|
3253 ps->getter.selfHosted.funname, |
|
3254 ps->setter.selfHosted.funname, |
|
3255 ps->flags, 0); |
|
3256 } |
|
3257 if (!ok) |
|
3258 break; |
|
3259 } |
|
3260 return ok; |
|
3261 } |
|
3262 |
|
3263 static bool |
|
3264 GetPropertyDescriptorById(JSContext *cx, HandleObject obj, HandleId id, |
|
3265 MutableHandle<PropertyDescriptor> desc) |
|
3266 { |
|
3267 RootedObject obj2(cx); |
|
3268 RootedShape shape(cx); |
|
3269 |
|
3270 if (!LookupPropertyById(cx, obj, id, &obj2, &shape)) |
|
3271 return false; |
|
3272 |
|
3273 desc.clear(); |
|
3274 if (!shape) |
|
3275 return true; |
|
3276 |
|
3277 desc.object().set(obj2); |
|
3278 if (obj2->isNative()) { |
|
3279 if (IsImplicitDenseOrTypedArrayElement(shape)) { |
|
3280 desc.setEnumerable(); |
|
3281 desc.value().set(obj2->getDenseOrTypedArrayElement(JSID_TO_INT(id))); |
|
3282 } else { |
|
3283 desc.setAttributes(shape->attributes()); |
|
3284 desc.setGetter(shape->getter()); |
|
3285 desc.setSetter(shape->setter()); |
|
3286 JS_ASSERT(desc.value().isUndefined()); |
|
3287 if (shape->hasSlot()) |
|
3288 desc.value().set(obj2->nativeGetSlot(shape->slot())); |
|
3289 } |
|
3290 } else { |
|
3291 if (obj2->is<ProxyObject>()) |
|
3292 return Proxy::getPropertyDescriptor(cx, obj2, id, desc); |
|
3293 if (!JSObject::getGenericAttributes(cx, obj2, id, &desc.attributesRef())) |
|
3294 return false; |
|
3295 JS_ASSERT(desc.getter() == nullptr); |
|
3296 JS_ASSERT(desc.setter() == nullptr); |
|
3297 JS_ASSERT(desc.value().isUndefined()); |
|
3298 } |
|
3299 return true; |
|
3300 } |
|
3301 |
|
3302 JS_PUBLIC_API(bool) |
|
3303 JS_GetOwnPropertyDescriptorById(JSContext *cx, HandleObject obj, HandleId id, |
|
3304 MutableHandle<JSPropertyDescriptor> desc) |
|
3305 { |
|
3306 AssertHeapIsIdle(cx); |
|
3307 CHECK_REQUEST(cx); |
|
3308 |
|
3309 return GetOwnPropertyDescriptor(cx, obj, id, desc); |
|
3310 } |
|
3311 |
|
3312 JS_PUBLIC_API(bool) |
|
3313 JS_GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, const char *name, |
|
3314 MutableHandle<JSPropertyDescriptor> desc) |
|
3315 { |
|
3316 JSAtom *atom = Atomize(cx, name, strlen(name)); |
|
3317 if (!atom) |
|
3318 return false; |
|
3319 RootedId id(cx, AtomToId(atom)); |
|
3320 return JS_GetOwnPropertyDescriptorById(cx, obj, id, desc); |
|
3321 } |
|
3322 |
|
3323 JS_PUBLIC_API(bool) |
|
3324 JS_GetPropertyDescriptorById(JSContext *cx, HandleObject obj, HandleId id, |
|
3325 MutableHandle<JSPropertyDescriptor> desc) |
|
3326 { |
|
3327 return GetPropertyDescriptorById(cx, obj, id, desc); |
|
3328 } |
|
3329 |
|
3330 JS_PUBLIC_API(bool) |
|
3331 JS_GetPropertyDescriptor(JSContext *cx, HandleObject obj, const char *name, |
|
3332 MutableHandle<JSPropertyDescriptor> desc) |
|
3333 { |
|
3334 JSAtom *atom = Atomize(cx, name, strlen(name)); |
|
3335 if (!atom) |
|
3336 return false; |
|
3337 RootedId id(cx, AtomToId(atom)); |
|
3338 return atom && JS_GetPropertyDescriptorById(cx, obj, id, desc); |
|
3339 } |
|
3340 |
|
3341 JS_PUBLIC_API(bool) |
|
3342 JS_GetPropertyById(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp) |
|
3343 { |
|
3344 return JS_ForwardGetPropertyTo(cx, obj, id, obj, vp); |
|
3345 } |
|
3346 |
|
3347 JS_PUBLIC_API(bool) |
|
3348 JS_ForwardGetPropertyTo(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject onBehalfOf, |
|
3349 JS::MutableHandleValue vp) |
|
3350 { |
|
3351 AssertHeapIsIdle(cx); |
|
3352 CHECK_REQUEST(cx); |
|
3353 assertSameCompartment(cx, obj, id); |
|
3354 assertSameCompartment(cx, onBehalfOf); |
|
3355 |
|
3356 return JSObject::getGeneric(cx, obj, onBehalfOf, id, vp); |
|
3357 } |
|
3358 |
|
3359 JS_PUBLIC_API(bool) |
|
3360 JS_GetElement(JSContext *cx, HandleObject objArg, uint32_t index, MutableHandleValue vp) |
|
3361 { |
|
3362 return JS_ForwardGetElementTo(cx, objArg, index, objArg, vp); |
|
3363 } |
|
3364 |
|
3365 JS_PUBLIC_API(bool) |
|
3366 JS_ForwardGetElementTo(JSContext *cx, HandleObject obj, uint32_t index, HandleObject onBehalfOf, |
|
3367 MutableHandleValue vp) |
|
3368 { |
|
3369 AssertHeapIsIdle(cx); |
|
3370 CHECK_REQUEST(cx); |
|
3371 assertSameCompartment(cx, obj); |
|
3372 |
|
3373 return JSObject::getElement(cx, obj, onBehalfOf, index, vp); |
|
3374 } |
|
3375 |
|
3376 JS_PUBLIC_API(bool) |
|
3377 JS_GetProperty(JSContext *cx, HandleObject obj, const char *name, MutableHandleValue vp) |
|
3378 { |
|
3379 JSAtom *atom = Atomize(cx, name, strlen(name)); |
|
3380 if (!atom) |
|
3381 return false; |
|
3382 RootedId id(cx, AtomToId(atom)); |
|
3383 return JS_GetPropertyById(cx, obj, id, vp); |
|
3384 } |
|
3385 |
|
3386 JS_PUBLIC_API(bool) |
|
3387 JS_GetUCProperty(JSContext *cx, HandleObject obj, const jschar *name, size_t namelen, |
|
3388 MutableHandleValue vp) |
|
3389 { |
|
3390 JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); |
|
3391 if (!atom) |
|
3392 return false; |
|
3393 RootedId id(cx, AtomToId(atom)); |
|
3394 return JS_GetPropertyById(cx, obj, id, vp); |
|
3395 } |
|
3396 |
|
3397 JS_PUBLIC_API(bool) |
|
3398 JS_SetPropertyById(JSContext *cx, HandleObject obj, HandleId id, HandleValue v) |
|
3399 { |
|
3400 RootedValue value(cx, v); |
|
3401 AssertHeapIsIdle(cx); |
|
3402 CHECK_REQUEST(cx); |
|
3403 assertSameCompartment(cx, obj, id); |
|
3404 |
|
3405 return JSObject::setGeneric(cx, obj, obj, id, &value, false); |
|
3406 } |
|
3407 |
|
3408 static bool |
|
3409 SetElement(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleValue vp) |
|
3410 { |
|
3411 AssertHeapIsIdle(cx); |
|
3412 CHECK_REQUEST(cx); |
|
3413 assertSameCompartment(cx, obj, vp); |
|
3414 |
|
3415 return JSObject::setElement(cx, obj, obj, index, vp, false); |
|
3416 } |
|
3417 |
|
3418 JS_PUBLIC_API(bool) |
|
3419 JS_SetElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue v) |
|
3420 { |
|
3421 RootedValue value(cx, v); |
|
3422 return SetElement(cx, obj, index, &value); |
|
3423 } |
|
3424 |
|
3425 JS_PUBLIC_API(bool) |
|
3426 JS_SetElement(JSContext *cx, HandleObject obj, uint32_t index, HandleObject v) |
|
3427 { |
|
3428 RootedValue value(cx, ObjectOrNullValue(v)); |
|
3429 return SetElement(cx, obj, index, &value); |
|
3430 } |
|
3431 |
|
3432 JS_PUBLIC_API(bool) |
|
3433 JS_SetElement(JSContext *cx, HandleObject obj, uint32_t index, HandleString v) |
|
3434 { |
|
3435 RootedValue value(cx, StringValue(v)); |
|
3436 return SetElement(cx, obj, index, &value); |
|
3437 } |
|
3438 |
|
3439 JS_PUBLIC_API(bool) |
|
3440 JS_SetElement(JSContext *cx, HandleObject obj, uint32_t index, int32_t v) |
|
3441 { |
|
3442 RootedValue value(cx, NumberValue(v)); |
|
3443 return SetElement(cx, obj, index, &value); |
|
3444 } |
|
3445 |
|
3446 JS_PUBLIC_API(bool) |
|
3447 JS_SetElement(JSContext *cx, HandleObject obj, uint32_t index, uint32_t v) |
|
3448 { |
|
3449 RootedValue value(cx, NumberValue(v)); |
|
3450 return SetElement(cx, obj, index, &value); |
|
3451 } |
|
3452 |
|
3453 JS_PUBLIC_API(bool) |
|
3454 JS_SetElement(JSContext *cx, HandleObject obj, uint32_t index, double v) |
|
3455 { |
|
3456 RootedValue value(cx, NumberValue(v)); |
|
3457 return SetElement(cx, obj, index, &value); |
|
3458 } |
|
3459 |
|
3460 JS_PUBLIC_API(bool) |
|
3461 JS_SetProperty(JSContext *cx, HandleObject obj, const char *name, HandleValue v) |
|
3462 { |
|
3463 JSAtom *atom = Atomize(cx, name, strlen(name)); |
|
3464 if (!atom) |
|
3465 return false; |
|
3466 RootedId id(cx, AtomToId(atom)); |
|
3467 return JS_SetPropertyById(cx, obj, id, v); |
|
3468 } |
|
3469 |
|
3470 JS_PUBLIC_API(bool) |
|
3471 JS_SetUCProperty(JSContext *cx, HandleObject obj, const jschar *name, size_t namelen, |
|
3472 HandleValue v) |
|
3473 { |
|
3474 JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); |
|
3475 if (!atom) |
|
3476 return false; |
|
3477 RootedId id(cx, AtomToId(atom)); |
|
3478 return JS_SetPropertyById(cx, obj, id, v); |
|
3479 } |
|
3480 |
|
3481 JS_PUBLIC_API(bool) |
|
3482 JS_DeletePropertyById2(JSContext *cx, HandleObject obj, HandleId id, bool *result) |
|
3483 { |
|
3484 AssertHeapIsIdle(cx); |
|
3485 CHECK_REQUEST(cx); |
|
3486 assertSameCompartment(cx, obj, id); |
|
3487 |
|
3488 return JSObject::deleteByValue(cx, obj, IdToValue(id), result); |
|
3489 } |
|
3490 |
|
3491 JS_PUBLIC_API(bool) |
|
3492 JS_DeleteElement2(JSContext *cx, HandleObject obj, uint32_t index, bool *result) |
|
3493 { |
|
3494 AssertHeapIsIdle(cx); |
|
3495 CHECK_REQUEST(cx); |
|
3496 assertSameCompartment(cx, obj); |
|
3497 |
|
3498 return JSObject::deleteElement(cx, obj, index, result); |
|
3499 } |
|
3500 |
|
3501 JS_PUBLIC_API(bool) |
|
3502 JS_DeleteProperty2(JSContext *cx, HandleObject obj, const char *name, bool *result) |
|
3503 { |
|
3504 CHECK_REQUEST(cx); |
|
3505 assertSameCompartment(cx, obj); |
|
3506 |
|
3507 JSAtom *atom = Atomize(cx, name, strlen(name)); |
|
3508 if (!atom) |
|
3509 return false; |
|
3510 return JSObject::deleteByValue(cx, obj, StringValue(atom), result); |
|
3511 } |
|
3512 |
|
3513 JS_PUBLIC_API(bool) |
|
3514 JS_DeleteUCProperty2(JSContext *cx, HandleObject obj, const jschar *name, size_t namelen, |
|
3515 bool *result) |
|
3516 { |
|
3517 CHECK_REQUEST(cx); |
|
3518 assertSameCompartment(cx, obj); |
|
3519 |
|
3520 JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); |
|
3521 if (!atom) |
|
3522 return false; |
|
3523 return JSObject::deleteByValue(cx, obj, StringValue(atom), result); |
|
3524 } |
|
3525 |
|
3526 JS_PUBLIC_API(bool) |
|
3527 JS_DeletePropertyById(JSContext *cx, HandleObject obj, HandleId id) |
|
3528 { |
|
3529 bool junk; |
|
3530 return JS_DeletePropertyById2(cx, obj, id, &junk); |
|
3531 } |
|
3532 |
|
3533 JS_PUBLIC_API(bool) |
|
3534 JS_DeleteElement(JSContext *cx, HandleObject obj, uint32_t index) |
|
3535 { |
|
3536 bool junk; |
|
3537 return JS_DeleteElement2(cx, obj, index, &junk); |
|
3538 } |
|
3539 |
|
3540 JS_PUBLIC_API(bool) |
|
3541 JS_DeleteProperty(JSContext *cx, HandleObject obj, const char *name) |
|
3542 { |
|
3543 bool junk; |
|
3544 return JS_DeleteProperty2(cx, obj, name, &junk); |
|
3545 } |
|
3546 |
|
3547 static Shape * |
|
3548 LastConfigurableShape(JSObject *obj) |
|
3549 { |
|
3550 for (Shape::Range<NoGC> r(obj->lastProperty()); !r.empty(); r.popFront()) { |
|
3551 Shape *shape = &r.front(); |
|
3552 if (shape->configurable()) |
|
3553 return shape; |
|
3554 } |
|
3555 return nullptr; |
|
3556 } |
|
3557 |
|
3558 JS_PUBLIC_API(void) |
|
3559 JS_ClearNonGlobalObject(JSContext *cx, HandleObject obj) |
|
3560 { |
|
3561 AssertHeapIsIdle(cx); |
|
3562 CHECK_REQUEST(cx); |
|
3563 assertSameCompartment(cx, obj); |
|
3564 |
|
3565 JS_ASSERT(!obj->is<GlobalObject>()); |
|
3566 |
|
3567 if (!obj->isNative()) |
|
3568 return; |
|
3569 |
|
3570 /* Remove all configurable properties from obj. */ |
|
3571 RootedShape shape(cx); |
|
3572 while ((shape = LastConfigurableShape(obj))) { |
|
3573 if (!obj->removeProperty(cx, shape->propid())) |
|
3574 return; |
|
3575 } |
|
3576 |
|
3577 /* Set all remaining writable plain data properties to undefined. */ |
|
3578 for (Shape::Range<NoGC> r(obj->lastProperty()); !r.empty(); r.popFront()) { |
|
3579 Shape *shape = &r.front(); |
|
3580 if (shape->isDataDescriptor() && |
|
3581 shape->writable() && |
|
3582 shape->hasDefaultSetter() && |
|
3583 shape->hasSlot()) |
|
3584 { |
|
3585 obj->nativeSetSlot(shape->slot(), UndefinedValue()); |
|
3586 } |
|
3587 } |
|
3588 } |
|
3589 |
|
3590 JS_PUBLIC_API(void) |
|
3591 JS_SetAllNonReservedSlotsToUndefined(JSContext *cx, JSObject *objArg) |
|
3592 { |
|
3593 RootedObject obj(cx, objArg); |
|
3594 AssertHeapIsIdle(cx); |
|
3595 CHECK_REQUEST(cx); |
|
3596 assertSameCompartment(cx, obj); |
|
3597 |
|
3598 if (!obj->isNative()) |
|
3599 return; |
|
3600 |
|
3601 const Class *clasp = obj->getClass(); |
|
3602 unsigned numReserved = JSCLASS_RESERVED_SLOTS(clasp); |
|
3603 unsigned numSlots = obj->slotSpan(); |
|
3604 for (unsigned i = numReserved; i < numSlots; i++) |
|
3605 obj->setSlot(i, UndefinedValue()); |
|
3606 } |
|
3607 |
|
3608 JS_PUBLIC_API(JSIdArray *) |
|
3609 JS_Enumerate(JSContext *cx, HandleObject obj) |
|
3610 { |
|
3611 AssertHeapIsIdle(cx); |
|
3612 CHECK_REQUEST(cx); |
|
3613 assertSameCompartment(cx, obj); |
|
3614 |
|
3615 AutoIdVector props(cx); |
|
3616 JSIdArray *ida; |
|
3617 if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &props) || !VectorToIdArray(cx, props, &ida)) |
|
3618 return nullptr; |
|
3619 return ida; |
|
3620 } |
|
3621 |
|
3622 /* |
|
3623 * XXX reverse iterator for properties, unreverse and meld with jsinterp.c's |
|
3624 * prop_iterator_class somehow... |
|
3625 * + preserve the obj->enumerate API while optimizing the native object case |
|
3626 * + native case here uses a JSShape *, but that iterates in reverse! |
|
3627 * + so we make non-native match, by reverse-iterating after JS_Enumerating |
|
3628 */ |
|
3629 static const uint32_t JSSLOT_ITER_INDEX = 0; |
|
3630 |
|
3631 static void |
|
3632 prop_iter_finalize(FreeOp *fop, JSObject *obj) |
|
3633 { |
|
3634 void *pdata = obj->getPrivate(); |
|
3635 if (!pdata) |
|
3636 return; |
|
3637 |
|
3638 if (obj->getSlot(JSSLOT_ITER_INDEX).toInt32() >= 0) { |
|
3639 /* Non-native case: destroy the ida enumerated when obj was created. */ |
|
3640 JSIdArray *ida = (JSIdArray *) pdata; |
|
3641 fop->free_(ida); |
|
3642 } |
|
3643 } |
|
3644 |
|
3645 static void |
|
3646 prop_iter_trace(JSTracer *trc, JSObject *obj) |
|
3647 { |
|
3648 void *pdata = obj->getPrivate(); |
|
3649 if (!pdata) |
|
3650 return; |
|
3651 |
|
3652 if (obj->getSlot(JSSLOT_ITER_INDEX).toInt32() < 0) { |
|
3653 /* |
|
3654 * Native case: just mark the next property to visit. We don't need a |
|
3655 * barrier here because the pointer is updated via setPrivate, which |
|
3656 * always takes a barrier. |
|
3657 */ |
|
3658 Shape *tmp = static_cast<Shape *>(pdata); |
|
3659 MarkShapeUnbarriered(trc, &tmp, "prop iter shape"); |
|
3660 obj->setPrivateUnbarriered(tmp); |
|
3661 } else { |
|
3662 /* Non-native case: mark each id in the JSIdArray private. */ |
|
3663 JSIdArray *ida = (JSIdArray *) pdata; |
|
3664 MarkIdRange(trc, ida->length, ida->vector, "prop iter"); |
|
3665 } |
|
3666 } |
|
3667 |
|
3668 static const Class prop_iter_class = { |
|
3669 "PropertyIterator", |
|
3670 JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(1), |
|
3671 JS_PropertyStub, /* addProperty */ |
|
3672 JS_DeletePropertyStub, /* delProperty */ |
|
3673 JS_PropertyStub, /* getProperty */ |
|
3674 JS_StrictPropertyStub, /* setProperty */ |
|
3675 JS_EnumerateStub, |
|
3676 JS_ResolveStub, |
|
3677 JS_ConvertStub, |
|
3678 prop_iter_finalize, |
|
3679 nullptr, /* call */ |
|
3680 nullptr, /* hasInstance */ |
|
3681 nullptr, /* construct */ |
|
3682 prop_iter_trace |
|
3683 }; |
|
3684 |
|
3685 JS_PUBLIC_API(JSObject *) |
|
3686 JS_NewPropertyIterator(JSContext *cx, HandleObject obj) |
|
3687 { |
|
3688 AssertHeapIsIdle(cx); |
|
3689 CHECK_REQUEST(cx); |
|
3690 assertSameCompartment(cx, obj); |
|
3691 |
|
3692 RootedObject iterobj(cx, NewObjectWithClassProto(cx, &prop_iter_class, nullptr, obj)); |
|
3693 if (!iterobj) |
|
3694 return nullptr; |
|
3695 |
|
3696 int index; |
|
3697 if (obj->isNative()) { |
|
3698 /* Native case: start with the last property in obj. */ |
|
3699 iterobj->setPrivateGCThing(obj->lastProperty()); |
|
3700 index = -1; |
|
3701 } else { |
|
3702 /* Non-native case: enumerate a JSIdArray and keep it via private. */ |
|
3703 JSIdArray *ida = JS_Enumerate(cx, obj); |
|
3704 if (!ida) |
|
3705 return nullptr; |
|
3706 iterobj->setPrivate((void *)ida); |
|
3707 index = ida->length; |
|
3708 } |
|
3709 |
|
3710 /* iterobj cannot escape to other threads here. */ |
|
3711 iterobj->setSlot(JSSLOT_ITER_INDEX, Int32Value(index)); |
|
3712 return iterobj; |
|
3713 } |
|
3714 |
|
3715 JS_PUBLIC_API(bool) |
|
3716 JS_NextProperty(JSContext *cx, HandleObject iterobj, jsid *idp) |
|
3717 { |
|
3718 AssertHeapIsIdle(cx); |
|
3719 CHECK_REQUEST(cx); |
|
3720 assertSameCompartment(cx, iterobj); |
|
3721 int32_t i = iterobj->getSlot(JSSLOT_ITER_INDEX).toInt32(); |
|
3722 if (i < 0) { |
|
3723 /* Native case: private data is a property tree node pointer. */ |
|
3724 JS_ASSERT(iterobj->getParent()->isNative()); |
|
3725 Shape *shape = static_cast<Shape *>(iterobj->getPrivate()); |
|
3726 |
|
3727 while (shape->previous() && !shape->enumerable()) |
|
3728 shape = shape->previous(); |
|
3729 |
|
3730 if (!shape->previous()) { |
|
3731 JS_ASSERT(shape->isEmptyShape()); |
|
3732 *idp = JSID_VOID; |
|
3733 } else { |
|
3734 iterobj->setPrivateGCThing(const_cast<Shape *>(shape->previous().get())); |
|
3735 *idp = shape->propid(); |
|
3736 } |
|
3737 } else { |
|
3738 /* Non-native case: use the ida enumerated when iterobj was created. */ |
|
3739 JSIdArray *ida = (JSIdArray *) iterobj->getPrivate(); |
|
3740 JS_ASSERT(i <= ida->length); |
|
3741 STATIC_ASSUME(i <= ida->length); |
|
3742 if (i == 0) { |
|
3743 *idp = JSID_VOID; |
|
3744 } else { |
|
3745 *idp = ida->vector[--i]; |
|
3746 iterobj->setSlot(JSSLOT_ITER_INDEX, Int32Value(i)); |
|
3747 } |
|
3748 } |
|
3749 return true; |
|
3750 } |
|
3751 |
|
3752 JS_PUBLIC_API(jsval) |
|
3753 JS_GetReservedSlot(JSObject *obj, uint32_t index) |
|
3754 { |
|
3755 return obj->getReservedSlot(index); |
|
3756 } |
|
3757 |
|
3758 JS_PUBLIC_API(void) |
|
3759 JS_SetReservedSlot(JSObject *obj, uint32_t index, Value value) |
|
3760 { |
|
3761 obj->setReservedSlot(index, value); |
|
3762 } |
|
3763 |
|
3764 JS_PUBLIC_API(JSObject *) |
|
3765 JS_NewArrayObject(JSContext *cx, const JS::HandleValueArray& contents) |
|
3766 { |
|
3767 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); |
|
3768 AssertHeapIsIdle(cx); |
|
3769 CHECK_REQUEST(cx); |
|
3770 |
|
3771 assertSameCompartment(cx, contents); |
|
3772 return NewDenseCopiedArray(cx, contents.length(), contents.begin()); |
|
3773 } |
|
3774 |
|
3775 JS_PUBLIC_API(JSObject *) |
|
3776 JS_NewArrayObject(JSContext *cx, size_t length) |
|
3777 { |
|
3778 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); |
|
3779 AssertHeapIsIdle(cx); |
|
3780 CHECK_REQUEST(cx); |
|
3781 |
|
3782 return NewDenseAllocatedArray(cx, length); |
|
3783 } |
|
3784 |
|
3785 JS_PUBLIC_API(bool) |
|
3786 JS_IsArrayObject(JSContext *cx, JS::HandleObject obj) |
|
3787 { |
|
3788 assertSameCompartment(cx, obj); |
|
3789 return ObjectClassIs(obj, ESClass_Array, cx); |
|
3790 } |
|
3791 |
|
3792 JS_PUBLIC_API(bool) |
|
3793 JS_IsArrayObject(JSContext *cx, JS::HandleValue value) |
|
3794 { |
|
3795 if (!value.isObject()) |
|
3796 return false; |
|
3797 RootedObject obj(cx, &value.toObject()); |
|
3798 return JS_IsArrayObject(cx, obj); |
|
3799 } |
|
3800 |
|
3801 JS_PUBLIC_API(bool) |
|
3802 JS_GetArrayLength(JSContext *cx, HandleObject obj, uint32_t *lengthp) |
|
3803 { |
|
3804 AssertHeapIsIdle(cx); |
|
3805 CHECK_REQUEST(cx); |
|
3806 assertSameCompartment(cx, obj); |
|
3807 return GetLengthProperty(cx, obj, lengthp); |
|
3808 } |
|
3809 |
|
3810 JS_PUBLIC_API(bool) |
|
3811 JS_SetArrayLength(JSContext *cx, HandleObject obj, uint32_t length) |
|
3812 { |
|
3813 AssertHeapIsIdle(cx); |
|
3814 CHECK_REQUEST(cx); |
|
3815 assertSameCompartment(cx, obj); |
|
3816 return SetLengthProperty(cx, obj, length); |
|
3817 } |
|
3818 |
|
3819 JS_PUBLIC_API(void) |
|
3820 JS_HoldPrincipals(JSPrincipals *principals) |
|
3821 { |
|
3822 ++principals->refcount; |
|
3823 } |
|
3824 |
|
3825 JS_PUBLIC_API(void) |
|
3826 JS_DropPrincipals(JSRuntime *rt, JSPrincipals *principals) |
|
3827 { |
|
3828 int rc = --principals->refcount; |
|
3829 if (rc == 0) |
|
3830 rt->destroyPrincipals(principals); |
|
3831 } |
|
3832 |
|
3833 JS_PUBLIC_API(void) |
|
3834 JS_SetSecurityCallbacks(JSRuntime *rt, const JSSecurityCallbacks *scb) |
|
3835 { |
|
3836 JS_ASSERT(scb != &NullSecurityCallbacks); |
|
3837 rt->securityCallbacks = scb ? scb : &NullSecurityCallbacks; |
|
3838 } |
|
3839 |
|
3840 JS_PUBLIC_API(const JSSecurityCallbacks *) |
|
3841 JS_GetSecurityCallbacks(JSRuntime *rt) |
|
3842 { |
|
3843 return (rt->securityCallbacks != &NullSecurityCallbacks) ? rt->securityCallbacks : nullptr; |
|
3844 } |
|
3845 |
|
3846 JS_PUBLIC_API(void) |
|
3847 JS_SetTrustedPrincipals(JSRuntime *rt, const JSPrincipals *prin) |
|
3848 { |
|
3849 rt->setTrustedPrincipals(prin); |
|
3850 } |
|
3851 |
|
3852 extern JS_PUBLIC_API(void) |
|
3853 JS_InitDestroyPrincipalsCallback(JSRuntime *rt, JSDestroyPrincipalsOp destroyPrincipals) |
|
3854 { |
|
3855 JS_ASSERT(destroyPrincipals); |
|
3856 JS_ASSERT(!rt->destroyPrincipals); |
|
3857 rt->destroyPrincipals = destroyPrincipals; |
|
3858 } |
|
3859 |
|
3860 JS_PUBLIC_API(JSFunction *) |
|
3861 JS_NewFunction(JSContext *cx, JSNative native, unsigned nargs, unsigned flags, |
|
3862 HandleObject parent, const char *name) |
|
3863 { |
|
3864 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); |
|
3865 |
|
3866 AssertHeapIsIdle(cx); |
|
3867 CHECK_REQUEST(cx); |
|
3868 assertSameCompartment(cx, parent); |
|
3869 |
|
3870 RootedAtom atom(cx); |
|
3871 if (name) { |
|
3872 atom = Atomize(cx, name, strlen(name)); |
|
3873 if (!atom) |
|
3874 return nullptr; |
|
3875 } |
|
3876 |
|
3877 JSFunction::Flags funFlags = JSAPIToJSFunctionFlags(flags); |
|
3878 return NewFunction(cx, NullPtr(), native, nargs, funFlags, parent, atom); |
|
3879 } |
|
3880 |
|
3881 JS_PUBLIC_API(JSFunction *) |
|
3882 JS_NewFunctionById(JSContext *cx, JSNative native, unsigned nargs, unsigned flags, |
|
3883 HandleObject parent, HandleId id) |
|
3884 { |
|
3885 JS_ASSERT(JSID_IS_STRING(id)); |
|
3886 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); |
|
3887 JS_ASSERT(native); |
|
3888 AssertHeapIsIdle(cx); |
|
3889 CHECK_REQUEST(cx); |
|
3890 assertSameCompartment(cx, parent); |
|
3891 |
|
3892 RootedAtom name(cx, JSID_TO_ATOM(id)); |
|
3893 JSFunction::Flags funFlags = JSAPIToJSFunctionFlags(flags); |
|
3894 return NewFunction(cx, NullPtr(), native, nargs, funFlags, parent, name); |
|
3895 } |
|
3896 |
|
3897 JS_PUBLIC_API(JSFunction *) |
|
3898 JS::GetSelfHostedFunction(JSContext *cx, const char *selfHostedName, HandleId id, unsigned nargs) |
|
3899 { |
|
3900 JS_ASSERT(JSID_IS_STRING(id)); |
|
3901 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); |
|
3902 AssertHeapIsIdle(cx); |
|
3903 CHECK_REQUEST(cx); |
|
3904 |
|
3905 RootedAtom name(cx, JSID_TO_ATOM(id)); |
|
3906 RootedAtom shName(cx, Atomize(cx, selfHostedName, strlen(selfHostedName))); |
|
3907 if (!shName) |
|
3908 return nullptr; |
|
3909 RootedValue funVal(cx); |
|
3910 if (!cx->global()->getSelfHostedFunction(cx, shName, name, nargs, &funVal)) |
|
3911 return nullptr; |
|
3912 return &funVal.toObject().as<JSFunction>(); |
|
3913 } |
|
3914 |
|
3915 JS_PUBLIC_API(JSObject *) |
|
3916 JS_CloneFunctionObject(JSContext *cx, HandleObject funobj, HandleObject parentArg) |
|
3917 { |
|
3918 RootedObject parent(cx, parentArg); |
|
3919 |
|
3920 AssertHeapIsIdle(cx); |
|
3921 CHECK_REQUEST(cx); |
|
3922 assertSameCompartment(cx, parent); |
|
3923 // Note that funobj can be in a different compartment. |
|
3924 |
|
3925 if (!parent) |
|
3926 parent = cx->global(); |
|
3927 |
|
3928 if (!funobj->is<JSFunction>()) { |
|
3929 AutoCompartment ac(cx, funobj); |
|
3930 RootedValue v(cx, ObjectValue(*funobj)); |
|
3931 ReportIsNotFunction(cx, v); |
|
3932 return nullptr; |
|
3933 } |
|
3934 |
|
3935 RootedFunction fun(cx, &funobj->as<JSFunction>()); |
|
3936 if (fun->isInterpretedLazy()) { |
|
3937 AutoCompartment ac(cx, funobj); |
|
3938 if (!fun->getOrCreateScript(cx)) |
|
3939 return nullptr; |
|
3940 } |
|
3941 /* |
|
3942 * If a function was compiled to be lexically nested inside some other |
|
3943 * script, we cannot clone it without breaking the compiler's assumptions. |
|
3944 */ |
|
3945 if (fun->isInterpreted() && (fun->nonLazyScript()->enclosingStaticScope() || |
|
3946 (fun->nonLazyScript()->compileAndGo() && !parent->is<GlobalObject>()))) |
|
3947 { |
|
3948 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_CLONE_FUNOBJ_SCOPE); |
|
3949 return nullptr; |
|
3950 } |
|
3951 |
|
3952 if (fun->isBoundFunction()) { |
|
3953 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_CLONE_OBJECT); |
|
3954 return nullptr; |
|
3955 } |
|
3956 |
|
3957 if (fun->isNative() && IsAsmJSModuleNative(fun->native())) { |
|
3958 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_CLONE_OBJECT); |
|
3959 return nullptr; |
|
3960 } |
|
3961 |
|
3962 return CloneFunctionObject(cx, fun, parent, fun->getAllocKind()); |
|
3963 } |
|
3964 |
|
3965 JS_PUBLIC_API(JSObject *) |
|
3966 JS_GetFunctionObject(JSFunction *fun) |
|
3967 { |
|
3968 return fun; |
|
3969 } |
|
3970 |
|
3971 JS_PUBLIC_API(JSString *) |
|
3972 JS_GetFunctionId(JSFunction *fun) |
|
3973 { |
|
3974 return fun->atom(); |
|
3975 } |
|
3976 |
|
3977 JS_PUBLIC_API(JSString *) |
|
3978 JS_GetFunctionDisplayId(JSFunction *fun) |
|
3979 { |
|
3980 return fun->displayAtom(); |
|
3981 } |
|
3982 |
|
3983 JS_PUBLIC_API(uint16_t) |
|
3984 JS_GetFunctionArity(JSFunction *fun) |
|
3985 { |
|
3986 return fun->nargs(); |
|
3987 } |
|
3988 |
|
3989 JS_PUBLIC_API(bool) |
|
3990 JS_ObjectIsFunction(JSContext *cx, JSObject *obj) |
|
3991 { |
|
3992 return obj->is<JSFunction>(); |
|
3993 } |
|
3994 |
|
3995 JS_PUBLIC_API(bool) |
|
3996 JS_ObjectIsCallable(JSContext *cx, JSObject *obj) |
|
3997 { |
|
3998 return obj->isCallable(); |
|
3999 } |
|
4000 |
|
4001 JS_PUBLIC_API(bool) |
|
4002 JS_IsNativeFunction(JSObject *funobj, JSNative call) |
|
4003 { |
|
4004 if (!funobj->is<JSFunction>()) |
|
4005 return false; |
|
4006 JSFunction *fun = &funobj->as<JSFunction>(); |
|
4007 return fun->isNative() && fun->native() == call; |
|
4008 } |
|
4009 |
|
4010 extern JS_PUBLIC_API(bool) |
|
4011 JS_IsConstructor(JSFunction *fun) |
|
4012 { |
|
4013 return fun->isNativeConstructor() || fun->isInterpretedConstructor(); |
|
4014 } |
|
4015 |
|
4016 JS_PUBLIC_API(JSObject*) |
|
4017 JS_BindCallable(JSContext *cx, HandleObject target, HandleObject newThis) |
|
4018 { |
|
4019 RootedValue thisArg(cx, ObjectValue(*newThis)); |
|
4020 return js_fun_bind(cx, target, thisArg, nullptr, 0); |
|
4021 } |
|
4022 |
|
4023 static bool |
|
4024 js_generic_native_method_dispatcher(JSContext *cx, unsigned argc, Value *vp) |
|
4025 { |
|
4026 CallArgs args = CallArgsFromVp(argc, vp); |
|
4027 |
|
4028 const JSFunctionSpec *fs = (JSFunctionSpec *) |
|
4029 args.callee().as<JSFunction>().getExtendedSlot(0).toPrivate(); |
|
4030 JS_ASSERT((fs->flags & JSFUN_GENERIC_NATIVE) != 0); |
|
4031 |
|
4032 if (argc < 1) { |
|
4033 js_ReportMissingArg(cx, args.calleev(), 0); |
|
4034 return false; |
|
4035 } |
|
4036 |
|
4037 /* |
|
4038 * Copy all actual (argc) arguments down over our |this| parameter, vp[1], |
|
4039 * which is almost always the class constructor object, e.g. Array. Then |
|
4040 * call the corresponding prototype native method with our first argument |
|
4041 * passed as |this|. |
|
4042 */ |
|
4043 memmove(vp + 1, vp + 2, argc * sizeof(jsval)); |
|
4044 |
|
4045 /* Clear the last parameter in case too few arguments were passed. */ |
|
4046 vp[2 + --argc].setUndefined(); |
|
4047 |
|
4048 return fs->call.op(cx, argc, vp); |
|
4049 } |
|
4050 |
|
4051 JS_PUBLIC_API(bool) |
|
4052 JS_DefineFunctions(JSContext *cx, HandleObject obj, const JSFunctionSpec *fs) |
|
4053 { |
|
4054 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); |
|
4055 AssertHeapIsIdle(cx); |
|
4056 CHECK_REQUEST(cx); |
|
4057 assertSameCompartment(cx, obj); |
|
4058 |
|
4059 RootedObject ctor(cx); |
|
4060 |
|
4061 for (; fs->name; fs++) { |
|
4062 RootedAtom atom(cx); |
|
4063 // If the name starts with "@@", it must be a well-known symbol. |
|
4064 if (fs->name[0] != '@' || fs->name[1] != '@') |
|
4065 atom = Atomize(cx, fs->name, strlen(fs->name)); |
|
4066 else if (strcmp(fs->name, "@@iterator") == 0) |
|
4067 // FIXME: This atom should be a symbol: bug 918828. |
|
4068 atom = cx->names().std_iterator; |
|
4069 else |
|
4070 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_SYMBOL, fs->name); |
|
4071 if (!atom) |
|
4072 return false; |
|
4073 |
|
4074 Rooted<jsid> id(cx, AtomToId(atom)); |
|
4075 |
|
4076 /* |
|
4077 * Define a generic arity N+1 static method for the arity N prototype |
|
4078 * method if flags contains JSFUN_GENERIC_NATIVE. |
|
4079 */ |
|
4080 unsigned flags = fs->flags; |
|
4081 if (flags & JSFUN_GENERIC_NATIVE) { |
|
4082 if (!ctor) { |
|
4083 ctor = JS_GetConstructor(cx, obj); |
|
4084 if (!ctor) |
|
4085 return false; |
|
4086 } |
|
4087 |
|
4088 flags &= ~JSFUN_GENERIC_NATIVE; |
|
4089 JSFunction *fun = DefineFunction(cx, ctor, id, |
|
4090 js_generic_native_method_dispatcher, |
|
4091 fs->nargs + 1, flags, |
|
4092 JSFunction::ExtendedFinalizeKind); |
|
4093 if (!fun) |
|
4094 return false; |
|
4095 |
|
4096 /* |
|
4097 * As jsapi.h notes, fs must point to storage that lives as long |
|
4098 * as fun->object lives. |
|
4099 */ |
|
4100 fun->setExtendedSlot(0, PrivateValue(const_cast<JSFunctionSpec*>(fs))); |
|
4101 } |
|
4102 |
|
4103 /* |
|
4104 * Delay cloning self-hosted functions until they are called. This is |
|
4105 * achieved by passing DefineFunction a nullptr JSNative which |
|
4106 * produces an interpreted JSFunction where !hasScript. Interpreted |
|
4107 * call paths then call InitializeLazyFunctionScript if !hasScript. |
|
4108 */ |
|
4109 if (fs->selfHostedName) { |
|
4110 JS_ASSERT(!fs->call.op); |
|
4111 JS_ASSERT(!fs->call.info); |
|
4112 /* |
|
4113 * During creation of the self-hosting global, we ignore all |
|
4114 * self-hosted functions, as that means we're currently setting up |
|
4115 * the global object that the self-hosted code is then compiled |
|
4116 * in. Self-hosted functions can access each other via their names, |
|
4117 * but not via the builtin classes they get installed into. |
|
4118 */ |
|
4119 if (cx->runtime()->isSelfHostingGlobal(cx->global())) |
|
4120 continue; |
|
4121 |
|
4122 RootedAtom shName(cx, Atomize(cx, fs->selfHostedName, strlen(fs->selfHostedName))); |
|
4123 if (!shName) |
|
4124 return false; |
|
4125 RootedValue funVal(cx); |
|
4126 if (!cx->global()->getSelfHostedFunction(cx, shName, atom, fs->nargs, &funVal)) |
|
4127 return false; |
|
4128 if (!JSObject::defineGeneric(cx, obj, id, funVal, nullptr, nullptr, flags)) |
|
4129 return false; |
|
4130 } else { |
|
4131 JSFunction *fun = DefineFunction(cx, obj, id, fs->call.op, fs->nargs, flags); |
|
4132 if (!fun) |
|
4133 return false; |
|
4134 if (fs->call.info) |
|
4135 fun->setJitInfo(fs->call.info); |
|
4136 } |
|
4137 } |
|
4138 return true; |
|
4139 } |
|
4140 |
|
4141 JS_PUBLIC_API(JSFunction *) |
|
4142 JS_DefineFunction(JSContext *cx, HandleObject obj, const char *name, JSNative call, |
|
4143 unsigned nargs, unsigned attrs) |
|
4144 { |
|
4145 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); |
|
4146 AssertHeapIsIdle(cx); |
|
4147 CHECK_REQUEST(cx); |
|
4148 assertSameCompartment(cx, obj); |
|
4149 JSAtom *atom = Atomize(cx, name, strlen(name)); |
|
4150 if (!atom) |
|
4151 return nullptr; |
|
4152 Rooted<jsid> id(cx, AtomToId(atom)); |
|
4153 return DefineFunction(cx, obj, id, call, nargs, attrs); |
|
4154 } |
|
4155 |
|
4156 JS_PUBLIC_API(JSFunction *) |
|
4157 JS_DefineUCFunction(JSContext *cx, HandleObject obj, |
|
4158 const jschar *name, size_t namelen, JSNative call, |
|
4159 unsigned nargs, unsigned attrs) |
|
4160 { |
|
4161 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); |
|
4162 AssertHeapIsIdle(cx); |
|
4163 CHECK_REQUEST(cx); |
|
4164 assertSameCompartment(cx, obj); |
|
4165 JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); |
|
4166 if (!atom) |
|
4167 return nullptr; |
|
4168 Rooted<jsid> id(cx, AtomToId(atom)); |
|
4169 return DefineFunction(cx, obj, id, call, nargs, attrs); |
|
4170 } |
|
4171 |
|
4172 extern JS_PUBLIC_API(JSFunction *) |
|
4173 JS_DefineFunctionById(JSContext *cx, HandleObject obj, HandleId id, JSNative call, |
|
4174 unsigned nargs, unsigned attrs) |
|
4175 { |
|
4176 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); |
|
4177 AssertHeapIsIdle(cx); |
|
4178 CHECK_REQUEST(cx); |
|
4179 assertSameCompartment(cx, obj); |
|
4180 return DefineFunction(cx, obj, id, call, nargs, attrs); |
|
4181 } |
|
4182 |
|
4183 struct AutoLastFrameCheck |
|
4184 { |
|
4185 AutoLastFrameCheck(JSContext *cx |
|
4186 MOZ_GUARD_OBJECT_NOTIFIER_PARAM) |
|
4187 : cx(cx) |
|
4188 { |
|
4189 JS_ASSERT(cx); |
|
4190 MOZ_GUARD_OBJECT_NOTIFIER_INIT; |
|
4191 } |
|
4192 |
|
4193 ~AutoLastFrameCheck() { |
|
4194 if (cx->isExceptionPending() && |
|
4195 !JS_IsRunning(cx) && |
|
4196 !cx->options().dontReportUncaught()) { |
|
4197 js_ReportUncaughtException(cx); |
|
4198 } |
|
4199 } |
|
4200 |
|
4201 private: |
|
4202 JSContext *cx; |
|
4203 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER |
|
4204 }; |
|
4205 |
|
4206 /* Use the fastest available getc. */ |
|
4207 #if defined(HAVE_GETC_UNLOCKED) |
|
4208 # define fast_getc getc_unlocked |
|
4209 #elif defined(HAVE__GETC_NOLOCK) |
|
4210 # define fast_getc _getc_nolock |
|
4211 #else |
|
4212 # define fast_getc getc |
|
4213 #endif |
|
4214 |
|
4215 typedef js::Vector<char, 8, TempAllocPolicy> FileContents; |
|
4216 |
|
4217 static bool |
|
4218 ReadCompleteFile(JSContext *cx, FILE *fp, FileContents &buffer) |
|
4219 { |
|
4220 /* Get the complete length of the file, if possible. */ |
|
4221 struct stat st; |
|
4222 int ok = fstat(fileno(fp), &st); |
|
4223 if (ok != 0) |
|
4224 return false; |
|
4225 if (st.st_size > 0) { |
|
4226 if (!buffer.reserve(st.st_size)) |
|
4227 return false; |
|
4228 } |
|
4229 |
|
4230 // Read in the whole file. Note that we can't assume the data's length |
|
4231 // is actually st.st_size, because 1) some files lie about their size |
|
4232 // (/dev/zero and /dev/random), and 2) reading files in text mode on |
|
4233 // Windows collapses "\r\n" pairs to single \n characters. |
|
4234 for (;;) { |
|
4235 int c = fast_getc(fp); |
|
4236 if (c == EOF) |
|
4237 break; |
|
4238 if (!buffer.append(c)) |
|
4239 return false; |
|
4240 } |
|
4241 |
|
4242 return true; |
|
4243 } |
|
4244 |
|
4245 namespace { |
|
4246 |
|
4247 class AutoFile |
|
4248 { |
|
4249 FILE *fp_; |
|
4250 public: |
|
4251 AutoFile() |
|
4252 : fp_(nullptr) |
|
4253 {} |
|
4254 ~AutoFile() |
|
4255 { |
|
4256 if (fp_ && fp_ != stdin) |
|
4257 fclose(fp_); |
|
4258 } |
|
4259 FILE *fp() const { return fp_; } |
|
4260 bool open(JSContext *cx, const char *filename); |
|
4261 bool readAll(JSContext *cx, FileContents &buffer) |
|
4262 { |
|
4263 JS_ASSERT(fp_); |
|
4264 return ReadCompleteFile(cx, fp_, buffer); |
|
4265 } |
|
4266 }; |
|
4267 |
|
4268 } /* anonymous namespace */ |
|
4269 |
|
4270 /* |
|
4271 * Open a source file for reading. Supports "-" and nullptr to mean stdin. The |
|
4272 * return value must be fclosed unless it is stdin. |
|
4273 */ |
|
4274 bool |
|
4275 AutoFile::open(JSContext *cx, const char *filename) |
|
4276 { |
|
4277 if (!filename || strcmp(filename, "-") == 0) { |
|
4278 fp_ = stdin; |
|
4279 } else { |
|
4280 fp_ = fopen(filename, "r"); |
|
4281 if (!fp_) { |
|
4282 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_OPEN, |
|
4283 filename, "No such file or directory"); |
|
4284 return false; |
|
4285 } |
|
4286 } |
|
4287 return true; |
|
4288 } |
|
4289 |
|
4290 JSObject * const JS::ReadOnlyCompileOptions::nullObjectPtr = nullptr; |
|
4291 |
|
4292 void |
|
4293 JS::ReadOnlyCompileOptions::copyPODOptions(const ReadOnlyCompileOptions &rhs) |
|
4294 { |
|
4295 version = rhs.version; |
|
4296 versionSet = rhs.versionSet; |
|
4297 utf8 = rhs.utf8; |
|
4298 lineno = rhs.lineno; |
|
4299 column = rhs.column; |
|
4300 compileAndGo = rhs.compileAndGo; |
|
4301 forEval = rhs.forEval; |
|
4302 noScriptRval = rhs.noScriptRval; |
|
4303 selfHostingMode = rhs.selfHostingMode; |
|
4304 canLazilyParse = rhs.canLazilyParse; |
|
4305 strictOption = rhs.strictOption; |
|
4306 extraWarningsOption = rhs.extraWarningsOption; |
|
4307 werrorOption = rhs.werrorOption; |
|
4308 asmJSOption = rhs.asmJSOption; |
|
4309 forceAsync = rhs.forceAsync; |
|
4310 installedFile = rhs.installedFile; |
|
4311 sourceIsLazy = rhs.sourceIsLazy; |
|
4312 introductionType = rhs.introductionType; |
|
4313 introductionLineno = rhs.introductionLineno; |
|
4314 introductionOffset = rhs.introductionOffset; |
|
4315 hasIntroductionInfo = rhs.hasIntroductionInfo; |
|
4316 } |
|
4317 |
|
4318 JSPrincipals * |
|
4319 JS::ReadOnlyCompileOptions::originPrincipals(ExclusiveContext *cx) const |
|
4320 { |
|
4321 return NormalizeOriginPrincipals(cx->compartment()->principals, originPrincipals_); |
|
4322 } |
|
4323 |
|
4324 JS::OwningCompileOptions::OwningCompileOptions(JSContext *cx) |
|
4325 : ReadOnlyCompileOptions(), |
|
4326 runtime(GetRuntime(cx)), |
|
4327 elementRoot(cx), |
|
4328 elementAttributeNameRoot(cx), |
|
4329 introductionScriptRoot(cx) |
|
4330 { |
|
4331 } |
|
4332 |
|
4333 JS::OwningCompileOptions::~OwningCompileOptions() |
|
4334 { |
|
4335 if (originPrincipals_) |
|
4336 JS_DropPrincipals(runtime, originPrincipals_); |
|
4337 |
|
4338 // OwningCompileOptions always owns these, so these casts are okay. |
|
4339 js_free(const_cast<char *>(filename_)); |
|
4340 js_free(const_cast<jschar *>(sourceMapURL_)); |
|
4341 js_free(const_cast<char *>(introducerFilename_)); |
|
4342 } |
|
4343 |
|
4344 bool |
|
4345 JS::OwningCompileOptions::copy(JSContext *cx, const ReadOnlyCompileOptions &rhs) |
|
4346 { |
|
4347 copyPODOptions(rhs); |
|
4348 |
|
4349 setOriginPrincipals(rhs.originPrincipals(cx)); |
|
4350 setElement(rhs.element()); |
|
4351 setElementAttributeName(rhs.elementAttributeName()); |
|
4352 setIntroductionScript(rhs.introductionScript()); |
|
4353 |
|
4354 return (setFileAndLine(cx, rhs.filename(), rhs.lineno) && |
|
4355 setSourceMapURL(cx, rhs.sourceMapURL()) && |
|
4356 setIntroducerFilename(cx, rhs.introducerFilename())); |
|
4357 } |
|
4358 |
|
4359 bool |
|
4360 JS::OwningCompileOptions::setFile(JSContext *cx, const char *f) |
|
4361 { |
|
4362 char *copy = nullptr; |
|
4363 if (f) { |
|
4364 copy = JS_strdup(cx, f); |
|
4365 if (!copy) |
|
4366 return false; |
|
4367 } |
|
4368 |
|
4369 // OwningCompileOptions always owns filename_, so this cast is okay. |
|
4370 js_free(const_cast<char *>(filename_)); |
|
4371 |
|
4372 filename_ = copy; |
|
4373 return true; |
|
4374 } |
|
4375 |
|
4376 bool |
|
4377 JS::OwningCompileOptions::setFileAndLine(JSContext *cx, const char *f, unsigned l) |
|
4378 { |
|
4379 if (!setFile(cx, f)) |
|
4380 return false; |
|
4381 |
|
4382 lineno = l; |
|
4383 return true; |
|
4384 } |
|
4385 |
|
4386 bool |
|
4387 JS::OwningCompileOptions::setSourceMapURL(JSContext *cx, const jschar *s) |
|
4388 { |
|
4389 jschar *copy = nullptr; |
|
4390 if (s) { |
|
4391 copy = js_strdup(cx, s); |
|
4392 if (!copy) |
|
4393 return false; |
|
4394 } |
|
4395 |
|
4396 // OwningCompileOptions always owns sourceMapURL_, so this cast is okay. |
|
4397 js_free(const_cast<jschar *>(sourceMapURL_)); |
|
4398 |
|
4399 sourceMapURL_ = copy; |
|
4400 return true; |
|
4401 } |
|
4402 |
|
4403 bool |
|
4404 JS::OwningCompileOptions::setIntroducerFilename(JSContext *cx, const char *s) |
|
4405 { |
|
4406 char *copy = nullptr; |
|
4407 if (s) { |
|
4408 copy = JS_strdup(cx, s); |
|
4409 if (!copy) |
|
4410 return false; |
|
4411 } |
|
4412 |
|
4413 // OwningCompileOptions always owns introducerFilename_, so this cast is okay. |
|
4414 js_free(const_cast<char *>(introducerFilename_)); |
|
4415 |
|
4416 introducerFilename_ = copy; |
|
4417 return true; |
|
4418 } |
|
4419 |
|
4420 bool |
|
4421 JS::OwningCompileOptions::wrap(JSContext *cx, JSCompartment *compartment) |
|
4422 { |
|
4423 if (!compartment->wrap(cx, &elementRoot)) |
|
4424 return false; |
|
4425 if (elementAttributeNameRoot) { |
|
4426 if (!compartment->wrap(cx, elementAttributeNameRoot.address())) |
|
4427 return false; |
|
4428 } |
|
4429 |
|
4430 // There is no equivalent of cross-compartment wrappers for scripts. If |
|
4431 // the introduction script would be in a different compartment from the |
|
4432 // compiled code, we would be creating a cross-compartment script |
|
4433 // reference, which would be bogus. In that case, just don't bother to |
|
4434 // retain the introduction script. |
|
4435 if (introductionScriptRoot) { |
|
4436 if (introductionScriptRoot->compartment() != compartment) |
|
4437 introductionScriptRoot = nullptr; |
|
4438 } |
|
4439 |
|
4440 return true; |
|
4441 } |
|
4442 |
|
4443 JS::CompileOptions::CompileOptions(JSContext *cx, JSVersion version) |
|
4444 : ReadOnlyCompileOptions(), elementRoot(cx), elementAttributeNameRoot(cx), |
|
4445 introductionScriptRoot(cx) |
|
4446 { |
|
4447 this->version = (version != JSVERSION_UNKNOWN) ? version : cx->findVersion(); |
|
4448 |
|
4449 compileAndGo = false; |
|
4450 noScriptRval = cx->options().noScriptRval(); |
|
4451 strictOption = cx->options().strictMode(); |
|
4452 extraWarningsOption = cx->options().extraWarnings(); |
|
4453 werrorOption = cx->options().werror(); |
|
4454 asmJSOption = cx->runtime()->options().asmJS(); |
|
4455 } |
|
4456 |
|
4457 bool |
|
4458 JS::CompileOptions::wrap(JSContext *cx, JSCompartment *compartment) |
|
4459 { |
|
4460 if (!compartment->wrap(cx, &elementRoot)) |
|
4461 return false; |
|
4462 if (elementAttributeNameRoot) { |
|
4463 if (!compartment->wrap(cx, elementAttributeNameRoot.address())) |
|
4464 return false; |
|
4465 } |
|
4466 |
|
4467 // There is no equivalent of cross-compartment wrappers for scripts. If |
|
4468 // the introduction script would be in a different compartment from the |
|
4469 // compiled code, we would be creating a cross-compartment script |
|
4470 // reference, which would be bogus. In that case, just don't bother to |
|
4471 // retain the introduction script. |
|
4472 if (introductionScriptRoot) { |
|
4473 if (introductionScriptRoot->compartment() != compartment) |
|
4474 introductionScriptRoot = nullptr; |
|
4475 } |
|
4476 |
|
4477 return true; |
|
4478 } |
|
4479 |
|
4480 bool |
|
4481 JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options, |
|
4482 SourceBufferHolder &srcBuf, MutableHandleScript script) |
|
4483 { |
|
4484 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); |
|
4485 AssertHeapIsIdle(cx); |
|
4486 CHECK_REQUEST(cx); |
|
4487 assertSameCompartment(cx, obj); |
|
4488 AutoLastFrameCheck lfc(cx); |
|
4489 |
|
4490 script.set(frontend::CompileScript(cx, &cx->tempLifoAlloc(), obj, NullPtr(), options, srcBuf)); |
|
4491 return !!script; |
|
4492 } |
|
4493 |
|
4494 JSScript * |
|
4495 JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options, |
|
4496 const jschar *chars, size_t length) |
|
4497 { |
|
4498 SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership); |
|
4499 RootedScript script(cx); |
|
4500 if (!Compile(cx, obj, options, srcBuf, &script)) |
|
4501 return nullptr; |
|
4502 return script; |
|
4503 } |
|
4504 |
|
4505 JSScript * |
|
4506 JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options, |
|
4507 const char *bytes, size_t length) |
|
4508 { |
|
4509 jschar *chars; |
|
4510 if (options.utf8) |
|
4511 chars = UTF8CharsToNewTwoByteCharsZ(cx, UTF8Chars(bytes, length), &length).get(); |
|
4512 else |
|
4513 chars = InflateString(cx, bytes, &length); |
|
4514 if (!chars) |
|
4515 return nullptr; |
|
4516 |
|
4517 JSScript *script = Compile(cx, obj, options, chars, length); |
|
4518 js_free(chars); |
|
4519 return script; |
|
4520 } |
|
4521 |
|
4522 JSScript * |
|
4523 JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options, FILE *fp) |
|
4524 { |
|
4525 FileContents buffer(cx); |
|
4526 if (!ReadCompleteFile(cx, fp, buffer)) |
|
4527 return nullptr; |
|
4528 |
|
4529 JSScript *script = Compile(cx, obj, options, buffer.begin(), buffer.length()); |
|
4530 return script; |
|
4531 } |
|
4532 |
|
4533 JSScript * |
|
4534 JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg, const char *filename) |
|
4535 { |
|
4536 AutoFile file; |
|
4537 if (!file.open(cx, filename)) |
|
4538 return nullptr; |
|
4539 CompileOptions options(cx, optionsArg); |
|
4540 options.setFileAndLine(filename, 1); |
|
4541 return Compile(cx, obj, options, file.fp()); |
|
4542 } |
|
4543 |
|
4544 JS_PUBLIC_API(bool) |
|
4545 JS::CanCompileOffThread(JSContext *cx, const ReadOnlyCompileOptions &options, size_t length) |
|
4546 { |
|
4547 static const size_t TINY_LENGTH = 1000; |
|
4548 static const size_t HUGE_LENGTH = 100 * 1000; |
|
4549 |
|
4550 // These are heuristics which the caller may choose to ignore (e.g., for |
|
4551 // testing purposes). |
|
4552 if (!options.forceAsync) { |
|
4553 // Compiling off the main thread inolves creating a new Zone and other |
|
4554 // significant overheads. Don't bother if the script is tiny. |
|
4555 if (length < TINY_LENGTH) |
|
4556 return false; |
|
4557 |
|
4558 #ifdef JS_THREADSAFE |
|
4559 // If the parsing task would have to wait for GC to complete, it'll probably |
|
4560 // be faster to just start it synchronously on the main thread unless the |
|
4561 // script is huge. |
|
4562 if (OffThreadParsingMustWaitForGC(cx->runtime()) && length < HUGE_LENGTH) |
|
4563 return false; |
|
4564 #endif // JS_THREADSAFE |
|
4565 } |
|
4566 |
|
4567 return cx->runtime()->canUseParallelParsing(); |
|
4568 } |
|
4569 |
|
4570 JS_PUBLIC_API(bool) |
|
4571 JS::CompileOffThread(JSContext *cx, const ReadOnlyCompileOptions &options, |
|
4572 const jschar *chars, size_t length, |
|
4573 OffThreadCompileCallback callback, void *callbackData) |
|
4574 { |
|
4575 JS_ASSERT(CanCompileOffThread(cx, options, length)); |
|
4576 return StartOffThreadParseScript(cx, options, chars, length, callback, callbackData); |
|
4577 } |
|
4578 |
|
4579 JS_PUBLIC_API(JSScript *) |
|
4580 JS::FinishOffThreadScript(JSContext *maybecx, JSRuntime *rt, void *token) |
|
4581 { |
|
4582 #ifdef JS_THREADSAFE |
|
4583 JS_ASSERT(CurrentThreadCanAccessRuntime(rt)); |
|
4584 |
|
4585 if (maybecx) { |
|
4586 RootedScript script(maybecx); |
|
4587 { |
|
4588 AutoLastFrameCheck lfc(maybecx); |
|
4589 script = WorkerThreadState().finishParseTask(maybecx, rt, token); |
|
4590 } |
|
4591 return script; |
|
4592 } else { |
|
4593 return WorkerThreadState().finishParseTask(maybecx, rt, token); |
|
4594 } |
|
4595 #else |
|
4596 MOZ_ASSUME_UNREACHABLE("Off thread compilation is not available."); |
|
4597 #endif |
|
4598 } |
|
4599 |
|
4600 JS_PUBLIC_API(JSScript *) |
|
4601 JS_CompileScript(JSContext *cx, JS::HandleObject obj, const char *ascii, |
|
4602 size_t length, const JS::CompileOptions &options) |
|
4603 { |
|
4604 return Compile(cx, obj, options, ascii, length); |
|
4605 } |
|
4606 |
|
4607 JS_PUBLIC_API(JSScript *) |
|
4608 JS_CompileUCScript(JSContext *cx, JS::HandleObject obj, const jschar *chars, |
|
4609 size_t length, const JS::CompileOptions &options) |
|
4610 { |
|
4611 return Compile(cx, obj, options, chars, length); |
|
4612 } |
|
4613 |
|
4614 JS_PUBLIC_API(bool) |
|
4615 JS_BufferIsCompilableUnit(JSContext *cx, HandleObject obj, const char *utf8, size_t length) |
|
4616 { |
|
4617 AssertHeapIsIdle(cx); |
|
4618 CHECK_REQUEST(cx); |
|
4619 assertSameCompartment(cx, obj); |
|
4620 |
|
4621 cx->clearPendingException(); |
|
4622 |
|
4623 jschar *chars = JS::UTF8CharsToNewTwoByteCharsZ(cx, JS::UTF8Chars(utf8, length), &length).get(); |
|
4624 if (!chars) |
|
4625 return true; |
|
4626 |
|
4627 // Return true on any out-of-memory error or non-EOF-related syntax error, so our |
|
4628 // caller doesn't try to collect more buffered source. |
|
4629 bool result = true; |
|
4630 |
|
4631 CompileOptions options(cx); |
|
4632 options.setCompileAndGo(false); |
|
4633 Parser<frontend::FullParseHandler> parser(cx, &cx->tempLifoAlloc(), |
|
4634 options, chars, length, |
|
4635 /* foldConstants = */ true, nullptr, nullptr); |
|
4636 JSErrorReporter older = JS_SetErrorReporter(cx, nullptr); |
|
4637 if (!parser.parse(obj)) { |
|
4638 // We ran into an error. If it was because we ran out of source, we |
|
4639 // return false so our caller knows to try to collect more buffered |
|
4640 // source. |
|
4641 if (parser.isUnexpectedEOF()) |
|
4642 result = false; |
|
4643 |
|
4644 cx->clearPendingException(); |
|
4645 } |
|
4646 JS_SetErrorReporter(cx, older); |
|
4647 |
|
4648 js_free(chars); |
|
4649 return result; |
|
4650 } |
|
4651 |
|
4652 JS_PUBLIC_API(JSObject *) |
|
4653 JS_GetGlobalFromScript(JSScript *script) |
|
4654 { |
|
4655 JS_ASSERT(!script->isCachedEval()); |
|
4656 return &script->global(); |
|
4657 } |
|
4658 |
|
4659 JS_PUBLIC_API(bool) |
|
4660 JS::CompileFunction(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options, |
|
4661 const char *name, unsigned nargs, const char *const *argnames, |
|
4662 SourceBufferHolder &srcBuf, MutableHandleFunction fun) |
|
4663 { |
|
4664 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); |
|
4665 AssertHeapIsIdle(cx); |
|
4666 CHECK_REQUEST(cx); |
|
4667 assertSameCompartment(cx, obj); |
|
4668 RootedAtom funAtom(cx); |
|
4669 AutoLastFrameCheck lfc(cx); |
|
4670 |
|
4671 if (name) { |
|
4672 funAtom = Atomize(cx, name, strlen(name)); |
|
4673 if (!funAtom) |
|
4674 return false; |
|
4675 } |
|
4676 |
|
4677 AutoNameVector formals(cx); |
|
4678 for (unsigned i = 0; i < nargs; i++) { |
|
4679 RootedAtom argAtom(cx, Atomize(cx, argnames[i], strlen(argnames[i]))); |
|
4680 if (!argAtom || !formals.append(argAtom->asPropertyName())) |
|
4681 return false; |
|
4682 } |
|
4683 |
|
4684 fun.set(NewFunction(cx, NullPtr(), nullptr, 0, JSFunction::INTERPRETED, obj, |
|
4685 funAtom, JSFunction::FinalizeKind, TenuredObject)); |
|
4686 if (!fun) |
|
4687 return false; |
|
4688 |
|
4689 if (!frontend::CompileFunctionBody(cx, fun, options, formals, srcBuf)) |
|
4690 return false; |
|
4691 |
|
4692 if (obj && funAtom && options.defineOnScope) { |
|
4693 Rooted<jsid> id(cx, AtomToId(funAtom)); |
|
4694 RootedValue value(cx, ObjectValue(*fun)); |
|
4695 if (!JSObject::defineGeneric(cx, obj, id, value, nullptr, nullptr, JSPROP_ENUMERATE)) |
|
4696 return false; |
|
4697 } |
|
4698 |
|
4699 return true; |
|
4700 } |
|
4701 |
|
4702 JS_PUBLIC_API(JSFunction *) |
|
4703 JS::CompileFunction(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options, |
|
4704 const char *name, unsigned nargs, const char *const *argnames, |
|
4705 const jschar *chars, size_t length) |
|
4706 { |
|
4707 RootedFunction fun(cx); |
|
4708 SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership); |
|
4709 if (!JS::CompileFunction(cx, obj, options, name, nargs, argnames, srcBuf, &fun)) |
|
4710 return nullptr; |
|
4711 return fun; |
|
4712 } |
|
4713 |
|
4714 JS_PUBLIC_API(JSFunction *) |
|
4715 JS::CompileFunction(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options, |
|
4716 const char *name, unsigned nargs, const char *const *argnames, |
|
4717 const char *bytes, size_t length) |
|
4718 { |
|
4719 jschar *chars; |
|
4720 if (options.utf8) |
|
4721 chars = UTF8CharsToNewTwoByteCharsZ(cx, UTF8Chars(bytes, length), &length).get(); |
|
4722 else |
|
4723 chars = InflateString(cx, bytes, &length); |
|
4724 if (!chars) |
|
4725 return nullptr; |
|
4726 |
|
4727 JSFunction *fun = CompileFunction(cx, obj, options, name, nargs, argnames, chars, length); |
|
4728 js_free(chars); |
|
4729 return fun; |
|
4730 } |
|
4731 |
|
4732 JS_PUBLIC_API(JSFunction *) |
|
4733 JS_CompileUCFunction(JSContext *cx, JS::HandleObject obj, const char *name, |
|
4734 unsigned nargs, const char *const *argnames, |
|
4735 const jschar *chars, size_t length, |
|
4736 const CompileOptions &options) |
|
4737 { |
|
4738 return CompileFunction(cx, obj, options, name, nargs, argnames, chars, length); |
|
4739 } |
|
4740 |
|
4741 JS_PUBLIC_API(JSFunction *) |
|
4742 JS_CompileFunction(JSContext *cx, JS::HandleObject obj, const char *name, |
|
4743 unsigned nargs, const char *const *argnames, |
|
4744 const char *ascii, size_t length, |
|
4745 const JS::CompileOptions &options) |
|
4746 { |
|
4747 return CompileFunction(cx, obj, options, name, nargs, argnames, ascii, length); |
|
4748 } |
|
4749 |
|
4750 JS_PUBLIC_API(JSString *) |
|
4751 JS_DecompileScript(JSContext *cx, HandleScript script, const char *name, unsigned indent) |
|
4752 { |
|
4753 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); |
|
4754 |
|
4755 AssertHeapIsIdle(cx); |
|
4756 CHECK_REQUEST(cx); |
|
4757 script->ensureNonLazyCanonicalFunction(cx); |
|
4758 RootedFunction fun(cx, script->functionNonDelazifying()); |
|
4759 if (fun) |
|
4760 return JS_DecompileFunction(cx, fun, indent); |
|
4761 bool haveSource = script->scriptSource()->hasSourceData(); |
|
4762 if (!haveSource && !JSScript::loadSource(cx, script->scriptSource(), &haveSource)) |
|
4763 return nullptr; |
|
4764 return haveSource ? script->sourceData(cx) : js_NewStringCopyZ<CanGC>(cx, "[no source]"); |
|
4765 } |
|
4766 |
|
4767 JS_PUBLIC_API(JSString *) |
|
4768 JS_DecompileFunction(JSContext *cx, HandleFunction fun, unsigned indent) |
|
4769 { |
|
4770 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); |
|
4771 AssertHeapIsIdle(cx); |
|
4772 CHECK_REQUEST(cx); |
|
4773 assertSameCompartment(cx, fun); |
|
4774 return FunctionToString(cx, fun, false, !(indent & JS_DONT_PRETTY_PRINT)); |
|
4775 } |
|
4776 |
|
4777 JS_PUBLIC_API(JSString *) |
|
4778 JS_DecompileFunctionBody(JSContext *cx, HandleFunction fun, unsigned indent) |
|
4779 { |
|
4780 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); |
|
4781 AssertHeapIsIdle(cx); |
|
4782 CHECK_REQUEST(cx); |
|
4783 assertSameCompartment(cx, fun); |
|
4784 return FunctionToString(cx, fun, true, !(indent & JS_DONT_PRETTY_PRINT)); |
|
4785 } |
|
4786 |
|
4787 MOZ_NEVER_INLINE static bool |
|
4788 ExecuteScript(JSContext *cx, HandleObject obj, HandleScript scriptArg, jsval *rval) |
|
4789 { |
|
4790 RootedScript script(cx, scriptArg); |
|
4791 |
|
4792 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); |
|
4793 AssertHeapIsIdle(cx); |
|
4794 CHECK_REQUEST(cx); |
|
4795 assertSameCompartment(cx, obj, scriptArg); |
|
4796 AutoLastFrameCheck lfc(cx); |
|
4797 return Execute(cx, script, *obj, rval); |
|
4798 } |
|
4799 |
|
4800 MOZ_NEVER_INLINE JS_PUBLIC_API(bool) |
|
4801 JS_ExecuteScript(JSContext *cx, HandleObject obj, HandleScript scriptArg, MutableHandleValue rval) |
|
4802 { |
|
4803 return ExecuteScript(cx, obj, scriptArg, rval.address()); |
|
4804 } |
|
4805 |
|
4806 MOZ_NEVER_INLINE JS_PUBLIC_API(bool) |
|
4807 JS_ExecuteScript(JSContext *cx, HandleObject obj, HandleScript scriptArg) |
|
4808 { |
|
4809 return ExecuteScript(cx, obj, scriptArg, nullptr); |
|
4810 } |
|
4811 |
|
4812 JS_PUBLIC_API(bool) |
|
4813 JS::CloneAndExecuteScript(JSContext *cx, HandleObject obj, HandleScript scriptArg) |
|
4814 { |
|
4815 CHECK_REQUEST(cx); |
|
4816 assertSameCompartment(cx, obj); |
|
4817 RootedScript script(cx, scriptArg); |
|
4818 if (script->compartment() != cx->compartment()) { |
|
4819 script = CloneScript(cx, NullPtr(), NullPtr(), script); |
|
4820 if (!script) |
|
4821 return false; |
|
4822 } |
|
4823 return ExecuteScript(cx, obj, script, nullptr); |
|
4824 } |
|
4825 |
|
4826 JS_PUBLIC_API(bool) |
|
4827 JS_ExecuteScriptVersion(JSContext *cx, HandleObject obj, HandleScript script, |
|
4828 MutableHandleValue rval, JSVersion version) |
|
4829 { |
|
4830 return ExecuteScript(cx, obj, script, rval.address()); |
|
4831 } |
|
4832 |
|
4833 JS_PUBLIC_API(bool) |
|
4834 JS_ExecuteScriptVersion(JSContext *cx, HandleObject obj, HandleScript script, JSVersion version) |
|
4835 { |
|
4836 return ExecuteScript(cx, obj, script, nullptr); |
|
4837 } |
|
4838 |
|
4839 static const unsigned LARGE_SCRIPT_LENGTH = 500*1024; |
|
4840 |
|
4841 static bool |
|
4842 Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg, |
|
4843 SourceBufferHolder &srcBuf, JS::Value *rval) |
|
4844 { |
|
4845 CompileOptions options(cx, optionsArg); |
|
4846 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); |
|
4847 AssertHeapIsIdle(cx); |
|
4848 CHECK_REQUEST(cx); |
|
4849 assertSameCompartment(cx, obj); |
|
4850 |
|
4851 AutoLastFrameCheck lfc(cx); |
|
4852 |
|
4853 options.setCompileAndGo(obj->is<GlobalObject>()); |
|
4854 options.setNoScriptRval(!rval); |
|
4855 SourceCompressionTask sct(cx); |
|
4856 RootedScript script(cx, frontend::CompileScript(cx, &cx->tempLifoAlloc(), |
|
4857 obj, NullPtr(), options, |
|
4858 srcBuf, nullptr, 0, &sct)); |
|
4859 if (!script) |
|
4860 return false; |
|
4861 |
|
4862 JS_ASSERT(script->getVersion() == options.version); |
|
4863 |
|
4864 bool result = Execute(cx, script, *obj, rval); |
|
4865 if (!sct.complete()) |
|
4866 result = false; |
|
4867 |
|
4868 // After evaluation, the compiled script will not be run again. |
|
4869 // script->ensureRanAnalysis allocated 1 analyze::Bytecode for every opcode |
|
4870 // which for large scripts means significant memory. Perform a GC eagerly |
|
4871 // to clear out this analysis data before anything happens to inhibit the |
|
4872 // flushing of this memory (such as setting requestAnimationFrame). |
|
4873 if (script->length() > LARGE_SCRIPT_LENGTH) { |
|
4874 script = nullptr; |
|
4875 PrepareZoneForGC(cx->zone()); |
|
4876 GC(cx->runtime(), GC_NORMAL, JS::gcreason::FINISH_LARGE_EVALUTE); |
|
4877 } |
|
4878 |
|
4879 return result; |
|
4880 } |
|
4881 |
|
4882 static bool |
|
4883 Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg, |
|
4884 const jschar *chars, size_t length, JS::Value *rval) |
|
4885 { |
|
4886 SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership); |
|
4887 return ::Evaluate(cx, obj, optionsArg, srcBuf, rval); |
|
4888 } |
|
4889 |
|
4890 static bool |
|
4891 Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options, |
|
4892 const char *bytes, size_t length, JS::Value *rval) |
|
4893 { |
|
4894 jschar *chars; |
|
4895 if (options.utf8) |
|
4896 chars = UTF8CharsToNewTwoByteCharsZ(cx, JS::UTF8Chars(bytes, length), &length).get(); |
|
4897 else |
|
4898 chars = InflateString(cx, bytes, &length); |
|
4899 if (!chars) |
|
4900 return false; |
|
4901 |
|
4902 SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::GiveOwnership); |
|
4903 bool ok = ::Evaluate(cx, obj, options, srcBuf, rval); |
|
4904 return ok; |
|
4905 } |
|
4906 |
|
4907 static bool |
|
4908 Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg, |
|
4909 const char *filename, JS::Value *rval) |
|
4910 { |
|
4911 FileContents buffer(cx); |
|
4912 { |
|
4913 AutoFile file; |
|
4914 if (!file.open(cx, filename) || !file.readAll(cx, buffer)) |
|
4915 return false; |
|
4916 } |
|
4917 |
|
4918 CompileOptions options(cx, optionsArg); |
|
4919 options.setFileAndLine(filename, 1); |
|
4920 return Evaluate(cx, obj, options, buffer.begin(), buffer.length(), rval); |
|
4921 } |
|
4922 |
|
4923 extern JS_PUBLIC_API(bool) |
|
4924 JS::Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg, |
|
4925 SourceBufferHolder &srcBuf, MutableHandleValue rval) |
|
4926 { |
|
4927 return ::Evaluate(cx, obj, optionsArg, srcBuf, rval.address()); |
|
4928 } |
|
4929 |
|
4930 extern JS_PUBLIC_API(bool) |
|
4931 JS::Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg, |
|
4932 const jschar *chars, size_t length, MutableHandleValue rval) |
|
4933 { |
|
4934 return ::Evaluate(cx, obj, optionsArg, chars, length, rval.address()); |
|
4935 } |
|
4936 |
|
4937 extern JS_PUBLIC_API(bool) |
|
4938 JS::Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options, |
|
4939 const char *bytes, size_t length, MutableHandleValue rval) |
|
4940 { |
|
4941 return ::Evaluate(cx, obj, options, bytes, length, rval.address()); |
|
4942 } |
|
4943 |
|
4944 extern JS_PUBLIC_API(bool) |
|
4945 JS::Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg, |
|
4946 const char *filename, MutableHandleValue rval) |
|
4947 { |
|
4948 return ::Evaluate(cx, obj, optionsArg, filename, rval.address()); |
|
4949 } |
|
4950 |
|
4951 extern JS_PUBLIC_API(bool) |
|
4952 JS::Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg, |
|
4953 SourceBufferHolder &srcBuf) |
|
4954 { |
|
4955 return ::Evaluate(cx, obj, optionsArg, srcBuf, nullptr); |
|
4956 } |
|
4957 |
|
4958 extern JS_PUBLIC_API(bool) |
|
4959 JS::Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg, |
|
4960 const jschar *chars, size_t length) |
|
4961 { |
|
4962 return ::Evaluate(cx, obj, optionsArg, chars, length, nullptr); |
|
4963 } |
|
4964 |
|
4965 extern JS_PUBLIC_API(bool) |
|
4966 JS::Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options, |
|
4967 const char *bytes, size_t length) |
|
4968 { |
|
4969 return ::Evaluate(cx, obj, options, bytes, length, nullptr); |
|
4970 } |
|
4971 |
|
4972 extern JS_PUBLIC_API(bool) |
|
4973 JS::Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg, |
|
4974 const char *filename) |
|
4975 { |
|
4976 return ::Evaluate(cx, obj, optionsArg, filename, nullptr); |
|
4977 } |
|
4978 |
|
4979 JS_PUBLIC_API(bool) |
|
4980 JS_EvaluateUCScript(JSContext *cx, HandleObject obj, const jschar *chars, unsigned length, |
|
4981 const char *filename, unsigned lineno, MutableHandleValue rval) |
|
4982 { |
|
4983 CompileOptions options(cx); |
|
4984 options.setFileAndLine(filename, lineno); |
|
4985 |
|
4986 return ::Evaluate(cx, obj, options, chars, length, rval.address()); |
|
4987 } |
|
4988 |
|
4989 JS_PUBLIC_API(bool) |
|
4990 JS_EvaluateUCScript(JSContext *cx, HandleObject obj, SourceBufferHolder &srcBuf, |
|
4991 const char *filename, unsigned lineno, MutableHandleValue rval) |
|
4992 { |
|
4993 CompileOptions options(cx); |
|
4994 options.setFileAndLine(filename, lineno); |
|
4995 |
|
4996 return ::Evaluate(cx, obj, options, srcBuf, rval.address()); |
|
4997 } |
|
4998 |
|
4999 JS_PUBLIC_API(bool) |
|
5000 JS_EvaluateScript(JSContext *cx, HandleObject obj, const char *bytes, unsigned nbytes, |
|
5001 const char *filename, unsigned lineno, MutableHandleValue rval) |
|
5002 { |
|
5003 CompileOptions options(cx); |
|
5004 options.setFileAndLine(filename, lineno); |
|
5005 |
|
5006 return ::Evaluate(cx, obj, options, bytes, nbytes, rval.address()); |
|
5007 } |
|
5008 |
|
5009 JS_PUBLIC_API(bool) |
|
5010 JS_EvaluateScript(JSContext *cx, HandleObject obj, const char *bytes, unsigned nbytes, |
|
5011 const char *filename, unsigned lineno) |
|
5012 { |
|
5013 CompileOptions options(cx); |
|
5014 options.setFileAndLine(filename, lineno); |
|
5015 |
|
5016 return ::Evaluate(cx, obj, options, bytes, nbytes, nullptr); |
|
5017 } |
|
5018 |
|
5019 JS_PUBLIC_API(bool) |
|
5020 JS_CallFunction(JSContext *cx, HandleObject obj, HandleFunction fun, const HandleValueArray& args, |
|
5021 MutableHandleValue rval) |
|
5022 { |
|
5023 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); |
|
5024 AssertHeapIsIdle(cx); |
|
5025 CHECK_REQUEST(cx); |
|
5026 assertSameCompartment(cx, obj, fun, args); |
|
5027 AutoLastFrameCheck lfc(cx); |
|
5028 |
|
5029 return Invoke(cx, ObjectOrNullValue(obj), ObjectValue(*fun), args.length(), args.begin(), rval); |
|
5030 } |
|
5031 |
|
5032 JS_PUBLIC_API(bool) |
|
5033 JS_CallFunctionName(JSContext *cx, HandleObject obj, const char *name, const HandleValueArray& args, |
|
5034 MutableHandleValue rval) |
|
5035 { |
|
5036 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); |
|
5037 AssertHeapIsIdle(cx); |
|
5038 CHECK_REQUEST(cx); |
|
5039 assertSameCompartment(cx, obj, args); |
|
5040 AutoLastFrameCheck lfc(cx); |
|
5041 |
|
5042 JSAtom *atom = Atomize(cx, name, strlen(name)); |
|
5043 if (!atom) |
|
5044 return false; |
|
5045 |
|
5046 RootedValue v(cx); |
|
5047 RootedId id(cx, AtomToId(atom)); |
|
5048 if (!JSObject::getGeneric(cx, obj, obj, id, &v)) |
|
5049 return false; |
|
5050 |
|
5051 return Invoke(cx, ObjectOrNullValue(obj), v, args.length(), args.begin(), rval); |
|
5052 } |
|
5053 |
|
5054 JS_PUBLIC_API(bool) |
|
5055 JS_CallFunctionValue(JSContext *cx, HandleObject obj, HandleValue fval, const HandleValueArray& args, |
|
5056 MutableHandleValue rval) |
|
5057 { |
|
5058 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); |
|
5059 AssertHeapIsIdle(cx); |
|
5060 CHECK_REQUEST(cx); |
|
5061 assertSameCompartment(cx, obj, fval, args); |
|
5062 AutoLastFrameCheck lfc(cx); |
|
5063 |
|
5064 return Invoke(cx, ObjectOrNullValue(obj), fval, args.length(), args.begin(), rval); |
|
5065 } |
|
5066 |
|
5067 JS_PUBLIC_API(bool) |
|
5068 JS::Call(JSContext *cx, HandleValue thisv, HandleValue fval, const JS::HandleValueArray& args, |
|
5069 MutableHandleValue rval) |
|
5070 { |
|
5071 AssertHeapIsIdle(cx); |
|
5072 CHECK_REQUEST(cx); |
|
5073 assertSameCompartment(cx, thisv, fval, args); |
|
5074 AutoLastFrameCheck lfc(cx); |
|
5075 |
|
5076 return Invoke(cx, thisv, fval, args.length(), args.begin(), rval); |
|
5077 } |
|
5078 |
|
5079 static JSObject * |
|
5080 JS_NewHelper(JSContext *cx, HandleObject ctor, const JS::HandleValueArray& inputArgs) |
|
5081 { |
|
5082 AssertHeapIsIdle(cx); |
|
5083 CHECK_REQUEST(cx); |
|
5084 assertSameCompartment(cx, ctor, inputArgs); |
|
5085 |
|
5086 // This is not a simple variation of JS_CallFunctionValue because JSOP_NEW |
|
5087 // is not a simple variation of JSOP_CALL. We have to determine what class |
|
5088 // of object to create, create it, and clamp the return value to an object, |
|
5089 // among other details. InvokeConstructor does the hard work. |
|
5090 InvokeArgs args(cx); |
|
5091 if (!args.init(inputArgs.length())) |
|
5092 return nullptr; |
|
5093 |
|
5094 args.setCallee(ObjectValue(*ctor)); |
|
5095 args.setThis(NullValue()); |
|
5096 PodCopy(args.array(), inputArgs.begin(), inputArgs.length()); |
|
5097 |
|
5098 if (!InvokeConstructor(cx, args)) |
|
5099 return nullptr; |
|
5100 |
|
5101 if (!args.rval().isObject()) { |
|
5102 /* |
|
5103 * Although constructors may return primitives (via proxies), this |
|
5104 * API is asking for an object, so we report an error. |
|
5105 */ |
|
5106 JSAutoByteString bytes; |
|
5107 if (js_ValueToPrintable(cx, args.rval(), &bytes)) { |
|
5108 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_NEW_RESULT, |
|
5109 bytes.ptr()); |
|
5110 } |
|
5111 return nullptr; |
|
5112 } |
|
5113 |
|
5114 return &args.rval().toObject(); |
|
5115 } |
|
5116 |
|
5117 JS_PUBLIC_API(JSObject *) |
|
5118 JS_New(JSContext *cx, HandleObject ctor, const JS::HandleValueArray& inputArgs) |
|
5119 { |
|
5120 RootedObject obj(cx); |
|
5121 { |
|
5122 AutoLastFrameCheck lfc(cx); |
|
5123 obj = JS_NewHelper(cx, ctor, inputArgs); |
|
5124 } |
|
5125 return obj; |
|
5126 } |
|
5127 |
|
5128 JS_PUBLIC_API(JSInterruptCallback) |
|
5129 JS_SetInterruptCallback(JSRuntime *rt, JSInterruptCallback callback) |
|
5130 { |
|
5131 JSInterruptCallback old = rt->interruptCallback; |
|
5132 rt->interruptCallback = callback; |
|
5133 return old; |
|
5134 } |
|
5135 |
|
5136 JS_PUBLIC_API(JSInterruptCallback) |
|
5137 JS_GetInterruptCallback(JSRuntime *rt) |
|
5138 { |
|
5139 return rt->interruptCallback; |
|
5140 } |
|
5141 |
|
5142 JS_PUBLIC_API(void) |
|
5143 JS_RequestInterruptCallback(JSRuntime *rt) |
|
5144 { |
|
5145 rt->requestInterrupt(JSRuntime::RequestInterruptAnyThread); |
|
5146 } |
|
5147 |
|
5148 JS_PUBLIC_API(bool) |
|
5149 JS_IsRunning(JSContext *cx) |
|
5150 { |
|
5151 return cx->currentlyRunning(); |
|
5152 } |
|
5153 |
|
5154 JS_PUBLIC_API(bool) |
|
5155 JS_SaveFrameChain(JSContext *cx) |
|
5156 { |
|
5157 AssertHeapIsIdleOrIterating(cx); |
|
5158 CHECK_REQUEST(cx); |
|
5159 return cx->saveFrameChain(); |
|
5160 } |
|
5161 |
|
5162 JS_PUBLIC_API(void) |
|
5163 JS_RestoreFrameChain(JSContext *cx) |
|
5164 { |
|
5165 AssertHeapIsIdleOrIterating(cx); |
|
5166 CHECK_REQUEST(cx); |
|
5167 cx->restoreFrameChain(); |
|
5168 } |
|
5169 |
|
5170 #ifdef MOZ_TRACE_JSCALLS |
|
5171 JS_PUBLIC_API(void) |
|
5172 JS_SetFunctionCallback(JSContext *cx, JSFunctionCallback fcb) |
|
5173 { |
|
5174 cx->functionCallback = fcb; |
|
5175 } |
|
5176 |
|
5177 JS_PUBLIC_API(JSFunctionCallback) |
|
5178 JS_GetFunctionCallback(JSContext *cx) |
|
5179 { |
|
5180 return cx->functionCallback; |
|
5181 } |
|
5182 #endif |
|
5183 |
|
5184 /************************************************************************/ |
|
5185 JS_PUBLIC_API(JSString *) |
|
5186 JS_NewStringCopyN(JSContext *cx, const char *s, size_t n) |
|
5187 { |
|
5188 AssertHeapIsIdle(cx); |
|
5189 CHECK_REQUEST(cx); |
|
5190 if (!n) |
|
5191 return cx->names().empty; |
|
5192 return js_NewStringCopyN<CanGC>(cx, s, n); |
|
5193 } |
|
5194 |
|
5195 JS_PUBLIC_API(JSString *) |
|
5196 JS_NewStringCopyZ(JSContext *cx, const char *s) |
|
5197 { |
|
5198 size_t n; |
|
5199 jschar *js; |
|
5200 JSString *str; |
|
5201 |
|
5202 AssertHeapIsIdle(cx); |
|
5203 CHECK_REQUEST(cx); |
|
5204 if (!s || !*s) |
|
5205 return cx->runtime()->emptyString; |
|
5206 n = strlen(s); |
|
5207 js = InflateString(cx, s, &n); |
|
5208 if (!js) |
|
5209 return nullptr; |
|
5210 str = js_NewString<CanGC>(cx, js, n); |
|
5211 if (!str) |
|
5212 js_free(js); |
|
5213 return str; |
|
5214 } |
|
5215 |
|
5216 JS_PUBLIC_API(bool) |
|
5217 JS_StringHasBeenInterned(JSContext *cx, JSString *str) |
|
5218 { |
|
5219 AssertHeapIsIdle(cx); |
|
5220 CHECK_REQUEST(cx); |
|
5221 |
|
5222 if (!str->isAtom()) |
|
5223 return false; |
|
5224 |
|
5225 return AtomIsInterned(cx, &str->asAtom()); |
|
5226 } |
|
5227 |
|
5228 JS_PUBLIC_API(jsid) |
|
5229 INTERNED_STRING_TO_JSID(JSContext *cx, JSString *str) |
|
5230 { |
|
5231 JS_ASSERT(str); |
|
5232 JS_ASSERT(((size_t)str & JSID_TYPE_MASK) == 0); |
|
5233 JS_ASSERT_IF(cx, JS_StringHasBeenInterned(cx, str)); |
|
5234 return AtomToId(&str->asAtom()); |
|
5235 } |
|
5236 |
|
5237 JS_PUBLIC_API(JSString *) |
|
5238 JS_InternJSString(JSContext *cx, HandleString str) |
|
5239 { |
|
5240 AssertHeapIsIdle(cx); |
|
5241 CHECK_REQUEST(cx); |
|
5242 JSAtom *atom = AtomizeString(cx, str, InternAtom); |
|
5243 JS_ASSERT_IF(atom, JS_StringHasBeenInterned(cx, atom)); |
|
5244 return atom; |
|
5245 } |
|
5246 |
|
5247 JS_PUBLIC_API(JSString *) |
|
5248 JS_InternString(JSContext *cx, const char *s) |
|
5249 { |
|
5250 return JS_InternStringN(cx, s, strlen(s)); |
|
5251 } |
|
5252 |
|
5253 JS_PUBLIC_API(JSString *) |
|
5254 JS_InternStringN(JSContext *cx, const char *s, size_t length) |
|
5255 { |
|
5256 AssertHeapIsIdle(cx); |
|
5257 CHECK_REQUEST(cx); |
|
5258 JSAtom *atom = Atomize(cx, s, length, InternAtom); |
|
5259 JS_ASSERT_IF(atom, JS_StringHasBeenInterned(cx, atom)); |
|
5260 return atom; |
|
5261 } |
|
5262 |
|
5263 JS_PUBLIC_API(JSString *) |
|
5264 JS_NewUCString(JSContext *cx, jschar *chars, size_t length) |
|
5265 { |
|
5266 AssertHeapIsIdle(cx); |
|
5267 CHECK_REQUEST(cx); |
|
5268 return js_NewString<CanGC>(cx, chars, length); |
|
5269 } |
|
5270 |
|
5271 JS_PUBLIC_API(JSString *) |
|
5272 JS_NewUCStringCopyN(JSContext *cx, const jschar *s, size_t n) |
|
5273 { |
|
5274 AssertHeapIsIdle(cx); |
|
5275 CHECK_REQUEST(cx); |
|
5276 if (!n) |
|
5277 return cx->names().empty; |
|
5278 return js_NewStringCopyN<CanGC>(cx, s, n); |
|
5279 } |
|
5280 |
|
5281 JS_PUBLIC_API(JSString *) |
|
5282 JS_NewUCStringCopyZ(JSContext *cx, const jschar *s) |
|
5283 { |
|
5284 AssertHeapIsIdle(cx); |
|
5285 CHECK_REQUEST(cx); |
|
5286 if (!s) |
|
5287 return cx->runtime()->emptyString; |
|
5288 return js_NewStringCopyZ<CanGC>(cx, s); |
|
5289 } |
|
5290 |
|
5291 JS_PUBLIC_API(JSString *) |
|
5292 JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length) |
|
5293 { |
|
5294 AssertHeapIsIdle(cx); |
|
5295 CHECK_REQUEST(cx); |
|
5296 JSAtom *atom = AtomizeChars(cx, s, length, InternAtom); |
|
5297 JS_ASSERT_IF(atom, JS_StringHasBeenInterned(cx, atom)); |
|
5298 return atom; |
|
5299 } |
|
5300 |
|
5301 JS_PUBLIC_API(JSString *) |
|
5302 JS_InternUCString(JSContext *cx, const jschar *s) |
|
5303 { |
|
5304 return JS_InternUCStringN(cx, s, js_strlen(s)); |
|
5305 } |
|
5306 |
|
5307 JS_PUBLIC_API(size_t) |
|
5308 JS_GetStringLength(JSString *str) |
|
5309 { |
|
5310 return str->length(); |
|
5311 } |
|
5312 |
|
5313 JS_PUBLIC_API(const jschar *) |
|
5314 JS_GetStringCharsZ(JSContext *cx, JSString *str) |
|
5315 { |
|
5316 size_t dummy; |
|
5317 return JS_GetStringCharsZAndLength(cx, str, &dummy); |
|
5318 } |
|
5319 |
|
5320 JS_PUBLIC_API(const jschar *) |
|
5321 JS_GetStringCharsZAndLength(JSContext *cx, JSString *str, size_t *plength) |
|
5322 { |
|
5323 /* |
|
5324 * Don't require |cx->compartment()| to be |str|'s compartment. We don't need |
|
5325 * it, and it's annoying for callers. |
|
5326 */ |
|
5327 JS_ASSERT(plength); |
|
5328 AssertHeapIsIdleOrStringIsFlat(cx, str); |
|
5329 CHECK_REQUEST(cx); |
|
5330 JSFlatString *flat = str->ensureFlat(cx); |
|
5331 if (!flat) |
|
5332 return nullptr; |
|
5333 *plength = flat->length(); |
|
5334 return flat->chars(); |
|
5335 } |
|
5336 |
|
5337 JS_PUBLIC_API(const jschar *) |
|
5338 JS_GetStringCharsAndLength(JSContext *cx, JSString *str, size_t *plength) |
|
5339 { |
|
5340 JS_ASSERT(plength); |
|
5341 AssertHeapIsIdleOrStringIsFlat(cx, str); |
|
5342 CHECK_REQUEST(cx); |
|
5343 assertSameCompartment(cx, str); |
|
5344 JSLinearString *linear = str->ensureLinear(cx); |
|
5345 if (!linear) |
|
5346 return nullptr; |
|
5347 *plength = linear->length(); |
|
5348 return linear->chars(); |
|
5349 } |
|
5350 |
|
5351 JS_PUBLIC_API(const jschar *) |
|
5352 JS_GetInternedStringChars(JSString *str) |
|
5353 { |
|
5354 JS_ASSERT(str->isAtom()); |
|
5355 JSFlatString *flat = str->ensureFlat(nullptr); |
|
5356 if (!flat) |
|
5357 return nullptr; |
|
5358 return flat->chars(); |
|
5359 } |
|
5360 |
|
5361 JS_PUBLIC_API(const jschar *) |
|
5362 JS_GetInternedStringCharsAndLength(JSString *str, size_t *plength) |
|
5363 { |
|
5364 JS_ASSERT(str->isAtom()); |
|
5365 JS_ASSERT(plength); |
|
5366 JSFlatString *flat = str->ensureFlat(nullptr); |
|
5367 if (!flat) |
|
5368 return nullptr; |
|
5369 *plength = flat->length(); |
|
5370 return flat->chars(); |
|
5371 } |
|
5372 |
|
5373 extern JS_PUBLIC_API(JSFlatString *) |
|
5374 JS_FlattenString(JSContext *cx, JSString *str) |
|
5375 { |
|
5376 AssertHeapIsIdle(cx); |
|
5377 CHECK_REQUEST(cx); |
|
5378 assertSameCompartment(cx, str); |
|
5379 JSFlatString *flat = str->ensureFlat(cx); |
|
5380 if (!flat) |
|
5381 return nullptr; |
|
5382 return flat; |
|
5383 } |
|
5384 |
|
5385 extern JS_PUBLIC_API(const jschar *) |
|
5386 JS_GetFlatStringChars(JSFlatString *str) |
|
5387 { |
|
5388 return str->chars(); |
|
5389 } |
|
5390 |
|
5391 JS_PUBLIC_API(bool) |
|
5392 JS_CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32_t *result) |
|
5393 { |
|
5394 AssertHeapIsIdle(cx); |
|
5395 CHECK_REQUEST(cx); |
|
5396 |
|
5397 return CompareStrings(cx, str1, str2, result); |
|
5398 } |
|
5399 |
|
5400 JS_PUBLIC_API(bool) |
|
5401 JS_StringEqualsAscii(JSContext *cx, JSString *str, const char *asciiBytes, bool *match) |
|
5402 { |
|
5403 AssertHeapIsIdle(cx); |
|
5404 CHECK_REQUEST(cx); |
|
5405 |
|
5406 JSLinearString *linearStr = str->ensureLinear(cx); |
|
5407 if (!linearStr) |
|
5408 return false; |
|
5409 *match = StringEqualsAscii(linearStr, asciiBytes); |
|
5410 return true; |
|
5411 } |
|
5412 |
|
5413 JS_PUBLIC_API(bool) |
|
5414 JS_FlatStringEqualsAscii(JSFlatString *str, const char *asciiBytes) |
|
5415 { |
|
5416 return StringEqualsAscii(str, asciiBytes); |
|
5417 } |
|
5418 |
|
5419 JS_PUBLIC_API(size_t) |
|
5420 JS_PutEscapedFlatString(char *buffer, size_t size, JSFlatString *str, char quote) |
|
5421 { |
|
5422 return PutEscapedString(buffer, size, str, quote); |
|
5423 } |
|
5424 |
|
5425 JS_PUBLIC_API(size_t) |
|
5426 JS_PutEscapedString(JSContext *cx, char *buffer, size_t size, JSString *str, char quote) |
|
5427 { |
|
5428 AssertHeapIsIdle(cx); |
|
5429 JSLinearString *linearStr = str->ensureLinear(cx); |
|
5430 if (!linearStr) |
|
5431 return size_t(-1); |
|
5432 return PutEscapedString(buffer, size, linearStr, quote); |
|
5433 } |
|
5434 |
|
5435 JS_PUBLIC_API(bool) |
|
5436 JS_FileEscapedString(FILE *fp, JSString *str, char quote) |
|
5437 { |
|
5438 JSLinearString *linearStr = str->ensureLinear(nullptr); |
|
5439 return linearStr && FileEscapedString(fp, linearStr, quote); |
|
5440 } |
|
5441 |
|
5442 JS_PUBLIC_API(JSString *) |
|
5443 JS_NewDependentString(JSContext *cx, HandleString str, size_t start, size_t length) |
|
5444 { |
|
5445 AssertHeapIsIdle(cx); |
|
5446 CHECK_REQUEST(cx); |
|
5447 return js_NewDependentString(cx, str, start, length); |
|
5448 } |
|
5449 |
|
5450 JS_PUBLIC_API(JSString *) |
|
5451 JS_ConcatStrings(JSContext *cx, HandleString left, HandleString right) |
|
5452 { |
|
5453 AssertHeapIsIdle(cx); |
|
5454 CHECK_REQUEST(cx); |
|
5455 return ConcatStrings<CanGC>(cx, left, right); |
|
5456 } |
|
5457 |
|
5458 JS_PUBLIC_API(bool) |
|
5459 JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst, size_t *dstlenp) |
|
5460 { |
|
5461 AssertHeapIsIdle(cx); |
|
5462 CHECK_REQUEST(cx); |
|
5463 |
|
5464 if (!dst) { |
|
5465 *dstlenp = srclen; |
|
5466 return true; |
|
5467 } |
|
5468 |
|
5469 size_t dstlen = *dstlenp; |
|
5470 |
|
5471 if (srclen > dstlen) { |
|
5472 InflateStringToBuffer(src, dstlen, dst); |
|
5473 |
|
5474 AutoSuppressGC suppress(cx); |
|
5475 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BUFFER_TOO_SMALL); |
|
5476 return false; |
|
5477 } |
|
5478 |
|
5479 InflateStringToBuffer(src, srclen, dst); |
|
5480 *dstlenp = srclen; |
|
5481 return true; |
|
5482 } |
|
5483 |
|
5484 JS_PUBLIC_API(char *) |
|
5485 JS_EncodeString(JSContext *cx, JSString *str) |
|
5486 { |
|
5487 AssertHeapIsIdle(cx); |
|
5488 CHECK_REQUEST(cx); |
|
5489 |
|
5490 JSLinearString *linear = str->ensureLinear(cx); |
|
5491 if (!linear) |
|
5492 return nullptr; |
|
5493 |
|
5494 return LossyTwoByteCharsToNewLatin1CharsZ(cx, linear->range()).c_str(); |
|
5495 } |
|
5496 |
|
5497 JS_PUBLIC_API(char *) |
|
5498 JS_EncodeStringToUTF8(JSContext *cx, HandleString str) |
|
5499 { |
|
5500 AssertHeapIsIdle(cx); |
|
5501 CHECK_REQUEST(cx); |
|
5502 |
|
5503 JSLinearString *linear = str->ensureLinear(cx); |
|
5504 if (!linear) |
|
5505 return nullptr; |
|
5506 |
|
5507 return TwoByteCharsToNewUTF8CharsZ(cx, linear->range()).c_str(); |
|
5508 } |
|
5509 |
|
5510 JS_PUBLIC_API(size_t) |
|
5511 JS_GetStringEncodingLength(JSContext *cx, JSString *str) |
|
5512 { |
|
5513 AssertHeapIsIdle(cx); |
|
5514 CHECK_REQUEST(cx); |
|
5515 |
|
5516 const jschar *chars = str->getChars(cx); |
|
5517 if (!chars) |
|
5518 return size_t(-1); |
|
5519 return str->length(); |
|
5520 } |
|
5521 |
|
5522 JS_PUBLIC_API(size_t) |
|
5523 JS_EncodeStringToBuffer(JSContext *cx, JSString *str, char *buffer, size_t length) |
|
5524 { |
|
5525 AssertHeapIsIdle(cx); |
|
5526 CHECK_REQUEST(cx); |
|
5527 |
|
5528 /* |
|
5529 * FIXME bug 612141 - fix DeflateStringToBuffer interface so the result |
|
5530 * would allow to distinguish between insufficient buffer and encoding |
|
5531 * error. |
|
5532 */ |
|
5533 size_t writtenLength = length; |
|
5534 const jschar *chars = str->getChars(nullptr); |
|
5535 if (!chars) |
|
5536 return size_t(-1); |
|
5537 if (DeflateStringToBuffer(nullptr, chars, str->length(), buffer, &writtenLength)) { |
|
5538 JS_ASSERT(writtenLength <= length); |
|
5539 return writtenLength; |
|
5540 } |
|
5541 JS_ASSERT(writtenLength <= length); |
|
5542 size_t necessaryLength = str->length(); |
|
5543 if (necessaryLength == size_t(-1)) |
|
5544 return size_t(-1); |
|
5545 JS_ASSERT(writtenLength == length); // C strings are NOT encoded. |
|
5546 return necessaryLength; |
|
5547 } |
|
5548 |
|
5549 JS_PUBLIC_API(bool) |
|
5550 JS_Stringify(JSContext *cx, MutableHandleValue vp, HandleObject replacer, |
|
5551 HandleValue space, JSONWriteCallback callback, void *data) |
|
5552 { |
|
5553 AssertHeapIsIdle(cx); |
|
5554 CHECK_REQUEST(cx); |
|
5555 assertSameCompartment(cx, replacer, space); |
|
5556 StringBuffer sb(cx); |
|
5557 if (!js_Stringify(cx, vp, replacer, space, sb)) |
|
5558 return false; |
|
5559 if (sb.empty()) { |
|
5560 HandlePropertyName null = cx->names().null; |
|
5561 return callback(null->chars(), null->length(), data); |
|
5562 } |
|
5563 return callback(sb.begin(), sb.length(), data); |
|
5564 } |
|
5565 |
|
5566 JS_PUBLIC_API(bool) |
|
5567 JS_ParseJSON(JSContext *cx, const jschar *chars, uint32_t len, JS::MutableHandleValue vp) |
|
5568 { |
|
5569 AssertHeapIsIdle(cx); |
|
5570 CHECK_REQUEST(cx); |
|
5571 |
|
5572 RootedValue reviver(cx, NullValue()); |
|
5573 return ParseJSONWithReviver(cx, ConstTwoByteChars(chars, len), len, reviver, vp); |
|
5574 } |
|
5575 |
|
5576 JS_PUBLIC_API(bool) |
|
5577 JS_ParseJSONWithReviver(JSContext *cx, const jschar *chars, uint32_t len, HandleValue reviver, MutableHandleValue vp) |
|
5578 { |
|
5579 AssertHeapIsIdle(cx); |
|
5580 CHECK_REQUEST(cx); |
|
5581 return ParseJSONWithReviver(cx, ConstTwoByteChars(chars, len), len, reviver, vp); |
|
5582 } |
|
5583 |
|
5584 /************************************************************************/ |
|
5585 |
|
5586 JS_PUBLIC_API(void) |
|
5587 JS_ReportError(JSContext *cx, const char *format, ...) |
|
5588 { |
|
5589 va_list ap; |
|
5590 |
|
5591 AssertHeapIsIdle(cx); |
|
5592 va_start(ap, format); |
|
5593 js_ReportErrorVA(cx, JSREPORT_ERROR, format, ap); |
|
5594 va_end(ap); |
|
5595 } |
|
5596 |
|
5597 JS_PUBLIC_API(void) |
|
5598 JS_ReportErrorNumber(JSContext *cx, JSErrorCallback errorCallback, |
|
5599 void *userRef, const unsigned errorNumber, ...) |
|
5600 { |
|
5601 va_list ap; |
|
5602 va_start(ap, errorNumber); |
|
5603 JS_ReportErrorNumberVA(cx, errorCallback, userRef, errorNumber, ap); |
|
5604 va_end(ap); |
|
5605 } |
|
5606 |
|
5607 JS_PUBLIC_API(void) |
|
5608 JS_ReportErrorNumberVA(JSContext *cx, JSErrorCallback errorCallback, |
|
5609 void *userRef, const unsigned errorNumber, |
|
5610 va_list ap) |
|
5611 { |
|
5612 AssertHeapIsIdle(cx); |
|
5613 js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef, |
|
5614 errorNumber, ArgumentsAreASCII, ap); |
|
5615 } |
|
5616 |
|
5617 JS_PUBLIC_API(void) |
|
5618 JS_ReportErrorNumberUC(JSContext *cx, JSErrorCallback errorCallback, |
|
5619 void *userRef, const unsigned errorNumber, ...) |
|
5620 { |
|
5621 va_list ap; |
|
5622 |
|
5623 AssertHeapIsIdle(cx); |
|
5624 va_start(ap, errorNumber); |
|
5625 js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef, |
|
5626 errorNumber, ArgumentsAreUnicode, ap); |
|
5627 va_end(ap); |
|
5628 } |
|
5629 |
|
5630 JS_PUBLIC_API(void) |
|
5631 JS_ReportErrorNumberUCArray(JSContext *cx, JSErrorCallback errorCallback, |
|
5632 void *userRef, const unsigned errorNumber, |
|
5633 const jschar **args) |
|
5634 { |
|
5635 AssertHeapIsIdle(cx); |
|
5636 js_ReportErrorNumberUCArray(cx, JSREPORT_ERROR, errorCallback, userRef, |
|
5637 errorNumber, args); |
|
5638 } |
|
5639 |
|
5640 JS_PUBLIC_API(bool) |
|
5641 JS_ReportWarning(JSContext *cx, const char *format, ...) |
|
5642 { |
|
5643 va_list ap; |
|
5644 bool ok; |
|
5645 |
|
5646 AssertHeapIsIdle(cx); |
|
5647 va_start(ap, format); |
|
5648 ok = js_ReportErrorVA(cx, JSREPORT_WARNING, format, ap); |
|
5649 va_end(ap); |
|
5650 return ok; |
|
5651 } |
|
5652 |
|
5653 JS_PUBLIC_API(bool) |
|
5654 JS_ReportErrorFlagsAndNumber(JSContext *cx, unsigned flags, |
|
5655 JSErrorCallback errorCallback, void *userRef, |
|
5656 const unsigned errorNumber, ...) |
|
5657 { |
|
5658 va_list ap; |
|
5659 bool ok; |
|
5660 |
|
5661 AssertHeapIsIdle(cx); |
|
5662 va_start(ap, errorNumber); |
|
5663 ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef, |
|
5664 errorNumber, ArgumentsAreASCII, ap); |
|
5665 va_end(ap); |
|
5666 return ok; |
|
5667 } |
|
5668 |
|
5669 JS_PUBLIC_API(bool) |
|
5670 JS_ReportErrorFlagsAndNumberUC(JSContext *cx, unsigned flags, |
|
5671 JSErrorCallback errorCallback, void *userRef, |
|
5672 const unsigned errorNumber, ...) |
|
5673 { |
|
5674 va_list ap; |
|
5675 bool ok; |
|
5676 |
|
5677 AssertHeapIsIdle(cx); |
|
5678 va_start(ap, errorNumber); |
|
5679 ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef, |
|
5680 errorNumber, ArgumentsAreUnicode, ap); |
|
5681 va_end(ap); |
|
5682 return ok; |
|
5683 } |
|
5684 |
|
5685 JS_PUBLIC_API(void) |
|
5686 JS_ReportOutOfMemory(JSContext *cx) |
|
5687 { |
|
5688 js_ReportOutOfMemory(cx); |
|
5689 } |
|
5690 |
|
5691 JS_PUBLIC_API(void) |
|
5692 JS_ReportAllocationOverflow(JSContext *cx) |
|
5693 { |
|
5694 js_ReportAllocationOverflow(cx); |
|
5695 } |
|
5696 |
|
5697 JS_PUBLIC_API(JSErrorReporter) |
|
5698 JS_GetErrorReporter(JSContext *cx) |
|
5699 { |
|
5700 return cx->errorReporter; |
|
5701 } |
|
5702 |
|
5703 JS_PUBLIC_API(JSErrorReporter) |
|
5704 JS_SetErrorReporter(JSContext *cx, JSErrorReporter er) |
|
5705 { |
|
5706 JSErrorReporter older; |
|
5707 |
|
5708 older = cx->errorReporter; |
|
5709 cx->errorReporter = er; |
|
5710 return older; |
|
5711 } |
|
5712 |
|
5713 /************************************************************************/ |
|
5714 |
|
5715 /* |
|
5716 * Dates. |
|
5717 */ |
|
5718 JS_PUBLIC_API(JSObject *) |
|
5719 JS_NewDateObject(JSContext *cx, int year, int mon, int mday, int hour, int min, int sec) |
|
5720 { |
|
5721 AssertHeapIsIdle(cx); |
|
5722 CHECK_REQUEST(cx); |
|
5723 return js_NewDateObject(cx, year, mon, mday, hour, min, sec); |
|
5724 } |
|
5725 |
|
5726 JS_PUBLIC_API(JSObject *) |
|
5727 JS_NewDateObjectMsec(JSContext *cx, double msec) |
|
5728 { |
|
5729 AssertHeapIsIdle(cx); |
|
5730 CHECK_REQUEST(cx); |
|
5731 return js_NewDateObjectMsec(cx, msec); |
|
5732 } |
|
5733 |
|
5734 JS_PUBLIC_API(bool) |
|
5735 JS_ObjectIsDate(JSContext *cx, HandleObject obj) |
|
5736 { |
|
5737 assertSameCompartment(cx, obj); |
|
5738 return ObjectClassIs(obj, ESClass_Date, cx); |
|
5739 } |
|
5740 |
|
5741 JS_PUBLIC_API(void) |
|
5742 JS_ClearDateCaches(JSContext *cx) |
|
5743 { |
|
5744 AssertHeapIsIdle(cx); |
|
5745 CHECK_REQUEST(cx); |
|
5746 cx->runtime()->dateTimeInfo.updateTimeZoneAdjustment(); |
|
5747 } |
|
5748 |
|
5749 /************************************************************************/ |
|
5750 |
|
5751 /* |
|
5752 * Regular Expressions. |
|
5753 */ |
|
5754 JS_PUBLIC_API(JSObject *) |
|
5755 JS_NewRegExpObject(JSContext *cx, HandleObject obj, char *bytes, size_t length, unsigned flags) |
|
5756 { |
|
5757 AssertHeapIsIdle(cx); |
|
5758 CHECK_REQUEST(cx); |
|
5759 jschar *chars = InflateString(cx, bytes, &length); |
|
5760 if (!chars) |
|
5761 return nullptr; |
|
5762 |
|
5763 RegExpStatics *res = obj->as<GlobalObject>().getRegExpStatics(); |
|
5764 RegExpObject *reobj = RegExpObject::create(cx, res, chars, length, |
|
5765 RegExpFlag(flags), nullptr); |
|
5766 js_free(chars); |
|
5767 return reobj; |
|
5768 } |
|
5769 |
|
5770 JS_PUBLIC_API(JSObject *) |
|
5771 JS_NewUCRegExpObject(JSContext *cx, HandleObject obj, jschar *chars, size_t length, |
|
5772 unsigned flags) |
|
5773 { |
|
5774 AssertHeapIsIdle(cx); |
|
5775 CHECK_REQUEST(cx); |
|
5776 RegExpStatics *res = obj->as<GlobalObject>().getRegExpStatics(); |
|
5777 return RegExpObject::create(cx, res, chars, length, |
|
5778 RegExpFlag(flags), nullptr); |
|
5779 } |
|
5780 |
|
5781 JS_PUBLIC_API(void) |
|
5782 JS_SetRegExpInput(JSContext *cx, HandleObject obj, HandleString input, bool multiline) |
|
5783 { |
|
5784 AssertHeapIsIdle(cx); |
|
5785 CHECK_REQUEST(cx); |
|
5786 assertSameCompartment(cx, input); |
|
5787 |
|
5788 obj->as<GlobalObject>().getRegExpStatics()->reset(cx, input, !!multiline); |
|
5789 } |
|
5790 |
|
5791 JS_PUBLIC_API(void) |
|
5792 JS_ClearRegExpStatics(JSContext *cx, HandleObject obj) |
|
5793 { |
|
5794 AssertHeapIsIdle(cx); |
|
5795 CHECK_REQUEST(cx); |
|
5796 JS_ASSERT(obj); |
|
5797 |
|
5798 obj->as<GlobalObject>().getRegExpStatics()->clear(); |
|
5799 } |
|
5800 |
|
5801 JS_PUBLIC_API(bool) |
|
5802 JS_ExecuteRegExp(JSContext *cx, HandleObject obj, HandleObject reobj, jschar *chars, |
|
5803 size_t length, size_t *indexp, bool test, MutableHandleValue rval) |
|
5804 { |
|
5805 AssertHeapIsIdle(cx); |
|
5806 CHECK_REQUEST(cx); |
|
5807 |
|
5808 RegExpStatics *res = obj->as<GlobalObject>().getRegExpStatics(); |
|
5809 |
|
5810 return ExecuteRegExpLegacy(cx, res, reobj->as<RegExpObject>(), NullPtr(), chars, length, indexp, |
|
5811 test, rval); |
|
5812 } |
|
5813 |
|
5814 JS_PUBLIC_API(JSObject *) |
|
5815 JS_NewRegExpObjectNoStatics(JSContext *cx, char *bytes, size_t length, unsigned flags) |
|
5816 { |
|
5817 AssertHeapIsIdle(cx); |
|
5818 CHECK_REQUEST(cx); |
|
5819 jschar *chars = InflateString(cx, bytes, &length); |
|
5820 if (!chars) |
|
5821 return nullptr; |
|
5822 RegExpObject *reobj = RegExpObject::createNoStatics(cx, chars, length, |
|
5823 RegExpFlag(flags), nullptr); |
|
5824 js_free(chars); |
|
5825 return reobj; |
|
5826 } |
|
5827 |
|
5828 JS_PUBLIC_API(JSObject *) |
|
5829 JS_NewUCRegExpObjectNoStatics(JSContext *cx, jschar *chars, size_t length, unsigned flags) |
|
5830 { |
|
5831 AssertHeapIsIdle(cx); |
|
5832 CHECK_REQUEST(cx); |
|
5833 return RegExpObject::createNoStatics(cx, chars, length, |
|
5834 RegExpFlag(flags), nullptr); |
|
5835 } |
|
5836 |
|
5837 JS_PUBLIC_API(bool) |
|
5838 JS_ExecuteRegExpNoStatics(JSContext *cx, HandleObject obj, jschar *chars, size_t length, |
|
5839 size_t *indexp, bool test, MutableHandleValue rval) |
|
5840 { |
|
5841 AssertHeapIsIdle(cx); |
|
5842 CHECK_REQUEST(cx); |
|
5843 |
|
5844 return ExecuteRegExpLegacy(cx, nullptr, obj->as<RegExpObject>(), NullPtr(), chars, length, |
|
5845 indexp, test, rval); |
|
5846 } |
|
5847 |
|
5848 JS_PUBLIC_API(bool) |
|
5849 JS_ObjectIsRegExp(JSContext *cx, HandleObject obj) |
|
5850 { |
|
5851 assertSameCompartment(cx, obj); |
|
5852 return ObjectClassIs(obj, ESClass_RegExp, cx); |
|
5853 } |
|
5854 |
|
5855 JS_PUBLIC_API(unsigned) |
|
5856 JS_GetRegExpFlags(JSContext *cx, HandleObject obj) |
|
5857 { |
|
5858 AssertHeapIsIdle(cx); |
|
5859 CHECK_REQUEST(cx); |
|
5860 |
|
5861 return obj->as<RegExpObject>().getFlags(); |
|
5862 } |
|
5863 |
|
5864 JS_PUBLIC_API(JSString *) |
|
5865 JS_GetRegExpSource(JSContext *cx, HandleObject obj) |
|
5866 { |
|
5867 AssertHeapIsIdle(cx); |
|
5868 CHECK_REQUEST(cx); |
|
5869 |
|
5870 return obj->as<RegExpObject>().getSource(); |
|
5871 } |
|
5872 |
|
5873 /************************************************************************/ |
|
5874 |
|
5875 JS_PUBLIC_API(bool) |
|
5876 JS_SetDefaultLocale(JSRuntime *rt, const char *locale) |
|
5877 { |
|
5878 AssertHeapIsIdle(rt); |
|
5879 return rt->setDefaultLocale(locale); |
|
5880 } |
|
5881 |
|
5882 JS_PUBLIC_API(const char*) |
|
5883 JS_GetDefaultLocale(JSRuntime *rt) |
|
5884 { |
|
5885 AssertHeapIsIdle(rt); |
|
5886 return rt->getDefaultLocale(); |
|
5887 } |
|
5888 |
|
5889 JS_PUBLIC_API(void) |
|
5890 JS_ResetDefaultLocale(JSRuntime *rt) |
|
5891 { |
|
5892 AssertHeapIsIdle(rt); |
|
5893 rt->resetDefaultLocale(); |
|
5894 } |
|
5895 |
|
5896 JS_PUBLIC_API(void) |
|
5897 JS_SetLocaleCallbacks(JSRuntime *rt, JSLocaleCallbacks *callbacks) |
|
5898 { |
|
5899 AssertHeapIsIdle(rt); |
|
5900 rt->localeCallbacks = callbacks; |
|
5901 } |
|
5902 |
|
5903 JS_PUBLIC_API(JSLocaleCallbacks *) |
|
5904 JS_GetLocaleCallbacks(JSRuntime *rt) |
|
5905 { |
|
5906 /* This function can be called by a finalizer. */ |
|
5907 return rt->localeCallbacks; |
|
5908 } |
|
5909 |
|
5910 /************************************************************************/ |
|
5911 |
|
5912 JS_PUBLIC_API(bool) |
|
5913 JS_IsExceptionPending(JSContext *cx) |
|
5914 { |
|
5915 /* This function can be called by a finalizer. */ |
|
5916 return (bool) cx->isExceptionPending(); |
|
5917 } |
|
5918 |
|
5919 JS_PUBLIC_API(bool) |
|
5920 JS_GetPendingException(JSContext *cx, MutableHandleValue vp) |
|
5921 { |
|
5922 AssertHeapIsIdle(cx); |
|
5923 CHECK_REQUEST(cx); |
|
5924 if (!cx->isExceptionPending()) |
|
5925 return false; |
|
5926 return cx->getPendingException(vp); |
|
5927 } |
|
5928 |
|
5929 JS_PUBLIC_API(void) |
|
5930 JS_SetPendingException(JSContext *cx, HandleValue value) |
|
5931 { |
|
5932 AssertHeapIsIdle(cx); |
|
5933 CHECK_REQUEST(cx); |
|
5934 assertSameCompartment(cx, value); |
|
5935 cx->setPendingException(value); |
|
5936 } |
|
5937 |
|
5938 JS_PUBLIC_API(void) |
|
5939 JS_ClearPendingException(JSContext *cx) |
|
5940 { |
|
5941 AssertHeapIsIdle(cx); |
|
5942 cx->clearPendingException(); |
|
5943 } |
|
5944 |
|
5945 JS_PUBLIC_API(bool) |
|
5946 JS_ReportPendingException(JSContext *cx) |
|
5947 { |
|
5948 AssertHeapIsIdle(cx); |
|
5949 CHECK_REQUEST(cx); |
|
5950 |
|
5951 // This can only fail due to oom. |
|
5952 bool ok = js_ReportUncaughtException(cx); |
|
5953 JS_ASSERT(!cx->isExceptionPending()); |
|
5954 return ok; |
|
5955 } |
|
5956 |
|
5957 JS::AutoSaveExceptionState::AutoSaveExceptionState(JSContext *cx) |
|
5958 : context(cx), wasThrowing(cx->throwing), exceptionValue(cx) |
|
5959 { |
|
5960 AssertHeapIsIdle(cx); |
|
5961 CHECK_REQUEST(cx); |
|
5962 if (wasThrowing) { |
|
5963 exceptionValue = cx->unwrappedException_; |
|
5964 cx->clearPendingException(); |
|
5965 } |
|
5966 } |
|
5967 |
|
5968 void |
|
5969 JS::AutoSaveExceptionState::restore() |
|
5970 { |
|
5971 context->throwing = wasThrowing; |
|
5972 context->unwrappedException_ = exceptionValue; |
|
5973 drop(); |
|
5974 } |
|
5975 |
|
5976 JS::AutoSaveExceptionState::~AutoSaveExceptionState() |
|
5977 { |
|
5978 if (wasThrowing && !context->isExceptionPending()) { |
|
5979 context->throwing = true; |
|
5980 context->unwrappedException_ = exceptionValue; |
|
5981 } |
|
5982 } |
|
5983 |
|
5984 struct JSExceptionState { |
|
5985 bool throwing; |
|
5986 jsval exception; |
|
5987 }; |
|
5988 |
|
5989 JS_PUBLIC_API(JSExceptionState *) |
|
5990 JS_SaveExceptionState(JSContext *cx) |
|
5991 { |
|
5992 JSExceptionState *state; |
|
5993 |
|
5994 AssertHeapIsIdle(cx); |
|
5995 CHECK_REQUEST(cx); |
|
5996 state = cx->pod_malloc<JSExceptionState>(); |
|
5997 if (state) { |
|
5998 state->throwing = |
|
5999 JS_GetPendingException(cx, MutableHandleValue::fromMarkedLocation(&state->exception)); |
|
6000 if (state->throwing && JSVAL_IS_GCTHING(state->exception)) |
|
6001 AddValueRoot(cx, &state->exception, "JSExceptionState.exception"); |
|
6002 } |
|
6003 return state; |
|
6004 } |
|
6005 |
|
6006 JS_PUBLIC_API(void) |
|
6007 JS_RestoreExceptionState(JSContext *cx, JSExceptionState *state) |
|
6008 { |
|
6009 AssertHeapIsIdle(cx); |
|
6010 CHECK_REQUEST(cx); |
|
6011 if (state) { |
|
6012 if (state->throwing) |
|
6013 JS_SetPendingException(cx, HandleValue::fromMarkedLocation(&state->exception)); |
|
6014 else |
|
6015 JS_ClearPendingException(cx); |
|
6016 JS_DropExceptionState(cx, state); |
|
6017 } |
|
6018 } |
|
6019 |
|
6020 JS_PUBLIC_API(void) |
|
6021 JS_DropExceptionState(JSContext *cx, JSExceptionState *state) |
|
6022 { |
|
6023 AssertHeapIsIdle(cx); |
|
6024 CHECK_REQUEST(cx); |
|
6025 if (state) { |
|
6026 if (state->throwing && JSVAL_IS_GCTHING(state->exception)) { |
|
6027 assertSameCompartment(cx, state->exception); |
|
6028 RemoveRoot(cx->runtime(), &state->exception); |
|
6029 } |
|
6030 js_free(state); |
|
6031 } |
|
6032 } |
|
6033 |
|
6034 JS_PUBLIC_API(JSErrorReport *) |
|
6035 JS_ErrorFromException(JSContext *cx, HandleObject obj) |
|
6036 { |
|
6037 AssertHeapIsIdle(cx); |
|
6038 CHECK_REQUEST(cx); |
|
6039 assertSameCompartment(cx, obj); |
|
6040 return js_ErrorFromException(cx, obj); |
|
6041 } |
|
6042 |
|
6043 JS_PUBLIC_API(bool) |
|
6044 JS_ThrowStopIteration(JSContext *cx) |
|
6045 { |
|
6046 AssertHeapIsIdle(cx); |
|
6047 return js_ThrowStopIteration(cx); |
|
6048 } |
|
6049 |
|
6050 JS_PUBLIC_API(bool) |
|
6051 JS_IsStopIteration(jsval v) |
|
6052 { |
|
6053 return v.isObject() && v.toObject().is<StopIterationObject>(); |
|
6054 } |
|
6055 |
|
6056 JS_PUBLIC_API(intptr_t) |
|
6057 JS_GetCurrentThread() |
|
6058 { |
|
6059 #ifdef JS_THREADSAFE |
|
6060 return reinterpret_cast<intptr_t>(PR_GetCurrentThread()); |
|
6061 #else |
|
6062 return 0; |
|
6063 #endif |
|
6064 } |
|
6065 |
|
6066 extern MOZ_NEVER_INLINE JS_PUBLIC_API(void) |
|
6067 JS_AbortIfWrongThread(JSRuntime *rt) |
|
6068 { |
|
6069 if (!CurrentThreadCanAccessRuntime(rt)) |
|
6070 MOZ_CRASH(); |
|
6071 if (!js::TlsPerThreadData.get()->associatedWith(rt)) |
|
6072 MOZ_CRASH(); |
|
6073 } |
|
6074 |
|
6075 #ifdef JS_GC_ZEAL |
|
6076 JS_PUBLIC_API(void) |
|
6077 JS_SetGCZeal(JSContext *cx, uint8_t zeal, uint32_t frequency) |
|
6078 { |
|
6079 SetGCZeal(cx->runtime(), zeal, frequency); |
|
6080 } |
|
6081 |
|
6082 JS_PUBLIC_API(void) |
|
6083 JS_ScheduleGC(JSContext *cx, uint32_t count) |
|
6084 { |
|
6085 cx->runtime()->gcNextScheduled = count; |
|
6086 } |
|
6087 #endif |
|
6088 |
|
6089 JS_PUBLIC_API(void) |
|
6090 JS_SetParallelParsingEnabled(JSRuntime *rt, bool enabled) |
|
6091 { |
|
6092 #ifdef JS_ION |
|
6093 rt->setParallelParsingEnabled(enabled); |
|
6094 #endif |
|
6095 } |
|
6096 |
|
6097 JS_PUBLIC_API(void) |
|
6098 JS_SetParallelIonCompilationEnabled(JSRuntime *rt, bool enabled) |
|
6099 { |
|
6100 #ifdef JS_ION |
|
6101 rt->setParallelIonCompilationEnabled(enabled); |
|
6102 #endif |
|
6103 } |
|
6104 |
|
6105 JS_PUBLIC_API(void) |
|
6106 JS_SetGlobalJitCompilerOption(JSRuntime *rt, JSJitCompilerOption opt, uint32_t value) |
|
6107 { |
|
6108 #ifdef JS_ION |
|
6109 |
|
6110 switch (opt) { |
|
6111 case JSJITCOMPILER_BASELINE_USECOUNT_TRIGGER: |
|
6112 if (value == uint32_t(-1)) { |
|
6113 jit::JitOptions defaultValues; |
|
6114 value = defaultValues.baselineUsesBeforeCompile; |
|
6115 } |
|
6116 jit::js_JitOptions.baselineUsesBeforeCompile = value; |
|
6117 break; |
|
6118 case JSJITCOMPILER_ION_USECOUNT_TRIGGER: |
|
6119 if (value == uint32_t(-1)) { |
|
6120 jit::js_JitOptions.resetUsesBeforeCompile(); |
|
6121 break; |
|
6122 } |
|
6123 jit::js_JitOptions.setUsesBeforeCompile(value); |
|
6124 if (value == 0) |
|
6125 jit::js_JitOptions.setEagerCompilation(); |
|
6126 break; |
|
6127 case JSJITCOMPILER_ION_ENABLE: |
|
6128 if (value == 1) { |
|
6129 JS::RuntimeOptionsRef(rt).setIon(true); |
|
6130 IonSpew(js::jit::IonSpew_Scripts, "Enable ion"); |
|
6131 } else if (value == 0) { |
|
6132 JS::RuntimeOptionsRef(rt).setIon(false); |
|
6133 IonSpew(js::jit::IonSpew_Scripts, "Disable ion"); |
|
6134 } |
|
6135 break; |
|
6136 case JSJITCOMPILER_BASELINE_ENABLE: |
|
6137 if (value == 1) { |
|
6138 JS::RuntimeOptionsRef(rt).setBaseline(true); |
|
6139 IonSpew(js::jit::IonSpew_BaselineScripts, "Enable baseline"); |
|
6140 } else if (value == 0) { |
|
6141 JS::RuntimeOptionsRef(rt).setBaseline(false); |
|
6142 IonSpew(js::jit::IonSpew_BaselineScripts, "Disable baseline"); |
|
6143 } |
|
6144 break; |
|
6145 case JSJITCOMPILER_PARALLEL_COMPILATION_ENABLE: |
|
6146 if (value == 1) { |
|
6147 rt->setParallelIonCompilationEnabled(true); |
|
6148 IonSpew(js::jit::IonSpew_Scripts, "Enable parallel compilation"); |
|
6149 } else if (value == 0) { |
|
6150 rt->setParallelIonCompilationEnabled(false); |
|
6151 IonSpew(js::jit::IonSpew_Scripts, "Disable parallel compilation"); |
|
6152 } |
|
6153 break; |
|
6154 default: |
|
6155 break; |
|
6156 } |
|
6157 #endif |
|
6158 } |
|
6159 |
|
6160 JS_PUBLIC_API(int) |
|
6161 JS_GetGlobalJitCompilerOption(JSRuntime *rt, JSJitCompilerOption opt) |
|
6162 { |
|
6163 #ifdef JS_ION |
|
6164 switch (opt) { |
|
6165 case JSJITCOMPILER_BASELINE_USECOUNT_TRIGGER: |
|
6166 return jit::js_JitOptions.baselineUsesBeforeCompile; |
|
6167 case JSJITCOMPILER_ION_USECOUNT_TRIGGER: |
|
6168 return jit::js_JitOptions.forcedDefaultIonUsesBeforeCompile; |
|
6169 case JSJITCOMPILER_ION_ENABLE: |
|
6170 return JS::RuntimeOptionsRef(rt).ion(); |
|
6171 case JSJITCOMPILER_BASELINE_ENABLE: |
|
6172 return JS::RuntimeOptionsRef(rt).baseline(); |
|
6173 case JSJITCOMPILER_PARALLEL_COMPILATION_ENABLE: |
|
6174 return rt->canUseParallelIonCompilation(); |
|
6175 default: |
|
6176 break; |
|
6177 } |
|
6178 #endif |
|
6179 return 0; |
|
6180 } |
|
6181 |
|
6182 /************************************************************************/ |
|
6183 |
|
6184 #if !defined(STATIC_EXPORTABLE_JS_API) && !defined(STATIC_JS_API) && defined(XP_WIN) |
|
6185 |
|
6186 #include "jswin.h" |
|
6187 |
|
6188 /* |
|
6189 * Initialization routine for the JS DLL. |
|
6190 */ |
|
6191 BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved) |
|
6192 { |
|
6193 return TRUE; |
|
6194 } |
|
6195 |
|
6196 #endif |
|
6197 |
|
6198 JS_PUBLIC_API(bool) |
|
6199 JS_IndexToId(JSContext *cx, uint32_t index, MutableHandleId id) |
|
6200 { |
|
6201 return IndexToId(cx, index, id); |
|
6202 } |
|
6203 |
|
6204 JS_PUBLIC_API(bool) |
|
6205 JS_CharsToId(JSContext* cx, JS::TwoByteChars chars, MutableHandleId idp) |
|
6206 { |
|
6207 RootedAtom atom(cx, AtomizeChars(cx, chars.start().get(), chars.length())); |
|
6208 if (!atom) |
|
6209 return false; |
|
6210 #ifdef DEBUG |
|
6211 uint32_t dummy; |
|
6212 MOZ_ASSERT(!atom->isIndex(&dummy), "API misuse: |chars| must not encode an index"); |
|
6213 #endif |
|
6214 idp.set(AtomToId(atom)); |
|
6215 return true; |
|
6216 } |
|
6217 |
|
6218 JS_PUBLIC_API(bool) |
|
6219 JS_IsIdentifier(JSContext *cx, HandleString str, bool *isIdentifier) |
|
6220 { |
|
6221 assertSameCompartment(cx, str); |
|
6222 |
|
6223 JSLinearString* linearStr = str->ensureLinear(cx); |
|
6224 if (!linearStr) |
|
6225 return false; |
|
6226 |
|
6227 *isIdentifier = js::frontend::IsIdentifier(linearStr); |
|
6228 return true; |
|
6229 } |
|
6230 |
|
6231 namespace JS { |
|
6232 |
|
6233 void |
|
6234 AutoFilename::reset(void *newScriptSource) |
|
6235 { |
|
6236 if (newScriptSource) |
|
6237 reinterpret_cast<ScriptSource*>(newScriptSource)->incref(); |
|
6238 if (scriptSource_) |
|
6239 reinterpret_cast<ScriptSource*>(scriptSource_)->decref(); |
|
6240 scriptSource_ = newScriptSource; |
|
6241 } |
|
6242 |
|
6243 const char * |
|
6244 AutoFilename::get() const |
|
6245 { |
|
6246 JS_ASSERT(scriptSource_); |
|
6247 return reinterpret_cast<ScriptSource*>(scriptSource_)->filename(); |
|
6248 } |
|
6249 |
|
6250 JS_PUBLIC_API(bool) |
|
6251 DescribeScriptedCaller(JSContext *cx, AutoFilename *filename, unsigned *lineno) |
|
6252 { |
|
6253 if (lineno) |
|
6254 *lineno = 0; |
|
6255 |
|
6256 NonBuiltinFrameIter i(cx); |
|
6257 if (i.done()) |
|
6258 return false; |
|
6259 |
|
6260 // If the caller is hidden, the embedding wants us to return false here so |
|
6261 // that it can check its own stack (see HideScriptedCaller). |
|
6262 if (i.activation()->scriptedCallerIsHidden()) |
|
6263 return false; |
|
6264 |
|
6265 if (filename) |
|
6266 filename->reset(i.scriptSource()); |
|
6267 if (lineno) |
|
6268 *lineno = i.computeLine(); |
|
6269 return true; |
|
6270 } |
|
6271 |
|
6272 JS_PUBLIC_API(JSObject *) |
|
6273 GetScriptedCallerGlobal(JSContext *cx) |
|
6274 { |
|
6275 NonBuiltinFrameIter i(cx); |
|
6276 if (i.done()) |
|
6277 return nullptr; |
|
6278 |
|
6279 // If the caller is hidden, the embedding wants us to return null here so |
|
6280 // that it can check its own stack (see HideScriptedCaller). |
|
6281 if (i.activation()->scriptedCallerIsHidden()) |
|
6282 return nullptr; |
|
6283 |
|
6284 GlobalObject *global = i.activation()->compartment()->maybeGlobal(); |
|
6285 |
|
6286 // Noone should be running code in the atoms compartment or running code in |
|
6287 // a compartment without any live objects, so there should definitely be a |
|
6288 // live global. |
|
6289 JS_ASSERT(global); |
|
6290 |
|
6291 return global; |
|
6292 } |
|
6293 |
|
6294 JS_PUBLIC_API(void) |
|
6295 HideScriptedCaller(JSContext *cx) |
|
6296 { |
|
6297 MOZ_ASSERT(cx); |
|
6298 |
|
6299 // If there's no accessible activation on the stack, we'll return null from |
|
6300 // DescribeScriptedCaller anyway, so there's no need to annotate anything. |
|
6301 Activation *act = cx->runtime()->mainThread.activation(); |
|
6302 if (!act) |
|
6303 return; |
|
6304 act->hideScriptedCaller(); |
|
6305 } |
|
6306 |
|
6307 JS_PUBLIC_API(void) |
|
6308 UnhideScriptedCaller(JSContext *cx) |
|
6309 { |
|
6310 Activation *act = cx->runtime()->mainThread.activation(); |
|
6311 if (!act) |
|
6312 return; |
|
6313 act->unhideScriptedCaller(); |
|
6314 } |
|
6315 |
|
6316 } /* namespace JS */ |
|
6317 |
|
6318 #ifdef JS_THREADSAFE |
|
6319 static PRStatus |
|
6320 CallOnce(void *func) |
|
6321 { |
|
6322 JSInitCallback init = JS_DATA_TO_FUNC_PTR(JSInitCallback, func); |
|
6323 return init() ? PR_SUCCESS : PR_FAILURE; |
|
6324 } |
|
6325 #endif |
|
6326 |
|
6327 JS_PUBLIC_API(bool) |
|
6328 JS_CallOnce(JSCallOnceType *once, JSInitCallback func) |
|
6329 { |
|
6330 #ifdef JS_THREADSAFE |
|
6331 return PR_CallOnceWithArg(once, CallOnce, JS_FUNC_TO_DATA_PTR(void *, func)) == PR_SUCCESS; |
|
6332 #else |
|
6333 if (!*once) { |
|
6334 *once = true; |
|
6335 return func(); |
|
6336 } else { |
|
6337 return true; |
|
6338 } |
|
6339 #endif |
|
6340 } |
|
6341 |
|
6342 AutoGCRooter::AutoGCRooter(JSContext *cx, ptrdiff_t tag) |
|
6343 : down(ContextFriendFields::get(cx)->autoGCRooters), |
|
6344 tag_(tag), |
|
6345 stackTop(&ContextFriendFields::get(cx)->autoGCRooters) |
|
6346 { |
|
6347 JS_ASSERT(this != *stackTop); |
|
6348 *stackTop = this; |
|
6349 } |
|
6350 |
|
6351 AutoGCRooter::AutoGCRooter(ContextFriendFields *cx, ptrdiff_t tag) |
|
6352 : down(cx->autoGCRooters), |
|
6353 tag_(tag), |
|
6354 stackTop(&cx->autoGCRooters) |
|
6355 { |
|
6356 JS_ASSERT(this != *stackTop); |
|
6357 *stackTop = this; |
|
6358 } |
|
6359 |
|
6360 #ifdef DEBUG |
|
6361 JS_PUBLIC_API(void) |
|
6362 JS::AssertArgumentsAreSane(JSContext *cx, HandleValue value) |
|
6363 { |
|
6364 AssertHeapIsIdle(cx); |
|
6365 CHECK_REQUEST(cx); |
|
6366 assertSameCompartment(cx, value); |
|
6367 } |
|
6368 #endif /* DEBUG */ |
|
6369 |
|
6370 JS_PUBLIC_API(void *) |
|
6371 JS_EncodeScript(JSContext *cx, HandleScript scriptArg, uint32_t *lengthp) |
|
6372 { |
|
6373 XDREncoder encoder(cx); |
|
6374 RootedScript script(cx, scriptArg); |
|
6375 if (!encoder.codeScript(&script)) |
|
6376 return nullptr; |
|
6377 return encoder.forgetData(lengthp); |
|
6378 } |
|
6379 |
|
6380 JS_PUBLIC_API(void *) |
|
6381 JS_EncodeInterpretedFunction(JSContext *cx, HandleObject funobjArg, uint32_t *lengthp) |
|
6382 { |
|
6383 XDREncoder encoder(cx); |
|
6384 RootedObject funobj(cx, funobjArg); |
|
6385 if (!encoder.codeFunction(&funobj)) |
|
6386 return nullptr; |
|
6387 return encoder.forgetData(lengthp); |
|
6388 } |
|
6389 |
|
6390 JS_PUBLIC_API(JSScript *) |
|
6391 JS_DecodeScript(JSContext *cx, const void *data, uint32_t length, |
|
6392 JSPrincipals *originPrincipals) |
|
6393 { |
|
6394 XDRDecoder decoder(cx, data, length, originPrincipals); |
|
6395 RootedScript script(cx); |
|
6396 if (!decoder.codeScript(&script)) |
|
6397 return nullptr; |
|
6398 return script; |
|
6399 } |
|
6400 |
|
6401 JS_PUBLIC_API(JSObject *) |
|
6402 JS_DecodeInterpretedFunction(JSContext *cx, const void *data, uint32_t length, |
|
6403 JSPrincipals *originPrincipals) |
|
6404 { |
|
6405 XDRDecoder decoder(cx, data, length, originPrincipals); |
|
6406 RootedObject funobj(cx); |
|
6407 if (!decoder.codeFunction(&funobj)) |
|
6408 return nullptr; |
|
6409 return funobj; |
|
6410 } |
|
6411 |
|
6412 JS_PUBLIC_API(bool) |
|
6413 JS_PreventExtensions(JSContext *cx, JS::HandleObject obj) |
|
6414 { |
|
6415 bool extensible; |
|
6416 if (!JSObject::isExtensible(cx, obj, &extensible)) |
|
6417 return false; |
|
6418 if (!extensible) |
|
6419 return true; |
|
6420 return JSObject::preventExtensions(cx, obj); |
|
6421 } |
|
6422 |
|
6423 JS_PUBLIC_API(void) |
|
6424 JS::SetAsmJSCacheOps(JSRuntime *rt, const JS::AsmJSCacheOps *ops) |
|
6425 { |
|
6426 rt->asmJSCacheOps = *ops; |
|
6427 } |
|
6428 |
|
6429 char * |
|
6430 JSAutoByteString::encodeLatin1(ExclusiveContext *cx, JSString *str) |
|
6431 { |
|
6432 JSLinearString *linear = str->ensureLinear(cx); |
|
6433 if (!linear) |
|
6434 return nullptr; |
|
6435 |
|
6436 mBytes = LossyTwoByteCharsToNewLatin1CharsZ(cx, linear->range()).c_str(); |
|
6437 return mBytes; |
|
6438 } |
|
6439 |
|
6440 JS_PUBLIC_API(void) |
|
6441 JS::SetLargeAllocationFailureCallback(JSRuntime *rt, JS::LargeAllocationFailureCallback lafc) |
|
6442 { |
|
6443 rt->largeAllocationFailureCallback = lafc; |
|
6444 } |
|
6445 |
|
6446 JS_PUBLIC_API(void) |
|
6447 JS::SetOutOfMemoryCallback(JSRuntime *rt, OutOfMemoryCallback cb) |
|
6448 { |
|
6449 rt->oomCallback = cb; |
|
6450 } |
|
6451 |