X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/4e4e5a6f2694187498445a6ac6f1634ce8141119..refs/heads/master:/runtime/RegExpConstructor.cpp diff --git a/runtime/RegExpConstructor.cpp b/runtime/RegExpConstructor.cpp index 5332a87..ee1d8b3 100644 --- a/runtime/RegExpConstructor.cpp +++ b/runtime/RegExpConstructor.cpp @@ -22,39 +22,31 @@ #include "config.h" #include "RegExpConstructor.h" -#include "ArrayPrototype.h" #include "Error.h" -#include "JSArray.h" -#include "JSFunction.h" -#include "JSString.h" -#include "Lookup.h" -#include "ObjectPrototype.h" +#include "JSCInlines.h" #include "RegExpMatchesArray.h" -#include "RegExpObject.h" #include "RegExpPrototype.h" -#include "RegExp.h" -#include "RegExpCache.h" namespace JSC { -static JSValue regExpConstructorInput(ExecState*, JSValue, const Identifier&); -static JSValue regExpConstructorMultiline(ExecState*, JSValue, const Identifier&); -static JSValue regExpConstructorLastMatch(ExecState*, JSValue, const Identifier&); -static JSValue regExpConstructorLastParen(ExecState*, JSValue, const Identifier&); -static JSValue regExpConstructorLeftContext(ExecState*, JSValue, const Identifier&); -static JSValue regExpConstructorRightContext(ExecState*, JSValue, const Identifier&); -static JSValue regExpConstructorDollar1(ExecState*, JSValue, const Identifier&); -static JSValue regExpConstructorDollar2(ExecState*, JSValue, const Identifier&); -static JSValue regExpConstructorDollar3(ExecState*, JSValue, const Identifier&); -static JSValue regExpConstructorDollar4(ExecState*, JSValue, const Identifier&); -static JSValue regExpConstructorDollar5(ExecState*, JSValue, const Identifier&); -static JSValue regExpConstructorDollar6(ExecState*, JSValue, const Identifier&); -static JSValue regExpConstructorDollar7(ExecState*, JSValue, const Identifier&); -static JSValue regExpConstructorDollar8(ExecState*, JSValue, const Identifier&); -static JSValue regExpConstructorDollar9(ExecState*, JSValue, const Identifier&); - -static void setRegExpConstructorInput(ExecState*, JSObject*, JSValue); -static void setRegExpConstructorMultiline(ExecState*, JSObject*, JSValue); +static EncodedJSValue regExpConstructorInput(ExecState*, JSObject*, EncodedJSValue, PropertyName); +static EncodedJSValue regExpConstructorMultiline(ExecState*, JSObject*, EncodedJSValue, PropertyName); +static EncodedJSValue regExpConstructorLastMatch(ExecState*, JSObject*, EncodedJSValue, PropertyName); +static EncodedJSValue regExpConstructorLastParen(ExecState*, JSObject*, EncodedJSValue, PropertyName); +static EncodedJSValue regExpConstructorLeftContext(ExecState*, JSObject*, EncodedJSValue, PropertyName); +static EncodedJSValue regExpConstructorRightContext(ExecState*, JSObject*, EncodedJSValue, PropertyName); +static EncodedJSValue regExpConstructorDollar1(ExecState*, JSObject*, EncodedJSValue, PropertyName); +static EncodedJSValue regExpConstructorDollar2(ExecState*, JSObject*, EncodedJSValue, PropertyName); +static EncodedJSValue regExpConstructorDollar3(ExecState*, JSObject*, EncodedJSValue, PropertyName); +static EncodedJSValue regExpConstructorDollar4(ExecState*, JSObject*, EncodedJSValue, PropertyName); +static EncodedJSValue regExpConstructorDollar5(ExecState*, JSObject*, EncodedJSValue, PropertyName); +static EncodedJSValue regExpConstructorDollar6(ExecState*, JSObject*, EncodedJSValue, PropertyName); +static EncodedJSValue regExpConstructorDollar7(ExecState*, JSObject*, EncodedJSValue, PropertyName); +static EncodedJSValue regExpConstructorDollar8(ExecState*, JSObject*, EncodedJSValue, PropertyName); +static EncodedJSValue regExpConstructorDollar9(ExecState*, JSObject*, EncodedJSValue, PropertyName); + +static void setRegExpConstructorInput(ExecState*, JSObject*, EncodedJSValue, EncodedJSValue); +static void setRegExpConstructorMultiline(ExecState*, JSObject*, EncodedJSValue, EncodedJSValue); } // namespace JSC @@ -62,9 +54,7 @@ static void setRegExpConstructorMultiline(ExecState*, JSObject*, JSValue); namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(RegExpConstructor); - -const ClassInfo RegExpConstructor::info = { "Function", &InternalFunction::info, 0, ExecState::regExpConstructorTable }; +const ClassInfo RegExpConstructor::s_info = { "Function", &InternalFunction::s_info, ®ExpConstructorTable, CREATE_METHOD_TABLE(RegExpConstructor) }; /* Source for RegExpConstructor.lut.h @begin regExpConstructorTable @@ -92,265 +82,226 @@ const ClassInfo RegExpConstructor::info = { "Function", &InternalFunction::info, @end */ -RegExpConstructor::RegExpConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, RegExpPrototype* regExpPrototype) - : InternalFunction(&exec->globalData(), structure, Identifier(exec, "RegExp")) - , d(new RegExpConstructorPrivate) +RegExpConstructor::RegExpConstructor(VM& vm, Structure* structure, RegExpPrototype* regExpPrototype) + : InternalFunction(vm, structure) + , m_cachedResult(vm, this, regExpPrototype->regExp()) + , m_multiline(false) { - // ECMA 15.10.5.1 RegExp.prototype - putDirectWithoutTransition(exec->propertyNames().prototype, regExpPrototype, DontEnum | DontDelete | ReadOnly); - - // no. of arguments for constructor - putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 2), ReadOnly | DontDelete | DontEnum); } -RegExpMatchesArray::RegExpMatchesArray(ExecState* exec, RegExpConstructorPrivate* data) - : JSArray(exec->lexicalGlobalObject()->regExpMatchesArrayStructure(), data->lastNumSubPatterns + 1) +void RegExpConstructor::finishCreation(VM& vm, RegExpPrototype* regExpPrototype) { - RegExpConstructorPrivate* d = new RegExpConstructorPrivate; - d->input = data->lastInput; - d->lastInput = data->lastInput; - d->lastNumSubPatterns = data->lastNumSubPatterns; - unsigned offsetVectorSize = (data->lastNumSubPatterns + 1) * 2; // only copying the result part of the vector - d->lastOvector().resize(offsetVectorSize); - memcpy(d->lastOvector().data(), data->lastOvector().data(), offsetVectorSize * sizeof(int)); - // d->multiline is not needed, and remains uninitialized - - setSubclassData(d); -} + Base::finishCreation(vm, regExpPrototype->classInfo()->className); + ASSERT(inherits(info())); -RegExpMatchesArray::~RegExpMatchesArray() -{ - delete static_cast<RegExpConstructorPrivate*>(subclassData()); + // ECMA 15.10.5.1 RegExp.prototype + putDirectWithoutTransition(vm, vm.propertyNames->prototype, regExpPrototype, DontEnum | DontDelete | ReadOnly); + + // no. of arguments for constructor + putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(2), ReadOnly | DontDelete | DontEnum); } -void RegExpMatchesArray::fillArrayInstance(ExecState* exec) +void RegExpConstructor::destroy(JSCell* cell) { - RegExpConstructorPrivate* d = static_cast<RegExpConstructorPrivate*>(subclassData()); - ASSERT(d); - - unsigned lastNumSubpatterns = d->lastNumSubPatterns; - - for (unsigned i = 0; i <= lastNumSubpatterns; ++i) { - int start = d->lastOvector()[2 * i]; - if (start >= 0) - JSArray::put(exec, i, jsSubstring(exec, d->lastInput, start, d->lastOvector()[2 * i + 1] - start)); - else - JSArray::put(exec, i, jsUndefined()); - } - - PutPropertySlot slot; - JSArray::put(exec, exec->propertyNames().index, jsNumber(exec, d->lastOvector()[0]), slot); - JSArray::put(exec, exec->propertyNames().input, jsString(exec, d->input), slot); - - delete d; - setSubclassData(0); + static_cast<RegExpConstructor*>(cell)->RegExpConstructor::~RegExpConstructor(); } -JSObject* RegExpConstructor::arrayOfMatches(ExecState* exec) const +void RegExpConstructor::visitChildren(JSCell* cell, SlotVisitor& visitor) { - return new (exec) RegExpMatchesArray(exec, d.get()); + RegExpConstructor* thisObject = jsCast<RegExpConstructor*>(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + Base::visitChildren(thisObject, visitor); + thisObject->m_cachedResult.visitChildren(visitor); } -JSValue RegExpConstructor::getBackref(ExecState* exec, unsigned i) const +JSValue RegExpConstructor::getBackref(ExecState* exec, unsigned i) { - if (!d->lastOvector().isEmpty() && i <= d->lastNumSubPatterns) { - int start = d->lastOvector()[2 * i]; - if (start >= 0) - return jsSubstring(exec, d->lastInput, start, d->lastOvector()[2 * i + 1] - start); + JSArray* array = m_cachedResult.lastResult(exec, this); + + if (i < array->length()) { + JSValue result = JSValue(array).get(exec, i); + ASSERT(result.isString() || result.isUndefined()); + if (!result.isUndefined()) + return result; } return jsEmptyString(exec); } -JSValue RegExpConstructor::getLastParen(ExecState* exec) const +JSValue RegExpConstructor::getLastParen(ExecState* exec) { - unsigned i = d->lastNumSubPatterns; - if (i > 0) { - ASSERT(!d->lastOvector().isEmpty()); - int start = d->lastOvector()[2 * i]; - if (start >= 0) - return jsSubstring(exec, d->lastInput, start, d->lastOvector()[2 * i + 1] - start); + JSArray* array = m_cachedResult.lastResult(exec, this); + unsigned length = array->length(); + if (length > 1) { + JSValue result = JSValue(array).get(exec, length - 1); + ASSERT(result.isString() || result.isUndefined()); + if (!result.isUndefined()) + return result; } return jsEmptyString(exec); } -JSValue RegExpConstructor::getLeftContext(ExecState* exec) const +JSValue RegExpConstructor::getLeftContext(ExecState* exec) { - if (!d->lastOvector().isEmpty()) - return jsSubstring(exec, d->lastInput, 0, d->lastOvector()[0]); - return jsEmptyString(exec); + return m_cachedResult.leftContext(exec, this); } -JSValue RegExpConstructor::getRightContext(ExecState* exec) const +JSValue RegExpConstructor::getRightContext(ExecState* exec) { - if (!d->lastOvector().isEmpty()) - return jsSubstring(exec, d->lastInput, d->lastOvector()[1], d->lastInput.size() - d->lastOvector()[1]); - return jsEmptyString(exec); + return m_cachedResult.rightContext(exec, this); } -bool RegExpConstructor::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) +bool RegExpConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { - return getStaticValueSlot<RegExpConstructor, InternalFunction>(exec, ExecState::regExpConstructorTable(exec), this, propertyName, slot); + return getStaticValueSlot<RegExpConstructor, InternalFunction>(exec, regExpConstructorTable, jsCast<RegExpConstructor*>(object), propertyName, slot); } - -bool RegExpConstructor::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) -{ - return getStaticValueDescriptor<RegExpConstructor, InternalFunction>(exec, ExecState::regExpConstructorTable(exec), this, propertyName, descriptor); -} - -JSValue regExpConstructorDollar1(ExecState* exec, JSValue slotBase, const Identifier&) + +EncodedJSValue regExpConstructorDollar1(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) { - return asRegExpConstructor(slotBase)->getBackref(exec, 1); + return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 1)); } -JSValue regExpConstructorDollar2(ExecState* exec, JSValue slotBase, const Identifier&) +EncodedJSValue regExpConstructorDollar2(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) { - return asRegExpConstructor(slotBase)->getBackref(exec, 2); + return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 2)); } -JSValue regExpConstructorDollar3(ExecState* exec, JSValue slotBase, const Identifier&) +EncodedJSValue regExpConstructorDollar3(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) { - return asRegExpConstructor(slotBase)->getBackref(exec, 3); + return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 3)); } -JSValue regExpConstructorDollar4(ExecState* exec, JSValue slotBase, const Identifier&) +EncodedJSValue regExpConstructorDollar4(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) { - return asRegExpConstructor(slotBase)->getBackref(exec, 4); + return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 4)); } -JSValue regExpConstructorDollar5(ExecState* exec, JSValue slotBase, const Identifier&) +EncodedJSValue regExpConstructorDollar5(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) { - return asRegExpConstructor(slotBase)->getBackref(exec, 5); + return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 5)); } -JSValue regExpConstructorDollar6(ExecState* exec, JSValue slotBase, const Identifier&) +EncodedJSValue regExpConstructorDollar6(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) { - return asRegExpConstructor(slotBase)->getBackref(exec, 6); + return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 6)); } -JSValue regExpConstructorDollar7(ExecState* exec, JSValue slotBase, const Identifier&) +EncodedJSValue regExpConstructorDollar7(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) { - return asRegExpConstructor(slotBase)->getBackref(exec, 7); + return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 7)); } -JSValue regExpConstructorDollar8(ExecState* exec, JSValue slotBase, const Identifier&) +EncodedJSValue regExpConstructorDollar8(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) { - return asRegExpConstructor(slotBase)->getBackref(exec, 8); + return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 8)); } -JSValue regExpConstructorDollar9(ExecState* exec, JSValue slotBase, const Identifier&) +EncodedJSValue regExpConstructorDollar9(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) { - return asRegExpConstructor(slotBase)->getBackref(exec, 9); + return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 9)); } -JSValue regExpConstructorInput(ExecState* exec, JSValue slotBase, const Identifier&) +EncodedJSValue regExpConstructorInput(ExecState*, JSObject* slotBase, EncodedJSValue, PropertyName) { - return jsString(exec, asRegExpConstructor(slotBase)->input()); + return JSValue::encode(asRegExpConstructor(slotBase)->input()); } -JSValue regExpConstructorMultiline(ExecState*, JSValue slotBase, const Identifier&) +EncodedJSValue regExpConstructorMultiline(ExecState*, JSObject* slotBase, EncodedJSValue, PropertyName) { - return jsBoolean(asRegExpConstructor(slotBase)->multiline()); + return JSValue::encode(jsBoolean(asRegExpConstructor(slotBase)->multiline())); } -JSValue regExpConstructorLastMatch(ExecState* exec, JSValue slotBase, const Identifier&) +EncodedJSValue regExpConstructorLastMatch(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) { - return asRegExpConstructor(slotBase)->getBackref(exec, 0); + return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 0)); } -JSValue regExpConstructorLastParen(ExecState* exec, JSValue slotBase, const Identifier&) +EncodedJSValue regExpConstructorLastParen(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) { - return asRegExpConstructor(slotBase)->getLastParen(exec); + return JSValue::encode(asRegExpConstructor(slotBase)->getLastParen(exec)); } -JSValue regExpConstructorLeftContext(ExecState* exec, JSValue slotBase, const Identifier&) +EncodedJSValue regExpConstructorLeftContext(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) { - return asRegExpConstructor(slotBase)->getLeftContext(exec); + return JSValue::encode(asRegExpConstructor(slotBase)->getLeftContext(exec)); } -JSValue regExpConstructorRightContext(ExecState* exec, JSValue slotBase, const Identifier&) +EncodedJSValue regExpConstructorRightContext(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) { - return asRegExpConstructor(slotBase)->getRightContext(exec); + return JSValue::encode(asRegExpConstructor(slotBase)->getRightContext(exec)); } -void RegExpConstructor::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) +void setRegExpConstructorInput(ExecState* exec, JSObject* baseObject, EncodedJSValue, EncodedJSValue value) { - lookupPut<RegExpConstructor, InternalFunction>(exec, propertyName, value, ExecState::regExpConstructorTable(exec), this, slot); + if (auto constructor = jsDynamicCast<RegExpConstructor*>(baseObject)) + constructor->setInput(exec, JSValue::decode(value).toString(exec)); } -void setRegExpConstructorInput(ExecState* exec, JSObject* baseObject, JSValue value) +void setRegExpConstructorMultiline(ExecState* exec, JSObject* baseObject, EncodedJSValue, EncodedJSValue value) { - asRegExpConstructor(baseObject)->setInput(value.toString(exec)); + if (auto constructor = jsDynamicCast<RegExpConstructor*>(baseObject)) + constructor->setMultiline(JSValue::decode(value).toBoolean(exec)); } -void setRegExpConstructorMultiline(ExecState* exec, JSObject* baseObject, JSValue value) -{ - asRegExpConstructor(baseObject)->setMultiline(value.toBoolean(exec)); -} - // ECMA 15.10.4 -JSObject* constructRegExp(ExecState* exec, const ArgList& args) +JSObject* constructRegExp(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, bool callAsConstructor) { JSValue arg0 = args.at(0); JSValue arg1 = args.at(1); - if (arg0.inherits(&RegExpObject::info)) { + if (arg0.inherits(RegExpObject::info())) { if (!arg1.isUndefined()) - return throwError(exec, TypeError, "Cannot supply flags when constructing one RegExp from another."); + return exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Cannot supply flags when constructing one RegExp from another."))); + // If called as a function, this just returns the first argument (see 15.10.3.1). + if (callAsConstructor) { + RegExp* regExp = static_cast<RegExpObject*>(asObject(arg0))->regExp(); + return RegExpObject::create(exec->vm(), globalObject->regExpStructure(), regExp); + } return asObject(arg0); } - UString pattern = arg0.isUndefined() ? UString("") : arg0.toString(exec); - UString flags = arg1.isUndefined() ? UString("") : arg1.toString(exec); + String pattern = arg0.isUndefined() ? emptyString() : arg0.toString(exec)->value(exec); + if (exec->hadException()) + return 0; + + RegExpFlags flags = NoFlags; + if (!arg1.isUndefined()) { + flags = regExpFlags(arg1.toString(exec)->value(exec)); + if (exec->hadException()) + return 0; + if (flags == InvalidFlags) + return exec->vm().throwException(exec, createSyntaxError(exec, ASCIILiteral("Invalid flags supplied to RegExp constructor."))); + } - RefPtr<RegExp> regExp = exec->globalData().regExpCache()->lookupOrCreate(pattern, flags); + VM& vm = exec->vm(); + RegExp* regExp = RegExp::create(vm, pattern, flags); if (!regExp->isValid()) - return throwError(exec, SyntaxError, makeString("Invalid regular expression: ", regExp->errorMessage())); - return new (exec) RegExpObject(exec->lexicalGlobalObject()->regExpStructure(), regExp.release()); + return vm.throwException(exec, createSyntaxError(exec, regExp->errorMessage())); + return RegExpObject::create(vm, globalObject->regExpStructure(), regExp); } -static JSObject* constructWithRegExpConstructor(ExecState* exec, JSObject*, const ArgList& args) +static EncodedJSValue JSC_HOST_CALL constructWithRegExpConstructor(ExecState* exec) { - return constructRegExp(exec, args); + ArgList args(exec); + return JSValue::encode(constructRegExp(exec, asInternalFunction(exec->callee())->globalObject(), args, true)); } -ConstructType RegExpConstructor::getConstructData(ConstructData& constructData) +ConstructType RegExpConstructor::getConstructData(JSCell*, ConstructData& constructData) { constructData.native.function = constructWithRegExpConstructor; return ConstructTypeHost; } // ECMA 15.10.3 -static JSValue JSC_HOST_CALL callRegExpConstructor(ExecState* exec, JSObject*, JSValue, const ArgList& args) +static EncodedJSValue JSC_HOST_CALL callRegExpConstructor(ExecState* exec) { - return constructRegExp(exec, args); + ArgList args(exec); + return JSValue::encode(constructRegExp(exec, asInternalFunction(exec->callee())->globalObject(), args)); } -CallType RegExpConstructor::getCallData(CallData& callData) +CallType RegExpConstructor::getCallData(JSCell*, CallData& callData) { callData.native.function = callRegExpConstructor; return CallTypeHost; } -void RegExpConstructor::setInput(const UString& input) -{ - d->input = input; -} - -const UString& RegExpConstructor::input() const -{ - // Can detect a distinct initial state that is invisible to JavaScript, by checking for null - // state (since jsString turns null strings to empty strings). - return d->input; -} - -void RegExpConstructor::setMultiline(bool multiline) -{ - d->multiline = multiline; -} - -bool RegExpConstructor::multiline() const -{ - return d->multiline; -} - } // namespace JSC