summaryrefslogtreecommitdiffstats
path: root/js/src/vm/PlainObject-inl.h
blob: f758915182f5fbbb3b6bd9f6538b49775e3b4331 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sts=2 et sw=2 tw=80:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef vm_PlainObject_inl_h
#define vm_PlainObject_inl_h

#include "vm/PlainObject.h"

#include "mozilla/Assertions.h"  // MOZ_ASSERT, MOZ_ASSERT_IF
#include "mozilla/Attributes.h"  // MOZ_ALWAYS_INLINE

#include "gc/Allocator.h"     // js::gc::InitialHeap
#include "js/RootingAPI.h"    // JS::Handle, JS::Rooted, JS::MutableHandle
#include "js/Value.h"         // JS::Value, JS_IS_CONSTRUCTING
#include "vm/JSFunction.h"    // JSFunction
#include "vm/NativeObject.h"  // js::NativeObject::create
#include "vm/ObjectGroup.h"  // js::ObjectGroup, js::GenericObject, js::NewObjectKind
#include "vm/Shape.h"        // js::Shape

#include "gc/ObjectKind-inl.h"  // js::gc::GetGCObjectKind
#include "vm/JSObject-inl.h"  // js::GetInitialHeap, js::NewBuiltinClassInstance
#include "vm/NativeObject-inl.h"  // js::NativeObject::{create,setLastProperty}

/* static */ inline JS::Result<js::PlainObject*, JS::OOM>
js::PlainObject::createWithTemplate(JSContext* cx,
                                    JS::Handle<PlainObject*> templateObject) {
  JS::Rooted<ObjectGroup*> group(cx, templateObject->group());
  MOZ_ASSERT(group->clasp() == &PlainObject::class_);

  gc::InitialHeap heap = GetInitialHeap(GenericObject, group);

  JS::Rooted<Shape*> shape(cx, templateObject->lastProperty());

  gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
  MOZ_ASSERT(gc::CanChangeToBackgroundAllocKind(kind, shape->getObjectClass()));
  kind = gc::ForegroundToBackgroundAllocKind(kind);

  return NativeObject::create(cx, kind, heap, shape, group)
      .map([](NativeObject* obj) { return &obj->as<PlainObject>(); });
}

inline js::gc::AllocKind js::PlainObject::allocKindForTenure() const {
  gc::AllocKind kind = gc::GetGCObjectFixedSlotsKind(numFixedSlots());
  MOZ_ASSERT(!gc::IsBackgroundFinalized(kind));
  MOZ_ASSERT(gc::CanChangeToBackgroundAllocKind(kind, getClass()));
  return gc::ForegroundToBackgroundAllocKind(kind);
}

namespace js {

// Create an object based on a template object created for either a NewObject
// bytecode op or for a constructor call.
static inline PlainObject* CopyTemplateObject(
    JSContext* cx, JS::Handle<PlainObject*> baseobj,
    NewObjectKind newKind = GenericObject) {
  MOZ_ASSERT(!baseobj->inDictionaryMode());

  gc::AllocKind allocKind =
      gc::GetGCObjectFixedSlotsKind(baseobj->numFixedSlots());
  allocKind = gc::ForegroundToBackgroundAllocKind(allocKind);
  MOZ_ASSERT_IF(baseobj->isTenured(),
                allocKind == baseobj->asTenured().getAllocKind());
  RootedObject proto(cx, baseobj->staticPrototype());
  JS::Rooted<PlainObject*> obj(cx, NewObjectWithGivenProtoAndKinds<PlainObject>(
                                       cx, proto, allocKind, newKind));
  if (!obj) {
    return nullptr;
  }

  if (!obj->setLastProperty(cx, baseobj->lastProperty())) {
    return nullptr;
  }

  return obj;
}

static MOZ_ALWAYS_INLINE bool CreateThis(JSContext* cx,
                                         JS::Handle<JSFunction*> callee,
                                         JS::Handle<JSObject*> newTarget,
                                         NewObjectKind newKind,
                                         JS::MutableHandle<JS::Value> thisv) {
  if (callee->constructorNeedsUninitializedThis()) {
    thisv.setMagic(JS_UNINITIALIZED_LEXICAL);
    return true;
  }

  MOZ_ASSERT(thisv.isMagic(JS_IS_CONSTRUCTING));

  PlainObject* obj = CreateThisForFunction(cx, callee, newTarget, newKind);
  if (!obj) {
    return false;
  }

  MOZ_ASSERT(obj->nonCCWRealm() == callee->realm());
  thisv.setObject(*obj);
  return true;
}

}  // namespace js

#endif  // vm_PlainObject_inl_h