X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/9dae56ea45a0f5f8136a5c93d6f3a7f99399ca73..ed1e77d3adeb83d26fd1dfb16dd84cabdcefd250:/runtime/RegExpConstructor.cpp?ds=inline diff --git a/runtime/RegExpConstructor.cpp b/runtime/RegExpConstructor.cpp index bff51e0..ee1d8b3 100644 --- a/runtime/RegExpConstructor.cpp +++ b/runtime/RegExpConstructor.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) * Copyright (C) 2003, 2007, 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2009 Torch Mobile, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -21,36 +22,31 @@ #include "config.h" #include "RegExpConstructor.h" -#include "ArrayPrototype.h" -#include "JSArray.h" -#include "JSFunction.h" -#include "JSString.h" -#include "ObjectPrototype.h" +#include "Error.h" +#include "JSCInlines.h" #include "RegExpMatchesArray.h" -#include "RegExpObject.h" #include "RegExpPrototype.h" -#include "RegExp.h" namespace JSC { -static JSValuePtr regExpConstructorInput(ExecState*, const Identifier&, const PropertySlot&); -static JSValuePtr regExpConstructorMultiline(ExecState*, const Identifier&, const PropertySlot&); -static JSValuePtr regExpConstructorLastMatch(ExecState*, const Identifier&, const PropertySlot&); -static JSValuePtr regExpConstructorLastParen(ExecState*, const Identifier&, const PropertySlot&); -static JSValuePtr regExpConstructorLeftContext(ExecState*, const Identifier&, const PropertySlot&); -static JSValuePtr regExpConstructorRightContext(ExecState*, const Identifier&, const PropertySlot&); -static JSValuePtr regExpConstructorDollar1(ExecState*, const Identifier&, const PropertySlot&); -static JSValuePtr regExpConstructorDollar2(ExecState*, const Identifier&, const PropertySlot&); -static JSValuePtr regExpConstructorDollar3(ExecState*, const Identifier&, const PropertySlot&); -static JSValuePtr regExpConstructorDollar4(ExecState*, const Identifier&, const PropertySlot&); -static JSValuePtr regExpConstructorDollar5(ExecState*, const Identifier&, const PropertySlot&); -static JSValuePtr regExpConstructorDollar6(ExecState*, const Identifier&, const PropertySlot&); -static JSValuePtr regExpConstructorDollar7(ExecState*, const Identifier&, const PropertySlot&); -static JSValuePtr regExpConstructorDollar8(ExecState*, const Identifier&, const PropertySlot&); -static JSValuePtr regExpConstructorDollar9(ExecState*, const Identifier&, const PropertySlot&); - -static void setRegExpConstructorInput(ExecState*, JSObject*, JSValuePtr); -static void setRegExpConstructorMultiline(ExecState*, JSObject*, JSValuePtr); +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 @@ -58,9 +54,7 @@ static void setRegExpConstructorMultiline(ExecState*, JSObject*, JSValuePtr); 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 @@ -88,298 +82,226 @@ const ClassInfo RegExpConstructor::info = { "Function", &InternalFunction::info, @end */ -struct RegExpConstructorPrivate { - // Global search cache / settings - RegExpConstructorPrivate() - : lastNumSubPatterns(0) - , multiline(false) - { - } - - UString input; - UString lastInput; - OwnArrayPtr lastOvector; - unsigned lastNumSubPatterns : 31; - bool multiline : 1; -}; - -RegExpConstructor::RegExpConstructor(ExecState* exec, PassRefPtr 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); } -/* - To facilitate result caching, exec(), test(), match(), search(), and replace() dipatch regular - expression matching through the performMatch function. We use cached results to calculate, - e.g., RegExp.lastMatch and RegExp.leftParen. -*/ -void RegExpConstructor::performMatch(RegExp* r, const UString& s, int startOffset, int& position, int& length, int** ovector) +void RegExpConstructor::finishCreation(VM& vm, RegExpPrototype* regExpPrototype) { - OwnArrayPtr tmpOvector; - position = r->match(s, startOffset, &tmpOvector); - - if (ovector) - *ovector = tmpOvector.get(); - - if (position != -1) { - ASSERT(tmpOvector); - - length = tmpOvector[1] - tmpOvector[0]; + Base::finishCreation(vm, regExpPrototype->classInfo()->className); + ASSERT(inherits(info())); - d->input = s; - d->lastInput = s; - d->lastOvector.set(tmpOvector.release()); - d->lastNumSubPatterns = r->numSubpatterns(); - } -} + // ECMA 15.10.5.1 RegExp.prototype + putDirectWithoutTransition(vm, vm.propertyNames->prototype, regExpPrototype, DontEnum | DontDelete | ReadOnly); -RegExpMatchesArray::RegExpMatchesArray(ExecState* exec, RegExpConstructorPrivate* data) - : JSArray(exec->lexicalGlobalObject()->regExpMatchesArrayStructure(), data->lastNumSubPatterns + 1) -{ - 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.set(new int[offsetVectorSize]); - memcpy(d->lastOvector.get(), data->lastOvector.get(), offsetVectorSize * sizeof(int)); - // d->multiline is not needed, and remains uninitialized - - setLazyCreationData(d); + // no. of arguments for constructor + putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(2), ReadOnly | DontDelete | DontEnum); } -RegExpMatchesArray::~RegExpMatchesArray() +void RegExpConstructor::destroy(JSCell* cell) { - delete static_cast(lazyCreationData()); + static_cast(cell)->RegExpConstructor::~RegExpConstructor(); } -void RegExpMatchesArray::fillArrayInstance(ExecState* exec) +void RegExpConstructor::visitChildren(JSCell* cell, SlotVisitor& visitor) { - RegExpConstructorPrivate* d = static_cast(lazyCreationData()); - 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)); - } - - 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; - setLazyCreationData(0); + RegExpConstructor* thisObject = jsCast(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + Base::visitChildren(thisObject, visitor); + thisObject->m_cachedResult.visitChildren(visitor); } -JSObject* RegExpConstructor::arrayOfMatches(ExecState* exec) const +JSValue RegExpConstructor::getBackref(ExecState* exec, unsigned i) { - return new (exec) RegExpMatchesArray(exec, d.get()); -} + JSArray* array = m_cachedResult.lastResult(exec, this); -JSValuePtr RegExpConstructor::getBackref(ExecState* exec, unsigned i) const -{ - if (d->lastOvector && i <= d->lastNumSubPatterns) { - int start = d->lastOvector[2 * i]; - if (start >= 0) - return jsSubstring(exec, d->lastInput, start, d->lastOvector[2 * i + 1] - start); + if (i < array->length()) { + JSValue result = JSValue(array).get(exec, i); + ASSERT(result.isString() || result.isUndefined()); + if (!result.isUndefined()) + return result; } return jsEmptyString(exec); } -JSValuePtr RegExpConstructor::getLastParen(ExecState* exec) const +JSValue RegExpConstructor::getLastParen(ExecState* exec) { - unsigned i = d->lastNumSubPatterns; - if (i > 0) { - ASSERT(d->lastOvector); - 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); } -JSValuePtr RegExpConstructor::getLeftContext(ExecState* exec) const +JSValue RegExpConstructor::getLeftContext(ExecState* exec) { - if (d->lastOvector) - return jsSubstring(exec, d->lastInput, 0, d->lastOvector[0]); - return jsEmptyString(exec); + return m_cachedResult.leftContext(exec, this); } -JSValuePtr RegExpConstructor::getRightContext(ExecState* exec) const +JSValue RegExpConstructor::getRightContext(ExecState* exec) { - if (d->lastOvector) - 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(exec, ExecState::regExpConstructorTable(exec), this, propertyName, slot); + return getStaticValueSlot(exec, regExpConstructorTable, jsCast(object), propertyName, slot); } - -JSValuePtr regExpConstructorDollar1(ExecState* exec, const Identifier&, const PropertySlot& slot) + +EncodedJSValue regExpConstructorDollar1(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) { - return asRegExpConstructor(slot.slotBase())->getBackref(exec, 1); + return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 1)); } -JSValuePtr regExpConstructorDollar2(ExecState* exec, const Identifier&, const PropertySlot& slot) +EncodedJSValue regExpConstructorDollar2(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) { - return asRegExpConstructor(slot.slotBase())->getBackref(exec, 2); + return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 2)); } -JSValuePtr regExpConstructorDollar3(ExecState* exec, const Identifier&, const PropertySlot& slot) +EncodedJSValue regExpConstructorDollar3(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) { - return asRegExpConstructor(slot.slotBase())->getBackref(exec, 3); + return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 3)); } -JSValuePtr regExpConstructorDollar4(ExecState* exec, const Identifier&, const PropertySlot& slot) +EncodedJSValue regExpConstructorDollar4(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) { - return asRegExpConstructor(slot.slotBase())->getBackref(exec, 4); + return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 4)); } -JSValuePtr regExpConstructorDollar5(ExecState* exec, const Identifier&, const PropertySlot& slot) +EncodedJSValue regExpConstructorDollar5(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) { - return asRegExpConstructor(slot.slotBase())->getBackref(exec, 5); + return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 5)); } -JSValuePtr regExpConstructorDollar6(ExecState* exec, const Identifier&, const PropertySlot& slot) +EncodedJSValue regExpConstructorDollar6(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) { - return asRegExpConstructor(slot.slotBase())->getBackref(exec, 6); + return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 6)); } -JSValuePtr regExpConstructorDollar7(ExecState* exec, const Identifier&, const PropertySlot& slot) +EncodedJSValue regExpConstructorDollar7(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) { - return asRegExpConstructor(slot.slotBase())->getBackref(exec, 7); + return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 7)); } -JSValuePtr regExpConstructorDollar8(ExecState* exec, const Identifier&, const PropertySlot& slot) +EncodedJSValue regExpConstructorDollar8(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) { - return asRegExpConstructor(slot.slotBase())->getBackref(exec, 8); + return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 8)); } -JSValuePtr regExpConstructorDollar9(ExecState* exec, const Identifier&, const PropertySlot& slot) +EncodedJSValue regExpConstructorDollar9(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) { - return asRegExpConstructor(slot.slotBase())->getBackref(exec, 9); + return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 9)); } -JSValuePtr regExpConstructorInput(ExecState* exec, const Identifier&, const PropertySlot& slot) +EncodedJSValue regExpConstructorInput(ExecState*, JSObject* slotBase, EncodedJSValue, PropertyName) { - return jsString(exec, asRegExpConstructor(slot.slotBase())->input()); + return JSValue::encode(asRegExpConstructor(slotBase)->input()); } -JSValuePtr regExpConstructorMultiline(ExecState*, const Identifier&, const PropertySlot& slot) +EncodedJSValue regExpConstructorMultiline(ExecState*, JSObject* slotBase, EncodedJSValue, PropertyName) { - return jsBoolean(asRegExpConstructor(slot.slotBase())->multiline()); + return JSValue::encode(jsBoolean(asRegExpConstructor(slotBase)->multiline())); } -JSValuePtr regExpConstructorLastMatch(ExecState* exec, const Identifier&, const PropertySlot& slot) +EncodedJSValue regExpConstructorLastMatch(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) { - return asRegExpConstructor(slot.slotBase())->getBackref(exec, 0); + return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 0)); } -JSValuePtr regExpConstructorLastParen(ExecState* exec, const Identifier&, const PropertySlot& slot) +EncodedJSValue regExpConstructorLastParen(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) { - return asRegExpConstructor(slot.slotBase())->getLastParen(exec); + return JSValue::encode(asRegExpConstructor(slotBase)->getLastParen(exec)); } -JSValuePtr regExpConstructorLeftContext(ExecState* exec, const Identifier&, const PropertySlot& slot) +EncodedJSValue regExpConstructorLeftContext(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) { - return asRegExpConstructor(slot.slotBase())->getLeftContext(exec); + return JSValue::encode(asRegExpConstructor(slotBase)->getLeftContext(exec)); } -JSValuePtr regExpConstructorRightContext(ExecState* exec, const Identifier&, const PropertySlot& slot) +EncodedJSValue regExpConstructorRightContext(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) { - return asRegExpConstructor(slot.slotBase())->getRightContext(exec); + return JSValue::encode(asRegExpConstructor(slotBase)->getRightContext(exec)); } -void RegExpConstructor::put(ExecState* exec, const Identifier& propertyName, JSValuePtr value, PutPropertySlot& slot) +void setRegExpConstructorInput(ExecState* exec, JSObject* baseObject, EncodedJSValue, EncodedJSValue value) { - lookupPut(exec, propertyName, value, ExecState::regExpConstructorTable(exec), this, slot); + if (auto constructor = jsDynamicCast(baseObject)) + constructor->setInput(exec, JSValue::decode(value).toString(exec)); } -void setRegExpConstructorInput(ExecState* exec, JSObject* baseObject, JSValuePtr value) +void setRegExpConstructorMultiline(ExecState* exec, JSObject* baseObject, EncodedJSValue, EncodedJSValue value) { - asRegExpConstructor(baseObject)->setInput(value.toString(exec)); + if (auto constructor = jsDynamicCast(baseObject)) + constructor->setMultiline(JSValue::decode(value).toBoolean(exec)); } -void setRegExpConstructorMultiline(ExecState* exec, JSObject* baseObject, JSValuePtr 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) { - JSValuePtr arg0 = args.at(exec, 0); - JSValuePtr arg1 = args.at(exec, 1); + JSValue arg0 = args.at(0); + JSValue arg1 = args.at(1); - if (arg0.isObject(&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(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::create(&exec->globalData(), pattern, flags); + VM& vm = exec->vm(); + RegExp* regExp = RegExp::create(vm, pattern, flags); if (!regExp->isValid()) - return throwError(exec, SyntaxError, UString("Invalid regular expression: ").append(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 JSValuePtr callRegExpConstructor(ExecState* exec, JSObject*, JSValuePtr, 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