Fix %NeverOptimizeFunction runtime call.

The current usage of this runtime function is broken as it does not
prevent inlining of the affected function but rather bails out from the
whole unit of compilation after trying to inline affected functions.
This simplifies said runtime function to avoid accidental misuse.

R=titzer@chromium.org
TEST=mjsunit/never-optimize

Review URL: https://codereview.chromium.org/19776006

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15762 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 76cbaf40
......@@ -7378,14 +7378,6 @@ void HOptimizedGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
const Runtime::Function* function = expr->function();
ASSERT(function != NULL);
if (static_cast<int>(function->function_id)
== static_cast<int>(Runtime::kNeverOptimize)
&& expr->arguments()->length() == 0) {
// %NeverOptimize() without arguments marks the caller as never optimize.
return Bailout("function marked itself as never optimize");
}
if (function->intrinsic_type == Runtime::INLINE) {
ASSERT(expr->name()->length() > 0);
ASSERT(expr->name()->Get(0) == '_');
......
......@@ -8425,23 +8425,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_NeverOptimize) {
RUNTIME_FUNCTION(MaybeObject*, Runtime_NeverOptimizeFunction) {
HandleScope scope(isolate);
if (args.length() == 0) {
// Disable optimization for the calling function.
JavaScriptFrameIterator it(isolate);
if (!it.done()) {
it.frame()->function()->shared()->set_optimization_disabled(true);
}
return isolate->heap()->undefined_value();
}
// Disable optimization for the functions passed.
for (int i = 0; i < args.length(); i++) {
CONVERT_ARG_CHECKED(JSFunction, function, i);
ASSERT(args.length() == 1);
CONVERT_ARG_CHECKED(JSFunction, function, 0);
ASSERT(!function->IsOptimized());
function->shared()->set_optimization_disabled(true);
}
return isolate->heap()->undefined_value();
}
......
......@@ -97,7 +97,7 @@ namespace internal {
F(RunningInSimulator, 0, 1) \
F(IsParallelRecompilationSupported, 0, 1) \
F(OptimizeFunctionOnNextCall, -1, 1) \
F(NeverOptimize, -1, 1) \
F(NeverOptimizeFunction, 1, 1) \
F(CompleteOptimization, 1, 1) \
F(GetOptimizationStatus, 1, 1) \
F(GetOptimizationCount, 1, 1) \
......
......@@ -115,9 +115,9 @@ F4(1);
})();
// Test arguments access from the inlined function.
%NeverOptimizeFunction(uninlinable);
function uninlinable(v) {
assertEquals(0, v);
%NeverOptimize();
return 0;
}
......
......@@ -170,22 +170,22 @@ for (var i = 0; i < 3; i++) monomorphic(smi_only);
monomorphic(smi_only);
if (support_smi_only_arrays) {
%NeverOptimizeFunction(construct_smis);
function construct_smis() {
%NeverOptimize();
var a = [0, 0, 0];
a[0] = 0; // Send the COW array map to the steak house.
assertKind(elements_kind.fast_smi_only, a);
return a;
}
%NeverOptimizeFunction(construct_doubles);
function construct_doubles() {
%NeverOptimize();
var a = construct_smis();
a[0] = 1.5;
assertKind(elements_kind.fast_double, a);
return a;
}
%NeverOptimizeFunction(construct_objects);
function construct_objects() {
%NeverOptimize();
var a = construct_smis();
a[0] = "one";
assertKind(elements_kind.fast, a);
......@@ -193,8 +193,8 @@ if (support_smi_only_arrays) {
}
// Test crankshafted transition SMI->DOUBLE.
%NeverOptimizeFunction(convert_to_double);
function convert_to_double(array) {
%NeverOptimize();
array[1] = 2.5;
assertKind(elements_kind.fast_double, array);
assertEquals(2.5, array[1]);
......@@ -205,8 +205,8 @@ if (support_smi_only_arrays) {
smis = construct_smis();
convert_to_double(smis);
// Test crankshafted transitions SMI->FAST and DOUBLE->FAST.
%NeverOptimizeFunction(convert_to_fast);
function convert_to_fast(array) {
%NeverOptimize();
array[1] = "two";
assertKind(elements_kind.fast, array);
assertEquals("two", array[1]);
......@@ -222,8 +222,8 @@ if (support_smi_only_arrays) {
convert_to_fast(doubles);
// Test transition chain SMI->DOUBLE->FAST (crankshafted function will
// transition to FAST directly).
%NeverOptimizeFunction(convert_mixed);
function convert_mixed(array, value, kind) {
%NeverOptimize();
array[1] = value;
assertKind(kind, array);
assertEquals(value, array[1]);
......
......@@ -29,8 +29,8 @@
var do_set = false;
%NeverOptimizeFunction(set_proto_elements);
function set_proto_elements() {
%NeverOptimize();
if (do_set) Array.prototype[1] = 1.5;
}
......
......@@ -27,43 +27,44 @@
// Flags: --allow-natives-syntax --compiled_transitions
%NeverOptimize();
%NeverOptimizeFunction(test);
function test() {
var iteration_count = 1;
var iteration_count = 1;
function transition1(a, i, v) {
function transition1(a, i, v) {
a[i] = v;
}
//
// Test PACKED SMI -> PACKED DOUBLE
//
}
var a1 = [0, 1, 2, 3, 4];
transition1(a1, 0, 2.5);
var a2 = [0, 1, 2, 3, 4];
transition1(a2, 0, 2.5);
assertFalse(%HasFastHoleyElements(a2));
%OptimizeFunctionOnNextCall(transition1);
var a3 = [0, 1, 2, 3, 4];
assertTrue(%HasFastSmiElements(a3));
transition1(a3, 0, 2.5);
assertFalse(%HasFastHoleyElements(a3));
assertEquals(4, a3[4]);
assertEquals(2.5, a3[0]);
// Test handling of hole.
var a4 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
a4.length = 7;
assertTrue(%HasFastSmiElements(a4));
transition1(a4, 0, 2.5);
assertFalse(%HasFastHoleyElements(a4));
assertEquals(2.5, a4[0]);
assertEquals(undefined, a4[8]);
// Large array should deopt to runtimea
for (j = 0; j < iteration_count; ++j) {
//
// Test PACKED SMI -> PACKED DOUBLE
//
var a1 = [0, 1, 2, 3, 4];
transition1(a1, 0, 2.5);
var a2 = [0, 1, 2, 3, 4];
transition1(a2, 0, 2.5);
assertFalse(%HasFastHoleyElements(a2));
%OptimizeFunctionOnNextCall(transition1);
var a3 = [0, 1, 2, 3, 4];
assertTrue(%HasFastSmiElements(a3));
transition1(a3, 0, 2.5);
assertFalse(%HasFastHoleyElements(a3));
assertEquals(4, a3[4]);
assertEquals(2.5, a3[0]);
// Test handling of hole.
var a4 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
a4.length = 7;
assertTrue(%HasFastSmiElements(a4));
transition1(a4, 0, 2.5);
assertFalse(%HasFastHoleyElements(a4));
assertEquals(2.5, a4[0]);
assertEquals(undefined, a4[8]);
// Large array should deopt to runtimea
for (j = 0; j < iteration_count; ++j) {
a5 = new Array();
for (i = 0; i < 0x40000; ++i) {
a5[i] = 0;
......@@ -71,33 +72,33 @@ for (j = 0; j < iteration_count; ++j) {
assertTrue(%HasFastSmiElements(a5) || %HasFastDoubleElements(a5));
transition1(a5, 0, 2.5);
assertEquals(2.5, a5[0]);
}
}
//
// Test HOLEY SMI -> HOLEY DOUBLE
//
//
// Test HOLEY SMI -> HOLEY DOUBLE
//
function transition2(a, i, v) {
function transition2(a, i, v) {
a[i] = v;
}
}
var b1 = [0, 1, 2, , 4];
transition2(b1, 0, 2.5);
var b2 = [0, 1, 2, , 4];
transition2(b2, 0, 2.5);
assertTrue(%HasFastHoleyElements(b2));
%OptimizeFunctionOnNextCall(transition2);
var b3 = [0, 1, 2, , 4];
assertTrue(%HasFastSmiElements(b3));
assertTrue(%HasFastHoleyElements(b3));
transition2(b3, 0, 2.5);
assertTrue(%HasFastHoleyElements(b3));
assertEquals(4, b3[4]);
assertEquals(2.5, b3[0]);
// Large array should deopt to runtime
for (j = 0; j < iteration_count; ++j) {
var b1 = [0, 1, 2, , 4];
transition2(b1, 0, 2.5);
var b2 = [0, 1, 2, , 4];
transition2(b2, 0, 2.5);
assertTrue(%HasFastHoleyElements(b2));
%OptimizeFunctionOnNextCall(transition2);
var b3 = [0, 1, 2, , 4];
assertTrue(%HasFastSmiElements(b3));
assertTrue(%HasFastHoleyElements(b3));
transition2(b3, 0, 2.5);
assertTrue(%HasFastHoleyElements(b3));
assertEquals(4, b3[4]);
assertEquals(2.5, b3[0]);
// Large array should deopt to runtime
for (j = 0; j < iteration_count; ++j) {
b4 = [0, ,0];
for (i = 3; i < 0x40000; ++i) {
b4[i] = 0;
......@@ -105,36 +106,36 @@ for (j = 0; j < iteration_count; ++j) {
assertTrue(%HasFastSmiElements(b4));
transition2(b4, 0, 2.5);
assertEquals(2.5, b4[0]);
}
}
//
// Test PACKED DOUBLE -> PACKED OBJECT
//
//
// Test PACKED DOUBLE -> PACKED OBJECT
//
function transition3(a, i, v) {
function transition3(a, i, v) {
a[i] = v;
}
}
var c1 = [0, 1, 2, 3.5, 4];
transition3(c1, 0, new Object());
var c2 = [0, 1, 2, 3.5, 4];
transition3(c2, 0, new Object());
assertTrue(%HasFastObjectElements(c2));
assertTrue(!%HasFastHoleyElements(c2));
%OptimizeFunctionOnNextCall(transition3);
var c3 = [0, 1, 2, 3.5, 4];
assertTrue(%HasFastDoubleElements(c3));
assertTrue(!%HasFastHoleyElements(c3));
transition3(c3, 0, new Array());
assertTrue(!%HasFastHoleyElements(c3));
assertTrue(%HasFastObjectElements(c3));
assertEquals(4, c3[4]);
assertEquals(0, c3[0].length);
// Large array under the deopt threshold should be able to trigger GC without
// causing crashes.
for (j = 0; j < iteration_count; ++j) {
var c1 = [0, 1, 2, 3.5, 4];
transition3(c1, 0, new Object());
var c2 = [0, 1, 2, 3.5, 4];
transition3(c2, 0, new Object());
assertTrue(%HasFastObjectElements(c2));
assertTrue(!%HasFastHoleyElements(c2));
%OptimizeFunctionOnNextCall(transition3);
var c3 = [0, 1, 2, 3.5, 4];
assertTrue(%HasFastDoubleElements(c3));
assertTrue(!%HasFastHoleyElements(c3));
transition3(c3, 0, new Array());
assertTrue(!%HasFastHoleyElements(c3));
assertTrue(%HasFastObjectElements(c3));
assertEquals(4, c3[4]);
assertEquals(0, c3[0].length);
// Large array under the deopt threshold should be able to trigger GC without
// causing crashes.
for (j = 0; j < iteration_count; ++j) {
c4 = [0, 2.5, 0];
for (i = 3; i < 0xa000; ++i) {
c4[i] = 0;
......@@ -145,10 +146,10 @@ for (j = 0; j < iteration_count; ++j) {
assertTrue(!%HasFastHoleyElements(c4));
assertTrue(%HasFastObjectElements(c4));
assertEquals(5, c4[0].length);
}
}
// Large array should deopt to runtime
for (j = 0; j < iteration_count; ++j) {
// Large array should deopt to runtime
for (j = 0; j < iteration_count; ++j) {
c5 = [0, 2.5, 0];
for (i = 3; i < 0x40000; ++i) {
c5[i] = 0;
......@@ -159,36 +160,36 @@ for (j = 0; j < iteration_count; ++j) {
assertTrue(!%HasFastHoleyElements(c5));
assertTrue(%HasFastObjectElements(c5));
assertEquals(5, c5[0].length);
}
}
//
// Test HOLEY DOUBLE -> HOLEY OBJECT
//
//
// Test HOLEY DOUBLE -> HOLEY OBJECT
//
function transition4(a, i, v) {
function transition4(a, i, v) {
a[i] = v;
}
}
var d1 = [0, 1, , 3.5, 4];
transition4(d1, 0, new Object());
var d2 = [0, 1, , 3.5, 4];
transition4(d2, 0, new Object());
assertTrue(%HasFastObjectElements(d2));
assertTrue(%HasFastHoleyElements(d2));
%OptimizeFunctionOnNextCall(transition4);
var d3 = [0, 1, , 3.5, 4];
assertTrue(%HasFastDoubleElements(d3));
assertTrue(%HasFastHoleyElements(d3));
transition4(d3, 0, new Array());
assertTrue(%HasFastHoleyElements(d3));
assertTrue(%HasFastObjectElements(d3));
assertEquals(4, d3[4]);
assertEquals(0, d3[0].length);
// Large array under the deopt threshold should be able to trigger GC without
// causing crashes.
for (j = 0; j < iteration_count; ++j) {
var d1 = [0, 1, , 3.5, 4];
transition4(d1, 0, new Object());
var d2 = [0, 1, , 3.5, 4];
transition4(d2, 0, new Object());
assertTrue(%HasFastObjectElements(d2));
assertTrue(%HasFastHoleyElements(d2));
%OptimizeFunctionOnNextCall(transition4);
var d3 = [0, 1, , 3.5, 4];
assertTrue(%HasFastDoubleElements(d3));
assertTrue(%HasFastHoleyElements(d3));
transition4(d3, 0, new Array());
assertTrue(%HasFastHoleyElements(d3));
assertTrue(%HasFastObjectElements(d3));
assertEquals(4, d3[4]);
assertEquals(0, d3[0].length);
// Large array under the deopt threshold should be able to trigger GC without
// causing crashes.
for (j = 0; j < iteration_count; ++j) {
d4 = [, 2.5, ,];
for (i = 3; i < 0xa000; ++i) {
d4[i] = 0;
......@@ -200,10 +201,10 @@ for (j = 0; j < iteration_count; ++j) {
assertTrue(%HasFastObjectElements(d4));
assertEquals(5, d4[0].length);
assertEquals(undefined, d4[2]);
}
}
// Large array should deopt to runtime
for (j = 0; j < iteration_count; ++j) {
// Large array should deopt to runtime
for (j = 0; j < iteration_count; ++j) {
d5 = [, 2.5, ,];
for (i = 3; i < 0x40000; ++i) {
d5[i] = 0;
......@@ -215,4 +216,7 @@ for (j = 0; j < iteration_count; ++j) {
assertTrue(%HasFastObjectElements(d5));
assertEquals(5, d5[0].length);
assertEquals(undefined, d5[2]);
}
}
test();
......@@ -36,22 +36,21 @@ if (%GetOptimizationStatus(o1) != 4) {
%OptimizeFunctionOnNextCall(o1);
o1();
// check that the given function was optimized.
// Check that the given function was optimized.
var o1_status = %GetOptimizationStatus(o1);
assertTrue(o1_status == 1 // optimized
|| o1_status == 3 // optimized (always opt)
|| o1_status == 5); // lazy recompile requested
// Test the %NeverOptimize runtime call.
// Test the %NeverOptimizeFunction runtime call.
%NeverOptimizeFunction(u1);
function u1() {
%NeverOptimize();
}
function u2() {
u1();
}
%NeverOptimize(u2);
u1(); u1();
u2(); u2();
......@@ -62,7 +61,6 @@ if (%GetOptimizationStatus(o1) != 4) {
u2(); u2();
// 2 => not optimized.
assertEquals(2, %GetOptimizationStatus(u1));
assertEquals(2, %GetOptimizationStatus(u2));
assertTrue(%GetOptimizationStatus(u1) == 2);
assertFalse(%GetOptimizationStatus(u2) == 2);
}
\ No newline at end of file
......@@ -108,24 +108,24 @@ function assertKind(expected, obj, name_opt) {
assertEquals(expected, getKind(obj), name_opt);
}
%NeverOptimizeFunction(construct_smis);
function construct_smis() {
%NeverOptimize();
var a = [0, 0, 0];
a[0] = 0; // Send the COW array map to the steak house.
assertKind(elements_kind.fast_smi_only, a);
return a;
}
%NeverOptimizeFunction(construct_doubles);
function construct_doubles() {
%NeverOptimize();
var a = construct_smis();
a[0] = 1.5;
assertKind(elements_kind.fast_double, a);
return a;
}
%NeverOptimizeFunction(convert_mixed);
function convert_mixed(array, value, kind) {
%NeverOptimize();
array[1] = value;
assertKind(kind, array);
assertEquals(value, array[1]);
......
......@@ -109,18 +109,19 @@ function assertKind(expected, obj, name_opt) {
}
// long-running loop forces OSR.
%NeverOptimizeFunction(construct_smis);
%NeverOptimizeFunction(construct_doubles);
%NeverOptimizeFunction(convert_mixed);
for (var i = 0; i < 1000000; i++) { }
if (support_smi_only_arrays) {
function construct_smis() {
%NeverOptimize();
var a = [0, 0, 0];
a[0] = 0; // Send the COW array map to the steak house.
assertKind(elements_kind.fast_smi_only, a);
return a;
}
function construct_doubles() {
%NeverOptimize();
var a = construct_smis();
a[0] = 1.5;
assertKind(elements_kind.fast_double, a);
......@@ -130,7 +131,6 @@ if (support_smi_only_arrays) {
// Test transition chain SMI->DOUBLE->FAST (crankshafted function will
// transition to FAST directly).
function convert_mixed(array, value, kind) {
%NeverOptimize();
array[1] = value;
assertKind(kind, array);
assertEquals(value, array[1]);
......
......@@ -62,6 +62,7 @@ var L = LongList(1024, function (O) {
%NeverOptimizeFunction(Incremental);
function Incremental(O, x) {
if (!x) {
return;
......@@ -83,8 +84,6 @@ function Incremental(O, x) {
L.execute(O);
%NeverOptimize();
L = null;
print(">>> 2 <<<");
AllocateXMb(8);
......
......@@ -30,8 +30,8 @@
// Check that we are not flushing code for inlined functions that
// have a pending lazy deoptimization on the stack.
%NeverOptimizeFunction(deopt);
function deopt() {
%NeverOptimize();
%DeoptimizeFunction(outer);
for (var i = 0; i < 10; i++) gc(); // Force code flushing.
}
......
......@@ -33,8 +33,8 @@ var K = 0.5;
var O = 0;
var result = new Float64Array(2);
%NeverOptimizeFunction(spill);
function spill() {
%NeverOptimize();
}
function buggy() {
......
......@@ -38,9 +38,9 @@ function opt_me() {
deopt();
}
// Make sure we don't inline this function
%NeverOptimizeFunction(deopt);
function deopt() {
// Make sure we don't inline this function
%NeverOptimize();
%DeoptimizeFunction(opt_me);
gc();
}
......
......@@ -30,8 +30,8 @@
function boom(a) {
return ((a | 0) * (a | 0)) | 0;
}
%NeverOptimizeFunction(boom_unoptimized);
function boom_unoptimized(a) {
%NeverOptimize();
return ((a | 0) * (a | 0)) | 0;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment