1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
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 #ifndef vm_Interpreter_inl_h
8 #define vm_Interpreter_inl_h
9
10 #include "vm/Interpreter.h"
11
12 #include "jsnum.h"
13
14 #include "jit/Ion.h"
15 #include "js/friend/DumpFunctions.h"
16 #include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
17 #include "vm/ArgumentsObject.h"
18 #include "vm/BytecodeUtil.h" // JSDVG_SEARCH_STACK
19 #include "vm/Realm.h"
20 #include "vm/SharedStencil.h" // GCThingIndex
21 #include "vm/ThrowMsgKind.h"
22
23 #include "vm/EnvironmentObject-inl.h"
24 #include "vm/GlobalObject-inl.h"
25 #include "vm/JSAtom-inl.h"
26 #include "vm/JSObject-inl.h"
27 #include "vm/ObjectOperations-inl.h"
28 #include "vm/Stack-inl.h"
29 #include "vm/StringType-inl.h"
30
31 namespace js {
32
33 /*
34 * Per ES6, lexical declarations may not be accessed in any fashion until they
35 * are initialized (i.e., until the actual declaring statement is
36 * executed). The various LEXICAL opcodes need to check if the slot is an
37 * uninitialized let declaration, represented by the magic value
38 * JS_UNINITIALIZED_LEXICAL.
39 */
IsUninitializedLexical(const Value & val)40 static inline bool IsUninitializedLexical(const Value& val) {
41 // Use whyMagic here because JS_OPTIMIZED_OUT could flow into here.
42 return val.isMagic() && val.whyMagic() == JS_UNINITIALIZED_LEXICAL;
43 }
44
IsUninitializedLexicalSlot(HandleObject obj,const PropertyResult & prop)45 static inline bool IsUninitializedLexicalSlot(HandleObject obj,
46 const PropertyResult& prop) {
47 MOZ_ASSERT(prop.isFound());
48 if (obj->is<WithEnvironmentObject>()) {
49 return false;
50 }
51
52 // Proxy hooks may return a non-native property.
53 if (prop.isNonNativeProperty()) {
54 return false;
55 }
56
57 PropertyInfo propInfo = prop.propertyInfo();
58 if (!propInfo.isDataProperty()) {
59 return false;
60 }
61
62 return IsUninitializedLexical(
63 obj->as<NativeObject>().getSlot(propInfo.slot()));
64 }
65
CheckUninitializedLexical(JSContext * cx,PropertyName * name_,HandleValue val)66 static inline bool CheckUninitializedLexical(JSContext* cx, PropertyName* name_,
67 HandleValue val) {
68 if (IsUninitializedLexical(val)) {
69 RootedPropertyName name(cx, name_);
70 ReportRuntimeLexicalError(cx, JSMSG_UNINITIALIZED_LEXICAL, name);
71 return false;
72 }
73 return true;
74 }
75
GetLengthProperty(const Value & lval,MutableHandleValue vp)76 inline bool GetLengthProperty(const Value& lval, MutableHandleValue vp) {
77 /* Optimize length accesses on strings, arrays, and arguments. */
78 if (lval.isString()) {
79 vp.setInt32(lval.toString()->length());
80 return true;
81 }
82 if (lval.isObject()) {
83 JSObject* obj = &lval.toObject();
84 if (obj->is<ArrayObject>()) {
85 vp.setNumber(obj->as<ArrayObject>().length());
86 return true;
87 }
88
89 if (obj->is<ArgumentsObject>()) {
90 ArgumentsObject* argsobj = &obj->as<ArgumentsObject>();
91 if (!argsobj->hasOverriddenLength()) {
92 uint32_t length = argsobj->initialLength();
93 MOZ_ASSERT(length < INT32_MAX);
94 vp.setInt32(int32_t(length));
95 return true;
96 }
97 }
98 }
99
100 return false;
101 }
102
103 enum class GetNameMode { Normal, TypeOf };
104
105 template <GetNameMode mode>
FetchName(JSContext * cx,HandleObject receiver,HandleObject holder,HandlePropertyName name,const PropertyResult & prop,MutableHandleValue vp)106 inline bool FetchName(JSContext* cx, HandleObject receiver, HandleObject holder,
107 HandlePropertyName name, const PropertyResult& prop,
108 MutableHandleValue vp) {
109 if (prop.isNotFound()) {
110 switch (mode) {
111 case GetNameMode::Normal:
112 ReportIsNotDefined(cx, name);
113 return false;
114 case GetNameMode::TypeOf:
115 vp.setUndefined();
116 return true;
117 }
118 }
119
120 /* Take the slow path if shape was not found in a native object. */
121 if (!receiver->is<NativeObject>() || !holder->is<NativeObject>()) {
122 Rooted<jsid> id(cx, NameToId(name));
123 if (!GetProperty(cx, receiver, receiver, id, vp)) {
124 return false;
125 }
126 } else {
127 PropertyInfo propInfo = prop.propertyInfo();
128 if (propInfo.isDataProperty()) {
129 /* Fast path for Object instance properties. */
130 vp.set(holder->as<NativeObject>().getSlot(propInfo.slot()));
131 } else {
132 // Unwrap 'with' environments for reasons given in
133 // GetNameBoundInEnvironment.
134 RootedObject normalized(cx, MaybeUnwrapWithEnvironment(receiver));
135 RootedId id(cx, NameToId(name));
136 if (!NativeGetExistingProperty(cx, normalized, holder.as<NativeObject>(),
137 id, propInfo, vp)) {
138 return false;
139 }
140 }
141 }
142
143 // We do our own explicit checking for |this|
144 if (name == cx->names().dotThis) {
145 return true;
146 }
147
148 // NAME operations are the slow paths already, so unconditionally check
149 // for uninitialized lets.
150 return CheckUninitializedLexical(cx, name, vp);
151 }
152
FetchNameNoGC(NativeObject * pobj,PropertyResult prop,Value * vp)153 inline bool FetchNameNoGC(NativeObject* pobj, PropertyResult prop, Value* vp) {
154 if (prop.isNotFound()) {
155 return false;
156 }
157
158 PropertyInfo propInfo = prop.propertyInfo();
159 if (!propInfo.isDataProperty()) {
160 return false;
161 }
162
163 *vp = pobj->getSlot(propInfo.slot());
164 return !IsUninitializedLexical(*vp);
165 }
166
167 template <js::GetNameMode mode>
GetEnvironmentName(JSContext * cx,HandleObject envChain,HandlePropertyName name,MutableHandleValue vp)168 inline bool GetEnvironmentName(JSContext* cx, HandleObject envChain,
169 HandlePropertyName name, MutableHandleValue vp) {
170 {
171 PropertyResult prop;
172 JSObject* obj = nullptr;
173 NativeObject* pobj = nullptr;
174 if (LookupNameNoGC(cx, name, envChain, &obj, &pobj, &prop)) {
175 if (FetchNameNoGC(pobj, prop, vp.address())) {
176 return true;
177 }
178 }
179 }
180
181 PropertyResult prop;
182 RootedObject obj(cx), pobj(cx);
183 if (!LookupName(cx, name, envChain, &obj, &pobj, &prop)) {
184 return false;
185 }
186
187 return FetchName<mode>(cx, obj, pobj, name, prop, vp);
188 }
189
HasOwnProperty(JSContext * cx,HandleValue val,HandleValue idValue,bool * result)190 inline bool HasOwnProperty(JSContext* cx, HandleValue val, HandleValue idValue,
191 bool* result) {
192 // As an optimization, provide a fast path when rooting is not necessary and
193 // we can safely retrieve the object's shape.
194 jsid id;
195 if (val.isObject() && idValue.isPrimitive() &&
196 PrimitiveValueToId<NoGC>(cx, idValue, &id)) {
197 JSObject* obj = &val.toObject();
198 PropertyResult prop;
199 if (obj->is<NativeObject>() &&
200 NativeLookupOwnProperty<NoGC>(cx, &obj->as<NativeObject>(), id,
201 &prop)) {
202 *result = prop.isFound();
203 return true;
204 }
205 }
206
207 // Step 1.
208 RootedId key(cx);
209 if (!ToPropertyKey(cx, idValue, &key)) {
210 return false;
211 }
212
213 // Step 2.
214 RootedObject obj(cx, ToObject(cx, val));
215 if (!obj) {
216 return false;
217 }
218
219 // Step 3.
220 return HasOwnProperty(cx, obj, key, result);
221 }
222
GetIntrinsicOperation(JSContext * cx,HandleScript script,jsbytecode * pc,MutableHandleValue vp)223 inline bool GetIntrinsicOperation(JSContext* cx, HandleScript script,
224 jsbytecode* pc, MutableHandleValue vp) {
225 RootedPropertyName name(cx, script->getName(pc));
226 return GlobalObject::getIntrinsicValue(cx, cx->global(), name, vp);
227 }
228
SetIntrinsicOperation(JSContext * cx,JSScript * script,jsbytecode * pc,HandleValue val)229 inline bool SetIntrinsicOperation(JSContext* cx, JSScript* script,
230 jsbytecode* pc, HandleValue val) {
231 RootedPropertyName name(cx, script->getName(pc));
232 return GlobalObject::setIntrinsicValue(cx, cx->global(), name, val);
233 }
234
SetAliasedVarOperation(JSContext * cx,JSScript * script,jsbytecode * pc,EnvironmentObject & obj,EnvironmentCoordinate ec,const Value & val,MaybeCheckTDZ checkTDZ)235 inline void SetAliasedVarOperation(JSContext* cx, JSScript* script,
236 jsbytecode* pc, EnvironmentObject& obj,
237 EnvironmentCoordinate ec, const Value& val,
238 MaybeCheckTDZ checkTDZ) {
239 MOZ_ASSERT_IF(checkTDZ, !IsUninitializedLexical(obj.aliasedBinding(ec)));
240 obj.setAliasedBinding(cx, ec, val);
241 }
242
SetNameOperation(JSContext * cx,JSScript * script,jsbytecode * pc,HandleObject env,HandleValue val)243 inline bool SetNameOperation(JSContext* cx, JSScript* script, jsbytecode* pc,
244 HandleObject env, HandleValue val) {
245 MOZ_ASSERT(JSOp(*pc) == JSOp::SetName || JSOp(*pc) == JSOp::StrictSetName ||
246 JSOp(*pc) == JSOp::SetGName || JSOp(*pc) == JSOp::StrictSetGName);
247 MOZ_ASSERT_IF(
248 (JSOp(*pc) == JSOp::SetGName || JSOp(*pc) == JSOp::StrictSetGName) &&
249 !script->hasNonSyntacticScope(),
250 env == cx->global() || env == &cx->global()->lexicalEnvironment() ||
251 env->is<RuntimeLexicalErrorObject>());
252
253 bool strict =
254 JSOp(*pc) == JSOp::StrictSetName || JSOp(*pc) == JSOp::StrictSetGName;
255 RootedPropertyName name(cx, script->getName(pc));
256
257 // In strict mode, assigning to an undeclared global variable is an
258 // error. To detect this, we call NativeSetProperty directly and pass
259 // Unqualified. It stores the error, if any, in |result|.
260 bool ok;
261 ObjectOpResult result;
262 RootedId id(cx, NameToId(name));
263 RootedValue receiver(cx, ObjectValue(*env));
264 if (env->isUnqualifiedVarObj()) {
265 RootedNativeObject varobj(cx);
266 if (env->is<DebugEnvironmentProxy>()) {
267 varobj =
268 &env->as<DebugEnvironmentProxy>().environment().as<NativeObject>();
269 } else {
270 varobj = &env->as<NativeObject>();
271 }
272 MOZ_ASSERT(!varobj->getOpsSetProperty());
273 ok = NativeSetProperty<Unqualified>(cx, varobj, id, val, receiver, result);
274 } else {
275 ok = SetProperty(cx, env, id, val, receiver, result);
276 }
277 return ok && result.checkStrictModeError(cx, env, id, strict);
278 }
279
InitGlobalLexicalOperation(JSContext * cx,ExtensibleLexicalEnvironmentObject * lexicalEnv,JSScript * script,jsbytecode * pc,HandleValue value)280 inline void InitGlobalLexicalOperation(
281 JSContext* cx, ExtensibleLexicalEnvironmentObject* lexicalEnv,
282 JSScript* script, jsbytecode* pc, HandleValue value) {
283 MOZ_ASSERT_IF(!script->hasNonSyntacticScope(),
284 lexicalEnv == &cx->global()->lexicalEnvironment());
285 MOZ_ASSERT(JSOp(*pc) == JSOp::InitGLexical);
286
287 mozilla::Maybe<PropertyInfo> prop =
288 lexicalEnv->lookup(cx, script->getName(pc));
289 MOZ_ASSERT(prop.isSome());
290 MOZ_ASSERT(IsUninitializedLexical(lexicalEnv->getSlot(prop->slot())));
291
292 lexicalEnv->setSlot(prop->slot(), value);
293 }
294
InitPropertyOperation(JSContext * cx,JSOp op,HandleObject obj,HandlePropertyName name,HandleValue rhs)295 inline bool InitPropertyOperation(JSContext* cx, JSOp op, HandleObject obj,
296 HandlePropertyName name, HandleValue rhs) {
297 unsigned propAttrs = GetInitDataPropAttrs(op);
298 return DefineDataProperty(cx, obj, name, rhs, propAttrs);
299 }
300
NegOperation(JSContext * cx,MutableHandleValue val,MutableHandleValue res)301 static MOZ_ALWAYS_INLINE bool NegOperation(JSContext* cx,
302 MutableHandleValue val,
303 MutableHandleValue res) {
304 /*
305 * When the operand is int jsval, INT32_FITS_IN_JSVAL(i) implies
306 * INT32_FITS_IN_JSVAL(-i) unless i is 0 or INT32_MIN when the
307 * results, -0.0 or INT32_MAX + 1, are double values.
308 */
309 int32_t i;
310 if (val.isInt32() && (i = val.toInt32()) != 0 && i != INT32_MIN) {
311 res.setInt32(-i);
312 return true;
313 }
314
315 if (!ToNumeric(cx, val)) {
316 return false;
317 }
318
319 if (val.isBigInt()) {
320 return BigInt::negValue(cx, val, res);
321 }
322
323 res.setNumber(-val.toNumber());
324 return true;
325 }
326
IncOperation(JSContext * cx,HandleValue val,MutableHandleValue res)327 static MOZ_ALWAYS_INLINE bool IncOperation(JSContext* cx, HandleValue val,
328 MutableHandleValue res) {
329 int32_t i;
330 if (val.isInt32() && (i = val.toInt32()) != INT32_MAX) {
331 res.setInt32(i + 1);
332 return true;
333 }
334
335 if (val.isNumber()) {
336 res.setNumber(val.toNumber() + 1);
337 return true;
338 }
339
340 MOZ_ASSERT(val.isBigInt(), "+1 only callable on result of JSOp::ToNumeric");
341 return BigInt::incValue(cx, val, res);
342 }
343
DecOperation(JSContext * cx,HandleValue val,MutableHandleValue res)344 static MOZ_ALWAYS_INLINE bool DecOperation(JSContext* cx, HandleValue val,
345 MutableHandleValue res) {
346 int32_t i;
347 if (val.isInt32() && (i = val.toInt32()) != INT32_MIN) {
348 res.setInt32(i - 1);
349 return true;
350 }
351
352 if (val.isNumber()) {
353 res.setNumber(val.toNumber() - 1);
354 return true;
355 }
356
357 MOZ_ASSERT(val.isBigInt(), "-1 only callable on result of JSOp::ToNumeric");
358 return BigInt::decValue(cx, val, res);
359 }
360
ToPropertyKeyOperation(JSContext * cx,HandleValue idval,MutableHandleValue res)361 static MOZ_ALWAYS_INLINE bool ToPropertyKeyOperation(JSContext* cx,
362 HandleValue idval,
363 MutableHandleValue res) {
364 if (idval.isInt32()) {
365 res.set(idval);
366 return true;
367 }
368
369 RootedId id(cx);
370 if (!ToPropertyKey(cx, idval, &id)) {
371 return false;
372 }
373
374 res.set(IdToValue(id));
375 return true;
376 }
377
GetObjectElementOperation(JSContext * cx,JSOp op,JS::HandleObject obj,JS::HandleValue receiver,HandleValue key,MutableHandleValue res)378 static MOZ_ALWAYS_INLINE bool GetObjectElementOperation(
379 JSContext* cx, JSOp op, JS::HandleObject obj, JS::HandleValue receiver,
380 HandleValue key, MutableHandleValue res) {
381 MOZ_ASSERT(op == JSOp::GetElem || op == JSOp::GetElemSuper);
382 MOZ_ASSERT_IF(op == JSOp::GetElem, obj == &receiver.toObject());
383
384 do {
385 uint32_t index;
386 if (IsDefinitelyIndex(key, &index)) {
387 if (GetElementNoGC(cx, obj, receiver, index, res.address())) {
388 break;
389 }
390
391 if (!GetElement(cx, obj, receiver, index, res)) {
392 return false;
393 }
394 break;
395 }
396
397 if (key.isString()) {
398 JSString* str = key.toString();
399 JSAtom* name = str->isAtom() ? &str->asAtom() : AtomizeString(cx, str);
400 if (!name) {
401 return false;
402 }
403 if (name->isIndex(&index)) {
404 if (GetElementNoGC(cx, obj, receiver, index, res.address())) {
405 break;
406 }
407 } else {
408 if (GetPropertyNoGC(cx, obj, receiver, name->asPropertyName(),
409 res.address())) {
410 break;
411 }
412 }
413 }
414
415 RootedId id(cx);
416 if (!ToPropertyKey(cx, key, &id)) {
417 return false;
418 }
419 if (!GetProperty(cx, obj, receiver, id, res)) {
420 return false;
421 }
422 } while (false);
423
424 cx->debugOnlyCheck(res);
425 return true;
426 }
427
GetPrimitiveElementOperation(JSContext * cx,JS::HandleValue receiver,int receiverIndex,HandleValue key,MutableHandleValue res)428 static MOZ_ALWAYS_INLINE bool GetPrimitiveElementOperation(
429 JSContext* cx, JS::HandleValue receiver, int receiverIndex, HandleValue key,
430 MutableHandleValue res) {
431 // FIXME: Bug 1234324 We shouldn't be boxing here.
432 RootedObject boxed(
433 cx, ToObjectFromStackForPropertyAccess(cx, receiver, receiverIndex, key));
434 if (!boxed) {
435 return false;
436 }
437
438 do {
439 uint32_t index;
440 if (IsDefinitelyIndex(key, &index)) {
441 if (GetElementNoGC(cx, boxed, receiver, index, res.address())) {
442 break;
443 }
444
445 if (!GetElement(cx, boxed, receiver, index, res)) {
446 return false;
447 }
448 break;
449 }
450
451 if (key.isString()) {
452 JSString* str = key.toString();
453 JSAtom* name = str->isAtom() ? &str->asAtom() : AtomizeString(cx, str);
454 if (!name) {
455 return false;
456 }
457 if (name->isIndex(&index)) {
458 if (GetElementNoGC(cx, boxed, receiver, index, res.address())) {
459 break;
460 }
461 } else {
462 if (GetPropertyNoGC(cx, boxed, receiver, name->asPropertyName(),
463 res.address())) {
464 break;
465 }
466 }
467 }
468
469 RootedId id(cx);
470 if (!ToPropertyKey(cx, key, &id)) {
471 return false;
472 }
473 if (!GetProperty(cx, boxed, receiver, id, res)) {
474 return false;
475 }
476 } while (false);
477
478 cx->debugOnlyCheck(res);
479 return true;
480 }
481
GetElementOperationWithStackIndex(JSContext * cx,HandleValue lref,int lrefIndex,HandleValue rref,MutableHandleValue res)482 static MOZ_ALWAYS_INLINE bool GetElementOperationWithStackIndex(
483 JSContext* cx, HandleValue lref, int lrefIndex, HandleValue rref,
484 MutableHandleValue res) {
485 uint32_t index;
486 if (lref.isString() && IsDefinitelyIndex(rref, &index)) {
487 JSString* str = lref.toString();
488 if (index < str->length()) {
489 str = cx->staticStrings().getUnitStringForElement(cx, str, index);
490 if (!str) {
491 return false;
492 }
493 res.setString(str);
494 return true;
495 }
496 }
497
498 if (lref.isPrimitive()) {
499 RootedValue thisv(cx, lref);
500 return GetPrimitiveElementOperation(cx, thisv, lrefIndex, rref, res);
501 }
502
503 RootedObject obj(cx, &lref.toObject());
504 RootedValue thisv(cx, lref);
505 return GetObjectElementOperation(cx, JSOp::GetElem, obj, thisv, rref, res);
506 }
507
508 // Wrapper for callVM from JIT.
GetElementOperation(JSContext * cx,HandleValue lref,HandleValue rref,MutableHandleValue res)509 static MOZ_ALWAYS_INLINE bool GetElementOperation(JSContext* cx,
510 HandleValue lref,
511 HandleValue rref,
512 MutableHandleValue res) {
513 return GetElementOperationWithStackIndex(cx, lref, JSDVG_SEARCH_STACK, rref,
514 res);
515 }
516
TypeOfOperation(const Value & v,JSRuntime * rt)517 static MOZ_ALWAYS_INLINE JSString* TypeOfOperation(const Value& v,
518 JSRuntime* rt) {
519 JSType type = js::TypeOfValue(v);
520 return TypeName(type, *rt->commonNames);
521 }
522
InitElemOperation(JSContext * cx,jsbytecode * pc,HandleObject obj,HandleValue idval,HandleValue val)523 static MOZ_ALWAYS_INLINE bool InitElemOperation(JSContext* cx, jsbytecode* pc,
524 HandleObject obj,
525 HandleValue idval,
526 HandleValue val) {
527 MOZ_ASSERT(!val.isMagic(JS_ELEMENTS_HOLE));
528
529 RootedId id(cx);
530 if (!ToPropertyKey(cx, idval, &id)) {
531 return false;
532 }
533
534 unsigned flags = GetInitDataPropAttrs(JSOp(*pc));
535 if (id.isPrivateName()) {
536 // Clear enumerate flag off of private names.
537 flags &= ~JSPROP_ENUMERATE;
538 }
539 return DefineDataProperty(cx, obj, id, val, flags);
540 }
541
CheckPrivateFieldOperation(JSContext * cx,jsbytecode * pc,HandleValue val,HandleValue idval,bool * result)542 static MOZ_ALWAYS_INLINE bool CheckPrivateFieldOperation(JSContext* cx,
543 jsbytecode* pc,
544 HandleValue val,
545 HandleValue idval,
546 bool* result) {
547 // Result had better not be a nullptr.
548 MOZ_ASSERT(result);
549
550 ThrowCondition condition;
551 ThrowMsgKind msgKind;
552 GetCheckPrivateFieldOperands(pc, &condition, &msgKind);
553
554 // When we are using OnlyCheckRhs, we are implementing PrivateInExpr
555 // This requires we throw if the rhs is not an object;
556 //
557 // The InlineCache for CheckPrivateField already checks for a
558 // non-object rhs and refuses to attach in that circumstance.
559 if (condition == ThrowCondition::OnlyCheckRhs) {
560 if (!val.isObject()) {
561 ReportInNotObjectError(cx, idval, val);
562 return false;
563 }
564 }
565
566 // js::DumpValue(idval.get());
567 // js::DumpValue(val.get());
568
569 MOZ_ASSERT(idval.isSymbol());
570 MOZ_ASSERT(idval.toSymbol()->isPrivateName());
571
572 if (!HasOwnProperty(cx, val, idval, result)) {
573 return false;
574 }
575
576 if (!CheckPrivateFieldWillThrow(condition, *result)) {
577 return true;
578 }
579
580 // Throw!
581 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
582 ThrowMsgKindToErrNum(msgKind));
583 return false;
584 }
585
InitElemIncOperation(JSContext * cx,HandleArrayObject arr,uint32_t index,HandleValue val)586 inline bool InitElemIncOperation(JSContext* cx, HandleArrayObject arr,
587 uint32_t index, HandleValue val) {
588 if (index == INT32_MAX) {
589 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
590 JSMSG_SPREAD_TOO_LARGE);
591 return false;
592 }
593
594 // If val is a hole, do not call DefineDataElement.
595 if (val.isMagic(JS_ELEMENTS_HOLE)) {
596 // Always call SetLengthProperty even if this is not the last element
597 // initialiser, because this may be followed by a SpreadElement loop,
598 // which will not set the array length if nothing is spread.
599 return SetLengthProperty(cx, arr, index + 1);
600 }
601
602 return DefineDataElement(cx, arr, index, val, JSPROP_ENUMERATE);
603 }
604
ProcessCallSiteObjOperation(JSContext * cx,HandleScript script,jsbytecode * pc)605 static inline ArrayObject* ProcessCallSiteObjOperation(JSContext* cx,
606 HandleScript script,
607 jsbytecode* pc) {
608 MOZ_ASSERT(JSOp(*pc) == JSOp::CallSiteObj);
609
610 RootedArrayObject cso(cx, &script->getObject(pc)->as<ArrayObject>());
611
612 if (cso->isExtensible()) {
613 RootedObject raw(cx, script->getObject(GET_GCTHING_INDEX(pc).next()));
614 MOZ_ASSERT(raw->is<ArrayObject>());
615
616 RootedValue rawValue(cx, ObjectValue(*raw));
617 if (!DefineDataProperty(cx, cso, cx->names().raw, rawValue, 0)) {
618 return nullptr;
619 }
620 if (!FreezeObject(cx, raw)) {
621 return nullptr;
622 }
623 if (!FreezeObject(cx, cso)) {
624 return nullptr;
625 }
626 }
627
628 return cso;
629 }
630
631 inline JSFunction* ReportIfNotFunction(
632 JSContext* cx, HandleValue v, MaybeConstruct construct = NO_CONSTRUCT) {
633 if (v.isObject() && v.toObject().is<JSFunction>()) {
634 return &v.toObject().as<JSFunction>();
635 }
636
637 ReportIsNotFunction(cx, v, -1, construct);
638 return nullptr;
639 }
640
641 } /* namespace js */
642
643 #endif /* vm_Interpreter_inl_h */
644