Revision: 10227
Author: [email protected]
Date: Fri Dec 9 04:49:39 2011
Log: Merge r10224 from the 3.6 to the 3.5 branch.
Merge r10215 from the bleeding_edge to the 3.6 branch.
Ensure that non-optimized code objects are not flushed for inlined
functions.
Collector was flushing them if optimized code was reachable only through
the stack (not through the JSFunction object) which happens when you have a
pending lazy deoptimization.
Also prevent v8::Script::New from leaking internal objects allocated by the
compiler into outer HandleScope.
[email protected]
BUG=http://crbug.com/97116
TEST=test/mjsunit/regress/regress-97116.js
Review URL: http://codereview.chromium.org/8883048
http://code.google.com/p/v8/source/detail?r=10227
Added:
/branches/3.5/test/mjsunit/regress/regress-97116.js
Modified:
/branches/3.5/src/api.cc
/branches/3.5/src/mark-compact.cc
/branches/3.5/src/mark-compact.h
/branches/3.5/src/v8threads.h
/branches/3.5/src/version.cc
=======================================
--- /dev/null
+++ /branches/3.5/test/mjsunit/regress/regress-97116.js Fri Dec 9 04:49:39
2011
@@ -0,0 +1,50 @@
+// 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: --expose-gc --allow-natives-syntax
+
+// Check that we are not flushing code for inlined functions that
+// have a pending lazy deoptimization on the stack.
+
+function deopt() {
+ try { } catch (e) { } // Avoid inlining.
+ %DeoptimizeFunction(outer);
+ for (var i = 0; i < 10; i++) gc(); // Force code flushing.
+}
+
+function outer(should_deopt) {
+ inner(should_deopt);
+}
+
+function inner(should_deopt) {
+ if (should_deopt) deopt();
+}
+
+outer(false);
+outer(false);
+%OptimizeFunctionOnNextCall(outer);
+outer(true);
=======================================
--- /branches/3.5/src/api.cc Fri Oct 14 02:24:03 2011
+++ /branches/3.5/src/api.cc Fri Dec 9 04:49:39 2011
@@ -1455,31 +1455,35 @@
ON_BAILOUT(isolate, "v8::Script::New()", return Local<Script>());
LOG_API(isolate, "Script::New");
ENTER_V8(isolate);
- i::Handle<i::String> str = Utils::OpenHandle(*source);
- i::Handle<i::Object> name_obj;
- int line_offset = 0;
- int column_offset = 0;
- if (origin != NULL) {
- if (!origin->ResourceName().IsEmpty()) {
- name_obj = Utils::OpenHandle(*origin->ResourceName());
- }
- if (!origin->ResourceLineOffset().IsEmpty()) {
- line_offset =
static_cast<int>(origin->ResourceLineOffset()->Value());
- }
- if (!origin->ResourceColumnOffset().IsEmpty()) {
- column_offset =
static_cast<int>(origin->ResourceColumnOffset()->Value());
- }
- }
- EXCEPTION_PREAMBLE(isolate);
- i::ScriptDataImpl* pre_data_impl =
static_cast<i::ScriptDataImpl*>(pre_data);
- // We assert that the pre-data is sane, even though we can actually
- // handle it if it turns out not to be in release mode.
- ASSERT(pre_data_impl == NULL || pre_data_impl->SanityCheck());
- // If the pre-data isn't sane we simply ignore it
- if (pre_data_impl != NULL && !pre_data_impl->SanityCheck()) {
- pre_data_impl = NULL;
- }
- i::Handle<i::SharedFunctionInfo> result =
+ i::SharedFunctionInfo* raw_result = NULL;
+ { i::HandleScope scope(isolate);
+ i::Handle<i::String> str = Utils::OpenHandle(*source);
+ i::Handle<i::Object> name_obj;
+ int line_offset = 0;
+ int column_offset = 0;
+ if (origin != NULL) {
+ if (!origin->ResourceName().IsEmpty()) {
+ name_obj = Utils::OpenHandle(*origin->ResourceName());
+ }
+ if (!origin->ResourceLineOffset().IsEmpty()) {
+ line_offset =
static_cast<int>(origin->ResourceLineOffset()->Value());
+ }
+ if (!origin->ResourceColumnOffset().IsEmpty()) {
+ column_offset =
+ static_cast<int>(origin->ResourceColumnOffset()->Value());
+ }
+ }
+ EXCEPTION_PREAMBLE(isolate);
+ i::ScriptDataImpl* pre_data_impl =
+ static_cast<i::ScriptDataImpl*>(pre_data);
+ // We assert that the pre-data is sane, even though we can actually
+ // handle it if it turns out not to be in release mode.
+ ASSERT(pre_data_impl == NULL || pre_data_impl->SanityCheck());
+ // If the pre-data isn't sane we simply ignore it
+ if (pre_data_impl != NULL && !pre_data_impl->SanityCheck()) {
+ pre_data_impl = NULL;
+ }
+ i::Handle<i::SharedFunctionInfo> result =
i::Compiler::Compile(str,
name_obj,
line_offset,
@@ -1488,8 +1492,11 @@
pre_data_impl,
Utils::OpenHandle(*script_data),
i::NOT_NATIVES_CODE);
- has_pending_exception = result.is_null();
- EXCEPTION_BAILOUT_CHECK(isolate, Local<Script>());
+ has_pending_exception = result.is_null();
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<Script>());
+ raw_result = *result;
+ }
+ i::Handle<i::SharedFunctionInfo> result(raw_result, isolate);
return Local<Script>(ToApi<Script>(result));
}
=======================================
--- /branches/3.5/src/mark-compact.cc Mon Aug 29 03:41:00 2011
+++ /branches/3.5/src/mark-compact.cc Fri Dec 9 04:49:39 2011
@@ -665,13 +665,19 @@
}
// Only flush code for functions.
- if (shared_info->code()->kind() != Code::FUNCTION) return false;
+ if (shared_info->code()->kind() != Code::FUNCTION) {
+ return false;
+ }
// Function must be lazy compilable.
- if (!shared_info->allows_lazy_compilation()) return false;
+ if (!shared_info->allows_lazy_compilation()) {
+ return false;
+ }
// If this is a full script wrapped in a function we do no flush the
code.
- if (shared_info->is_toplevel()) return false;
+ if (shared_info->is_toplevel()) {
+ return false;
+ }
// Age this shared function info.
if (shared_info->code_age() < kCodeAgeThreshold) {
@@ -864,21 +870,7 @@
collector->MarkObject(jsfunction->unchecked_shared()->unchecked_code());
if (jsfunction->unchecked_code()->kind() ==
Code::OPTIMIZED_FUNCTION) {
- // For optimized functions we should retain both non-optimized
version
- // of it's code and non-optimized version of all inlined functions.
- // This is required to support bailing out from inlined code.
- DeoptimizationInputData* data =
- reinterpret_cast<DeoptimizationInputData*>(
-
jsfunction->unchecked_code()->unchecked_deoptimization_data());
-
- FixedArray* literals = data->UncheckedLiteralArray();
-
- for (int i = 0, count = data->InlinedFunctionCount()->value();
- i < count;
- i++) {
- JSFunction* inlined =
reinterpret_cast<JSFunction*>(literals->get(i));
-
collector->MarkObject(inlined->unchecked_shared()->unchecked_code());
- }
+ collector->MarkInlinedFunctionsCode(jsfunction->unchecked_code());
}
}
@@ -994,9 +986,7 @@
: collector_(collector) {}
void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
- for (StackFrameIterator it(isolate, top); !it.done(); it.Advance()) {
- collector_->MarkObject(it.frame()->unchecked_code());
- }
+ collector_->PrepareThreadForCodeFlushing(isolate, top);
}
private:
@@ -1027,6 +1017,42 @@
};
+void MarkCompactCollector::MarkInlinedFunctionsCode(Code* code) {
+ // For optimized functions we should retain both non-optimized version
+ // of it's code and non-optimized version of all inlined functions.
+ // This is required to support bailing out from inlined code.
+ DeoptimizationInputData* data =
+ reinterpret_cast<DeoptimizationInputData*>(
+ code->unchecked_deoptimization_data());
+
+ FixedArray* literals = data->UncheckedLiteralArray();
+
+ for (int i = 0, count = data->InlinedFunctionCount()->value();
+ i < count;
+ i++) {
+ JSFunction* inlined = reinterpret_cast<JSFunction*>(literals->get(i));
+ MarkObject(inlined->unchecked_shared()->unchecked_code());
+ }
+}
+
+
+void MarkCompactCollector::PrepareThreadForCodeFlushing(Isolate* isolate,
+ ThreadLocalTop*
top) {
+ for (StackFrameIterator it(isolate, top); !it.done(); it.Advance()) {
+ // Note: for the frame that has a pending lazy deoptimization
+ // StackFrame::unchecked_code will return a non-optimized code object
for
+ // the outermost function and StackFrame::LookupCode will return
+ // actual optimized code object.
+ StackFrame* frame = it.frame();
+ Code* code = frame->unchecked_code();
+ MarkObject(code);
+ if (frame->is_optimized()) {
+ MarkInlinedFunctionsCode(frame->LookupCode());
+ }
+ }
+}
+
+
void MarkCompactCollector::PrepareForCodeFlushing() {
ASSERT(heap() == Isolate::Current()->heap());
@@ -1050,9 +1076,8 @@
// Make sure we are not referencing the code from the stack.
ASSERT(this == heap()->mark_compact_collector());
- for (StackFrameIterator it; !it.done(); it.Advance()) {
- MarkObject(it.frame()->unchecked_code());
- }
+ PrepareThreadForCodeFlushing(heap()->isolate(),
+ heap()->isolate()->thread_local_top());
// Iterate the archived stacks in all threads to check if
// the code is referenced.
=======================================
--- /branches/3.5/src/mark-compact.h Wed Aug 10 04:27:35 2011
+++ /branches/3.5/src/mark-compact.h Fri Dec 9 04:49:39 2011
@@ -96,6 +96,10 @@
};
+// Defined in isolate.h.
+class ThreadLocalTop;
+
+
//
-------------------------------------------------------------------------
// Mark-Compact collector
@@ -253,6 +257,14 @@
friend class CodeMarkingVisitor;
friend class SharedFunctionInfoMarkingVisitor;
+ // Mark non-optimize code for functions inlined into the given optimized
+ // code. This will prevent it from being flushed.
+ void MarkInlinedFunctionsCode(Code* code);
+
+ // Mark code objects that are active on the stack to prevent them
+ // from being flushed.
+ void PrepareThreadForCodeFlushing(Isolate* isolate, ThreadLocalTop* top);
+
void PrepareForCodeFlushing();
// Marking operations for objects reachable from roots.
=======================================
--- /branches/3.5/src/v8threads.h Wed Jun 15 03:58:27 2011
+++ /branches/3.5/src/v8threads.h Fri Dec 9 04:49:39 2011
@@ -71,7 +71,7 @@
};
-// Defined in top.h
+// Defined in isolate.h.
class ThreadLocalTop;
=======================================
--- /branches/3.5/src/version.cc Wed Dec 7 08:45:21 2011
+++ /branches/3.5/src/version.cc Fri Dec 9 04:49:39 2011
@@ -35,7 +35,7 @@
#define MAJOR_VERSION 3
#define MINOR_VERSION 5
#define BUILD_NUMBER 10
-#define PATCH_LEVEL 27
+#define PATCH_LEVEL 28
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
#define IS_CANDIDATE_VERSION 0
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev