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