[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:
parent
c5479518e0
commit
a1e9a6d77f
@ -345,6 +345,12 @@ void BytecodeGraphBuilder::VisitCreateClosure(
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGraphBuilder::VisitCreateRegExpLiteral(
|
||||
const interpreter::BytecodeArrayIterator& iterator) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGraphBuilder::VisitCreateArrayLiteral(
|
||||
const interpreter::BytecodeArrayIterator& iterator) {
|
||||
UNIMPLEMENTED();
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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) \
|
||||
\
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user