String HeapSnapshotBuilder::descriptionForCell(JSCell *cell) const { if (cell->isString()) return emptyString(); // FIXME: get part of string. VM& vm = m_profiler.vm(); Structure* structure = cell->structure(vm); if (structure->classInfo()->isSubClassOf(Structure::info())) { Structure* cellAsStructure = jsCast<Structure*>(cell); return cellAsStructure->classInfo()->className; } return emptyString(); }
inline Structure* getBoundFunctionStructure(VM& vm, ExecState* exec, JSGlobalObject* globalObject, JSObject* targetFunction) { auto scope = DECLARE_THROW_SCOPE(vm); JSValue prototype = targetFunction->getPrototype(vm, exec); RETURN_IF_EXCEPTION(scope, nullptr); JSFunction* targetJSFunction = jsDynamicCast<JSFunction*>(vm, targetFunction); // We only cache the structure of the bound function if the bindee is a JSFunction since there // isn't any good place to put the structure on Internal Functions. if (targetJSFunction) { Structure* structure = targetJSFunction->rareData(vm)->getBoundFunctionStructure(); if (structure && structure->storedPrototype() == prototype && structure->globalObject() == globalObject) return structure; } Structure* result = globalObject->boundFunctionStructure(); // It would be nice if the structure map was keyed global objects in addition to the other things. Unfortunately, it is not // currently. Whoever works on caching structure changes for prototype transistions should consider this problem as well. // See: https://bugs.webkit.org/show_bug.cgi?id=152738 if (prototype.isObject() && prototype.getObject()->globalObject() == globalObject) { result = vm.prototypeMap.emptyStructureForPrototypeFromBaseStructure(globalObject, prototype.getObject(), result); ASSERT_WITH_SECURITY_IMPLICATION(result->globalObject() == globalObject); } else result = Structure::create(vm, globalObject, prototype, result->typeInfo(), result->classInfo()); if (targetJSFunction) targetJSFunction->rareData(vm)->setBoundFunctionStructure(vm, result); return result; }
// In future we may want to cache this transition. Structure* Structure::freezeTransition(VM& vm, Structure* structure) { Structure* transition = preventExtensionsTransition(vm, structure); if (transition->propertyTable()) { PropertyTable::iterator iter = transition->propertyTable()->begin(); PropertyTable::iterator end = transition->propertyTable()->end(); if (iter != end) transition->setHasReadOnlyOrGetterSetterPropertiesExcludingProto(true); for (; iter != end; ++iter) iter->attributes |= iter->attributes & Accessor ? DontDelete : (DontDelete | ReadOnly); } ASSERT(transition->hasReadOnlyOrGetterSetterPropertiesExcludingProto() || !transition->classInfo()->hasStaticSetterOrReadonlyProperties()); ASSERT(transition->hasGetterSetterProperties() || !transition->classInfo()->hasStaticSetterOrReadonlyProperties()); transition->checkOffsetConsistency(); return transition; }
void HeapVerifier::reportObject(LiveObjectData& objData, int cycleIndex, HeapVerifier::GCCycle& cycle, LiveObjectList& list) { JSObject* obj = objData.obj; if (objData.isConfirmedDead) { dataLogF("FOUND dead obj %p in GC[%d] %s list '%s'\n", obj, cycleIndex, cycle.collectionTypeName(), list.name); return; } Structure* structure = obj->structure(); Butterfly* butterfly = obj->butterfly(); void* butterflyBase; size_t butterflyCapacityInBytes; CopiedBlock* butterflyBlock; getButterflyDetails(obj, butterflyBase, butterflyCapacityInBytes, butterflyBlock); dataLogF("FOUND obj %p type '%s' butterfly %p (base %p size %zu block %p) in GC[%d] %s list '%s'\n", obj, structure->classInfo()->className, butterfly, butterflyBase, butterflyCapacityInBytes, butterflyBlock, cycleIndex, cycle.collectionTypeName(), list.name); }
bool HeapVerifier::verifyButterflyIsInStorageSpace(Phase phase, LiveObjectList& list) { auto& liveObjects = list.liveObjects; CopiedSpace& storageSpace = m_heap->m_storageSpace; bool listNamePrinted = false; bool success = true; for (size_t i = 0; i < liveObjects.size(); i++) { LiveObjectData& objectData = liveObjects[i]; if (objectData.isConfirmedDead) continue; JSObject* obj = objectData.obj; Butterfly* butterfly = obj->butterfly(); if (butterfly) { void* butterflyBase; size_t butterflyCapacityInBytes; CopiedBlock* butterflyBlock; getButterflyDetails(obj, butterflyBase, butterflyCapacityInBytes, butterflyBlock); if (!storageSpace.contains(butterflyBlock)) { if (!listNamePrinted) { dataLogF("Verification @ phase %s FAILED in object list '%s' (size %zu)\n", phaseName(phase), list.name, liveObjects.size()); listNamePrinted = true; } Structure* structure = obj->structure(); const char* structureClassName = structure->classInfo()->className; dataLogF(" butterfly %p (base %p size %zu block %p) NOT in StorageSpace | obj %p type '%s'\n", butterfly, butterflyBase, butterflyCapacityInBytes, butterflyBlock, obj, structureClassName); success = false; } } } return success; }
Structure* InternalFunction::createSubclassStructure(ExecState* exec, JSValue newTarget, Structure* baseClass) { VM& vm = exec->vm(); // We allow newTarget == JSValue() because the API needs to be able to create classes without having a real JS frame. // Since we don't allow subclassing in the API we just treat newTarget == JSValue() as newTarget == exec->callee() ASSERT(!newTarget || newTarget.isConstructor()); if (newTarget && newTarget != exec->callee()) { // newTarget may be an InternalFunction if we were called from Reflect.construct. JSFunction* targetFunction = jsDynamicCast<JSFunction*>(newTarget); if (LIKELY(targetFunction)) { Structure* structure = targetFunction->rareData(vm)->internalFunctionAllocationStructure(); if (LIKELY(structure && structure->classInfo() == baseClass->classInfo())) return structure; // Note, Reflect.construct might cause the profile to churn but we don't care. JSValue prototypeValue = newTarget.get(exec, exec->propertyNames().prototype); if (UNLIKELY(vm.exception())) return nullptr; if (JSObject* prototype = jsDynamicCast<JSObject*>(prototypeValue)) return targetFunction->rareData(vm)->createInternalFunctionAllocationStructureFromBase(vm, prototype, baseClass); } else { JSValue prototypeValue = newTarget.get(exec, exec->propertyNames().prototype); if (UNLIKELY(vm.exception())) return nullptr; if (JSObject* prototype = jsDynamicCast<JSObject*>(prototypeValue)) { // This only happens if someone Reflect.constructs our builtin constructor with another builtin constructor as the new.target. // Thus, we don't care about the cost of looking up the structure from our hash table every time. return vm.prototypeMap.emptyStructureForPrototypeFromBaseStructure(prototype, baseClass); } } } return baseClass; }