summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/runtime/RegExpConstructor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/runtime/RegExpConstructor.cpp')
-rw-r--r--Source/JavaScriptCore/runtime/RegExpConstructor.cpp284
1 files changed, 151 insertions, 133 deletions
diff --git a/Source/JavaScriptCore/runtime/RegExpConstructor.cpp b/Source/JavaScriptCore/runtime/RegExpConstructor.cpp
index bc516b06d..432283f0a 100644
--- a/Source/JavaScriptCore/runtime/RegExpConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/RegExpConstructor.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, 2016 Apple Inc. All Rights Reserved.
* Copyright (C) 2009 Torch Mobile, Inc.
*
* This library is free software; you can redistribute it and/or
@@ -23,30 +23,24 @@
#include "RegExpConstructor.h"
#include "Error.h"
-#include "Operations.h"
-#include "RegExpMatchesArray.h"
+#include "GetterSetter.h"
+#include "JSCInlines.h"
#include "RegExpPrototype.h"
+#include "StructureInlines.h"
namespace JSC {
-static EncodedJSValue regExpConstructorInput(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue regExpConstructorMultiline(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue regExpConstructorLastMatch(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue regExpConstructorLastParen(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue regExpConstructorLeftContext(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue regExpConstructorRightContext(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue regExpConstructorDollar1(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue regExpConstructorDollar2(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue regExpConstructorDollar3(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue regExpConstructorDollar4(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue regExpConstructorDollar5(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue regExpConstructorDollar6(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue regExpConstructorDollar7(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue regExpConstructorDollar8(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue regExpConstructorDollar9(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-
-static void setRegExpConstructorInput(ExecState*, JSObject*, EncodedJSValue, EncodedJSValue);
-static void setRegExpConstructorMultiline(ExecState*, JSObject*, EncodedJSValue, EncodedJSValue);
+static EncodedJSValue regExpConstructorInput(ExecState*, EncodedJSValue, PropertyName);
+static EncodedJSValue regExpConstructorMultiline(ExecState*, EncodedJSValue, PropertyName);
+static EncodedJSValue regExpConstructorLastMatch(ExecState*, EncodedJSValue, PropertyName);
+static EncodedJSValue regExpConstructorLastParen(ExecState*, EncodedJSValue, PropertyName);
+static EncodedJSValue regExpConstructorLeftContext(ExecState*, EncodedJSValue, PropertyName);
+static EncodedJSValue regExpConstructorRightContext(ExecState*, EncodedJSValue, PropertyName);
+template<int N>
+static EncodedJSValue regExpConstructorDollar(ExecState*, EncodedJSValue, PropertyName);
+
+static bool setRegExpConstructorInput(ExecState*, EncodedJSValue, EncodedJSValue);
+static bool setRegExpConstructorMultiline(ExecState*, EncodedJSValue, EncodedJSValue);
} // namespace JSC
@@ -54,7 +48,7 @@ static void setRegExpConstructorMultiline(ExecState*, JSObject*, EncodedJSValue,
namespace JSC {
-const ClassInfo RegExpConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::regExpConstructorTable, CREATE_METHOD_TABLE(RegExpConstructor) };
+const ClassInfo RegExpConstructor::s_info = { "Function", &InternalFunction::s_info, &regExpConstructorTable, CREATE_METHOD_TABLE(RegExpConstructor) };
/* Source for RegExpConstructor.lut.h
@begin regExpConstructorTable
@@ -70,35 +64,36 @@ const ClassInfo RegExpConstructor::s_info = { "Function", &InternalFunction::s_i
$` regExpConstructorLeftContext DontDelete|ReadOnly|DontEnum
rightContext regExpConstructorRightContext DontDelete|ReadOnly
$' regExpConstructorRightContext DontDelete|ReadOnly|DontEnum
- $1 regExpConstructorDollar1 DontDelete|ReadOnly
- $2 regExpConstructorDollar2 DontDelete|ReadOnly
- $3 regExpConstructorDollar3 DontDelete|ReadOnly
- $4 regExpConstructorDollar4 DontDelete|ReadOnly
- $5 regExpConstructorDollar5 DontDelete|ReadOnly
- $6 regExpConstructorDollar6 DontDelete|ReadOnly
- $7 regExpConstructorDollar7 DontDelete|ReadOnly
- $8 regExpConstructorDollar8 DontDelete|ReadOnly
- $9 regExpConstructorDollar9 DontDelete|ReadOnly
+ $1 regExpConstructorDollar<1> DontDelete|ReadOnly
+ $2 regExpConstructorDollar<2> DontDelete|ReadOnly
+ $3 regExpConstructorDollar<3> DontDelete|ReadOnly
+ $4 regExpConstructorDollar<4> DontDelete|ReadOnly
+ $5 regExpConstructorDollar<5> DontDelete|ReadOnly
+ $6 regExpConstructorDollar<6> DontDelete|ReadOnly
+ $7 regExpConstructorDollar<7> DontDelete|ReadOnly
+ $8 regExpConstructorDollar<8> DontDelete|ReadOnly
+ $9 regExpConstructorDollar<9> DontDelete|ReadOnly
@end
*/
RegExpConstructor::RegExpConstructor(VM& vm, Structure* structure, RegExpPrototype* regExpPrototype)
: InternalFunction(vm, structure)
- , m_cachedResult(vm, this, regExpPrototype->regExp())
+ , m_cachedResult(vm, this, regExpPrototype->emptyRegExp())
, m_multiline(false)
{
}
-void RegExpConstructor::finishCreation(VM& vm, RegExpPrototype* regExpPrototype)
+void RegExpConstructor::finishCreation(VM& vm, RegExpPrototype* regExpPrototype, GetterSetter* speciesSymbol)
{
- Base::finishCreation(vm, Identifier(&vm, "RegExp").string());
- ASSERT(inherits(info()));
+ Base::finishCreation(vm, ASCIILiteral("RegExp"));
+ ASSERT(inherits(vm, info()));
- // 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);
+
+ putDirectNonIndexAccessor(vm, vm.propertyNames->speciesSymbol, speciesSymbol, Accessor | ReadOnly | DontEnum);
}
void RegExpConstructor::destroy(JSCell* cell)
@@ -110,16 +105,13 @@ void RegExpConstructor::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
RegExpConstructor* thisObject = jsCast<RegExpConstructor*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
-
Base::visitChildren(thisObject, visitor);
thisObject->m_cachedResult.visitChildren(visitor);
}
JSValue RegExpConstructor::getBackref(ExecState* exec, unsigned i)
{
- RegExpMatchesArray* array = m_cachedResult.lastResult(exec, this);
+ JSArray* array = m_cachedResult.lastResult(exec, this);
if (i < array->length()) {
JSValue result = JSValue(array).get(exec, i);
@@ -132,7 +124,7 @@ JSValue RegExpConstructor::getBackref(ExecState* exec, unsigned i)
JSValue RegExpConstructor::getLastParen(ExecState* exec)
{
- RegExpMatchesArray* array = m_cachedResult.lastResult(exec, this);
+ JSArray* array = m_cachedResult.lastResult(exec, this);
unsigned length = array->length();
if (length > 1) {
JSValue result = JSValue(array).get(exec, length - 1);
@@ -145,171 +137,197 @@ JSValue RegExpConstructor::getLastParen(ExecState* exec)
JSValue RegExpConstructor::getLeftContext(ExecState* exec)
{
- return m_cachedResult.lastResult(exec, this)->leftContext(exec);
+ return m_cachedResult.leftContext(exec, this);
}
JSValue RegExpConstructor::getRightContext(ExecState* exec)
{
- return m_cachedResult.lastResult(exec, this)->rightContext(exec);
-}
-
-bool RegExpConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
-{
- return getStaticValueSlot<RegExpConstructor, InternalFunction>(exec, ExecState::regExpConstructorTable(exec->vm()), jsCast<RegExpConstructor*>(object), propertyName, slot);
+ return m_cachedResult.rightContext(exec, this);
}
-static inline RegExpConstructor* asRegExpConstructor(EncodedJSValue value)
+template<int N>
+EncodedJSValue regExpConstructorDollar(ExecState* exec, EncodedJSValue thisValue, PropertyName)
{
- return jsCast<RegExpConstructor*>(JSValue::decode(value));
-}
-
-EncodedJSValue regExpConstructorDollar1(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
-{
- return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 1));
+ return JSValue::encode(asRegExpConstructor(JSValue::decode(thisValue))->getBackref(exec, N));
}
-EncodedJSValue regExpConstructorDollar2(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
+EncodedJSValue regExpConstructorInput(ExecState*, EncodedJSValue thisValue, PropertyName)
{
- return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 2));
+ return JSValue::encode(asRegExpConstructor(JSValue::decode(thisValue))->input());
}
-EncodedJSValue regExpConstructorDollar3(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
+EncodedJSValue regExpConstructorMultiline(ExecState*, EncodedJSValue thisValue, PropertyName)
{
- return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 3));
+ return JSValue::encode(jsBoolean(asRegExpConstructor(JSValue::decode(thisValue))->multiline()));
}
-EncodedJSValue regExpConstructorDollar4(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
+EncodedJSValue regExpConstructorLastMatch(ExecState* exec, EncodedJSValue thisValue, PropertyName)
{
- return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 4));
+ return JSValue::encode(asRegExpConstructor(JSValue::decode(thisValue))->getBackref(exec, 0));
}
-EncodedJSValue regExpConstructorDollar5(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
+EncodedJSValue regExpConstructorLastParen(ExecState* exec, EncodedJSValue thisValue, PropertyName)
{
- return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 5));
+ return JSValue::encode(asRegExpConstructor(JSValue::decode(thisValue))->getLastParen(exec));
}
-EncodedJSValue regExpConstructorDollar6(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
+EncodedJSValue regExpConstructorLeftContext(ExecState* exec, EncodedJSValue thisValue, PropertyName)
{
- return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 6));
+ return JSValue::encode(asRegExpConstructor(JSValue::decode(thisValue))->getLeftContext(exec));
}
-EncodedJSValue regExpConstructorDollar7(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
+EncodedJSValue regExpConstructorRightContext(ExecState* exec, EncodedJSValue thisValue, PropertyName)
{
- return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 7));
+ return JSValue::encode(asRegExpConstructor(JSValue::decode(thisValue))->getRightContext(exec));
}
-EncodedJSValue regExpConstructorDollar8(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
+bool setRegExpConstructorInput(ExecState* exec, EncodedJSValue thisValue, EncodedJSValue value)
{
- return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 8));
+ if (auto constructor = jsDynamicCast<RegExpConstructor*>(exec->vm(), JSValue::decode(thisValue))) {
+ constructor->setInput(exec, JSValue::decode(value).toString(exec));
+ return true;
+ }
+ return false;
}
-EncodedJSValue regExpConstructorDollar9(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
+bool setRegExpConstructorMultiline(ExecState* exec, EncodedJSValue thisValue, EncodedJSValue value)
{
- return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 9));
+ if (auto constructor = jsDynamicCast<RegExpConstructor*>(exec->vm(), JSValue::decode(thisValue))) {
+ constructor->setMultiline(JSValue::decode(value).toBoolean(exec));
+ return true;
+ }
+ return false;
}
-EncodedJSValue regExpConstructorInput(ExecState*, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
+inline Structure* getRegExpStructure(ExecState* exec, JSGlobalObject* globalObject, JSValue newTarget)
{
- return JSValue::encode(asRegExpConstructor(slotBase)->input());
+ Structure* structure = globalObject->regExpStructure();
+ if (newTarget != jsUndefined())
+ structure = InternalFunction::createSubclassStructure(exec, newTarget, structure);
+ return structure;
}
-EncodedJSValue regExpConstructorMultiline(ExecState*, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
+inline RegExpFlags toFlags(ExecState* exec, JSValue flags)
{
- return JSValue::encode(jsBoolean(asRegExpConstructor(slotBase)->multiline()));
-}
+ VM& vm = exec->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
-EncodedJSValue regExpConstructorLastMatch(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
-{
- return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 0));
-}
+ if (flags.isUndefined())
+ return NoFlags;
+ JSString* flagsString = flags.toStringOrNull(exec);
+ ASSERT(!!scope.exception() == !flagsString);
+ if (UNLIKELY(!flagsString))
+ return InvalidFlags;
-EncodedJSValue regExpConstructorLastParen(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
-{
- return JSValue::encode(asRegExpConstructor(slotBase)->getLastParen(exec));
+ RegExpFlags result = regExpFlags(flagsString->value(exec));
+ RETURN_IF_EXCEPTION(scope, InvalidFlags);
+ if (result == InvalidFlags)
+ throwSyntaxError(exec, scope, ASCIILiteral("Invalid flags supplied to RegExp constructor."));
+ return result;
}
-EncodedJSValue regExpConstructorLeftContext(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
+static JSObject* regExpCreate(ExecState* exec, JSGlobalObject* globalObject, JSValue newTarget, JSValue patternArg, JSValue flagsArg)
{
- return JSValue::encode(asRegExpConstructor(slotBase)->getLeftContext(exec));
-}
+ VM& vm = exec->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
-EncodedJSValue regExpConstructorRightContext(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
-{
- return JSValue::encode(asRegExpConstructor(slotBase)->getRightContext(exec));
-}
+ String pattern = patternArg.isUndefined() ? emptyString() : patternArg.toWTFString(exec);
+ RETURN_IF_EXCEPTION(scope, nullptr);
-void setRegExpConstructorInput(ExecState* exec, JSObject* baseObject, EncodedJSValue, EncodedJSValue value)
-{
- if (auto constructor = jsDynamicCast<RegExpConstructor*>(baseObject))
- constructor->setInput(exec, JSValue::decode(value).toString(exec));
-}
+ RegExpFlags flags = toFlags(exec, flagsArg);
+ ASSERT(!!scope.exception() == (flags == InvalidFlags));
+ if (UNLIKELY(flags == InvalidFlags))
+ return nullptr;
-void setRegExpConstructorMultiline(ExecState* exec, JSObject* baseObject, EncodedJSValue, EncodedJSValue value)
-{
- if (auto constructor = jsDynamicCast<RegExpConstructor*>(baseObject))
- constructor->setMultiline(JSValue::decode(value).toBoolean(exec));
+ RegExp* regExp = RegExp::create(vm, pattern, flags);
+ if (!regExp->isValid())
+ return throwException(exec, scope, createSyntaxError(exec, regExp->errorMessage()));
+
+ Structure* structure = getRegExpStructure(exec, globalObject, newTarget);
+ RETURN_IF_EXCEPTION(scope, nullptr);
+ return RegExpObject::create(vm, structure, regExp);
}
-// ECMA 15.10.4
-JSObject* constructRegExp(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, bool callAsConstructor)
+JSObject* constructRegExp(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, JSObject* callee, JSValue newTarget)
{
- JSValue arg0 = args.at(0);
- JSValue arg1 = args.at(1);
-
- if (arg0.inherits(RegExpObject::info())) {
- if (!arg1.isUndefined())
- 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);
+ VM& vm = exec->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+ JSValue patternArg = args.at(0);
+ JSValue flagsArg = args.at(1);
+
+ bool isPatternRegExp = patternArg.inherits(vm, RegExpObject::info());
+ bool constructAsRegexp = isRegExp(vm, exec, patternArg);
+ RETURN_IF_EXCEPTION(scope, nullptr);
+
+ if (newTarget.isUndefined() && constructAsRegexp && flagsArg.isUndefined()) {
+ JSValue constructor = patternArg.get(exec, vm.propertyNames->constructor);
+ RETURN_IF_EXCEPTION(scope, nullptr);
+ if (callee == constructor) {
+ // We know that patternArg is a object otherwise constructAsRegexp would be false.
+ return patternArg.getObject();
+ }
+ }
+
+ if (isPatternRegExp) {
+ RegExp* regExp = jsCast<RegExpObject*>(patternArg)->regExp();
+ Structure* structure = getRegExpStructure(exec, globalObject, newTarget);
+ RETURN_IF_EXCEPTION(scope, nullptr);
+
+ if (!flagsArg.isUndefined()) {
+ RegExpFlags flags = toFlags(exec, flagsArg);
+ ASSERT(!!scope.exception() == (flags == InvalidFlags));
+ if (flags == InvalidFlags)
+ return nullptr;
+ regExp = RegExp::create(vm, regExp->pattern(), flags);
}
- return asObject(arg0);
+
+ return RegExpObject::create(vm, structure, regExp);
}
- 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.")));
+ if (constructAsRegexp) {
+ JSValue pattern = patternArg.get(exec, vm.propertyNames->source);
+ RETURN_IF_EXCEPTION(scope, nullptr);
+ if (flagsArg.isUndefined()) {
+ flagsArg = patternArg.get(exec, vm.propertyNames->flags);
+ RETURN_IF_EXCEPTION(scope, nullptr);
+ }
+ patternArg = pattern;
}
- VM& vm = exec->vm();
- RegExp* regExp = RegExp::create(vm, pattern, flags);
- if (!regExp->isValid())
- return vm.throwException(exec, createSyntaxError(exec, regExp->errorMessage()));
- return RegExpObject::create(vm, globalObject->regExpStructure(), regExp);
+ scope.release();
+ return regExpCreate(exec, globalObject, newTarget, patternArg, flagsArg);
+}
+
+EncodedJSValue JSC_HOST_CALL esSpecRegExpCreate(ExecState* exec)
+{
+ JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+ JSValue patternArg = exec->argument(0);
+ JSValue flagsArg = exec->argument(1);
+ return JSValue::encode(regExpCreate(exec, globalObject, jsUndefined(), patternArg, flagsArg));
}
static EncodedJSValue JSC_HOST_CALL constructWithRegExpConstructor(ExecState* exec)
{
ArgList args(exec);
- return JSValue::encode(constructRegExp(exec, asInternalFunction(exec->callee())->globalObject(), args, true));
+ return JSValue::encode(constructRegExp(exec, asInternalFunction(exec->jsCallee())->globalObject(), args, exec->jsCallee(), exec->newTarget()));
}
ConstructType RegExpConstructor::getConstructData(JSCell*, ConstructData& constructData)
{
constructData.native.function = constructWithRegExpConstructor;
- return ConstructTypeHost;
+ return ConstructType::Host;
}
-// ECMA 15.10.3
static EncodedJSValue JSC_HOST_CALL callRegExpConstructor(ExecState* exec)
{
ArgList args(exec);
- return JSValue::encode(constructRegExp(exec, asInternalFunction(exec->callee())->globalObject(), args));
+ return JSValue::encode(constructRegExp(exec, asInternalFunction(exec->jsCallee())->globalObject(), args, exec->jsCallee()));
}
CallType RegExpConstructor::getCallData(JSCell*, CallData& callData)
{
callData.native.function = callRegExpConstructor;
- return CallTypeHost;
+ return CallType::Host;
}
} // namespace JSC