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 "jit/VMFunctions.h"
8 :
9 : #include "builtin/TypedObject.h"
10 : #include "frontend/BytecodeCompiler.h"
11 : #include "jit/arm/Simulator-arm.h"
12 : #include "jit/BaselineIC.h"
13 : #include "jit/JitFrames.h"
14 : #include "jit/JitRealm.h"
15 : #include "jit/mips32/Simulator-mips32.h"
16 : #include "jit/mips64/Simulator-mips64.h"
17 : #include "vm/ArrayObject.h"
18 : #include "vm/Debugger.h"
19 : #include "vm/Interpreter.h"
20 : #include "vm/SelfHosting.h"
21 : #include "vm/TraceLogging.h"
22 :
23 : #include "jit/BaselineFrame-inl.h"
24 : #include "jit/JitFrames-inl.h"
25 : #include "vm/Debugger-inl.h"
26 : #include "vm/Interpreter-inl.h"
27 : #include "vm/NativeObject-inl.h"
28 : #include "vm/StringObject-inl.h"
29 : #include "vm/TypeInference-inl.h"
30 : #include "vm/UnboxedObject-inl.h"
31 :
32 : using namespace js;
33 : using namespace js::jit;
34 :
35 : namespace js {
36 : namespace jit {
37 :
38 : // Statics are initialized to null.
39 : /* static */ VMFunction* VMFunction::functions;
40 :
41 0 : AutoDetectInvalidation::AutoDetectInvalidation(JSContext* cx, MutableHandleValue rval)
42 : : cx_(cx),
43 0 : ionScript_(GetTopJitJSScript(cx)->ionScript()),
44 : rval_(rval),
45 0 : disabled_(false)
46 0 : { }
47 :
48 : bool
49 0 : InvokeFunction(JSContext* cx, HandleObject obj, bool constructing, bool ignoresReturnValue,
50 : uint32_t argc, Value* argv, MutableHandleValue rval)
51 : {
52 0 : TraceLoggerThread* logger = TraceLoggerForCurrentThread(cx);
53 0 : TraceLogStartEvent(logger, TraceLogger_Call);
54 :
55 0 : AutoArrayRooter argvRoot(cx, argc + 1 + constructing, argv);
56 :
57 : // Data in the argument vector is arranged for a JIT -> JIT call.
58 0 : RootedValue thisv(cx, argv[0]);
59 0 : Value* argvWithoutThis = argv + 1;
60 :
61 0 : RootedValue fval(cx, ObjectValue(*obj));
62 0 : if (constructing) {
63 0 : if (!IsConstructor(fval)) {
64 0 : ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_IGNORE_STACK, fval, nullptr);
65 0 : return false;
66 : }
67 :
68 0 : ConstructArgs cargs(cx);
69 0 : if (!cargs.init(cx, argc))
70 : return false;
71 :
72 0 : for (uint32_t i = 0; i < argc; i++)
73 0 : cargs[i].set(argvWithoutThis[i]);
74 :
75 0 : RootedValue newTarget(cx, argvWithoutThis[argc]);
76 :
77 : // If |this| hasn't been created, or is JS_UNINITIALIZED_LEXICAL,
78 : // we can use normal construction code without creating an extraneous
79 : // object.
80 0 : if (thisv.isMagic()) {
81 0 : MOZ_ASSERT(thisv.whyMagic() == JS_IS_CONSTRUCTING ||
82 : thisv.whyMagic() == JS_UNINITIALIZED_LEXICAL);
83 :
84 0 : RootedObject obj(cx);
85 0 : if (!Construct(cx, fval, cargs, newTarget, &obj))
86 : return false;
87 :
88 0 : rval.setObject(*obj);
89 0 : return true;
90 : }
91 :
92 : // Otherwise the default |this| has already been created. We could
93 : // almost perform a *call* at this point, but we'd break |new.target|
94 : // in the function. So in this one weird case we call a one-off
95 : // construction path that *won't* set |this| to JS_IS_CONSTRUCTING.
96 0 : return InternalConstructWithProvidedThis(cx, fval, thisv, cargs, newTarget, rval);
97 : }
98 :
99 0 : InvokeArgsMaybeIgnoresReturnValue args(cx, ignoresReturnValue);
100 0 : if (!args.init(cx, argc))
101 : return false;
102 :
103 0 : for (size_t i = 0; i < argc; i++)
104 0 : args[i].set(argvWithoutThis[i]);
105 :
106 0 : return Call(cx, fval, thisv, args, rval);
107 : }
108 :
109 : bool
110 0 : InvokeFunctionShuffleNewTarget(JSContext* cx, HandleObject obj, uint32_t numActualArgs,
111 : uint32_t numFormalArgs, Value* argv, MutableHandleValue rval)
112 : {
113 0 : MOZ_ASSERT(numFormalArgs > numActualArgs);
114 0 : argv[1 + numActualArgs] = argv[1 + numFormalArgs];
115 0 : return InvokeFunction(cx, obj, true, false, numActualArgs, argv, rval);
116 : }
117 :
118 : bool
119 0 : InvokeFromInterpreterStub(JSContext* cx, InterpreterStubExitFrameLayout* frame)
120 : {
121 0 : JitFrameLayout* jsFrame = frame->jsFrame();
122 0 : CalleeToken token = jsFrame->calleeToken();
123 :
124 0 : Value* argv = jsFrame->argv();
125 0 : uint32_t numActualArgs = jsFrame->numActualArgs();
126 0 : bool constructing = CalleeTokenIsConstructing(token);
127 0 : RootedFunction fun(cx, CalleeTokenToFunction(token));
128 :
129 : // Ensure new.target immediately follows the actual arguments (the arguments
130 : // rectifier added padding). See also InvokeFunctionShuffleNewTarget.
131 0 : if (constructing && numActualArgs < fun->nargs())
132 0 : argv[1 + numActualArgs] = argv[1 + fun->nargs()];
133 :
134 0 : RootedValue rval(cx);
135 0 : if (!InvokeFunction(cx, fun, constructing,
136 : /* ignoresReturnValue = */ false,
137 : numActualArgs, argv, &rval))
138 : {
139 : return false;
140 : }
141 :
142 : // Overwrite |this| with the return value.
143 0 : argv[0] = rval;
144 0 : return true;
145 : }
146 :
147 : #ifdef JS_SIMULATOR
148 : static bool
149 : CheckSimulatorRecursionLimitWithExtra(JSContext* cx, uint32_t extra)
150 : {
151 : if (cx->simulator()->overRecursedWithExtra(extra)) {
152 : ReportOverRecursed(cx);
153 : return false;
154 : }
155 : return true;
156 : }
157 : #endif
158 :
159 : bool
160 0 : CheckOverRecursed(JSContext* cx)
161 : {
162 : // We just failed the jitStackLimit check. There are two possible reasons:
163 : // - jitStackLimit was the real stack limit and we're over-recursed
164 : // - jitStackLimit was set to UINTPTR_MAX by JSRuntime::requestInterrupt
165 : // and we need to call JSRuntime::handleInterrupt.
166 : #ifdef JS_SIMULATOR
167 : if (!CheckSimulatorRecursionLimitWithExtra(cx, 0))
168 : return false;
169 : #else
170 0 : if (!CheckRecursionLimit(cx))
171 : return false;
172 : #endif
173 0 : gc::MaybeVerifyBarriers(cx);
174 0 : return cx->handleInterrupt();
175 : }
176 :
177 : // This function can get called in two contexts. In the usual context, it's
178 : // called with earlyCheck=false, after the env chain has been initialized on
179 : // a baseline frame. In this case, it's ok to throw an exception, so a failed
180 : // stack check returns false, and a successful stack check promps a check for
181 : // an interrupt from the runtime, which may also cause a false return.
182 : //
183 : // In the second case, it's called with earlyCheck=true, prior to frame
184 : // initialization. An exception cannot be thrown in this instance, so instead
185 : // an error flag is set on the frame and true returned.
186 : bool
187 0 : CheckOverRecursedWithExtra(JSContext* cx, BaselineFrame* frame,
188 : uint32_t extra, uint32_t earlyCheck)
189 : {
190 0 : MOZ_ASSERT_IF(earlyCheck, !frame->overRecursed());
191 :
192 : // See |CheckOverRecursed| above. This is a variant of that function which
193 : // accepts an argument holding the extra stack space needed for the Baseline
194 : // frame that's about to be pushed.
195 : uint8_t spDummy;
196 0 : uint8_t* checkSp = (&spDummy) - extra;
197 0 : if (earlyCheck) {
198 : #ifdef JS_SIMULATOR
199 : (void)checkSp;
200 : if (!CheckSimulatorRecursionLimitWithExtra(cx, extra))
201 : frame->setOverRecursed();
202 : #else
203 0 : if (!CheckRecursionLimitWithStackPointer(cx, checkSp))
204 0 : frame->setOverRecursed();
205 : #endif
206 : return true;
207 : }
208 :
209 : // The OVERRECURSED flag may have already been set on the frame by an
210 : // early over-recursed check. If so, throw immediately.
211 0 : if (frame->overRecursed())
212 : return false;
213 :
214 : #ifdef JS_SIMULATOR
215 : if (!CheckSimulatorRecursionLimitWithExtra(cx, extra))
216 : return false;
217 : #else
218 0 : if (!CheckRecursionLimitWithStackPointer(cx, checkSp))
219 : return false;
220 : #endif
221 :
222 0 : gc::MaybeVerifyBarriers(cx);
223 0 : return cx->handleInterrupt();
224 : }
225 :
226 : JSObject*
227 0 : BindVar(JSContext* cx, HandleObject envChain)
228 : {
229 0 : JSObject* obj = envChain;
230 0 : while (!obj->isQualifiedVarObj())
231 0 : obj = obj->enclosingEnvironment();
232 0 : MOZ_ASSERT(obj);
233 0 : return obj;
234 : }
235 :
236 : bool
237 0 : DefVar(JSContext* cx, HandlePropertyName dn, unsigned attrs, HandleObject envChain)
238 : {
239 : // Given the ScopeChain, extract the VarObj.
240 0 : RootedObject obj(cx, BindVar(cx, envChain));
241 0 : return DefVarOperation(cx, obj, dn, attrs);
242 : }
243 :
244 : bool
245 0 : DefLexical(JSContext* cx, HandlePropertyName dn, unsigned attrs, HandleObject envChain)
246 : {
247 : // Find the extensible lexical scope.
248 : Rooted<LexicalEnvironmentObject*> lexicalEnv(cx,
249 0 : &NearestEnclosingExtensibleLexicalEnvironment(envChain));
250 :
251 : // Find the variables object.
252 0 : RootedObject varObj(cx, BindVar(cx, envChain));
253 0 : return DefLexicalOperation(cx, lexicalEnv, varObj, dn, attrs);
254 : }
255 :
256 : bool
257 0 : DefGlobalLexical(JSContext* cx, HandlePropertyName dn, unsigned attrs)
258 : {
259 0 : Rooted<LexicalEnvironmentObject*> globalLexical(cx, &cx->global()->lexicalEnvironment());
260 0 : return DefLexicalOperation(cx, globalLexical, cx->global(), dn, attrs);
261 : }
262 :
263 : bool
264 0 : MutatePrototype(JSContext* cx, HandlePlainObject obj, HandleValue value)
265 : {
266 0 : if (!value.isObjectOrNull())
267 : return true;
268 :
269 0 : RootedObject newProto(cx, value.toObjectOrNull());
270 0 : return SetPrototype(cx, obj, newProto);
271 : }
272 :
273 : template<bool Equal>
274 : bool
275 0 : LooselyEqual(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res)
276 : {
277 0 : if (!js::LooselyEqual(cx, lhs, rhs, res))
278 : return false;
279 : if (!Equal)
280 0 : *res = !*res;
281 0 : return true;
282 : }
283 :
284 : template bool LooselyEqual<true>(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res);
285 : template bool LooselyEqual<false>(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res);
286 :
287 : template<bool Equal>
288 : bool
289 0 : StrictlyEqual(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res)
290 : {
291 0 : if (!js::StrictlyEqual(cx, lhs, rhs, res))
292 : return false;
293 : if (!Equal)
294 0 : *res = !*res;
295 0 : return true;
296 : }
297 :
298 : template bool StrictlyEqual<true>(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res);
299 : template bool StrictlyEqual<false>(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res);
300 :
301 : bool
302 0 : LessThan(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res)
303 : {
304 0 : return LessThanOperation(cx, lhs, rhs, res);
305 : }
306 :
307 : bool
308 0 : LessThanOrEqual(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res)
309 : {
310 0 : return LessThanOrEqualOperation(cx, lhs, rhs, res);
311 : }
312 :
313 : bool
314 0 : GreaterThan(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res)
315 : {
316 0 : return GreaterThanOperation(cx, lhs, rhs, res);
317 : }
318 :
319 : bool
320 0 : GreaterThanOrEqual(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res)
321 : {
322 0 : return GreaterThanOrEqualOperation(cx, lhs, rhs, res);
323 : }
324 :
325 : template<bool Equal>
326 : bool
327 0 : StringsEqual(JSContext* cx, HandleString lhs, HandleString rhs, bool* res)
328 : {
329 0 : if (!js::EqualStrings(cx, lhs, rhs, res))
330 : return false;
331 : if (!Equal)
332 0 : *res = !*res;
333 0 : return true;
334 : }
335 :
336 : template bool StringsEqual<true>(JSContext* cx, HandleString lhs, HandleString rhs, bool* res);
337 : template bool StringsEqual<false>(JSContext* cx, HandleString lhs, HandleString rhs, bool* res);
338 :
339 : typedef bool (*StringCompareFn)(JSContext*, HandleString, HandleString, bool*);
340 1 : const VMFunction StringsEqualInfo =
341 3 : FunctionInfo<StringCompareFn>(jit::StringsEqual<true>, "StringsEqual");
342 1 : const VMFunction StringsNotEqualInfo =
343 0 : FunctionInfo<StringCompareFn>(jit::StringsEqual<false>, "StringsEqual");
344 :
345 201 : bool StringSplitHelper(JSContext* cx, HandleString str, HandleString sep,
346 : HandleObjectGroup group, uint32_t limit,
347 : MutableHandleValue result)
348 : {
349 201 : JSObject* resultObj = str_split_string(cx, group, str, sep, limit);
350 201 : if (!resultObj)
351 : return false;
352 :
353 0 : result.setObject(*resultObj);
354 201 : return true;
355 : }
356 :
357 :
358 : bool
359 0 : ArrayPopDense(JSContext* cx, HandleObject obj, MutableHandleValue rval)
360 : {
361 0 : MOZ_ASSERT(obj->is<ArrayObject>());
362 :
363 0 : AutoDetectInvalidation adi(cx, rval);
364 :
365 0 : JS::AutoValueArray<2> argv(cx);
366 0 : argv[0].setUndefined();
367 0 : argv[1].setObject(*obj);
368 0 : if (!js::array_pop(cx, 0, argv.begin()))
369 : return false;
370 :
371 : // If the result is |undefined|, the array was probably empty and we
372 : // have to monitor the return value.
373 0 : rval.set(argv[0]);
374 0 : if (rval.isUndefined())
375 0 : TypeScript::Monitor(cx, rval);
376 : return true;
377 : }
378 :
379 : bool
380 0 : ArrayPushDense(JSContext* cx, HandleArrayObject arr, HandleValue v, uint32_t* length)
381 : {
382 6 : *length = arr->length();
383 6 : DenseElementResult result = arr->setOrExtendDenseElements(cx, *length, v.address(), 1,
384 3 : ShouldUpdateTypes::DontUpdate);
385 3 : if (result != DenseElementResult::Incomplete) {
386 3 : (*length)++;
387 3 : return result == DenseElementResult::Success;
388 : }
389 :
390 : // AutoDetectInvalidation uses GetTopJitJSScript(cx)->ionScript(), but it's
391 : // possible the setOrExtendDenseElements call already invalidated the
392 : // IonScript. JSJitFrameIter::ionScript works when the script is invalidated
393 : // so we use that instead.
394 0 : JSJitFrameIter frame(cx->activation()->asJit());
395 0 : MOZ_ASSERT(frame.type() == JitFrame_Exit);
396 0 : ++frame;
397 0 : IonScript* ionScript = frame.ionScript();
398 :
399 0 : JS::AutoValueArray<3> argv(cx);
400 0 : AutoDetectInvalidation adi(cx, argv[0], ionScript);
401 0 : argv[0].setUndefined();
402 0 : argv[1].setObject(*arr);
403 0 : argv[2].set(v);
404 0 : if (!js::array_push(cx, 1, argv.begin()))
405 : return false;
406 :
407 0 : if (argv[0].isInt32()) {
408 0 : *length = argv[0].toInt32();
409 0 : return true;
410 : }
411 :
412 : // array_push changed the length to be larger than INT32_MAX. In this case
413 : // OBJECT_FLAG_LENGTH_OVERFLOW was set, TI invalidated the script, and the
414 : // AutoDetectInvalidation instance on the stack will replace *length with
415 : // the actual return value during bailout.
416 0 : MOZ_ASSERT(adi.shouldSetReturnOverride());
417 0 : MOZ_ASSERT(argv[0].toDouble() == double(INT32_MAX) + 1);
418 0 : *length = 0;
419 0 : return true;
420 : }
421 :
422 : bool
423 0 : ArrayShiftDense(JSContext* cx, HandleObject obj, MutableHandleValue rval)
424 : {
425 0 : MOZ_ASSERT(obj->is<ArrayObject>());
426 :
427 0 : AutoDetectInvalidation adi(cx, rval);
428 :
429 0 : JS::AutoValueArray<2> argv(cx);
430 0 : argv[0].setUndefined();
431 0 : argv[1].setObject(*obj);
432 0 : if (!js::array_shift(cx, 0, argv.begin()))
433 : return false;
434 :
435 : // If the result is |undefined|, the array was probably empty and we
436 : // have to monitor the return value.
437 0 : rval.set(argv[0]);
438 0 : if (rval.isUndefined())
439 0 : TypeScript::Monitor(cx, rval);
440 : return true;
441 : }
442 :
443 : JSString*
444 0 : ArrayJoin(JSContext* cx, HandleObject array, HandleString sep)
445 : {
446 0 : JS::AutoValueArray<3> argv(cx);
447 0 : argv[0].setUndefined();
448 0 : argv[1].setObject(*array);
449 0 : argv[2].setString(sep);
450 0 : if (!js::array_join(cx, 1, argv.begin()))
451 : return nullptr;
452 0 : return argv[0].toString();
453 : }
454 :
455 : bool
456 235 : SetArrayLength(JSContext* cx, HandleObject obj, HandleValue value, bool strict)
457 : {
458 235 : Handle<ArrayObject*> array = obj.as<ArrayObject>();
459 :
460 1175 : RootedId id(cx, NameToId(cx->names().length));
461 235 : ObjectOpResult result;
462 :
463 : // SetArrayLength is called by IC stubs for SetProp and SetElem on arrays'
464 : // "length" property.
465 : //
466 : // ArraySetLength below coerces |value| before checking for length being
467 : // writable, and in the case of illegal values, will throw RangeError even
468 : // when "length" is not writable. This is incorrect observable behavior,
469 : // as a regular [[Set]] operation will check for "length" being
470 : // writable before attempting any assignment.
471 : //
472 : // So, perform ArraySetLength if and only if "length" is writable.
473 470 : if (array->lengthIsWritable()) {
474 0 : if (!ArraySetLength(cx, array, id, JSPROP_PERMANENT, value, result))
475 : return false;
476 : } else {
477 0 : MOZ_ALWAYS_TRUE(result.fail(JSMSG_READ_ONLY));
478 : }
479 :
480 470 : return result.checkStrictErrorOrWarning(cx, obj, id, strict);
481 : }
482 :
483 : bool
484 0 : CharCodeAt(JSContext* cx, HandleString str, int32_t index, uint32_t* code)
485 : {
486 : char16_t c;
487 0 : if (!str->getChar(cx, index, &c))
488 : return false;
489 0 : *code = c;
490 0 : return true;
491 : }
492 :
493 : JSFlatString*
494 0 : StringFromCharCode(JSContext* cx, int32_t code)
495 : {
496 0 : char16_t c = char16_t(code);
497 :
498 0 : if (StaticStrings::hasUnit(c))
499 0 : return cx->staticStrings().getUnit(c);
500 :
501 0 : return NewStringCopyNDontDeflate<CanGC>(cx, &c, 1);
502 : }
503 :
504 : JSString*
505 0 : StringFromCodePoint(JSContext* cx, int32_t codePoint)
506 : {
507 0 : RootedValue rval(cx, Int32Value(codePoint));
508 0 : if (!str_fromCodePoint_one_arg(cx, rval, &rval))
509 : return nullptr;
510 :
511 0 : return rval.toString();
512 : }
513 :
514 : bool
515 6 : SetProperty(JSContext* cx, HandleObject obj, HandlePropertyName name, HandleValue value,
516 : bool strict, jsbytecode* pc)
517 : {
518 18 : RootedId id(cx, NameToId(name));
519 :
520 0 : JSOp op = JSOp(*pc);
521 :
522 0 : if (op == JSOP_SETALIASEDVAR || op == JSOP_INITALIASEDLEXICAL) {
523 : // Aliased var assigns ignore readonly attributes on the property, as
524 : // required for initializing 'const' closure variables.
525 0 : Shape* shape = obj->as<NativeObject>().lookup(cx, name);
526 0 : MOZ_ASSERT(shape && shape->isDataProperty());
527 0 : obj->as<NativeObject>().setSlotWithType(cx, shape, value);
528 0 : return true;
529 : }
530 :
531 0 : RootedValue receiver(cx, ObjectValue(*obj));
532 6 : ObjectOpResult result;
533 12 : if (MOZ_LIKELY(!obj->getOpsSetProperty())) {
534 6 : if (op == JSOP_SETNAME || op == JSOP_STRICTSETNAME ||
535 6 : op == JSOP_SETGNAME || op == JSOP_STRICTSETGNAME)
536 : {
537 0 : if (!NativeSetProperty<Unqualified>(cx, obj.as<NativeObject>(), id, value, receiver,
538 : result))
539 : {
540 : return false;
541 : }
542 : } else {
543 12 : if (!NativeSetProperty<Qualified>(cx, obj.as<NativeObject>(), id, value, receiver,
544 : result))
545 : {
546 : return false;
547 : }
548 : }
549 : } else {
550 0 : if (!SetProperty(cx, obj, id, value, receiver, result))
551 : return false;
552 : }
553 0 : return result.checkStrictErrorOrWarning(cx, obj, id, strict);
554 : }
555 :
556 : bool
557 15 : InterruptCheck(JSContext* cx)
558 : {
559 0 : gc::MaybeVerifyBarriers(cx);
560 :
561 0 : return CheckForInterrupt(cx);
562 : }
563 :
564 : void*
565 0 : MallocWrapper(JS::Zone* zone, size_t nbytes)
566 : {
567 0 : AutoUnsafeCallWithABI unsafe;
568 0 : return zone->pod_malloc<uint8_t>(nbytes);
569 : }
570 :
571 : JSObject*
572 3 : NewCallObject(JSContext* cx, HandleShape shape, HandleObjectGroup group)
573 : {
574 3 : JSObject* obj = CallObject::create(cx, shape, group);
575 0 : if (!obj)
576 : return nullptr;
577 :
578 : // The JIT creates call objects in the nursery, so elides barriers for
579 : // the initializing writes. The interpreter, however, may have allocated
580 : // the call object tenured, so barrier as needed before re-entering.
581 3 : if (!IsInsideNursery(obj))
582 0 : cx->runtime()->gc.storeBuffer().putWholeCell(obj);
583 :
584 : return obj;
585 : }
586 :
587 : JSObject*
588 0 : NewSingletonCallObject(JSContext* cx, HandleShape shape)
589 : {
590 0 : JSObject* obj = CallObject::createSingleton(cx, shape);
591 0 : if (!obj)
592 : return nullptr;
593 :
594 : // The JIT creates call objects in the nursery, so elides barriers for
595 : // the initializing writes. The interpreter, however, may have allocated
596 : // the call object tenured, so barrier as needed before re-entering.
597 0 : MOZ_ASSERT(!IsInsideNursery(obj),
598 : "singletons are created in the tenured heap");
599 0 : cx->runtime()->gc.storeBuffer().putWholeCell(obj);
600 :
601 0 : return obj;
602 : }
603 :
604 : JSObject*
605 0 : NewStringObject(JSContext* cx, HandleString str)
606 : {
607 0 : return StringObject::create(cx, str);
608 : }
609 :
610 : bool
611 560 : OperatorIn(JSContext* cx, HandleValue key, HandleObject obj, bool* out)
612 : {
613 0 : RootedId id(cx);
614 1680 : return ToPropertyKey(cx, key, &id) &&
615 0 : HasProperty(cx, obj, id, out);
616 : }
617 :
618 : bool
619 0 : OperatorInI(JSContext* cx, uint32_t index, HandleObject obj, bool* out)
620 : {
621 0 : RootedValue key(cx, Int32Value(index));
622 0 : return OperatorIn(cx, key, obj, out);
623 : }
624 :
625 : bool
626 0 : GetIntrinsicValue(JSContext* cx, HandlePropertyName name, MutableHandleValue rval)
627 : {
628 0 : if (!GlobalObject::getIntrinsicValue(cx, cx->global(), name, rval))
629 : return false;
630 :
631 : // This function is called when we try to compile a cold getintrinsic
632 : // op. MCallGetIntrinsicValue has an AliasSet of None for optimization
633 : // purposes, as its side effect is not observable from JS. We are
634 : // guaranteed to bail out after this function, but because of its AliasSet,
635 : // type info will not be reflowed. Manually monitor here.
636 0 : TypeScript::Monitor(cx, rval);
637 :
638 0 : return true;
639 : }
640 :
641 : bool
642 0 : CreateThis(JSContext* cx, HandleObject callee, HandleObject newTarget, MutableHandleValue rval)
643 : {
644 0 : rval.set(MagicValue(JS_IS_CONSTRUCTING));
645 :
646 0 : if (callee->is<JSFunction>()) {
647 0 : RootedFunction fun(cx, &callee->as<JSFunction>());
648 9828 : if (fun->isInterpreted() && fun->isConstructor()) {
649 2457 : JSScript* script = JSFunction::getOrCreateScript(cx, fun);
650 4914 : AutoKeepTypeScripts keepTypes(cx);
651 2457 : if (!script || !script->ensureHasTypes(cx, keepTypes))
652 0 : return false;
653 2457 : if (!js::CreateThis(cx, fun, script, newTarget, GenericObject, rval))
654 : return false;
655 : }
656 : }
657 :
658 : return true;
659 : }
660 :
661 : void
662 0 : GetDynamicName(JSContext* cx, JSObject* envChain, JSString* str, Value* vp)
663 : {
664 : // Lookup a string on the env chain, returning either the value found or
665 : // undefined through rval. This function is infallible, and cannot GC or
666 : // invalidate.
667 :
668 0 : AutoUnsafeCallWithABI unsafe;
669 :
670 : JSAtom* atom;
671 0 : if (str->isAtom()) {
672 0 : atom = &str->asAtom();
673 : } else {
674 0 : atom = AtomizeString(cx, str);
675 0 : if (!atom) {
676 : vp->setUndefined();
677 0 : return;
678 : }
679 : }
680 :
681 0 : if (!frontend::IsIdentifier(atom) || frontend::IsKeyword(atom)) {
682 : vp->setUndefined();
683 : return;
684 : }
685 :
686 0 : PropertyResult prop;
687 0 : JSObject* scope = nullptr;
688 0 : JSObject* pobj = nullptr;
689 0 : if (LookupNameNoGC(cx, atom->asPropertyName(), envChain, &scope, &pobj, &prop)) {
690 0 : if (FetchNameNoGC(pobj, prop, MutableHandleValue::fromMarkedLocation(vp)))
691 : return;
692 : }
693 :
694 0 : vp->setUndefined();
695 : }
696 :
697 : void
698 1681 : PostWriteBarrier(JSRuntime* rt, js::gc::Cell* cell)
699 : {
700 3362 : AutoUnsafeCallWithABI unsafe;
701 1681 : MOZ_ASSERT(!IsInsideNursery(cell));
702 5043 : rt->gc.storeBuffer().putWholeCell(cell);
703 0 : }
704 :
705 : static const size_t MAX_WHOLE_CELL_BUFFER_SIZE = 4096;
706 :
707 : template <IndexInBounds InBounds>
708 : void
709 121 : PostWriteElementBarrier(JSRuntime* rt, JSObject* obj, int32_t index)
710 : {
711 127 : AutoUnsafeCallWithABI unsafe;
712 :
713 121 : MOZ_ASSERT(!IsInsideNursery(obj));
714 :
715 : if (InBounds == IndexInBounds::Yes) {
716 1 : MOZ_ASSERT(uint32_t(index) < obj->as<NativeObject>().getDenseInitializedLength());
717 : } else {
718 80 : if (MOZ_UNLIKELY(!obj->is<NativeObject>() ||
719 : index < 0 ||
720 : uint32_t(index) >= NativeObject::MAX_DENSE_ELEMENTS_COUNT))
721 : {
722 0 : rt->gc.storeBuffer().putWholeCell(obj);
723 115 : return;
724 : }
725 : }
726 :
727 0 : NativeObject* nobj = &obj->as<NativeObject>();
728 121 : if (nobj->isInWholeCellBuffer())
729 : return;
730 :
731 0 : if (nobj->getDenseInitializedLength() > MAX_WHOLE_CELL_BUFFER_SIZE
732 : #ifdef JS_GC_ZEAL
733 12 : || rt->hasZealMode(gc::ZealMode::ElementsBarrier)
734 : #endif
735 : )
736 : {
737 0 : rt->gc.storeBuffer().putSlot(nobj, HeapSlot::Element,
738 : nobj->unshiftedIndex(index),
739 : 1);
740 0 : return;
741 : }
742 :
743 18 : rt->gc.storeBuffer().putWholeCell(obj);
744 : }
745 :
746 : template void
747 : PostWriteElementBarrier<IndexInBounds::Yes>(JSRuntime* rt, JSObject* obj, int32_t index);
748 :
749 : template void
750 : PostWriteElementBarrier<IndexInBounds::Maybe>(JSRuntime* rt, JSObject* obj, int32_t index);
751 :
752 : void
753 0 : PostGlobalWriteBarrier(JSRuntime* rt, JSObject* obj)
754 : {
755 0 : MOZ_ASSERT(obj->is<GlobalObject>());
756 0 : if (!obj->realm()->globalWriteBarriered) {
757 0 : PostWriteBarrier(rt, obj);
758 0 : obj->realm()->globalWriteBarriered = 1;
759 : }
760 0 : }
761 :
762 : int32_t
763 2 : GetIndexFromString(JSString* str)
764 : {
765 : // We shouldn't GC here as this is called directly from IC code.
766 0 : AutoUnsafeCallWithABI unsafe;
767 :
768 2 : if (!str->isFlat())
769 : return -1;
770 :
771 : uint32_t index;
772 2 : if (!str->asFlat().isIndex(&index) || index > INT32_MAX)
773 : return -1;
774 :
775 2 : return int32_t(index);
776 : }
777 :
778 : JSObject*
779 0 : WrapObjectPure(JSContext* cx, JSObject* obj)
780 : {
781 : // IC code calls this directly so we shouldn't GC.
782 17888 : AutoUnsafeCallWithABI unsafe;
783 :
784 8944 : MOZ_ASSERT(obj);
785 17888 : MOZ_ASSERT(cx->compartment() != obj->compartment());
786 :
787 : // From: Compartment::getNonWrapperObjectForCurrentCompartment
788 : // Note that if the object is same-compartment, but has been wrapped into a
789 : // different compartment, we need to unwrap it and return the bare same-
790 : // compartment object. Note again that windows are always wrapped by a
791 : // WindowProxy even when same-compartment so take care not to strip this
792 : // particular wrapper.
793 8944 : obj = UncheckedUnwrap(obj, /* stopAtWindowProxy = */ true);
794 17888 : if (cx->compartment() == obj->compartment()) {
795 10 : MOZ_ASSERT(!IsWindow(obj));
796 0 : JS::ExposeObjectToActiveJS(obj);
797 0 : return obj;
798 : }
799 :
800 : // Try to Lookup an existing wrapper for this object. We assume that
801 : // if we can find such a wrapper, not calling preWrap is correct.
802 17878 : if (WrapperMap::Ptr p = cx->compartment()->lookupWrapper(obj)) {
803 17814 : JSObject* wrapped = &p->value().get().toObject();
804 :
805 : // Ensure the wrapper is still exposed.
806 8907 : JS::ExposeObjectToActiveJS(wrapped);
807 8907 : return wrapped;
808 : }
809 :
810 0 : return nullptr;
811 : }
812 :
813 : bool
814 0 : DebugPrologue(JSContext* cx, BaselineFrame* frame, jsbytecode* pc, bool* mustReturn)
815 : {
816 0 : *mustReturn = false;
817 :
818 0 : switch (Debugger::onEnterFrame(cx, frame)) {
819 : case ResumeMode::Continue:
820 : return true;
821 :
822 : case ResumeMode::Return:
823 : // The script is going to return immediately, so we have to call the
824 : // debug epilogue handler as well.
825 0 : MOZ_ASSERT(frame->hasReturnValue());
826 0 : *mustReturn = true;
827 0 : return jit::DebugEpilogue(cx, frame, pc, true);
828 :
829 : case ResumeMode::Throw:
830 : case ResumeMode::Terminate:
831 0 : return false;
832 :
833 : default:
834 0 : MOZ_CRASH("bad Debugger::onEnterFrame resume mode");
835 : }
836 : }
837 :
838 : bool
839 0 : DebugEpilogueOnBaselineReturn(JSContext* cx, BaselineFrame* frame, jsbytecode* pc)
840 : {
841 0 : if (!DebugEpilogue(cx, frame, pc, true)) {
842 : // DebugEpilogue popped the frame by updating packedExitFP, so run the
843 : // stop event here before we enter the exception handler.
844 0 : TraceLoggerThread* logger = TraceLoggerForCurrentThread(cx);
845 0 : TraceLogStopEvent(logger, TraceLogger_Baseline);
846 : TraceLogStopEvent(logger, TraceLogger_Scripts);
847 : return false;
848 : }
849 :
850 : return true;
851 : }
852 :
853 : bool
854 40 : DebugEpilogue(JSContext* cx, BaselineFrame* frame, jsbytecode* pc, bool ok)
855 : {
856 : // If Debugger::onLeaveFrame returns |true| we have to return the frame's
857 : // return value. If it returns |false|, the debugger threw an exception.
858 : // In both cases we have to pop debug scopes.
859 0 : ok = Debugger::onLeaveFrame(cx, frame, pc, ok);
860 :
861 : // Unwind to the outermost environment and set pc to the end of the
862 : // script, regardless of error.
863 80 : EnvironmentIter ei(cx, frame, pc);
864 40 : UnwindAllEnvironmentsInFrame(cx, ei);
865 0 : JSScript* script = frame->script();
866 0 : frame->setOverridePc(script->lastPC());
867 :
868 40 : if (!ok) {
869 : // Pop this frame by updating packedExitFP, so that the exception
870 : // handling code will start at the previous frame.
871 40 : JitFrameLayout* prefix = frame->framePrefix();
872 40 : EnsureBareExitFrame(cx->activation()->asJit(), prefix);
873 0 : return false;
874 : }
875 :
876 : // Clear the override pc. This is not necessary for correctness: the frame
877 : // will return immediately, but this simplifies the check we emit in debug
878 : // builds after each callVM, to ensure this flag is not set.
879 0 : frame->clearOverridePc();
880 0 : return true;
881 : }
882 :
883 : void
884 0 : FrameIsDebuggeeCheck(BaselineFrame* frame)
885 : {
886 0 : AutoUnsafeCallWithABI unsafe;
887 0 : if (frame->script()->isDebuggee())
888 0 : frame->setIsDebuggee();
889 0 : }
890 :
891 : JSObject*
892 0 : CreateGenerator(JSContext* cx, BaselineFrame* frame)
893 : {
894 456 : return GeneratorObject::create(cx, frame);
895 : }
896 :
897 : bool
898 0 : NormalSuspend(JSContext* cx, HandleObject obj, BaselineFrame* frame, jsbytecode* pc,
899 : uint32_t stackDepth)
900 : {
901 72 : MOZ_ASSERT(*pc == JSOP_YIELD || *pc == JSOP_AWAIT);
902 :
903 : // Return value is still on the stack.
904 0 : MOZ_ASSERT(stackDepth >= 1);
905 :
906 : // The expression stack slots are stored on the stack in reverse order, so
907 : // we copy them to a Vector and pass a pointer to that instead. We use
908 : // stackDepth - 1 because we don't want to include the return value.
909 0 : AutoValueVector exprStack(cx);
910 144 : if (!exprStack.reserve(stackDepth - 1))
911 : return false;
912 :
913 0 : size_t firstSlot = frame->numValueSlots() - stackDepth;
914 453 : for (size_t i = 0; i < stackDepth - 1; i++)
915 762 : exprStack.infallibleAppend(*frame->valueSlot(firstSlot + i));
916 :
917 0 : MOZ_ASSERT(exprStack.length() == stackDepth - 1);
918 :
919 0 : return GeneratorObject::normalSuspend(cx, obj, frame, pc, exprStack.begin(), stackDepth - 1);
920 : }
921 :
922 : bool
923 490 : FinalSuspend(JSContext* cx, HandleObject obj, jsbytecode* pc)
924 : {
925 0 : MOZ_ASSERT(*pc == JSOP_FINALYIELDRVAL);
926 490 : GeneratorObject::finalSuspend(obj);
927 490 : return true;
928 : }
929 :
930 : bool
931 1005 : InterpretResume(JSContext* cx, HandleObject obj, HandleValue val, HandlePropertyName kind,
932 : MutableHandleValue rval)
933 : {
934 0 : MOZ_ASSERT(obj->is<GeneratorObject>());
935 :
936 0 : FixedInvokeArgs<3> args(cx);
937 :
938 2010 : args[0].setObject(*obj);
939 1005 : args[1].set(val);
940 2010 : args[2].setString(kind);
941 :
942 2010 : return CallSelfHostedFunction(cx, cx->names().InterpretGeneratorResume, UndefinedHandleValue,
943 2010 : args, rval);
944 : }
945 :
946 : bool
947 0 : DebugAfterYield(JSContext* cx, BaselineFrame* frame)
948 : {
949 : // The BaselineFrame has just been constructed by JSOP_RESUME in the
950 : // caller. We need to set its debuggee flag as necessary.
951 0 : if (frame->script()->isDebuggee())
952 0 : frame->setIsDebuggee();
953 11 : return true;
954 : }
955 :
956 : bool
957 0 : GeneratorThrowOrReturn(JSContext* cx, BaselineFrame* frame, Handle<GeneratorObject*> genObj,
958 : HandleValue arg, uint32_t resumeKind)
959 : {
960 : // Set the frame's pc to the current resume pc, so that frame iterators
961 : // work. This function always returns false, so we're guaranteed to enter
962 : // the exception handler where we will clear the pc.
963 0 : JSScript* script = frame->script();
964 11 : uint32_t offset = script->yieldAndAwaitOffsets()[genObj->yieldAndAwaitIndex()];
965 11 : frame->setOverridePc(script->offsetToPC(offset));
966 :
967 0 : MOZ_ALWAYS_TRUE(DebugAfterYield(cx, frame));
968 11 : MOZ_ALWAYS_FALSE(js::GeneratorThrowOrReturn(cx, frame, genObj, arg, resumeKind));
969 0 : return false;
970 : }
971 :
972 : bool
973 0 : CheckGlobalOrEvalDeclarationConflicts(JSContext* cx, BaselineFrame* frame)
974 : {
975 0 : RootedScript script(cx, frame->script());
976 0 : RootedObject envChain(cx, frame->environmentChain());
977 0 : RootedObject varObj(cx, BindVar(cx, envChain));
978 :
979 0 : if (script->isForEval()) {
980 : // Strict eval and eval in parameter default expressions have their
981 : // own call objects.
982 : //
983 : // Non-strict eval may introduce 'var' bindings that conflict with
984 : // lexical bindings in an enclosing lexical scope.
985 0 : if (!script->bodyScope()->hasEnvironment()) {
986 0 : MOZ_ASSERT(!script->strict() &&
987 : (!script->enclosingScope()->is<FunctionScope>() ||
988 : !script->enclosingScope()->as<FunctionScope>().hasParameterExprs()));
989 0 : if (!CheckEvalDeclarationConflicts(cx, script, envChain, varObj))
990 : return false;
991 : }
992 : } else {
993 : Rooted<LexicalEnvironmentObject*> lexicalEnv(cx,
994 0 : &NearestEnclosingExtensibleLexicalEnvironment(envChain));
995 0 : if (!CheckGlobalDeclarationConflicts(cx, script, lexicalEnv, varObj))
996 0 : return false;
997 : }
998 :
999 : return true;
1000 : }
1001 :
1002 : bool
1003 0 : GlobalNameConflictsCheckFromIon(JSContext* cx, HandleScript script)
1004 : {
1005 0 : Rooted<LexicalEnvironmentObject*> globalLexical(cx, &cx->global()->lexicalEnvironment());
1006 0 : return CheckGlobalDeclarationConflicts(cx, script, globalLexical, cx->global());
1007 : }
1008 :
1009 : bool
1010 0 : InitFunctionEnvironmentObjects(JSContext* cx, BaselineFrame* frame)
1011 : {
1012 0 : return frame->initFunctionEnvironmentObjects(cx);
1013 : }
1014 :
1015 : bool
1016 0 : NewArgumentsObject(JSContext* cx, BaselineFrame* frame, MutableHandleValue res)
1017 : {
1018 61 : ArgumentsObject* obj = ArgumentsObject::createExpected(cx, frame);
1019 61 : if (!obj)
1020 : return false;
1021 122 : res.setObject(*obj);
1022 0 : return true;
1023 : }
1024 :
1025 : JSObject*
1026 0 : CopyLexicalEnvironmentObject(JSContext* cx, HandleObject env, bool copySlots)
1027 : {
1028 0 : Handle<LexicalEnvironmentObject*> lexicalEnv = env.as<LexicalEnvironmentObject>();
1029 :
1030 0 : if (copySlots)
1031 0 : return LexicalEnvironmentObject::clone(cx, lexicalEnv);
1032 :
1033 0 : return LexicalEnvironmentObject::recreate(cx, lexicalEnv);
1034 : }
1035 :
1036 : JSObject*
1037 0 : InitRestParameter(JSContext* cx, uint32_t length, Value* rest, HandleObject templateObj,
1038 : HandleObject objRes)
1039 : {
1040 0 : if (objRes) {
1041 0 : Rooted<ArrayObject*> arrRes(cx, &objRes->as<ArrayObject>());
1042 :
1043 0 : MOZ_ASSERT(!arrRes->getDenseInitializedLength());
1044 0 : MOZ_ASSERT(arrRes->group() == templateObj->group());
1045 :
1046 : // Fast path: we managed to allocate the array inline; initialize the
1047 : // slots.
1048 0 : if (length > 0) {
1049 0 : if (!arrRes->ensureElements(cx, length))
1050 : return nullptr;
1051 0 : arrRes->initDenseElements(rest, length);
1052 0 : arrRes->setLengthInt32(length);
1053 : }
1054 0 : return arrRes;
1055 : }
1056 :
1057 : NewObjectKind newKind;
1058 : {
1059 0 : AutoSweepObjectGroup sweep(templateObj->group());
1060 0 : newKind = templateObj->group()->shouldPreTenure(sweep) ? TenuredObject : GenericObject;
1061 : }
1062 0 : ArrayObject* arrRes = NewDenseCopiedArray(cx, length, rest, nullptr, newKind);
1063 0 : if (arrRes)
1064 0 : arrRes->setGroup(templateObj->group());
1065 : return arrRes;
1066 : }
1067 :
1068 : bool
1069 0 : HandleDebugTrap(JSContext* cx, BaselineFrame* frame, uint8_t* retAddr, bool* mustReturn)
1070 : {
1071 0 : *mustReturn = false;
1072 :
1073 0 : RootedScript script(cx, frame->script());
1074 0 : jsbytecode* pc = script->baselineScript()->icEntryFromReturnAddress(retAddr).pc(script);
1075 :
1076 0 : if (*pc == JSOP_DEBUGAFTERYIELD) {
1077 : // JSOP_DEBUGAFTERYIELD will set the frame's debuggee flag, but if we
1078 : // set a breakpoint there we have to do it now.
1079 0 : MOZ_ASSERT(!frame->isDebuggee());
1080 0 : if (!DebugAfterYield(cx, frame))
1081 : return false;
1082 : }
1083 :
1084 0 : MOZ_ASSERT(frame->isDebuggee());
1085 0 : MOZ_ASSERT(script->stepModeEnabled() || script->hasBreakpointsAt(pc));
1086 :
1087 0 : RootedValue rval(cx);
1088 0 : ResumeMode resumeMode = ResumeMode::Continue;
1089 :
1090 0 : if (script->stepModeEnabled())
1091 0 : resumeMode = Debugger::onSingleStep(cx, &rval);
1092 :
1093 0 : if (resumeMode == ResumeMode::Continue && script->hasBreakpointsAt(pc))
1094 0 : resumeMode = Debugger::onTrap(cx, &rval);
1095 :
1096 0 : switch (resumeMode) {
1097 : case ResumeMode::Continue:
1098 : break;
1099 :
1100 : case ResumeMode::Terminate:
1101 : return false;
1102 :
1103 : case ResumeMode::Return:
1104 0 : *mustReturn = true;
1105 0 : frame->setReturnValue(rval);
1106 0 : return jit::DebugEpilogue(cx, frame, pc, true);
1107 :
1108 : case ResumeMode::Throw:
1109 0 : cx->setPendingException(rval);
1110 0 : return false;
1111 :
1112 : default:
1113 0 : MOZ_CRASH("Invalid step/breakpoint resume mode");
1114 : }
1115 :
1116 0 : return true;
1117 : }
1118 :
1119 : bool
1120 0 : OnDebuggerStatement(JSContext* cx, BaselineFrame* frame, jsbytecode* pc, bool* mustReturn)
1121 : {
1122 0 : *mustReturn = false;
1123 :
1124 0 : switch (Debugger::onDebuggerStatement(cx, frame)) {
1125 : case ResumeMode::Continue:
1126 : return true;
1127 :
1128 : case ResumeMode::Return:
1129 0 : *mustReturn = true;
1130 0 : return jit::DebugEpilogue(cx, frame, pc, true);
1131 :
1132 : case ResumeMode::Throw:
1133 : case ResumeMode::Terminate:
1134 0 : return false;
1135 :
1136 : default:
1137 0 : MOZ_CRASH("Invalid OnDebuggerStatement resume mode");
1138 : }
1139 : }
1140 :
1141 : bool
1142 0 : GlobalHasLiveOnDebuggerStatement(JSContext* cx)
1143 : {
1144 0 : AutoUnsafeCallWithABI unsafe;
1145 0 : return cx->realm()->isDebuggee() &&
1146 0 : Debugger::hasLiveHook(cx->global(), Debugger::OnDebuggerStatement);
1147 : }
1148 :
1149 : bool
1150 0 : PushLexicalEnv(JSContext* cx, BaselineFrame* frame, Handle<LexicalScope*> scope)
1151 : {
1152 0 : return frame->pushLexicalEnvironment(cx, scope);
1153 : }
1154 :
1155 : bool
1156 2351 : PopLexicalEnv(JSContext* cx, BaselineFrame* frame)
1157 : {
1158 2351 : frame->popOffEnvironmentChain<LexicalEnvironmentObject>();
1159 0 : return true;
1160 : }
1161 :
1162 : bool
1163 0 : DebugLeaveThenPopLexicalEnv(JSContext* cx, BaselineFrame* frame, jsbytecode* pc)
1164 : {
1165 0 : MOZ_ALWAYS_TRUE(DebugLeaveLexicalEnv(cx, frame, pc));
1166 0 : frame->popOffEnvironmentChain<LexicalEnvironmentObject>();
1167 0 : return true;
1168 : }
1169 :
1170 : bool
1171 0 : FreshenLexicalEnv(JSContext* cx, BaselineFrame* frame)
1172 : {
1173 0 : return frame->freshenLexicalEnvironment(cx);
1174 : }
1175 :
1176 : bool
1177 0 : DebugLeaveThenFreshenLexicalEnv(JSContext* cx, BaselineFrame* frame, jsbytecode* pc)
1178 : {
1179 0 : MOZ_ALWAYS_TRUE(DebugLeaveLexicalEnv(cx, frame, pc));
1180 0 : return frame->freshenLexicalEnvironment(cx);
1181 : }
1182 :
1183 : bool
1184 0 : RecreateLexicalEnv(JSContext* cx, BaselineFrame* frame)
1185 : {
1186 0 : return frame->recreateLexicalEnvironment(cx);
1187 : }
1188 :
1189 : bool
1190 0 : DebugLeaveThenRecreateLexicalEnv(JSContext* cx, BaselineFrame* frame, jsbytecode* pc)
1191 : {
1192 0 : MOZ_ALWAYS_TRUE(DebugLeaveLexicalEnv(cx, frame, pc));
1193 0 : return frame->recreateLexicalEnvironment(cx);
1194 : }
1195 :
1196 : bool
1197 0 : DebugLeaveLexicalEnv(JSContext* cx, BaselineFrame* frame, jsbytecode* pc)
1198 : {
1199 0 : MOZ_ASSERT(frame->script()->baselineScript()->hasDebugInstrumentation());
1200 0 : if (cx->realm()->isDebuggee())
1201 0 : DebugEnvironments::onPopLexical(cx, frame, pc);
1202 0 : return true;
1203 : }
1204 :
1205 : bool
1206 0 : PushVarEnv(JSContext* cx, BaselineFrame* frame, HandleScope scope)
1207 : {
1208 0 : return frame->pushVarEnvironment(cx, scope);
1209 : }
1210 :
1211 : bool
1212 0 : PopVarEnv(JSContext* cx, BaselineFrame* frame)
1213 : {
1214 0 : frame->popOffEnvironmentChain<VarEnvironmentObject>();
1215 0 : return true;
1216 : }
1217 :
1218 : bool
1219 0 : EnterWith(JSContext* cx, BaselineFrame* frame, HandleValue val, Handle<WithScope*> templ)
1220 : {
1221 0 : return EnterWithOperation(cx, frame, val, templ);
1222 : }
1223 :
1224 : bool
1225 0 : LeaveWith(JSContext* cx, BaselineFrame* frame)
1226 : {
1227 0 : if (MOZ_UNLIKELY(frame->isDebuggee()))
1228 0 : DebugEnvironments::onPopWith(frame);
1229 0 : frame->popOffEnvironmentChain<WithEnvironmentObject>();
1230 0 : return true;
1231 : }
1232 :
1233 : bool
1234 193 : InitBaselineFrameForOsr(BaselineFrame* frame, InterpreterFrame* interpFrame,
1235 : uint32_t numStackValues)
1236 : {
1237 193 : return frame->initForOsr(interpFrame, numStackValues);
1238 : }
1239 :
1240 : JSObject*
1241 0 : CreateDerivedTypedObj(JSContext* cx, HandleObject descr,
1242 : HandleObject owner, int32_t offset)
1243 : {
1244 0 : MOZ_ASSERT(descr->is<TypeDescr>());
1245 0 : MOZ_ASSERT(owner->is<TypedObject>());
1246 0 : Rooted<TypeDescr*> descr1(cx, &descr->as<TypeDescr>());
1247 0 : Rooted<TypedObject*> owner1(cx, &owner->as<TypedObject>());
1248 0 : return OutlineTypedObject::createDerived(cx, descr1, owner1, offset);
1249 : }
1250 :
1251 : JSString*
1252 0 : StringReplace(JSContext* cx, HandleString string, HandleString pattern, HandleString repl)
1253 : {
1254 0 : MOZ_ASSERT(string);
1255 0 : MOZ_ASSERT(pattern);
1256 0 : MOZ_ASSERT(repl);
1257 :
1258 0 : return str_replace_string_raw(cx, string, pattern, repl);
1259 : }
1260 :
1261 : bool
1262 0 : RecompileImpl(JSContext* cx, bool force)
1263 : {
1264 0 : MOZ_ASSERT(cx->currentlyRunningInJit());
1265 0 : JitActivationIterator activations(cx);
1266 0 : JSJitFrameIter frame(activations->asJit());
1267 :
1268 0 : MOZ_ASSERT(frame.type() == JitFrame_Exit);
1269 0 : ++frame;
1270 :
1271 0 : RootedScript script(cx, frame.script());
1272 0 : MOZ_ASSERT(script->hasIonScript());
1273 :
1274 0 : if (!IsIonEnabled(cx))
1275 : return true;
1276 :
1277 0 : MethodStatus status = Recompile(cx, script, nullptr, nullptr, force);
1278 0 : if (status == Method_Error)
1279 : return false;
1280 :
1281 0 : return true;
1282 : }
1283 :
1284 : bool
1285 0 : ForcedRecompile(JSContext* cx)
1286 : {
1287 0 : return RecompileImpl(cx, /* force = */ true);
1288 : }
1289 :
1290 : bool
1291 0 : Recompile(JSContext* cx)
1292 : {
1293 0 : return RecompileImpl(cx, /* force = */ false);
1294 : }
1295 :
1296 : bool
1297 408 : SetDenseElement(JSContext* cx, HandleNativeObject obj, int32_t index, HandleValue value,
1298 : bool strict)
1299 : {
1300 : // This function is called from Ion code for StoreElementHole's OOL path.
1301 : // In this case we know the object is native and that no type changes are
1302 : // needed.
1303 :
1304 0 : DenseElementResult result = obj->setOrExtendDenseElements(cx, index, value.address(), 1,
1305 408 : ShouldUpdateTypes::DontUpdate);
1306 408 : if (result != DenseElementResult::Incomplete)
1307 408 : return result == DenseElementResult::Success;
1308 :
1309 0 : RootedValue indexVal(cx, Int32Value(index));
1310 0 : return SetObjectElement(cx, obj, indexVal, value, strict);
1311 : }
1312 :
1313 : void
1314 0 : AutoDetectInvalidation::setReturnOverride()
1315 : {
1316 0 : cx_->setIonReturnOverride(rval_.get());
1317 0 : }
1318 :
1319 : void
1320 0 : AssertValidObjectPtr(JSContext* cx, JSObject* obj)
1321 : {
1322 0 : AutoUnsafeCallWithABI unsafe;
1323 : #ifdef DEBUG
1324 : // Check what we can, so that we'll hopefully assert/crash if we get a
1325 : // bogus object (pointer).
1326 0 : MOZ_ASSERT(obj->compartment() == cx->compartment());
1327 0 : MOZ_ASSERT(obj->zoneFromAnyThread() == cx->zone());
1328 0 : MOZ_ASSERT(obj->runtimeFromMainThread() == cx->runtime());
1329 :
1330 0 : MOZ_ASSERT_IF(!obj->hasLazyGroup() && obj->maybeShape(),
1331 : obj->group()->clasp() == obj->maybeShape()->getObjectClass());
1332 :
1333 0 : if (obj->isTenured()) {
1334 0 : MOZ_ASSERT(obj->isAligned());
1335 0 : gc::AllocKind kind = obj->asTenured().getAllocKind();
1336 0 : MOZ_ASSERT(gc::IsObjectAllocKind(kind));
1337 : }
1338 : #endif
1339 0 : }
1340 :
1341 : void
1342 0 : AssertValidObjectOrNullPtr(JSContext* cx, JSObject* obj)
1343 : {
1344 0 : AutoUnsafeCallWithABI unsafe;
1345 0 : if (obj)
1346 0 : AssertValidObjectPtr(cx, obj);
1347 0 : }
1348 :
1349 : void
1350 0 : AssertValidStringPtr(JSContext* cx, JSString* str)
1351 : {
1352 0 : AutoUnsafeCallWithABI unsafe;
1353 : #ifdef DEBUG
1354 : // We can't closely inspect strings from another runtime.
1355 0 : if (str->runtimeFromAnyThread() != cx->runtime()) {
1356 0 : MOZ_ASSERT(str->isPermanentAtom());
1357 0 : return;
1358 : }
1359 :
1360 0 : if (str->isAtom())
1361 0 : MOZ_ASSERT(str->zone()->isAtomsZone());
1362 : else
1363 0 : MOZ_ASSERT(str->zone() == cx->zone());
1364 :
1365 0 : MOZ_ASSERT(str->isAligned());
1366 0 : MOZ_ASSERT(str->length() <= JSString::MAX_LENGTH);
1367 :
1368 0 : gc::AllocKind kind = str->getAllocKind();
1369 0 : if (str->isFatInline()) {
1370 0 : MOZ_ASSERT(kind == gc::AllocKind::FAT_INLINE_STRING ||
1371 : kind == gc::AllocKind::FAT_INLINE_ATOM);
1372 0 : } else if (str->isExternal()) {
1373 0 : MOZ_ASSERT(kind == gc::AllocKind::EXTERNAL_STRING);
1374 0 : } else if (str->isAtom()) {
1375 0 : MOZ_ASSERT(kind == gc::AllocKind::ATOM);
1376 0 : } else if (str->isFlat()) {
1377 0 : MOZ_ASSERT(kind == gc::AllocKind::STRING ||
1378 : kind == gc::AllocKind::FAT_INLINE_STRING ||
1379 : kind == gc::AllocKind::EXTERNAL_STRING);
1380 : } else {
1381 0 : MOZ_ASSERT(kind == gc::AllocKind::STRING);
1382 : }
1383 : #endif
1384 : }
1385 :
1386 : void
1387 0 : AssertValidSymbolPtr(JSContext* cx, JS::Symbol* sym)
1388 : {
1389 0 : AutoUnsafeCallWithABI unsafe;
1390 :
1391 : // We can't closely inspect symbols from another runtime.
1392 0 : if (sym->runtimeFromAnyThread() != cx->runtime()) {
1393 0 : MOZ_ASSERT(sym->isWellKnownSymbol());
1394 0 : return;
1395 : }
1396 :
1397 0 : MOZ_ASSERT(sym->zone()->isAtomsZone());
1398 0 : MOZ_ASSERT(sym->isAligned());
1399 0 : if (JSString* desc = sym->description()) {
1400 0 : MOZ_ASSERT(desc->isAtom());
1401 0 : AssertValidStringPtr(cx, desc);
1402 : }
1403 :
1404 0 : MOZ_ASSERT(sym->getAllocKind() == gc::AllocKind::SYMBOL);
1405 : }
1406 :
1407 : void
1408 0 : AssertValidValue(JSContext* cx, Value* v)
1409 : {
1410 0 : AutoUnsafeCallWithABI unsafe;
1411 0 : if (v->isObject())
1412 0 : AssertValidObjectPtr(cx, &v->toObject());
1413 0 : else if (v->isString())
1414 0 : AssertValidStringPtr(cx, v->toString());
1415 0 : else if (v->isSymbol())
1416 0 : AssertValidSymbolPtr(cx, v->toSymbol());
1417 0 : }
1418 :
1419 : bool
1420 11 : ObjectIsCallable(JSObject* obj)
1421 : {
1422 22 : AutoUnsafeCallWithABI unsafe;
1423 0 : return obj->isCallable();
1424 : }
1425 :
1426 : bool
1427 0 : ObjectIsConstructor(JSObject* obj)
1428 : {
1429 0 : AutoUnsafeCallWithABI unsafe;
1430 0 : return obj->isConstructor();
1431 : }
1432 :
1433 : void
1434 0 : MarkValueFromJit(JSRuntime* rt, Value* vp)
1435 : {
1436 0 : AutoUnsafeCallWithABI unsafe;
1437 0 : TraceManuallyBarrieredEdge(&rt->gc.marker, vp, "write barrier");
1438 0 : }
1439 :
1440 : void
1441 0 : MarkStringFromJit(JSRuntime* rt, JSString** stringp)
1442 : {
1443 0 : AutoUnsafeCallWithABI unsafe;
1444 0 : MOZ_ASSERT(*stringp);
1445 0 : TraceManuallyBarrieredEdge(&rt->gc.marker, stringp, "write barrier");
1446 0 : }
1447 :
1448 : void
1449 0 : MarkObjectFromJit(JSRuntime* rt, JSObject** objp)
1450 : {
1451 0 : AutoUnsafeCallWithABI unsafe;
1452 0 : MOZ_ASSERT(*objp);
1453 0 : TraceManuallyBarrieredEdge(&rt->gc.marker, objp, "write barrier");
1454 0 : }
1455 :
1456 : void
1457 0 : MarkShapeFromJit(JSRuntime* rt, Shape** shapep)
1458 : {
1459 0 : AutoUnsafeCallWithABI unsafe;
1460 0 : TraceManuallyBarrieredEdge(&rt->gc.marker, shapep, "write barrier");
1461 0 : }
1462 :
1463 : void
1464 0 : MarkObjectGroupFromJit(JSRuntime* rt, ObjectGroup** groupp)
1465 : {
1466 0 : AutoUnsafeCallWithABI unsafe;
1467 0 : TraceManuallyBarrieredEdge(&rt->gc.marker, groupp, "write barrier");
1468 0 : }
1469 :
1470 : bool
1471 0 : ThrowRuntimeLexicalError(JSContext* cx, unsigned errorNumber)
1472 : {
1473 0 : ScriptFrameIter iter(cx);
1474 0 : RootedScript script(cx, iter.script());
1475 0 : ReportRuntimeLexicalError(cx, errorNumber, script, iter.pc());
1476 0 : return false;
1477 : }
1478 :
1479 : bool
1480 0 : ThrowBadDerivedReturn(JSContext* cx, HandleValue v)
1481 : {
1482 0 : ReportValueError(cx, JSMSG_BAD_DERIVED_RETURN, JSDVG_IGNORE_STACK, v, nullptr);
1483 0 : return false;
1484 : }
1485 :
1486 : bool
1487 0 : BaselineThrowUninitializedThis(JSContext* cx, BaselineFrame* frame)
1488 : {
1489 0 : return ThrowUninitializedThis(cx, frame);
1490 : }
1491 :
1492 : bool
1493 0 : BaselineThrowInitializedThis(JSContext* cx)
1494 : {
1495 0 : return ThrowInitializedThis(cx);
1496 : }
1497 :
1498 :
1499 : bool
1500 0 : ThrowObjectCoercible(JSContext* cx, HandleValue v)
1501 : {
1502 0 : MOZ_ASSERT(v.isUndefined() || v.isNull());
1503 0 : MOZ_ALWAYS_FALSE(ToObjectSlow(cx, v, true));
1504 0 : return false;
1505 : }
1506 :
1507 : bool
1508 0 : BaselineGetFunctionThis(JSContext* cx, BaselineFrame* frame, MutableHandleValue res)
1509 : {
1510 0 : return GetFunctionThis(cx, frame, res);
1511 : }
1512 :
1513 : bool
1514 0 : CallNativeGetter(JSContext* cx, HandleFunction callee, HandleObject obj,
1515 : MutableHandleValue result)
1516 : {
1517 4436 : MOZ_ASSERT(callee->isNative());
1518 0 : JSNative natfun = callee->native();
1519 :
1520 4436 : JS::AutoValueArray<2> vp(cx);
1521 0 : vp[0].setObject(*callee.get());
1522 0 : vp[1].setObject(*obj.get());
1523 :
1524 2218 : if (!natfun(cx, 0, vp.begin()))
1525 : return false;
1526 :
1527 4436 : result.set(vp[0]);
1528 0 : return true;
1529 : }
1530 :
1531 : bool
1532 0 : CallNativeSetter(JSContext* cx, HandleFunction callee, HandleObject obj, HandleValue rhs)
1533 : {
1534 0 : MOZ_ASSERT(callee->isNative());
1535 2 : JSNative natfun = callee->native();
1536 :
1537 4 : JS::AutoValueArray<3> vp(cx);
1538 6 : vp[0].setObject(*callee.get());
1539 6 : vp[1].setObject(*obj.get());
1540 0 : vp[2].set(rhs);
1541 :
1542 4 : return natfun(cx, 1, vp.begin());
1543 : }
1544 :
1545 : bool
1546 0 : EqualStringsHelper(JSString* str1, JSString* str2)
1547 : {
1548 : // IC code calls this directly so we shouldn't GC.
1549 1960 : AutoUnsafeCallWithABI unsafe;
1550 :
1551 0 : MOZ_ASSERT(str1->isAtom());
1552 0 : MOZ_ASSERT(!str2->isAtom());
1553 2940 : MOZ_ASSERT(str1->length() == str2->length());
1554 :
1555 : // ensureLinear is intentionally called with a nullptr to avoid OOM
1556 : // reporting; if it fails, we will continue to the next stub.
1557 980 : JSLinearString* str2Linear = str2->ensureLinear(nullptr);
1558 980 : if (!str2Linear)
1559 : return false;
1560 :
1561 0 : return EqualChars(&str1->asLinear(), str2Linear);
1562 : }
1563 :
1564 : bool
1565 0 : CheckIsCallable(JSContext* cx, HandleValue v, CheckIsCallableKind kind)
1566 : {
1567 0 : if (!IsCallable(v))
1568 0 : return ThrowCheckIsCallable(cx, kind);
1569 :
1570 : return true;
1571 : }
1572 :
1573 : template <bool HandleMissing>
1574 : static MOZ_ALWAYS_INLINE bool
1575 0 : GetNativeDataProperty(JSContext* cx, NativeObject* obj, jsid id, Value* vp)
1576 : {
1577 : // Fast path used by megamorphic IC stubs. Unlike our other property
1578 : // lookup paths, this is optimized to be as fast as possible for simple
1579 : // data property lookups.
1580 :
1581 0 : AutoUnsafeCallWithABI unsafe;
1582 :
1583 19851 : MOZ_ASSERT(JSID_IS_ATOM(id) || JSID_IS_SYMBOL(id));
1584 :
1585 0 : while (true) {
1586 56134 : if (Shape* shape = obj->lastProperty()->search(cx, id)) {
1587 13815 : if (!shape->isDataProperty())
1588 : return false;
1589 :
1590 0 : *vp = obj->getSlot(shape->slot());
1591 13802 : return true;
1592 : }
1593 :
1594 : // Property not found. Watch out for Class hooks.
1595 0 : if (MOZ_UNLIKELY(!obj->is<PlainObject>())) {
1596 2085 : if (ClassMayResolveId(cx->names(), obj->getClass(), id, obj))
1597 : return false;
1598 : }
1599 :
1600 14242 : JSObject* proto = obj->staticPrototype();
1601 14242 : if (!proto) {
1602 : if (HandleMissing) {
1603 0 : vp->setUndefined();
1604 5481 : return true;
1605 : }
1606 : return false;
1607 : }
1608 :
1609 8216 : if (!proto->isNative())
1610 : return false;
1611 0 : obj = &proto->as<NativeObject>();
1612 : }
1613 : }
1614 :
1615 : template <bool HandleMissing>
1616 : bool
1617 9883 : GetNativeDataProperty(JSContext* cx, JSObject* obj, PropertyName* name, Value* vp)
1618 : {
1619 : // Condition checked by caller.
1620 9883 : MOZ_ASSERT(obj->isNative());
1621 9883 : return GetNativeDataProperty<HandleMissing>(cx, &obj->as<NativeObject>(), NameToId(name), vp);
1622 : }
1623 :
1624 : template bool
1625 : GetNativeDataProperty<true>(JSContext* cx, JSObject* obj, PropertyName* name, Value* vp);
1626 :
1627 : template bool
1628 : GetNativeDataProperty<false>(JSContext* cx, JSObject* obj, PropertyName* name, Value* vp);
1629 :
1630 : static MOZ_ALWAYS_INLINE bool
1631 23429 : ValueToAtomOrSymbol(JSContext* cx, Value& idVal, jsid* id)
1632 : {
1633 0 : AutoUnsafeCallWithABI unsafe;
1634 :
1635 0 : if (MOZ_LIKELY(idVal.isString())) {
1636 0 : JSString* s = idVal.toString();
1637 : JSAtom* atom;
1638 46850 : if (s->isAtom()) {
1639 0 : atom = &s->asAtom();
1640 : } else {
1641 0 : atom = AtomizeString(cx, s);
1642 752 : if (!atom)
1643 : return false;
1644 : }
1645 23425 : *id = AtomToId(atom);
1646 4 : } else if (idVal.isSymbol()) {
1647 4 : *id = SYMBOL_TO_JSID(idVal.toSymbol());
1648 : } else {
1649 0 : if (!ValueToIdPure(idVal, id))
1650 : return false;
1651 : }
1652 :
1653 : // Watch out for ids that may be stored in dense elements.
1654 : static_assert(NativeObject::MAX_DENSE_ELEMENTS_COUNT < JSID_INT_MAX,
1655 : "All dense elements must have integer jsids");
1656 23429 : if (MOZ_UNLIKELY(JSID_IS_INT(*id)))
1657 : return false;
1658 :
1659 23427 : return true;
1660 : }
1661 :
1662 : template <bool HandleMissing>
1663 : bool
1664 9969 : GetNativeDataPropertyByValue(JSContext* cx, JSObject* obj, Value* vp)
1665 : {
1666 0 : AutoUnsafeCallWithABI unsafe;
1667 :
1668 : // Condition checked by caller.
1669 9969 : MOZ_ASSERT(obj->isNative());
1670 :
1671 : // vp[0] contains the id, result will be stored in vp[1].
1672 0 : Value idVal = vp[0];
1673 9969 : jsid id;
1674 9969 : if (!ValueToAtomOrSymbol(cx, idVal, &id))
1675 : return false;
1676 :
1677 9968 : Value* res = vp + 1;
1678 9968 : return GetNativeDataProperty<HandleMissing>(cx, &obj->as<NativeObject>(), id, res);
1679 : }
1680 :
1681 : template bool
1682 : GetNativeDataPropertyByValue<true>(JSContext* cx, JSObject* obj, Value* vp);
1683 :
1684 : template bool
1685 : GetNativeDataPropertyByValue<false>(JSContext* cx, JSObject* obj, Value* vp);
1686 :
1687 : template <bool NeedsTypeBarrier>
1688 : bool
1689 2 : SetNativeDataProperty(JSContext* cx, JSObject* obj, PropertyName* name, Value* val)
1690 : {
1691 0 : AutoUnsafeCallWithABI unsafe;
1692 :
1693 0 : if (MOZ_UNLIKELY(!obj->isNative()))
1694 : return false;
1695 :
1696 2 : NativeObject* nobj = &obj->as<NativeObject>();
1697 4 : Shape* shape = nobj->lastProperty()->search(cx, NameToId(name));
1698 4 : if (!shape ||
1699 0 : !shape->isDataProperty() ||
1700 : !shape->writable())
1701 : {
1702 : return false;
1703 : }
1704 :
1705 4 : if (NeedsTypeBarrier && !HasTypePropertyId(nobj, NameToId(name), *val))
1706 : return false;
1707 :
1708 2 : nobj->setSlot(shape->slot(), *val);
1709 2 : return true;
1710 : }
1711 :
1712 : template bool
1713 : SetNativeDataProperty<true>(JSContext* cx, JSObject* obj, PropertyName* name, Value* val);
1714 :
1715 : template bool
1716 : SetNativeDataProperty<false>(JSContext* cx, JSObject* obj, PropertyName* name, Value* val);
1717 :
1718 : bool
1719 1325 : ObjectHasGetterSetter(JSContext* cx, JSObject* objArg, Shape* propShape)
1720 : {
1721 0 : AutoUnsafeCallWithABI unsafe;
1722 :
1723 1325 : MOZ_ASSERT(propShape->hasGetterObject() || propShape->hasSetterObject());
1724 :
1725 : // Window objects may require outerizing (passing the WindowProxy to the
1726 : // getter/setter), so we don't support them here.
1727 2649 : if (MOZ_UNLIKELY(!objArg->isNative() || IsWindow(objArg)))
1728 : return false;
1729 :
1730 1324 : NativeObject* nobj = &objArg->as<NativeObject>();
1731 0 : jsid id = propShape->propid();
1732 :
1733 : while (true) {
1734 4012 : if (Shape* shape = nobj->lastProperty()->search(cx, id)) {
1735 1324 : if (shape == propShape)
1736 : return true;
1737 2649 : if (shape->getterOrUndefined() == propShape->getterOrUndefined() &&
1738 0 : shape->setterOrUndefined() == propShape->setterOrUndefined())
1739 : {
1740 : return true;
1741 : }
1742 883 : return false;
1743 : }
1744 :
1745 : // Property not found. Watch out for Class hooks.
1746 0 : if (!nobj->is<PlainObject>()) {
1747 1974 : if (ClassMayResolveId(cx->names(), nobj->getClass(), id, nobj))
1748 : return false;
1749 : }
1750 :
1751 0 : JSObject* proto = nobj->staticPrototype();
1752 0 : if (!proto)
1753 : return false;
1754 :
1755 682 : if (!proto->isNative())
1756 : return false;
1757 0 : nobj = &proto->as<NativeObject>();
1758 682 : }
1759 : }
1760 :
1761 : template <bool HasOwn>
1762 : bool
1763 0 : HasNativeDataProperty(JSContext* cx, JSObject* obj, Value* vp)
1764 : {
1765 26920 : AutoUnsafeCallWithABI unsafe;
1766 :
1767 : // vp[0] contains the id, result will be stored in vp[1].
1768 0 : Value idVal = vp[0];
1769 0 : jsid id;
1770 0 : if (!ValueToAtomOrSymbol(cx, idVal, &id))
1771 : return false;
1772 :
1773 14657 : do {
1774 20998 : if (obj->isNative()) {
1775 35048 : if (obj->as<NativeObject>().lastProperty()->search(cx, id)) {
1776 0 : vp[1].setBoolean(true);
1777 4321 : return true;
1778 : }
1779 :
1780 : // Fail if there's a resolve hook, unless the mayResolve hook tells
1781 : // us the resolve hook won't define a property with this id.
1782 26406 : if (MOZ_UNLIKELY(ClassMayResolveId(cx->names(), obj->getClass(), id, obj)))
1783 : return false;
1784 1 : } else if (obj->is<UnboxedPlainObject>()) {
1785 1 : if (obj->as<UnboxedPlainObject>().containsUnboxedOrExpandoProperty(cx, id)) {
1786 1 : vp[1].setBoolean(true);
1787 1840 : return true;
1788 : }
1789 0 : } else if (obj->is<TypedObject>()) {
1790 0 : if (obj->as<TypedObject>().typeDescr().hasProperty(cx->names(), id)) {
1791 0 : vp[1].setBoolean(true);
1792 0 : return true;
1793 : }
1794 : } else {
1795 : return false;
1796 : }
1797 :
1798 : // If implementing Object.hasOwnProperty, don't follow protochain.
1799 : if (HasOwn)
1800 : break;
1801 :
1802 : // Get prototype. Objects that may allow dynamic prototypes are already
1803 : // filtered out above.
1804 14657 : obj = obj->staticPrototype();
1805 : } while (obj);
1806 :
1807 : // Missing property.
1808 14596 : vp[1].setBoolean(false);
1809 7298 : return true;
1810 : }
1811 :
1812 : template bool
1813 : HasNativeDataProperty<true>(JSContext* cx, JSObject* obj, Value* vp);
1814 :
1815 : template bool
1816 : HasNativeDataProperty<false>(JSContext* cx, JSObject* obj, Value* vp);
1817 :
1818 :
1819 : bool
1820 0 : HasNativeElement(JSContext* cx, NativeObject* obj, int32_t index, Value* vp)
1821 : {
1822 0 : AutoUnsafeCallWithABI unsafe;
1823 :
1824 0 : MOZ_ASSERT(obj->getClass()->isNative());
1825 0 : MOZ_ASSERT(!obj->getOpsHasProperty());
1826 0 : MOZ_ASSERT(!obj->getOpsLookupProperty());
1827 0 : MOZ_ASSERT(!obj->getOpsGetOwnPropertyDescriptor());
1828 :
1829 0 : if (MOZ_UNLIKELY(index < 0))
1830 : return false;
1831 :
1832 0 : if (obj->containsDenseElement(index)) {
1833 0 : vp[0].setBoolean(true);
1834 0 : return true;
1835 : }
1836 :
1837 0 : jsid id = INT_TO_JSID(index);
1838 0 : if (obj->lastProperty()->search(cx, id)) {
1839 0 : vp[0].setBoolean(true);
1840 0 : return true;
1841 : }
1842 :
1843 : // Fail if there's a resolve hook, unless the mayResolve hook tells
1844 : // us the resolve hook won't define a property with this id.
1845 0 : if (MOZ_UNLIKELY(ClassMayResolveId(cx->names(), obj->getClass(), id, obj)))
1846 : return false;
1847 : // TypedArrayObject are also native and contain indexed properties.
1848 0 : if (MOZ_UNLIKELY(obj->is<TypedArrayObject>())) {
1849 0 : vp[0].setBoolean(uint32_t(index) < obj->as<TypedArrayObject>().length());
1850 0 : return true;
1851 : }
1852 :
1853 0 : vp[0].setBoolean(false);
1854 0 : return true;
1855 : }
1856 :
1857 : JSString*
1858 528 : TypeOfObject(JSObject* obj, JSRuntime* rt)
1859 : {
1860 0 : AutoUnsafeCallWithABI unsafe;
1861 528 : JSType type = js::TypeOfObject(obj);
1862 0 : return TypeName(type, *rt->commonNames);
1863 : }
1864 :
1865 : bool
1866 0 : GetPrototypeOf(JSContext* cx, HandleObject target, MutableHandleValue rval)
1867 : {
1868 0 : MOZ_ASSERT(target->hasDynamicPrototype());
1869 :
1870 0 : RootedObject proto(cx);
1871 0 : if (!GetPrototype(cx, target, &proto))
1872 : return false;
1873 0 : rval.setObjectOrNull(proto);
1874 : return true;
1875 : }
1876 :
1877 : void
1878 0 : CloseIteratorFromIon(JSContext* cx, JSObject* obj)
1879 : {
1880 0 : CloseIterator(obj);
1881 : }
1882 :
1883 : typedef bool (*SetObjectElementFn)(JSContext*, HandleObject, HandleValue,
1884 : HandleValue, HandleValue, bool);
1885 : const VMFunction SetObjectElementInfo =
1886 : FunctionInfo<SetObjectElementFn>(js::SetObjectElement, "SetObjectElement");
1887 :
1888 : } // namespace jit
1889 : } // namespace js
|