X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/6fe7ccc865dc7d7541b93c5bcaf6368d2c98a174..ed1e77d3adeb83d26fd1dfb16dd84cabdcefd250:/runtime/RegExpObject.cpp?ds=sidebyside diff --git a/runtime/RegExpObject.cpp b/runtime/RegExpObject.cpp index 5e10a1c..60a26ef 100644 --- a/runtime/RegExpObject.cpp +++ b/runtime/RegExpObject.cpp @@ -21,124 +21,96 @@ #include "config.h" #include "RegExpObject.h" +#include "ButterflyInlines.h" +#include "CopiedSpaceInlines.h" #include "Error.h" #include "ExceptionHelpers.h" #include "JSArray.h" #include "JSGlobalObject.h" #include "JSString.h" -#include "Lexer.h" #include "Lookup.h" +#include "JSCInlines.h" #include "RegExpConstructor.h" #include "RegExpMatchesArray.h" #include "RegExpPrototype.h" -#include "UStringBuilder.h" -#include "UStringConcatenate.h" -#include - -#include - -namespace JSC { - -static JSValue regExpObjectGlobal(ExecState*, JSValue, const Identifier&); -static JSValue regExpObjectIgnoreCase(ExecState*, JSValue, const Identifier&); -static JSValue regExpObjectMultiline(ExecState*, JSValue, const Identifier&); -static JSValue regExpObjectSource(ExecState*, JSValue, const Identifier&); - -} // namespace JSC - -#include "RegExpObject.lut.h" +#include namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(RegExpObject); - -const ClassInfo RegExpObject::s_info = { "RegExp", &JSNonFinalObject::s_info, 0, ExecState::regExpTable, CREATE_METHOD_TABLE(RegExpObject) }; +STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(RegExpObject); -/* Source for RegExpObject.lut.h -@begin regExpTable - global regExpObjectGlobal DontDelete|ReadOnly|DontEnum - ignoreCase regExpObjectIgnoreCase DontDelete|ReadOnly|DontEnum - multiline regExpObjectMultiline DontDelete|ReadOnly|DontEnum - source regExpObjectSource DontDelete|ReadOnly|DontEnum -@end -*/ +const ClassInfo RegExpObject::s_info = { "RegExp", &Base::s_info, nullptr, CREATE_METHOD_TABLE(RegExpObject) }; -RegExpObject::RegExpObject(JSGlobalObject* globalObject, Structure* structure, RegExp* regExp) - : JSNonFinalObject(globalObject->globalData(), structure) - , m_regExp(globalObject->globalData(), this, regExp) +RegExpObject::RegExpObject(VM& vm, Structure* structure, RegExp* regExp) + : JSNonFinalObject(vm, structure) + , m_regExp(vm, this, regExp) , m_lastIndexIsWritable(true) { m_lastIndex.setWithoutWriteBarrier(jsNumber(0)); } -void RegExpObject::finishCreation(JSGlobalObject* globalObject) +void RegExpObject::finishCreation(VM& vm) { - Base::finishCreation(globalObject->globalData()); - ASSERT(inherits(&s_info)); + Base::finishCreation(vm); + ASSERT(inherits(info())); } void RegExpObject::visitChildren(JSCell* cell, SlotVisitor& visitor) { RegExpObject* thisObject = jsCast(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); Base::visitChildren(thisObject, visitor); - if (thisObject->m_regExp) - visitor.append(&thisObject->m_regExp); - if (UNLIKELY(!thisObject->m_lastIndex.get().isInt32())) - visitor.append(&thisObject->m_lastIndex); + visitor.append(&thisObject->m_regExp); + visitor.append(&thisObject->m_lastIndex); } -bool RegExpObject::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot) -{ - if (propertyName == exec->propertyNames().lastIndex) { - RegExpObject* regExp = asRegExpObject(cell); - slot.setValue(regExp, regExp->getLastIndex()); - return true; - } - return getStaticValueSlot(exec, ExecState::regExpTable(exec), jsCast(cell), propertyName, slot); -} - -bool RegExpObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) +bool RegExpObject::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { if (propertyName == exec->propertyNames().lastIndex) { RegExpObject* regExp = asRegExpObject(object); - descriptor.setDescriptor(regExp->getLastIndex(), regExp->m_lastIndexIsWritable ? DontDelete | DontEnum : DontDelete | DontEnum | ReadOnly); + unsigned attributes = regExp->m_lastIndexIsWritable ? DontDelete | DontEnum : DontDelete | DontEnum | ReadOnly; + slot.setValue(regExp, attributes, regExp->getLastIndex()); return true; } - return getStaticValueDescriptor(exec, ExecState::regExpTable(exec), jsCast(object), propertyName, descriptor); + return Base::getOwnPropertySlot(object, exec, propertyName, slot); } -bool RegExpObject::deleteProperty(JSCell* cell, ExecState* exec, const Identifier& propertyName) +bool RegExpObject::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName) { if (propertyName == exec->propertyNames().lastIndex) return false; return Base::deleteProperty(cell, exec, propertyName); } -void RegExpObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) +void RegExpObject::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) { - if (mode == IncludeDontEnumProperties) + if (mode.includeDontEnumProperties()) propertyNames.add(exec->propertyNames().lastIndex); - Base::getOwnPropertyNames(object, exec, propertyNames, mode); + Base::getOwnNonIndexPropertyNames(object, exec, propertyNames, mode); } void RegExpObject::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) { - if (mode == IncludeDontEnumProperties) + if (mode.includeDontEnumProperties()) propertyNames.add(exec->propertyNames().lastIndex); Base::getPropertyNames(object, exec, propertyNames, mode); } +void RegExpObject::getGenericPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) +{ + if (mode.includeDontEnumProperties()) + propertyNames.add(exec->propertyNames().lastIndex); + Base::getGenericPropertyNames(object, exec, propertyNames, mode); +} + static bool reject(ExecState* exec, bool throwException, const char* message) { if (throwException) - throwTypeError(exec, message); + throwTypeError(exec, ASCIILiteral(message)); return false; } -bool RegExpObject::defineOwnProperty(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor, bool shouldThrow) +bool RegExpObject::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool shouldThrow) { if (propertyName == exec->propertyNames().lastIndex) { RegExpObject* regExp = asRegExpObject(object); @@ -165,124 +137,32 @@ bool RegExpObject::defineOwnProperty(JSObject* object, ExecState* exec, const Id return Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow); } -JSValue regExpObjectGlobal(ExecState*, JSValue slotBase, const Identifier&) +static void regExpObjectSetLastIndexStrict(ExecState* exec, JSObject* slotBase, EncodedJSValue, EncodedJSValue value) { - return jsBoolean(asRegExpObject(slotBase)->regExp()->global()); + asRegExpObject(slotBase)->setLastIndex(exec, JSValue::decode(value), true); } -JSValue regExpObjectIgnoreCase(ExecState*, JSValue slotBase, const Identifier&) +static void regExpObjectSetLastIndexNonStrict(ExecState* exec, JSObject* slotBase, EncodedJSValue, EncodedJSValue value) { - return jsBoolean(asRegExpObject(slotBase)->regExp()->ignoreCase()); -} - -JSValue regExpObjectMultiline(ExecState*, JSValue slotBase, const Identifier&) -{ - return jsBoolean(asRegExpObject(slotBase)->regExp()->multiline()); -} - -JSValue regExpObjectSource(ExecState* exec, JSValue slotBase, const Identifier&) -{ - UString pattern = asRegExpObject(slotBase)->regExp()->pattern(); - unsigned length = pattern.length(); - const UChar* characters = pattern.characters(); - bool previousCharacterWasBackslash = false; - bool inBrackets = false; - bool shouldEscape = false; - - // 15.10.6.4 specifies that RegExp.prototype.toString must return '/' + source + '/', - // and also states that the result must be a valid RegularExpressionLiteral. '//' is - // not a valid RegularExpressionLiteral (since it is a single line comment), and hence - // source cannot ever validly be "". If the source is empty, return a different Pattern - // that would match the same thing. - if (!length) - return jsString(exec, "(?:)"); - - // early return for strings that don't contain a forwards slash and LineTerminator - for (unsigned i = 0; i < length; ++i) { - UChar ch = characters[i]; - if (!previousCharacterWasBackslash) { - if (inBrackets) { - if (ch == ']') - inBrackets = false; - } else { - if (ch == '/') { - shouldEscape = true; - break; - } - if (ch == '[') - inBrackets = true; - } - } - - if (Lexer::isLineTerminator(ch)) { - shouldEscape = true; - break; - } - - if (previousCharacterWasBackslash) - previousCharacterWasBackslash = false; - else - previousCharacterWasBackslash = ch == '\\'; - } - - if (!shouldEscape) - return jsString(exec, pattern); - - previousCharacterWasBackslash = false; - inBrackets = false; - UStringBuilder result; - for (unsigned i = 0; i < length; ++i) { - UChar ch = characters[i]; - if (!previousCharacterWasBackslash) { - if (inBrackets) { - if (ch == ']') - inBrackets = false; - } else { - if (ch == '/') - result.append('\\'); - else if (ch == '[') - inBrackets = true; - } - } - - // escape LineTerminator - if (Lexer::isLineTerminator(ch)) { - if (!previousCharacterWasBackslash) - result.append('\\'); - - if (ch == '\n') - result.append('n'); - else if (ch == '\r') - result.append('r'); - else if (ch == 0x2028) - result.append("u2028"); - else - result.append("u2029"); - } else - result.append(ch); - - if (previousCharacterWasBackslash) - previousCharacterWasBackslash = false; - else - previousCharacterWasBackslash = ch == '\\'; - } - - return jsString(exec, result.toUString()); + asRegExpObject(slotBase)->setLastIndex(exec, JSValue::decode(value), false); } -void RegExpObject::put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) +void RegExpObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { if (propertyName == exec->propertyNames().lastIndex) { asRegExpObject(cell)->setLastIndex(exec, value, slot.isStrictMode()); + slot.setCustomProperty(asRegExpObject(cell), slot.isStrictMode() + ? regExpObjectSetLastIndexStrict + : regExpObjectSetLastIndexNonStrict); return; } - lookupPut(exec, propertyName, value, ExecState::regExpTable(exec), jsCast(cell), slot); + Base::put(cell, exec, propertyName, value, slot); } JSValue RegExpObject::exec(ExecState* exec, JSString* string) { if (MatchResult result = match(exec, string)) - return RegExpMatchesArray::create(exec, string, regExp(), result); + return createRegExpMatchesArray(exec, string, regExp(), result); return jsNull(); } @@ -291,10 +171,10 @@ MatchResult RegExpObject::match(ExecState* exec, JSString* string) { RegExp* regExp = this->regExp(); RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); - UString input = string->value(exec); - JSGlobalData& globalData = exec->globalData(); + String input = string->value(exec); + VM& vm = exec->vm(); if (!regExp->global()) - return regExpConstructor->performMatch(globalData, regExp, string, input, 0); + return regExpConstructor->performMatch(vm, regExp, string, input, 0); JSValue jsLastIndex = getLastIndex(); unsigned lastIndex; @@ -313,7 +193,7 @@ MatchResult RegExpObject::match(ExecState* exec, JSString* string) lastIndex = static_cast(doubleLastIndex); } - MatchResult result = regExpConstructor->performMatch(globalData, regExp, string, input, lastIndex); + MatchResult result = regExpConstructor->performMatch(vm, regExp, string, input, lastIndex); setLastIndex(exec, result.end); return result; }