[Interpreter] Add support for RegExp literals.

Adds support for creating RegExp literals and adds some tests. Adds the
CreateRegExpLiteral bytecode.

BUG=v8:4280
LOG=N
TBR=bmeurer@chromium.org

Review URL: https://codereview.chromium.org/1410853002

Cr-Commit-Position: refs/heads/master@{#31345}
This commit is contained in:
rmcilroy 2015-10-16 09:14:23 -07:00 committed by Commit bot
parent c5479518e0
commit a1e9a6d77f
9 changed files with 166 additions and 19 deletions

View File

@ -345,6 +345,12 @@ void BytecodeGraphBuilder::VisitCreateClosure(
}
void BytecodeGraphBuilder::VisitCreateRegExpLiteral(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::VisitCreateArrayLiteral(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();

View File

@ -353,6 +353,18 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CreateClosure(
}
BytecodeArrayBuilder& BytecodeArrayBuilder::CreateRegExpLiteral(
int literal_index, Register flags) {
if (FitsInIdx8Operand(literal_index)) {
Output(Bytecode::kCreateRegExpLiteral, static_cast<uint8_t>(literal_index),
flags.ToOperand());
} else {
UNIMPLEMENTED();
}
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArrayLiteral(
int literal_index, int flags) {
DCHECK(FitsInImm8Operand(flags)); // Flags should fit in 8 bytes.

View File

@ -98,6 +98,7 @@ class BytecodeArrayBuilder {
BytecodeArrayBuilder& CreateClosure(PretenureFlag tenured);
// Literals creation. Constant elements should be in the accumulator.
BytecodeArrayBuilder& CreateRegExpLiteral(int literal_index, Register flags);
BytecodeArrayBuilder& CreateArrayLiteral(int literal_index, int flags);
BytecodeArrayBuilder& CreateObjectLiteral(int literal_index, int flags);

View File

@ -538,7 +538,14 @@ void BytecodeGenerator::VisitLiteral(Literal* expr) {
void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
UNIMPLEMENTED();
// Materialize a regular expression literal.
TemporaryRegisterScope temporary_register_scope(builder());
Register flags = temporary_register_scope.NewRegister();
builder()
->LoadLiteral(expr->flags())
.StoreAccumulatorInRegister(flags)
.LoadLiteral(expr->pattern())
.CreateRegExpLiteral(expr->literal_index(), flags);
}

View File

@ -114,6 +114,7 @@ namespace interpreter {
V(ToName, OperandType::kNone) \
\
/* Literals */ \
V(CreateRegExpLiteral, OperandType::kIdx8, OperandType::kReg8) \
V(CreateArrayLiteral, OperandType::kIdx8, OperandType::kImm8) \
V(CreateObjectLiteral, OperandType::kIdx8, OperandType::kImm8) \
\

View File

@ -767,23 +767,6 @@ void Interpreter::DoJumpIfFalseConstant(
}
void Interpreter::DoCreateLiteral(Runtime::FunctionId function_id,
compiler::InterpreterAssembler* assembler) {
Node* constant_elements = __ GetAccumulator();
Node* literal_index_raw = __ BytecodeOperandIdx8(0);
Node* literal_index = __ SmiTag(literal_index_raw);
Node* flags_raw = __ BytecodeOperandImm8(1);
Node* flags = __ SmiTag(flags_raw);
Node* closure = __ LoadRegister(Register::function_closure());
Node* literals_array =
__ LoadObjectField(closure, JSFunction::kLiteralsOffset);
Node* result = __ CallRuntime(function_id, literals_array, literal_index,
constant_elements, flags);
__ SetAccumulator(result);
__ Dispatch();
}
// JumpIfToBooleanTrue <imm8>
//
// Jump by number of bytes represented by an immediate operand if the object
@ -850,6 +833,44 @@ void Interpreter::DoJumpIfToBooleanFalseConstant(
}
// CreateRegExpLiteral <idx> <flags_reg>
//
// Creates a regular expression literal for literal index <idx> with flags held
// in <flags_reg> and the pattern in the accumulator.
void Interpreter::DoCreateRegExpLiteral(
compiler::InterpreterAssembler* assembler) {
Node* pattern = __ GetAccumulator();
Node* literal_index_raw = __ BytecodeOperandIdx8(0);
Node* literal_index = __ SmiTag(literal_index_raw);
Node* flags_reg = __ BytecodeOperandReg8(1);
Node* flags = __ LoadRegister(flags_reg);
Node* closure = __ LoadRegister(Register::function_closure());
Node* literals_array =
__ LoadObjectField(closure, JSFunction::kLiteralsOffset);
Node* result = __ CallRuntime(Runtime::kMaterializeRegExpLiteral,
literals_array, literal_index, pattern, flags);
__ SetAccumulator(result);
__ Dispatch();
}
void Interpreter::DoCreateLiteral(Runtime::FunctionId function_id,
compiler::InterpreterAssembler* assembler) {
Node* constant_elements = __ GetAccumulator();
Node* literal_index_raw = __ BytecodeOperandIdx8(0);
Node* literal_index = __ SmiTag(literal_index_raw);
Node* flags_raw = __ BytecodeOperandImm8(1);
Node* flags = __ SmiTag(flags_raw);
Node* closure = __ LoadRegister(Register::function_closure());
Node* literals_array =
__ LoadObjectField(closure, JSFunction::kLiteralsOffset);
Node* result = __ CallRuntime(function_id, literals_array, literal_index,
constant_elements, flags);
__ SetAccumulator(result);
__ Dispatch();
}
// CreateArrayLiteral <idx> <flags>
//
// Creates an array literal for literal index <idx> with flags <flags> and

View File

@ -2063,6 +2063,75 @@ TEST(FunctionLiterals) {
}
TEST(RegExpLiterals) {
InitializedHandleScope handle_scope;
BytecodeGeneratorHelper helper;
Zone zone;
FeedbackVectorSpec feedback_spec(&zone);
feedback_spec.AddLoadICSlot();
FeedbackVectorSlot slot2 = feedback_spec.AddLoadICSlot();
Handle<i::TypeFeedbackVector> vector =
i::NewTypeFeedbackVector(helper.isolate(), &feedback_spec);
ExpectedSnippet<const char*> snippets[] = {
{"return /ab+d/;",
1 * kPointerSize,
1,
10,
{
B(LdaConstant), U8(0), //
B(Star), R(0), //
B(LdaConstant), U8(1), //
B(CreateRegExpLiteral), U8(0), R(0), //
B(Return), //
},
2,
{"", "ab+d"}},
{"return /(\\w+)\\s(\\w+)/i;",
1 * kPointerSize,
1,
10,
{
B(LdaConstant), U8(0), //
B(Star), R(0), //
B(LdaConstant), U8(1), //
B(CreateRegExpLiteral), U8(0), R(0), //
B(Return), //
},
2,
{"i", "(\\w+)\\s(\\w+)"}},
{"return /ab+d/.exec('abdd');",
3 * kPointerSize,
1,
27,
{
B(LdaConstant), U8(0), //
B(Star), R(2), //
B(LdaConstant), U8(1), //
B(CreateRegExpLiteral), U8(0), R(2), //
B(Star), R(1), //
B(LdaConstant), U8(2), //
B(LoadICSloppy), R(1), U8(vector->GetIndex(slot2)), //
B(Star), R(0), //
B(LdaConstant), U8(3), //
B(Star), R(2), //
B(Call), R(0), R(1), U8(1), //
B(Return), //
},
4,
{"", "ab+d", "exec", "abdd"}},
};
for (size_t i = 0; i < arraysize(snippets); i++) {
Handle<BytecodeArray> bytecode_array =
helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet);
CheckBytecodeArrayEqual(snippets[i], bytecode_array);
}
}
TEST(ArrayLiterals) {
InitializedHandleScope handle_scope;
BytecodeGeneratorHelper helper;

View File

@ -1683,6 +1683,35 @@ TEST(InterpreterFunctionLiteral) {
}
TEST(InterpreterRegExpLiterals) {
HandleAndZoneScope handles;
i::Isolate* isolate = handles.main_isolate();
i::Factory* factory = isolate->factory();
std::pair<const char*, Handle<Object>> literals[5] = {
std::make_pair("return /abd/.exec('cccabbdd');\n",
factory->null_value()),
std::make_pair("return /ab+d/.exec('cccabbdd')[0];\n",
factory->NewStringFromStaticChars("abbd")),
std::make_pair("return /AbC/i.exec('ssaBC')[0];\n",
factory->NewStringFromStaticChars("aBC")),
std::make_pair("return 'ssaBC'.match(/AbC/i)[0];\n",
factory->NewStringFromStaticChars("aBC")),
std::make_pair("return 'ssaBCtAbC'.match(/(AbC)/gi)[1];\n",
factory->NewStringFromStaticChars("AbC")),
};
for (size_t i = 0; i < arraysize(literals); i++) {
std::string source(InterpreterTester::SourceForBody(literals[i].first));
InterpreterTester tester(handles.main_isolate(), source.c_str());
auto callable = tester.GetCallable<>();
Handle<i::Object> return_value = callable().ToHandleChecked();
CHECK(return_value->SameValue(*literals[i].second));
}
}
TEST(InterpreterArrayLiterals) {
HandleAndZoneScope handles;
i::Isolate* isolate = handles.main_isolate();

View File

@ -68,7 +68,8 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
builder.CreateClosure(NOT_TENURED);
// Emit literal creation operations
builder.CreateArrayLiteral(0, 0)
builder.CreateRegExpLiteral(0, reg)
.CreateArrayLiteral(0, 0)
.CreateObjectLiteral(0, 0);
// Call operations.