}
+bool RedirectToExternalString(i::Isolate* isolate,
+ i::Handle<i::String> parent,
+ i::Handle<i::String> external) {
+ if (parent->IsConsString()) {
+ i::Handle<i::ConsString> cons = i::Handle<i::ConsString>::cast(parent);
+ cons->set_first(*external);
+ cons->set_second(isolate->heap()->empty_string());
+ } else {
+ ASSERT(parent->IsSlicedString());
+ i::Handle<i::SlicedString> slice = i::Handle<i::SlicedString>::cast(parent);
+ slice->set_parent(*external);
+ slice->set_offset(0);
+ }
+ return true;
+}
+
+
Local<String> v8::String::NewExternal(
v8::String::ExternalStringResource* resource) {
i::Isolate* isolate = i::Isolate::Current();
return false;
}
CHECK(resource && resource->data());
- bool result = obj->MakeExternal(resource);
- if (result && !obj->IsInternalizedString()) {
- isolate->heap()->external_string_table()->AddString(*obj);
+
+ bool result;
+ i::Handle<i::String> external;
+ if (isolate->heap()->old_pointer_space()->Contains(*obj)) {
+ // We do not allow external strings in the old pointer space. Instead of
+ // converting the string in-place, we keep the cons/sliced string and
+ // point it to a newly-allocated external string.
+ external = NewExternalStringHandle(isolate, resource);
+ result = RedirectToExternalString(isolate, obj, external);
+ } else {
+ result = obj->MakeExternal(resource);
+ external = obj;
+ }
+
+ ASSERT(external->IsExternalString());
+ if (result && !external->IsInternalizedString()) {
+ isolate->heap()->external_string_table()->AddString(*external);
}
return result;
}
return false;
}
CHECK(resource && resource->data());
- bool result = obj->MakeExternal(resource);
- if (result && !obj->IsInternalizedString()) {
- isolate->heap()->external_string_table()->AddString(*obj);
+
+ bool result;
+ i::Handle<i::String> external;
+ if (isolate->heap()->old_pointer_space()->Contains(*obj)) {
+ // We do not allow external strings in the old pointer space. Instead of
+ // converting the string in-place, we keep the cons/sliced string and
+ // point it to a newly-allocated external string.
+ external = NewExternalAsciiStringHandle(isolate, resource);
+ result = RedirectToExternalString(isolate, obj, external);
+ } else {
+ result = obj->MakeExternal(resource);
+ external = obj;
+ }
+
+ ASSERT(external->IsExternalString());
+ if (result && !external->IsInternalizedString()) {
+ isolate->heap()->external_string_table()->AddString(*external);
}
return result;
}
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
+ CompileRun("function cons(a, b) { return a + b; }"
+ "function slice(a) { return a.substring(1); }");
// Create a cons string that will land in old pointer space.
- Local<String> string = Local<String>::Cast(CompileRun(
- "function cons(a, b) { return a + b; }"
+ Local<String> cons = Local<String>::Cast(CompileRun(
"cons('abcdefghijklm', 'nopqrstuvwxyz');"));
+ // Create a sliced string that will land in old pointer space.
+ Local<String> slice = Local<String>::Cast(CompileRun(
+ "slice('abcdefghijklmnopqrstuvwxyz');"));
// Trigger GCs so that the newly allocated string moves to old gen.
SimulateFullSpace(HEAP->old_pointer_space());
// Turn into external string with unaligned resource data.
int dispose_count = 0;
- const char* c_source = "_abcdefghijklmnopqrstuvwxyz";
- bool success = string->MakeExternal(
- new TestAsciiResource(i::StrDup(c_source) + 1, &dispose_count));
+ const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
+ bool success = cons->MakeExternal(
+ new TestAsciiResource(i::StrDup(c_cons) + 1, &dispose_count));
+ CHECK(success);
+ const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
+ success = slice->MakeExternal(
+ new TestAsciiResource(i::StrDup(c_slice) + 1, &dispose_count));
CHECK(success);
// Trigger GCs and force evacuation.