StringObject.cpp
1 /* 2 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) 3 * Copyright (C) 2004-2019 Apple Inc. All rights reserved. 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 * 19 */ 20 21 #include "config.h" 22 #include "StringObject.h" 23 24 #include "JSCInlines.h" 25 #include "PropertyNameArray.h" 26 #include "TypeError.h" 27 28 namespace JSC { 29 30 STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(StringObject); 31 32 const ClassInfo StringObject::s_info = { "String", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(StringObject) }; 33 34 StringObject::StringObject(VM& vm, Structure* structure) 35 : Base(vm, structure) 36 { 37 } 38 39 void StringObject::finishCreation(VM& vm, JSString* string) 40 { 41 Base::finishCreation(vm); 42 ASSERT(inherits(vm, info())); 43 setInternalValue(vm, string); 44 ASSERT_WITH_MESSAGE(type() == StringObjectType || type() == DerivedStringObjectType, "Instance inheriting StringObject should have DerivedStringObjectType"); 45 } 46 47 bool StringObject::getOwnPropertySlot(JSObject* cell, JSGlobalObject* globalObject, PropertyName propertyName, PropertySlot& slot) 48 { 49 StringObject* thisObject = jsCast<StringObject*>(cell); 50 if (thisObject->internalValue()->getStringPropertySlot(globalObject, propertyName, slot)) 51 return true; 52 return JSObject::getOwnPropertySlot(thisObject, globalObject, propertyName, slot); 53 } 54 55 bool StringObject::getOwnPropertySlotByIndex(JSObject* object, JSGlobalObject* globalObject, unsigned propertyName, PropertySlot& slot) 56 { 57 StringObject* thisObject = jsCast<StringObject*>(object); 58 if (thisObject->internalValue()->getStringPropertySlot(globalObject, propertyName, slot)) 59 return true; 60 VM& vm = globalObject->vm(); 61 return JSObject::getOwnPropertySlot(thisObject, globalObject, Identifier::from(vm, propertyName), slot); 62 } 63 64 bool StringObject::put(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, JSValue value, PutPropertySlot& slot) 65 { 66 VM& vm = globalObject->vm(); 67 auto scope = DECLARE_THROW_SCOPE(vm); 68 69 StringObject* thisObject = jsCast<StringObject*>(cell); 70 71 if (UNLIKELY(isThisValueAltered(slot, thisObject))) 72 RELEASE_AND_RETURN(scope, ordinarySetSlow(globalObject, thisObject, propertyName, value, slot.thisValue(), slot.isStrictMode())); 73 74 if (propertyName == vm.propertyNames->length) 75 return typeError(globalObject, scope, slot.isStrictMode(), ReadonlyPropertyWriteError); 76 if (Optional<uint32_t> index = parseIndex(propertyName)) 77 RELEASE_AND_RETURN(scope, putByIndex(cell, globalObject, index.value(), value, slot.isStrictMode())); 78 RELEASE_AND_RETURN(scope, JSObject::put(cell, globalObject, propertyName, value, slot)); 79 } 80 81 bool StringObject::putByIndex(JSCell* cell, JSGlobalObject* globalObject, unsigned propertyName, JSValue value, bool shouldThrow) 82 { 83 VM& vm = globalObject->vm(); 84 auto scope = DECLARE_THROW_SCOPE(vm); 85 86 StringObject* thisObject = jsCast<StringObject*>(cell); 87 if (thisObject->internalValue()->canGetIndex(propertyName)) 88 return typeError(globalObject, scope, shouldThrow, ReadonlyPropertyWriteError); 89 RELEASE_AND_RETURN(scope, JSObject::putByIndex(cell, globalObject, propertyName, value, shouldThrow)); 90 } 91 92 static bool isStringOwnProperty(JSGlobalObject* globalObject, StringObject* object, PropertyName propertyName) 93 { 94 VM& vm = globalObject->vm(); 95 if (propertyName == vm.propertyNames->length) 96 return true; 97 if (Optional<uint32_t> index = parseIndex(propertyName)) { 98 if (object->internalValue()->canGetIndex(index.value())) 99 return true; 100 } 101 return false; 102 } 103 104 bool StringObject::defineOwnProperty(JSObject* object, JSGlobalObject* globalObject, PropertyName propertyName, const PropertyDescriptor& descriptor, bool throwException) 105 { 106 VM& vm = globalObject->vm(); 107 auto scope = DECLARE_THROW_SCOPE(vm); 108 StringObject* thisObject = jsCast<StringObject*>(object); 109 110 if (isStringOwnProperty(globalObject, thisObject, propertyName)) { 111 // The current PropertyDescriptor is always 112 // PropertyDescriptor{[[Value]]: value, [[Writable]]: false, [[Enumerable]]: true, [[Configurable]]: false}. 113 // This ensures that any property descriptor cannot change the existing one. 114 // Here, simply return the result of validateAndApplyPropertyDescriptor. 115 // https://tc39.github.io/ecma262/#sec-string-exotic-objects-getownproperty-p 116 PropertyDescriptor current; 117 bool isCurrentDefined = thisObject->getOwnPropertyDescriptor(globalObject, propertyName, current); 118 EXCEPTION_ASSERT(!scope.exception() == isCurrentDefined); 119 RETURN_IF_EXCEPTION(scope, false); 120 bool isExtensible = thisObject->isExtensible(globalObject); 121 RETURN_IF_EXCEPTION(scope, false); 122 RELEASE_AND_RETURN(scope, validateAndApplyPropertyDescriptor(globalObject, nullptr, propertyName, isExtensible, descriptor, isCurrentDefined, current, throwException)); 123 } 124 125 RELEASE_AND_RETURN(scope, Base::defineOwnProperty(object, globalObject, propertyName, descriptor, throwException)); 126 } 127 128 bool StringObject::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, DeletePropertySlot& slot) 129 { 130 VM& vm = globalObject->vm(); 131 StringObject* thisObject = jsCast<StringObject*>(cell); 132 if (propertyName == vm.propertyNames->length) 133 return false; 134 Optional<uint32_t> index = parseIndex(propertyName); 135 if (index && thisObject->internalValue()->canGetIndex(index.value())) 136 return false; 137 return JSObject::deleteProperty(thisObject, globalObject, propertyName, slot); 138 } 139 140 bool StringObject::deletePropertyByIndex(JSCell* cell, JSGlobalObject* globalObject, unsigned i) 141 { 142 StringObject* thisObject = jsCast<StringObject*>(cell); 143 if (thisObject->internalValue()->canGetIndex(i)) 144 return false; 145 return JSObject::deletePropertyByIndex(thisObject, globalObject, i); 146 } 147 148 void StringObject::getOwnPropertyNames(JSObject* object, JSGlobalObject* globalObject, PropertyNameArray& propertyNames, DontEnumPropertiesMode mode) 149 { 150 VM& vm = globalObject->vm(); 151 StringObject* thisObject = jsCast<StringObject*>(object); 152 if (propertyNames.includeStringProperties()) { 153 int size = thisObject->internalValue()->length(); 154 for (int i = 0; i < size; ++i) 155 propertyNames.add(Identifier::from(vm, i)); 156 thisObject->getOwnIndexedPropertyNames(globalObject, propertyNames, mode); 157 } 158 if (mode == DontEnumPropertiesMode::Include) 159 propertyNames.add(vm.propertyNames->length); 160 thisObject->getOwnNonIndexPropertyNames(globalObject, propertyNames, mode); 161 } 162 163 String StringObject::toStringName(const JSObject*, JSGlobalObject*) 164 { 165 return "String"_s; 166 } 167 168 StringObject* constructString(VM& vm, JSGlobalObject* globalObject, JSValue string) 169 { 170 StringObject* object = StringObject::create(vm, globalObject->stringObjectStructure()); 171 object->setInternalValue(vm, string); 172 return object; 173 } 174 175 } // namespace JSC