+2012-03-17 Gavin Barraclough <barraclough@apple.com>
+
+ Strength reduction, RegExp.exec -> RegExp.test
+ https://bugs.webkit.org/show_bug.cgi?id=81459
+
+ Reviewed by Sam Weinig.
+
+ RegExp.prototype.exec & RegExp.prototype.test can both be used to test a regular
+ expression for a match against a string - however exec is more expensive, since
+ it allocates a matches array object. In cases where the result is consumed in a
+ boolean context the allocation of the matches array can be trivially elided.
+
+ For example:
+ function f()
+ {
+ for (i =0; i < 10000000; ++i)
+ if(!/a/.exec("a"))
+ err = true;
+ }
+
+ This is a 2.5x speedup on this example microbenchmark loop.
+
+ In a more advanced form of this optimization, we may be able to avoid allocating
+ the array where access to the array can be observed.
+
+ * create_hash_table:
+ * dfg/DFGAbstractState.cpp:
+ (JSC::DFG::AbstractState::execute):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::handleIntrinsic):
+ * dfg/DFGNode.h:
+ (JSC::DFG::Node::hasHeapPrediction):
+ * dfg/DFGNodeType.h:
+ (DFG):
+ * dfg/DFGOperations.cpp:
+ * dfg/DFGOperations.h:
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ (JSC::DFG::PredictionPropagationPhase::propagate):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compileRegExpExec):
+ (DFG):
+ * dfg/DFGSpeculativeJIT.h:
+ (JSC::DFG::SpeculativeJIT::callOperation):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * jsc.cpp:
+ (GlobalObject::addConstructableFunction):
+ * runtime/Intrinsic.h:
+ * runtime/JSFunction.cpp:
+ (JSC::JSFunction::create):
+ (JSC):
+ * runtime/JSFunction.h:
+ (JSFunction):
+ * runtime/Lookup.cpp:
+ (JSC::setUpStaticFunctionSlot):
+ * runtime/RegExpObject.cpp:
+ (JSC::RegExpObject::exec):
+ (JSC::RegExpObject::match):
+ * runtime/RegExpObject.h:
+ (RegExpObject):
+ * runtime/RegExpPrototype.cpp:
+ (JSC::regExpProtoFuncTest):
+ (JSC::regExpProtoFuncExec):
+
2012-03-16 Michael Saboff <msaboff@apple.com>
Improve diagnostic benefit of JSGlobalData::m_isInitializingObject
$intrinsic = "ArrayPushIntrinsic" if ($key eq "push");
$intrinsic = "ArrayPopIntrinsic" if ($key eq "pop");
}
+ if ($name eq "regExpPrototypeTable") {
+ $intrinsic = "RegExpExecIntrinsic" if ($key eq "exec");
+ $intrinsic = "RegExpTestIntrinsic" if ($key eq "test");
+ }
print " { \"$key\", $attrs[$i], (intptr_t)" . $castStr . "($firstValue), (intptr_t)$secondValue, $intrinsic },\n";
$i++;
forNode(nodeIndex).makeTop();
break;
+ case RegExpExec:
+ case RegExpTest:
+ forNode(node.child1()).filter(PredictCell);
+ forNode(node.child2()).filter(PredictCell);
+ forNode(nodeIndex).makeTop();
+ break;
+
case Jump:
break;
return true;
}
+ case RegExpExecIntrinsic: {
+ if (argumentCountIncludingThis != 2)
+ return false;
+
+ NodeIndex regExpExec = addToGraph(RegExpExec, OpInfo(0), OpInfo(prediction), get(registerOffset + argumentToOperand(0)), get(registerOffset + argumentToOperand(1)));
+ if (usesResult)
+ set(resultOperand, regExpExec);
+
+ return true;
+ }
+
+ case RegExpTestIntrinsic: {
+ if (argumentCountIncludingThis != 2)
+ return false;
+
+ NodeIndex regExpExec = addToGraph(RegExpTest, OpInfo(0), OpInfo(prediction), get(registerOffset + argumentToOperand(0)), get(registerOffset + argumentToOperand(1)));
+ if (usesResult)
+ set(resultOperand, regExpExec);
+
+ return true;
+ }
+
default:
return false;
}
case ResolveGlobal:
case ArrayPop:
case ArrayPush:
+ case RegExpExec:
+ case RegExpTest:
return true;
default:
return false;
macro(ArrayPush, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
macro(ArrayPop, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
\
+ /* Optimizations for regular expression matching. */\
+ macro(RegExpExec, NodeResultJS | NodeMustGenerate) \
+ macro(RegExpTest, NodeResultJS | NodeMustGenerate) \
+ \
/* Optimizations for string access */ \
macro(StringCharCodeAt, NodeResultInt32) \
macro(StringCharAt, NodeResultJS) \
array->push(exec, JSValue::decode(encodedValue));
return JSValue::encode(jsNumber(array->length()));
}
+
+EncodedJSValue DFG_OPERATION operationRegExpExec(ExecState* exec, JSCell* base, JSCell* argument)
+{
+ if (!base->inherits(&RegExpObject::s_info))
+ return throwVMTypeError(exec);
+
+ ASSERT(argument->isString() || argument->isObject());
+ JSString* input = argument->isString() ? asString(argument) : asObject(argument)->toString(exec);
+ return JSValue::encode(asRegExpObject(base)->exec(exec, input));
+}
+
+size_t DFG_OPERATION operationRegExpTest(ExecState* exec, JSCell* base, JSCell* argument)
+{
+ if (!base->inherits(&RegExpObject::s_info)) {
+ throwTypeError(exec);
+ return false;
+ }
+
+ ASSERT(argument->isString() || argument->isObject());
+ JSString* input = argument->isString() ? asString(argument) : asObject(argument)->toString(exec);
+ return asRegExpObject(base)->match(exec, input);
+}
EncodedJSValue DFG_OPERATION operationArrayPop(ExecState* exec, JSArray* array)
{
I: Identifier*
G: GlobalResolveInfo*
*/
-typedef int32_t DFG_OPERATION (*Z_DFGOperation_D)(double);
-typedef JSCell* DFG_OPERATION (*C_DFGOperation_E)(ExecState*);
-typedef JSCell* DFG_OPERATION (*C_DFGOperation_EC)(ExecState*, JSCell*);
-typedef JSCell* DFG_OPERATION (*C_DFGOperation_ECC)(ExecState*, JSCell*, JSCell*);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EA)(ExecState*, JSArray*);
-typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EJA)(ExecState*, EncodedJSValue, JSArray*);
+typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ECC)(ExecState*, JSCell*, JSCell*);
+typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ECI)(ExecState*, JSCell*, Identifier*);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ECJ)(ExecState*, JSCell*, EncodedJSValue);
-typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EJJ)(ExecState*, EncodedJSValue, EncodedJSValue);
+typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EGI)(ExecState*, GlobalResolveInfo*, Identifier*);
+typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EI)(ExecState*, Identifier*);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EJ)(ExecState*, EncodedJSValue);
-typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EJP)(ExecState*, EncodedJSValue, void*);
-typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ECI)(ExecState*, JSCell*, Identifier*);
+typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EJA)(ExecState*, EncodedJSValue, JSArray*);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EJI)(ExecState*, EncodedJSValue, Identifier*);
+typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EJJ)(ExecState*, EncodedJSValue, EncodedJSValue);
+typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EJP)(ExecState*, EncodedJSValue, void*);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EP)(ExecState*, void*);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EPP)(ExecState*, void*, void*);
-typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EGI)(ExecState*, GlobalResolveInfo*, Identifier*);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EPS)(ExecState*, void*, size_t);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ESS)(ExecState*, size_t, size_t);
-typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EI)(ExecState*, Identifier*);
+typedef JSCell* DFG_OPERATION (*C_DFGOperation_E)(ExecState*);
+typedef JSCell* DFG_OPERATION (*C_DFGOperation_EC)(ExecState*, JSCell*);
+typedef JSCell* DFG_OPERATION (*C_DFGOperation_ECC)(ExecState*, JSCell*, JSCell*);
+typedef double DFG_OPERATION (*D_DFGOperation_DD)(double, double);
+typedef double DFG_OPERATION (*D_DFGOperation_EJ)(ExecState*, EncodedJSValue);
+typedef int32_t DFG_OPERATION (*Z_DFGOperation_D)(double);
+typedef size_t DFG_OPERATION (*S_DFGOperation_ECC)(ExecState*, JSCell*, JSCell*);
typedef size_t DFG_OPERATION (*S_DFGOperation_EJ)(ExecState*, EncodedJSValue);
typedef size_t DFG_OPERATION (*S_DFGOperation_EJJ)(ExecState*, EncodedJSValue, EncodedJSValue);
-typedef void DFG_OPERATION (*V_DFGOperation_EJJJ)(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue);
+typedef void DFG_OPERATION (*V_DFGOperation_EAZJ)(ExecState*, JSArray*, int32_t, EncodedJSValue);
typedef void DFG_OPERATION (*V_DFGOperation_ECJJ)(ExecState*, JSCell*, EncodedJSValue, EncodedJSValue);
-typedef void DFG_OPERATION (*V_DFGOperation_EJPP)(ExecState*, EncodedJSValue, EncodedJSValue, void*);
typedef void DFG_OPERATION (*V_DFGOperation_EJCI)(ExecState*, EncodedJSValue, JSCell*, Identifier*);
+typedef void DFG_OPERATION (*V_DFGOperation_EJJJ)(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue);
+typedef void DFG_OPERATION (*V_DFGOperation_EJPP)(ExecState*, EncodedJSValue, EncodedJSValue, void*);
typedef void DFG_OPERATION (*V_DFGOperation_EPZJ)(ExecState*, void*, int32_t, EncodedJSValue);
-typedef void DFG_OPERATION (*V_DFGOperation_EAZJ)(ExecState*, JSArray*, int32_t, EncodedJSValue);
-typedef double DFG_OPERATION (*D_DFGOperation_DD)(double, double);
-typedef double DFG_OPERATION (*D_DFGOperation_EJ)(ExecState*, EncodedJSValue);
-typedef void* DFG_OPERATION (*P_DFGOperation_E)(ExecState*);
typedef void DFG_OPERATION (V_DFGOperation_EC)(ExecState*, JSCell*);
+typedef void* DFG_OPERATION (*P_DFGOperation_E)(ExecState*);
// These routines are provide callbacks out to C++ implementations of operations too complex to JIT.
JSCell* DFG_OPERATION operationNewObject(ExecState*);
void DFG_OPERATION operationPutByValBeyondArrayBoundsNonStrict(ExecState*, JSArray*, int32_t index, EncodedJSValue encodedValue);
EncodedJSValue DFG_OPERATION operationArrayPush(ExecState*, EncodedJSValue encodedValue, JSArray*);
EncodedJSValue DFG_OPERATION operationArrayPop(ExecState*, JSArray*);
+EncodedJSValue DFG_OPERATION operationRegExpExec(ExecState*, JSCell*, JSCell*);
void DFG_OPERATION operationPutByIdStrict(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*);
void DFG_OPERATION operationPutByIdNonStrict(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*);
void DFG_OPERATION operationPutByIdDirectStrict(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*);
void DFG_OPERATION operationPutByIdDirectStrictBuildList(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*);
void DFG_OPERATION operationPutByIdDirectNonStrictBuildList(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*);
// These comparisons return a boolean within a size_t such that the value is zero extended to fill the register.
+size_t DFG_OPERATION operationRegExpTest(ExecState*, JSCell*, JSCell*);
size_t DFG_OPERATION operationCompareLess(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2);
size_t DFG_OPERATION operationCompareLessEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2);
size_t DFG_OPERATION operationCompareGreater(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2);
break;
}
+ case RegExpExec:
+ case RegExpTest: {
+ if (node.getHeapPrediction())
+ changed |= mergePrediction(node.getHeapPrediction());
+ changed |= mergeDefaultArithFlags(node, flags);
+ break;
+ }
+
case StringCharCodeAt: {
changed |= mergePrediction(PredictInt32);
changed |= mergeDefaultArithFlags(node, flags);
cellResult(resultGPR, m_compileIndex);
}
+bool SpeculativeJIT::compileRegExpExec(Node& node)
+{
+ unsigned branchIndexInBlock = detectPeepHoleBranch();
+ if (branchIndexInBlock == UINT_MAX)
+ return false;
+ NodeIndex branchNodeIndex = m_jit.graph().m_blocks[m_block]->at(branchIndexInBlock);
+ ASSERT(node.adjustedRefCount() == 1);
+
+ Node& branchNode = at(branchNodeIndex);
+ BlockIndex taken = branchNode.takenBlockIndex();
+ BlockIndex notTaken = branchNode.notTakenBlockIndex();
+
+ bool invert = false;
+ if (taken == (m_block + 1)) {
+ invert = true;
+ BlockIndex tmp = taken;
+ taken = notTaken;
+ notTaken = tmp;
+ }
+
+ SpeculateCellOperand base(this, node.child1());
+ SpeculateCellOperand argument(this, node.child2());
+ GPRReg baseGPR = base.gpr();
+ GPRReg argumentGPR = argument.gpr();
+
+ flushRegisters();
+ GPRResult result(this);
+ callOperation(operationRegExpTest, result.gpr(), baseGPR, argumentGPR);
+
+ branchTest32(invert ? JITCompiler::Zero : JITCompiler::NonZero, result.gpr(), taken);
+ jump(notTaken);
+
+ use(node.child1());
+ use(node.child2());
+ m_indexInBlock = branchIndexInBlock;
+ m_compileIndex = branchNodeIndex;
+
+ return true;
+}
+
} } // namespace JSC::DFG
#endif
m_jit.setupArgumentsWithExecState(arg1, arg2);
return appendCallWithExceptionCheckSetResult(operation, result);
}
+ JITCompiler::Call callOperation(S_DFGOperation_ECC operation, GPRReg result, GPRReg arg1, GPRReg arg2)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, arg2);
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
JITCompiler::Call callOperation(J_DFGOperation_EPP operation, GPRReg result, GPRReg arg1, GPRReg arg2)
{
m_jit.setupArgumentsWithExecState(arg1, arg2);
m_jit.setupArgumentsWithExecState(MacroAssembler::TrustedImmPtr(static_cast<const void*>(JSValue::encode(jsNumber(imm.m_value)))), arg2);
return appendCallWithExceptionCheckSetResult(operation, result);
}
+ JITCompiler::Call callOperation(J_DFGOperation_ECC operation, GPRReg result, GPRReg arg1, GPRReg arg2)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, arg2);
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
JITCompiler::Call callOperation(J_DFGOperation_ECJ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
{
m_jit.setupArgumentsWithExecState(arg1, arg2);
m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag);
return appendCallWithExceptionCheckSetResult(operation, result);
}
+ JITCompiler::Call callOperation(S_DFGOperation_ECC operation, GPRReg result, GPRReg arg1, GPRReg arg2)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, arg2);
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
JITCompiler::Call callOperation(S_DFGOperation_EJJ operation, GPRReg result, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2Tag, GPRReg arg2Payload)
{
m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag, arg2Payload, arg2Tag);
m_jit.setupArgumentsWithExecState(arg1, arg2Payload, arg2Tag);
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
+ JITCompiler::Call callOperation(J_DFGOperation_ECC operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1, GPRReg arg2)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, arg2);
+ return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
+ }
JITCompiler::Call callOperation(V_DFGOperation_EC operation, GPRReg arg1)
{
m_jit.setupArgumentsWithExecState(arg1);
void compilePutByValForIntTypedArray(const TypedArrayDescriptor&, GPRReg base, GPRReg property, Node&, size_t elementSize, TypedArraySpeculationRequirements, TypedArraySignedness, TypedArrayRounding = TruncateRounding);
void compileGetByValOnFloatTypedArray(const TypedArrayDescriptor&, Node&, size_t elementSize, TypedArraySpeculationRequirements);
void compilePutByValForFloatTypedArray(const TypedArrayDescriptor&, GPRReg base, GPRReg property, Node&, size_t elementSize, TypedArraySpeculationRequirements);
- void compileNewFunctionNoCheck(Node& node);
- void compileNewFunctionExpression(Node& node);
+ void compileNewFunctionNoCheck(Node&);
+ void compileNewFunctionExpression(Node&);
+ bool compileRegExpExec(Node&);
template <typename ClassType, bool destructor, typename StructureType>
void emitAllocateBasicJSObject(StructureType structure, GPRReg resultGPR, GPRReg scratchGPR, MacroAssembler::JumpList& slowPath)
break;
}
+ case RegExpExec: {
+ if (compileRegExpExec(node))
+ return;
+
+ if (!node.adjustedRefCount()) {
+ SpeculateCellOperand base(this, node.child1());
+ SpeculateCellOperand argument(this, node.child2());
+ GPRReg baseGPR = base.gpr();
+ GPRReg argumentGPR = argument.gpr();
+
+ flushRegisters();
+ GPRResult result(this);
+ callOperation(operationRegExpTest, result.gpr(), baseGPR, argumentGPR);
+
+ noResult(m_compileIndex);
+ break;
+ }
+
+ SpeculateCellOperand base(this, node.child1());
+ SpeculateCellOperand argument(this, node.child2());
+ GPRReg baseGPR = base.gpr();
+ GPRReg argumentGPR = argument.gpr();
+
+ flushRegisters();
+ GPRResult2 resultTag(this);
+ GPRResult resultPayload(this);
+ callOperation(operationRegExpExec, resultTag.gpr(), resultPayload.gpr(), baseGPR, argumentGPR);
+
+ jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex);
+ break;
+ }
+
+ case RegExpTest: {
+ SpeculateCellOperand base(this, node.child1());
+ SpeculateCellOperand argument(this, node.child2());
+ GPRReg baseGPR = base.gpr();
+ GPRReg argumentGPR = argument.gpr();
+
+ flushRegisters();
+ GPRResult result(this);
+ callOperation(operationRegExpTest, result.gpr(), baseGPR, argumentGPR);
+
+ // If we add a DataFormatBool, we should use it here.
+ booleanResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
case ArrayPush: {
SpeculateCellOperand base(this, node.child1());
JSValueOperand value(this, node.child2());
break;
}
+ case RegExpExec: {
+ if (compileRegExpExec(node))
+ return;
+
+ if (!node.adjustedRefCount()) {
+ SpeculateCellOperand base(this, node.child1());
+ SpeculateCellOperand argument(this, node.child2());
+ GPRReg baseGPR = base.gpr();
+ GPRReg argumentGPR = argument.gpr();
+
+ flushRegisters();
+ GPRResult result(this);
+ callOperation(operationRegExpTest, result.gpr(), baseGPR, argumentGPR);
+
+ noResult(m_compileIndex);
+ break;
+ }
+
+ SpeculateCellOperand base(this, node.child1());
+ SpeculateCellOperand argument(this, node.child2());
+ GPRReg baseGPR = base.gpr();
+ GPRReg argumentGPR = argument.gpr();
+
+ flushRegisters();
+ GPRResult result(this);
+ callOperation(operationRegExpExec, result.gpr(), baseGPR, argumentGPR);
+
+ jsValueResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ case RegExpTest: {
+ SpeculateCellOperand base(this, node.child1());
+ SpeculateCellOperand argument(this, node.child2());
+ GPRReg baseGPR = base.gpr();
+ GPRReg argumentGPR = argument.gpr();
+
+ flushRegisters();
+ GPRResult result(this);
+ callOperation(operationRegExpTest, result.gpr(), baseGPR, argumentGPR);
+
+ // If we add a DataFormatBool, we should use it here.
+ m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
+ jsValueResult(result.gpr(), m_compileIndex, DataFormatJSBoolean);
+ break;
+ }
+
case ArrayPush: {
SpeculateCellOperand base(this, node.child1());
JSValueOperand value(this, node.child2());
void addConstructableFunction(JSGlobalData& globalData, const char* name, NativeFunction function, unsigned arguments)
{
Identifier identifier(globalExec(), name);
- putDirect(globalData, identifier, JSFunction::create(globalExec(), this, arguments, identifier, function, function));
+ putDirect(globalData, identifier, JSFunction::create(globalExec(), this, arguments, identifier, function, NoIntrinsic, function));
}
};
COMPILE_ASSERT(!IsInteger<GlobalObject>::value, WTF_IsInteger_GlobalObject_false);
RoundIntrinsic,
ExpIntrinsic,
LogIntrinsic,
+ RegExpExecIntrinsic,
+ RegExpTestIntrinsic,
};
} // namespace JSC
return isHostFunction();
}
-JSFunction* JSFunction::create(ExecState* exec, JSGlobalObject* globalObject, int length, const Identifier& name, NativeFunction nativeFunction, NativeFunction nativeConstructor)
+JSFunction* JSFunction::create(ExecState* exec, JSGlobalObject* globalObject, int length, const Identifier& name, NativeFunction nativeFunction, Intrinsic intrinsic, NativeFunction nativeConstructor)
{
- NativeExecutable* executable = exec->globalData().getHostFunction(nativeFunction, nativeConstructor);
+ NativeExecutable* executable;
+#if ENABLE(JIT)
+ if (intrinsic != NoIntrinsic && exec->globalData().canUseJIT()) {
+ ASSERT(nativeConstructor == callHostFunctionAsConstructor);
+ executable = exec->globalData().getHostFunction(nativeFunction, intrinsic);
+ } else
+#endif
+ executable = exec->globalData().getHostFunction(nativeFunction, nativeConstructor);
+
JSFunction* function = new (NotNull, allocateCell<JSFunction>(*exec->heap())) JSFunction(exec, globalObject, globalObject->functionStructure());
// Can't do this during initialization because getHostFunction might do a GC allocation.
function->finishCreation(exec, executable, length, name);
return function;
}
-JSFunction* JSFunction::create(ExecState* exec, JSGlobalObject* globalObject, int length, const Identifier& name, NativeExecutable* nativeExecutable)
-{
- JSFunction* function = new (NotNull, allocateCell<JSFunction>(*exec->heap())) JSFunction(exec, globalObject, globalObject->functionStructure());
- function->finishCreation(exec, nativeExecutable, length, name);
- return function;
-}
-
JSFunction::JSFunction(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
: Base(exec->globalData(), structure)
, m_executable()
public:
typedef JSNonFinalObject Base;
- JS_EXPORT_PRIVATE static JSFunction* create(ExecState*, JSGlobalObject*, int length, const Identifier& name, NativeFunction nativeFunction, NativeFunction nativeConstructor = callHostFunctionAsConstructor);
- static JSFunction* create(ExecState*, JSGlobalObject*, int length, const Identifier& name, NativeExecutable* nativeExecutable);
+ JS_EXPORT_PRIVATE static JSFunction* create(ExecState*, JSGlobalObject*, int length, const Identifier& name, NativeFunction nativeFunction, Intrinsic = NoIntrinsic, NativeFunction nativeConstructor = callHostFunctionAsConstructor);
static JSFunction* create(ExecState* exec, FunctionExecutable* executable, ScopeChainNode* scopeChain)
{
if (thisObj->staticFunctionsReified())
return false;
- JSFunction* function;
- JSGlobalObject* globalObject = thisObj->globalObject();
-#if ENABLE(JIT)
- if (exec->globalData().canUseJIT() && entry->intrinsic() != NoIntrinsic)
- function = JSFunction::create(exec, globalObject, entry->functionLength(), propertyName, exec->globalData().getHostFunction(entry->function(), entry->intrinsic()));
- else
-#endif
- function = JSFunction::create(exec, globalObject, entry->functionLength(), propertyName, entry->function());
-
+ JSFunction* function = JSFunction::create(exec, thisObj->globalObject(), entry->functionLength(), propertyName, entry->function(), entry->intrinsic());
thisObj->putDirect(exec->globalData(), propertyName, function, entry->attributes());
location = thisObj->getDirectLocation(exec->globalData(), propertyName);
}
lookupPut<RegExpObject, JSObject>(exec, propertyName, value, ExecState::regExpTable(exec), jsCast<RegExpObject*>(cell), slot);
}
-JSValue RegExpObject::test(ExecState* exec)
+JSValue RegExpObject::exec(ExecState* exec, JSString* string)
{
- return jsBoolean(match(exec));
-}
-
-JSValue RegExpObject::exec(ExecState* exec)
-{
- if (match(exec))
+ if (match(exec, string))
return exec->lexicalGlobalObject()->regExpConstructor()->arrayOfMatches(exec);
return jsNull();
}
// Shared implementation used by test and exec.
-bool RegExpObject::match(ExecState* exec)
+bool RegExpObject::match(ExecState* exec, JSString* string)
{
RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
- UString input = exec->argument(0).toString(exec)->value(exec);
+ UString input = string->value(exec);
JSGlobalData* globalData = &exec->globalData();
if (!regExp()->global()) {
int position;
return m_lastIndex.get();
}
- JSValue test(ExecState*);
- JSValue exec(ExecState*);
+ bool match(ExecState*, JSString* string);
+ JSValue exec(ExecState*, JSString* string);
static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier& propertyName, PropertySlot&);
static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, const Identifier& propertyName, PropertyDescriptor&, bool shouldThrow);
private:
- bool match(ExecState*);
-
WriteBarrier<RegExp> m_regExp;
WriteBarrier<Unknown> m_lastIndex;
bool m_lastIndexIsWritable;
JSValue thisValue = exec->hostThisValue();
if (!thisValue.inherits(&RegExpObject::s_info))
return throwVMTypeError(exec);
- return JSValue::encode(asRegExpObject(thisValue)->test(exec));
+ return JSValue::encode(jsBoolean(asRegExpObject(thisValue)->match(exec, exec->argument(0).toString(exec))));
}
EncodedJSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState* exec)
JSValue thisValue = exec->hostThisValue();
if (!thisValue.inherits(&RegExpObject::s_info))
return throwVMTypeError(exec);
- return JSValue::encode(asRegExpObject(thisValue)->exec(exec));
+ return JSValue::encode(asRegExpObject(thisValue)->exec(exec, exec->argument(0).toString(exec)));
}
EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState* exec)