Index: src/x64/full-codegen-x64.cc |
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc |
index a8626b3164bc56274617dcbf67028cbdbdeecb1a..4d74735ebd0ad90282f60fec43e715fc09e70cc3 100644 |
--- a/src/x64/full-codegen-x64.cc |
+++ b/src/x64/full-codegen-x64.cc |
@@ -1199,26 +1199,54 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var, |
void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
Comment cmnt(masm_, "[ RegExpLiteral"); |
- Label done; |
+ Label materialized; |
// Registers will be used as follows: |
// rdi = JS function. |
- // rbx = literals array. |
- // rax = regexp literal. |
+ // rcx = literals array. |
+ // rbx = regexp literal. |
+ // rax = regexp literal clone. |
__ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
- __ movq(rbx, FieldOperand(rdi, JSFunction::kLiteralsOffset)); |
+ __ movq(rcx, FieldOperand(rdi, JSFunction::kLiteralsOffset)); |
int literal_offset = |
FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; |
- __ movq(rax, FieldOperand(rbx, literal_offset)); |
- __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
- __ j(not_equal, &done); |
+ __ movq(rbx, FieldOperand(rcx, literal_offset)); |
+ __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex); |
+ __ j(not_equal, &materialized); |
+ |
// Create regexp literal using runtime function |
// Result will be in rax. |
- __ push(rbx); |
+ __ push(rcx); |
__ Push(Smi::FromInt(expr->literal_index())); |
__ Push(expr->pattern()); |
__ Push(expr->flags()); |
__ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); |
- __ bind(&done); |
+ __ movq(rbx, rax); |
+ |
+ __ bind(&materialized); |
+ int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize; |
+ Label allocated, runtime_allocate; |
+ __ AllocateInNewSpace(size, rax, rcx, rdx, &runtime_allocate, TAG_OBJECT); |
+ __ jmp(&allocated); |
+ |
+ __ bind(&runtime_allocate); |
+ __ push(rbx); |
+ __ Push(Smi::FromInt(size)); |
+ __ CallRuntime(Runtime::kAllocateInNewSpace, 1); |
+ __ pop(rbx); |
+ |
+ __ bind(&allocated); |
+ // Copy the content into the newly allocated memory. |
+ // (Unroll copy loop once for better throughput). |
+ for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) { |
+ __ movq(rdx, FieldOperand(rbx, i)); |
+ __ movq(rcx, FieldOperand(rbx, i + kPointerSize)); |
+ __ movq(FieldOperand(rax, i), rdx); |
+ __ movq(FieldOperand(rax, i + kPointerSize), rcx); |
+ } |
+ if ((size % (2 * kPointerSize)) != 0) { |
+ __ movq(rdx, FieldOperand(rbx, size - kPointerSize)); |
+ __ movq(FieldOperand(rax, size - kPointerSize), rdx); |
+ } |
Apply(context_, rax); |
} |
@@ -2644,6 +2672,44 @@ void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) { |
} |
+void FullCodeGenerator::EmitIsRegExpEquivalent(ZoneList<Expression*>* args) { |
+ ASSERT_EQ(2, args->length()); |
+ |
+ Register right = rax; |
+ Register left = rbx; |
+ Register tmp = rcx; |
+ |
+ VisitForValue(args->at(0), kStack); |
+ VisitForValue(args->at(1), kAccumulator); |
+ __ pop(left); |
+ |
+ Label done, fail, ok; |
+ __ cmpq(left, right); |
+ __ j(equal, &ok); |
+ // Fail if either is a non-HeapObject. |
+ Condition either_smi = masm()->CheckEitherSmi(left, right, tmp); |
+ __ j(either_smi, &fail); |
+ __ j(zero, &fail); |
+ __ movq(tmp, FieldOperand(left, HeapObject::kMapOffset)); |
+ __ cmpb(FieldOperand(tmp, Map::kInstanceTypeOffset), |
+ Immediate(JS_REGEXP_TYPE)); |
+ __ j(not_equal, &fail); |
+ __ cmpq(tmp, FieldOperand(right, HeapObject::kMapOffset)); |
+ __ j(not_equal, &fail); |
+ __ movq(tmp, FieldOperand(left, JSRegExp::kDataOffset)); |
+ __ cmpq(tmp, FieldOperand(right, JSRegExp::kDataOffset)); |
+ __ j(equal, &ok); |
+ __ bind(&fail); |
+ __ Move(rax, Factory::false_value()); |
+ __ jmp(&done); |
+ __ bind(&ok); |
+ __ Move(rax, Factory::true_value()); |
+ __ bind(&done); |
+ |
+ Apply(context_, rax); |
+} |
+ |
+ |
void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { |
Handle<String> name = expr->name(); |
if (name->length() > 0 && name->Get(0) == '_') { |