1/*
2 * Copyright (C) 2013-2019 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "StructureCache.h"
28
29#include "JSGlobalObject.h"
30#include "JSCInlines.h"
31#include <wtf/Locker.h>
32
33namespace JSC {
34
35inline Structure* StructureCache::createEmptyStructure(JSGlobalObject* globalObject, JSObject* prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType, unsigned inlineCapacity, bool makePolyProtoStructure, FunctionExecutable* executable)
36{
37 RELEASE_ASSERT(!!prototype); // We use nullptr inside the HashMap for prototype to mean poly proto, so user's of this API must provide non-null prototypes.
38
39 // We don't need to lock here because only the main thread can get here, and only the main thread can mutate the cache
40 PrototypeKey key { makePolyProtoStructure ? nullptr : prototype, executable, inlineCapacity, classInfo, globalObject };
41 if (Structure* structure = m_structures.get(key)) {
42 if (makePolyProtoStructure) {
43 prototype->didBecomePrototype();
44 RELEASE_ASSERT(structure->hasPolyProto());
45 } else
46 RELEASE_ASSERT(structure->hasMonoProto());
47 ASSERT(prototype->mayBePrototype());
48 return structure;
49 }
50
51 prototype->didBecomePrototype();
52
53 VM& vm = globalObject->vm();
54 Structure* structure;
55 if (makePolyProtoStructure) {
56 structure = Structure::create(
57 Structure::PolyProto, vm, globalObject, prototype, typeInfo, classInfo, indexingType, inlineCapacity);
58 } else {
59 structure = Structure::create(
60 vm, globalObject, prototype, typeInfo, classInfo, indexingType, inlineCapacity);
61 }
62 auto locker = holdLock(m_lock);
63 m_structures.set(key, structure);
64 return structure;
65}
66
67Structure* StructureCache::emptyObjectStructureConcurrently(JSGlobalObject* globalObject, JSObject* prototype, unsigned inlineCapacity)
68{
69 RELEASE_ASSERT(!!prototype); // We use nullptr inside the HashMap for prototype to mean poly proto, so user's of this API must provide non-null prototypes.
70
71 PrototypeKey key { prototype, nullptr, inlineCapacity, JSFinalObject::info(), globalObject };
72 auto locker = holdLock(m_lock);
73 if (Structure* structure = m_structures.get(key)) {
74 ASSERT(prototype->mayBePrototype());
75 return structure;
76 }
77 return nullptr;
78}
79
80Structure* StructureCache::emptyStructureForPrototypeFromBaseStructure(JSGlobalObject* globalObject, JSObject* prototype, Structure* baseStructure)
81{
82 // We currently do not have inline capacity static analysis for subclasses and all internal function constructors have a default inline capacity of 0.
83 IndexingType indexingType = baseStructure->indexingType();
84 if (prototype->anyObjectInChainMayInterceptIndexedAccesses(globalObject->vm()) && hasIndexedProperties(indexingType))
85 indexingType = (indexingType & ~IndexingShapeMask) | SlowPutArrayStorageShape;
86
87 return createEmptyStructure(globalObject, prototype, baseStructure->typeInfo(), baseStructure->classInfo(), indexingType, 0, false, nullptr);
88}
89
90Structure* StructureCache::emptyObjectStructureForPrototype(JSGlobalObject* globalObject, JSObject* prototype, unsigned inlineCapacity, bool makePolyProtoStructure, FunctionExecutable* executable)
91{
92 return createEmptyStructure(globalObject, prototype, JSFinalObject::typeInfo(), JSFinalObject::info(), JSFinalObject::defaultIndexingType, inlineCapacity, makePolyProtoStructure, executable);
93}
94
95} // namespace JSC
96