DirectArguments.cpp
1 /* 2 * Copyright (C) 2015-2018 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 "DirectArguments.h" 28 29 #include "CodeBlock.h" 30 #include "GenericArgumentsInlines.h" 31 32 namespace JSC { 33 34 STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(DirectArguments); 35 36 const ClassInfo DirectArguments::s_info = { "Arguments", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(DirectArguments) }; 37 38 DirectArguments::DirectArguments(VM& vm, Structure* structure, unsigned length, unsigned capacity) 39 : GenericArguments(vm, structure) 40 , m_length(length) 41 , m_minCapacity(capacity) 42 { 43 // When we construct the object from C++ code, we expect the capacity to be at least as large as 44 // length. JIT-allocated DirectArguments objects play evil tricks, though. 45 ASSERT(capacity >= length); 46 } 47 48 DirectArguments* DirectArguments::createUninitialized( 49 VM& vm, Structure* structure, unsigned length, unsigned capacity) 50 { 51 DirectArguments* result = 52 new (NotNull, allocateCell<DirectArguments>(vm.heap, allocationSize(capacity))) 53 DirectArguments(vm, structure, length, capacity); 54 result->finishCreation(vm); 55 return result; 56 } 57 58 DirectArguments* DirectArguments::create(VM& vm, Structure* structure, unsigned length, unsigned capacity) 59 { 60 DirectArguments* result = createUninitialized(vm, structure, length, capacity); 61 62 for (unsigned i = capacity; i--;) 63 result->storage()[i].setUndefined(); 64 65 return result; 66 } 67 68 DirectArguments* DirectArguments::createByCopying(JSGlobalObject* globalObject, CallFrame* callFrame) 69 { 70 VM& vm = globalObject->vm(); 71 72 unsigned length = callFrame->argumentCount(); 73 unsigned capacity = std::max(length, static_cast<unsigned>(callFrame->codeBlock()->numParameters() - 1)); 74 DirectArguments* result = createUninitialized( 75 vm, globalObject->directArgumentsStructure(), length, capacity); 76 77 for (unsigned i = capacity; i--;) 78 result->storage()[i].set(vm, result, callFrame->getArgumentUnsafe(i)); 79 80 result->setCallee(vm, jsCast<JSFunction*>(callFrame->jsCallee())); 81 82 return result; 83 } 84 85 size_t DirectArguments::estimatedSize(JSCell* cell, VM& vm) 86 { 87 DirectArguments* thisObject = jsCast<DirectArguments*>(cell); 88 size_t mappedArgumentsSize = thisObject->m_mappedArguments ? thisObject->mappedArgumentsSize() * sizeof(bool) : 0; 89 size_t modifiedArgumentsSize = thisObject->m_modifiedArgumentsDescriptor ? thisObject->m_length * sizeof(bool) : 0; 90 return Base::estimatedSize(cell, vm) + mappedArgumentsSize + modifiedArgumentsSize; 91 } 92 93 void DirectArguments::visitChildren(JSCell* thisCell, SlotVisitor& visitor) 94 { 95 DirectArguments* thisObject = static_cast<DirectArguments*>(thisCell); 96 ASSERT_GC_OBJECT_INHERITS(thisObject, info()); 97 Base::visitChildren(thisObject, visitor); 98 99 visitor.appendValues(thisObject->storage(), std::max(thisObject->m_length, thisObject->m_minCapacity)); 100 visitor.append(thisObject->m_callee); 101 102 if (thisObject->m_mappedArguments) 103 visitor.markAuxiliary(thisObject->m_mappedArguments.get(thisObject->internalLength())); 104 GenericArguments<DirectArguments>::visitChildren(thisCell, visitor); 105 } 106 107 Structure* DirectArguments::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) 108 { 109 return Structure::create(vm, globalObject, prototype, TypeInfo(DirectArgumentsType, StructureFlags), info()); 110 } 111 112 void DirectArguments::overrideThings(JSGlobalObject* globalObject) 113 { 114 VM& vm = globalObject->vm(); 115 auto scope = DECLARE_THROW_SCOPE(vm); 116 117 RELEASE_ASSERT(!m_mappedArguments); 118 119 putDirect(vm, vm.propertyNames->length, jsNumber(m_length), static_cast<unsigned>(PropertyAttribute::DontEnum)); 120 putDirect(vm, vm.propertyNames->callee, m_callee.get(), static_cast<unsigned>(PropertyAttribute::DontEnum)); 121 putDirect(vm, vm.propertyNames->iteratorSymbol, globalObject->arrayProtoValuesFunction(), static_cast<unsigned>(PropertyAttribute::DontEnum)); 122 123 void* backingStore = vm.gigacageAuxiliarySpace(m_mappedArguments.kind).allocateNonVirtual(vm, mappedArgumentsSize(), nullptr, AllocationFailureMode::ReturnNull); 124 if (UNLIKELY(!backingStore)) { 125 throwOutOfMemoryError(globalObject, scope); 126 return; 127 } 128 bool* overrides = static_cast<bool*>(backingStore); 129 m_mappedArguments.set(vm, this, overrides, internalLength()); 130 for (unsigned i = internalLength(); i--;) 131 overrides[i] = false; 132 } 133 134 void DirectArguments::overrideThingsIfNecessary(JSGlobalObject* globalObject) 135 { 136 if (!m_mappedArguments) 137 overrideThings(globalObject); 138 } 139 140 void DirectArguments::unmapArgument(JSGlobalObject* globalObject, unsigned index) 141 { 142 VM& vm = globalObject->vm(); 143 auto scope = DECLARE_THROW_SCOPE(vm); 144 145 overrideThingsIfNecessary(globalObject); 146 RETURN_IF_EXCEPTION(scope, void()); 147 148 m_mappedArguments.at(index, internalLength()) = true; 149 } 150 151 void DirectArguments::copyToArguments(JSGlobalObject* globalObject, JSValue* firstElementDest, unsigned offset, unsigned length) 152 { 153 if (!m_mappedArguments) { 154 unsigned limit = std::min(length + offset, m_length); 155 unsigned i; 156 for (i = offset; i < limit; ++i) 157 firstElementDest[i - offset] = storage()[i].get(); 158 for (; i < length; ++i) 159 firstElementDest[i - offset] = get(globalObject, i); 160 return; 161 } 162 163 GenericArguments::copyToArguments(globalObject, firstElementDest, offset, length); 164 } 165 166 unsigned DirectArguments::mappedArgumentsSize() 167 { 168 // We always allocate something; in the relatively uncommon case of overriding an empty argument we 169 // still allocate so that m_mappedArguments is non-null. We use that to indicate that the other properties 170 // (length, etc) are overridden. 171 return WTF::roundUpToMultipleOf<8>(m_length ? m_length : 1); 172 } 173 174 } // namespace JSC 175