blob: 056c98184537c9ff40f94cf15310ca0ed7554977 [file] [log] [blame]
Ben Murdoch85b71792012-04-11 18:30:58 +01001// Copyright 2007-2010 the V8 project authors. All rights reserved.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "api.h"
Steve Block44f0eee2011-05-26 01:26:41 +010033#include "cctest.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010034#include "compilation-cache.h"
35#include "debug.h"
36#include "deoptimizer.h"
Steve Block44f0eee2011-05-26 01:26:41 +010037#include "isolate.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010038#include "platform.h"
39#include "stub-cache.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010040
Ben Murdochb0fe1622011-05-05 13:52:32 +010041using ::v8::internal::Deoptimizer;
42using ::v8::internal::EmbeddedVector;
Steve Block44f0eee2011-05-26 01:26:41 +010043using ::v8::internal::Handle;
44using ::v8::internal::Isolate;
45using ::v8::internal::JSFunction;
Ben Murdochb0fe1622011-05-05 13:52:32 +010046using ::v8::internal::OS;
Steve Block44f0eee2011-05-26 01:26:41 +010047using ::v8::internal::Object;
Ben Murdochb0fe1622011-05-05 13:52:32 +010048
49// Size of temp buffer for formatting small strings.
50#define SMALL_STRING_BUFFER_SIZE 80
51
52// Utility class to set --allow-natives-syntax --always-opt and --nouse-inlining
53// when constructed and return to their default state when destroyed.
54class AlwaysOptimizeAllowNativesSyntaxNoInlining {
55 public:
56 AlwaysOptimizeAllowNativesSyntaxNoInlining()
57 : always_opt_(i::FLAG_always_opt),
58 allow_natives_syntax_(i::FLAG_allow_natives_syntax),
59 use_inlining_(i::FLAG_use_inlining) {
60 i::FLAG_always_opt = true;
61 i::FLAG_allow_natives_syntax = true;
62 i::FLAG_use_inlining = false;
63 }
64
65 ~AlwaysOptimizeAllowNativesSyntaxNoInlining() {
66 i::FLAG_allow_natives_syntax = allow_natives_syntax_;
67 i::FLAG_always_opt = always_opt_;
68 i::FLAG_use_inlining = use_inlining_;
69 }
70
71 private:
72 bool always_opt_;
73 bool allow_natives_syntax_;
74 bool use_inlining_;
75};
76
77
78// Utility class to set --allow-natives-syntax and --nouse-inlining when
79// constructed and return to their default state when destroyed.
80class AllowNativesSyntaxNoInlining {
81 public:
82 AllowNativesSyntaxNoInlining()
83 : allow_natives_syntax_(i::FLAG_allow_natives_syntax),
84 use_inlining_(i::FLAG_use_inlining) {
85 i::FLAG_allow_natives_syntax = true;
86 i::FLAG_use_inlining = false;
87 }
88
89 ~AllowNativesSyntaxNoInlining() {
90 i::FLAG_allow_natives_syntax = allow_natives_syntax_;
91 i::FLAG_use_inlining = use_inlining_;
92 }
93
94 private:
95 bool allow_natives_syntax_;
96 bool use_inlining_;
97};
98
99
Steve Block053d10c2011-06-13 19:13:29 +0100100static Handle<JSFunction> GetJSFunction(v8::Handle<v8::Object> obj,
101 const char* property_name) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100102 v8::Local<v8::Function> fun =
103 v8::Local<v8::Function>::Cast(obj->Get(v8_str(property_name)));
104 return v8::Utils::OpenHandle(*fun);
105}
106
107
108TEST(DeoptimizeSimple) {
109 v8::HandleScope scope;
Ben Murdoch85b71792012-04-11 18:30:58 +0100110 const char* extension_list[] = { "v8/gc" };
111 v8::ExtensionConfiguration extensions(1, extension_list);
112 LocalContext env(&extensions);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100113
114 // Test lazy deoptimization of a simple function.
115 {
116 AlwaysOptimizeAllowNativesSyntaxNoInlining options;
117 CompileRun(
118 "var count = 0;"
119 "function h() { %DeoptimizeFunction(f); }"
120 "function g() { count++; h(); }"
121 "function f() { g(); };"
Ben Murdoch85b71792012-04-11 18:30:58 +0100122 "f();"
123 "gc(); gc()");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100124 }
125
126 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
127 CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
Steve Block44f0eee2011-05-26 01:26:41 +0100128 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100129
130 // Test lazy deoptimization of a simple function. Call the function after the
131 // deoptimization while it is still activated further down the stack.
132 {
133 AlwaysOptimizeAllowNativesSyntaxNoInlining options;
134 CompileRun(
135 "var count = 0;"
136 "function g() { count++; %DeoptimizeFunction(f); f(false); }"
137 "function f(x) { if (x) { g(); } else { return } };"
Ben Murdoch85b71792012-04-11 18:30:58 +0100138 "f(true);"
139 "gc(); gc()");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100140 }
141
142 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
143 CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
Steve Block44f0eee2011-05-26 01:26:41 +0100144 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100145}
146
147
148TEST(DeoptimizeSimpleWithArguments) {
149 v8::HandleScope scope;
Ben Murdoch85b71792012-04-11 18:30:58 +0100150 const char* extension_list[] = { "v8/gc" };
151 v8::ExtensionConfiguration extensions(1, extension_list);
152 LocalContext env(&extensions);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100153
154 // Test lazy deoptimization of a simple function with some arguments.
155 {
156 AlwaysOptimizeAllowNativesSyntaxNoInlining options;
157 CompileRun(
158 "var count = 0;"
159 "function h(x) { %DeoptimizeFunction(f); }"
160 "function g(x, y) { count++; h(x); }"
161 "function f(x, y, z) { g(1,x); y+z; };"
Ben Murdoch85b71792012-04-11 18:30:58 +0100162 "f(1, \"2\", false);"
163 "gc(); gc()");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100164 }
165
166 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
167 CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
Steve Block44f0eee2011-05-26 01:26:41 +0100168 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100169
170 // Test lazy deoptimization of a simple function with some arguments. Call the
171 // function after the deoptimization while it is still activated further down
172 // the stack.
173 {
174 AlwaysOptimizeAllowNativesSyntaxNoInlining options;
175 CompileRun(
176 "var count = 0;"
177 "function g(x, y) { count++; %DeoptimizeFunction(f); f(false, 1, y); }"
178 "function f(x, y, z) { if (x) { g(x, y); } else { return y + z; } };"
Ben Murdoch85b71792012-04-11 18:30:58 +0100179 "f(true, 1, \"2\");"
180 "gc(); gc()");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100181 }
182
183 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
184 CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
Steve Block44f0eee2011-05-26 01:26:41 +0100185 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100186}
187
188
189TEST(DeoptimizeSimpleNested) {
190 v8::HandleScope scope;
Ben Murdoch85b71792012-04-11 18:30:58 +0100191 const char* extension_list[] = { "v8/gc" };
192 v8::ExtensionConfiguration extensions(1, extension_list);
193 LocalContext env(&extensions);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100194
195 // Test lazy deoptimization of a simple function. Have a nested function call
196 // do the deoptimization.
197 {
198 AlwaysOptimizeAllowNativesSyntaxNoInlining options;
199 CompileRun(
200 "var count = 0;"
201 "var result = 0;"
202 "function h(x, y, z) { return x + y + z; }"
203 "function g(z) { count++; %DeoptimizeFunction(f); return z;}"
204 "function f(x,y,z) { return h(x, y, g(z)); };"
Ben Murdoch85b71792012-04-11 18:30:58 +0100205 "result = f(1, 2, 3);"
206 "gc(); gc()");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100207
208 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
209 CHECK_EQ(6, env->Global()->Get(v8_str("result"))->Int32Value());
210 CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
Steve Block44f0eee2011-05-26 01:26:41 +0100211 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100212 }
213}
214
215
216TEST(DeoptimizeRecursive) {
217 v8::HandleScope scope;
Ben Murdoch85b71792012-04-11 18:30:58 +0100218 const char* extension_list[] = { "v8/gc" };
219 v8::ExtensionConfiguration extensions(1, extension_list);
220 LocalContext env(&extensions);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100221
222 {
223 // Test lazy deoptimization of a simple function called recursively. Call
224 // the function recursively a number of times before deoptimizing it.
225 AlwaysOptimizeAllowNativesSyntaxNoInlining options;
226 CompileRun(
227 "var count = 0;"
228 "var calls = 0;"
229 "function g() { count++; %DeoptimizeFunction(f); }"
230 "function f(x) { calls++; if (x > 0) { f(x - 1); } else { g(); } };"
Ben Murdoch85b71792012-04-11 18:30:58 +0100231 "f(10); gc(); gc()");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100232 }
233
234 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
235 CHECK_EQ(11, env->Global()->Get(v8_str("calls"))->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +0100236 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100237
238 v8::Local<v8::Function> fun =
239 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
Ben Murdoch85b71792012-04-11 18:30:58 +0100240 Handle<v8::internal::JSFunction> f = v8::Utils::OpenHandle(*fun);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100241}
242
243
244TEST(DeoptimizeMultiple) {
245 v8::HandleScope scope;
Ben Murdoch85b71792012-04-11 18:30:58 +0100246 const char* extension_list[] = { "v8/gc" };
247 v8::ExtensionConfiguration extensions(1, extension_list);
248 LocalContext env(&extensions);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100249
250 {
251 AlwaysOptimizeAllowNativesSyntaxNoInlining options;
252 CompileRun(
253 "var count = 0;"
254 "var result = 0;"
255 "function g() { count++;"
256 " %DeoptimizeFunction(f1);"
257 " %DeoptimizeFunction(f2);"
258 " %DeoptimizeFunction(f3);"
259 " %DeoptimizeFunction(f4);}"
260 "function f4(x) { g(); };"
261 "function f3(x, y, z) { f4(); return x + y + z; };"
262 "function f2(x, y) { return x + f3(y + 1, y + 1, y + 1) + y; };"
263 "function f1(x) { return f2(x + 1, x + 1) + x; };"
Ben Murdoch85b71792012-04-11 18:30:58 +0100264 "result = f1(1);"
265 "gc(); gc()");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100266 }
267
268 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
269 CHECK_EQ(14, env->Global()->Get(v8_str("result"))->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +0100270 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100271}
272
273
274TEST(DeoptimizeConstructor) {
275 v8::HandleScope scope;
Ben Murdoch85b71792012-04-11 18:30:58 +0100276 const char* extension_list[] = { "v8/gc" };
277 v8::ExtensionConfiguration extensions(1, extension_list);
278 LocalContext env(&extensions);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100279
280 {
281 AlwaysOptimizeAllowNativesSyntaxNoInlining options;
282 CompileRun(
283 "var count = 0;"
284 "function g() { count++;"
285 " %DeoptimizeFunction(f); }"
286 "function f() { g(); };"
Ben Murdoch85b71792012-04-11 18:30:58 +0100287 "result = new f() instanceof f;"
288 "gc(); gc()");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100289 }
290
291 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
292 CHECK(env->Global()->Get(v8_str("result"))->IsTrue());
Steve Block44f0eee2011-05-26 01:26:41 +0100293 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100294
295 {
296 AlwaysOptimizeAllowNativesSyntaxNoInlining options;
297 CompileRun(
298 "var count = 0;"
299 "var result = 0;"
300 "function g() { count++;"
301 " %DeoptimizeFunction(f); }"
302 "function f(x, y) { this.x = x; g(); this.y = y; };"
303 "result = new f(1, 2);"
Ben Murdoch85b71792012-04-11 18:30:58 +0100304 "result = result.x + result.y;"
305 "gc(); gc()");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100306 }
307
308 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
309 CHECK_EQ(3, env->Global()->Get(v8_str("result"))->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +0100310 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100311}
312
313
314TEST(DeoptimizeConstructorMultiple) {
315 v8::HandleScope scope;
Ben Murdoch85b71792012-04-11 18:30:58 +0100316 const char* extension_list[] = { "v8/gc" };
317 v8::ExtensionConfiguration extensions(1, extension_list);
318 LocalContext env(&extensions);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100319
320 {
321 AlwaysOptimizeAllowNativesSyntaxNoInlining options;
322 CompileRun(
323 "var count = 0;"
324 "var result = 0;"
325 "function g() { count++;"
326 " %DeoptimizeFunction(f1);"
327 " %DeoptimizeFunction(f2);"
328 " %DeoptimizeFunction(f3);"
329 " %DeoptimizeFunction(f4);}"
330 "function f4(x) { this.result = x; g(); };"
331 "function f3(x, y, z) { this.result = new f4(x + y + z).result; };"
332 "function f2(x, y) {"
333 " this.result = x + new f3(y + 1, y + 1, y + 1).result + y; };"
334 "function f1(x) { this.result = new f2(x + 1, x + 1).result + x; };"
Ben Murdoch85b71792012-04-11 18:30:58 +0100335 "result = new f1(1).result;"
336 "gc(); gc()");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100337 }
338
339 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
340 CHECK_EQ(14, env->Global()->Get(v8_str("result"))->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +0100341 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100342}
343
344
345TEST(DeoptimizeBinaryOperationADDString) {
346 v8::HandleScope scope;
Ben Murdoch85b71792012-04-11 18:30:58 +0100347 const char* extension_list[] = { "v8/gc" };
348 v8::ExtensionConfiguration extensions(1, extension_list);
349 LocalContext env(&extensions);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100350
351 const char* f_source = "function f(x, y) { return x + y; };";
352
353 {
354 AllowNativesSyntaxNoInlining options;
355 // Compile function f and collect to type feedback to insert binary op stub
356 // call in the optimized code.
357 i::FLAG_prepare_always_opt = true;
358 CompileRun("var count = 0;"
359 "var result = 0;"
360 "var deopt = false;"
361 "function X() { };"
362 "X.prototype.toString = function () {"
363 " if (deopt) { count++; %DeoptimizeFunction(f); } return 'an X'"
364 "};");
365 CompileRun(f_source);
366 CompileRun("for (var i = 0; i < 5; i++) {"
367 " f('a+', new X());"
368 "};");
369
370 // Compile an optimized version of f.
371 i::FLAG_always_opt = true;
372 CompileRun(f_source);
373 CompileRun("f('a+', new X());");
374 CHECK(!i::V8::UseCrankshaft() ||
375 GetJSFunction(env->Global(), "f")->IsOptimized());
376
377 // Call f and force deoptimization while processing the binary operation.
378 CompileRun("deopt = true;"
Ben Murdoch85b71792012-04-11 18:30:58 +0100379 "var result = f('a+', new X());"
380 "gc(); gc();");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100381 }
382
383 CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
384 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
385 v8::Handle<v8::Value> result = env->Global()->Get(v8_str("result"));
386 CHECK(result->IsString());
387 v8::String::AsciiValue ascii(result);
388 CHECK_EQ("a+an X", *ascii);
Steve Block44f0eee2011-05-26 01:26:41 +0100389 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100390}
391
392
393static void CompileConstructorWithDeoptimizingValueOf() {
394 CompileRun("var count = 0;"
395 "var result = 0;"
396 "var deopt = false;"
397 "function X() { };"
398 "X.prototype.valueOf = function () {"
399 " if (deopt) { count++; %DeoptimizeFunction(f); } return 8"
400 "};");
401}
402
403
404static void TestDeoptimizeBinaryOpHelper(LocalContext* env,
405 const char* binary_op) {
406 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> f_source_buffer;
407 OS::SNPrintF(f_source_buffer,
408 "function f(x, y) { return x %s y; };",
409 binary_op);
410 char* f_source = f_source_buffer.start();
411
412 AllowNativesSyntaxNoInlining options;
413 // Compile function f and collect to type feedback to insert binary op stub
414 // call in the optimized code.
415 i::FLAG_prepare_always_opt = true;
416 CompileConstructorWithDeoptimizingValueOf();
417 CompileRun(f_source);
418 CompileRun("for (var i = 0; i < 5; i++) {"
419 " f(8, new X());"
420 "};");
421
422 // Compile an optimized version of f.
423 i::FLAG_always_opt = true;
424 CompileRun(f_source);
425 CompileRun("f(7, new X());");
426 CHECK(!i::V8::UseCrankshaft() ||
427 GetJSFunction((*env)->Global(), "f")->IsOptimized());
428
429 // Call f and force deoptimization while processing the binary operation.
430 CompileRun("deopt = true;"
Ben Murdoch85b71792012-04-11 18:30:58 +0100431 "var result = f(7, new X());"
432 "gc(); gc();");
433
Ben Murdochb0fe1622011-05-05 13:52:32 +0100434 CHECK(!GetJSFunction((*env)->Global(), "f")->IsOptimized());
435}
436
437
438TEST(DeoptimizeBinaryOperationADD) {
439 v8::HandleScope scope;
Ben Murdoch85b71792012-04-11 18:30:58 +0100440 const char* extension_list[] = { "v8/gc" };
441 v8::ExtensionConfiguration extensions(1, extension_list);
442 LocalContext env(&extensions);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100443
444 TestDeoptimizeBinaryOpHelper(&env, "+");
445
446 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
447 CHECK_EQ(15, env->Global()->Get(v8_str("result"))->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +0100448 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100449}
450
451
452TEST(DeoptimizeBinaryOperationSUB) {
453 v8::HandleScope scope;
Ben Murdoch85b71792012-04-11 18:30:58 +0100454 const char* extension_list[] = { "v8/gc" };
455 v8::ExtensionConfiguration extensions(1, extension_list);
456 LocalContext env(&extensions);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100457
458 TestDeoptimizeBinaryOpHelper(&env, "-");
459
460 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
461 CHECK_EQ(-1, env->Global()->Get(v8_str("result"))->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +0100462 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100463}
464
465
466TEST(DeoptimizeBinaryOperationMUL) {
467 v8::HandleScope scope;
Ben Murdoch85b71792012-04-11 18:30:58 +0100468 const char* extension_list[] = { "v8/gc" };
469 v8::ExtensionConfiguration extensions(1, extension_list);
470 LocalContext env(&extensions);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100471
472 TestDeoptimizeBinaryOpHelper(&env, "*");
473
474 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
475 CHECK_EQ(56, env->Global()->Get(v8_str("result"))->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +0100476 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100477}
478
479
480TEST(DeoptimizeBinaryOperationDIV) {
481 v8::HandleScope scope;
Ben Murdoch85b71792012-04-11 18:30:58 +0100482 const char* extension_list[] = { "v8/gc" };
483 v8::ExtensionConfiguration extensions(1, extension_list);
484 LocalContext env(&extensions);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100485
486 TestDeoptimizeBinaryOpHelper(&env, "/");
487
488 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
489 CHECK_EQ(0, env->Global()->Get(v8_str("result"))->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +0100490 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100491}
492
493
494TEST(DeoptimizeBinaryOperationMOD) {
495 v8::HandleScope scope;
Ben Murdoch85b71792012-04-11 18:30:58 +0100496 const char* extension_list[] = { "v8/gc" };
497 v8::ExtensionConfiguration extensions(1, extension_list);
498 LocalContext env(&extensions);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100499
500 TestDeoptimizeBinaryOpHelper(&env, "%");
501
502 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
503 CHECK_EQ(7, env->Global()->Get(v8_str("result"))->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +0100504 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100505}
506
507
508TEST(DeoptimizeCompare) {
509 v8::HandleScope scope;
Ben Murdoch85b71792012-04-11 18:30:58 +0100510 const char* extension_list[] = { "v8/gc" };
511 v8::ExtensionConfiguration extensions(1, extension_list);
512 LocalContext env(&extensions);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100513
514 const char* f_source = "function f(x, y) { return x < y; };";
515
516 {
517 AllowNativesSyntaxNoInlining options;
518 // Compile function f and collect to type feedback to insert compare ic
519 // call in the optimized code.
520 i::FLAG_prepare_always_opt = true;
521 CompileRun("var count = 0;"
522 "var result = 0;"
523 "var deopt = false;"
524 "function X() { };"
525 "X.prototype.toString = function () {"
526 " if (deopt) { count++; %DeoptimizeFunction(f); } return 'b'"
527 "};");
528 CompileRun(f_source);
529 CompileRun("for (var i = 0; i < 5; i++) {"
530 " f('a', new X());"
531 "};");
532
533 // Compile an optimized version of f.
534 i::FLAG_always_opt = true;
535 CompileRun(f_source);
536 CompileRun("f('a', new X());");
537 CHECK(!i::V8::UseCrankshaft() ||
538 GetJSFunction(env->Global(), "f")->IsOptimized());
539
540 // Call f and force deoptimization while processing the comparison.
541 CompileRun("deopt = true;"
Ben Murdoch85b71792012-04-11 18:30:58 +0100542 "var result = f('a', new X());"
543 "gc(); gc();");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100544 }
545
546 CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
547 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
548 CHECK_EQ(true, env->Global()->Get(v8_str("result"))->BooleanValue());
Steve Block44f0eee2011-05-26 01:26:41 +0100549 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100550}
551
552
553TEST(DeoptimizeLoadICStoreIC) {
554 v8::HandleScope scope;
Ben Murdoch85b71792012-04-11 18:30:58 +0100555 const char* extension_list[] = { "v8/gc" };
556 v8::ExtensionConfiguration extensions(1, extension_list);
557 LocalContext env(&extensions);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100558
559 // Functions to generate load/store/keyed load/keyed store IC calls.
560 const char* f1_source = "function f1(x) { return x.y; };";
561 const char* g1_source = "function g1(x) { x.y = 1; };";
562 const char* f2_source = "function f2(x, y) { return x[y]; };";
563 const char* g2_source = "function g2(x, y) { x[y] = 1; };";
564
565 {
566 AllowNativesSyntaxNoInlining options;
567 // Compile functions and collect to type feedback to insert ic
568 // calls in the optimized code.
569 i::FLAG_prepare_always_opt = true;
570 CompileRun("var count = 0;"
571 "var result = 0;"
572 "var deopt = false;"
573 "function X() { };"
574 "X.prototype.__defineGetter__('y', function () {"
575 " if (deopt) { count++; %DeoptimizeFunction(f1); };"
576 " return 13;"
577 "});"
578 "X.prototype.__defineSetter__('y', function () {"
579 " if (deopt) { count++; %DeoptimizeFunction(g1); };"
580 "});"
581 "X.prototype.__defineGetter__('z', function () {"
582 " if (deopt) { count++; %DeoptimizeFunction(f2); };"
583 " return 13;"
584 "});"
585 "X.prototype.__defineSetter__('z', function () {"
586 " if (deopt) { count++; %DeoptimizeFunction(g2); };"
587 "});");
588 CompileRun(f1_source);
589 CompileRun(g1_source);
590 CompileRun(f2_source);
591 CompileRun(g2_source);
592 CompileRun("for (var i = 0; i < 5; i++) {"
593 " f1(new X());"
594 " g1(new X());"
595 " f2(new X(), 'z');"
596 " g2(new X(), 'z');"
597 "};");
598
599 // Compile an optimized version of the functions.
600 i::FLAG_always_opt = true;
601 CompileRun(f1_source);
602 CompileRun(g1_source);
603 CompileRun(f2_source);
604 CompileRun(g2_source);
605 CompileRun("f1(new X());");
606 CompileRun("g1(new X());");
607 CompileRun("f2(new X(), 'z');");
608 CompileRun("g2(new X(), 'z');");
609 if (i::V8::UseCrankshaft()) {
610 CHECK(GetJSFunction(env->Global(), "f1")->IsOptimized());
611 CHECK(GetJSFunction(env->Global(), "g1")->IsOptimized());
612 CHECK(GetJSFunction(env->Global(), "f2")->IsOptimized());
613 CHECK(GetJSFunction(env->Global(), "g2")->IsOptimized());
614 }
615
616 // Call functions and force deoptimization while processing the ics.
617 CompileRun("deopt = true;"
618 "var result = f1(new X());"
619 "g1(new X());"
620 "f2(new X(), 'z');"
Ben Murdoch85b71792012-04-11 18:30:58 +0100621 "g2(new X(), 'z');"
622 "gc(); gc();");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100623 }
624
625 CHECK(!GetJSFunction(env->Global(), "f1")->IsOptimized());
626 CHECK(!GetJSFunction(env->Global(), "g1")->IsOptimized());
627 CHECK(!GetJSFunction(env->Global(), "f2")->IsOptimized());
628 CHECK(!GetJSFunction(env->Global(), "g2")->IsOptimized());
629 CHECK_EQ(4, env->Global()->Get(v8_str("count"))->Int32Value());
630 CHECK_EQ(13, env->Global()->Get(v8_str("result"))->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +0100631 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100632}
633
634
635TEST(DeoptimizeLoadICStoreICNested) {
636 v8::HandleScope scope;
Ben Murdoch85b71792012-04-11 18:30:58 +0100637 const char* extension_list[] = { "v8/gc" };
638 v8::ExtensionConfiguration extensions(1, extension_list);
639 LocalContext env(&extensions);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100640
641 // Functions to generate load/store/keyed load/keyed store IC calls.
642 const char* f1_source = "function f1(x) { return x.y; };";
643 const char* g1_source = "function g1(x) { x.y = 1; };";
644 const char* f2_source = "function f2(x, y) { return x[y]; };";
645 const char* g2_source = "function g2(x, y) { x[y] = 1; };";
646
647 {
648 AllowNativesSyntaxNoInlining options;
649 // Compile functions and collect to type feedback to insert ic
650 // calls in the optimized code.
651 i::FLAG_prepare_always_opt = true;
652 CompileRun("var count = 0;"
653 "var result = 0;"
654 "var deopt = false;"
655 "function X() { };"
656 "X.prototype.__defineGetter__('y', function () {"
657 " g1(this);"
658 " return 13;"
659 "});"
660 "X.prototype.__defineSetter__('y', function () {"
661 " f2(this, 'z');"
662 "});"
663 "X.prototype.__defineGetter__('z', function () {"
664 " g2(this, 'z');"
665 "});"
666 "X.prototype.__defineSetter__('z', function () {"
667 " if (deopt) {"
668 " count++;"
669 " %DeoptimizeFunction(f1);"
670 " %DeoptimizeFunction(g1);"
671 " %DeoptimizeFunction(f2);"
672 " %DeoptimizeFunction(g2); };"
673 "});");
674 CompileRun(f1_source);
675 CompileRun(g1_source);
676 CompileRun(f2_source);
677 CompileRun(g2_source);
678 CompileRun("for (var i = 0; i < 5; i++) {"
679 " f1(new X());"
680 " g1(new X());"
681 " f2(new X(), 'z');"
682 " g2(new X(), 'z');"
683 "};");
684
685 // Compile an optimized version of the functions.
686 i::FLAG_always_opt = true;
687 CompileRun(f1_source);
688 CompileRun(g1_source);
689 CompileRun(f2_source);
690 CompileRun(g2_source);
691 CompileRun("f1(new X());");
692 CompileRun("g1(new X());");
693 CompileRun("f2(new X(), 'z');");
694 CompileRun("g2(new X(), 'z');");
695 if (i::V8::UseCrankshaft()) {
696 CHECK(GetJSFunction(env->Global(), "f1")->IsOptimized());
697 CHECK(GetJSFunction(env->Global(), "g1")->IsOptimized());
698 CHECK(GetJSFunction(env->Global(), "f2")->IsOptimized());
699 CHECK(GetJSFunction(env->Global(), "g2")->IsOptimized());
700 }
701
702 // Call functions and force deoptimization while processing the ics.
703 CompileRun("deopt = true;"
Ben Murdoch85b71792012-04-11 18:30:58 +0100704 "var result = f1(new X());"
705 "gc(); gc();");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100706 }
707
708 CHECK(!GetJSFunction(env->Global(), "f1")->IsOptimized());
709 CHECK(!GetJSFunction(env->Global(), "g1")->IsOptimized());
710 CHECK(!GetJSFunction(env->Global(), "f2")->IsOptimized());
711 CHECK(!GetJSFunction(env->Global(), "g2")->IsOptimized());
712 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
713 CHECK_EQ(13, env->Global()->Get(v8_str("result"))->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +0100714 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100715}