1 | /* |
2 | * Copyright (C) 1999-2001 Harri Porten ([email protected]) |
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 "Error.h" |
25 | #include "JSGlobalObject.h" |
26 | #include "JSCInlines.h" |
27 | #include "PropertyNameArray.h" |
28 | |
29 | namespace JSC { |
30 | |
31 | STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(StringObject); |
32 | |
33 | const ClassInfo StringObject::s_info = { "String" , &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(StringObject) }; |
34 | |
35 | StringObject::StringObject(VM& vm, Structure* structure) |
36 | : Base(vm, structure) |
37 | { |
38 | } |
39 | |
40 | void StringObject::finishCreation(VM& vm, JSString* string) |
41 | { |
42 | Base::finishCreation(vm); |
43 | ASSERT(inherits(vm, info())); |
44 | setInternalValue(vm, string); |
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) |
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); |
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, EnumerationMode 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 | } |
157 | return JSObject::getOwnPropertyNames(thisObject, globalObject, propertyNames, mode); |
158 | } |
159 | |
160 | void StringObject::getOwnNonIndexPropertyNames(JSObject* object, JSGlobalObject* globalObject, PropertyNameArray& propertyNames, EnumerationMode mode) |
161 | { |
162 | VM& vm = globalObject->vm(); |
163 | StringObject* thisObject = jsCast<StringObject*>(object); |
164 | if (mode.includeDontEnumProperties()) |
165 | propertyNames.add(vm.propertyNames->length); |
166 | return JSObject::getOwnNonIndexPropertyNames(thisObject, globalObject, propertyNames, mode); |
167 | } |
168 | |
169 | StringObject* constructString(VM& vm, JSGlobalObject* globalObject, JSValue string) |
170 | { |
171 | StringObject* object = StringObject::create(vm, globalObject->stringObjectStructure()); |
172 | object->setInternalValue(vm, string); |
173 | return object; |
174 | } |
175 | |
176 | } // namespace JSC |
177 | |