Line data Source code
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 : #include "vm/SelfHosting.h"
8 :
9 : #include "mozilla/ArrayUtils.h"
10 : #include "mozilla/Casting.h"
11 : #include "mozilla/DebugOnly.h"
12 : #include "mozilla/Maybe.h"
13 :
14 : #include "jsarray.h"
15 : #include "jscntxt.h"
16 : #include "jscompartment.h"
17 : #include "jsdate.h"
18 : #include "jsfriendapi.h"
19 : #include "jsfun.h"
20 : #include "jshashutil.h"
21 : #include "jsiter.h"
22 : #include "jsstr.h"
23 : #include "jsweakmap.h"
24 : #include "jswrapper.h"
25 : #include "selfhosted.out.h"
26 :
27 : #include "builtin/Intl.h"
28 : #include "builtin/MapObject.h"
29 : #include "builtin/ModuleObject.h"
30 : #include "builtin/Object.h"
31 : #include "builtin/Promise.h"
32 : #include "builtin/Reflect.h"
33 : #include "builtin/RegExp.h"
34 : #include "builtin/SelfHostingDefines.h"
35 : #include "builtin/SIMD.h"
36 : #include "builtin/TypedObject.h"
37 : #include "builtin/WeakSetObject.h"
38 : #include "gc/Marking.h"
39 : #include "gc/Policy.h"
40 : #include "jit/AtomicOperations.h"
41 : #include "jit/InlinableNatives.h"
42 : #include "js/CharacterEncoding.h"
43 : #include "js/Date.h"
44 : #include "vm/Compression.h"
45 : #include "vm/GeneratorObject.h"
46 : #include "vm/Interpreter.h"
47 : #include "vm/RegExpObject.h"
48 : #include "vm/String.h"
49 : #include "vm/StringBuffer.h"
50 : #include "vm/TypedArrayObject.h"
51 : #include "vm/WrapperObject.h"
52 :
53 : #include "jsatominlines.h"
54 : #include "jsfuninlines.h"
55 : #include "jsobjinlines.h"
56 : #include "jsscriptinlines.h"
57 :
58 : #include "vm/BooleanObject-inl.h"
59 : #include "vm/NativeObject-inl.h"
60 : #include "vm/NumberObject-inl.h"
61 : #include "vm/StringObject-inl.h"
62 :
63 : using namespace js;
64 : using namespace js::selfhosted;
65 :
66 : using JS::AutoCheckCannotGC;
67 : using mozilla::IsInRange;
68 : using mozilla::Maybe;
69 : using mozilla::PodMove;
70 : using mozilla::Maybe;
71 :
72 : static void
73 0 : selfHosting_WarningReporter(JSContext* cx, JSErrorReport* report)
74 : {
75 0 : MOZ_ASSERT(report);
76 0 : MOZ_ASSERT(JSREPORT_IS_WARNING(report->flags));
77 :
78 0 : PrintError(cx, stderr, JS::ConstUTF8CharsZ(), report, true);
79 0 : }
80 :
81 : static bool
82 2903 : intrinsic_ToObject(JSContext* cx, unsigned argc, Value* vp)
83 : {
84 2903 : CallArgs args = CallArgsFromVp(argc, vp);
85 2903 : JSObject* obj = ToObject(cx, args[0]);
86 2903 : if (!obj)
87 0 : return false;
88 2903 : args.rval().setObject(*obj);
89 2903 : return true;
90 : }
91 :
92 : static bool
93 7131 : intrinsic_IsObject(JSContext* cx, unsigned argc, Value* vp)
94 : {
95 7131 : CallArgs args = CallArgsFromVp(argc, vp);
96 7131 : Value val = args[0];
97 7131 : bool isObject = val.isObject();
98 7131 : args.rval().setBoolean(isObject);
99 7131 : return true;
100 : }
101 :
102 : static bool
103 264 : intrinsic_IsArray(JSContext* cx, unsigned argc, Value* vp)
104 : {
105 264 : CallArgs args = CallArgsFromVp(argc, vp);
106 264 : MOZ_ASSERT(args.length() == 1);
107 528 : RootedValue val(cx, args[0]);
108 264 : if (val.isObject()) {
109 528 : RootedObject obj(cx, &val.toObject());
110 264 : bool isArray = false;
111 264 : if (!IsArray(cx, obj, &isArray))
112 0 : return false;
113 264 : args.rval().setBoolean(isArray);
114 : } else {
115 0 : args.rval().setBoolean(false);
116 : }
117 264 : return true;
118 : }
119 :
120 : static bool
121 151 : intrinsic_IsWrappedArrayConstructor(JSContext* cx, unsigned argc, Value* vp)
122 : {
123 151 : CallArgs args = CallArgsFromVp(argc, vp);
124 151 : bool result = false;
125 151 : if (!IsWrappedArrayConstructor(cx, args[0], &result))
126 0 : return false;
127 151 : args.rval().setBoolean(result);
128 151 : return true;
129 : }
130 :
131 : static bool
132 5515 : intrinsic_ToInteger(JSContext* cx, unsigned argc, Value* vp)
133 : {
134 5515 : CallArgs args = CallArgsFromVp(argc, vp);
135 : double result;
136 5515 : if (!ToInteger(cx, args[0], &result))
137 0 : return false;
138 5515 : args.rval().setNumber(result);
139 5515 : return true;
140 : }
141 :
142 : static bool
143 459 : intrinsic_ToString(JSContext* cx, unsigned argc, Value* vp)
144 : {
145 459 : CallArgs args = CallArgsFromVp(argc, vp);
146 459 : JSString* str = ToString<CanGC>(cx, args[0]);
147 459 : if (!str)
148 0 : return false;
149 459 : args.rval().setString(str);
150 459 : return true;
151 : }
152 :
153 : static bool
154 0 : intrinsic_ToSource(JSContext* cx, unsigned argc, Value* vp)
155 : {
156 0 : CallArgs args = CallArgsFromVp(argc, vp);
157 0 : JSString* str = ValueToSource(cx, args[0]);
158 0 : if (!str)
159 0 : return false;
160 0 : args.rval().setString(str);
161 0 : return true;
162 : }
163 :
164 : static bool
165 76 : intrinsic_ToPropertyKey(JSContext* cx, unsigned argc, Value* vp)
166 : {
167 76 : CallArgs args = CallArgsFromVp(argc, vp);
168 152 : RootedId id(cx);
169 76 : if (!ToPropertyKey(cx, args[0], &id))
170 0 : return false;
171 :
172 76 : args.rval().set(IdToValue(id));
173 76 : return true;
174 : }
175 :
176 : static bool
177 892 : intrinsic_IsCallable(JSContext* cx, unsigned argc, Value* vp)
178 : {
179 892 : CallArgs args = CallArgsFromVp(argc, vp);
180 892 : args.rval().setBoolean(IsCallable(args[0]));
181 892 : return true;
182 : }
183 :
184 : static bool
185 450 : intrinsic_IsConstructor(JSContext* cx, unsigned argc, Value* vp)
186 : {
187 450 : CallArgs args = CallArgsFromVp(argc, vp);
188 450 : MOZ_ASSERT(args.length() == 1);
189 :
190 900 : RootedValue val(cx, args[0]);
191 450 : if (!IsConstructor(val)) {
192 0 : args.rval().setBoolean(false);
193 0 : return true;
194 : }
195 :
196 900 : RootedObject obj(cx, &val.toObject());
197 450 : if (!IsWrapper(obj)) {
198 450 : args.rval().setBoolean(true);
199 450 : return true;
200 : }
201 :
202 0 : obj = UncheckedUnwrap(obj);
203 0 : args.rval().setBoolean(obj && obj->isConstructor());
204 0 : return true;
205 : }
206 :
207 : template<typename T>
208 : static bool
209 6180 : intrinsic_IsInstanceOfBuiltin(JSContext* cx, unsigned argc, Value* vp)
210 : {
211 6180 : CallArgs args = CallArgsFromVp(argc, vp);
212 6180 : MOZ_ASSERT(args.length() == 1);
213 6180 : MOZ_ASSERT(args[0].isObject());
214 :
215 6180 : args.rval().setBoolean(args[0].toObject().is<T>());
216 6180 : return true;
217 : }
218 :
219 : /**
220 : * Self-hosting intrinsic returning the original constructor for a builtin
221 : * the name of which is the first and only argument.
222 : *
223 : * The return value is guaranteed to be the original constructor even if
224 : * content code changed the named binding on the global object.
225 : *
226 : * This intrinsic shouldn't be called directly. Instead, the
227 : * `GetBuiltinConstructor` and `GetBuiltinPrototype` helper functions in
228 : * Utilities.js should be used, as they cache results, improving performance.
229 : */
230 : static bool
231 59 : intrinsic_GetBuiltinConstructor(JSContext* cx, unsigned argc, Value* vp)
232 : {
233 59 : CallArgs args = CallArgsFromVp(argc, vp);
234 59 : MOZ_ASSERT(args.length() == 1);
235 118 : RootedString str(cx, args[0].toString());
236 : JSAtom* atom;
237 59 : if (str->isAtom()) {
238 59 : atom = &str->asAtom();
239 : } else {
240 0 : atom = AtomizeString(cx, str);
241 0 : if (!atom)
242 0 : return false;
243 : }
244 118 : RootedId id(cx, AtomToId(atom));
245 59 : JSProtoKey key = JS_IdToProtoKey(cx, id);
246 59 : MOZ_ASSERT(key != JSProto_Null);
247 118 : RootedObject ctor(cx);
248 59 : if (!GetBuiltinConstructor(cx, key, &ctor))
249 0 : return false;
250 59 : args.rval().setObject(*ctor);
251 59 : return true;
252 : }
253 :
254 : static bool
255 177 : intrinsic_SubstringKernel(JSContext* cx, unsigned argc, Value* vp)
256 : {
257 177 : CallArgs args = CallArgsFromVp(argc, vp);
258 177 : MOZ_ASSERT(args[0].isString());
259 177 : MOZ_ASSERT(args[1].isInt32());
260 177 : MOZ_ASSERT(args[2].isInt32());
261 :
262 354 : RootedString str(cx, args[0].toString());
263 177 : int32_t begin = args[1].toInt32();
264 177 : int32_t length = args[2].toInt32();
265 :
266 177 : JSString* substr = SubstringKernel(cx, str, begin, length);
267 177 : if (!substr)
268 0 : return false;
269 :
270 177 : args.rval().setString(substr);
271 177 : return true;
272 : }
273 :
274 : static bool
275 0 : intrinsic_OwnPropertyKeys(JSContext* cx, unsigned argc, Value* vp)
276 : {
277 0 : CallArgs args = CallArgsFromVp(argc, vp);
278 0 : MOZ_ASSERT(args[0].isObject());
279 0 : MOZ_ASSERT(args[1].isInt32());
280 0 : return GetOwnPropertyKeys(cx, args, args[1].toInt32());
281 : }
282 :
283 : static void
284 0 : ThrowErrorWithType(JSContext* cx, JSExnType type, const CallArgs& args)
285 : {
286 0 : uint32_t errorNumber = args[0].toInt32();
287 :
288 : #ifdef DEBUG
289 0 : const JSErrorFormatString* efs = GetErrorMessage(nullptr, errorNumber);
290 0 : MOZ_ASSERT(efs->argCount == args.length() - 1);
291 0 : MOZ_ASSERT(efs->exnType == type, "error-throwing intrinsic and error number are inconsistent");
292 : #endif
293 :
294 0 : JSAutoByteString errorArgs[3];
295 0 : for (unsigned i = 1; i < 4 && i < args.length(); i++) {
296 0 : RootedValue val(cx, args[i]);
297 0 : if (val.isInt32()) {
298 0 : JSString* str = ToString<CanGC>(cx, val);
299 0 : if (!str)
300 0 : return;
301 0 : errorArgs[i - 1].encodeLatin1(cx, str);
302 0 : } else if (val.isString()) {
303 0 : errorArgs[i - 1].encodeLatin1(cx, val.toString());
304 : } else {
305 0 : UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, val, nullptr);
306 0 : if (!bytes)
307 0 : return;
308 0 : errorArgs[i - 1].initBytes(Move(bytes));
309 : }
310 0 : if (!errorArgs[i - 1])
311 0 : return;
312 : }
313 :
314 0 : JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, errorNumber,
315 0 : errorArgs[0].ptr(), errorArgs[1].ptr(), errorArgs[2].ptr());
316 : }
317 :
318 : static bool
319 0 : intrinsic_ThrowRangeError(JSContext* cx, unsigned argc, Value* vp)
320 : {
321 0 : CallArgs args = CallArgsFromVp(argc, vp);
322 0 : MOZ_ASSERT(args.length() >= 1);
323 :
324 0 : ThrowErrorWithType(cx, JSEXN_RANGEERR, args);
325 0 : return false;
326 : }
327 :
328 : static bool
329 0 : intrinsic_ThrowTypeError(JSContext* cx, unsigned argc, Value* vp)
330 : {
331 0 : CallArgs args = CallArgsFromVp(argc, vp);
332 0 : MOZ_ASSERT(args.length() >= 1);
333 :
334 0 : ThrowErrorWithType(cx, JSEXN_TYPEERR, args);
335 0 : return false;
336 : }
337 :
338 : static bool
339 0 : intrinsic_ThrowSyntaxError(JSContext* cx, unsigned argc, Value* vp)
340 : {
341 0 : CallArgs args = CallArgsFromVp(argc, vp);
342 0 : MOZ_ASSERT(args.length() >= 1);
343 :
344 0 : ThrowErrorWithType(cx, JSEXN_SYNTAXERR, args);
345 0 : return false;
346 : }
347 :
348 : static bool
349 0 : intrinsic_ThrowInternalError(JSContext* cx, unsigned argc, Value* vp)
350 : {
351 0 : CallArgs args = CallArgsFromVp(argc, vp);
352 0 : MOZ_ASSERT(args.length() >= 1);
353 :
354 0 : ThrowErrorWithType(cx, JSEXN_INTERNALERR, args);
355 0 : return false;
356 : }
357 :
358 : /**
359 : * Handles an assertion failure in self-hosted code just like an assertion
360 : * failure in C++ code. Information about the failure can be provided in args[0].
361 : */
362 : static bool
363 0 : intrinsic_AssertionFailed(JSContext* cx, unsigned argc, Value* vp)
364 : {
365 : #ifdef DEBUG
366 0 : CallArgs args = CallArgsFromVp(argc, vp);
367 0 : if (args.length() > 0) {
368 : // try to dump the informative string
369 0 : JSString* str = ToString<CanGC>(cx, args[0]);
370 0 : if (str) {
371 0 : fprintf(stderr, "Self-hosted JavaScript assertion info: ");
372 0 : str->dumpCharsNoNewline();
373 0 : fputc('\n', stderr);
374 : }
375 : }
376 : #endif
377 0 : MOZ_ASSERT(false);
378 : return false;
379 : }
380 :
381 : /**
382 : * Dumps a message to stderr, after stringifying it. Doesn't append a newline.
383 : */
384 : static bool
385 0 : intrinsic_DumpMessage(JSContext* cx, unsigned argc, Value* vp)
386 : {
387 0 : CallArgs args = CallArgsFromVp(argc, vp);
388 : #ifdef DEBUG
389 0 : if (args.length() > 0) {
390 : // try to dump the informative string
391 0 : JSString* str = ToString<CanGC>(cx, args[0]);
392 0 : if (str) {
393 0 : str->dumpCharsNoNewline();
394 0 : fputc('\n', stderr);
395 : } else {
396 0 : cx->recoverFromOutOfMemory();
397 : }
398 : }
399 : #endif
400 0 : args.rval().setUndefined();
401 0 : return true;
402 : }
403 :
404 : static bool
405 6 : intrinsic_MakeConstructible(JSContext* cx, unsigned argc, Value* vp)
406 : {
407 6 : CallArgs args = CallArgsFromVp(argc, vp);
408 6 : MOZ_ASSERT(args.length() == 2);
409 6 : MOZ_ASSERT(args[0].isObject());
410 6 : MOZ_ASSERT(args[0].toObject().is<JSFunction>());
411 6 : MOZ_ASSERT(args[0].toObject().as<JSFunction>().isSelfHostedBuiltin());
412 6 : MOZ_ASSERT(args[1].isObjectOrNull());
413 :
414 : // Normal .prototype properties aren't enumerable. But for this to clone
415 : // correctly, it must be enumerable.
416 12 : RootedObject ctor(cx, &args[0].toObject());
417 6 : if (!DefineProperty(cx, ctor, cx->names().prototype, args[1],
418 : nullptr, nullptr,
419 : JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT))
420 : {
421 0 : return false;
422 : }
423 :
424 6 : ctor->as<JSFunction>().setIsConstructor();
425 6 : args.rval().setUndefined();
426 6 : return true;
427 : }
428 :
429 : static bool
430 6 : intrinsic_MakeDefaultConstructor(JSContext* cx, unsigned argc, Value* vp)
431 : {
432 6 : CallArgs args = CallArgsFromVp(argc, vp);
433 6 : MOZ_ASSERT(args.length() == 1);
434 6 : MOZ_ASSERT(args[0].toObject().as<JSFunction>().isSelfHostedBuiltin());
435 :
436 12 : RootedFunction ctor(cx, &args[0].toObject().as<JSFunction>());
437 :
438 6 : ctor->nonLazyScript()->setIsDefaultClassConstructor();
439 :
440 : // Because self-hosting code does not allow top-level lexicals,
441 : // class constructors are class expressions in top-level vars.
442 : // Because of this, we give them a guessed atom. Since they
443 : // will always be cloned, and given an explicit atom, instead
444 : // overrule that.
445 6 : ctor->clearGuessedAtom();
446 :
447 6 : args.rval().setUndefined();
448 12 : return true;
449 : }
450 :
451 : static bool
452 330 : intrinsic_FinishBoundFunctionInit(JSContext* cx, unsigned argc, Value* vp)
453 : {
454 330 : CallArgs args = CallArgsFromVp(argc, vp);
455 330 : MOZ_ASSERT(args.length() == 3);
456 330 : MOZ_ASSERT(IsCallable(args[1]));
457 330 : MOZ_ASSERT(args[2].isInt32());
458 :
459 660 : RootedFunction bound(cx, &args[0].toObject().as<JSFunction>());
460 660 : RootedObject targetObj(cx, &args[1].toObject());
461 330 : int32_t argCount = args[2].toInt32();
462 :
463 330 : args.rval().setUndefined();
464 660 : return JSFunction::finishBoundFunctionInit(cx, bound, targetObj, argCount);
465 : }
466 :
467 : /*
468 : * Used to decompile values in the nearest non-builtin stack frame, falling
469 : * back to decompiling in the current frame. Helpful for printing higher-order
470 : * function arguments.
471 : *
472 : * The user must supply the argument number of the value in question; it
473 : * _cannot_ be automatically determined.
474 : */
475 : static bool
476 0 : intrinsic_DecompileArg(JSContext* cx, unsigned argc, Value* vp)
477 : {
478 0 : CallArgs args = CallArgsFromVp(argc, vp);
479 0 : MOZ_ASSERT(args.length() == 2);
480 :
481 0 : RootedValue value(cx, args[1]);
482 0 : ScopedJSFreePtr<char> str(DecompileArgument(cx, args[0].toInt32(), value));
483 0 : if (!str)
484 0 : return false;
485 0 : JSAtom* atom = Atomize(cx, str, strlen(str));
486 0 : if (!atom)
487 0 : return false;
488 0 : args.rval().setString(atom);
489 0 : return true;
490 : }
491 :
492 : static bool
493 0 : intrinsic_DefineDataProperty(JSContext* cx, unsigned argc, Value* vp)
494 : {
495 0 : CallArgs args = CallArgsFromVp(argc, vp);
496 :
497 : // When DefineDataProperty is called with 3 arguments, it's compiled to
498 : // JSOP_INITELEM in the bytecode emitter so we shouldn't get here.
499 0 : MOZ_ASSERT(args.length() == 4);
500 0 : MOZ_ASSERT(args[0].isObject());
501 :
502 0 : RootedObject obj(cx, &args[0].toObject());
503 0 : RootedId id(cx);
504 0 : if (!ValueToId<CanGC>(cx, args[1], &id))
505 0 : return false;
506 0 : RootedValue value(cx, args[2]);
507 :
508 0 : unsigned attrs = 0;
509 0 : unsigned attributes = args[3].toInt32();
510 :
511 0 : MOZ_ASSERT(bool(attributes & ATTR_ENUMERABLE) != bool(attributes & ATTR_NONENUMERABLE),
512 : "_DefineDataProperty must receive either ATTR_ENUMERABLE xor ATTR_NONENUMERABLE");
513 0 : if (attributes & ATTR_ENUMERABLE)
514 0 : attrs |= JSPROP_ENUMERATE;
515 :
516 0 : MOZ_ASSERT(bool(attributes & ATTR_CONFIGURABLE) != bool(attributes & ATTR_NONCONFIGURABLE),
517 : "_DefineDataProperty must receive either ATTR_CONFIGURABLE xor "
518 : "ATTR_NONCONFIGURABLE");
519 0 : if (attributes & ATTR_NONCONFIGURABLE)
520 0 : attrs |= JSPROP_PERMANENT;
521 :
522 0 : MOZ_ASSERT(bool(attributes & ATTR_WRITABLE) != bool(attributes & ATTR_NONWRITABLE),
523 : "_DefineDataProperty must receive either ATTR_WRITABLE xor ATTR_NONWRITABLE");
524 0 : if (attributes & ATTR_NONWRITABLE)
525 0 : attrs |= JSPROP_READONLY;
526 :
527 0 : Rooted<PropertyDescriptor> desc(cx);
528 0 : desc.setDataDescriptor(value, attrs);
529 0 : if (!DefineProperty(cx, obj, id, desc))
530 0 : return false;
531 :
532 0 : args.rval().setUndefined();
533 0 : return true;
534 : }
535 :
536 : static bool
537 137 : intrinsic_ObjectHasPrototype(JSContext* cx, unsigned argc, Value* vp)
538 : {
539 137 : CallArgs args = CallArgsFromVp(argc, vp);
540 137 : MOZ_ASSERT(args.length() == 2);
541 274 : RootedObject obj(cx, &args[0].toObject());
542 274 : RootedObject proto(cx, &args[1].toObject());
543 :
544 274 : RootedObject actualProto(cx);
545 137 : if (!GetPrototype(cx, obj, &actualProto))
546 0 : return false;
547 :
548 137 : args.rval().setBoolean(actualProto == proto);
549 137 : return true;
550 : }
551 :
552 : static bool
553 10859 : intrinsic_UnsafeSetReservedSlot(JSContext* cx, unsigned argc, Value* vp)
554 : {
555 10859 : CallArgs args = CallArgsFromVp(argc, vp);
556 10859 : MOZ_ASSERT(args.length() == 3);
557 10859 : MOZ_ASSERT(args[0].isObject());
558 10859 : MOZ_ASSERT(args[1].isInt32());
559 :
560 10859 : args[0].toObject().as<NativeObject>().setReservedSlot(args[1].toPrivateUint32(), args[2]);
561 10859 : args.rval().setUndefined();
562 10859 : return true;
563 : }
564 :
565 : static bool
566 15086 : intrinsic_UnsafeGetReservedSlot(JSContext* cx, unsigned argc, Value* vp)
567 : {
568 15086 : CallArgs args = CallArgsFromVp(argc, vp);
569 15086 : MOZ_ASSERT(args.length() == 2);
570 15086 : MOZ_ASSERT(args[0].isObject());
571 15086 : MOZ_ASSERT(args[1].isInt32());
572 :
573 15086 : args.rval().set(args[0].toObject().as<NativeObject>().getReservedSlot(args[1].toPrivateUint32()));
574 15086 : return true;
575 : }
576 :
577 : static bool
578 0 : intrinsic_UnsafeGetObjectFromReservedSlot(JSContext* cx, unsigned argc, Value* vp)
579 : {
580 0 : if (!intrinsic_UnsafeGetReservedSlot(cx, argc, vp))
581 0 : return false;
582 0 : MOZ_ASSERT(vp->isObject());
583 0 : return true;
584 : }
585 :
586 : static bool
587 5938 : intrinsic_UnsafeGetInt32FromReservedSlot(JSContext* cx, unsigned argc, Value* vp)
588 : {
589 5938 : if (!intrinsic_UnsafeGetReservedSlot(cx, argc, vp))
590 0 : return false;
591 5938 : MOZ_ASSERT(vp->isInt32());
592 5938 : return true;
593 : }
594 :
595 : static bool
596 17 : intrinsic_UnsafeGetStringFromReservedSlot(JSContext* cx, unsigned argc, Value* vp)
597 : {
598 17 : if (!intrinsic_UnsafeGetReservedSlot(cx, argc, vp))
599 0 : return false;
600 17 : MOZ_ASSERT(vp->isString());
601 17 : return true;
602 : }
603 :
604 : static bool
605 0 : intrinsic_UnsafeGetBooleanFromReservedSlot(JSContext* cx, unsigned argc, Value* vp)
606 : {
607 0 : if (!intrinsic_UnsafeGetReservedSlot(cx, argc, vp))
608 0 : return false;
609 0 : MOZ_ASSERT(vp->isBoolean());
610 0 : return true;
611 : }
612 :
613 : static bool
614 214 : intrinsic_IsPackedArray(JSContext* cx, unsigned argc, Value* vp)
615 : {
616 214 : CallArgs args = CallArgsFromVp(argc, vp);
617 214 : MOZ_ASSERT(args.length() == 1);
618 214 : MOZ_ASSERT(args[0].isObject());
619 214 : args.rval().setBoolean(IsPackedArray(&args[0].toObject()));
620 214 : return true;
621 : }
622 :
623 : static bool
624 0 : intrinsic_GetIteratorPrototype(JSContext* cx, unsigned argc, Value* vp)
625 : {
626 0 : CallArgs args = CallArgsFromVp(argc, vp);
627 0 : MOZ_ASSERT(args.length() == 0);
628 :
629 0 : JSObject* obj = GlobalObject::getOrCreateIteratorPrototype(cx, cx->global());
630 0 : if (!obj)
631 0 : return false;
632 :
633 0 : args.rval().setObject(*obj);
634 0 : return true;
635 : }
636 :
637 : bool
638 2098 : js::intrinsic_NewArrayIterator(JSContext* cx, unsigned argc, Value* vp)
639 : {
640 2098 : CallArgs args = CallArgsFromVp(argc, vp);
641 2098 : MOZ_ASSERT(args.length() == 0);
642 :
643 2098 : JSObject* obj = NewArrayIteratorObject(cx);
644 2098 : if (!obj)
645 0 : return false;
646 :
647 2098 : args.rval().setObject(*obj);
648 2098 : return true;
649 : }
650 :
651 : static bool
652 1070 : intrinsic_GetNextMapEntryForIterator(JSContext* cx, unsigned argc, Value* vp)
653 : {
654 1070 : CallArgs args = CallArgsFromVp(argc, vp);
655 1070 : MOZ_ASSERT(args.length() == 2);
656 1070 : MOZ_ASSERT(args[0].toObject().is<MapIteratorObject>());
657 1070 : MOZ_ASSERT(args[1].isObject());
658 :
659 2140 : Rooted<MapIteratorObject*> mapIterator(cx, &args[0].toObject().as<MapIteratorObject>());
660 2140 : RootedArrayObject result(cx, &args[1].toObject().as<ArrayObject>());
661 :
662 1070 : args.rval().setBoolean(MapIteratorObject::next(mapIterator, result, cx));
663 2140 : return true;
664 : }
665 :
666 : static bool
667 15 : intrinsic_CreateMapIterationResultPair(JSContext* cx, unsigned argc, Value* vp)
668 : {
669 15 : CallArgs args = CallArgsFromVp(argc, vp);
670 15 : MOZ_ASSERT(args.length() == 0);
671 :
672 15 : JSObject* result = MapIteratorObject::createResultPair(cx);
673 15 : if (!result)
674 0 : return false;
675 :
676 15 : args.rval().setObject(*result);
677 15 : return true;
678 : }
679 :
680 : static bool
681 255 : intrinsic_GetNextSetEntryForIterator(JSContext* cx, unsigned argc, Value* vp)
682 : {
683 255 : CallArgs args = CallArgsFromVp(argc, vp);
684 255 : MOZ_ASSERT(args.length() == 2);
685 255 : MOZ_ASSERT(args[0].toObject().is<SetIteratorObject>());
686 255 : MOZ_ASSERT(args[1].isObject());
687 :
688 510 : Rooted<SetIteratorObject*> setIterator(cx, &args[0].toObject().as<SetIteratorObject>());
689 510 : RootedArrayObject result(cx, &args[1].toObject().as<ArrayObject>());
690 :
691 255 : args.rval().setBoolean(SetIteratorObject::next(setIterator, result, cx));
692 510 : return true;
693 : }
694 :
695 : static bool
696 8 : intrinsic_CreateSetIterationResult(JSContext* cx, unsigned argc, Value* vp)
697 : {
698 8 : CallArgs args = CallArgsFromVp(argc, vp);
699 8 : MOZ_ASSERT(args.length() == 0);
700 :
701 8 : JSObject* result = SetIteratorObject::createResult(cx);
702 8 : if (!result)
703 0 : return false;
704 :
705 8 : args.rval().setObject(*result);
706 8 : return true;
707 : }
708 :
709 : bool
710 0 : js::intrinsic_NewStringIterator(JSContext* cx, unsigned argc, Value* vp)
711 : {
712 0 : CallArgs args = CallArgsFromVp(argc, vp);
713 0 : MOZ_ASSERT(args.length() == 0);
714 :
715 0 : JSObject* obj = NewStringIteratorObject(cx);
716 0 : if (!obj)
717 0 : return false;
718 :
719 0 : args.rval().setObject(*obj);
720 0 : return true;
721 : }
722 :
723 : static bool
724 63 : intrinsic_SetCanonicalName(JSContext* cx, unsigned argc, Value* vp)
725 : {
726 63 : CallArgs args = CallArgsFromVp(argc, vp);
727 63 : MOZ_ASSERT(args.length() == 2);
728 :
729 126 : RootedFunction fun(cx, &args[0].toObject().as<JSFunction>());
730 63 : MOZ_ASSERT(fun->isSelfHostedBuiltin());
731 63 : JSAtom* atom = AtomizeString(cx, args[1].toString());
732 63 : if (!atom)
733 0 : return false;
734 :
735 63 : fun->setAtom(atom);
736 : #ifdef DEBUG
737 63 : fun->setExtendedSlot(HAS_SELFHOSTED_CANONICAL_NAME_SLOT, BooleanValue(true));
738 : #endif
739 63 : args.rval().setUndefined();
740 63 : return true;
741 : }
742 :
743 : static bool
744 0 : intrinsic_StarGeneratorObjectIsClosed(JSContext* cx, unsigned argc, Value* vp)
745 : {
746 0 : CallArgs args = CallArgsFromVp(argc, vp);
747 0 : MOZ_ASSERT(args.length() == 1);
748 0 : MOZ_ASSERT(args[0].isObject());
749 :
750 0 : StarGeneratorObject* genObj = &args[0].toObject().as<StarGeneratorObject>();
751 0 : args.rval().setBoolean(genObj->isClosed());
752 0 : return true;
753 : }
754 :
755 : bool
756 126 : js::intrinsic_IsSuspendedStarGenerator(JSContext* cx, unsigned argc, Value* vp)
757 : {
758 126 : CallArgs args = CallArgsFromVp(argc, vp);
759 126 : MOZ_ASSERT(args.length() == 1);
760 :
761 126 : if (!args[0].isObject() || !args[0].toObject().is<StarGeneratorObject>()) {
762 0 : args.rval().setBoolean(false);
763 0 : return true;
764 : }
765 :
766 126 : StarGeneratorObject& genObj = args[0].toObject().as<StarGeneratorObject>();
767 126 : args.rval().setBoolean(!genObj.isClosed() && genObj.isSuspended());
768 126 : return true;
769 : }
770 :
771 : static bool
772 0 : intrinsic_LegacyGeneratorObjectIsClosed(JSContext* cx, unsigned argc, Value* vp)
773 : {
774 0 : CallArgs args = CallArgsFromVp(argc, vp);
775 0 : MOZ_ASSERT(args.length() == 1);
776 0 : MOZ_ASSERT(args[0].isObject());
777 :
778 0 : LegacyGeneratorObject* genObj = &args[0].toObject().as<LegacyGeneratorObject>();
779 0 : args.rval().setBoolean(genObj->isClosed());
780 0 : return true;
781 : }
782 :
783 : static bool
784 0 : intrinsic_CloseClosingLegacyGeneratorObject(JSContext* cx, unsigned argc, Value* vp)
785 : {
786 0 : CallArgs args = CallArgsFromVp(argc, vp);
787 0 : MOZ_ASSERT(args.length() == 1);
788 0 : MOZ_ASSERT(args[0].isObject());
789 :
790 0 : LegacyGeneratorObject* genObj = &args[0].toObject().as<LegacyGeneratorObject>();
791 0 : MOZ_ASSERT(genObj->isClosing());
792 0 : genObj->setClosed();
793 0 : return true;
794 : }
795 :
796 : static bool
797 0 : intrinsic_ThrowStopIteration(JSContext* cx, unsigned argc, Value* vp)
798 : {
799 0 : MOZ_ASSERT(CallArgsFromVp(argc, vp).length() == 0);
800 :
801 0 : return ThrowStopIteration(cx);
802 : }
803 :
804 : static bool
805 0 : intrinsic_GeneratorIsRunning(JSContext* cx, unsigned argc, Value* vp)
806 : {
807 0 : CallArgs args = CallArgsFromVp(argc, vp);
808 0 : MOZ_ASSERT(args.length() == 1);
809 0 : MOZ_ASSERT(args[0].isObject());
810 :
811 0 : GeneratorObject* genObj = &args[0].toObject().as<GeneratorObject>();
812 0 : args.rval().setBoolean(genObj->isRunning() || genObj->isClosing());
813 0 : return true;
814 : }
815 :
816 : static bool
817 0 : intrinsic_GeneratorSetClosed(JSContext* cx, unsigned argc, Value* vp)
818 : {
819 0 : CallArgs args = CallArgsFromVp(argc, vp);
820 0 : MOZ_ASSERT(args.length() == 1);
821 0 : MOZ_ASSERT(args[0].isObject());
822 :
823 0 : GeneratorObject* genObj = &args[0].toObject().as<GeneratorObject>();
824 0 : genObj->setClosed();
825 0 : return true;
826 : }
827 :
828 : template<typename T>
829 : static bool
830 0 : intrinsic_IsWrappedArrayBuffer(JSContext* cx, unsigned argc, Value* vp)
831 : {
832 0 : CallArgs args = CallArgsFromVp(argc, vp);
833 0 : MOZ_ASSERT(args.length() == 1);
834 :
835 0 : if (!args[0].isObject()) {
836 0 : args.rval().setBoolean(false);
837 0 : return true;
838 : }
839 :
840 0 : JSObject* obj = &args[0].toObject();
841 0 : if (!obj->is<WrapperObject>()) {
842 0 : args.rval().setBoolean(false);
843 0 : return true;
844 : }
845 :
846 0 : JSObject* unwrapped = CheckedUnwrap(obj);
847 0 : if (!unwrapped) {
848 0 : ReportAccessDenied(cx);
849 0 : return false;
850 : }
851 :
852 0 : args.rval().setBoolean(unwrapped->is<T>());
853 0 : return true;
854 : }
855 :
856 : template<typename T>
857 : static bool
858 0 : intrinsic_ArrayBufferByteLength(JSContext* cx, unsigned argc, Value* vp)
859 : {
860 0 : CallArgs args = CallArgsFromVp(argc, vp);
861 0 : MOZ_ASSERT(args.length() == 1);
862 0 : MOZ_ASSERT(args[0].isObject());
863 0 : MOZ_ASSERT(args[0].toObject().is<T>());
864 :
865 0 : size_t byteLength = args[0].toObject().as<T>().byteLength();
866 0 : args.rval().setInt32(mozilla::AssertedCast<int32_t>(byteLength));
867 0 : return true;
868 : }
869 :
870 : template<typename T>
871 : static bool
872 0 : intrinsic_PossiblyWrappedArrayBufferByteLength(JSContext* cx, unsigned argc, Value* vp)
873 : {
874 0 : CallArgs args = CallArgsFromVp(argc, vp);
875 0 : MOZ_ASSERT(args.length() == 1);
876 :
877 0 : JSObject* obj = CheckedUnwrap(&args[0].toObject());
878 0 : if (!obj) {
879 0 : ReportAccessDenied(cx);
880 0 : return false;
881 : }
882 :
883 0 : uint32_t length = obj->as<T>().byteLength();
884 0 : args.rval().setInt32(mozilla::AssertedCast<int32_t>(length));
885 0 : return true;
886 : }
887 :
888 : template<typename T>
889 : static bool
890 0 : intrinsic_ArrayBufferCopyData(JSContext* cx, unsigned argc, Value* vp)
891 : {
892 0 : CallArgs args = CallArgsFromVp(argc, vp);
893 0 : MOZ_ASSERT(args.length() == 6);
894 :
895 0 : bool isWrapped = args[5].toBoolean();
896 0 : Rooted<T*> toBuffer(cx);
897 0 : if (!isWrapped) {
898 0 : toBuffer = &args[0].toObject().as<T>();
899 : } else {
900 0 : JSObject* wrapped = &args[0].toObject();
901 0 : MOZ_ASSERT(wrapped->is<WrapperObject>());
902 0 : RootedObject toBufferObj(cx, CheckedUnwrap(wrapped));
903 0 : if (!toBufferObj) {
904 0 : ReportAccessDenied(cx);
905 0 : return false;
906 : }
907 0 : toBuffer = toBufferObj.as<T>();
908 : }
909 0 : uint32_t toIndex = uint32_t(args[1].toInt32());
910 0 : Rooted<T*> fromBuffer(cx, &args[2].toObject().as<T>());
911 0 : uint32_t fromIndex = uint32_t(args[3].toInt32());
912 0 : uint32_t count = uint32_t(args[4].toInt32());
913 :
914 0 : T::copyData(toBuffer, toIndex, fromBuffer, fromIndex, count);
915 :
916 0 : args.rval().setUndefined();
917 0 : return true;
918 : }
919 :
920 : // Arguments must both be SharedArrayBuffer or wrapped SharedArrayBuffer.
921 : static bool
922 0 : intrinsic_SharedArrayBuffersMemorySame(JSContext* cx, unsigned argc, Value* vp)
923 : {
924 0 : CallArgs args = CallArgsFromVp(argc, vp);
925 0 : MOZ_ASSERT(args.length() == 2);
926 :
927 0 : JSObject* lhs = CheckedUnwrap(&args[0].toObject());
928 0 : if (!lhs) {
929 0 : ReportAccessDenied(cx);
930 0 : return false;
931 : }
932 0 : JSObject* rhs = CheckedUnwrap(&args[1].toObject());
933 0 : if (!rhs) {
934 0 : ReportAccessDenied(cx);
935 0 : return false;
936 : }
937 :
938 0 : args.rval().setBoolean(lhs->as<SharedArrayBufferObject>().rawBufferObject() ==
939 0 : rhs->as<SharedArrayBufferObject>().rawBufferObject());
940 0 : return true;
941 : }
942 :
943 : static bool
944 0 : intrinsic_IsSpecificTypedArray(JSContext* cx, unsigned argc, Value* vp, Scalar::Type type)
945 : {
946 0 : CallArgs args = CallArgsFromVp(argc, vp);
947 0 : MOZ_ASSERT(args.length() == 1);
948 0 : MOZ_ASSERT(args[0].isObject());
949 :
950 0 : JSObject* obj = &args[0].toObject();
951 :
952 0 : bool isArray = JS_GetArrayBufferViewType(obj) == type;
953 :
954 0 : args.rval().setBoolean(isArray);
955 0 : return true;
956 : }
957 :
958 : static bool
959 0 : intrinsic_IsUint8TypedArray(JSContext* cx, unsigned argc, Value* vp)
960 : {
961 0 : return intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::Uint8) ||
962 0 : intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::Uint8Clamped);
963 : }
964 :
965 : static bool
966 0 : intrinsic_IsInt8TypedArray(JSContext* cx, unsigned argc, Value* vp)
967 : {
968 0 : return intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::Int8);
969 : }
970 :
971 : static bool
972 0 : intrinsic_IsUint16TypedArray(JSContext* cx, unsigned argc, Value* vp)
973 : {
974 0 : return intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::Uint16);
975 : }
976 :
977 : static bool
978 0 : intrinsic_IsInt16TypedArray(JSContext* cx, unsigned argc, Value* vp)
979 : {
980 0 : return intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::Int16);
981 : }
982 :
983 : static bool
984 0 : intrinsic_IsUint32TypedArray(JSContext* cx, unsigned argc, Value* vp)
985 : {
986 0 : return intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::Uint32);
987 : }
988 :
989 : static bool
990 0 : intrinsic_IsInt32TypedArray(JSContext* cx, unsigned argc, Value* vp)
991 : {
992 0 : return intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::Int32);
993 : }
994 :
995 : static bool
996 0 : intrinsic_IsFloat32TypedArray(JSContext* cx, unsigned argc, Value* vp)
997 : {
998 0 : return intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::Float32);
999 : }
1000 :
1001 : static bool
1002 6488 : intrinsic_IsPossiblyWrappedTypedArray(JSContext* cx, unsigned argc, Value* vp)
1003 : {
1004 6488 : CallArgs args = CallArgsFromVp(argc, vp);
1005 6488 : MOZ_ASSERT(args.length() == 1);
1006 :
1007 6488 : bool isTypedArray = false;
1008 6488 : if (args[0].isObject()) {
1009 6488 : JSObject* obj = CheckedUnwrap(&args[0].toObject());
1010 6488 : if (!obj) {
1011 0 : ReportAccessDenied(cx);
1012 0 : return false;
1013 : }
1014 :
1015 6488 : isTypedArray = obj->is<TypedArrayObject>();
1016 : }
1017 :
1018 6488 : args.rval().setBoolean(isTypedArray);
1019 6488 : return true;
1020 : }
1021 :
1022 : static bool
1023 0 : intrinsic_TypedArrayBuffer(JSContext* cx, unsigned argc, Value* vp)
1024 : {
1025 0 : CallArgs args = CallArgsFromVp(argc, vp);
1026 0 : MOZ_ASSERT(args.length() == 1);
1027 0 : MOZ_ASSERT(TypedArrayObject::is(args[0]));
1028 :
1029 0 : Rooted<TypedArrayObject*> tarray(cx, &args[0].toObject().as<TypedArrayObject>());
1030 0 : if (!TypedArrayObject::ensureHasBuffer(cx, tarray))
1031 0 : return false;
1032 :
1033 0 : args.rval().set(TypedArrayObject::bufferValue(tarray));
1034 0 : return true;
1035 : }
1036 :
1037 : static bool
1038 0 : intrinsic_TypedArrayByteOffset(JSContext* cx, unsigned argc, Value* vp)
1039 : {
1040 0 : CallArgs args = CallArgsFromVp(argc, vp);
1041 0 : MOZ_ASSERT(args.length() == 1);
1042 0 : MOZ_ASSERT(TypedArrayObject::is(args[0]));
1043 :
1044 0 : args.rval().set(TypedArrayObject::byteOffsetValue(&args[0].toObject().as<TypedArrayObject>()));
1045 0 : return true;
1046 : }
1047 :
1048 : static bool
1049 0 : intrinsic_TypedArrayElementShift(JSContext* cx, unsigned argc, Value* vp)
1050 : {
1051 0 : CallArgs args = CallArgsFromVp(argc, vp);
1052 0 : MOZ_ASSERT(args.length() == 1);
1053 0 : MOZ_ASSERT(TypedArrayObject::is(args[0]));
1054 :
1055 0 : unsigned shift = TypedArrayShift(args[0].toObject().as<TypedArrayObject>().type());
1056 0 : MOZ_ASSERT(shift == 0 || shift == 1 || shift == 2 || shift == 3);
1057 :
1058 0 : args.rval().setInt32(mozilla::AssertedCast<int32_t>(shift));
1059 0 : return true;
1060 : }
1061 :
1062 : // Return the value of [[ArrayLength]] internal slot of the TypedArray
1063 : static bool
1064 0 : intrinsic_TypedArrayLength(JSContext* cx, unsigned argc, Value* vp)
1065 : {
1066 0 : CallArgs args = CallArgsFromVp(argc, vp);
1067 0 : MOZ_ASSERT(args.length() == 1);
1068 :
1069 0 : JSObject* obj = &args[0].toObject();
1070 0 : MOZ_ASSERT(obj->is<TypedArrayObject>());
1071 0 : args.rval().setInt32(obj->as<TypedArrayObject>().length());
1072 0 : return true;
1073 : }
1074 :
1075 : static bool
1076 0 : intrinsic_PossiblyWrappedTypedArrayLength(JSContext* cx, unsigned argc, Value* vp)
1077 : {
1078 0 : CallArgs args = CallArgsFromVp(argc, vp);
1079 0 : MOZ_ASSERT(args.length() == 1);
1080 0 : MOZ_ASSERT(args[0].isObject());
1081 :
1082 0 : JSObject* obj = CheckedUnwrap(&args[0].toObject());
1083 0 : if (!obj) {
1084 0 : ReportAccessDenied(cx);
1085 0 : return false;
1086 : }
1087 :
1088 0 : MOZ_ASSERT(obj->is<TypedArrayObject>());
1089 0 : uint32_t typedArrayLength = obj->as<TypedArrayObject>().length();
1090 0 : args.rval().setInt32(mozilla::AssertedCast<int32_t>(typedArrayLength));
1091 0 : return true;
1092 : }
1093 :
1094 : static bool
1095 0 : intrinsic_PossiblyWrappedTypedArrayHasDetachedBuffer(JSContext* cx, unsigned argc, Value* vp)
1096 : {
1097 0 : CallArgs args = CallArgsFromVp(argc, vp);
1098 0 : MOZ_ASSERT(args.length() == 1);
1099 0 : MOZ_ASSERT(args[0].isObject());
1100 :
1101 0 : JSObject* obj = CheckedUnwrap(&args[0].toObject());
1102 0 : if (!obj) {
1103 0 : ReportAccessDenied(cx);
1104 0 : return false;
1105 : }
1106 :
1107 0 : MOZ_ASSERT(obj->is<TypedArrayObject>());
1108 0 : bool detached = obj->as<TypedArrayObject>().hasDetachedBuffer();
1109 0 : args.rval().setBoolean(detached);
1110 0 : return true;
1111 : }
1112 :
1113 : static bool
1114 0 : intrinsic_MoveTypedArrayElements(JSContext* cx, unsigned argc, Value* vp)
1115 : {
1116 0 : CallArgs args = CallArgsFromVp(argc, vp);
1117 0 : MOZ_ASSERT(args.length() == 4);
1118 :
1119 0 : Rooted<TypedArrayObject*> tarray(cx, &args[0].toObject().as<TypedArrayObject>());
1120 0 : uint32_t to = uint32_t(args[1].toInt32());
1121 0 : uint32_t from = uint32_t(args[2].toInt32());
1122 0 : uint32_t count = uint32_t(args[3].toInt32());
1123 :
1124 0 : MOZ_ASSERT(count > 0,
1125 : "don't call this method if copying no elements, because then "
1126 : "the not-detached requirement is wrong");
1127 :
1128 0 : if (tarray->hasDetachedBuffer()) {
1129 0 : JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
1130 0 : return false;
1131 : }
1132 :
1133 : // Don't multiply by |tarray->bytesPerElement()| in case the compiler can't
1134 : // strength-reduce multiplication by 1/2/4/8 into the equivalent shift.
1135 0 : const size_t ElementShift = TypedArrayShift(tarray->type());
1136 :
1137 0 : MOZ_ASSERT((UINT32_MAX >> ElementShift) > to);
1138 0 : uint32_t byteDest = to << ElementShift;
1139 :
1140 0 : MOZ_ASSERT((UINT32_MAX >> ElementShift) > from);
1141 0 : uint32_t byteSrc = from << ElementShift;
1142 :
1143 0 : MOZ_ASSERT((UINT32_MAX >> ElementShift) >= count);
1144 0 : uint32_t byteSize = count << ElementShift;
1145 :
1146 : #ifdef DEBUG
1147 : {
1148 0 : uint32_t viewByteLength = tarray->byteLength();
1149 0 : MOZ_ASSERT(byteSize <= viewByteLength);
1150 0 : MOZ_ASSERT(byteDest < viewByteLength);
1151 0 : MOZ_ASSERT(byteSrc < viewByteLength);
1152 0 : MOZ_ASSERT(byteDest <= viewByteLength - byteSize);
1153 0 : MOZ_ASSERT(byteSrc <= viewByteLength - byteSize);
1154 : }
1155 : #endif
1156 :
1157 0 : SharedMem<uint8_t*> data = tarray->viewDataEither().cast<uint8_t*>();
1158 0 : jit::AtomicOperations::memmoveSafeWhenRacy(data + byteDest, data + byteSrc, byteSize);
1159 :
1160 0 : args.rval().setUndefined();
1161 0 : return true;
1162 : }
1163 :
1164 : // Extract the TypedArrayObject* underlying |obj| and return it. This method,
1165 : // in a TOTALLY UNSAFE manner, completely violates the normal compartment
1166 : // boundaries, returning an object not necessarily in the current compartment
1167 : // or in |obj|'s compartment.
1168 : //
1169 : // All callers of this method are expected to sigil this TypedArrayObject*, and
1170 : // all values and information derived from it, with an "unsafe" prefix, to
1171 : // indicate the extreme caution required when dealing with such values.
1172 : //
1173 : // If calling code discipline ever fails to be maintained, it's gonna have a
1174 : // bad time.
1175 : static TypedArrayObject*
1176 0 : DangerouslyUnwrapTypedArray(JSContext* cx, JSObject* obj)
1177 : {
1178 : // An unwrapped pointer to an object potentially on the other side of a
1179 : // compartment boundary! Isn't this such fun?
1180 0 : JSObject* unwrapped = CheckedUnwrap(obj);
1181 0 : if (!unwrapped->is<TypedArrayObject>()) {
1182 : // By *appearances* this can't happen, as self-hosted TypedArraySet
1183 : // checked this. But. Who's to say a GC couldn't happen between
1184 : // the check that this value was a typed array, and this extraction
1185 : // occurring? A GC might turn a cross-compartment wrapper |obj| into
1186 : // |unwrapped == obj|, a dead object no longer connected its typed
1187 : // array.
1188 : //
1189 : // Yeah, yeah, it's pretty unlikely. Are you willing to stake a
1190 : // sec-critical bug on that assessment, now and forever, against
1191 : // all changes those pesky GC and JIT people might make?
1192 0 : JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
1193 0 : return nullptr;
1194 : }
1195 :
1196 : // Be super-duper careful using this, as we've just punched through
1197 : // the compartment boundary, and things like buffer() on this aren't
1198 : // same-compartment with anything else in the calling method.
1199 0 : return &unwrapped->as<TypedArrayObject>();
1200 : }
1201 :
1202 : // ES6 draft 20150403 22.2.3.22.2, steps 12-24, 29.
1203 : static bool
1204 0 : intrinsic_SetFromTypedArrayApproach(JSContext* cx, unsigned argc, Value* vp)
1205 : {
1206 0 : CallArgs args = CallArgsFromVp(argc, vp);
1207 0 : MOZ_ASSERT(args.length() == 4);
1208 :
1209 0 : Rooted<TypedArrayObject*> target(cx, &args[0].toObject().as<TypedArrayObject>());
1210 0 : MOZ_ASSERT(!target->hasDetachedBuffer(),
1211 : "something should have defended against a target viewing a "
1212 : "detached buffer");
1213 :
1214 : // As directed by |DangerouslyUnwrapTypedArray|, sigil this pointer and all
1215 : // variables derived from it to counsel extreme caution here.
1216 0 : Rooted<TypedArrayObject*> unsafeTypedArrayCrossCompartment(cx);
1217 0 : unsafeTypedArrayCrossCompartment = DangerouslyUnwrapTypedArray(cx, &args[1].toObject());
1218 0 : if (!unsafeTypedArrayCrossCompartment)
1219 0 : return false;
1220 :
1221 0 : double doubleTargetOffset = args[2].toNumber();
1222 0 : MOZ_ASSERT(doubleTargetOffset >= 0, "caller failed to ensure |targetOffset >= 0|");
1223 :
1224 0 : uint32_t targetLength = uint32_t(args[3].toInt32());
1225 :
1226 : // Handle all checks preceding the actual element-setting. A visual skim
1227 : // of 22.2.3.22.2 should confirm these are the only steps after steps 1-11
1228 : // that might abort processing (other than for reason of internal error.)
1229 :
1230 : // Steps 12-13.
1231 0 : if (unsafeTypedArrayCrossCompartment->hasDetachedBuffer()) {
1232 0 : JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
1233 0 : return false;
1234 : }
1235 :
1236 : // Steps 21, 23.
1237 0 : uint32_t unsafeSrcLengthCrossCompartment = unsafeTypedArrayCrossCompartment->length();
1238 0 : if (unsafeSrcLengthCrossCompartment + doubleTargetOffset > targetLength) {
1239 0 : JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
1240 0 : return false;
1241 : }
1242 :
1243 : // Now that that's confirmed, we can use |targetOffset| of a sane type.
1244 0 : uint32_t targetOffset = uint32_t(doubleTargetOffset);
1245 :
1246 : // The remaining steps are unobservable *except* through their effect on
1247 : // which elements are copied and how.
1248 :
1249 0 : Scalar::Type targetType = target->type();
1250 0 : Scalar::Type unsafeSrcTypeCrossCompartment = unsafeTypedArrayCrossCompartment->type();
1251 :
1252 0 : size_t targetElementSize = TypedArrayElemSize(targetType);
1253 : SharedMem<uint8_t*> targetData =
1254 0 : target->viewDataEither().cast<uint8_t*>() + targetOffset * targetElementSize;
1255 :
1256 : SharedMem<uint8_t*> unsafeSrcDataCrossCompartment =
1257 0 : unsafeTypedArrayCrossCompartment->viewDataEither().cast<uint8_t*>();
1258 :
1259 : uint32_t unsafeSrcElementSizeCrossCompartment =
1260 0 : TypedArrayElemSize(unsafeSrcTypeCrossCompartment);
1261 : uint32_t unsafeSrcByteLengthCrossCompartment =
1262 0 : unsafeSrcLengthCrossCompartment * unsafeSrcElementSizeCrossCompartment;
1263 :
1264 : // Step 29.
1265 : //
1266 : // The same-type case requires exact copying preserving the bit-level
1267 : // encoding of the source data, so move the values. (We could PodCopy if
1268 : // we knew the buffers differed, but it's doubtful the work to check
1269 : // wouldn't swap any minor wins PodCopy would afford. Because of the
1270 : // TOTALLY UNSAFE CROSS-COMPARTMENT NONSENSE here, comparing buffer
1271 : // pointers directly could give an incorrect answer.) If this occurs,
1272 : // the %TypedArray%.prototype.set operation is completely finished.
1273 0 : if (targetType == unsafeSrcTypeCrossCompartment) {
1274 0 : jit::AtomicOperations::memmoveSafeWhenRacy(targetData,
1275 : unsafeSrcDataCrossCompartment,
1276 0 : unsafeSrcByteLengthCrossCompartment);
1277 0 : args.rval().setInt32(JS_SETTYPEDARRAY_SAME_TYPE);
1278 0 : return true;
1279 : }
1280 :
1281 : // Every other bit of element-copying is handled by step 28. Indicate
1282 : // whether such copying must take care not to overlap, so that self-hosted
1283 : // code may correctly perform the copying.
1284 :
1285 : SharedMem<uint8_t*> unsafeSrcDataLimitCrossCompartment =
1286 0 : unsafeSrcDataCrossCompartment + unsafeSrcByteLengthCrossCompartment;
1287 : SharedMem<uint8_t*> targetDataLimit =
1288 0 : target->viewDataEither().cast<uint8_t*>() + targetLength * targetElementSize;
1289 :
1290 : // Step 24 test (but not steps 24a-d -- the caller handles those).
1291 : bool overlap =
1292 0 : IsInRange(targetData.unwrap(/*safe - used for ptr value*/),
1293 0 : unsafeSrcDataCrossCompartment.unwrap(/*safe - ditto*/),
1294 0 : unsafeSrcDataLimitCrossCompartment.unwrap(/*safe - ditto*/)) ||
1295 0 : IsInRange(unsafeSrcDataCrossCompartment.unwrap(/*safe - ditto*/),
1296 0 : targetData.unwrap(/*safe - ditto*/),
1297 0 : targetDataLimit.unwrap(/*safe - ditto*/));
1298 :
1299 0 : args.rval().setInt32(overlap ? JS_SETTYPEDARRAY_OVERLAPPING : JS_SETTYPEDARRAY_DISJOINT);
1300 0 : return true;
1301 : }
1302 :
1303 : template <typename From, typename To>
1304 : static void
1305 0 : CopyValues(SharedMem<To*> dest, SharedMem<From*> src, uint32_t count)
1306 : {
1307 : #ifdef DEBUG
1308 0 : void* destVoid = dest.template cast<void*>().unwrap(/*safe - used for ptr value*/);
1309 0 : void* destVoidEnd = (dest + count).template cast<void*>().unwrap(/*safe - ditto*/);
1310 0 : const void* srcVoid = src.template cast<void*>().unwrap(/*safe - ditto*/);
1311 0 : const void* srcVoidEnd = (src + count).template cast<void*>().unwrap(/*safe - ditto*/);
1312 0 : MOZ_ASSERT(!IsInRange(destVoid, srcVoid, srcVoidEnd));
1313 0 : MOZ_ASSERT(!IsInRange(srcVoid, destVoid, destVoidEnd));
1314 : #endif
1315 :
1316 : using namespace jit;
1317 :
1318 0 : for (; count > 0; count--) {
1319 0 : AtomicOperations::storeSafeWhenRacy(dest++,
1320 0 : To(AtomicOperations::loadSafeWhenRacy(src++)));
1321 : }
1322 0 : }
1323 :
1324 : struct DisjointElements
1325 : {
1326 : template <typename To>
1327 : static void
1328 0 : copy(SharedMem<To*> dest, SharedMem<void*> src, Scalar::Type fromType, uint32_t count) {
1329 0 : switch (fromType) {
1330 : case Scalar::Int8:
1331 0 : CopyValues(dest, src.cast<int8_t*>(), count);
1332 0 : return;
1333 :
1334 : case Scalar::Uint8:
1335 0 : CopyValues(dest, src.cast<uint8_t*>(), count);
1336 0 : return;
1337 :
1338 : case Scalar::Int16:
1339 0 : CopyValues(dest, src.cast<int16_t*>(), count);
1340 0 : return;
1341 :
1342 : case Scalar::Uint16:
1343 0 : CopyValues(dest, src.cast<uint16_t*>(), count);
1344 0 : return;
1345 :
1346 : case Scalar::Int32:
1347 0 : CopyValues(dest, src.cast<int32_t*>(), count);
1348 0 : return;
1349 :
1350 : case Scalar::Uint32:
1351 0 : CopyValues(dest, src.cast<uint32_t*>(), count);
1352 0 : return;
1353 :
1354 : case Scalar::Float32:
1355 0 : CopyValues(dest, src.cast<float*>(), count);
1356 0 : return;
1357 :
1358 : case Scalar::Float64:
1359 0 : CopyValues(dest, src.cast<double*>(), count);
1360 0 : return;
1361 :
1362 : case Scalar::Uint8Clamped:
1363 0 : CopyValues(dest, src.cast<uint8_clamped*>(), count);
1364 0 : return;
1365 :
1366 : default:
1367 0 : MOZ_CRASH("NonoverlappingSet with bogus from-type");
1368 : }
1369 : }
1370 : };
1371 :
1372 : static void
1373 0 : CopyToDisjointArray(TypedArrayObject* target, uint32_t targetOffset, SharedMem<void*> src,
1374 : Scalar::Type srcType, uint32_t count)
1375 : {
1376 0 : Scalar::Type destType = target->type();
1377 0 : SharedMem<uint8_t*> dest = target->viewDataEither().cast<uint8_t*>() + targetOffset * TypedArrayElemSize(destType);
1378 :
1379 0 : switch (destType) {
1380 : case Scalar::Int8: {
1381 0 : DisjointElements::copy(dest.cast<int8_t*>(), src, srcType, count);
1382 0 : break;
1383 : }
1384 :
1385 : case Scalar::Uint8: {
1386 0 : DisjointElements::copy(dest.cast<uint8_t*>(), src, srcType, count);
1387 0 : break;
1388 : }
1389 :
1390 : case Scalar::Int16: {
1391 0 : DisjointElements::copy(dest.cast<int16_t*>(), src, srcType, count);
1392 0 : break;
1393 : }
1394 :
1395 : case Scalar::Uint16: {
1396 0 : DisjointElements::copy(dest.cast<uint16_t*>(), src, srcType, count);
1397 0 : break;
1398 : }
1399 :
1400 : case Scalar::Int32: {
1401 0 : DisjointElements::copy(dest.cast<int32_t*>(), src, srcType, count);
1402 0 : break;
1403 : }
1404 :
1405 : case Scalar::Uint32: {
1406 0 : DisjointElements::copy(dest.cast<uint32_t*>(), src, srcType, count);
1407 0 : break;
1408 : }
1409 :
1410 : case Scalar::Float32: {
1411 0 : DisjointElements::copy(dest.cast<float*>(), src, srcType, count);
1412 0 : break;
1413 : }
1414 :
1415 : case Scalar::Float64: {
1416 0 : DisjointElements::copy(dest.cast<double*>(), src, srcType, count);
1417 0 : break;
1418 : }
1419 :
1420 : case Scalar::Uint8Clamped: {
1421 0 : DisjointElements::copy(dest.cast<uint8_clamped*>(), src, srcType, count);
1422 0 : break;
1423 : }
1424 :
1425 : default:
1426 0 : MOZ_CRASH("setFromTypedArray with a typed array with bogus type");
1427 : }
1428 0 : }
1429 :
1430 : // |unsafeSrcCrossCompartment| is produced by |DangerouslyUnwrapTypedArray|,
1431 : // counseling extreme caution when using it. As directed by
1432 : // |DangerouslyUnwrapTypedArray|, sigil this pointer and all variables derived
1433 : // from it to counsel extreme caution here.
1434 : void
1435 0 : js::SetDisjointTypedElements(TypedArrayObject* target, uint32_t targetOffset,
1436 : TypedArrayObject* unsafeSrcCrossCompartment)
1437 : {
1438 0 : Scalar::Type unsafeSrcTypeCrossCompartment = unsafeSrcCrossCompartment->type();
1439 :
1440 0 : SharedMem<void*> unsafeSrcDataCrossCompartment = unsafeSrcCrossCompartment->viewDataEither();
1441 0 : uint32_t count = unsafeSrcCrossCompartment->length();
1442 :
1443 : CopyToDisjointArray(target, targetOffset,
1444 : unsafeSrcDataCrossCompartment,
1445 0 : unsafeSrcTypeCrossCompartment, count);
1446 0 : }
1447 :
1448 : static bool
1449 0 : intrinsic_SetDisjointTypedElements(JSContext* cx, unsigned argc, Value* vp)
1450 : {
1451 0 : CallArgs args = CallArgsFromVp(argc, vp);
1452 0 : MOZ_ASSERT(args.length() == 3);
1453 :
1454 0 : Rooted<TypedArrayObject*> target(cx, &args[0].toObject().as<TypedArrayObject>());
1455 0 : MOZ_ASSERT(!target->hasDetachedBuffer(),
1456 : "a typed array viewing a detached buffer has no elements to "
1457 : "set, so it's nonsensical to be setting them");
1458 :
1459 0 : uint32_t targetOffset = uint32_t(args[1].toInt32());
1460 :
1461 : // As directed by |DangerouslyUnwrapTypedArray|, sigil this pointer and all
1462 : // variables derived from it to counsel extreme caution here.
1463 0 : Rooted<TypedArrayObject*> unsafeSrcCrossCompartment(cx);
1464 0 : unsafeSrcCrossCompartment = DangerouslyUnwrapTypedArray(cx, &args[2].toObject());
1465 0 : if (!unsafeSrcCrossCompartment)
1466 0 : return false;
1467 :
1468 0 : SetDisjointTypedElements(target, targetOffset, unsafeSrcCrossCompartment);
1469 :
1470 0 : args.rval().setUndefined();
1471 0 : return true;
1472 : }
1473 :
1474 : static bool
1475 0 : intrinsic_SetOverlappingTypedElements(JSContext* cx, unsigned argc, Value* vp)
1476 : {
1477 0 : CallArgs args = CallArgsFromVp(argc, vp);
1478 0 : MOZ_ASSERT(args.length() == 3);
1479 :
1480 0 : Rooted<TypedArrayObject*> target(cx, &args[0].toObject().as<TypedArrayObject>());
1481 0 : MOZ_ASSERT(!target->hasDetachedBuffer(),
1482 : "shouldn't set elements if underlying buffer is detached");
1483 :
1484 0 : uint32_t targetOffset = uint32_t(args[1].toInt32());
1485 :
1486 : // As directed by |DangerouslyUnwrapTypedArray|, sigil this pointer and all
1487 : // variables derived from it to counsel extreme caution here.
1488 0 : Rooted<TypedArrayObject*> unsafeSrcCrossCompartment(cx);
1489 0 : unsafeSrcCrossCompartment = DangerouslyUnwrapTypedArray(cx, &args[2].toObject());
1490 0 : if (!unsafeSrcCrossCompartment)
1491 0 : return false;
1492 :
1493 : // Smarter algorithms exist to perform overlapping transfers of the sort
1494 : // this method performs (for example, v8's self-hosted implementation).
1495 : // But it seems likely deliberate overlapping transfers are rare enough
1496 : // that it's not worth the trouble to implement one (and worry about its
1497 : // safety/correctness!). Make a copy and do a disjoint set from that.
1498 0 : uint32_t count = unsafeSrcCrossCompartment->length();
1499 0 : Scalar::Type unsafeSrcTypeCrossCompartment = unsafeSrcCrossCompartment->type();
1500 0 : size_t sourceByteLen = count * TypedArrayElemSize(unsafeSrcTypeCrossCompartment);
1501 :
1502 0 : auto copyOfSrcData = target->zone()->make_pod_array<uint8_t>(sourceByteLen);
1503 0 : if (!copyOfSrcData)
1504 0 : return false;
1505 :
1506 0 : jit::AtomicOperations::memcpySafeWhenRacy(SharedMem<uint8_t*>::unshared(copyOfSrcData.get()),
1507 0 : unsafeSrcCrossCompartment->viewDataEither().cast<uint8_t*>(),
1508 0 : sourceByteLen);
1509 :
1510 0 : CopyToDisjointArray(target, targetOffset, SharedMem<void*>::unshared(copyOfSrcData.get()),
1511 0 : unsafeSrcTypeCrossCompartment, count);
1512 :
1513 0 : args.rval().setUndefined();
1514 0 : return true;
1515 : }
1516 :
1517 : static bool
1518 0 : intrinsic_RegExpCreate(JSContext* cx, unsigned argc, Value* vp)
1519 : {
1520 0 : CallArgs args = CallArgsFromVp(argc, vp);
1521 :
1522 0 : MOZ_ASSERT(args.length() == 1 || args.length() == 2);
1523 0 : MOZ_ASSERT_IF(args.length() == 2, args[1].isString() || args[1].isUndefined());
1524 0 : MOZ_ASSERT(!args.isConstructing());
1525 :
1526 0 : return RegExpCreate(cx, args[0], args.get(1), args.rval());
1527 : }
1528 :
1529 : static bool
1530 0 : intrinsic_RegExpGetSubstitution(JSContext* cx, unsigned argc, Value* vp)
1531 : {
1532 0 : CallArgs args = CallArgsFromVp(argc, vp);
1533 :
1534 0 : MOZ_ASSERT(args.length() == 6);
1535 :
1536 0 : RootedString matched(cx, args[0].toString());
1537 0 : RootedString string(cx, args[1].toString());
1538 :
1539 0 : int32_t position = int32_t(args[2].toNumber());
1540 0 : MOZ_ASSERT(position >= 0);
1541 :
1542 0 : RootedObject captures(cx, &args[3].toObject());
1543 : #ifdef DEBUG
1544 0 : bool isArray = false;
1545 0 : MOZ_ALWAYS_TRUE(IsArray(cx, captures, &isArray));
1546 0 : MOZ_ASSERT(isArray);
1547 : #endif
1548 :
1549 0 : RootedString replacement(cx, args[4].toString());
1550 :
1551 0 : int32_t firstDollarIndex = int32_t(args[5].toNumber());
1552 0 : MOZ_ASSERT(firstDollarIndex >= 0);
1553 :
1554 0 : RootedLinearString matchedLinear(cx, matched->ensureLinear(cx));
1555 0 : if (!matchedLinear)
1556 0 : return false;
1557 0 : RootedLinearString stringLinear(cx, string->ensureLinear(cx));
1558 0 : if (!stringLinear)
1559 0 : return false;
1560 0 : RootedLinearString replacementLinear(cx, replacement->ensureLinear(cx));
1561 0 : if (!replacementLinear)
1562 0 : return false;
1563 :
1564 0 : return RegExpGetSubstitution(cx, matchedLinear, stringLinear, size_t(position), captures,
1565 0 : replacementLinear, size_t(firstDollarIndex), args.rval());
1566 : }
1567 :
1568 : static bool
1569 28 : intrinsic_StringReplaceString(JSContext* cx, unsigned argc, Value* vp)
1570 : {
1571 28 : CallArgs args = CallArgsFromVp(argc, vp);
1572 28 : MOZ_ASSERT(args.length() == 3);
1573 :
1574 56 : RootedString string(cx, args[0].toString());
1575 56 : RootedString pattern(cx, args[1].toString());
1576 56 : RootedString replacement(cx, args[2].toString());
1577 28 : JSString* result = str_replace_string_raw(cx, string, pattern, replacement);
1578 28 : if (!result)
1579 0 : return false;
1580 :
1581 28 : args.rval().setString(result);
1582 28 : return true;
1583 : }
1584 :
1585 : bool
1586 67 : js::intrinsic_StringSplitString(JSContext* cx, unsigned argc, Value* vp)
1587 : {
1588 67 : CallArgs args = CallArgsFromVp(argc, vp);
1589 67 : MOZ_ASSERT(args.length() == 2);
1590 :
1591 134 : RootedString string(cx, args[0].toString());
1592 134 : RootedString sep(cx, args[1].toString());
1593 :
1594 134 : RootedObjectGroup group(cx, ObjectGroupCompartment::getStringSplitStringGroup(cx));
1595 67 : if (!group)
1596 0 : return false;
1597 :
1598 67 : JSObject* aobj = str_split_string(cx, group, string, sep, INT32_MAX);
1599 67 : if (!aobj)
1600 0 : return false;
1601 :
1602 67 : args.rval().setObject(*aobj);
1603 67 : return true;
1604 : }
1605 :
1606 : static bool
1607 1 : intrinsic_StringSplitStringLimit(JSContext* cx, unsigned argc, Value* vp)
1608 : {
1609 1 : CallArgs args = CallArgsFromVp(argc, vp);
1610 1 : MOZ_ASSERT(args.length() == 3);
1611 :
1612 2 : RootedString string(cx, args[0].toString());
1613 2 : RootedString sep(cx, args[1].toString());
1614 :
1615 : // args[2] should be already in UInt32 range, but it could be double typed,
1616 : // because of Ion optimization.
1617 1 : uint32_t limit = uint32_t(args[2].toNumber());
1618 :
1619 2 : RootedObjectGroup group(cx, ObjectGroupCompartment::getStringSplitStringGroup(cx));
1620 1 : if (!group)
1621 0 : return false;
1622 :
1623 1 : JSObject* aobj = str_split_string(cx, group, string, sep, limit);
1624 1 : if (!aobj)
1625 0 : return false;
1626 :
1627 1 : args.rval().setObject(*aobj);
1628 1 : return true;
1629 : }
1630 :
1631 : bool
1632 0 : CallSelfHostedNonGenericMethod(JSContext* cx, const CallArgs& args)
1633 : {
1634 : // This function is called when a self-hosted method is invoked on a
1635 : // wrapper object, like a CrossCompartmentWrapper. The last argument is
1636 : // the name of the self-hosted function. The other arguments are the
1637 : // arguments to pass to this function.
1638 :
1639 0 : MOZ_ASSERT(args.length() > 0);
1640 0 : RootedPropertyName name(cx, args[args.length() - 1].toString()->asAtom().asPropertyName());
1641 :
1642 0 : RootedValue selfHostedFun(cx);
1643 0 : if (!GlobalObject::getIntrinsicValue(cx, cx->global(), name, &selfHostedFun))
1644 0 : return false;
1645 :
1646 0 : MOZ_ASSERT(selfHostedFun.toObject().is<JSFunction>());
1647 :
1648 0 : InvokeArgs args2(cx);
1649 0 : if (!args2.init(cx, args.length() - 1))
1650 0 : return false;
1651 :
1652 0 : for (size_t i = 0; i < args.length() - 1; i++)
1653 0 : args2[i].set(args[i]);
1654 :
1655 0 : return js::Call(cx, selfHostedFun, args.thisv(), args2, args.rval());
1656 : }
1657 :
1658 : bool
1659 0 : js::CallSelfHostedFunction(JSContext* cx, const char* name, HandleValue thisv,
1660 : const AnyInvokeArgs& args, MutableHandleValue rval)
1661 : {
1662 0 : RootedAtom funAtom(cx, Atomize(cx, name, strlen(name)));
1663 0 : if (!funAtom)
1664 0 : return false;
1665 0 : RootedPropertyName funName(cx, funAtom->asPropertyName());
1666 0 : return CallSelfHostedFunction(cx, funName, thisv, args, rval);
1667 : }
1668 :
1669 : bool
1670 143 : js::CallSelfHostedFunction(JSContext* cx, HandlePropertyName name, HandleValue thisv,
1671 : const AnyInvokeArgs& args, MutableHandleValue rval)
1672 : {
1673 286 : RootedValue fun(cx);
1674 143 : if (!GlobalObject::getIntrinsicValue(cx, cx->global(), name, &fun))
1675 0 : return false;
1676 143 : MOZ_ASSERT(fun.toObject().is<JSFunction>());
1677 :
1678 143 : return Call(cx, fun, thisv, args, rval);
1679 : }
1680 :
1681 : template<typename T>
1682 : bool
1683 0 : Is(HandleValue v)
1684 : {
1685 0 : return v.isObject() && v.toObject().is<T>();
1686 : }
1687 :
1688 : template<IsAcceptableThis Test>
1689 : static bool
1690 0 : CallNonGenericSelfhostedMethod(JSContext* cx, unsigned argc, Value* vp)
1691 : {
1692 0 : CallArgs args = CallArgsFromVp(argc, vp);
1693 0 : return CallNonGenericMethod<Test, CallSelfHostedNonGenericMethod>(cx, args);
1694 : }
1695 :
1696 : bool
1697 0 : js::IsCallSelfHostedNonGenericMethod(NativeImpl impl)
1698 : {
1699 0 : return impl == CallSelfHostedNonGenericMethod;
1700 : }
1701 :
1702 : bool
1703 0 : js::ReportIncompatibleSelfHostedMethod(JSContext* cx, const CallArgs& args)
1704 : {
1705 : // The contract for this function is the same as CallSelfHostedNonGenericMethod.
1706 : // The normal ReportIncompatible function doesn't work for selfhosted functions,
1707 : // because they always call the different CallXXXMethodIfWrapped methods,
1708 : // which would be reported as the called function instead.
1709 :
1710 : // Lookup the selfhosted method that was invoked. But skip over
1711 : // IsTypedArrayEnsuringArrayBuffer frames, because those are never the
1712 : // actual self-hosted callee from external code. We can't just skip
1713 : // self-hosted things until we find a non-self-hosted one because of cases
1714 : // like array.sort(somethingSelfHosted), where we want to report the error
1715 : // in the somethingSelfHosted, not in the sort() call.
1716 0 : ScriptFrameIter iter(cx);
1717 0 : MOZ_ASSERT(iter.isFunctionFrame());
1718 :
1719 0 : while (!iter.done()) {
1720 0 : MOZ_ASSERT(iter.callee(cx)->isSelfHostedOrIntrinsic() &&
1721 : !iter.callee(cx)->isBoundFunction());
1722 0 : JSAutoByteString funNameBytes;
1723 0 : const char* funName = GetFunctionNameBytes(cx, iter.callee(cx), &funNameBytes);
1724 0 : if (!funName)
1725 0 : return false;
1726 0 : if (strcmp(funName, "IsTypedArrayEnsuringArrayBuffer") != 0) {
1727 0 : JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_METHOD,
1728 0 : funName, "method", InformalValueTypeName(args.thisv()));
1729 0 : return false;
1730 : }
1731 0 : ++iter;
1732 : }
1733 :
1734 0 : MOZ_ASSERT_UNREACHABLE("How did we not find a useful self-hosted frame?");
1735 : return false;
1736 : }
1737 :
1738 : /**
1739 : * Returns the default locale as a well-formed, but not necessarily canonicalized,
1740 : * BCP-47 language tag.
1741 : */
1742 : static bool
1743 0 : intrinsic_RuntimeDefaultLocale(JSContext* cx, unsigned argc, Value* vp)
1744 : {
1745 0 : CallArgs args = CallArgsFromVp(argc, vp);
1746 :
1747 0 : const char* locale = cx->runtime()->getDefaultLocale();
1748 0 : if (!locale) {
1749 0 : JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEFAULT_LOCALE_ERROR);
1750 0 : return false;
1751 : }
1752 :
1753 0 : JSString* jslocale = JS_NewStringCopyZ(cx, locale);
1754 0 : if (!jslocale)
1755 0 : return false;
1756 :
1757 0 : args.rval().setString(jslocale);
1758 0 : return true;
1759 : }
1760 :
1761 : using GetOrCreateIntlConstructor = JSFunction* (*)(JSContext*, Handle<GlobalObject*>);
1762 :
1763 : template <GetOrCreateIntlConstructor getOrCreateIntlConstructor>
1764 : static bool
1765 0 : intrinsic_GetBuiltinIntlConstructor(JSContext* cx, unsigned argc, Value* vp)
1766 : {
1767 0 : CallArgs args = CallArgsFromVp(argc, vp);
1768 0 : MOZ_ASSERT(args.length() == 0);
1769 :
1770 0 : JSFunction* constructor = getOrCreateIntlConstructor(cx, cx->global());
1771 0 : if (!constructor)
1772 0 : return false;
1773 :
1774 0 : args.rval().setObject(*constructor);
1775 0 : return true;
1776 : }
1777 :
1778 : static bool
1779 0 : intrinsic_AddContentTelemetry(JSContext* cx, unsigned argc, Value* vp)
1780 : {
1781 0 : CallArgs args = CallArgsFromVp(argc, vp);
1782 0 : MOZ_ASSERT(args.length() == 2);
1783 :
1784 0 : int id = args[0].toInt32();
1785 0 : MOZ_ASSERT(id < JS_TELEMETRY_END);
1786 0 : MOZ_ASSERT(id >= 0);
1787 :
1788 0 : if (!cx->compartment()->isProbablySystemOrAddonCode())
1789 0 : cx->runtime()->addTelemetry(id, args[1].toInt32());
1790 :
1791 0 : args.rval().setUndefined();
1792 0 : return true;
1793 : }
1794 :
1795 : static bool
1796 0 : intrinsic_WarnDeprecatedStringMethod(JSContext* cx, unsigned argc, Value* vp)
1797 : {
1798 0 : CallArgs args = CallArgsFromVp(argc, vp);
1799 0 : MOZ_ASSERT(args.length() == 2);
1800 0 : MOZ_ASSERT(args[0].isInt32());
1801 0 : MOZ_ASSERT(args[1].isString());
1802 :
1803 0 : uint32_t id = uint32_t(args[0].toInt32());
1804 0 : MOZ_ASSERT(id < STRING_GENERICS_METHODS_LIMIT);
1805 :
1806 0 : uint32_t mask = (1 << id);
1807 0 : if (!(cx->compartment()->warnedAboutStringGenericsMethods & mask)) {
1808 0 : JSFlatString* name = args[1].toString()->ensureFlat(cx);
1809 0 : if (!name)
1810 0 : return false;
1811 :
1812 0 : AutoStableStringChars stableChars(cx);
1813 0 : if (!stableChars.initTwoByte(cx, name))
1814 0 : return false;
1815 0 : const char16_t* nameChars = stableChars.twoByteRange().begin().get();
1816 :
1817 0 : if (!JS_ReportErrorFlagsAndNumberUC(cx, JSREPORT_WARNING, GetErrorMessage, nullptr,
1818 : JSMSG_DEPRECATED_STRING_METHOD, nameChars, nameChars))
1819 : {
1820 0 : return false;
1821 : }
1822 0 : cx->compartment()->warnedAboutStringGenericsMethods |= mask;
1823 : }
1824 :
1825 0 : args.rval().setUndefined();
1826 0 : return true;
1827 : }
1828 :
1829 : static bool
1830 0 : intrinsic_ConstructFunction(JSContext* cx, unsigned argc, Value* vp)
1831 : {
1832 0 : CallArgs args = CallArgsFromVp(argc, vp);
1833 0 : MOZ_ASSERT(args.length() == 3);
1834 0 : MOZ_ASSERT(IsConstructor(args[0]));
1835 0 : MOZ_ASSERT(IsConstructor(args[1]));
1836 0 : MOZ_ASSERT(args[2].toObject().is<ArrayObject>());
1837 :
1838 0 : RootedArrayObject argsList(cx, &args[2].toObject().as<ArrayObject>());
1839 0 : uint32_t len = argsList->length();
1840 0 : ConstructArgs constructArgs(cx);
1841 0 : if (!constructArgs.init(cx, len))
1842 0 : return false;
1843 0 : for (uint32_t index = 0; index < len; index++)
1844 0 : constructArgs[index].set(argsList->getDenseElement(index));
1845 :
1846 0 : RootedObject res(cx);
1847 0 : if (!Construct(cx, args[0], constructArgs, args[1], &res))
1848 0 : return false;
1849 :
1850 0 : args.rval().setObject(*res);
1851 0 : return true;
1852 : }
1853 :
1854 :
1855 : static bool
1856 118 : intrinsic_IsConstructing(JSContext* cx, unsigned argc, Value* vp)
1857 : {
1858 118 : CallArgs args = CallArgsFromVp(argc, vp);
1859 118 : MOZ_ASSERT(args.length() == 0);
1860 :
1861 236 : ScriptFrameIter iter(cx);
1862 118 : bool isConstructing = iter.isConstructing();
1863 118 : args.rval().setBoolean(isConstructing);
1864 236 : return true;
1865 : }
1866 :
1867 : static bool
1868 0 : intrinsic_ConstructorForTypedArray(JSContext* cx, unsigned argc, Value* vp)
1869 : {
1870 0 : CallArgs args = CallArgsFromVp(argc, vp);
1871 0 : MOZ_ASSERT(args.length() == 1);
1872 0 : MOZ_ASSERT(args[0].isObject());
1873 :
1874 0 : RootedObject object(cx, &args[0].toObject());
1875 0 : object = CheckedUnwrap(object);
1876 0 : MOZ_ASSERT(object->is<TypedArrayObject>());
1877 :
1878 0 : JSProtoKey protoKey = StandardProtoKeyOrNull(object);
1879 0 : MOZ_ASSERT(protoKey);
1880 :
1881 : // While it may seem like an invariant that in any compartment,
1882 : // seeing a typed array object implies that the TypedArray constructor
1883 : // for that type is initialized on the compartment's global, this is not
1884 : // the case. When we construct a typed array given a cross-compartment
1885 : // ArrayBuffer, we put the constructed TypedArray in the same compartment
1886 : // as the ArrayBuffer. Since we use the prototype from the initial
1887 : // compartment, and never call the constructor in the ArrayBuffer's
1888 : // compartment from script, we are not guaranteed to have initialized
1889 : // the constructor.
1890 0 : RootedObject ctor(cx);
1891 0 : if (!GetBuiltinConstructor(cx, protoKey, &ctor))
1892 0 : return false;
1893 :
1894 0 : args.rval().setObject(*ctor);
1895 0 : return true;
1896 : }
1897 :
1898 : static bool
1899 0 : intrinsic_NameForTypedArray(JSContext* cx, unsigned argc, Value* vp)
1900 : {
1901 0 : CallArgs args = CallArgsFromVp(argc, vp);
1902 0 : MOZ_ASSERT(args.length() == 1);
1903 0 : MOZ_ASSERT(args[0].isObject());
1904 :
1905 0 : RootedObject object(cx, &args[0].toObject());
1906 0 : MOZ_ASSERT(object->is<TypedArrayObject>());
1907 :
1908 0 : JSProtoKey protoKey = StandardProtoKeyOrNull(object);
1909 0 : MOZ_ASSERT(protoKey);
1910 :
1911 0 : args.rval().setString(ClassName(protoKey, cx));
1912 0 : return true;
1913 : }
1914 :
1915 : static bool
1916 0 : intrinsic_HostResolveImportedModule(JSContext* cx, unsigned argc, Value* vp)
1917 : {
1918 0 : CallArgs args = CallArgsFromVp(argc, vp);
1919 0 : MOZ_ASSERT(args.length() == 2);
1920 0 : MOZ_ASSERT(args[0].toObject().is<ModuleObject>());
1921 0 : MOZ_ASSERT(args[1].isString());
1922 :
1923 0 : RootedFunction moduleResolveHook(cx, cx->global()->moduleResolveHook());
1924 0 : if (!moduleResolveHook) {
1925 0 : JS_ReportErrorASCII(cx, "Module resolve hook not set");
1926 0 : return false;
1927 : }
1928 :
1929 0 : RootedValue result(cx);
1930 0 : if (!JS_CallFunction(cx, nullptr, moduleResolveHook, args, &result))
1931 0 : return false;
1932 :
1933 0 : if (!result.isObject() || !result.toObject().is<ModuleObject>()) {
1934 0 : JS_ReportErrorASCII(cx, "Module resolve hook did not return Module object");
1935 0 : return false;
1936 : }
1937 :
1938 0 : args.rval().set(result);
1939 0 : return true;
1940 : }
1941 :
1942 : static bool
1943 0 : intrinsic_CreateModuleEnvironment(JSContext* cx, unsigned argc, Value* vp)
1944 : {
1945 0 : CallArgs args = CallArgsFromVp(argc, vp);
1946 0 : MOZ_ASSERT(args.length() == 1);
1947 0 : RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>());
1948 0 : module->createEnvironment();
1949 0 : args.rval().setUndefined();
1950 0 : return true;
1951 : }
1952 :
1953 : static bool
1954 0 : intrinsic_CreateImportBinding(JSContext* cx, unsigned argc, Value* vp)
1955 : {
1956 0 : CallArgs args = CallArgsFromVp(argc, vp);
1957 0 : MOZ_ASSERT(args.length() == 4);
1958 0 : RootedModuleEnvironmentObject environment(cx, &args[0].toObject().as<ModuleEnvironmentObject>());
1959 0 : RootedAtom importedName(cx, &args[1].toString()->asAtom());
1960 0 : RootedModuleObject module(cx, &args[2].toObject().as<ModuleObject>());
1961 0 : RootedAtom localName(cx, &args[3].toString()->asAtom());
1962 0 : if (!environment->createImportBinding(cx, importedName, module, localName))
1963 0 : return false;
1964 :
1965 0 : args.rval().setUndefined();
1966 0 : return true;
1967 : }
1968 :
1969 : static bool
1970 0 : intrinsic_CreateNamespaceBinding(JSContext* cx, unsigned argc, Value* vp)
1971 : {
1972 0 : CallArgs args = CallArgsFromVp(argc, vp);
1973 0 : MOZ_ASSERT(args.length() == 3);
1974 0 : RootedModuleEnvironmentObject environment(cx, &args[0].toObject().as<ModuleEnvironmentObject>());
1975 0 : RootedId name(cx, AtomToId(&args[1].toString()->asAtom()));
1976 0 : MOZ_ASSERT(args[2].toObject().is<ModuleNamespaceObject>());
1977 : // The property already exists in the evironment but is not writable, so set
1978 : // the slot directly.
1979 0 : RootedShape shape(cx, environment->lookup(cx, name));
1980 0 : MOZ_ASSERT(shape);
1981 0 : MOZ_ASSERT(environment->getSlot(shape->slot()).isMagic(JS_UNINITIALIZED_LEXICAL));
1982 0 : environment->setSlot(shape->slot(), args[2]);
1983 0 : args.rval().setUndefined();
1984 0 : return true;
1985 : }
1986 :
1987 : static bool
1988 0 : intrinsic_InstantiateModuleFunctionDeclarations(JSContext* cx, unsigned argc, Value* vp)
1989 : {
1990 0 : CallArgs args = CallArgsFromVp(argc, vp);
1991 0 : MOZ_ASSERT(args.length() == 1);
1992 0 : RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>());
1993 0 : args.rval().setUndefined();
1994 0 : return ModuleObject::instantiateFunctionDeclarations(cx, module);
1995 : }
1996 :
1997 : static bool
1998 0 : intrinsic_SetModuleState(JSContext* cx, unsigned argc, Value* vp)
1999 : {
2000 0 : CallArgs args = CallArgsFromVp(argc, vp);
2001 0 : MOZ_ASSERT(args.length() == 2);
2002 0 : RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>());
2003 0 : ModuleState newState = args[1].toInt32();
2004 0 : module->setState(newState);
2005 0 : args.rval().setUndefined();
2006 0 : return true;
2007 : }
2008 :
2009 : static bool
2010 0 : intrinsic_EvaluateModule(JSContext* cx, unsigned argc, Value* vp)
2011 : {
2012 0 : CallArgs args = CallArgsFromVp(argc, vp);
2013 0 : MOZ_ASSERT(args.length() == 1);
2014 0 : RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>());
2015 0 : return ModuleObject::evaluate(cx, module, args.rval());
2016 : }
2017 :
2018 : static bool
2019 0 : intrinsic_NewModuleNamespace(JSContext* cx, unsigned argc, Value* vp)
2020 : {
2021 0 : CallArgs args = CallArgsFromVp(argc, vp);
2022 0 : MOZ_ASSERT(args.length() == 2);
2023 0 : RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>());
2024 0 : RootedObject exports(cx, &args[1].toObject());
2025 0 : JSObject* namespace_ = ModuleObject::createNamespace(cx, module, exports);
2026 0 : if (!namespace_)
2027 0 : return false;
2028 :
2029 0 : args.rval().setObject(*namespace_);
2030 0 : return true;
2031 : }
2032 :
2033 : static bool
2034 0 : intrinsic_AddModuleNamespaceBinding(JSContext* cx, unsigned argc, Value* vp)
2035 : {
2036 0 : CallArgs args = CallArgsFromVp(argc, vp);
2037 0 : MOZ_ASSERT(args.length() == 4);
2038 0 : RootedModuleNamespaceObject namespace_(cx, &args[0].toObject().as<ModuleNamespaceObject>());
2039 0 : RootedAtom exportedName(cx, &args[1].toString()->asAtom());
2040 0 : RootedModuleObject targetModule(cx, &args[2].toObject().as<ModuleObject>());
2041 0 : RootedAtom localName(cx, &args[3].toString()->asAtom());
2042 0 : if (!namespace_->addBinding(cx, exportedName, targetModule, localName))
2043 0 : return false;
2044 :
2045 0 : args.rval().setUndefined();
2046 0 : return true;
2047 : }
2048 :
2049 : static bool
2050 0 : intrinsic_ModuleNamespaceExports(JSContext* cx, unsigned argc, Value* vp)
2051 : {
2052 0 : CallArgs args = CallArgsFromVp(argc, vp);
2053 0 : MOZ_ASSERT(args.length() == 1);
2054 0 : RootedModuleNamespaceObject namespace_(cx, &args[0].toObject().as<ModuleNamespaceObject>());
2055 0 : args.rval().setObject(namespace_->exports());
2056 0 : return true;
2057 : }
2058 :
2059 : static bool
2060 0 : intrinsic_CreatePendingPromise(JSContext* cx, unsigned argc, Value* vp)
2061 : {
2062 0 : CallArgs args = CallArgsFromVp(argc, vp);
2063 0 : MOZ_ASSERT(args.length() == 0);
2064 0 : JSObject* promise = PromiseObject::createSkippingExecutor(cx);
2065 0 : if (!promise)
2066 0 : return false;
2067 0 : args.rval().setObject(*promise);
2068 0 : return true;
2069 : }
2070 :
2071 : static bool
2072 0 : intrinsic_CreatePromiseResolvedWith(JSContext* cx, unsigned argc, Value* vp)
2073 : {
2074 0 : CallArgs args = CallArgsFromVp(argc, vp);
2075 0 : MOZ_ASSERT(args.length() == 1);
2076 0 : JSObject* promise = PromiseObject::unforgeableResolve(cx, args[0]);
2077 0 : if (!promise)
2078 0 : return false;
2079 0 : args.rval().setObject(*promise);
2080 0 : return true;
2081 : }
2082 :
2083 : static bool
2084 0 : intrinsic_CreatePromiseRejectedWith(JSContext* cx, unsigned argc, Value* vp)
2085 : {
2086 0 : CallArgs args = CallArgsFromVp(argc, vp);
2087 0 : MOZ_ASSERT(args.length() == 1);
2088 0 : JSObject* promise = PromiseObject::unforgeableReject(cx, args[0]);
2089 0 : if (!promise)
2090 0 : return false;
2091 0 : args.rval().setObject(*promise);
2092 0 : return true;
2093 : }
2094 :
2095 : static bool
2096 0 : intrinsic_ResolvePromise(JSContext* cx, unsigned argc, Value* vp)
2097 : {
2098 0 : CallArgs args = CallArgsFromVp(argc, vp);
2099 0 : MOZ_ASSERT(args.length() == 2);
2100 0 : Rooted<PromiseObject*> promise(cx, &args[0].toObject().as<PromiseObject>());
2101 0 : if (!PromiseObject::resolve(cx, promise, args[1]))
2102 0 : return false;
2103 0 : args.rval().setUndefined();
2104 0 : return true;
2105 : }
2106 :
2107 : static bool
2108 0 : intrinsic_RejectPromise(JSContext* cx, unsigned argc, Value* vp)
2109 : {
2110 0 : CallArgs args = CallArgsFromVp(argc, vp);
2111 0 : MOZ_ASSERT(args.length() == 2);
2112 0 : Rooted<PromiseObject*> promise(cx, &args[0].toObject().as<PromiseObject>());
2113 0 : if (!PromiseObject::reject(cx, promise, args[1]))
2114 0 : return false;
2115 0 : args.rval().setUndefined();
2116 0 : return true;
2117 : }
2118 :
2119 : static bool
2120 0 : intrinsic_CallOriginalPromiseThen(JSContext* cx, unsigned argc, Value* vp)
2121 : {
2122 0 : CallArgs args = CallArgsFromVp(argc, vp);
2123 0 : MOZ_ASSERT(args.length() >= 2);
2124 :
2125 0 : RootedObject promise(cx, &args[0].toObject());
2126 0 : Value val = args[1];
2127 0 : RootedObject onResolvedObj(cx, val.isUndefined() ? nullptr : val.toObjectOrNull());
2128 0 : val = args.get(2);
2129 0 : RootedObject onRejectedObj(cx, val.isUndefined() ? nullptr : val.toObjectOrNull());
2130 :
2131 0 : JSObject* resultPromise = JS::CallOriginalPromiseThen(cx, promise, onResolvedObj,
2132 0 : onRejectedObj);
2133 0 : if (!resultPromise)
2134 0 : return false;
2135 0 : args.rval().setObject(*resultPromise);
2136 0 : return true;
2137 : }
2138 :
2139 : static bool
2140 0 : intrinsic_AddPromiseReactions(JSContext* cx, unsigned argc, Value* vp)
2141 : {
2142 0 : CallArgs args = CallArgsFromVp(argc, vp);
2143 0 : MOZ_ASSERT(args.length() >= 2);
2144 :
2145 0 : RootedObject promise(cx, &args[0].toObject());
2146 0 : Value val = args[1];
2147 0 : RootedObject onResolvedObj(cx, val.isUndefined() ? nullptr : val.toObjectOrNull());
2148 0 : val = args.get(2);
2149 0 : RootedObject onRejectedObj(cx, val.isUndefined() ? nullptr : val.toObjectOrNull());
2150 :
2151 0 : if (!JS::AddPromiseReactions(cx, promise, onResolvedObj, onRejectedObj))
2152 0 : return false;
2153 0 : args.rval().setUndefined();
2154 0 : return true;
2155 : }
2156 :
2157 : // The self-hosting global isn't initialized with the normal set of builtins.
2158 : // Instead, individual C++-implemented functions that're required by
2159 : // self-hosted code are defined as global functions. Accessing these
2160 : // functions via a content compartment's builtins would be unsafe, because
2161 : // content script might have changed the builtins' prototypes' members.
2162 : // Installing the whole set of builtins in the self-hosting compartment, OTOH,
2163 : // would be wasteful: it increases memory usage and initialization time for
2164 : // self-hosting compartment.
2165 : //
2166 : // Additionally, a set of C++-implemented helper functions is defined on the
2167 : // self-hosting global.
2168 : static const JSFunctionSpec intrinsic_functions[] = {
2169 : JS_INLINABLE_FN("std_Array", array_construct, 1,0, Array),
2170 : JS_FN("std_Array_join", array_join, 1,0),
2171 : JS_INLINABLE_FN("std_Array_push", array_push, 1,0, ArrayPush),
2172 : JS_INLINABLE_FN("std_Array_pop", array_pop, 0,0, ArrayPop),
2173 : JS_INLINABLE_FN("std_Array_shift", array_shift, 0,0, ArrayShift),
2174 : JS_FN("std_Array_unshift", array_unshift, 1,0),
2175 : JS_INLINABLE_FN("std_Array_slice", array_slice, 2,0, ArraySlice),
2176 : JS_FN("std_Array_sort", array_sort, 1,0),
2177 : JS_FN("std_Array_reverse", array_reverse, 0,0),
2178 : JS_FNINFO("std_Array_splice", array_splice, &array_splice_info, 2,0),
2179 :
2180 : JS_FN("std_Date_now", date_now, 0,0),
2181 : JS_FN("std_Date_valueOf", date_valueOf, 0,0),
2182 :
2183 : JS_FN("std_Function_apply", fun_apply, 2,0),
2184 :
2185 : JS_INLINABLE_FN("std_Math_floor", math_floor, 1,0, MathFloor),
2186 : JS_INLINABLE_FN("std_Math_max", math_max, 2,0, MathMax),
2187 : JS_INLINABLE_FN("std_Math_min", math_min, 2,0, MathMin),
2188 : JS_INLINABLE_FN("std_Math_abs", math_abs, 1,0, MathAbs),
2189 :
2190 : JS_FN("std_Map_has", MapObject::has, 1,0),
2191 : JS_FN("std_Map_iterator", MapObject::entries, 0,0),
2192 :
2193 : JS_FN("std_Number_valueOf", num_valueOf, 0,0),
2194 :
2195 : JS_INLINABLE_FN("std_Object_create", obj_create, 2, 0, ObjectCreate),
2196 : JS_FN("std_Object_propertyIsEnumerable", obj_propertyIsEnumerable, 1,0),
2197 : JS_FN("std_Object_defineProperty", obj_defineProperty, 3,0),
2198 : JS_FN("std_Object_getOwnPropertyNames", obj_getOwnPropertyNames, 1,0),
2199 : JS_FN("std_Object_getOwnPropertyDescriptor", obj_getOwnPropertyDescriptor, 2,0),
2200 : JS_FN("std_Object_toString", obj_toString, 0,0),
2201 :
2202 : JS_FN("std_Reflect_getPrototypeOf", Reflect_getPrototypeOf, 1,0),
2203 : JS_FN("std_Reflect_isExtensible", Reflect_isExtensible, 1,0),
2204 :
2205 : JS_FN("std_Set_has", SetObject::has, 1,0),
2206 : JS_FN("std_Set_iterator", SetObject::values, 0,0),
2207 :
2208 : JS_INLINABLE_FN("std_String_fromCharCode", str_fromCharCode, 1,0, StringFromCharCode),
2209 : JS_INLINABLE_FN("std_String_fromCodePoint", str_fromCodePoint, 1,0, StringFromCodePoint),
2210 : JS_INLINABLE_FN("std_String_charCodeAt", str_charCodeAt, 1,0, StringCharCodeAt),
2211 : JS_FN("std_String_includes", str_includes, 1,0),
2212 : JS_FN("std_String_indexOf", str_indexOf, 1,0),
2213 : JS_FN("std_String_lastIndexOf", str_lastIndexOf, 1,0),
2214 : JS_FN("std_String_startsWith", str_startsWith, 1,0),
2215 : JS_FN("std_String_toLowerCase", str_toLowerCase, 0,0),
2216 : JS_FN("std_String_toUpperCase", str_toUpperCase, 0,0),
2217 :
2218 : JS_INLINABLE_FN("std_String_charAt", str_charAt, 1,0, StringCharAt),
2219 : JS_FN("std_String_endsWith", str_endsWith, 1,0),
2220 : JS_FN("std_String_trim", str_trim, 0,0),
2221 : JS_FN("std_String_trimLeft", str_trimLeft, 0,0),
2222 : JS_FN("std_String_trimRight", str_trimRight, 0,0),
2223 : #if !EXPOSE_INTL_API
2224 : JS_FN("std_String_toLocaleLowerCase", str_toLocaleLowerCase, 0,0),
2225 : JS_FN("std_String_toLocaleUpperCase", str_toLocaleUpperCase, 0,0),
2226 : JS_FN("std_String_localeCompare", str_localeCompare, 1,0),
2227 : #else
2228 : JS_FN("std_String_normalize", str_normalize, 0,0),
2229 : #endif
2230 : JS_FN("std_String_concat", str_concat, 1,0),
2231 :
2232 : JS_FN("std_TypedArray_buffer", js::TypedArray_bufferGetter, 1,0),
2233 :
2234 : JS_FN("std_WeakMap_has", WeakMap_has, 1,0),
2235 : JS_FN("std_WeakMap_get", WeakMap_get, 2,0),
2236 : JS_FN("std_WeakMap_set", WeakMap_set, 2,0),
2237 : JS_FN("std_WeakMap_delete", WeakMap_delete, 1,0),
2238 :
2239 : JS_FN("std_SIMD_Int8x16_extractLane", simd_int8x16_extractLane, 2,0),
2240 : JS_FN("std_SIMD_Int16x8_extractLane", simd_int16x8_extractLane, 2,0),
2241 : JS_INLINABLE_FN("std_SIMD_Int32x4_extractLane", simd_int32x4_extractLane, 2,0, SimdInt32x4_extractLane),
2242 : JS_FN("std_SIMD_Uint8x16_extractLane", simd_uint8x16_extractLane, 2,0),
2243 : JS_FN("std_SIMD_Uint16x8_extractLane", simd_uint16x8_extractLane, 2,0),
2244 : JS_FN("std_SIMD_Uint32x4_extractLane", simd_uint32x4_extractLane, 2,0),
2245 : JS_INLINABLE_FN("std_SIMD_Float32x4_extractLane", simd_float32x4_extractLane,2,0, SimdFloat32x4_extractLane),
2246 : JS_FN("std_SIMD_Float64x2_extractLane", simd_float64x2_extractLane, 2,0),
2247 : JS_FN("std_SIMD_Bool8x16_extractLane", simd_bool8x16_extractLane, 2,0),
2248 : JS_FN("std_SIMD_Bool16x8_extractLane", simd_bool16x8_extractLane, 2,0),
2249 : JS_FN("std_SIMD_Bool32x4_extractLane", simd_bool32x4_extractLane, 2,0),
2250 : JS_FN("std_SIMD_Bool64x2_extractLane", simd_bool64x2_extractLane, 2,0),
2251 :
2252 : // Helper funtions after this point.
2253 : JS_INLINABLE_FN("ToObject", intrinsic_ToObject, 1,0, IntrinsicToObject),
2254 : JS_INLINABLE_FN("IsObject", intrinsic_IsObject, 1,0, IntrinsicIsObject),
2255 : JS_INLINABLE_FN("IsArray", intrinsic_IsArray, 1,0, ArrayIsArray),
2256 : JS_INLINABLE_FN("IsWrappedArrayConstructor", intrinsic_IsWrappedArrayConstructor, 1,0,
2257 : IntrinsicIsWrappedArrayConstructor),
2258 : JS_INLINABLE_FN("ToInteger", intrinsic_ToInteger, 1,0, IntrinsicToInteger),
2259 : JS_INLINABLE_FN("ToString", intrinsic_ToString, 1,0, IntrinsicToString),
2260 : JS_FN("ToSource", intrinsic_ToSource, 1,0),
2261 : JS_FN("ToPropertyKey", intrinsic_ToPropertyKey, 1,0),
2262 : JS_INLINABLE_FN("IsCallable", intrinsic_IsCallable, 1,0, IntrinsicIsCallable),
2263 : JS_INLINABLE_FN("IsConstructor", intrinsic_IsConstructor, 1,0,
2264 : IntrinsicIsConstructor),
2265 : JS_FN("GetBuiltinConstructorImpl", intrinsic_GetBuiltinConstructor, 1,0),
2266 : JS_FN("MakeConstructible", intrinsic_MakeConstructible, 2,0),
2267 : JS_FN("_ConstructFunction", intrinsic_ConstructFunction, 2,0),
2268 : JS_FN("ThrowRangeError", intrinsic_ThrowRangeError, 4,0),
2269 : JS_FN("ThrowTypeError", intrinsic_ThrowTypeError, 4,0),
2270 : JS_FN("ThrowSyntaxError", intrinsic_ThrowSyntaxError, 4,0),
2271 : JS_FN("ThrowInternalError", intrinsic_ThrowInternalError, 4,0),
2272 : JS_FN("AssertionFailed", intrinsic_AssertionFailed, 1,0),
2273 : JS_FN("DumpMessage", intrinsic_DumpMessage, 1,0),
2274 : JS_FN("OwnPropertyKeys", intrinsic_OwnPropertyKeys, 1,0),
2275 : JS_FN("MakeDefaultConstructor", intrinsic_MakeDefaultConstructor, 2,0),
2276 : JS_FN("_ConstructorForTypedArray", intrinsic_ConstructorForTypedArray, 1,0),
2277 : JS_FN("_NameForTypedArray", intrinsic_NameForTypedArray, 1,0),
2278 : JS_FN("DecompileArg", intrinsic_DecompileArg, 2,0),
2279 : JS_INLINABLE_FN("_FinishBoundFunctionInit", intrinsic_FinishBoundFunctionInit, 3,0,
2280 : IntrinsicFinishBoundFunctionInit),
2281 : JS_FN("RuntimeDefaultLocale", intrinsic_RuntimeDefaultLocale, 0,0),
2282 : JS_FN("AddContentTelemetry", intrinsic_AddContentTelemetry, 2,0),
2283 : JS_FN("_DefineDataProperty", intrinsic_DefineDataProperty, 4,0),
2284 :
2285 : JS_INLINABLE_FN("_IsConstructing", intrinsic_IsConstructing, 0,0,
2286 : IntrinsicIsConstructing),
2287 : JS_INLINABLE_FN("SubstringKernel", intrinsic_SubstringKernel, 3,0,
2288 : IntrinsicSubstringKernel),
2289 : JS_INLINABLE_FN("ObjectHasPrototype", intrinsic_ObjectHasPrototype, 2,0,
2290 : IntrinsicObjectHasPrototype),
2291 : JS_INLINABLE_FN("UnsafeSetReservedSlot", intrinsic_UnsafeSetReservedSlot, 3,0,
2292 : IntrinsicUnsafeSetReservedSlot),
2293 : JS_INLINABLE_FN("UnsafeGetReservedSlot", intrinsic_UnsafeGetReservedSlot, 2,0,
2294 : IntrinsicUnsafeGetReservedSlot),
2295 : JS_INLINABLE_FN("UnsafeGetObjectFromReservedSlot", intrinsic_UnsafeGetObjectFromReservedSlot, 2,0,
2296 : IntrinsicUnsafeGetObjectFromReservedSlot),
2297 : JS_INLINABLE_FN("UnsafeGetInt32FromReservedSlot", intrinsic_UnsafeGetInt32FromReservedSlot, 2,0,
2298 : IntrinsicUnsafeGetInt32FromReservedSlot),
2299 : JS_INLINABLE_FN("UnsafeGetStringFromReservedSlot", intrinsic_UnsafeGetStringFromReservedSlot, 2,0,
2300 : IntrinsicUnsafeGetStringFromReservedSlot),
2301 : JS_INLINABLE_FN("UnsafeGetBooleanFromReservedSlot", intrinsic_UnsafeGetBooleanFromReservedSlot,2,0,
2302 : IntrinsicUnsafeGetBooleanFromReservedSlot),
2303 :
2304 : JS_FN("IsPackedArray", intrinsic_IsPackedArray, 1,0),
2305 :
2306 : JS_FN("GetIteratorPrototype", intrinsic_GetIteratorPrototype, 0,0),
2307 :
2308 : JS_INLINABLE_FN("NewArrayIterator", intrinsic_NewArrayIterator, 0,0,
2309 : IntrinsicNewArrayIterator),
2310 :
2311 : JS_FN("CallArrayIteratorMethodIfWrapped",
2312 : CallNonGenericSelfhostedMethod<Is<ArrayIteratorObject>>, 2,0),
2313 :
2314 : JS_FN("_SetCanonicalName", intrinsic_SetCanonicalName, 2,0),
2315 :
2316 : JS_INLINABLE_FN("IsArrayIterator",
2317 : intrinsic_IsInstanceOfBuiltin<ArrayIteratorObject>, 1,0,
2318 : IntrinsicIsArrayIterator),
2319 : JS_INLINABLE_FN("IsMapIterator",
2320 : intrinsic_IsInstanceOfBuiltin<MapIteratorObject>, 1,0,
2321 : IntrinsicIsMapIterator),
2322 : JS_INLINABLE_FN("IsSetIterator",
2323 : intrinsic_IsInstanceOfBuiltin<SetIteratorObject>, 1,0,
2324 : IntrinsicIsSetIterator),
2325 : JS_INLINABLE_FN("IsStringIterator",
2326 : intrinsic_IsInstanceOfBuiltin<StringIteratorObject>, 1,0,
2327 : IntrinsicIsStringIterator),
2328 :
2329 : JS_FN("_CreateMapIterationResultPair", intrinsic_CreateMapIterationResultPair, 0, 0),
2330 : JS_INLINABLE_FN("_GetNextMapEntryForIterator", intrinsic_GetNextMapEntryForIterator, 2,0,
2331 : IntrinsicGetNextMapEntryForIterator),
2332 : JS_FN("CallMapIteratorMethodIfWrapped",
2333 : CallNonGenericSelfhostedMethod<Is<MapIteratorObject>>, 2,0),
2334 :
2335 : JS_FN("_CreateSetIterationResult", intrinsic_CreateSetIterationResult, 0, 0),
2336 : JS_INLINABLE_FN("_GetNextSetEntryForIterator", intrinsic_GetNextSetEntryForIterator, 2,0,
2337 : IntrinsicGetNextSetEntryForIterator),
2338 : JS_FN("CallSetIteratorMethodIfWrapped",
2339 : CallNonGenericSelfhostedMethod<Is<SetIteratorObject>>, 2,0),
2340 :
2341 :
2342 : JS_INLINABLE_FN("NewStringIterator", intrinsic_NewStringIterator, 0,0,
2343 : IntrinsicNewStringIterator),
2344 : JS_FN("CallStringIteratorMethodIfWrapped",
2345 : CallNonGenericSelfhostedMethod<Is<StringIteratorObject>>, 2,0),
2346 :
2347 : JS_FN("IsStarGeneratorObject",
2348 : intrinsic_IsInstanceOfBuiltin<StarGeneratorObject>, 1,0),
2349 : JS_FN("StarGeneratorObjectIsClosed", intrinsic_StarGeneratorObjectIsClosed, 1,0),
2350 : JS_FN("IsSuspendedStarGenerator",intrinsic_IsSuspendedStarGenerator,1,0),
2351 :
2352 : JS_FN("IsLegacyGeneratorObject",
2353 : intrinsic_IsInstanceOfBuiltin<LegacyGeneratorObject>, 1,0),
2354 : JS_FN("LegacyGeneratorObjectIsClosed", intrinsic_LegacyGeneratorObjectIsClosed, 1,0),
2355 : JS_FN("CloseClosingLegacyGeneratorObject", intrinsic_CloseClosingLegacyGeneratorObject, 1,0),
2356 : JS_FN("ThrowStopIteration", intrinsic_ThrowStopIteration, 0,0),
2357 :
2358 : JS_FN("GeneratorIsRunning", intrinsic_GeneratorIsRunning, 1,0),
2359 : JS_FN("GeneratorSetClosed", intrinsic_GeneratorSetClosed, 1,0),
2360 :
2361 : JS_FN("IsArrayBuffer",
2362 : intrinsic_IsInstanceOfBuiltin<ArrayBufferObject>, 1,0),
2363 : JS_FN("IsSharedArrayBuffer",
2364 : intrinsic_IsInstanceOfBuiltin<SharedArrayBufferObject>, 1,0),
2365 : JS_FN("IsWrappedArrayBuffer",
2366 : intrinsic_IsWrappedArrayBuffer<ArrayBufferObject>, 1,0),
2367 : JS_FN("IsWrappedSharedArrayBuffer",
2368 : intrinsic_IsWrappedArrayBuffer<SharedArrayBufferObject>, 1,0),
2369 :
2370 : JS_INLINABLE_FN("ArrayBufferByteLength",
2371 : intrinsic_ArrayBufferByteLength<ArrayBufferObject>, 1,0,
2372 : IntrinsicArrayBufferByteLength),
2373 : JS_INLINABLE_FN("PossiblyWrappedArrayBufferByteLength",
2374 : intrinsic_PossiblyWrappedArrayBufferByteLength<ArrayBufferObject>, 1,0,
2375 : IntrinsicPossiblyWrappedArrayBufferByteLength),
2376 : JS_FN("ArrayBufferCopyData",
2377 : intrinsic_ArrayBufferCopyData<ArrayBufferObject>, 6,0),
2378 :
2379 : JS_FN("SharedArrayBufferByteLength",
2380 : intrinsic_ArrayBufferByteLength<SharedArrayBufferObject>, 1,0),
2381 : JS_FN("PossiblyWrappedSharedArrayBufferByteLength",
2382 : intrinsic_PossiblyWrappedArrayBufferByteLength<SharedArrayBufferObject>, 1,0),
2383 : JS_FN("SharedArrayBufferCopyData",
2384 : intrinsic_ArrayBufferCopyData<SharedArrayBufferObject>, 6,0),
2385 : JS_FN("SharedArrayBuffersMemorySame",
2386 : intrinsic_SharedArrayBuffersMemorySame, 2,0),
2387 :
2388 : JS_FN("IsUint8TypedArray", intrinsic_IsUint8TypedArray, 1,0),
2389 : JS_FN("IsInt8TypedArray", intrinsic_IsInt8TypedArray, 1,0),
2390 : JS_FN("IsUint16TypedArray", intrinsic_IsUint16TypedArray, 1,0),
2391 : JS_FN("IsInt16TypedArray", intrinsic_IsInt16TypedArray, 1,0),
2392 : JS_FN("IsUint32TypedArray", intrinsic_IsUint32TypedArray, 1,0),
2393 : JS_FN("IsInt32TypedArray", intrinsic_IsInt32TypedArray, 1,0),
2394 : JS_FN("IsFloat32TypedArray", intrinsic_IsFloat32TypedArray, 1,0),
2395 : JS_INLINABLE_FN("IsTypedArray",
2396 : intrinsic_IsInstanceOfBuiltin<TypedArrayObject>, 1,0,
2397 : IntrinsicIsTypedArray),
2398 : JS_INLINABLE_FN("IsPossiblyWrappedTypedArray",intrinsic_IsPossiblyWrappedTypedArray,1,0,
2399 : IntrinsicIsPossiblyWrappedTypedArray),
2400 :
2401 : JS_FN("TypedArrayBuffer", intrinsic_TypedArrayBuffer, 1,0),
2402 : JS_FN("TypedArrayByteOffset", intrinsic_TypedArrayByteOffset, 1,0),
2403 : JS_FN("TypedArrayElementShift", intrinsic_TypedArrayElementShift, 1,0),
2404 :
2405 : JS_INLINABLE_FN("TypedArrayLength", intrinsic_TypedArrayLength, 1,0,
2406 : IntrinsicTypedArrayLength),
2407 : JS_INLINABLE_FN("PossiblyWrappedTypedArrayLength", intrinsic_PossiblyWrappedTypedArrayLength,
2408 : 1, 0, IntrinsicPossiblyWrappedTypedArrayLength),
2409 : JS_FN("PossiblyWrappedTypedArrayHasDetachedBuffer",
2410 : intrinsic_PossiblyWrappedTypedArrayHasDetachedBuffer, 1, 0),
2411 :
2412 : JS_FN("MoveTypedArrayElements", intrinsic_MoveTypedArrayElements, 4,0),
2413 : JS_FN("SetFromTypedArrayApproach",intrinsic_SetFromTypedArrayApproach, 4, 0),
2414 : JS_FN("SetOverlappingTypedElements",intrinsic_SetOverlappingTypedElements,3,0),
2415 :
2416 : JS_INLINABLE_FN("SetDisjointTypedElements",intrinsic_SetDisjointTypedElements,3,0,
2417 : IntrinsicSetDisjointTypedElements),
2418 :
2419 : JS_FN("CallArrayBufferMethodIfWrapped",
2420 : CallNonGenericSelfhostedMethod<Is<ArrayBufferObject>>, 2, 0),
2421 : JS_FN("CallSharedArrayBufferMethodIfWrapped",
2422 : CallNonGenericSelfhostedMethod<Is<SharedArrayBufferObject>>, 2, 0),
2423 : JS_FN("CallTypedArrayMethodIfWrapped",
2424 : CallNonGenericSelfhostedMethod<Is<TypedArrayObject>>, 2, 0),
2425 :
2426 : JS_FN("CallLegacyGeneratorMethodIfWrapped",
2427 : CallNonGenericSelfhostedMethod<Is<LegacyGeneratorObject>>, 2, 0),
2428 : JS_FN("CallStarGeneratorMethodIfWrapped",
2429 : CallNonGenericSelfhostedMethod<Is<StarGeneratorObject>>, 2, 0),
2430 :
2431 : JS_FN("IsWeakSet", intrinsic_IsInstanceOfBuiltin<WeakSetObject>, 1,0),
2432 : JS_FN("CallWeakSetMethodIfWrapped",
2433 : CallNonGenericSelfhostedMethod<Is<WeakSetObject>>, 2, 0),
2434 :
2435 : // See builtin/TypedObject.h for descriptors of the typedobj functions.
2436 : JS_FN("NewOpaqueTypedObject", js::NewOpaqueTypedObject, 1, 0),
2437 : JS_FN("NewDerivedTypedObject", js::NewDerivedTypedObject, 3, 0),
2438 : JS_FN("TypedObjectBuffer", TypedObject::GetBuffer, 1, 0),
2439 : JS_FN("TypedObjectByteOffset", TypedObject::GetByteOffset, 1, 0),
2440 : JS_FN("AttachTypedObject", js::AttachTypedObject, 3, 0),
2441 : JS_FN("TypedObjectIsAttached", js::TypedObjectIsAttached, 1, 0),
2442 : JS_FN("TypedObjectTypeDescr", js::TypedObjectTypeDescr, 1, 0),
2443 : JS_FN("ClampToUint8", js::ClampToUint8, 1, 0),
2444 : JS_FN("GetTypedObjectModule", js::GetTypedObjectModule, 0, 0),
2445 : JS_FN("GetSimdTypeDescr", js::GetSimdTypeDescr, 1, 0),
2446 :
2447 : JS_INLINABLE_FN("ObjectIsTypeDescr" , js::ObjectIsTypeDescr, 1, 0,
2448 : IntrinsicObjectIsTypeDescr),
2449 : JS_INLINABLE_FN("ObjectIsTypedObject", js::ObjectIsTypedObject, 1, 0,
2450 : IntrinsicObjectIsTypedObject),
2451 : JS_INLINABLE_FN("ObjectIsOpaqueTypedObject", js::ObjectIsOpaqueTypedObject, 1, 0,
2452 : IntrinsicObjectIsOpaqueTypedObject),
2453 : JS_INLINABLE_FN("ObjectIsTransparentTypedObject", js::ObjectIsTransparentTypedObject, 1, 0,
2454 : IntrinsicObjectIsTransparentTypedObject),
2455 : JS_INLINABLE_FN("TypeDescrIsArrayType", js::TypeDescrIsArrayType, 1, 0,
2456 : IntrinsicTypeDescrIsArrayType),
2457 : JS_INLINABLE_FN("TypeDescrIsSimpleType", js::TypeDescrIsSimpleType, 1, 0,
2458 : IntrinsicTypeDescrIsSimpleType),
2459 : JS_INLINABLE_FN("SetTypedObjectOffset", js::SetTypedObjectOffset, 2, 0,
2460 : IntrinsicSetTypedObjectOffset),
2461 :
2462 : #define LOAD_AND_STORE_SCALAR_FN_DECLS(_constant, _type, _name) \
2463 : JS_FN("Store_" #_name, js::StoreScalar##_type::Func, 3, 0), \
2464 : JS_FN("Load_" #_name, js::LoadScalar##_type::Func, 3, 0),
2465 : JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(LOAD_AND_STORE_SCALAR_FN_DECLS)
2466 : #undef LOAD_AND_STORE_SCALAR_FN_DECLS
2467 :
2468 : #define LOAD_AND_STORE_REFERENCE_FN_DECLS(_constant, _type, _name) \
2469 : JS_FN("Store_" #_name, js::StoreReference##_name::Func, 3, 0), \
2470 : JS_FN("Load_" #_name, js::LoadReference##_name::Func, 3, 0),
2471 : JS_FOR_EACH_REFERENCE_TYPE_REPR(LOAD_AND_STORE_REFERENCE_FN_DECLS)
2472 : #undef LOAD_AND_STORE_REFERENCE_FN_DECLS
2473 :
2474 : // See builtin/Intl.h for descriptions of the intl_* functions.
2475 : JS_FN("intl_availableCalendars", intl_availableCalendars, 1,0),
2476 : JS_FN("intl_availableCollations", intl_availableCollations, 1,0),
2477 : JS_FN("intl_canonicalizeTimeZone", intl_canonicalizeTimeZone, 1,0),
2478 : JS_FN("intl_Collator", intl_Collator, 2,0),
2479 : JS_FN("intl_Collator_availableLocales", intl_Collator_availableLocales, 0,0),
2480 : JS_FN("intl_CompareStrings", intl_CompareStrings, 3,0),
2481 : JS_FN("intl_DateTimeFormat", intl_DateTimeFormat, 2,0),
2482 : JS_FN("intl_DateTimeFormat_availableLocales", intl_DateTimeFormat_availableLocales, 0,0),
2483 : JS_FN("intl_defaultCalendar", intl_defaultCalendar, 1,0),
2484 : JS_FN("intl_defaultTimeZone", intl_defaultTimeZone, 0,0),
2485 : JS_FN("intl_defaultTimeZoneOffset", intl_defaultTimeZoneOffset, 0,0),
2486 : JS_FN("intl_FormatDateTime", intl_FormatDateTime, 2,0),
2487 : JS_FN("intl_FormatNumber", intl_FormatNumber, 2,0),
2488 : JS_FN("intl_GetCalendarInfo", intl_GetCalendarInfo, 1,0),
2489 : JS_FN("intl_GetLocaleInfo", intl_GetLocaleInfo, 1,0),
2490 : JS_FN("intl_ComputeDisplayNames", intl_ComputeDisplayNames, 3,0),
2491 : JS_FN("intl_isUpperCaseFirst", intl_isUpperCaseFirst, 1,0),
2492 : JS_FN("intl_IsValidTimeZoneName", intl_IsValidTimeZoneName, 1,0),
2493 : JS_FN("intl_NumberFormat", intl_NumberFormat, 2,0),
2494 : JS_FN("intl_NumberFormat_availableLocales", intl_NumberFormat_availableLocales, 0,0),
2495 : JS_FN("intl_numberingSystem", intl_numberingSystem, 1,0),
2496 : JS_FN("intl_patternForSkeleton", intl_patternForSkeleton, 2,0),
2497 : JS_FN("intl_patternForStyle", intl_patternForStyle, 3,0),
2498 : JS_FN("intl_PluralRules_availableLocales", intl_PluralRules_availableLocales, 0,0),
2499 : JS_FN("intl_GetPluralCategories", intl_GetPluralCategories, 2, 0),
2500 : JS_FN("intl_SelectPluralRule", intl_SelectPluralRule, 2,0),
2501 : JS_FN("intl_toLocaleLowerCase", intl_toLocaleLowerCase, 2,0),
2502 : JS_FN("intl_toLocaleUpperCase", intl_toLocaleUpperCase, 2,0),
2503 :
2504 : JS_INLINABLE_FN("IsCollator",
2505 : intrinsic_IsInstanceOfBuiltin<CollatorObject>, 1,0,
2506 : IntlIsCollator),
2507 : JS_INLINABLE_FN("IsDateTimeFormat",
2508 : intrinsic_IsInstanceOfBuiltin<DateTimeFormatObject>, 1,0,
2509 : IntlIsDateTimeFormat),
2510 : JS_INLINABLE_FN("IsNumberFormat",
2511 : intrinsic_IsInstanceOfBuiltin<NumberFormatObject>, 1,0,
2512 : IntlIsNumberFormat),
2513 : JS_INLINABLE_FN("IsPluralRules",
2514 : intrinsic_IsInstanceOfBuiltin<PluralRulesObject>, 1,0,
2515 : IntlIsPluralRules),
2516 : JS_FN("GetDateTimeFormatConstructor",
2517 : intrinsic_GetBuiltinIntlConstructor<GlobalObject::getOrCreateDateTimeFormatConstructor>,
2518 : 0,0),
2519 : JS_FN("GetNumberFormatConstructor",
2520 : intrinsic_GetBuiltinIntlConstructor<GlobalObject::getOrCreateNumberFormatConstructor>,
2521 : 0,0),
2522 :
2523 : JS_INLINABLE_FN("IsRegExpObject",
2524 : intrinsic_IsInstanceOfBuiltin<RegExpObject>, 1,0,
2525 : IsRegExpObject),
2526 : JS_FN("CallRegExpMethodIfWrapped",
2527 : CallNonGenericSelfhostedMethod<Is<RegExpObject>>, 2,0),
2528 : JS_INLINABLE_FN("RegExpMatcher", RegExpMatcher, 3,0,
2529 : RegExpMatcher),
2530 : JS_INLINABLE_FN("RegExpSearcher", RegExpSearcher, 3,0,
2531 : RegExpSearcher),
2532 : JS_INLINABLE_FN("RegExpTester", RegExpTester, 3,0,
2533 : RegExpTester),
2534 : JS_FN("RegExpCreate", intrinsic_RegExpCreate, 2,0),
2535 : JS_INLINABLE_FN("RegExpPrototypeOptimizable", RegExpPrototypeOptimizable, 1,0,
2536 : RegExpPrototypeOptimizable),
2537 : JS_INLINABLE_FN("RegExpInstanceOptimizable", RegExpInstanceOptimizable, 1,0,
2538 : RegExpInstanceOptimizable),
2539 : JS_FN("RegExpGetSubstitution", intrinsic_RegExpGetSubstitution, 6,0),
2540 : JS_FN("GetElemBaseForLambda", intrinsic_GetElemBaseForLambda, 1,0),
2541 : JS_FN("GetStringDataProperty", intrinsic_GetStringDataProperty, 2,0),
2542 : JS_INLINABLE_FN("GetFirstDollarIndex", GetFirstDollarIndex, 1,0,
2543 : GetFirstDollarIndex),
2544 :
2545 : JS_FN("FlatStringMatch", FlatStringMatch, 2,0),
2546 : JS_FN("FlatStringSearch", FlatStringSearch, 2,0),
2547 : JS_INLINABLE_FN("StringReplaceString", intrinsic_StringReplaceString, 3, 0,
2548 : IntrinsicStringReplaceString),
2549 : JS_INLINABLE_FN("StringSplitString", intrinsic_StringSplitString, 2, 0,
2550 : IntrinsicStringSplitString),
2551 : JS_FN("StringSplitStringLimit", intrinsic_StringSplitStringLimit, 3, 0),
2552 : JS_FN("WarnDeprecatedStringMethod", intrinsic_WarnDeprecatedStringMethod, 2, 0),
2553 :
2554 : // See builtin/RegExp.h for descriptions of the regexp_* functions.
2555 : JS_FN("regexp_exec_no_statics", regexp_exec_no_statics, 2,0),
2556 : JS_FN("regexp_test_no_statics", regexp_test_no_statics, 2,0),
2557 : JS_FN("regexp_construct_raw_flags", regexp_construct_raw_flags, 2,0),
2558 :
2559 : JS_FN("IsModule", intrinsic_IsInstanceOfBuiltin<ModuleObject>, 1, 0),
2560 : JS_FN("CallModuleMethodIfWrapped",
2561 : CallNonGenericSelfhostedMethod<Is<ModuleObject>>, 2, 0),
2562 : JS_FN("HostResolveImportedModule", intrinsic_HostResolveImportedModule, 2, 0),
2563 : JS_FN("IsModuleEnvironment", intrinsic_IsInstanceOfBuiltin<ModuleEnvironmentObject>, 1, 0),
2564 : JS_FN("CreateModuleEnvironment", intrinsic_CreateModuleEnvironment, 1, 0),
2565 : JS_FN("CreateImportBinding", intrinsic_CreateImportBinding, 4, 0),
2566 : JS_FN("CreateNamespaceBinding", intrinsic_CreateNamespaceBinding, 3, 0),
2567 : JS_FN("InstantiateModuleFunctionDeclarations",
2568 : intrinsic_InstantiateModuleFunctionDeclarations, 1, 0),
2569 : JS_FN("SetModuleState", intrinsic_SetModuleState, 1, 0),
2570 : JS_FN("EvaluateModule", intrinsic_EvaluateModule, 1, 0),
2571 : JS_FN("NewModuleNamespace", intrinsic_NewModuleNamespace, 2, 0),
2572 : JS_FN("AddModuleNamespaceBinding", intrinsic_AddModuleNamespaceBinding, 4, 0),
2573 : JS_FN("ModuleNamespaceExports", intrinsic_ModuleNamespaceExports, 1, 0),
2574 :
2575 : JS_FN("CreatePendingPromise", intrinsic_CreatePendingPromise, 0, 0),
2576 : JS_FN("CreatePromiseResolvedWith", intrinsic_CreatePromiseResolvedWith, 1, 0),
2577 : JS_FN("CreatePromiseRejectedWith", intrinsic_CreatePromiseRejectedWith, 1, 0),
2578 : JS_FN("ResolvePromise", intrinsic_ResolvePromise, 2, 0),
2579 : JS_FN("RejectPromise", intrinsic_RejectPromise, 2, 0),
2580 : JS_FN("AddPromiseReactions", intrinsic_AddPromiseReactions, 3, 0),
2581 : JS_FN("CallOriginalPromiseThen", intrinsic_CallOriginalPromiseThen, 3, 0),
2582 :
2583 : JS_FS_END
2584 : };
2585 :
2586 : void
2587 144 : js::FillSelfHostingCompileOptions(CompileOptions& options)
2588 : {
2589 : /*
2590 : * In self-hosting mode, scripts use JSOP_GETINTRINSIC instead of
2591 : * JSOP_GETNAME or JSOP_GETGNAME to access unbound variables.
2592 : * JSOP_GETINTRINSIC does a name lookup on a special object, whose
2593 : * properties are filled in lazily upon first access for a given global.
2594 : *
2595 : * As that object is inaccessible to client code, the lookups are
2596 : * guaranteed to return the original objects, ensuring safe implementation
2597 : * of self-hosted builtins.
2598 : *
2599 : * Additionally, the special syntax callFunction(fun, receiver, ...args)
2600 : * is supported, for which bytecode is emitted that invokes |fun| with
2601 : * |receiver| as the this-object and ...args as the arguments.
2602 : */
2603 144 : options.setIntroductionType("self-hosted");
2604 144 : options.setFileAndLine("self-hosted", 1);
2605 144 : options.setSelfHostingMode(true);
2606 144 : options.setCanLazilyParse(false);
2607 144 : options.setVersion(JSVERSION_LATEST);
2608 144 : options.werrorOption = true;
2609 144 : options.strictOption = true;
2610 :
2611 : #ifdef DEBUG
2612 144 : options.extraWarningsOption = true;
2613 : #endif
2614 144 : }
2615 :
2616 : GlobalObject*
2617 3 : JSRuntime::createSelfHostingGlobal(JSContext* cx)
2618 : {
2619 3 : MOZ_ASSERT(!cx->isExceptionPending());
2620 3 : MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
2621 :
2622 3 : JS::CompartmentOptions options;
2623 3 : options.creationOptions().setNewZoneInSystemZoneGroup();
2624 3 : options.behaviors().setDiscardSource(true);
2625 :
2626 3 : JSCompartment* compartment = NewCompartment(cx, nullptr, options);
2627 3 : if (!compartment)
2628 0 : return nullptr;
2629 :
2630 : static const ClassOps shgClassOps = {
2631 : nullptr, nullptr, nullptr, nullptr,
2632 : nullptr, nullptr, nullptr, nullptr,
2633 : nullptr, nullptr, nullptr, nullptr,
2634 : JS_GlobalObjectTraceHook
2635 : };
2636 :
2637 : static const Class shgClass = {
2638 : "self-hosting-global", JSCLASS_GLOBAL_FLAGS,
2639 : &shgClassOps
2640 : };
2641 :
2642 6 : AutoCompartmentUnchecked ac(cx, compartment);
2643 6 : Rooted<GlobalObject*> shg(cx, GlobalObject::createInternal(cx, &shgClass));
2644 3 : if (!shg)
2645 0 : return nullptr;
2646 :
2647 3 : cx->runtime()->selfHostingGlobal_ = shg;
2648 3 : compartment->isSelfHosting = true;
2649 3 : compartment->setIsSystem(true);
2650 :
2651 3 : if (!GlobalObject::initSelfHostingBuiltins(cx, shg, intrinsic_functions))
2652 0 : return nullptr;
2653 :
2654 3 : JS_FireOnNewGlobalObject(cx, shg);
2655 :
2656 3 : return shg;
2657 : }
2658 :
2659 : static void
2660 3 : MaybePrintAndClearPendingException(JSContext* cx, FILE* file)
2661 : {
2662 3 : if (!cx->isExceptionPending())
2663 6 : return;
2664 :
2665 0 : AutoClearPendingException acpe(cx);
2666 :
2667 0 : RootedValue exn(cx);
2668 0 : if (!cx->getPendingException(&exn)) {
2669 0 : fprintf(file, "error getting pending exception\n");
2670 0 : return;
2671 : }
2672 0 : cx->clearPendingException();
2673 :
2674 0 : ErrorReport report(cx);
2675 0 : if (!report.init(cx, exn, js::ErrorReport::WithSideEffects)) {
2676 0 : fprintf(file, "out of memory initializing ErrorReport\n");
2677 0 : return;
2678 : }
2679 :
2680 0 : MOZ_ASSERT(!JSREPORT_IS_WARNING(report.report()->flags));
2681 0 : PrintError(cx, file, report.toStringResult(), report.report(), true);
2682 : }
2683 :
2684 : class MOZ_STACK_CLASS AutoSelfHostingErrorReporter
2685 : {
2686 : JSContext* cx_;
2687 : JS::WarningReporter oldReporter_;
2688 :
2689 : public:
2690 3 : explicit AutoSelfHostingErrorReporter(JSContext* cx)
2691 3 : : cx_(cx)
2692 : {
2693 3 : oldReporter_ = JS::SetWarningReporter(cx_, selfHosting_WarningReporter);
2694 3 : }
2695 6 : ~AutoSelfHostingErrorReporter() {
2696 3 : JS::SetWarningReporter(cx_, oldReporter_);
2697 :
2698 : // Exceptions in self-hosted code will usually be printed to stderr in
2699 : // ErrorToException, but not all exceptions are handled there. For
2700 : // instance, ReportOutOfMemory will throw the "out of memory" string
2701 : // without going through ErrorToException. We handle these other
2702 : // exceptions here.
2703 3 : MaybePrintAndClearPendingException(cx_, stderr);
2704 3 : }
2705 : };
2706 :
2707 : static bool
2708 3 : VerifyGlobalNames(JSContext* cx, Handle<GlobalObject*> shg)
2709 : {
2710 : #ifdef DEBUG
2711 6 : RootedId id(cx);
2712 3 : bool nameMissing = false;
2713 :
2714 2802 : for (auto iter = cx->zone()->cellIter<JSScript>();
2715 1401 : !iter.done() && !nameMissing;
2716 1398 : iter.next())
2717 : {
2718 1398 : JSScript* script = iter;
2719 1398 : jsbytecode* end = script->codeEnd();
2720 : jsbytecode* nextpc;
2721 127314 : for (jsbytecode* pc = script->code(); pc < end; pc = nextpc) {
2722 125916 : JSOp op = JSOp(*pc);
2723 125916 : nextpc = pc + GetBytecodeLength(pc);
2724 :
2725 125916 : if (op == JSOP_GETINTRINSIC) {
2726 9273 : PropertyName* name = script->getName(pc);
2727 9273 : id = NameToId(name);
2728 :
2729 9273 : if (!shg->lookupPure(id)) {
2730 : // cellIter disallows GCs, but error reporting wants to
2731 : // have them, so we need to move it out of the loop.
2732 0 : nameMissing = true;
2733 0 : break;
2734 : }
2735 : }
2736 : }
2737 : }
2738 :
2739 3 : if (nameMissing) {
2740 0 : RootedValue value(cx, IdToValue(id));
2741 0 : return ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_NO_SUCH_SELF_HOSTED_PROP,
2742 0 : JSDVG_IGNORE_STACK, value, nullptr, nullptr, nullptr);
2743 : }
2744 : #endif // DEBUG
2745 :
2746 3 : return true;
2747 : }
2748 :
2749 : bool
2750 4 : JSRuntime::initSelfHosting(JSContext* cx)
2751 : {
2752 4 : MOZ_ASSERT(!selfHostingGlobal_);
2753 :
2754 4 : if (cx->runtime()->parentRuntime) {
2755 1 : selfHostingGlobal_ = cx->runtime()->parentRuntime->selfHostingGlobal_;
2756 1 : return true;
2757 : }
2758 :
2759 : /*
2760 : * Self hosted state can be accessed from threads for other runtimes
2761 : * parented to this one, so cannot include state in the nursery.
2762 : */
2763 6 : JS::AutoDisableGenerationalGC disable(cx);
2764 :
2765 6 : Rooted<GlobalObject*> shg(cx, JSRuntime::createSelfHostingGlobal(cx));
2766 3 : if (!shg)
2767 0 : return false;
2768 :
2769 6 : JSAutoCompartment ac(cx, shg);
2770 :
2771 : /*
2772 : * Set a temporary error reporter printing to stderr because it is too
2773 : * early in the startup process for any other reporter to be registered
2774 : * and we don't want errors in self-hosted code to be silently swallowed.
2775 : *
2776 : * This class also overrides the warning reporter to print warnings to
2777 : * stderr. See selfHosting_WarningReporter.
2778 : */
2779 6 : AutoSelfHostingErrorReporter errorReporter(cx);
2780 :
2781 6 : CompileOptions options(cx);
2782 3 : FillSelfHostingCompileOptions(options);
2783 :
2784 6 : RootedValue rv(cx);
2785 :
2786 3 : uint32_t srcLen = GetRawScriptsSize();
2787 :
2788 3 : const unsigned char* compressed = compressedSources;
2789 3 : uint32_t compressedLen = GetCompressedSize();
2790 6 : ScopedJSFreePtr<char> src(selfHostingGlobal_->zone()->pod_malloc<char>(srcLen));
2791 6 : if (!src || !DecompressString(compressed, compressedLen,
2792 3 : reinterpret_cast<unsigned char*>(src.get()), srcLen))
2793 : {
2794 0 : return false;
2795 : }
2796 :
2797 3 : if (!Evaluate(cx, options, src, srcLen, &rv))
2798 0 : return false;
2799 :
2800 3 : if (!VerifyGlobalNames(cx, shg))
2801 0 : return false;
2802 :
2803 3 : return true;
2804 : }
2805 :
2806 : void
2807 0 : JSRuntime::finishSelfHosting()
2808 : {
2809 0 : selfHostingGlobal_ = nullptr;
2810 0 : }
2811 :
2812 : void
2813 22 : JSRuntime::traceSelfHostingGlobal(JSTracer* trc)
2814 : {
2815 22 : if (selfHostingGlobal_ && !parentRuntime)
2816 22 : TraceRoot(trc, const_cast<NativeObject**>(&selfHostingGlobal_.ref()), "self-hosting global");
2817 22 : }
2818 :
2819 : bool
2820 9634 : JSRuntime::isSelfHostingCompartment(JSCompartment* comp) const
2821 : {
2822 9634 : return selfHostingGlobal_->compartment() == comp;
2823 : }
2824 :
2825 : bool
2826 0 : JSRuntime::isSelfHostingZone(const JS::Zone* zone) const
2827 : {
2828 0 : return selfHostingGlobal_ && selfHostingGlobal_->zoneFromAnyThread() == zone;
2829 : }
2830 :
2831 : static bool
2832 : CloneValue(JSContext* cx, HandleValue selfHostedValue, MutableHandleValue vp);
2833 :
2834 : static bool
2835 22898 : GetUnclonedValue(JSContext* cx, HandleNativeObject selfHostedObject,
2836 : HandleId id, MutableHandleValue vp)
2837 : {
2838 22898 : vp.setUndefined();
2839 :
2840 22898 : if (JSID_IS_INT(id)) {
2841 0 : size_t index = JSID_TO_INT(id);
2842 0 : if (index < selfHostedObject->getDenseInitializedLength() &&
2843 0 : !selfHostedObject->getDenseElement(index).isMagic(JS_ELEMENTS_HOLE))
2844 : {
2845 0 : vp.set(selfHostedObject->getDenseElement(JSID_TO_INT(id)));
2846 0 : return true;
2847 : }
2848 : }
2849 :
2850 : // Since all atoms used by self-hosting are marked as permanent, the only
2851 : // reason we'd see a non-permanent atom here is code looking for
2852 : // properties on the self hosted global which aren't present.
2853 : // Since we ensure that that can't happen during startup, encountering
2854 : // non-permanent atoms here should be impossible.
2855 22898 : MOZ_ASSERT_IF(JSID_IS_STRING(id), JSID_TO_STRING(id)->isPermanentAtom());
2856 :
2857 45796 : RootedShape shape(cx, selfHostedObject->lookupPure(id));
2858 22898 : MOZ_ASSERT(shape);
2859 22898 : MOZ_ASSERT(shape->hasSlot() && shape->hasDefaultGetter());
2860 22898 : vp.set(selfHostedObject->getSlot(shape->slot()));
2861 22898 : return true;
2862 : }
2863 :
2864 : static bool
2865 2092 : CloneProperties(JSContext* cx, HandleNativeObject selfHostedObject, HandleObject clone)
2866 : {
2867 4184 : AutoIdVector ids(cx);
2868 4184 : Vector<uint8_t, 16> attrs(cx);
2869 :
2870 2092 : for (size_t i = 0; i < selfHostedObject->getDenseInitializedLength(); i++) {
2871 0 : if (!selfHostedObject->getDenseElement(i).isMagic(JS_ELEMENTS_HOLE)) {
2872 0 : if (!ids.append(INT_TO_JSID(i)))
2873 0 : return false;
2874 0 : if (!attrs.append(JSPROP_ENUMERATE))
2875 0 : return false;
2876 : }
2877 : }
2878 :
2879 4184 : Rooted<ShapeVector> shapes(cx, ShapeVector(cx));
2880 2118 : for (Shape::Range<NoGC> range(selfHostedObject->lastProperty()); !range.empty(); range.popFront()) {
2881 26 : Shape& shape = range.front();
2882 26 : if (shape.enumerable() && !shapes.append(&shape))
2883 0 : return false;
2884 : }
2885 :
2886 : // Now our shapes are in last-to-first order, so....
2887 2092 : Reverse(shapes.begin(), shapes.end());
2888 2118 : for (size_t i = 0; i < shapes.length(); ++i) {
2889 26 : MOZ_ASSERT(!shapes[i]->isAccessorShape(),
2890 : "Can't handle cloning accessors here yet.");
2891 26 : if (!ids.append(shapes[i]->propid()))
2892 0 : return false;
2893 : uint8_t shapeAttrs =
2894 26 : shapes[i]->attributes() & (JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY);
2895 26 : if (!attrs.append(shapeAttrs))
2896 0 : return false;
2897 : }
2898 :
2899 4184 : RootedId id(cx);
2900 4184 : RootedValue val(cx);
2901 4184 : RootedValue selfHostedValue(cx);
2902 2118 : for (uint32_t i = 0; i < ids.length(); i++) {
2903 26 : id = ids[i];
2904 26 : if (!GetUnclonedValue(cx, selfHostedObject, id, &selfHostedValue))
2905 0 : return false;
2906 130 : if (!CloneValue(cx, selfHostedValue, &val) ||
2907 104 : !JS_DefinePropertyById(cx, clone, id, val, attrs[i]))
2908 : {
2909 0 : return false;
2910 : }
2911 : }
2912 :
2913 2092 : return true;
2914 : }
2915 :
2916 : static JSString*
2917 0 : CloneString(JSContext* cx, JSFlatString* selfHostedString)
2918 : {
2919 0 : size_t len = selfHostedString->length();
2920 : {
2921 0 : JS::AutoCheckCannotGC nogc;
2922 : JSString* clone;
2923 0 : if (selfHostedString->hasLatin1Chars())
2924 0 : clone = NewStringCopyN<NoGC>(cx, selfHostedString->latin1Chars(nogc), len);
2925 : else
2926 0 : clone = NewStringCopyNDontDeflate<NoGC>(cx, selfHostedString->twoByteChars(nogc), len);
2927 0 : if (clone)
2928 0 : return clone;
2929 : }
2930 :
2931 0 : AutoStableStringChars chars(cx);
2932 0 : if (!chars.init(cx, selfHostedString))
2933 0 : return nullptr;
2934 :
2935 0 : return chars.isLatin1()
2936 0 : ? NewStringCopyN<CanGC>(cx, chars.latin1Range().begin().get(), len)
2937 0 : : NewStringCopyNDontDeflate<CanGC>(cx, chars.twoByteRange().begin().get(), len);
2938 : }
2939 :
2940 : static JSObject*
2941 2092 : CloneObject(JSContext* cx, HandleNativeObject selfHostedObject)
2942 : {
2943 : #ifdef DEBUG
2944 : // Object hash identities are owned by the hashed object, which may be on a
2945 : // different thread than the clone target. In theory, these objects are all
2946 : // tenured and will not be compacted; however, we simply avoid the issue
2947 : // altogether by skipping the cycle-detection when off thread.
2948 4184 : mozilla::Maybe<AutoCycleDetector> detect;
2949 2092 : if (js::CurrentThreadCanAccessZone(selfHostedObject->zoneFromAnyThread())) {
2950 2086 : detect.emplace(cx, selfHostedObject);
2951 2086 : if (!detect->init())
2952 0 : return nullptr;
2953 2086 : if (detect->foundCycle())
2954 0 : MOZ_CRASH("SelfHosted cloning cannot handle cyclic object graphs.");
2955 : }
2956 : #endif
2957 :
2958 4184 : RootedObject clone(cx);
2959 2092 : if (selfHostedObject->is<JSFunction>()) {
2960 4060 : RootedFunction selfHostedFunction(cx, &selfHostedObject->as<JSFunction>());
2961 2030 : bool hasName = selfHostedFunction->explicitName() != nullptr;
2962 :
2963 : // Arrow functions use the first extended slot for their lexical |this| value.
2964 2030 : MOZ_ASSERT(!selfHostedFunction->isArrow());
2965 : js::gc::AllocKind kind = hasName
2966 2030 : ? gc::AllocKind::FUNCTION_EXTENDED
2967 2030 : : selfHostedFunction->getAllocKind();
2968 2030 : MOZ_ASSERT(!CanReuseScriptForClone(cx->compartment(), selfHostedFunction, cx->global()));
2969 4060 : Rooted<LexicalEnvironmentObject*> globalLexical(cx, &cx->global()->lexicalEnvironment());
2970 4060 : RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
2971 4060 : clone = CloneFunctionAndScript(cx, selfHostedFunction, globalLexical, emptyGlobalScope,
2972 2030 : kind);
2973 : // To be able to re-lazify the cloned function, its name in the
2974 : // self-hosting compartment has to be stored on the clone.
2975 2030 : if (clone && hasName) {
2976 2030 : clone->as<JSFunction>().setExtendedSlot(LAZY_FUNCTION_NAME_SLOT,
2977 4060 : StringValue(selfHostedFunction->explicitName()));
2978 : }
2979 62 : } else if (selfHostedObject->is<RegExpObject>()) {
2980 0 : RegExpObject& reobj = selfHostedObject->as<RegExpObject>();
2981 0 : RootedAtom source(cx, reobj.getSource());
2982 0 : MOZ_ASSERT(source->isPermanentAtom());
2983 0 : clone = RegExpObject::create(cx, source, reobj.getFlags(),
2984 : nullptr, nullptr, cx->tempLifoAlloc(),
2985 0 : TenuredObject);
2986 62 : } else if (selfHostedObject->is<DateObject>()) {
2987 0 : clone = JS::NewDateObject(cx, selfHostedObject->as<DateObject>().clippedTime());
2988 62 : } else if (selfHostedObject->is<BooleanObject>()) {
2989 0 : clone = BooleanObject::create(cx, selfHostedObject->as<BooleanObject>().unbox());
2990 62 : } else if (selfHostedObject->is<NumberObject>()) {
2991 0 : clone = NumberObject::create(cx, selfHostedObject->as<NumberObject>().unbox());
2992 62 : } else if (selfHostedObject->is<StringObject>()) {
2993 0 : JSString* selfHostedString = selfHostedObject->as<StringObject>().unbox();
2994 0 : if (!selfHostedString->isFlat())
2995 0 : MOZ_CRASH();
2996 0 : RootedString str(cx, CloneString(cx, &selfHostedString->asFlat()));
2997 0 : if (!str)
2998 0 : return nullptr;
2999 0 : clone = StringObject::create(cx, str);
3000 62 : } else if (selfHostedObject->is<ArrayObject>()) {
3001 0 : clone = NewDenseEmptyArray(cx, nullptr, TenuredObject);
3002 : } else {
3003 62 : MOZ_ASSERT(selfHostedObject->isNative());
3004 124 : clone = NewObjectWithGivenProto(cx, selfHostedObject->getClass(), nullptr,
3005 62 : selfHostedObject->asTenured().getAllocKind(),
3006 62 : SingletonObject);
3007 : }
3008 2092 : if (!clone)
3009 0 : return nullptr;
3010 :
3011 2092 : if (!CloneProperties(cx, selfHostedObject, clone))
3012 0 : return nullptr;
3013 2092 : return clone;
3014 : }
3015 :
3016 : static bool
3017 2307 : CloneValue(JSContext* cx, HandleValue selfHostedValue, MutableHandleValue vp)
3018 : {
3019 2307 : if (selfHostedValue.isObject()) {
3020 4184 : RootedNativeObject selfHostedObject(cx, &selfHostedValue.toObject().as<NativeObject>());
3021 2092 : JSObject* clone = CloneObject(cx, selfHostedObject);
3022 2092 : if (!clone)
3023 0 : return false;
3024 2092 : vp.setObject(*clone);
3025 215 : } else if (selfHostedValue.isBoolean() || selfHostedValue.isNumber() || selfHostedValue.isNullOrUndefined()) {
3026 : // Nothing to do here: these are represented inline in the value.
3027 129 : vp.set(selfHostedValue);
3028 86 : } else if (selfHostedValue.isString()) {
3029 0 : if (!selfHostedValue.toString()->isFlat())
3030 0 : MOZ_CRASH();
3031 0 : JSFlatString* selfHostedString = &selfHostedValue.toString()->asFlat();
3032 0 : JSString* clone = CloneString(cx, selfHostedString);
3033 0 : if (!clone)
3034 0 : return false;
3035 0 : vp.setString(clone);
3036 86 : } else if (selfHostedValue.isSymbol()) {
3037 : // Well-known symbols are shared.
3038 172 : mozilla::DebugOnly<JS::Symbol*> sym = selfHostedValue.toSymbol();
3039 86 : MOZ_ASSERT(sym->isWellKnownSymbol());
3040 86 : MOZ_ASSERT(cx->wellKnownSymbols().get(size_t(sym->code())) == sym);
3041 86 : vp.set(selfHostedValue);
3042 : } else {
3043 0 : MOZ_CRASH("Self-hosting CloneValue can't clone given value.");
3044 : }
3045 2307 : return true;
3046 : }
3047 :
3048 : bool
3049 19856 : JSRuntime::createLazySelfHostedFunctionClone(JSContext* cx, HandlePropertyName selfHostedName,
3050 : HandleAtom name, unsigned nargs,
3051 : HandleObject proto, NewObjectKind newKind,
3052 : MutableHandleFunction fun)
3053 : {
3054 19856 : MOZ_ASSERT(newKind != GenericObject);
3055 :
3056 39712 : RootedAtom funName(cx, name);
3057 19856 : JSFunction* selfHostedFun = getUnclonedSelfHostedFunction(cx, selfHostedName);
3058 19856 : if (!selfHostedFun)
3059 0 : return false;
3060 :
3061 39709 : if (!selfHostedFun->isClassConstructor() && !selfHostedFun->hasGuessedAtom() &&
3062 19853 : selfHostedFun->explicitName() != selfHostedName)
3063 : {
3064 1151 : MOZ_ASSERT(selfHostedFun->getExtendedSlot(HAS_SELFHOSTED_CANONICAL_NAME_SLOT).toBoolean());
3065 1151 : funName = selfHostedFun->explicitName();
3066 : }
3067 :
3068 39712 : fun.set(NewScriptedFunction(cx, nargs, JSFunction::INTERPRETED_LAZY,
3069 19856 : funName, proto, gc::AllocKind::FUNCTION_EXTENDED, newKind));
3070 19856 : if (!fun)
3071 0 : return false;
3072 19856 : fun->setIsSelfHostedBuiltin();
3073 19856 : fun->setExtendedSlot(LAZY_FUNCTION_NAME_SLOT, StringValue(selfHostedName));
3074 19856 : return true;
3075 : }
3076 :
3077 : bool
3078 556 : JSRuntime::cloneSelfHostedFunctionScript(JSContext* cx, HandlePropertyName name,
3079 : HandleFunction targetFun)
3080 : {
3081 1112 : RootedFunction sourceFun(cx, getUnclonedSelfHostedFunction(cx, name));
3082 556 : if (!sourceFun)
3083 0 : return false;
3084 : // JSFunction::generatorKind can't handle lazy self-hosted functions, so we make sure there
3085 : // aren't any.
3086 556 : MOZ_ASSERT(!sourceFun->isStarGenerator() && !sourceFun->isLegacyGenerator() &&
3087 : !sourceFun->isAsync());
3088 556 : MOZ_ASSERT(targetFun->isExtended());
3089 556 : MOZ_ASSERT(targetFun->isInterpretedLazy());
3090 556 : MOZ_ASSERT(targetFun->isSelfHostedBuiltin());
3091 :
3092 1112 : RootedScript sourceScript(cx, JSFunction::getOrCreateScript(cx, sourceFun));
3093 556 : if (!sourceScript)
3094 0 : return false;
3095 :
3096 : // Assert that there are no intervening scopes between the global scope
3097 : // and the self-hosted script. Toplevel lexicals are explicitly forbidden
3098 : // by the parser when parsing self-hosted code. The fact they have the
3099 : // global lexical scope on the scope chain is for uniformity and engine
3100 : // invariants.
3101 556 : MOZ_ASSERT(sourceScript->outermostScope()->enclosing()->kind() == ScopeKind::Global);
3102 1112 : RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
3103 556 : if (!CloneScriptIntoFunction(cx, emptyGlobalScope, targetFun, sourceScript))
3104 0 : return false;
3105 556 : MOZ_ASSERT(!targetFun->isInterpretedLazy());
3106 :
3107 556 : MOZ_ASSERT(sourceFun->nargs() == targetFun->nargs());
3108 556 : MOZ_ASSERT(sourceScript->hasRest() == targetFun->nonLazyScript()->hasRest());
3109 :
3110 : // The target function might have been relazified after its flags changed.
3111 556 : targetFun->setFlags(targetFun->flags() | sourceFun->flags());
3112 556 : return true;
3113 : }
3114 :
3115 : bool
3116 22872 : JSRuntime::getUnclonedSelfHostedValue(JSContext* cx, HandlePropertyName name,
3117 : MutableHandleValue vp)
3118 : {
3119 45744 : RootedId id(cx, NameToId(name));
3120 45744 : return GetUnclonedValue(cx, HandleNativeObject::fromMarkedLocation(&selfHostingGlobal_.ref()), id, vp);
3121 : }
3122 :
3123 : JSFunction*
3124 20591 : JSRuntime::getUnclonedSelfHostedFunction(JSContext* cx, HandlePropertyName name)
3125 : {
3126 41182 : RootedValue selfHostedValue(cx);
3127 20591 : if (!getUnclonedSelfHostedValue(cx, name, &selfHostedValue))
3128 0 : return nullptr;
3129 :
3130 20591 : return &selfHostedValue.toObject().as<JSFunction>();
3131 : }
3132 :
3133 : bool
3134 2281 : JSRuntime::cloneSelfHostedValue(JSContext* cx, HandlePropertyName name, MutableHandleValue vp)
3135 : {
3136 4562 : RootedValue selfHostedValue(cx);
3137 2281 : if (!getUnclonedSelfHostedValue(cx, name, &selfHostedValue))
3138 0 : return false;
3139 :
3140 : /*
3141 : * We don't clone if we're operating in the self-hosting global, as that
3142 : * means we're currently executing the self-hosting script while
3143 : * initializing the runtime (see JSRuntime::initSelfHosting).
3144 : */
3145 2281 : if (cx->global() == selfHostingGlobal_) {
3146 0 : vp.set(selfHostedValue);
3147 0 : return true;
3148 : }
3149 :
3150 2281 : return CloneValue(cx, selfHostedValue, vp);
3151 : }
3152 :
3153 : void
3154 179 : JSRuntime::assertSelfHostedFunctionHasCanonicalName(JSContext* cx, HandlePropertyName name)
3155 : {
3156 : #ifdef DEBUG
3157 179 : JSFunction* selfHostedFun = getUnclonedSelfHostedFunction(cx, name);
3158 179 : MOZ_ASSERT(selfHostedFun);
3159 179 : MOZ_ASSERT(selfHostedFun->getExtendedSlot(HAS_SELFHOSTED_CANONICAL_NAME_SLOT).toBoolean());
3160 : #endif
3161 179 : }
3162 :
3163 : JSFunction*
3164 0 : js::SelfHostedFunction(JSContext* cx, HandlePropertyName propName)
3165 : {
3166 0 : RootedValue func(cx);
3167 0 : if (!GlobalObject::getIntrinsicValue(cx, cx->global(), propName, &func))
3168 0 : return nullptr;
3169 :
3170 0 : MOZ_ASSERT(func.isObject());
3171 0 : MOZ_ASSERT(func.toObject().is<JSFunction>());
3172 0 : return &func.toObject().as<JSFunction>();
3173 : }
3174 :
3175 : bool
3176 67 : js::IsSelfHostedFunctionWithName(JSFunction* fun, JSAtom* name)
3177 : {
3178 67 : return fun->isSelfHostedBuiltin() && GetSelfHostedFunctionName(fun) == name;
3179 : }
3180 :
3181 : JSAtom*
3182 67 : js::GetSelfHostedFunctionName(JSFunction* fun)
3183 : {
3184 67 : Value name = fun->getExtendedSlot(LAZY_FUNCTION_NAME_SLOT);
3185 67 : if (!name.isString())
3186 0 : return nullptr;
3187 67 : return &name.toString()->asAtom();
3188 : }
3189 :
3190 : static_assert(JSString::MAX_LENGTH <= INT32_MAX,
3191 : "StringIteratorNext in builtin/String.js assumes the stored index "
3192 : "into the string is an Int32Value");
|