The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / test / cctest / test-deoptimization.cc @ f230a1cf

History | View | Annotate | Download (23.9 KB)

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;
47
using ::v8::internal::Object;
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.
54
class 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.
80
class AllowNativesSyntaxNoInliningNoConcurrent {
81
 public:
82
  AllowNativesSyntaxNoInliningNoConcurrent()
83
      : allow_natives_syntax_(i::FLAG_allow_natives_syntax),
84
        use_inlining_(i::FLAG_use_inlining),
85
        concurrent_recompilation_(i::FLAG_concurrent_recompilation) {
86
    i::FLAG_allow_natives_syntax = true;
87
    i::FLAG_use_inlining = false;
88
    i::FLAG_concurrent_recompilation = false;
89
  }
90

    
91
  ~AllowNativesSyntaxNoInliningNoConcurrent() {
92
    i::FLAG_allow_natives_syntax = allow_natives_syntax_;
93
    i::FLAG_use_inlining = use_inlining_;
94
    i::FLAG_concurrent_recompilation = concurrent_recompilation_;
95
  }
96

    
97
 private:
98
  bool allow_natives_syntax_;
99
  bool use_inlining_;
100
  bool concurrent_recompilation_;
101
};
102

    
103

    
104
// Abort any ongoing incremental marking to make sure that all weak global
105
// handle callbacks are processed.
106
static void NonIncrementalGC() {
107
  CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
108
}
109

    
110

    
111
static Handle<JSFunction> GetJSFunction(v8::Handle<v8::Object> obj,
112
                                        const char* property_name) {
113
  v8::Local<v8::Function> fun =
114
      v8::Local<v8::Function>::Cast(obj->Get(v8_str(property_name)));
115
  return v8::Utils::OpenHandle(*fun);
116
}
117

    
118

    
119
TEST(DeoptimizeSimple) {
120
  LocalContext env;
121
  v8::HandleScope scope(env->GetIsolate());
122

    
123
  // Test lazy deoptimization of a simple function.
124
  {
125
    AlwaysOptimizeAllowNativesSyntaxNoInlining options;
126
    CompileRun(
127
        "var count = 0;"
128
        "function h() { %DeoptimizeFunction(f); }"
129
        "function g() { count++; h(); }"
130
        "function f() { g(); };"
131
        "f();");
132
  }
133
  NonIncrementalGC();
134

    
135
  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
136
  CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
137
  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
138

    
139
  // Test lazy deoptimization of a simple function. Call the function after the
140
  // deoptimization while it is still activated further down the stack.
141
  {
142
    AlwaysOptimizeAllowNativesSyntaxNoInlining options;
143
    CompileRun(
144
        "var count = 0;"
145
        "function g() { count++; %DeoptimizeFunction(f); f(false); }"
146
        "function f(x) { if (x) { g(); } else { return } };"
147
        "f(true);");
148
  }
149
  NonIncrementalGC();
150

    
151
  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
152
  CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
153
  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
154
}
155

    
156

    
157
TEST(DeoptimizeSimpleWithArguments) {
158
  LocalContext env;
159
  v8::HandleScope scope(env->GetIsolate());
160

    
161
  // Test lazy deoptimization of a simple function with some arguments.
162
  {
163
    AlwaysOptimizeAllowNativesSyntaxNoInlining options;
164
    CompileRun(
165
        "var count = 0;"
166
        "function h(x) { %DeoptimizeFunction(f); }"
167
        "function g(x, y) { count++; h(x); }"
168
        "function f(x, y, z) { g(1,x); y+z; };"
169
        "f(1, \"2\", false);");
170
  }
171
  NonIncrementalGC();
172

    
173
  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
174
  CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
175
  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
176

    
177
  // Test lazy deoptimization of a simple function with some arguments. Call the
178
  // function after the deoptimization while it is still activated further down
179
  // the stack.
180
  {
181
    AlwaysOptimizeAllowNativesSyntaxNoInlining options;
182
    CompileRun(
183
        "var count = 0;"
184
        "function g(x, y) { count++; %DeoptimizeFunction(f); f(false, 1, y); }"
185
        "function f(x, y, z) { if (x) { g(x, y); } else { return y + z; } };"
186
        "f(true, 1, \"2\");");
187
  }
188
  NonIncrementalGC();
189

    
190
  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
191
  CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
192
  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
193
}
194

    
195

    
196
TEST(DeoptimizeSimpleNested) {
197
  LocalContext env;
198
  v8::HandleScope scope(env->GetIsolate());
199

    
200
  // Test lazy deoptimization of a simple function. Have a nested function call
201
  // do the deoptimization.
202
  {
203
    AlwaysOptimizeAllowNativesSyntaxNoInlining options;
204
    CompileRun(
205
        "var count = 0;"
206
        "var result = 0;"
207
        "function h(x, y, z) { return x + y + z; }"
208
        "function g(z) { count++; %DeoptimizeFunction(f); return z;}"
209
        "function f(x,y,z) { return h(x, y, g(z)); };"
210
        "result = f(1, 2, 3);");
211
    NonIncrementalGC();
212

    
213
    CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
214
    CHECK_EQ(6, env->Global()->Get(v8_str("result"))->Int32Value());
215
    CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
216
    CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
217
  }
218
}
219

    
220

    
221
TEST(DeoptimizeRecursive) {
222
  LocalContext env;
223
  v8::HandleScope scope(env->GetIsolate());
224

    
225
  {
226
    // Test lazy deoptimization of a simple function called recursively. Call
227
    // the function recursively a number of times before deoptimizing it.
228
    AlwaysOptimizeAllowNativesSyntaxNoInlining options;
229
    CompileRun(
230
        "var count = 0;"
231
        "var calls = 0;"
232
        "function g() { count++; %DeoptimizeFunction(f); }"
233
        "function f(x) { calls++; if (x > 0) { f(x - 1); } else { g(); } };"
234
        "f(10);");
235
  }
236
  NonIncrementalGC();
237

    
238
  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
239
  CHECK_EQ(11, env->Global()->Get(v8_str("calls"))->Int32Value());
240
  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
241

    
242
  v8::Local<v8::Function> fun =
243
      v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
244
  CHECK(!fun.IsEmpty());
245
}
246

    
247

    
248
TEST(DeoptimizeMultiple) {
249
  LocalContext env;
250
  v8::HandleScope scope(env->GetIsolate());
251

    
252
  {
253
    AlwaysOptimizeAllowNativesSyntaxNoInlining options;
254
    CompileRun(
255
        "var count = 0;"
256
        "var result = 0;"
257
        "function g() { count++;"
258
        "               %DeoptimizeFunction(f1);"
259
        "               %DeoptimizeFunction(f2);"
260
        "               %DeoptimizeFunction(f3);"
261
        "               %DeoptimizeFunction(f4);}"
262
        "function f4(x) { g(); };"
263
        "function f3(x, y, z) { f4(); return x + y + z; };"
264
        "function f2(x, y) { return x + f3(y + 1, y + 1, y + 1) + y; };"
265
        "function f1(x) { return f2(x + 1, x + 1) + x; };"
266
        "result = f1(1);");
267
  }
268
  NonIncrementalGC();
269

    
270
  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
271
  CHECK_EQ(14, env->Global()->Get(v8_str("result"))->Int32Value());
272
  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
273
}
274

    
275

    
276
TEST(DeoptimizeConstructor) {
277
  LocalContext env;
278
  v8::HandleScope scope(env->GetIsolate());
279

    
280
  {
281
    AlwaysOptimizeAllowNativesSyntaxNoInlining options;
282
    CompileRun(
283
        "var count = 0;"
284
        "function g() { count++;"
285
        "               %DeoptimizeFunction(f); }"
286
        "function f() {  g(); };"
287
        "result = new f() instanceof f;");
288
  }
289
  NonIncrementalGC();
290

    
291
  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
292
  CHECK(env->Global()->Get(v8_str("result"))->IsTrue());
293
  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
294

    
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);"
304
        "result = result.x + result.y;");
