X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/14957cd040308e3eeec43d26bae5d76da13fcd85..HEAD:/runtime/RegExpObject.cpp diff --git a/runtime/RegExpObject.cpp b/runtime/RegExpObject.cpp index fc3b205..60a26ef 100644 --- a/runtime/RegExpObject.cpp +++ b/runtime/RegExpObject.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2003, 2007, 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2003, 2007, 2008, 2012 Apple Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -21,168 +21,181 @@ #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 "Lookup.h" +#include "JSCInlines.h" #include "RegExpConstructor.h" +#include "RegExpMatchesArray.h" #include "RegExpPrototype.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&); -static JSValue regExpObjectLastIndex(ExecState*, JSValue, const Identifier&); -static void setRegExpObjectLastIndex(ExecState*, JSObject*, JSValue); - -} // namespace JSC - -#include "RegExpObject.lut.h" +#include namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(RegExpObject); - -const ClassInfo RegExpObject::s_info = { "RegExp", &JSObjectWithGlobalObject::s_info, 0, ExecState::regExpTable }; +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 - lastIndex regExpObjectLastIndex DontDelete|DontEnum -@end -*/ +const ClassInfo RegExpObject::s_info = { "RegExp", &Base::s_info, nullptr, CREATE_METHOD_TABLE(RegExpObject) }; -RegExpObject::RegExpObject(JSGlobalObject* globalObject, Structure* structure, RegExp* regExp) - : JSObjectWithGlobalObject(globalObject, structure) - , d(adoptPtr(new RegExpObjectData(globalObject->globalData(), this, regExp))) +RegExpObject::RegExpObject(VM& vm, Structure* structure, RegExp* regExp) + : JSNonFinalObject(vm, structure) + , m_regExp(vm, this, regExp) + , m_lastIndexIsWritable(true) { - ASSERT(inherits(&s_info)); + m_lastIndex.setWithoutWriteBarrier(jsNumber(0)); } -RegExpObject::~RegExpObject() +void RegExpObject::finishCreation(VM& vm) { + Base::finishCreation(vm); + ASSERT(inherits(info())); } -void RegExpObject::visitChildren(SlotVisitor& visitor) +void RegExpObject::visitChildren(JSCell* cell, SlotVisitor& visitor) { - ASSERT_GC_OBJECT_INHERITS(this, &s_info); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(structure()->typeInfo().overridesVisitChildren()); - Base::visitChildren(visitor); - if (d->regExp) - visitor.append(&d->regExp); - if (UNLIKELY(!d->lastIndex.get().isInt32())) - visitor.append(&d->lastIndex); + RegExpObject* thisObject = jsCast(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + Base::visitChildren(thisObject, visitor); + visitor.append(&thisObject->m_regExp); + visitor.append(&thisObject->m_lastIndex); } -bool RegExpObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) +bool RegExpObject::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { - return getStaticValueSlot(exec, ExecState::regExpTable(exec), this, propertyName, slot); + if (propertyName == exec->propertyNames().lastIndex) { + RegExpObject* regExp = asRegExpObject(object); + unsigned attributes = regExp->m_lastIndexIsWritable ? DontDelete | DontEnum : DontDelete | DontEnum | ReadOnly; + slot.setValue(regExp, attributes, regExp->getLastIndex()); + return true; + } + return Base::getOwnPropertySlot(object, exec, propertyName, slot); } -bool RegExpObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) +bool RegExpObject::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName) { - return getStaticValueDescriptor(exec, ExecState::regExpTable(exec), this, propertyName, descriptor); + if (propertyName == exec->propertyNames().lastIndex) + return false; + return Base::deleteProperty(cell, exec, propertyName); } -JSValue regExpObjectGlobal(ExecState*, JSValue slotBase, const Identifier&) +void RegExpObject::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) { - return jsBoolean(asRegExpObject(slotBase)->regExp()->global()); + if (mode.includeDontEnumProperties()) + propertyNames.add(exec->propertyNames().lastIndex); + Base::getOwnNonIndexPropertyNames(object, exec, propertyNames, mode); } -JSValue regExpObjectIgnoreCase(ExecState*, JSValue slotBase, const Identifier&) +void RegExpObject::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) { - return jsBoolean(asRegExpObject(slotBase)->regExp()->ignoreCase()); + if (mode.includeDontEnumProperties()) + propertyNames.add(exec->propertyNames().lastIndex); + Base::getPropertyNames(object, exec, propertyNames, mode); } - -JSValue regExpObjectMultiline(ExecState*, JSValue slotBase, const Identifier&) -{ - return jsBoolean(asRegExpObject(slotBase)->regExp()->multiline()); + +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); } -JSValue regExpObjectSource(ExecState* exec, JSValue slotBase, const Identifier&) +static bool reject(ExecState* exec, bool throwException, const char* message) { - return jsString(exec, asRegExpObject(slotBase)->regExp()->pattern()); + if (throwException) + throwTypeError(exec, ASCIILiteral(message)); + return false; } -JSValue regExpObjectLastIndex(ExecState*, JSValue slotBase, const Identifier&) +bool RegExpObject::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool shouldThrow) { - return asRegExpObject(slotBase)->getLastIndex(); + if (propertyName == exec->propertyNames().lastIndex) { + RegExpObject* regExp = asRegExpObject(object); + if (descriptor.configurablePresent() && descriptor.configurable()) + return reject(exec, shouldThrow, "Attempting to change configurable attribute of unconfigurable property."); + if (descriptor.enumerablePresent() && descriptor.enumerable()) + return reject(exec, shouldThrow, "Attempting to change enumerable attribute of unconfigurable property."); + if (descriptor.isAccessorDescriptor()) + return reject(exec, shouldThrow, "Attempting to change access mechanism for an unconfigurable property."); + if (!regExp->m_lastIndexIsWritable) { + if (descriptor.writablePresent() && descriptor.writable()) + return reject(exec, shouldThrow, "Attempting to change writable attribute of unconfigurable property."); + if (!sameValue(exec, regExp->getLastIndex(), descriptor.value())) + return reject(exec, shouldThrow, "Attempting to change value of a readonly property."); + return true; + } + if (descriptor.writablePresent() && !descriptor.writable()) + regExp->m_lastIndexIsWritable = false; + if (descriptor.value()) + regExp->setLastIndex(exec, descriptor.value(), false); + return true; + } + + return Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow); } -void RegExpObject::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) +static void regExpObjectSetLastIndexStrict(ExecState* exec, JSObject* slotBase, EncodedJSValue, EncodedJSValue value) { - lookupPut(exec, propertyName, value, ExecState::regExpTable(exec), this, slot); + asRegExpObject(slotBase)->setLastIndex(exec, JSValue::decode(value), true); } -void setRegExpObjectLastIndex(ExecState* exec, JSObject* baseObject, JSValue value) +static void regExpObjectSetLastIndexNonStrict(ExecState* exec, JSObject* slotBase, EncodedJSValue, EncodedJSValue value) { - asRegExpObject(baseObject)->setLastIndex(exec->globalData(), value); + asRegExpObject(slotBase)->setLastIndex(exec, JSValue::decode(value), false); } -JSValue RegExpObject::test(ExecState* exec) +void RegExpObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { - return jsBoolean(match(exec)); + if (propertyName == exec->propertyNames().lastIndex) { + asRegExpObject(cell)->setLastIndex(exec, value, slot.isStrictMode()); + slot.setCustomProperty(asRegExpObject(cell), slot.isStrictMode() + ? regExpObjectSetLastIndexStrict + : regExpObjectSetLastIndexNonStrict); + return; + } + Base::put(cell, exec, propertyName, value, slot); } -JSValue RegExpObject::exec(ExecState* exec) +JSValue RegExpObject::exec(ExecState* exec, JSString* string) { - if (match(exec)) - return exec->lexicalGlobalObject()->regExpConstructor()->arrayOfMatches(exec); + if (MatchResult result = match(exec, string)) + return createRegExpMatchesArray(exec, string, regExp(), result); return jsNull(); } // Shared implementation used by test and exec. -bool RegExpObject::match(ExecState* exec) +MatchResult RegExpObject::match(ExecState* exec, JSString* string) { + RegExp* regExp = this->regExp(); RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); - UString input = exec->argument(0).toString(exec); - JSGlobalData* globalData = &exec->globalData(); - if (!regExp()->global()) { - int position; - int length; - regExpConstructor->performMatch(*globalData, d->regExp.get(), input, 0, position, length); - return position >= 0; - } + String input = string->value(exec); + VM& vm = exec->vm(); + if (!regExp->global()) + return regExpConstructor->performMatch(vm, regExp, string, input, 0); JSValue jsLastIndex = getLastIndex(); unsigned lastIndex; if (LIKELY(jsLastIndex.isUInt32())) { lastIndex = jsLastIndex.asUInt32(); if (lastIndex > input.length()) { - setLastIndex(0); - return false; + setLastIndex(exec, 0); + return MatchResult::failed(); } } else { double doubleLastIndex = jsLastIndex.toInteger(exec); if (doubleLastIndex < 0 || doubleLastIndex > input.length()) { - setLastIndex(0); - return false; + setLastIndex(exec, 0); + return MatchResult::failed(); } lastIndex = static_cast(doubleLastIndex); } - int position; - int length = 0; - regExpConstructor->performMatch(*globalData, d->regExp.get(), input, lastIndex, position, length); - if (position < 0) { - setLastIndex(0); - return false; - } - - setLastIndex(position + length); - return true; + MatchResult result = regExpConstructor->performMatch(vm, regExp, string, input, lastIndex); + setLastIndex(exec, result.end); + return result; } } // namespace JSC