Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/js/src/vm/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 10 kB image not shown  

Quelle  PlainObject.cpp   Sprache: C

 
/* -*- 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/. */


/*
 * JS object implementation.
 */


#include "vm/PlainObject-inl.h"

#include "mozilla/Assertions.h"  // MOZ_ASSERT

#include "jspubtd.h"  // JSProto_Object

#include "ds/IdValuePair.h"  // js::IdValuePair
#include "gc/AllocKind.h"    // js::gc::AllocKind
#include "vm/JSContext.h"    // JSContext
#include "vm/JSFunction.h"   // JSFunction
#include "vm/JSObject.h"     // JSObject, js::GetPrototypeFromConstructor
#include "vm/TaggedProto.h"  // js::TaggedProto

#include "vm/JSFunction-inl.h"
#include "vm/JSObject-inl.h"  // js::NewObjectWithGroup, js::NewObjectGCKind

using namespace js;

using JS::Handle;
using JS::Rooted;

static MOZ_ALWAYS_INLINE SharedShape* GetPlainObjectShapeWithProto(
    JSContext* cx, JSObject* proto, gc::AllocKind kind) {
  MOZ_ASSERT(JSCLASS_RESERVED_SLOTS(&PlainObject::class_) == 0,
             "all slots can be used for properties");
  uint32_t nfixed = GetGCKindSlots(kind);
  return SharedShape::getInitialShape(cx, &PlainObject::class_, cx->realm(),
                                      TaggedProto(proto), nfixed);
}

SharedShape* js::ThisShapeForFunction(JSContext* cx, Handle<JSFunction*> callee,
                                      Handle<JSObject*> newTarget) {
  MOZ_ASSERT(cx->realm() == callee->realm());
  MOZ_ASSERT(!callee->constructorNeedsUninitializedThis());

  Rooted<JSObject*> proto(cx);
  if (!GetPrototypeFromConstructor(cx, newTarget, JSProto_Object, &proto)) {
    return nullptr;
  }

  js::gc::AllocKind allocKind = NewObjectGCKind();
  if (!JSFunction::getAllocKindForThis(cx, callee, allocKind)) {
    return nullptr;
  }

  SharedShape* res;
  if (proto && proto != cx->global()->maybeGetPrototype(JSProto_Object)) {
    res = GetPlainObjectShapeWithProto(cx, proto, allocKind);
  } else {
    res = GlobalObject::getPlainObjectShapeWithDefaultProto(cx, allocKind);
  }

  MOZ_ASSERT_IF(res, res->realm() == callee->realm());

  return res;
}

#ifdef DEBUG
void PlainObject::assertHasNoNonWritableOrAccessorPropExclProto() const {
  // Check the most recent MaxCount properties to not slow down debug builds too
  // much.
  static constexpr size_t MaxCount = 8;

  size_t count = 0;
  PropertyName* protoName = runtimeFromMainThread()->commonNames->proto_;

  for (ShapePropertyIter<NoGC> iter(shape()); !iter.done(); iter++) {
    // __proto__ is always allowed.
    if (iter->key().isAtom(protoName)) {
      continue;
    }

    MOZ_ASSERT(iter->isDataProperty());
    MOZ_ASSERT(iter->writable());

    count++;
    if (count > MaxCount) {
      return;
    }
  }
}
#endif

// static
PlainObject* PlainObject::createWithTemplateFromDifferentRealm(
    JSContext* cx, Handle<PlainObject*> templateObject) {
  MOZ_ASSERT(cx->realm() != templateObject->realm(),
             "Use createWithTemplate() for same-realm objects");

  // Currently only implemented for null-proto.
  MOZ_ASSERT(templateObject->staticPrototype() == nullptr);

  // The object mustn't be in dictionary mode.
  MOZ_ASSERT(!templateObject->shape()->isDictionary());

  TaggedProto proto = TaggedProto(nullptr);
  SharedShape* templateShape = templateObject->sharedShape();
  Rooted<SharedPropMap*> map(cx, templateShape->propMap());

  Rooted<SharedShape*> shape(
      cx, SharedShape::getInitialOrPropMapShape(
              cx, &PlainObject::class_, cx->realm(), proto,
              templateShape->numFixedSlots(), map,
              templateShape->propMapLength(), templateShape->objectFlags()));
  if (!shape) {
    return nullptr;
  }
  return createWithShape(cx, shape);
}