305
  }
306
  NonIncrementalGC();
307

    
308
  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
309
  CHECK_EQ(3, env->Global()->Get(v8_str("result"))->Int32Value());
310
  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
311
}
312

    
313

    
314
TEST(DeoptimizeConstructorMultiple) {
315
  LocalContext env;
316
  v8::HandleScope scope(env->GetIsolate());
317

    
318
  {
319
    AlwaysOptimizeAllowNativesSyntaxNoInlining options;
320
    CompileRun(
321
        "var count = 0;"
322
        "var result = 0;"
323
        "function g() { count++;"
324
        "               %DeoptimizeFunction(f1);"
325
        "               %DeoptimizeFunction(f2);"
326
        "               %DeoptimizeFunction(f3);"
327
        "               %DeoptimizeFunction(f4);}"
328
        "function f4(x) { this.result = x; g(); };"
329
        "function f3(x, y, z) { this.result = new f4(x + y + z).result; };"
330
        "function f2(x, y) {"
331
        "    this.result = x + new f3(y + 1, y + 1, y + 1).result + y; };"
332
        "function f1(x) { this.result = new f2(x + 1, x + 1).result + x; };"
333
        "result = new f1(1).result;");
334
  }
335
  NonIncrementalGC();
336

    
337
  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
338
  CHECK_EQ(14, env->Global()->Get(v8_str("result"))->Int32Value());
339
  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
340
}
341

    
342

    
343
TEST(DeoptimizeBinaryOperationADDString) {
344
  LocalContext env;
345
  v8::HandleScope scope(env->GetIsolate());
346

    
347
  const char* f_source = "function f(x, y) { return x + y; };";
348

    
349
  {
350
    AllowNativesSyntaxNoInliningNoConcurrent options;
351
    // Compile function f and collect to type feedback to insert binary op stub
352
    // call in the optimized code.
353
    i::FLAG_prepare_always_opt = true;
354
    CompileRun("var count = 0;"
355
               "var result = 0;"
356
               "var deopt = false;"
357
               "function X() { };"
358
               "X.prototype.toString = function () {"
359
               "  if (deopt) { count++; %DeoptimizeFunction(f); } return 'an X'"
360
               "};");
361
    CompileRun(f_source);
362
    CompileRun("for (var i = 0; i < 5; i++) {"
363
               "  f('a+', new X());"
364
               "};");
365

    
366
    // Compile an optimized version of f.
367
    i::FLAG_always_opt = true;
368
    CompileRun(f_source);
369
    CompileRun("f('a+', new X());");
370
    CHECK(!CcTest::i_isolate()->use_crankshaft() ||
371
          GetJSFunction(env->Global(), "f")->IsOptimized());
372

    
373
    // Call f and force deoptimization while processing the binary operation.
374
    CompileRun("deopt = true;"
375
               "var result = f('a+', new X());");
376
  }
377
  NonIncrementalGC();
378

    
379
  CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
380
  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
381
  v8::Handle<v8::Value> result = env->Global()->Get(v8_str("result"));
382
  CHECK(result->IsString());
383
  v8::String::Utf8Value utf8(result);
384
  CHECK_EQ("a+an X", *utf8);
385
  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
386
}
387

    
388

    
389
static void CompileConstructorWithDeoptimizingValueOf() {
390
  CompileRun("var count = 0;"
391
             "var result = 0;"
392
             "var deopt = false;"
393
             "function X() { };"
394
             "X.prototype.valueOf = function () {"
395
             "  if (deopt) { count++; %DeoptimizeFunction(f); } return 8"
396
             "};");
397
}
398

    
399

    
400
static void TestDeoptimizeBinaryOpHelper(LocalContext* env,
401
                                         const char* binary_op) {
402
  EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> f_source_buffer;
403
  OS::SNPrintF(f_source_buffer,
404
               "function f(x, y) { return x %s y; };",
405
               binary_op);
406
  char* f_source = f_source_buffer.start();
407

    
408
  AllowNativesSyntaxNoInliningNoConcurrent options;
409
  // Compile function f and collect to type feedback to insert binary op stub
410
  // call in the optimized code.
411
  i::FLAG_prepare_always_opt = true;
412
  CompileConstructorWithDeoptimizingValueOf();
413
  CompileRun(f_source);
414
  CompileRun("for (var i = 0; i < 5; i++) {"
415
             "  f(8, new X());"
416
             "};");
417

    
418
  // Compile an optimized version of f.
419
  i::FLAG_always_opt = true;
420
  CompileRun(f_source);
421
  CompileRun("f(7, new X());");
422
  CHECK(!CcTest::i_isolate()->use_crankshaft() ||
423
        GetJSFunction((*env)->Global(), "f")->IsOptimized());
424

    
425
  // Call f and force deoptimization while processing the binary operation.
426
  CompileRun("deopt = true;"
427
             "var result = f(7, new X());");
428
  NonIncrementalGC();
429
  CHECK(!GetJSFunction((*env)->Global(), "f")->IsOptimized());
430
}
431

    
432

    
433
TEST(DeoptimizeBinaryOperationADD) {
434
  LocalContext env;
435
  v8::HandleScope scope(env->GetIsolate());
436

    
437
  TestDeoptimizeBinaryOpHelper(&env, "+");
438

    
439
  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
440
  CHECK_EQ(15, env->Global()->Get(v8_str("result"))->Int32Value());
441
  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
442
}
443

    
444

    
445
TEST(DeoptimizeBinaryOperationSUB) {
446
  LocalContext env;
447
  v8::HandleScope scope(env->GetIsolate());
448

    
449
  TestDeoptimizeBinaryOpHelper(&env, "-");
450

    
451
  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
452
  CHECK_EQ(-1, env->Global()->Get(v8_str("result"))->Int32Value());
453
  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
454
}
455

    
456

    
457
TEST(DeoptimizeBinaryOperationMUL) {
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
  LocalContext env;
471
  v8::HandleScope scope(env->GetIsolate());
472

    
473
  TestDeoptimizeBinaryOpHelper(&env, "/");
474

    
475
  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
476
  CHECK_EQ(0, env->Global()->Get(v8_str("result"))->Int32Value());
477
  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
478
}
479

    
480

    
481
TEST(DeoptimizeBinaryOperationMOD) {
482
  LocalContext env;
483
  v8::HandleScope scope(env->GetIsolate());
484

    
485
  TestDeoptimizeBinaryOpHelper(&env, "%");
486

    
487
  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
488
  CHECK_EQ(7, env->Global()->Get(v8_str("result"))->Int32Value());
489
  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
490
}
491

    
492

    
493
TEST(DeoptimizeCompare) {
494
  LocalContext env;
495
  v8::HandleScope scope(env->GetIsolate());
496

    
497
  const char* f_source = "function f(x, y) { return x < y; };";
498

    
499
  {
500
    AllowNativesSyntaxNoInliningNoConcurrent options;
501
    // Compile function f and collect to type feedback to insert compare ic
502
    // call in the optimized code.
503
    i::FLAG_prepare_always_opt = true;
504
    CompileRun("var count = 0;"
505
               "var result = 0;"
506
               "var deopt = false;"
507
               "function X() { };"
508
               "X.prototype.toString = function () {"
509
               "  if (deopt) { count++; %DeoptimizeFunction(f); } return 'b'"
510
               "};");
511
    CompileRun(f_source);
512
    CompileRun("for (var i = 0; i < 5; i++) {"
513
               "  f('a', new X());"
514
               "};");
515

    
516
    // Compile an optimized version of f.
517
    i::FLAG_always_opt = true;
518
    CompileRun(f_source);
519
    CompileRun("f('a', new X());");
520
    CHECK(!CcTest::i_isolate()->use_crankshaft() ||
521
          GetJSFunction(env->Global(), "f")->IsOptimized());
522

    
523
    // Call f and force deoptimization while processing the comparison.
524
    CompileRun("deopt = true;"
525
               "var result = f('a', new X());");
526
  }
527
  NonIncrementalGC();
528

    
529
  CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
530
  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
531
  CHECK_EQ(true, env->Global()->Get(v8_str("result"))->BooleanValue());
532
  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
533
}
534

    
535

    
536
TEST(DeoptimizeLoadICStoreIC) {
537
  LocalContext env;
538
  v8::HandleScope scope(env->GetIsolate());
539

    
540
  // Functions to generate load/store/keyed load/keyed store IC calls.
541
  const char* f1_source = "function f1(x) { return x.y; };";
542
  const char* g1_source = "function g1(x) { x.y = 1; };";
543
  const char* f2_source = "function f2(x, y) { return x[y]; };";
544
  const char* g2_source = "function g2(x, y) { x[y] = 1; };";
545

    
546
  {
547
    AllowNativesSyntaxNoInliningNoConcurrent options;
548
    // Compile functions and collect to type feedback to insert ic
549
    // calls in the optimized code.
550
    i::FLAG_prepare_always_opt = true;
551
    CompileRun("var count = 0;"
552
               "var result = 0;"
553
               "var deopt = false;"
554
               "function X() { };"
555
               "X.prototype.__defineGetter__('y', function () {"
556
               "  if (deopt) { count++; %DeoptimizeFunction(f1); };"
557
               "  return 13;"
558
               "});"
559
               "X.prototype.__defineSetter__('y', function () {"
560
               "  if (deopt) { count++; %DeoptimizeFunction(g1); };"
561
               "});"
562
               "X.prototype.__defineGetter__('z', function () {"
563
               "  if (deopt) { count++; %DeoptimizeFunction(f2); };"
564
               "  return 13;"
565
               "});"
566
               "X.prototype.__defineSetter__('z', function () {"
567
               "  if (deopt) { count++; %DeoptimizeFunction(g2); };"
568
               "});");
569
    CompileRun(f1_source);
570
    CompileRun(g1_source);
571
    CompileRun(f2_source);
572
    CompileRun(g2_source);
573
    CompileRun("for (var i = 0; i < 5; i++) {"
574
               "  f1(new X());"
575
               "  g1(new X());"
576
               "  f2(new X(), 'z');"
577
               "  g2(new X(), 'z');"
578
               "};");
579

    
580
    // Compile an optimized version of the functions.
581
    i::FLAG_always_opt = true;
582
    CompileRun(f1_source);
583
    CompileRun(g1_source);
584
    CompileRun(f2_source);
585
    CompileRun(g2_source);
586
    CompileRun("f1(new X());");
587
    CompileRun("g1(new X());");
588
    CompileRun("f2(new X(), 'z');");
589
    CompileRun("g2(new X(), 'z');");
590
    if (CcTest::i_isolate()->use_crankshaft()) {
591
      CHECK(GetJSFunction(env->Global(), "f1")->IsOptimized());
592
      CHECK(GetJSFunction(env->Global(), "g1")->IsOptimized());
593
      CHECK(GetJSFunction(env->Global(), "f2")->IsOptimized());
594
      CHECK(GetJSFunction(env->Global(), "g2")->IsOptimized());
595
    }
596

    
597
    // Call functions and force deoptimization while processing the ics.
598
    CompileRun("deopt = true;"
599
               "var result = f1(new X());"
600
               "g1(new X());"
601
               "f2(new X(), 'z');"
602
               "g2(new X(), 'z');");
603
  }
604
  NonIncrementalGC();
605

    
606
  CHECK(!GetJSFunction(env->Global(), "f1")->IsOptimized());
607
  CHECK(!GetJSFunction(env->Global(), "g1")->IsOptimized());
608
  CHECK(!GetJSFunction(env->Global(), "f2")->IsOptimized());
609
  CHECK(!GetJSFunction(env->Global(), "g2")->IsOptimized());
610
  CHECK_EQ(4, env->Global()->Get(v8_str("count"))->Int32Value());
611
  CHECK_EQ(13, env->Global()->Get(v8_str("result"))->Int32Value());
612
  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
613
}
614

    
615

    
616
TEST(DeoptimizeLoadICStoreICNested) {
617
  LocalContext env;
618
  v8::HandleScope scope(env->GetIsolate());
619

    
620
  // Functions to generate load/store/keyed load/keyed store IC calls.
621
  const char* f1_source = "function f1(x) { return x.y; };";
622
  const char* g1_source = "function g1(x) { x.y = 1; };";
623
  const char* f2_source = "function f2(x, y) { return x[y]; };";
624
  const char* g2_source = "function g2(x, y) { x[y] = 1; };";
625

    
626
  {
627
    AllowNativesSyntaxNoInliningNoConcurrent options;
628
    // Compile functions and collect to type feedback to insert ic
629
    // calls in the optimized code.
630
    i::FLAG_prepare_always_opt = true;
631
    CompileRun("var count = 0;"
632
               "var result = 0;"
633
               "var deopt = false;"
634
               "function X() { };"
635
               "X.prototype.__defineGetter__('y', function () {"
636
               "  g1(this);"
637
               "  return 13;"
638
               "});"
639
               "X.prototype.__defineSetter__('y', function () {"
640
               "  f2(this, 'z');"
641
               "});"
642
               "X.prototype.__defineGetter__('z', function () {"
643
               "  g2(this, 'z');"
644
               "});"
645
               "X.prototype.__defineSetter__('z', function () {"
646
               "  if (deopt) {"
647
               "    count++;"
648
               "    %DeoptimizeFunction(f1);"
649
               "    %DeoptimizeFunction(g1);"
650
               "    %DeoptimizeFunction(f2);"
651
               "    %DeoptimizeFunction(g2); };"
652
               "});");
653
    CompileRun(f1_source);
654
    CompileRun(g1_source);
655
    CompileRun(f2_source);
656
    CompileRun(g2_source);
657
    CompileRun("for (var i = 0; i < 5; i++) {"
658
               "  f1(new X());"
659
               "  g1(new X());"
660
               "  f2(new X(), 'z');"
661
               "  g2(new X(), 'z');"
662
               "};");
663

    
664
    // Compile an optimized version of the functions.
665
    i::FLAG_always_opt = true;
666
    CompileRun(f1_source);
667
    CompileRun(g1_source);
668
    CompileRun(f2_source);
669
    CompileRun(g2_source);
670
    CompileRun("f1(new X());");
671
    CompileRun("g1(new X());");
672
    CompileRun("f2(new X(), 'z');");
673
    CompileRun("g2(new X(), 'z');");
674
    if (CcTest::i_isolate()->use_crankshaft()) {
675
      CHECK(GetJSFunction(env->Global(), "f1")->IsOptimized());
676
      CHECK(GetJSFunction(env->Global(), "g1")->IsOptimized());
677
      CHECK(GetJSFunction(env->Global(), "f2")->IsOptimized());
678
      CHECK(GetJSFunction(env->Global(), "g2")->IsOptimized());
679
    }
680

    
681
    // Call functions and force deoptimization while processing the ics.
682
    CompileRun("deopt = true;"
683
               "var result = f1(new X());");
684
  }
685
  NonIncrementalGC();
686

    
687
  CHECK(!GetJSFunction(env->Global(), "f1")->IsOptimized());
688
  CHECK(!GetJSFunction(env->Global(), "g1")->IsOptimized());
689
  CHECK(!GetJSFunction(env->Global(), "f2")->IsOptimized());
690
  CHECK(!GetJSFunction(env->Global(), "g2")->IsOptimized());
691
  CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
692
  CHECK_EQ(13, env->Global()->Get(v8_str("result"))->Int32Value());
693
  CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
694
}