blob: c52c5788dbce107e3db13e444bac44af56cd9c1e [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// Copyright 2012 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
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100100// Abort any ongoing incremental marking to make sure that all weak global
101// handle callbacks are processed.
102static void NonIncrementalGC() {
103 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
104}
105
106
Steve Block053d10c2011-06-13 19:13:29 +0100107static Handle<JSFunction> GetJSFunction(v8::Handle<v8::Object> obj,
108 const char* property_name) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100109 v8::Local<v8::Function> fun =
110 v8::Local<v8::Function>::Cast(obj->Get(v8_str(property_name)));
111 return v8::Utils::OpenHandle(*fun);
112}
113
114
115TEST(DeoptimizeSimple) {
116 v8::HandleScope scope;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100117 LocalContext env;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100118
119 // Test lazy deoptimization of a simple function.
120 {
121 AlwaysOptimizeAllowNativesSyntaxNoInlining options;
122 CompileRun(
123 "var count = 0;"
124 "function h() { %DeoptimizeFunction(f); }"
125 "function g() { count++; h(); }"
126 "function f() { g(); };"
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100127 "f();");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100128 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100129 NonIncrementalGC();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100130
131 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
132 CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
Steve Block44f0eee2011-05-26 01:26:41 +0100133 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100134
135 // Test lazy deoptimization of a simple function. Call the function after the
136 // deoptimization while it is still activated further down the stack.
137 {
138 AlwaysOptimizeAllowNativesSyntaxNoInlining options;
139 CompileRun(
140 "var count = 0;"
141 "function g() { count++; %DeoptimizeFunction(f); f(false); }"
142 "function f(x) { if (x) { g(); } else { return } };"
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100143 "f(true);");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100144 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100145 NonIncrementalGC();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100146
147 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
148 CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
Steve Block44f0eee2011-05-26 01:26:41 +0100149 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100150}
151
152
153TEST(DeoptimizeSimpleWithArguments) {
154 v8::HandleScope scope;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100155 LocalContext env;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100156
157 // Test lazy deoptimization of a simple function with some arguments.
158 {
159 AlwaysOptimizeAllowNativesSyntaxNoInlining options;
160 CompileRun(
161 "var count = 0;"
162 "function h(x) { %DeoptimizeFunction(f); }"
163 "function g(x, y) { count++; h(x); }"
164 "function f(x, y, z) { g(1,x); y+z; };"
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100165 "f(1, \"2\", false);");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100166 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100167 NonIncrementalGC();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100168
169 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
170 CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
Steve Block44f0eee2011-05-26 01:26:41 +0100171 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100172
173 // Test lazy deoptimization of a simple function with some arguments. Call the
174 // function after the deoptimization while it is still activated further down
175 // the stack.
176 {
177 AlwaysOptimizeAllowNativesSyntaxNoInlining options;
178 CompileRun(
179 "var count = 0;"
180 "function g(x, y) { count++; %DeoptimizeFunction(f); f(false, 1, y); }"
181 "function f(x, y, z) { if (x) { g(x, y); } else { return y + z; } };"
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100182 "f(true, 1, \"2\");");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100183 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100184 NonIncrementalGC();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100185
186 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
187 CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
Steve Block44f0eee2011-05-26 01:26:41 +0100188 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100189}
190
191
192TEST(DeoptimizeSimpleNested) {
193 v8::HandleScope scope;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100194 LocalContext env;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100195
196 // Test lazy deoptimization of a simple function. Have a nested function call
197 // do the deoptimization.
198 {
199 AlwaysOptimizeAllowNativesSyntaxNoInlining options;
200 CompileRun(
201 "var count = 0;"
202 "var result = 0;"
203 "function h(x, y, z) { return x + y + z; }"
204 "function g(z) { count++; %DeoptimizeFunction(f); return z;}"
205 "function f(x,y,z) { return h(x, y, g(z)); };"
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100206 "result = f(1, 2, 3);");
207 NonIncrementalGC();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100208
209 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
210 CHECK_EQ(6, env->Global()->Get(v8_str("result"))->Int32Value());
211 CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
Steve Block44f0eee2011-05-26 01:26:41 +0100212 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100213 }
214}
215
216
217TEST(DeoptimizeRecursive) {
218 v8::HandleScope scope;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100219 LocalContext env;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100220
221 {
222 // Test lazy deoptimization of a simple function called recursively. Call
223 // the function recursively a number of times before deoptimizing it.
224 AlwaysOptimizeAllowNativesSyntaxNoInlining options;
225 CompileRun(
226 "var count = 0;"
227 "var calls = 0;"
228 "function g() { count++; %DeoptimizeFunction(f); }"
229 "function f(x) { calls++; if (x > 0) { f(x - 1); } else { g(); } };"
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100230 "f(10);");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100231 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100232 NonIncrementalGC();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100233
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 Murdoch3ef787d2012-04-12 10:51:47 +0100240 CHECK(!fun.IsEmpty());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100241}
242
243
244TEST(DeoptimizeMultiple) {
245 v8::HandleScope scope;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100246 LocalContext env;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100247
248 {
249 AlwaysOptimizeAllowNativesSyntaxNoInlining options;
250 CompileRun(
251 "var count = 0;"
252 "var result = 0;"
253 "function g() { count++;"
254 " %DeoptimizeFunction(f1);"
255 " %DeoptimizeFunction(f2);"
256 " %DeoptimizeFunction(f3);"
257 " %DeoptimizeFunction(f4);}"
258 "function f4(x) { g(); };"
259 "function f3(x, y, z) { f4(); return x + y + z; };"
260 "function f2(x, y) { return x + f3(y + 1, y + 1, y + 1) + y; };"
261 "function f1(x) { return f2(x + 1, x + 1) + x; };"
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100262 "result = f1(1);");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100263 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100264 NonIncrementalGC();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100265
266 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
267 CHECK_EQ(14, env->Global()->Get(v8_str("result"))->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +0100268 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100269}
270
271
272TEST(DeoptimizeConstructor) {
273 v8::HandleScope scope;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100274 LocalContext env;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100275
276 {
277 AlwaysOptimizeAllowNativesSyntaxNoInlining options;
278 CompileRun(
279 "var count = 0;"
280 "function g() { count++;"
281 " %DeoptimizeFunction(f); }"
282 "function f() { g(); };"
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100283 "result = new f() instanceof f;");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100284 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100285 NonIncrementalGC();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100286
287 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
288 CHECK(env->Global()->Get(v8_str("result"))->IsTrue());
Steve Block44f0eee2011-05-26 01:26:41 +0100289 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100290
291 {
292 AlwaysOptimizeAllowNativesSyntaxNoInlining options;
293 CompileRun(
294 "var count = 0;"
295 "var result = 0;"
296 "function g() { count++;"
297 " %DeoptimizeFunction(f); }"
298 "function f(x, y) { this.x = x; g(); this.y = y; };"
299 "result = new f(1, 2);"
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100300 "result = result.x + result.y;");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100301 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100302 NonIncrementalGC();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100303
304 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
305 CHECK_EQ(3, env->Global()->Get(v8_str("result"))->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +0100306 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100307}
308
309
310TEST(DeoptimizeConstructorMultiple) {
311 v8::HandleScope scope;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100312 LocalContext env;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100313
314 {
315 AlwaysOptimizeAllowNativesSyntaxNoInlining options;
316 CompileRun(
317 "var count = 0;"
318 "var result = 0;"
319 "function g() { count++;"
320 " %DeoptimizeFunction(f1);"
321 " %DeoptimizeFunction(f2);"
322 " %DeoptimizeFunction(f3);"
323 " %DeoptimizeFunction(f4);}"
324 "function f4(x) { this.result = x; g(); };"
325 "function f3(x, y, z) { this.result = new f4(x + y + z).result; };"
326 "function f2(x, y) {"
327 " this.result = x + new f3(y + 1, y + 1, y + 1).result + y; };"
328 "function f1(x) { this.result = new f2(x + 1, x + 1).result + x; };"
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100329 "result = new f1(1).result;");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100330 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100331 NonIncrementalGC();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100332
333 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
334 CHECK_EQ(14, env->Global()->Get(v8_str("result"))->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +0100335 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100336}
337
338
339TEST(DeoptimizeBinaryOperationADDString) {
340 v8::HandleScope scope;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100341 LocalContext env;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100342
343 const char* f_source = "function f(x, y) { return x + y; };";
344
345 {
346 AllowNativesSyntaxNoInlining options;
347 // Compile function f and collect to type feedback to insert binary op stub
348 // call in the optimized code.
349 i::FLAG_prepare_always_opt = true;
350 CompileRun("var count = 0;"
351 "var result = 0;"
352 "var deopt = false;"
353 "function X() { };"
354 "X.prototype.toString = function () {"
355 " if (deopt) { count++; %DeoptimizeFunction(f); } return 'an X'"
356 "};");
357 CompileRun(f_source);
358 CompileRun("for (var i = 0; i < 5; i++) {"
359 " f('a+', new X());"
360 "};");
361
362 // Compile an optimized version of f.
363 i::FLAG_always_opt = true;
364 CompileRun(f_source);
365 CompileRun("f('a+', new X());");
366 CHECK(!i::V8::UseCrankshaft() ||
367 GetJSFunction(env->Global(), "f")->IsOptimized());
368
369 // Call f and force deoptimization while processing the binary operation.
370 CompileRun("deopt = true;"
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100371 "var result = f('a+', new X());");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100372 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100373 NonIncrementalGC();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100374
375 CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
376 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
377 v8::Handle<v8::Value> result = env->Global()->Get(v8_str("result"));
378 CHECK(result->IsString());
379 v8::String::AsciiValue ascii(result);
380 CHECK_EQ("a+an X", *ascii);
Steve Block44f0eee2011-05-26 01:26:41 +0100381 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100382}
383
384
385static void CompileConstructorWithDeoptimizingValueOf() {
386 CompileRun("var count = 0;"
387 "var result = 0;"
388 "var deopt = false;"
389 "function X() { };"
390 "X.prototype.valueOf = function () {"
391 " if (deopt) { count++; %DeoptimizeFunction(f); } return 8"
392 "};");
393}
394
395
396static void TestDeoptimizeBinaryOpHelper(LocalContext* env,
397 const char* binary_op) {
398 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> f_source_buffer;
399 OS::SNPrintF(f_source_buffer,
400 "function f(x, y) { return x %s y; };",
401 binary_op);
402 char* f_source = f_source_buffer.start();
403
404 AllowNativesSyntaxNoInlining options;
405 // Compile function f and collect to type feedback to insert binary op stub
406 // call in the optimized code.
407 i::FLAG_prepare_always_opt = true;
408 CompileConstructorWithDeoptimizingValueOf();
409 CompileRun(f_source);
410 CompileRun("for (var i = 0; i < 5; i++) {"
411 " f(8, new X());"
412 "};");
413
414 // Compile an optimized version of f.
415 i::FLAG_always_opt = true;
416 CompileRun(f_source);
417 CompileRun("f(7, new X());");
418 CHECK(!i::V8::UseCrankshaft() ||
419 GetJSFunction((*env)->Global(), "f")->IsOptimized());
420
421 // Call f and force deoptimization while processing the binary operation.
422 CompileRun("deopt = true;"
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100423 "var result = f(7, new X());");
424 NonIncrementalGC();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100425 CHECK(!GetJSFunction((*env)->Global(), "f")->IsOptimized());
426}
427
428
429TEST(DeoptimizeBinaryOperationADD) {
430 v8::HandleScope scope;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100431 LocalContext env;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100432
433 TestDeoptimizeBinaryOpHelper(&env, "+");
434
435 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
436 CHECK_EQ(15, env->Global()->Get(v8_str("result"))->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +0100437 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100438}
439
440
441TEST(DeoptimizeBinaryOperationSUB) {
442 v8::HandleScope scope;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100443 LocalContext env;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100444
445 TestDeoptimizeBinaryOpHelper(&env, "-");
446
447 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
448 CHECK_EQ(-1, env->Global()->Get(v8_str("result"))->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +0100449 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100450}
451
452
453TEST(DeoptimizeBinaryOperationMUL) {
454 v8::HandleScope scope;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100455 LocalContext env;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100456
457 TestDeoptimizeBinaryOpHelper(&env, "*");
458
459 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
460 CHECK_EQ(56, env->Global()->Get(v8_str("result"))->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +0100461 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100462}
463
464
465TEST(DeoptimizeBinaryOperationDIV) {
466 v8::HandleScope scope;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100467 LocalContext env;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100468
469 TestDeoptimizeBinaryOpHelper(&env, "/");
470
471 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
472 CHECK_EQ(0, env->Global()->Get(v8_str("result"))->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +0100473 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100474}
475
476
477TEST(DeoptimizeBinaryOperationMOD) {
478 v8::HandleScope scope;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100479 LocalContext env;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100480
481 TestDeoptimizeBinaryOpHelper(&env, "%");
482
483 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
484 CHECK_EQ(7, env->Global()->Get(v8_str("result"))->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +0100485 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100486}
487
488
489TEST(DeoptimizeCompare) {
490 v8::HandleScope scope;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100491 LocalContext env;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100492
493 const char* f_source = "function f(x, y) { return x < y; };";
494
495 {
496 AllowNativesSyntaxNoInlining options;
497 // Compile function f and collect to type feedback to insert compare ic
498 // call in the optimized code.
499 i::FLAG_prepare_always_opt = true;
500 CompileRun("var count = 0;"
501 "var result = 0;"
502 "var deopt = false;"
503 "function X() { };"
504 "X.prototype.toString = function () {"
505 " if (deopt) { count++; %DeoptimizeFunction(f); } return 'b'"
506 "};");
507 CompileRun(f_source);
508 CompileRun("for (var i = 0; i < 5; i++) {"
509 " f('a', new X());"
510 "};");
511
512 // Compile an optimized version of f.
513 i::FLAG_always_opt = true;
514 CompileRun(f_source);
515 CompileRun("f('a', new X());");
516 CHECK(!i::V8::UseCrankshaft() ||
517 GetJSFunction(env->Global(), "f")->IsOptimized());
518
519 // Call f and force deoptimization while processing the comparison.
520 CompileRun("deopt = true;"
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100521 "var result = f('a', new X());");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100522 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100523 NonIncrementalGC();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100524
525 CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
526 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
527 CHECK_EQ(true, env->Global()->Get(v8_str("result"))->BooleanValue());
Steve Block44f0eee2011-05-26 01:26:41 +0100528 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100529}
530
531
532TEST(DeoptimizeLoadICStoreIC) {
533 v8::HandleScope scope;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100534 LocalContext env;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100535
536 // Functions to generate load/store/keyed load/keyed store IC calls.
537 const char* f1_source = "function f1(x) { return x.y; };";
538 const char* g1_source = "function g1(x) { x.y = 1; };";
539 const char* f2_source = "function f2(x, y) { return x[y]; };";
540 const char* g2_source = "function g2(x, y) { x[y] = 1; };";
541
542 {
543 AllowNativesSyntaxNoInlining options;
544 // Compile functions and collect to type feedback to insert ic
545 // calls in the optimized code.
546 i::FLAG_prepare_always_opt = true;
547 CompileRun("var count = 0;"
548 "var result = 0;"
549 "var deopt = false;"
550 "function X() { };"
551 "X.prototype.__defineGetter__('y', function () {"
552 " if (deopt) { count++; %DeoptimizeFunction(f1); };"
553 " return 13;"
554 "});"
555 "X.prototype.__defineSetter__('y', function () {"
556 " if (deopt) { count++; %DeoptimizeFunction(g1); };"
557 "});"
558 "X.prototype.__defineGetter__('z', function () {"
559 " if (deopt) { count++; %DeoptimizeFunction(f2); };"
560 " return 13;"
561 "});"
562 "X.prototype.__defineSetter__('z', function () {"
563 " if (deopt) { count++; %DeoptimizeFunction(g2); };"
564 "});");
565 CompileRun(f1_source);
566 CompileRun(g1_source);
567 CompileRun(f2_source);
568 CompileRun(g2_source);
569 CompileRun("for (var i = 0; i < 5; i++) {"
570 " f1(new X());"
571 " g1(new X());"
572 " f2(new X(), 'z');"
573 " g2(new X(), 'z');"
574 "};");
575
576 // Compile an optimized version of the functions.
577 i::FLAG_always_opt = true;
578 CompileRun(f1_source);
579 CompileRun(g1_source);
580 CompileRun(f2_source);
581 CompileRun(g2_source);
582 CompileRun("f1(new X());");
583 CompileRun("g1(new X());");
584 CompileRun("f2(new X(), 'z');");
585 CompileRun("g2(new X(), 'z');");
586 if (i::V8::UseCrankshaft()) {
587 CHECK(GetJSFunction(env->Global(), "f1")->IsOptimized());
588 CHECK(GetJSFunction(env->Global(), "g1")->IsOptimized());
589 CHECK(GetJSFunction(env->Global(), "f2")->IsOptimized());
590 CHECK(GetJSFunction(env->Global(), "g2")->IsOptimized());
591 }
592
593 // Call functions and force deoptimization while processing the ics.
594 CompileRun("deopt = true;"
595 "var result = f1(new X());"
596 "g1(new X());"
597 "f2(new X(), 'z');"
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100598 "g2(new X(), 'z');");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100599 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100600 NonIncrementalGC();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100601
602 CHECK(!GetJSFunction(env->Global(), "f1")->IsOptimized());
603 CHECK(!GetJSFunction(env->Global(), "g1")->IsOptimized());
604 CHECK(!GetJSFunction(env->Global(), "f2")->IsOptimized());
605 CHECK(!GetJSFunction(env->Global(), "g2")->IsOptimized());
606 CHECK_EQ(4, env->Global()->Get(v8_str("count"))->Int32Value());
607 CHECK_EQ(13, env->Global()->Get(v8_str("result"))->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +0100608 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100609}
610
611
612TEST(DeoptimizeLoadICStoreICNested) {
613 v8::HandleScope scope;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100614 LocalContext env;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100615
616 // Functions to generate load/store/keyed load/keyed store IC calls.
617 const char* f1_source = "function f1(x) { return x.y; };";
618 const char* g1_source = "function g1(x) { x.y = 1; };";
619 const char* f2_source = "function f2(x, y) { return x[y]; };";
620 const char* g2_source = "function g2(x, y) { x[y] = 1; };";
621
622 {
623 AllowNativesSyntaxNoInlining options;
624 // Compile functions and collect to type feedback to insert ic
625 // calls in the optimized code.
626 i::FLAG_prepare_always_opt = true;
627 CompileRun("var count = 0;"
628 "var result = 0;"
629 "var deopt = false;"
630 "function X() { };"
631 "X.prototype.__defineGetter__('y', function () {"
632 " g1(this);"
633 " return 13;"
634 "});"
635 "X.prototype.__defineSetter__('y', function () {"
636 " f2(this, 'z');"
637 "});"
638 "X.prototype.__defineGetter__('z', function () {"
639 " g2(this, 'z');"
640 "});"
641 "X.prototype.__defineSetter__('z', function () {"
642 " if (deopt) {"
643 " count++;"
644 " %DeoptimizeFunction(f1);"
645 " %DeoptimizeFunction(g1);"
646 " %DeoptimizeFunction(f2);"
647 " %DeoptimizeFunction(g2); };"
648 "});");
649 CompileRun(f1_source);
650 CompileRun(g1_source);
651 CompileRun(f2_source);
652 CompileRun(g2_source);
653 CompileRun("for (var i = 0; i < 5; i++) {"
654 " f1(new X());"
655 " g1(new X());"
656 " f2(new X(), 'z');"
657 " g2(new X(), 'z');"
658 "};");
659
660 // Compile an optimized version of the functions.
661 i::FLAG_always_opt = true;
662 CompileRun(f1_source);
663 CompileRun(g1_source);
664 CompileRun(f2_source);
665 CompileRun(g2_source);
666 CompileRun("f1(new X());");
667 CompileRun("g1(new X());");
668 CompileRun("f2(new X(), 'z');");
669 CompileRun("g2(new X(), 'z');");
670 if (i::V8::UseCrankshaft()) {
671 CHECK(GetJSFunction(env->Global(), "f1")->IsOptimized());
672 CHECK(GetJSFunction(env->Global(), "g1")->IsOptimized());
673 CHECK(GetJSFunction(env->Global(), "f2")->IsOptimized());
674 CHECK(GetJSFunction(env->Global(), "g2")->IsOptimized());
675 }
676
677 // Call functions and force deoptimization while processing the ics.
678 CompileRun("deopt = true;"
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100679 "var result = f1(new X());");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100680 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100681 NonIncrementalGC();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100682
683 CHECK(!GetJSFunction(env->Global(), "f1")->IsOptimized());
684 CHECK(!GetJSFunction(env->Global(), "g1")->IsOptimized());
685 CHECK(!GetJSFunction(env->Global(), "f2")->IsOptimized());
686 CHECK(!GetJSFunction(env->Global(), "g2")->IsOptimized());
687 CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
688 CHECK_EQ(13, env->Global()->Get(v8_str("result"))->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +0100689 CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100690}