// static
SharedShape* GlobalObject::createPlainObjectShapeWithDefaultProto(
    JSContext* cx, gc::AllocKind kind) {
  PlainObjectSlotsKind slotsKind = PlainObjectSlotsKindFromAllocKind(kind);
  GCPtr<SharedShape*>& shapeRef =
      cx->global()->data().plainObjectShapesWithDefaultProto[slotsKind];
  MOZ_ASSERT(!shapeRef);

  JSObject* proto = &cx->global()->getObjectPrototype();
  SharedShape* shape = GetPlainObjectShapeWithProto(cx, proto, kind);
  if (!shape) {
    return nullptr;
  }

  shapeRef.init(shape);
  return shape;
}

PlainObject* js::NewPlainObject(JSContext* cx, NewObjectKind newKind) {
  constexpr gc::AllocKind allocKind = gc::AllocKind::OBJECT0;
  MOZ_ASSERT(gc::GetGCObjectKind(&PlainObject::class_) == allocKind);

  Rooted<SharedShape*> shape(
      cx, GlobalObject::getPlainObjectShapeWithDefaultProto(cx, allocKind));
  if (!shape) {
    return nullptr;
  }

  return PlainObject::createWithShape(cx, shape, allocKind, newKind);
}

PlainObject* js::NewPlainObjectWithAllocKind(JSContext* cx,
                                             gc::AllocKind allocKind,
                                             NewObjectKind newKind) {
  Rooted<SharedShape*> shape(
      cx, GlobalObject::getPlainObjectShapeWithDefaultProto(cx, allocKind));
  if (!shape) {
    return nullptr;
  }

  return PlainObject::createWithShape(cx, shape, allocKind, newKind);
}

PlainObject* js::NewPlainObjectWithProto(JSContext* cx, HandleObject proto,
                                         NewObjectKind newKind) {
  // Use a faster path if |proto| is %Object.prototype% (the common case).
  if (proto && proto == cx->global()->maybeGetPrototype(JSProto_Object)) {
    return NewPlainObject(cx, newKind);
  }

  constexpr gc::AllocKind allocKind = gc::AllocKind::OBJECT0;
  MOZ_ASSERT(gc::GetGCObjectKind(&PlainObject::class_) == allocKind);

  Rooted<SharedShape*> shape(
      cx, GetPlainObjectShapeWithProto(cx, proto, allocKind));
  if (!shape) {
    return nullptr;
  }

  return PlainObject::createWithShape(cx, shape, allocKind, newKind);
}

PlainObject* js::NewPlainObjectWithProtoAndAllocKind(JSContext* cx,
                                                     HandleObject proto,
                                                     gc::AllocKind allocKind,
                                                     NewObjectKind newKind) {
  // Use a faster path if |proto| is %Object.prototype% (the common case).
  if (proto && proto == cx->global()->maybeGetPrototype(JSProto_Object)) {
    return NewPlainObjectWithAllocKind(cx, allocKind, newKind);
  }

  Rooted<SharedShape*> shape(
      cx, GetPlainObjectShapeWithProto(cx, proto, allocKind));
  if (!shape) {
    return nullptr;
  }

  return PlainObject::createWithShape(cx, shape, allocKind, newKind);
}

void js::NewPlainObjectWithPropsCache::add(SharedShape* shape) {
  MOZ_ASSERT(shape);
  MOZ_ASSERT(shape->slotSpan() > 0);
  for (size_t i = NumEntries - 1; i > 0; i--) {
    entries_[i] = entries_[i - 1];
  }
  entries_[0] = shape;
}

