| Index: test/mjsunit/regress/regress-4023.js
 | 
| diff --git a/test/mjsunit/regress/regress-4023.js b/test/mjsunit/regress/regress-4023.js
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..902741f6f5cf9f53abff965ce9dc3b87d98d549a
 | 
| --- /dev/null
 | 
| +++ b/test/mjsunit/regress/regress-4023.js
 | 
| @@ -0,0 +1,67 @@
 | 
| +// Copyright 2015 the V8 project authors. All rights reserved.
 | 
| +// Use of this source code is governed by a BSD-style license that can be
 | 
| +// found in the LICENSE file.
 | 
| +
 | 
| +// Flags: --allow-natives-syntax --expose-gc --block-concurrent-recompilation
 | 
| +
 | 
| +function Inner() {
 | 
| +  this.property = "OK";
 | 
| +  this.prop2 = 1;
 | 
| +}
 | 
| +
 | 
| +function Outer() {
 | 
| +  this.o = "u";
 | 
| +}
 | 
| +function KeepMapAlive(o) {
 | 
| +  return o.o;
 | 
| +}
 | 
| +function SetInner(o, i) {
 | 
| +  o.inner_field = i;
 | 
| +}
 | 
| +function Crash(o) {
 | 
| +  return o.inner_field.property;
 | 
| +}
 | 
| +
 | 
| +var inner = new Inner();
 | 
| +var outer = new Outer();
 | 
| +
 | 
| +// Collect type feedback.
 | 
| +SetInner(new Outer(), inner);
 | 
| +SetInner(outer, inner);
 | 
| +
 | 
| +// This function's only purpose is to stash away a Handle that keeps
 | 
| +// outer's map alive during the gc() call below. We store this handle
 | 
| +// on the compiler thread :-)
 | 
| +KeepMapAlive(outer);
 | 
| +KeepMapAlive(outer);
 | 
| +%OptimizeFunctionOnNextCall(KeepMapAlive, "concurrent");
 | 
| +KeepMapAlive(outer);
 | 
| +
 | 
| +// So far, all is well. Collect type feedback and optimize.
 | 
| +print(Crash(outer));
 | 
| +print(Crash(outer));
 | 
| +%OptimizeFunctionOnNextCall(Crash);
 | 
| +print(Crash(outer));
 | 
| +
 | 
| +// Null out references and perform GC. This will keep outer's map alive
 | 
| +// (due to the handle created above), but will let inner's map die. Hence,
 | 
| +// inner_field's field type stored in outer's map will get cleared.
 | 
| +inner = undefined;
 | 
| +outer = undefined;
 | 
| +gc();
 | 
| +
 | 
| +// We could unblock the compiler thread now. But why bother?
 | 
| +
 | 
| +// Now optimize SetInner while inner_field's type is still cleared!
 | 
| +// This will generate optimized code that stores arbitrary objects
 | 
| +// into inner_field without checking their type against the field type.
 | 
| +%OptimizeFunctionOnNextCall(SetInner);
 | 
| +
 | 
| +// Use the optimized code to store an arbitrary object into
 | 
| +// o2's inner_field, without triggering any dependent code deopts...
 | 
| +var o2 = new Outer();
 | 
| +SetInner(o2, { invalid: 1.51, property: "OK" });
 | 
| +// ...and then use the existing code expecting an Inner-class object to
 | 
| +// read invalid data (in this case, a raw double).
 | 
| +// We crash trying to convert the raw double into a printable string.
 | 
| +print(Crash(o2));
 | 
| 
 |