void Structure::materializePropertyMap(VM& vm) { ASSERT(structure()->classInfo() == info()); ASSERT(!propertyTable()); Vector<Structure*, 8> structures; Structure* structure; PropertyTable* table; findStructuresAndMapForMaterialization(structures, structure, table); if (table) { table = table->copy(vm, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity)); structure->m_lock.unlock(); } // Must hold the lock on this structure, since we will be modifying this structure's // property map. We don't want getConcurrently() to see the property map in a half-baked // state. GCSafeConcurrentJITLocker locker(m_lock, vm.heap); if (!table) createPropertyMap(locker, vm, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity)); else propertyTable().set(vm, this, table); InferredTypeTable* typeTable = m_inferredTypeTable.get(); for (size_t i = structures.size(); i--;) { structure = structures[i]; if (!structure->m_nameInPrevious) continue; PropertyMapEntry entry(structure->m_nameInPrevious.get(), structure->m_offset, structure->attributesInPrevious()); if (typeTable && typeTable->get(structure->m_nameInPrevious.get())) entry.hasInferredType = true; propertyTable()->add(entry, m_offset, PropertyTable::PropertyOffsetMustNotChange); } checkOffsetConsistency(); }
Structure* Structure::nonPropertyTransition(VM& vm, Structure* structure, NonPropertyTransition transitionKind) { unsigned attributes = toAttributes(transitionKind); IndexingType indexingType = newIndexingType(structure->indexingTypeIncludingHistory(), transitionKind); if (changesIndexingType(transitionKind)) { if (JSGlobalObject* globalObject = structure->m_globalObject.get()) { if (globalObject->isOriginalArrayStructure(structure)) { Structure* result = globalObject->originalArrayStructureForIndexingType(indexingType); if (result->indexingTypeIncludingHistory() == indexingType) { structure->didTransitionFromThisStructure(); return result; } } } } Structure* existingTransition; if (!structure->isDictionary() && (existingTransition = structure->m_transitionTable.get(0, attributes))) { ASSERT(existingTransition->attributesInPrevious() == attributes); ASSERT(existingTransition->indexingTypeIncludingHistory() == indexingType); return existingTransition; } DeferGC deferGC(vm.heap); Structure* transition = create(vm, structure); transition->setAttributesInPrevious(attributes); transition->m_blob.setIndexingType(indexingType); if (preventsExtensions(transitionKind)) transition->setDidPreventExtensions(true); unsigned additionalPropertyAttributes = 0; if (setsDontDeleteOnAllProperties(transitionKind)) additionalPropertyAttributes |= DontDelete; if (setsReadOnlyOnAllProperties(transitionKind)) additionalPropertyAttributes |= ReadOnly; if (additionalPropertyAttributes) { // We pin the property table on transitions that do wholesale editing of the property // table, since our logic for walking the property transition chain to rematerialize the // table doesn't know how to take into account such wholesale edits. structure->materializePropertyMapIfNecessary(vm, deferGC); transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm)); transition->m_offset = structure->m_offset; transition->pinForCaching(); if (transition->propertyTable()) { for (auto& entry : *transition->propertyTable().get()) entry.attributes |= additionalPropertyAttributes; } } else { transition->propertyTable().set(vm, transition, structure->takePropertyTableOrCloneIfPinned(vm)); transition->m_offset = structure->m_offset; checkOffset(transition->m_offset, transition->inlineCapacity()); } if (setsReadOnlyOnAllProperties(transitionKind) && transition->propertyTable() && !transition->propertyTable()->isEmpty()) transition->setHasReadOnlyOrGetterSetterPropertiesExcludingProto(true); if (structure->isDictionary()) transition->pin(); else { ConcurrentJITLocker locker(structure->m_lock); structure->m_transitionTable.add(vm, transition); } transition->checkOffsetConsistency(); return transition; }