static bool ShapeMatches(Handle<IdValueVector> properties, SharedShape* shape) {
  if (shape->slotSpan() != properties.length()) {
    return false;
  }
  SharedShapePropertyIter<NoGC> iter(shape);
  for (size_t i = properties.length(); i > 0; i--) {
    MOZ_ASSERT(iter->isDataProperty());
    MOZ_ASSERT(iter->flags() == PropertyFlags::defaultDataPropFlags);
    if (properties[i - 1].get().id != iter->key()) {
      return false;
    }
    iter++;
  }
  MOZ_ASSERT(iter.done());
  return true;
}

SharedShape* js::NewPlainObjectWithPropsCache::lookup(
    Handle<IdValueVector> properties) const {
  for (size_t i = 0; i < NumEntries; i++) {
    SharedShape* shape = entries_[i];
    if (shape && ShapeMatches(properties, shape)) {
      return shape;
    }
  }
  return nullptr;
}

enum class KeysKind { UniqueNames, Unknown };

template <KeysKind Kind>
static PlainObject* NewPlainObjectWithProperties(
    JSContext* cx, Handle<IdValueVector> properties, NewObjectKind newKind) {
  auto& cache = cx->realm()->newPlainObjectWithPropsCache;

  // If we recently created an object with these properties, we can use that
  // Shape directly.
  if (SharedShape* shape = cache.lookup(properties)) {
    Rooted<SharedShape*> shapeRoot(cx, shape);
    PlainObject* obj = PlainObject::createWithShape(cx, shapeRoot, newKind);
    if (!obj) {
      return nullptr;
    }
    MOZ_ASSERT(obj->slotSpan() == properties.length());
    for (size_t i = 0; i < properties.length(); i++) {
      obj->initSlot(i, properties[i].get().value);
    }
    return obj;
  }

  gc::AllocKind allocKind = gc::GetGCObjectKind(properties.length());
  Rooted<PlainObject*> obj(cx,
                           NewPlainObjectWithAllocKind(cx, allocKind, newKind));
  if (!obj) {
    return nullptr;
  }

  if (properties.empty()) {
    return obj;
  }

  Rooted<PropertyKey> key(cx);
  Rooted<Value> value(cx);
  bool canCache = true;

  for (const auto& prop : properties) {
    key = prop.id;
    value = prop.value;

    // Integer keys may need to be stored in dense elements. This is uncommon so
    // just fall back to NativeDefineDataProperty.
    if constexpr (Kind == KeysKind::Unknown) {
      if (MOZ_UNLIKELY(key.isInt())) {
        canCache = false;
        if (!NativeDefineDataProperty(cx, obj, key, value, JSPROP_ENUMERATE)) {
          return nullptr;
        }
        continue;
      }
    }

    MOZ_ASSERT(key.isAtom() || key.isSymbol());

    // Check for duplicate keys. In this case we must overwrite the earlier
    // property value.
    if constexpr (Kind == KeysKind::UniqueNames) {
      MOZ_ASSERT(!obj->containsPure(key));
    } else {
      mozilla::Maybe<PropertyInfo> prop = obj->lookup(cx, key);
      if (MOZ_UNLIKELY(prop)) {
        canCache = false;
        MOZ_ASSERT(prop->isDataProperty());
        obj->setSlot(prop->slot(), value);
        continue;
      }
    }

    if (!AddDataPropertyToPlainObject(cx, obj, key, value)) {
      return nullptr;
    }
  }

  if (canCache && !obj->inDictionaryMode()) {
    MOZ_ASSERT(obj->getDenseInitializedLength() == 0);
    MOZ_ASSERT(obj->slotSpan() == properties.length());
    cache.add(obj->sharedShape());
  }

  return obj;
}

PlainObject* js::NewPlainObjectWithUniqueNames(JSContext* cx,
                                               Handle<IdValueVector> properties,
                                               NewObjectKind newKind) {
  return NewPlainObjectWithProperties<KeysKind::UniqueNames>(cx, properties,
                                                             newKind);
}

PlainObject* js::NewPlainObjectWithMaybeDuplicateKeys(
    JSContext* cx, Handle<IdValueVector> properties, NewObjectKind newKind) {
  return NewPlainObjectWithProperties<KeysKind::Unknown>(cx, properties,
                                                         newKind);
}

Messung V0.5
C=95 H=97 G=95

¤ Dauer der Verarbeitung: 0.14 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.