Revision: 8772
Author: [email protected]
Date: Mon Aug 1 11:06:10 2011
Log: Merge regexp codeflushing (r8532+r8560) to the 3.3 branch.
Slava and Danno: this was a clean merge, but please do take a good look
anyway.
Review URL: http://codereview.chromium.org/7540025
http://code.google.com/p/v8/source/detail?r=8772
Added:
/branches/3.3/test/mjsunit/regress/regress-regexp-codeflush.js
Modified:
/branches/3.3/src/arm/code-stubs-arm.cc
/branches/3.3/src/factory.cc
/branches/3.3/src/heap.cc
/branches/3.3/src/heap.h
/branches/3.3/src/ia32/code-stubs-ia32.cc
/branches/3.3/src/jsregexp.cc
/branches/3.3/src/mark-compact.cc
/branches/3.3/src/objects-debug.cc
/branches/3.3/src/objects-inl.h
/branches/3.3/src/objects-visiting.cc
/branches/3.3/src/objects-visiting.h
/branches/3.3/src/objects.h
/branches/3.3/src/regexp.js
/branches/3.3/src/string.js
/branches/3.3/src/version.cc
/branches/3.3/src/x64/code-stubs-x64.cc
=======================================
--- /dev/null
+++ /branches/3.3/test/mjsunit/regress/regress-regexp-codeflush.js Mon Aug
1 11:06:10 2011
@@ -0,0 +1,55 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --gc_global
+
+// Regression test for regexp that has multiple matches and which
+// internally calls RegExpImpl::IrregexpExecOnce more than once without
+// ensuring that the regexp is compiled.
+// This can create a crash if the code was exchanged with the sweep
+// generation (for code flushing support) in GC durring the matching.
+
+var re = new RegExp('(s)', "g");
+
+function foo() {
+ return "42";
+}
+
+// Run enough times to get a number of GC's (all mark sweep because of the
+// --gc_global) flag.
+for ( var i = 0; i < 10; i++) {
+ // Make a long string with plenty of matches for re.
+ var x = "s foo s bar s foo s bar s";
+ x = x + x;
+ x = x + x;
+ x = x + x;
+ x = x + x;
+ x = x + x;
+ x = x + x;
+ x = x + x;
+ x.replace(re, foo);
+}
=======================================
--- /branches/3.3/src/arm/code-stubs-arm.cc Fri Jun 24 04:54:25 2011
+++ /branches/3.3/src/arm/code-stubs-arm.cc Mon Aug 1 11:06:10 2011
@@ -4226,9 +4226,8 @@
// Check that the irregexp code has been generated for the actual string
// encoding. If it has, the field contains a code object otherwise it
contains
- // the hole.
- __ CompareObjectType(r7, r0, r0, CODE_TYPE);
- __ b(ne, &runtime);
+ // a smi (code flushing support).
+ __ JumpIfSmi(r7, &runtime);
// r3: encoding of subject string (1 if ASCII, 0 if two_byte);
// r7: code
=======================================
--- /branches/3.3/src/factory.cc Wed May 25 00:58:50 2011
+++ /branches/3.3/src/factory.cc Mon Aug 1 11:06:10 2011
@@ -1189,12 +1189,14 @@
JSRegExp::Flags flags,
int capture_count) {
Handle<FixedArray> store = NewFixedArray(JSRegExp::kIrregexpDataSize);
-
+ Smi* uninitialized = Smi::FromInt(JSRegExp::kUninitializedValue);
store->set(JSRegExp::kTagIndex, Smi::FromInt(type));
store->set(JSRegExp::kSourceIndex, *source);
store->set(JSRegExp::kFlagsIndex, Smi::FromInt(flags.value()));
- store->set(JSRegExp::kIrregexpASCIICodeIndex, HEAP->the_hole_value());
- store->set(JSRegExp::kIrregexpUC16CodeIndex, HEAP->the_hole_value());
+ store->set(JSRegExp::kIrregexpASCIICodeIndex, uninitialized);
+ store->set(JSRegExp::kIrregexpUC16CodeIndex, uninitialized);
+ store->set(JSRegExp::kIrregexpASCIICodeSavedIndex, uninitialized);
+ store->set(JSRegExp::kIrregexpUC16CodeSavedIndex, uninitialized);
store->set(JSRegExp::kIrregexpMaxRegisterCountIndex, Smi::FromInt(0));
store->set(JSRegExp::kIrregexpCaptureCountIndex,
Smi::FromInt(capture_count));
=======================================
--- /branches/3.3/src/heap.cc Wed May 25 00:58:50 2011
+++ /branches/3.3/src/heap.cc Mon Aug 1 11:06:10 2011
@@ -96,6 +96,7 @@
// Will be 4 * reserved_semispace_size_ to ensure that young
// generation can be aligned to its size.
survived_since_last_expansion_(0),
+ sweep_generation_(0),
always_allocate_scope_depth_(0),
linear_allocation_scope_depth_(0),
contexts_disposed_(0),
@@ -736,7 +737,7 @@
if (collector == MARK_COMPACTOR) {
// Perform mark-sweep with optional compaction.
MarkCompact(tracer);
-
+ sweep_generation_++;
bool high_survival_rate_during_scavenges = IsHighSurvivalRate() &&
IsStableOrIncreasingSurvivalTrend();
@@ -1292,6 +1293,10 @@
&ObjectEvacuationStrategy<POINTER_OBJECT>::
template
VisitSpecialized<SharedFunctionInfo::kSize>);
+ table_.Register(kVisitJSRegExp,
+ &ObjectEvacuationStrategy<POINTER_OBJECT>::
+ Visit);
+
table_.Register(kVisitJSFunction,
&ObjectEvacuationStrategy<POINTER_OBJECT>::
template VisitSpecialized<JSFunction::kSize>);
=======================================
--- /branches/3.3/src/heap.h Wed May 25 00:58:50 2011
+++ /branches/3.3/src/heap.h Mon Aug 1 11:06:10 2011
@@ -1227,6 +1227,11 @@
ExternalStringTable* external_string_table() {
return &external_string_table_;
}
+
+ // Returns the current sweep generation.
+ int sweep_generation() {
+ return sweep_generation_;
+ }
inline Isolate* isolate();
bool is_safe_to_read_maps() { return is_safe_to_read_maps_; }
@@ -1257,6 +1262,9 @@
// scavenge since last new space expansion.
int survived_since_last_expansion_;
+ // For keeping track on when to flush RegExp code.
+ int sweep_generation_;
+
int always_allocate_scope_depth_;
int linear_allocation_scope_depth_;
=======================================
--- /branches/3.3/src/ia32/code-stubs-ia32.cc Mon May 30 07:32:41 2011
+++ /branches/3.3/src/ia32/code-stubs-ia32.cc Mon Aug 1 11:06:10 2011
@@ -3199,9 +3199,8 @@
__ bind(&check_code);
// Check that the irregexp code has been generated for the actual string
// encoding. If it has, the field contains a code object otherwise it
contains
- // the hole.
- __ CmpObjectType(edx, CODE_TYPE, ebx);
- __ j(not_equal, &runtime);
+ // a smi (code flushing support).
+ __ JumpIfSmi(edx, &runtime);
// eax: subject string
// edx: code
=======================================
--- /branches/3.3/src/jsregexp.cc Mon Jun 20 06:21:43 2011
+++ /branches/3.3/src/jsregexp.cc Mon Aug 1 11:06:10 2011
@@ -295,8 +295,33 @@
#else // V8_INTERPRETED_REGEXP (RegExp native code)
if (compiled_code->IsCode()) return true;
#endif
+ // We could potentially have marked this as flushable, but have kept
+ // a saved version if we did not flush it yet.
+ Object* saved_code = re->DataAt(JSRegExp::saved_code_index(is_ascii));
+ if (saved_code->IsCode()) {
+ // Reinstate the code in the original place.
+ re->SetDataAt(JSRegExp::code_index(is_ascii), saved_code);
+ ASSERT(compiled_code->IsSmi());
+ return true;
+ }
return CompileIrregexp(re, is_ascii);
}
+
+
+static bool CreateRegExpErrorObjectAndThrow(Handle<JSRegExp> re,
+ bool is_ascii,
+ Handle<String> error_message,
+ Isolate* isolate) {
+ Factory* factory = isolate->factory();
+ Handle<FixedArray> elements = factory->NewFixedArray(2);
+ elements->set(0, re->Pattern());
+ elements->set(1, *error_message);
+ Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
+ Handle<Object> regexp_err =
+ factory->NewSyntaxError("malformed_regexp", array);
+ isolate->Throw(*regexp_err);
+ return false;
+}
bool RegExpImpl::CompileIrregexp(Handle<JSRegExp> re, bool is_ascii) {
@@ -304,14 +329,28 @@
Isolate* isolate = re->GetIsolate();
CompilationZoneScope zone_scope(isolate, DELETE_ON_EXIT);
PostponeInterruptsScope postpone(isolate);
+ // If we had a compilation error the last time this is saved at the
+ // saved code index.
Object* entry = re->DataAt(JSRegExp::code_index(is_ascii));
- if (entry->IsJSObject()) {
- // If it's a JSObject, a previous compilation failed and threw this
object.
- // Re-throw the object without trying again.
- isolate->Throw(entry);
+ // When arriving here entry can only be a smi, either representing an
+ // uncompiled regexp, a previous compilation error, or code that has
+ // been flushed.
+ ASSERT(entry->IsSmi());
+ int entry_value = Smi::cast(entry)->value();
+ ASSERT(entry_value == JSRegExp::kUninitializedValue ||
+ entry_value == JSRegExp::kCompilationErrorValue ||
+ (entry_value < JSRegExp::kCodeAgeMask && entry_value >= 0));
+
+ if (entry_value == JSRegExp::kCompilationErrorValue) {
+ // A previous compilation failed and threw an error which we store in
+ // the saved code index (we store the error message, not the actual
+ // error). Recreate the error object and throw it.
+ Object* error_string =
re->DataAt(JSRegExp::saved_code_index(is_ascii));
+ ASSERT(error_string->IsString());
+ Handle<String> error_message(String::cast(error_string));
+ CreateRegExpErrorObjectAndThrow(re, is_ascii, error_message, isolate);
return false;
}
- ASSERT(entry->IsTheHole());
JSRegExp::Flags flags = re->GetFlags();
@@ -340,17 +379,9 @@
is_ascii);
if (result.error_message != NULL) {
// Unable to compile regexp.
- Factory* factory = isolate->factory();
- Handle<FixedArray> elements = factory->NewFixedArray(2);
- elements->set(0, *pattern);
Handle<String> error_message =
- factory->NewStringFromUtf8(CStrVector(result.error_message));
- elements->set(1, *error_message);
- Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
- Handle<Object> regexp_err =
- factory->NewSyntaxError("malformed_regexp", array);
- isolate->Throw(*regexp_err);
- re->SetDataAt(JSRegExp::code_index(is_ascii), *regexp_err);
+
isolate->factory()->NewStringFromUtf8(CStrVector(result.error_message));
+ CreateRegExpErrorObjectAndThrow(re, is_ascii, error_message, isolate);
return false;
}
@@ -460,6 +491,7 @@
ASSERT(output.length() >= (IrregexpNumberOfCaptures(*irregexp) + 1) * 2);
do {
bool is_ascii = subject->IsAsciiRepresentation();
+ EnsureCompiledIrregexp(regexp, is_ascii);
Handle<Code> code(IrregexpNativeCode(*irregexp, is_ascii), isolate);
NativeRegExpMacroAssembler::Result res =
NativeRegExpMacroAssembler::Match(code,
=======================================
--- /branches/3.3/src/mark-compact.cc Wed May 25 00:58:50 2011
+++ /branches/3.3/src/mark-compact.cc Mon Aug 1 11:06:10 2011
@@ -422,6 +422,9 @@
table_.Register(kVisitJSFunction,
&VisitJSFunctionAndFlushCode);
+ table_.Register(kVisitJSRegExp,
+ &VisitRegExpAndFlushCode);
+
table_.Register(kVisitPropertyCell,
&FixedBodyVisitor<StaticMarkingVisitor,
JSGlobalPropertyCell::BodyDescriptor,
@@ -562,6 +565,8 @@
// flushed.
static const int kCodeAgeThreshold = 5;
+ static const int kRegExpCodeThreshold = 5;
+
inline static bool HasSourceCode(Heap* heap, SharedFunctionInfo* info) {
Object* undefined = heap->raw_unchecked_undefined_value();
return (info->script() != undefined) &&
@@ -695,6 +700,68 @@
SharedFunctionInfo::BodyDescriptor,
void>::Visit(map, object);
}
+
+
+ static void UpdateRegExpCodeAgeAndFlush(Heap* heap,
+ JSRegExp* re,
+ bool is_ascii) {
+ // Make sure that the fixed array is in fact initialized on the RegExp.
+ // We could potentially trigger a GC when initializing the RegExp.
+ if (SafeMap(re->data())->instance_type() != FIXED_ARRAY_TYPE) return;
+
+ // Make sure this is a RegExp that actually contains code.
+ if (re->TypeTagUnchecked() != JSRegExp::IRREGEXP) return;
+
+ Object* code = re->DataAtUnchecked(JSRegExp::code_index(is_ascii));
+ if (!code->IsSmi() && SafeMap(code)->instance_type() == CODE_TYPE) {
+ // Save a copy that can be reinstated if we need the code again.
+ re->SetDataAtUnchecked(JSRegExp::saved_code_index(is_ascii),
+ code,
+ heap);
+ // Set a number in the 0-255 range to guarantee no smi overflow.
+ re->SetDataAtUnchecked(JSRegExp::code_index(is_ascii),
+ Smi::FromInt(heap->sweep_generation() & 0xff),
+ heap);
+ } else if (code->IsSmi()) {
+ int value = Smi::cast(code)->value();
+ // The regexp has not been compiled yet or there was a compilation
error.
+ if (value == JSRegExp::kUninitializedValue ||
+ value == JSRegExp::kCompilationErrorValue) {
+ return;
+ }
+
+ // Check if we should flush now.
+ if (value == ((heap->sweep_generation() - kRegExpCodeThreshold) &
0xff)) {
+ re->SetDataAtUnchecked(JSRegExp::code_index(is_ascii),
+ Smi::FromInt(JSRegExp::kUninitializedValue),
+ heap);
+ re->SetDataAtUnchecked(JSRegExp::saved_code_index(is_ascii),
+ Smi::FromInt(JSRegExp::kUninitializedValue),
+ heap);
+ }
+ }
+ }
+
+
+ // Works by setting the current sweep_generation (as a smi) in the
+ // code object place in the data array of the RegExp and keeps a copy
+ // around that can be reinstated if we reuse the RegExp before flushing.
+ // If we did not use the code for kRegExpCodeThreshold mark sweep GCs
+ // we flush the code.
+ static void VisitRegExpAndFlushCode(Map* map, HeapObject* object) {
+ Heap* heap = map->heap();
+ MarkCompactCollector* collector = heap->mark_compact_collector();
+ if (!collector->is_code_flushing_enabled()) {
+ VisitJSRegExpFields(map, object);
+ return;
+ }
+ JSRegExp* re = reinterpret_cast<JSRegExp*>(object);
+ // Flush code or set age on both ascii and two byte code.
+ UpdateRegExpCodeAgeAndFlush(heap, re, true);
+ UpdateRegExpCodeAgeAndFlush(heap, re, false);
+ // Visit the fields of the RegExp, including the updated FixedArray.
+ VisitJSRegExpFields(map, object);
+ }
static void VisitSharedFunctionInfoAndFlushCode(Map* map,
@@ -826,6 +893,15 @@
// Don't visit the next function list field as it is a weak reference.
}
+
+ static inline void VisitJSRegExpFields(Map* map,
+ HeapObject* object) {
+ int last_property_offset =
+ JSRegExp::kSize + kPointerSize * map->inobject_properties();
+ VisitPointers(map->heap(),
+ SLOT_ADDR(object, JSRegExp::kPropertiesOffset),
+ SLOT_ADDR(object, last_property_offset));
+ }
static void VisitSharedFunctionInfoFields(Heap* heap,
=======================================
--- /branches/3.3/src/objects-debug.cc Wed May 25 00:58:50 2011
+++ /branches/3.3/src/objects-debug.cc Mon Aug 1 11:06:10 2011
@@ -444,14 +444,22 @@
FixedArray* arr = FixedArray::cast(data());
Object* ascii_data = arr->get(JSRegExp::kIrregexpASCIICodeIndex);
- // TheHole : Not compiled yet.
+ // Smi : Not compiled yet (-1) or code prepared for flushing.
// JSObject: Compilation error.
// Code/ByteArray: Compiled code.
- ASSERT(ascii_data->IsTheHole() || ascii_data->IsJSObject() ||
- (is_native ? ascii_data->IsCode() : ascii_data->IsByteArray()));
+ ASSERT(ascii_data->IsSmi() ||
+ (is_native ? ascii_data->IsCode() :
ascii_data->IsByteArray()));
Object* uc16_data = arr->get(JSRegExp::kIrregexpUC16CodeIndex);
- ASSERT(uc16_data->IsTheHole() || uc16_data->IsJSObject() ||
- (is_native ? uc16_data->IsCode() : uc16_data->IsByteArray()));
+ ASSERT(uc16_data->IsSmi() ||
+ (is_native ? uc16_data->IsCode() : uc16_data->IsByteArray()));
+
+ Object* ascii_saved =
arr->get(JSRegExp::kIrregexpASCIICodeSavedIndex);
+ ASSERT(ascii_saved->IsSmi() || ascii_saved->IsString() ||
+ ascii_saved->IsCode());
+ Object* uc16_saved = arr->get(JSRegExp::kIrregexpUC16CodeSavedIndex);
+ ASSERT(uc16_saved->IsSmi() || uc16_saved->IsString() ||
+ uc16_saved->IsCode());
+
ASSERT(arr->get(JSRegExp::kIrregexpCaptureCountIndex)->IsSmi());
ASSERT(arr->get(JSRegExp::kIrregexpMaxRegisterCountIndex)->IsSmi());
break;
=======================================
--- /branches/3.3/src/objects-inl.h Wed May 25 00:58:50 2011
+++ /branches/3.3/src/objects-inl.h Mon Aug 1 11:06:10 2011
@@ -3717,6 +3717,12 @@
Smi* smi = Smi::cast(FixedArray::cast(data)->get(kTagIndex));
return static_cast<JSRegExp::Type>(smi->value());
}
+
+
+JSRegExp::Type JSRegExp::TypeTagUnchecked() {
+ Smi* smi = Smi::cast(DataAtUnchecked(kTagIndex));
+ return static_cast<JSRegExp::Type>(smi->value());
+}
int JSRegExp::CaptureCount() {
@@ -3752,6 +3758,13 @@
ASSERT(TypeTag() != NOT_COMPILED);
return FixedArray::cast(data())->get(index);
}
+
+
+Object* JSRegExp::DataAtUnchecked(int index) {
+ FixedArray* fa = reinterpret_cast<FixedArray*>(data());
+ int offset = FixedArray::kHeaderSize + index * kPointerSize;
+ return READ_FIELD(fa, offset);
+}
void JSRegExp::SetDataAt(int index, Object* value) {
@@ -3759,6 +3772,17 @@
ASSERT(index >= kDataIndex); // Only implementation data can be set
this way.
FixedArray::cast(data())->set(index, value);
}
+
+
+void JSRegExp::SetDataAtUnchecked(int index, Object* value, Heap* heap) {
+ ASSERT(index >= kDataIndex); // Only implementation data can be set
this way.
+ FixedArray* fa = reinterpret_cast<FixedArray*>(data());
+ if (value->IsSmi()) {
+ fa->set_unchecked(index, Smi::cast(value));
+ } else {
+ fa->set_unchecked(heap, index, value, SKIP_WRITE_BARRIER);
+ }
+}
JSObject::ElementsKind JSObject::GetElementsKind() {
=======================================
--- /branches/3.3/src/objects-visiting.cc Wed May 25 00:58:50 2011
+++ /branches/3.3/src/objects-visiting.cc Mon Aug 1 11:06:10 2011
@@ -85,6 +85,9 @@
case JS_GLOBAL_PROPERTY_CELL_TYPE:
return kVisitPropertyCell;
+ case JS_REGEXP_TYPE:
+ return kVisitJSRegExp;
+
case SHARED_FUNCTION_INFO_TYPE:
return kVisitSharedFunctionInfo;
@@ -105,7 +108,6 @@
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
case JS_VALUE_TYPE:
case JS_ARRAY_TYPE:
- case JS_REGEXP_TYPE:
case JS_GLOBAL_PROXY_TYPE:
case JS_GLOBAL_OBJECT_TYPE:
case JS_BUILTINS_OBJECT_TYPE:
=======================================
--- /branches/3.3/src/objects-visiting.h Mon May 9 02:42:16 2011
+++ /branches/3.3/src/objects-visiting.h Mon Aug 1 11:06:10 2011
@@ -104,6 +104,7 @@
kVisitPropertyCell,
kVisitSharedFunctionInfo,
kVisitJSFunction,
+ kVisitJSRegExp,
kVisitorIdCount,
kMinObjectSizeInWords = 2
@@ -297,6 +298,8 @@
SharedFunctionInfo::BodyDescriptor,
int>::Visit);
+ table_.Register(kVisitJSRegExp, &VisitJSRegExp);
+
table_.Register(kVisitSeqAsciiString, &VisitSeqAsciiString);
table_.Register(kVisitSeqTwoByteString, &VisitSeqTwoByteString);
@@ -333,6 +336,10 @@
return SeqAsciiString::cast(object)->
SeqAsciiStringSize(map->instance_type());
}
+
+ static inline int VisitJSRegExp(Map* map, HeapObject* object) {
+ return JSObjectVisitor::Visit(map, object);
+ }
static inline int VisitSeqTwoByteString(Map* map, HeapObject* object) {
return SeqTwoByteString::cast(object)->
=======================================
--- /branches/3.3/src/objects.h Wed May 25 00:58:50 2011
+++ /branches/3.3/src/objects.h Mon Aug 1 11:06:10 2011
@@ -5053,8 +5053,10 @@
// If it is an atom regexp
// - a reference to a literal string to search for
// If it is an irregexp regexp:
-// - a reference to code for ASCII inputs (bytecode or compiled).
-// - a reference to code for UC16 inputs (bytecode or compiled).
+// - a reference to code for ASCII inputs (bytecode or compiled), or a smi
+// used for tracking the last usage (used for code flushing).
+// - a reference to code for UC16 inputs (bytecode or compiled), or a smi
+// used for tracking the last usage (used for code flushing)..
// - max number of registers used by irregexp implementations.
// - number of capture registers (output values) of the regexp.
class JSRegExp: public JSObject {
@@ -5087,6 +5089,12 @@
inline Object* DataAt(int index);
// Set implementation data after the object has been prepared.
inline void SetDataAt(int index, Object* value);
+
+ // Used during GC when flushing code or setting age.
+ inline Object* DataAtUnchecked(int index);
+ inline void SetDataAtUnchecked(int index, Object* value, Heap* heap);
+ inline Type TypeTagUnchecked();
+
static int code_index(bool is_ascii) {
if (is_ascii) {
return kIrregexpASCIICodeIndex;
@@ -5094,6 +5102,14 @@
return kIrregexpUC16CodeIndex;
}
}
+
+ static int saved_code_index(bool is_ascii) {
+ if (is_ascii) {
+ return kIrregexpASCIICodeSavedIndex;
+ } else {
+ return kIrregexpUC16CodeSavedIndex;
+ }
+ }
static inline JSRegExp* cast(Object* obj);
@@ -5125,11 +5141,19 @@
// fails, this fields hold an exception object that should be
// thrown if the regexp is used again.
static const int kIrregexpUC16CodeIndex = kDataIndex + 1;
+
+ // Saved instance of Irregexp compiled code or bytecode for ASCII that
+ // is a potential candidate for flushing.
+ static const int kIrregexpASCIICodeSavedIndex = kDataIndex + 2;
+ // Saved instance of Irregexp compiled code or bytecode for UC16 that is
+ // a potential candidate for flushing.
+ static const int kIrregexpUC16CodeSavedIndex = kDataIndex + 3;
+
// Maximal number of registers used by either ASCII or UC16.
// Only used to check that there is enough stack space
- static const int kIrregexpMaxRegisterCountIndex = kDataIndex + 2;
+ static const int kIrregexpMaxRegisterCountIndex = kDataIndex + 4;
// Number of captures in the compiled regexp.
- static const int kIrregexpCaptureCountIndex = kDataIndex + 3;
+ static const int kIrregexpCaptureCountIndex = kDataIndex + 5;
static const int kIrregexpDataSize = kIrregexpCaptureCountIndex + 1;
@@ -5150,6 +5174,18 @@
static const int kMultilineFieldIndex = 3;
static const int kLastIndexFieldIndex = 4;
static const int kInObjectFieldCount = 5;
+
+ // The uninitialized value for a regexp code object.
+ static const int kUninitializedValue = -1;
+
+ // The compilation error value for the regexp code object. The real error
+ // object is in the saved code field.
+ static const int kCompilationErrorValue = -2;
+
+ // When we store the sweep generation at which we moved the code from the
+ // code index to the saved code index we mask it of to be in the [0:255]
+ // range.
+ static const int kCodeAgeMask = 0xff;
};
=======================================
--- /branches/3.3/src/regexp.js Sun May 22 23:06:11 2011
+++ /branches/3.3/src/regexp.js Mon Aug 1 11:06:10 2011
@@ -235,7 +235,7 @@
// Conversion is required by the ES5 specification (RegExp.prototype.exec
// algorithm, step 5) even if the value is discarded for non-global
RegExps.
var i = TO_INTEGER(lastIndex);
-
+
if (this.global) {
if (i < 0 || i > string.length) {
this.lastIndex = 0;
@@ -250,11 +250,11 @@
}
lastMatchInfoOverride = null;
this.lastIndex = lastMatchInfo[CAPTURE1];
- return true;
+ return true;
} else {
// Non-global regexp.
- // Remove irrelevant preceeding '.*' in a non-global test regexp.
- // The expression checks whether this.source starts with '.*' and
+ // Remove irrelevant preceeding '.*' in a non-global test regexp.
+ // The expression checks whether this.source starts with '.*' and
// that the third char is not a '?'.
if (%_StringCharCodeAt(this.source, 0) == 46 && // '.'
%_StringCharCodeAt(this.source, 1) == 42 && // '*'
@@ -262,14 +262,14 @@
if (!%_ObjectEquals(regexp_key, this)) {
regexp_key = this;
regexp_val = new $RegExp(SubString(this.source, 2,
this.source.length),
- (!this.ignoreCase
+ (!this.ignoreCase
? !this.multiline ? "" : "m"
: !this.multiline ? "i" : "im"));
}
if (%_RegExpExec(regexp_val, string, 0, lastMatchInfo) === null) {
return false;
}
- }
+ }
%_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, string, lastIndex]);
// matchIndices is either null or the lastMatchInfo array.
var matchIndices = %_RegExpExec(this, string, 0, lastMatchInfo);
=======================================
--- /branches/3.3/src/string.js Mon May 9 02:42:16 2011
+++ /branches/3.3/src/string.js Mon Aug 1 11:06:10 2011
@@ -274,7 +274,7 @@
// the result.
function ExpandReplacement(string, subject, matchInfo, builder) {
var length = string.length;
- var builder_elements = builder.elements;
+ var builder_elements = builder.elements;
var next = %StringIndexOf(string, '$', 0);
if (next < 0) {
if (length > 0) builder_elements.push(string);
=======================================
--- /branches/3.3/src/version.cc Thu Jul 21 05:28:18 2011
+++ /branches/3.3/src/version.cc Mon Aug 1 11:06:10 2011
@@ -35,7 +35,7 @@
#define MAJOR_VERSION 3
#define MINOR_VERSION 3
#define BUILD_NUMBER 10
-#define PATCH_LEVEL 22
+#define PATCH_LEVEL 23
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
#define IS_CANDIDATE_VERSION 0
=======================================
--- /branches/3.3/src/x64/code-stubs-x64.cc Mon May 30 07:32:41 2011
+++ /branches/3.3/src/x64/code-stubs-x64.cc Mon Aug 1 11:06:10 2011
@@ -2239,9 +2239,8 @@
__ bind(&check_code);
// Check that the irregexp code has been generated for the actual string
// encoding. If it has, the field contains a code object otherwise it
contains
- // the hole.
- __ CmpObjectType(r11, CODE_TYPE, kScratchRegister);
- __ j(not_equal, &runtime);
+ // smi (code flushing support)
+ __ JumpIfSmi(r11, &runtime);
// rdi: subject string
// rcx: encoding of subject string (1 if ascii, 0 if two_byte);
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev