v8  3.11.10(node0.8.26)
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() {
103  HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
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  v8::HandleScope scope;
117  LocalContext env;
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(Isolate::Current()));
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(Isolate::Current()));
150 }
151 
152 
153 TEST(DeoptimizeSimpleWithArguments) {
154  v8::HandleScope scope;
155  LocalContext env;
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(Isolate::Current()));
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(Isolate::Current()));
189 }
190 
191 
192 TEST(DeoptimizeSimpleNested) {
193  v8::HandleScope scope;
194  LocalContext env;
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(Isolate::Current()));
213  }
214 }
215 
216 
217 TEST(DeoptimizeRecursive) {
218  v8::HandleScope scope;
219  LocalContext env;
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(Isolate::Current()));
237 
240  CHECK(!fun.IsEmpty());
241 }
242 
243 
244 TEST(DeoptimizeMultiple) {
245  v8::HandleScope scope;
246  LocalContext env;
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(Isolate::Current()));
269 }
270 
271 
272 TEST(DeoptimizeConstructor) {
273  v8::HandleScope scope;
274  LocalContext env;
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(Isolate::Current()));
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(Isolate::Current()));
307 }
308 
309 
310 TEST(DeoptimizeConstructorMultiple) {
311  v8::HandleScope scope;
312  LocalContext env;
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(Isolate::Current()));
336 }
337 
338 
339 TEST(DeoptimizeBinaryOperationADDString) {
340  v8::HandleScope scope;
341  LocalContext env;
342 
343  const char* f_source = "function f(x, y) { return x + y; };";
344 
345  {
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());");
367  GetJSFunction(env->Global(), "f")->IsOptimized());
368 
369  // Call f and force deoptimization while processing the binary operation.
370  CompileRun("deopt = true;"
371  "var result = f('a+', new X());");
372  }
373  NonIncrementalGC();
374 
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);
381  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
382 }
383 
384 
385 static 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 
396 static 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 
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());");
419  GetJSFunction((*env)->Global(), "f")->IsOptimized());
420 
421  // Call f and force deoptimization while processing the binary operation.
422  CompileRun("deopt = true;"
423  "var result = f(7, new X());");
424  NonIncrementalGC();
425  CHECK(!GetJSFunction((*env)->Global(), "f")->IsOptimized());
426 }
427 
428 
429 TEST(DeoptimizeBinaryOperationADD) {
430  v8::HandleScope scope;
431  LocalContext env;
432 
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());
437  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
438 }
439 
440 
441 TEST(DeoptimizeBinaryOperationSUB) {
442  v8::HandleScope scope;
443  LocalContext env;
444 
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());
449  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
450 }
451 
452 
453 TEST(DeoptimizeBinaryOperationMUL) {
454  v8::HandleScope scope;
455  LocalContext env;
456 
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());
461  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
462 }
463 
464 
465 TEST(DeoptimizeBinaryOperationDIV) {
466  v8::HandleScope scope;
467  LocalContext env;
468 
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());
473  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
474 }
475 
476 
477 TEST(DeoptimizeBinaryOperationMOD) {
478  v8::HandleScope scope;
479  LocalContext env;
480 
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());
485  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
486 }
487 
488 
489 TEST(DeoptimizeCompare) {
490  v8::HandleScope scope;
491  LocalContext env;
492 
493  const char* f_source = "function f(x, y) { return x < y; };";
494 
495  {
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());");
517  GetJSFunction(env->Global(), "f")->IsOptimized());
518 
519  // Call f and force deoptimization while processing the comparison.
520  CompileRun("deopt = true;"
521  "var result = f('a', new X());");
522  }
523  NonIncrementalGC();
524 
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());
528  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
529 }
530 
531 
532 TEST(DeoptimizeLoadICStoreIC) {
533  v8::HandleScope scope;
534  LocalContext env;
535 
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  {
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');"
598  "g2(new X(), 'z');");
599  }
600  NonIncrementalGC();
601 
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());
608  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
609 }
610 
611 
612 TEST(DeoptimizeLoadICStoreICNested) {
613  v8::HandleScope scope;
614  LocalContext env;
615 
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  {
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;"
679  "var result = f1(new X());");
680  }
681  NonIncrementalGC();
682 
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());
689  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
690 }
#define CHECK_EQ(expected, value)
Definition: checks.h:219
static bool UseCrankshaft()
Definition: v8.h:86
V8EXPORT Local< Value > Get(Handle< Value > key)
Definition: api.cc:2845
static V8EXPORT Local< String > New(const char *data, int length=-1)
Definition: api.cc:4655
#define CHECK(condition)
Definition: checks.h:56
Local< Object > Global()
Definition: api.cc:4467
TEST(DeoptimizeSimple)
static const int kAbortIncrementalMarkingMask
Definition: heap.h:1052
static Local< T > Cast(Local< S > that)
Definition: v8.h:281
#define HEAP
Definition: isolate.h:1408
bool IsEmpty() const
Definition: v8.h:208
Definition: v8.h:105
static v8::internal::Handle< v8::internal::TemplateInfo > OpenHandle(const Template *that)