v8  3.25.30(node0.11.13)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
test-deoptimization.cc
Go to the documentation of this file.
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // 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"
33 #include "cctest.h"
34 #include "compilation-cache.h"
35 #include "debug.h"
36 #include "deoptimizer.h"
37 #include "isolate.h"
38 #include "platform.h"
39 #include "stub-cache.h"
40 
41 using ::v8::internal::Deoptimizer;
42 using ::v8::internal::EmbeddedVector;
43 using ::v8::internal::Handle;
44 using ::v8::internal::Isolate;
45 using ::v8::internal::JSFunction;
46 using ::v8::internal::OS;
48 
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.
55  public:
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 
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.
81  public:
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 
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 
100 // Abort any ongoing incremental marking to make sure that all weak global
101 // handle callbacks are processed.
102 static void NonIncrementalGC() {
104 }
105 
106 
107 static Handle<JSFunction> GetJSFunction(v8::Handle<v8::Object> obj,
108  const char* property_name) {
110  v8::Local<v8::Function>::Cast(obj->Get(v8_str(property_name)));
111  return v8::Utils::OpenHandle(*fun);
112 }
113 
114 
115 TEST(DeoptimizeSimple) {
116  LocalContext env;
117  v8::HandleScope scope(env->GetIsolate());
118 
119  // Test lazy deoptimization of a simple function.
120  {
122  CompileRun(
123  "var count = 0;"
124  "function h() { %DeoptimizeFunction(f); }"
125  "function g() { count++; h(); }"
126  "function f() { g(); };"
127  "f();");
128  }
129  NonIncrementalGC();
130 
131  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
132  CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
133  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
134 
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  {
139  CompileRun(
140  "var count = 0;"
141  "function g() { count++; %DeoptimizeFunction(f); f(false); }"
142  "function f(x) { if (x) { g(); } else { return } };"
143  "f(true);");
144  }
145  NonIncrementalGC();
146 
147  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
148  CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
149  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
150 }
151 
152 
153 TEST(DeoptimizeSimpleWithArguments) {
154  LocalContext env;
155  v8::HandleScope scope(env->GetIsolate());
156 
157  // Test lazy deoptimization of a simple function with some arguments.
158  {
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; };"
165  "f(1, \"2\", false);");
166  }
167  NonIncrementalGC();
168 
169  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
170  CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
171  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
172 
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  {
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; } };"
182  "f(true, 1, \"2\");");
183  }
184  NonIncrementalGC();
185 
186  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
187  CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
188  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
189 }
190 
191 
192 TEST(DeoptimizeSimpleNested) {
193  LocalContext env;
194  v8::HandleScope scope(env->GetIsolate());
195 
196  // Test lazy deoptimization of a simple function. Have a nested function call
197  // do the deoptimization.
198  {
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)); };"
206  "result = f(1, 2, 3);");
207  NonIncrementalGC();
208 
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());
212  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
213  }
214 }
215 
216 
217 TEST(DeoptimizeRecursive) {
218  LocalContext env;
219  v8::HandleScope scope(env->GetIsolate());
220 
221  {
222  // Test lazy deoptimization of a simple function called recursively. Call
223  // the function recursively a number of times before deoptimizing it.
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(); } };"
230  "f(10);");
231  }
232  NonIncrementalGC();
233 
234  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
235  CHECK_EQ(11, env->Global()->Get(v8_str("calls"))->Int32Value());
236  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
237 
239  env->Global()->Get(v8::String::NewFromUtf8(CcTest::isolate(), "f")));
240  CHECK(!fun.IsEmpty());
241 }
242 
243 
244 TEST(DeoptimizeMultiple) {
245  LocalContext env;
246  v8::HandleScope scope(env->GetIsolate());
247 
248  {
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; };"
262  "result = f1(1);");
263  }
264  NonIncrementalGC();
265 
266  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
267  CHECK_EQ(14, env->Global()->Get(v8_str("result"))->Int32Value());
268  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
269 }
270 
271 
272 TEST(DeoptimizeConstructor) {
273  LocalContext env;
274  v8::HandleScope scope(env->GetIsolate());
275 
276  {
278  CompileRun(
279  "var count = 0;"
280  "function g() { count++;"
281  " %DeoptimizeFunction(f); }"
282  "function f() { g(); };"
283  "result = new f() instanceof f;");
284  }
285  NonIncrementalGC();
286 
287  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
288  CHECK(env->Global()->Get(v8_str("result"))->IsTrue());
289  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
290 
291  {
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);"
300  "result = result.x + result.y;");
301  }
302  NonIncrementalGC();
303 
304  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
305  CHECK_EQ(3, env->Global()->Get(v8_str("result"))->Int32Value());
306  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
307 }
308 
309 
310 TEST(DeoptimizeConstructorMultiple) {
311  LocalContext env;
312  v8::HandleScope scope(env->GetIsolate());
313 
314  {
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; };"
329  "result = new f1(1).result;");
330  }
331  NonIncrementalGC();
332 
333  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
334  CHECK_EQ(14, env->Global()->Get(v8_str("result"))->Int32Value());
335  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
336 }
337 
338 
339 TEST(DeoptimizeBinaryOperationADDString) {
340  i::FLAG_concurrent_recompilation = false;
342  LocalContext env;
343  v8::HandleScope scope(env->GetIsolate());
344 
345  const char* f_source = "function f(x, y) { return x + y; };";
346 
347  {
348  // Compile function f and collect to type feedback to insert binary op stub
349  // call in the optimized code.
350  i::FLAG_prepare_always_opt = true;
351  CompileRun("var count = 0;"
352  "var result = 0;"
353  "var deopt = false;"
354  "function X() { };"
355  "X.prototype.toString = function () {"
356  " if (deopt) { count++; %DeoptimizeFunction(f); } return 'an X'"
357  "};");
358  CompileRun(f_source);
359  CompileRun("for (var i = 0; i < 5; i++) {"
360  " f('a+', new X());"
361  "};");
362 
363  // Compile an optimized version of f.
364  i::FLAG_always_opt = true;
365  CompileRun(f_source);
366  CompileRun("f('a+', new X());");
367  CHECK(!CcTest::i_isolate()->use_crankshaft() ||
368  GetJSFunction(env->Global(), "f")->IsOptimized());
369 
370  // Call f and force deoptimization while processing the binary operation.
371  CompileRun("deopt = true;"
372  "var result = f('a+', new X());");
373  }
374  NonIncrementalGC();
375 
376  CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
377  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
378  v8::Handle<v8::Value> result = env->Global()->Get(v8_str("result"));
379  CHECK(result->IsString());
380  v8::String::Utf8Value utf8(result);
381  CHECK_EQ("a+an X", *utf8);
382  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
383 }
384 
385 
386 static void CompileConstructorWithDeoptimizingValueOf() {
387  CompileRun("var count = 0;"
388  "var result = 0;"
389  "var deopt = false;"
390  "function X() { };"
391  "X.prototype.valueOf = function () {"
392  " if (deopt) { count++; %DeoptimizeFunction(f); } return 8"
393  "};");
394 }
395 
396 
397 static void TestDeoptimizeBinaryOpHelper(LocalContext* env,
398  const char* binary_op) {
399  EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> f_source_buffer;
400  OS::SNPrintF(f_source_buffer,
401  "function f(x, y) { return x %s y; };",
402  binary_op);
403  char* f_source = f_source_buffer.start();
404 
406  // Compile function f and collect to type feedback to insert binary op stub
407  // call in the optimized code.
408  i::FLAG_prepare_always_opt = true;
409  CompileConstructorWithDeoptimizingValueOf();
410  CompileRun(f_source);
411  CompileRun("for (var i = 0; i < 5; i++) {"
412  " f(8, new X());"
413  "};");
414 
415  // Compile an optimized version of f.
416  i::FLAG_always_opt = true;
417  CompileRun(f_source);
418  CompileRun("f(7, new X());");
419  CHECK(!CcTest::i_isolate()->use_crankshaft() ||
420  GetJSFunction((*env)->Global(), "f")->IsOptimized());
421 
422  // Call f and force deoptimization while processing the binary operation.
423  CompileRun("deopt = true;"
424  "var result = f(7, new X());");
425  NonIncrementalGC();
426  CHECK(!GetJSFunction((*env)->Global(), "f")->IsOptimized());
427 }
428 
429 
430 TEST(DeoptimizeBinaryOperationADD) {
431  i::FLAG_concurrent_recompilation = false;
432  LocalContext env;
433  v8::HandleScope scope(env->GetIsolate());
434 
435  TestDeoptimizeBinaryOpHelper(&env, "+");
436 
437  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
438  CHECK_EQ(15, env->Global()->Get(v8_str("result"))->Int32Value());
439  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
440 }
441 
442 
443 TEST(DeoptimizeBinaryOperationSUB) {
444  i::FLAG_concurrent_recompilation = false;
445  LocalContext env;
446  v8::HandleScope scope(env->GetIsolate());
447 
448  TestDeoptimizeBinaryOpHelper(&env, "-");
449 
450  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
451  CHECK_EQ(-1, env->Global()->Get(v8_str("result"))->Int32Value());
452  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
453 }
454 
455 
456 TEST(DeoptimizeBinaryOperationMUL) {
457  i::FLAG_concurrent_recompilation = false;
458  LocalContext env;
459  v8::HandleScope scope(env->GetIsolate());
460 
461  TestDeoptimizeBinaryOpHelper(&env, "*");
462 
463  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
464  CHECK_EQ(56, env->Global()->Get(v8_str("result"))->Int32Value());
465  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
466 }
467 
468 
469 TEST(DeoptimizeBinaryOperationDIV) {
470  i::FLAG_concurrent_recompilation = false;
471  LocalContext env;
472  v8::HandleScope scope(env->GetIsolate());
473 
474  TestDeoptimizeBinaryOpHelper(&env, "/");
475 
476  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
477  CHECK_EQ(0, env->Global()->Get(v8_str("result"))->Int32Value());
478  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
479 }
480 
481 
482 TEST(DeoptimizeBinaryOperationMOD) {
483  i::FLAG_concurrent_recompilation = false;
484  LocalContext env;
485  v8::HandleScope scope(env->GetIsolate());
486 
487  TestDeoptimizeBinaryOpHelper(&env, "%");
488 
489  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
490  CHECK_EQ(7, env->Global()->Get(v8_str("result"))->Int32Value());
491  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
492 }
493 
494 
495 TEST(DeoptimizeCompare) {
496  i::FLAG_concurrent_recompilation = false;
497  LocalContext env;
498  v8::HandleScope scope(env->GetIsolate());
499 
500  const char* f_source = "function f(x, y) { return x < y; };";
501 
502  {
504  // Compile function f and collect to type feedback to insert compare ic
505  // call in the optimized code.
506  i::FLAG_prepare_always_opt = true;
507  CompileRun("var count = 0;"
508  "var result = 0;"
509  "var deopt = false;"
510  "function X() { };"
511  "X.prototype.toString = function () {"
512  " if (deopt) { count++; %DeoptimizeFunction(f); } return 'b'"
513  "};");
514  CompileRun(f_source);
515  CompileRun("for (var i = 0; i < 5; i++) {"
516  " f('a', new X());"
517  "};");
518 
519  // Compile an optimized version of f.
520  i::FLAG_always_opt = true;
521  CompileRun(f_source);
522  CompileRun("f('a', new X());");
523  CHECK(!CcTest::i_isolate()->use_crankshaft() ||
524  GetJSFunction(env->Global(), "f")->IsOptimized());
525 
526  // Call f and force deoptimization while processing the comparison.
527  CompileRun("deopt = true;"
528  "var result = f('a', new X());");
529  }
530  NonIncrementalGC();
531 
532  CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
533  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
534  CHECK_EQ(true, env->Global()->Get(v8_str("result"))->BooleanValue());
535  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
536 }
537 
538 
539 TEST(DeoptimizeLoadICStoreIC) {
540  i::FLAG_concurrent_recompilation = false;
541  LocalContext env;
542  v8::HandleScope scope(env->GetIsolate());
543 
544  // Functions to generate load/store/keyed load/keyed store IC calls.
545  const char* f1_source = "function f1(x) { return x.y; };";
546  const char* g1_source = "function g1(x) { x.y = 1; };";
547  const char* f2_source = "function f2(x, y) { return x[y]; };";
548  const char* g2_source = "function g2(x, y) { x[y] = 1; };";
549 
550  {
552  // Compile functions and collect to type feedback to insert ic
553  // calls in the optimized code.
554  i::FLAG_prepare_always_opt = true;
555  CompileRun("var count = 0;"
556  "var result = 0;"
557  "var deopt = false;"
558  "function X() { };"
559  "X.prototype.__defineGetter__('y', function () {"
560  " if (deopt) { count++; %DeoptimizeFunction(f1); };"
561  " return 13;"
562  "});"
563  "X.prototype.__defineSetter__('y', function () {"
564  " if (deopt) { count++; %DeoptimizeFunction(g1); };"
565  "});"
566  "X.prototype.__defineGetter__('z', function () {"
567  " if (deopt) { count++; %DeoptimizeFunction(f2); };"
568  " return 13;"
569  "});"
570  "X.prototype.__defineSetter__('z', function () {"
571  " if (deopt) { count++; %DeoptimizeFunction(g2); };"
572  "});");
573  CompileRun(f1_source);
574  CompileRun(g1_source);
575  CompileRun(f2_source);
576  CompileRun(g2_source);
577  CompileRun("for (var i = 0; i < 5; i++) {"
578  " f1(new X());"
579  " g1(new X());"
580  " f2(new X(), 'z');"
581  " g2(new X(), 'z');"
582  "};");
583 
584  // Compile an optimized version of the functions.
585  i::FLAG_always_opt = true;
586  CompileRun(f1_source);
587  CompileRun(g1_source);
588  CompileRun(f2_source);
589  CompileRun(g2_source);
590  CompileRun("f1(new X());");
591  CompileRun("g1(new X());");
592  CompileRun("f2(new X(), 'z');");
593  CompileRun("g2(new X(), 'z');");
594  if (CcTest::i_isolate()->use_crankshaft()) {
595  CHECK(GetJSFunction(env->Global(), "f1")->IsOptimized());
596  CHECK(GetJSFunction(env->Global(), "g1")->IsOptimized());
597  CHECK(GetJSFunction(env->Global(), "f2")->IsOptimized());
598  CHECK(GetJSFunction(env->Global(), "g2")->IsOptimized());
599  }
600 
601  // Call functions and force deoptimization while processing the ics.
602  CompileRun("deopt = true;"
603  "var result = f1(new X());"
604  "g1(new X());"
605  "f2(new X(), 'z');"
606  "g2(new X(), 'z');");
607  }
608  NonIncrementalGC();
609 
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  CHECK_EQ(4, env->Global()->Get(v8_str("count"))->Int32Value());
615  CHECK_EQ(13, env->Global()->Get(v8_str("result"))->Int32Value());
616 }
617 
618 
619 TEST(DeoptimizeLoadICStoreICNested) {
620  i::FLAG_concurrent_recompilation = false;
621  LocalContext env;
622  v8::HandleScope scope(env->GetIsolate());
623 
624  // Functions to generate load/store/keyed load/keyed store IC calls.
625  const char* f1_source = "function f1(x) { return x.y; };";
626  const char* g1_source = "function g1(x) { x.y = 1; };";
627  const char* f2_source = "function f2(x, y) { return x[y]; };";
628  const char* g2_source = "function g2(x, y) { x[y] = 1; };";
629 
630  {
632  // Compile functions and collect to type feedback to insert ic
633  // calls in the optimized code.
634  i::FLAG_prepare_always_opt = true;
635  CompileRun("var count = 0;"
636  "var result = 0;"
637  "var deopt = false;"
638  "function X() { };"
639  "X.prototype.__defineGetter__('y', function () {"
640  " g1(this);"
641  " return 13;"
642  "});"
643  "X.prototype.__defineSetter__('y', function () {"
644  " f2(this, 'z');"
645  "});"
646  "X.prototype.__defineGetter__('z', function () {"
647  " g2(this, 'z');"
648  "});"
649  "X.prototype.__defineSetter__('z', function () {"
650  " if (deopt) {"
651  " count++;"
652  " %DeoptimizeFunction(f1);"
653  " %DeoptimizeFunction(g1);"
654  " %DeoptimizeFunction(f2);"
655  " %DeoptimizeFunction(g2); };"
656  "});");
657  CompileRun(f1_source);
658  CompileRun(g1_source);
659  CompileRun(f2_source);
660  CompileRun(g2_source);
661  CompileRun("for (var i = 0; i < 5; i++) {"
662  " f1(new X());"
663  " g1(new X());"
664  " f2(new X(), 'z');"
665  " g2(new X(), 'z');"
666  "};");
667 
668  // Compile an optimized version of the functions.
669  i::FLAG_always_opt = true;
670  CompileRun(f1_source);
671  CompileRun(g1_source);
672  CompileRun(f2_source);
673  CompileRun(g2_source);
674  CompileRun("f1(new X());");
675  CompileRun("g1(new X());");
676  CompileRun("f2(new X(), 'z');");
677  CompileRun("g2(new X(), 'z');");
678  if (CcTest::i_isolate()->use_crankshaft()) {
679  CHECK(GetJSFunction(env->Global(), "f1")->IsOptimized());
680  CHECK(GetJSFunction(env->Global(), "g1")->IsOptimized());
681  CHECK(GetJSFunction(env->Global(), "f2")->IsOptimized());
682  CHECK(GetJSFunction(env->Global(), "g2")->IsOptimized());
683  }
684 
685  // Call functions and force deoptimization while processing the ics.
686  CompileRun("deopt = true;"
687  "var result = f1(new X());");
688  }
689  NonIncrementalGC();
690 
691  CHECK(!GetJSFunction(env->Global(), "f1")->IsOptimized());
692  CHECK(!GetJSFunction(env->Global(), "g1")->IsOptimized());
693  CHECK(!GetJSFunction(env->Global(), "f2")->IsOptimized());
694  CHECK(!GetJSFunction(env->Global(), "g2")->IsOptimized());
695  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
696  CHECK_EQ(13, env->Global()->Get(v8_str("result"))->Int32Value());
697 }
#define CHECK_EQ(expected, value)
Definition: checks.h:252
void CollectAllGarbage(int flags, const char *gc_reason=NULL, const GCCallbackFlags gc_callback_flags=kNoGCCallbackFlags)
Definition: heap.cc:731
Local< Value > Get(Handle< Value > key)
Definition: api.cc:3139
kSerializedDataOffset Object
Definition: objects-inl.h:5016
static i::Heap * heap()
Definition: cctest.h:106
#define CHECK(condition)
Definition: checks.h:75
v8::Isolate * GetIsolate()
Definition: api.cc:5233
Local< Object > Global()
Definition: api.cc:5239
TEST(DeoptimizeSimple)
static i::Isolate * i_isolate()
Definition: cctest.h:102
Definition: v8.h:123
static v8::internal::Handle< To > OpenHandle(v8::Local< From > handle)
Definition: api.h:308
static V8_INLINE Local< T > Cast(Local< S > that)
Definition: v8.h:372
static const int kAbortIncrementalMarkingMask
Definition: heap.h:1260
V8_INLINE bool IsEmpty() const
Definition: v8.h:248
HeapObject * obj
Definition: v8.h:124
static v8::Isolate * isolate()
Definition: cctest.h:96
static Local< String > NewFromUtf8(Isolate *isolate, const char *data, NewStringType type=kNormalString, int length=-1)
Definition: api.cc:5417