1/*
2 * Copyright (C) 2017-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 "PolyProtoAccessChain.h"
28
29#include "JSCInlines.h"
30#include "JSObject.h"
31
32namespace JSC {
33
34std::unique_ptr<PolyProtoAccessChain> PolyProtoAccessChain::create(JSGlobalObject* globalObject, JSCell* base, const PropertySlot& slot)
35{
36 JSObject* target = slot.isUnset() ? nullptr : slot.slotBase();
37 return create(globalObject, base, target);
38}
39
40std::unique_ptr<PolyProtoAccessChain> PolyProtoAccessChain::create(JSGlobalObject* globalObject, JSCell* base, JSObject* target)
41{
42 JSCell* current = base;
43 VM& vm = base->vm();
44
45 bool found = false;
46
47 std::unique_ptr<PolyProtoAccessChain> result(new PolyProtoAccessChain());
48
49 for (unsigned iterationNumber = 0; true; ++iterationNumber) {
50 Structure* structure = current->structure(vm);
51
52 if (structure->isDictionary())
53 return nullptr;
54
55 if (!structure->propertyAccessesAreCacheable())
56 return nullptr;
57
58 if (structure->isProxy())
59 return nullptr;
60
61 // To save memory, we don't include the base in the chain. We let
62 // AccessCase provide the base to us as needed.
63 if (iterationNumber)
64 result->m_chain.append(structure);
65 else
66 RELEASE_ASSERT(current == base);
67
68 if (current == target) {
69 found = true;
70 break;
71 }
72
73 JSValue prototype = structure->prototypeForLookup(globalObject, current);
74 if (prototype.isNull())
75 break;
76 current = asObject(prototype);
77 }
78
79 if (!found && !!target)
80 return nullptr;
81
82 return result;
83}
84
85bool PolyProtoAccessChain::needImpurePropertyWatchpoint() const
86{
87 for (Structure* structure : m_chain) {
88 if (structure->needImpurePropertyWatchpoint())
89 return true;
90 }
91 return false;
92}
93
94bool PolyProtoAccessChain::operator==(const PolyProtoAccessChain& other) const
95{
96 return m_chain == other.m_chain;
97}
98
99void PolyProtoAccessChain::dump(Structure* baseStructure, PrintStream& out) const
100{
101 out.print("PolyPolyProtoAccessChain: [\n");
102 forEach(baseStructure, [&] (Structure* structure, bool) {
103 out.print("\t");
104 structure->dump(out);
105 out.print("\n");
106 });
107}
108
109}
110