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