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_PlainObject_inl_h
8 #define vm_PlainObject_inl_h
9 
10 #include "vm/PlainObject.h"
11 
12 #include "mozilla/Assertions.h"  // MOZ_ASSERT, MOZ_ASSERT_IF
13 #include "mozilla/Attributes.h"  // MOZ_ALWAYS_INLINE
14 
15 #include "gc/Allocator.h"     // js::gc::InitialHeap
16 #include "js/RootingAPI.h"    // JS::Handle, JS::Rooted, JS::MutableHandle
17 #include "js/Value.h"         // JS::Value, JS_IS_CONSTRUCTING
18 #include "vm/JSFunction.h"    // JSFunction
19 #include "vm/JSObject.h"      // js::GenericObject, js::NewObjectKind
20 #include "vm/NativeObject.h"  // js::NativeObject::create
21 #include "vm/Shape.h"         // js::Shape
22 
23 #include "gc/ObjectKind-inl.h"  // js::gc::GetGCObjectKind
24 #include "vm/JSObject-inl.h"  // js::GetInitialHeap, js::NewBuiltinClassInstance
25 #include "vm/NativeObject-inl.h"  // js::NativeObject::{create,setLastProperty}
26 
27 /* static */ inline JS::Result<js::PlainObject*, JS::OOM>
createWithShape(JSContext * cx,JS::Handle<Shape * > shape)28 js::PlainObject::createWithShape(JSContext* cx, JS::Handle<Shape*> shape) {
29   MOZ_ASSERT(shape->getObjectClass() == &PlainObject::class_);
30   gc::InitialHeap heap = GetInitialHeap(GenericObject, &PlainObject::class_);
31 
32   gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
33   MOZ_ASSERT(gc::CanChangeToBackgroundAllocKind(kind, shape->getObjectClass()));
34   kind = gc::ForegroundToBackgroundAllocKind(kind);
35 
36   return NativeObject::create(cx, kind, heap, shape).map([](NativeObject* obj) {
37     return &obj->as<PlainObject>();
38   });
39 }
40 
41 /* static */ inline JS::Result<js::PlainObject*, JS::OOM>
createWithTemplate(JSContext * cx,JS::Handle<PlainObject * > templateObject)42 js::PlainObject::createWithTemplate(JSContext* cx,
43                                     JS::Handle<PlainObject*> templateObject) {
44   JS::Rooted<Shape*> shape(cx, templateObject->shape());
45   return createWithShape(cx, shape);
46 }
47 
allocKindForTenure()48 inline js::gc::AllocKind js::PlainObject::allocKindForTenure() const {
49   gc::AllocKind kind = gc::GetGCObjectFixedSlotsKind(numFixedSlots());
50   MOZ_ASSERT(!gc::IsBackgroundFinalized(kind));
51   MOZ_ASSERT(gc::CanChangeToBackgroundAllocKind(kind, getClass()));
52   return gc::ForegroundToBackgroundAllocKind(kind);
53 }
54 
55 namespace js {
56 
57 // Create an object based on a template object created for either a NewObject
58 // bytecode op or for a constructor call.
59 static inline PlainObject* CopyTemplateObject(
60     JSContext* cx, JS::Handle<PlainObject*> baseobj,
61     NewObjectKind newKind = GenericObject) {
62   MOZ_ASSERT(!baseobj->inDictionaryMode());
63 
64   gc::AllocKind allocKind =
65       gc::GetGCObjectFixedSlotsKind(baseobj->numFixedSlots());
66   allocKind = gc::ForegroundToBackgroundAllocKind(allocKind);
67   MOZ_ASSERT_IF(baseobj->isTenured(),
68                 allocKind == baseobj->asTenured().getAllocKind());
69   RootedObject proto(cx, baseobj->staticPrototype());
70   JS::Rooted<PlainObject*> obj(cx, NewObjectWithGivenProtoAndKinds<PlainObject>(
71                                        cx, proto, allocKind, newKind));
72   if (!obj) {
73     return nullptr;
74   }
75 
76   if (!obj->setShapeAndUpdateSlots(cx, baseobj->shape())) {
77     return nullptr;
78   }
79 
80   return obj;
81 }
82 
CreateThis(JSContext * cx,JS::Handle<JSFunction * > callee,JS::Handle<JSObject * > newTarget,NewObjectKind newKind,JS::MutableHandle<JS::Value> thisv)83 static MOZ_ALWAYS_INLINE bool CreateThis(JSContext* cx,
84                                          JS::Handle<JSFunction*> callee,
85                                          JS::Handle<JSObject*> newTarget,
86                                          NewObjectKind newKind,
87                                          JS::MutableHandle<JS::Value> thisv) {
88   if (callee->constructorNeedsUninitializedThis()) {
89     thisv.setMagic(JS_UNINITIALIZED_LEXICAL);
90     return true;
91   }
92 
93   MOZ_ASSERT(thisv.isMagic(JS_IS_CONSTRUCTING));
94 
95   PlainObject* obj = CreateThisForFunction(cx, callee, newTarget, newKind);
96   if (!obj) {
97     return false;
98   }
99 
100   MOZ_ASSERT(obj->nonCCWRealm() == callee->realm());
101   thisv.setObject(*obj);
102   return true;
103 }
104 
105 }  // namespace js
106 
107 #endif  // vm_PlainObject_inl_h
108