1 /* 2 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) 3 * Copyright (C) 2001 Peter Kelly (pmk@post.com) 4 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Library General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Library General Public License for more details. 15 * 16 * You should have received a copy of the GNU Library General Public License 17 * along with this library; see the file COPYING.LIB. If not, write to 18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA. 20 * 21 */ 22 23 #ifndef JSString_h 24 #define JSString_h 25 26 #include "CallFrame.h" 27 #include "CommonIdentifiers.h" 28 #include "Identifier.h" 29 #include "JSNumberCell.h" 30 #include "PropertySlot.h" 31 32 namespace JSC { 33 34 class JSString; 35 36 JSString* jsEmptyString(JSGlobalData*); 37 JSString* jsEmptyString(ExecState*); 38 JSString* jsString(JSGlobalData*, const UString&); // returns empty string if passed null string 39 JSString* jsString(ExecState*, const UString&); // returns empty string if passed null string 40 41 JSString* jsSingleCharacterString(JSGlobalData*, UChar); 42 JSString* jsSingleCharacterString(ExecState*, UChar); 43 JSString* jsSingleCharacterSubstring(JSGlobalData*, const UString&, unsigned offset); 44 JSString* jsSingleCharacterSubstring(ExecState*, const UString&, unsigned offset); 45 JSString* jsSubstring(JSGlobalData*, const UString&, unsigned offset, unsigned length); 46 JSString* jsSubstring(ExecState*, const UString&, unsigned offset, unsigned length); 47 48 // Non-trivial strings are two or more characters long. 49 // These functions are faster than just calling jsString. 50 JSString* jsNontrivialString(JSGlobalData*, const UString&); 51 JSString* jsNontrivialString(ExecState*, const UString&); 52 JSString* jsNontrivialString(JSGlobalData*, const char*); 53 JSString* jsNontrivialString(ExecState*, const char*); 54 55 // Should be used for strings that are owned by an object that will 56 // likely outlive the JSValue this makes, such as the parse tree or a 57 // DOM object that contains a UString 58 JSString* jsOwnedString(JSGlobalData*, const UString&); 59 JSString* jsOwnedString(ExecState*, const UString&); 60 61 class JSString : public JSCell { 62 friend class JIT; 63 friend struct VPtrSet; 64 65 public: JSString(JSGlobalData * globalData,const UString & value)66 JSString(JSGlobalData* globalData, const UString& value) 67 : JSCell(globalData->stringStructure.get()) 68 , m_value(value) 69 { 70 Heap::heap(this)->reportExtraMemoryCost(value.cost()); 71 } 72 73 enum HasOtherOwnerType { HasOtherOwner }; JSString(JSGlobalData * globalData,const UString & value,HasOtherOwnerType)74 JSString(JSGlobalData* globalData, const UString& value, HasOtherOwnerType) 75 : JSCell(globalData->stringStructure.get()) 76 , m_value(value) 77 { 78 } JSString(JSGlobalData * globalData,PassRefPtr<UString::Rep> value,HasOtherOwnerType)79 JSString(JSGlobalData* globalData, PassRefPtr<UString::Rep> value, HasOtherOwnerType) 80 : JSCell(globalData->stringStructure.get()) 81 , m_value(value) 82 { 83 } 84 value()85 const UString& value() const { return m_value; } 86 87 bool getStringPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); 88 bool getStringPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); 89 canGetIndex(unsigned i)90 bool canGetIndex(unsigned i) { return i < static_cast<unsigned>(m_value.size()); } 91 JSString* getIndex(JSGlobalData*, unsigned); 92 createStructure(JSValue proto)93 static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(StringType, NeedsThisConversion)); } 94 95 private: 96 enum VPtrStealingHackType { VPtrStealingHack }; JSString(VPtrStealingHackType)97 JSString(VPtrStealingHackType) 98 : JSCell(0) 99 { 100 } 101 102 virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; 103 virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue& value); 104 virtual bool toBoolean(ExecState*) const; 105 virtual double toNumber(ExecState*) const; 106 virtual JSObject* toObject(ExecState*) const; 107 virtual UString toString(ExecState*) const; 108 109 virtual JSObject* toThisObject(ExecState*) const; 110 virtual UString toThisString(ExecState*) const; 111 virtual JSString* toThisJSString(ExecState*); 112 113 // Actually getPropertySlot, not getOwnPropertySlot (see JSCell). 114 virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); 115 virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); 116 117 UString m_value; 118 }; 119 120 JSString* asString(JSValue); 121 asString(JSValue value)122 inline JSString* asString(JSValue value) 123 { 124 ASSERT(asCell(value)->isString()); 125 return static_cast<JSString*>(asCell(value)); 126 } 127 jsEmptyString(JSGlobalData * globalData)128 inline JSString* jsEmptyString(JSGlobalData* globalData) 129 { 130 return globalData->smallStrings.emptyString(globalData); 131 } 132 jsSingleCharacterString(JSGlobalData * globalData,UChar c)133 inline JSString* jsSingleCharacterString(JSGlobalData* globalData, UChar c) 134 { 135 if (c <= 0xFF) 136 return globalData->smallStrings.singleCharacterString(globalData, c); 137 return new (globalData) JSString(globalData, UString(&c, 1)); 138 } 139 jsSingleCharacterSubstring(JSGlobalData * globalData,const UString & s,unsigned offset)140 inline JSString* jsSingleCharacterSubstring(JSGlobalData* globalData, const UString& s, unsigned offset) 141 { 142 ASSERT(offset < static_cast<unsigned>(s.size())); 143 UChar c = s.data()[offset]; 144 if (c <= 0xFF) 145 return globalData->smallStrings.singleCharacterString(globalData, c); 146 return new (globalData) JSString(globalData, UString::Rep::create(s.rep(), offset, 1)); 147 } 148 jsNontrivialString(JSGlobalData * globalData,const char * s)149 inline JSString* jsNontrivialString(JSGlobalData* globalData, const char* s) 150 { 151 ASSERT(s); 152 ASSERT(s[0]); 153 ASSERT(s[1]); 154 return new (globalData) JSString(globalData, s); 155 } 156 jsNontrivialString(JSGlobalData * globalData,const UString & s)157 inline JSString* jsNontrivialString(JSGlobalData* globalData, const UString& s) 158 { 159 ASSERT(s.size() > 1); 160 return new (globalData) JSString(globalData, s); 161 } 162 getIndex(JSGlobalData * globalData,unsigned i)163 inline JSString* JSString::getIndex(JSGlobalData* globalData, unsigned i) 164 { 165 ASSERT(canGetIndex(i)); 166 return jsSingleCharacterSubstring(globalData, m_value, i); 167 } 168 jsEmptyString(ExecState * exec)169 inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->globalData()); } jsString(ExecState * exec,const UString & s)170 inline JSString* jsString(ExecState* exec, const UString& s) { return jsString(&exec->globalData(), s); } jsSingleCharacterString(ExecState * exec,UChar c)171 inline JSString* jsSingleCharacterString(ExecState* exec, UChar c) { return jsSingleCharacterString(&exec->globalData(), c); } jsSingleCharacterSubstring(ExecState * exec,const UString & s,unsigned offset)172 inline JSString* jsSingleCharacterSubstring(ExecState* exec, const UString& s, unsigned offset) { return jsSingleCharacterSubstring(&exec->globalData(), s, offset); } jsSubstring(ExecState * exec,const UString & s,unsigned offset,unsigned length)173 inline JSString* jsSubstring(ExecState* exec, const UString& s, unsigned offset, unsigned length) { return jsSubstring(&exec->globalData(), s, offset, length); } jsNontrivialString(ExecState * exec,const UString & s)174 inline JSString* jsNontrivialString(ExecState* exec, const UString& s) { return jsNontrivialString(&exec->globalData(), s); } jsNontrivialString(ExecState * exec,const char * s)175 inline JSString* jsNontrivialString(ExecState* exec, const char* s) { return jsNontrivialString(&exec->globalData(), s); } jsOwnedString(ExecState * exec,const UString & s)176 inline JSString* jsOwnedString(ExecState* exec, const UString& s) { return jsOwnedString(&exec->globalData(), s); } 177 getStringPropertySlot(ExecState * exec,const Identifier & propertyName,PropertySlot & slot)178 ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) 179 { 180 if (propertyName == exec->propertyNames().length) { 181 slot.setValue(jsNumber(exec, m_value.size())); 182 return true; 183 } 184 185 bool isStrictUInt32; 186 unsigned i = propertyName.toStrictUInt32(&isStrictUInt32); 187 if (isStrictUInt32 && i < static_cast<unsigned>(m_value.size())) { 188 slot.setValue(jsSingleCharacterSubstring(exec, m_value, i)); 189 return true; 190 } 191 192 return false; 193 } 194 getStringPropertySlot(ExecState * exec,unsigned propertyName,PropertySlot & slot)195 ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) 196 { 197 if (propertyName < static_cast<unsigned>(m_value.size())) { 198 slot.setValue(jsSingleCharacterSubstring(exec, m_value, propertyName)); 199 return true; 200 } 201 202 return false; 203 } 204 isJSString(JSGlobalData * globalData,JSValue v)205 inline bool isJSString(JSGlobalData* globalData, JSValue v) { return v.isCell() && v.asCell()->vptr() == globalData->jsStringVPtr; } 206 207 // --- JSValue inlines ---------------------------- 208 toThisJSString(ExecState * exec)209 inline JSString* JSValue::toThisJSString(ExecState* exec) 210 { 211 return isCell() ? asCell()->toThisJSString(exec) : jsString(exec, toString(exec)); 212 } 213 214 } // namespace JSC 215 216 #endif // JSString_h 217