libv8 3.10.8.0 → 3.11.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (215) hide show
  1. data/Rakefile +10 -3
  2. data/ext/libv8/compiler.rb +46 -0
  3. data/ext/libv8/extconf.rb +5 -1
  4. data/ext/libv8/make.rb +13 -0
  5. data/lib/libv8/version.rb +1 -1
  6. data/patches/add-freebsd9-and-freebsd10-to-gyp-GetFlavor.patch +11 -0
  7. data/patches/src_platform-freebsd.cc.patch +10 -0
  8. data/vendor/v8/ChangeLog +124 -0
  9. data/vendor/v8/DEPS +27 -0
  10. data/vendor/v8/Makefile +7 -0
  11. data/vendor/v8/SConstruct +15 -2
  12. data/vendor/v8/build/common.gypi +129 -157
  13. data/vendor/v8/build/gyp_v8 +11 -25
  14. data/vendor/v8/build/standalone.gypi +9 -3
  15. data/vendor/v8/include/v8.h +5 -3
  16. data/vendor/v8/src/SConscript +1 -0
  17. data/vendor/v8/src/api.cc +4 -33
  18. data/vendor/v8/src/api.h +2 -2
  19. data/vendor/v8/src/arm/builtins-arm.cc +5 -4
  20. data/vendor/v8/src/arm/code-stubs-arm.cc +21 -14
  21. data/vendor/v8/src/arm/codegen-arm.cc +2 -2
  22. data/vendor/v8/src/arm/debug-arm.cc +3 -1
  23. data/vendor/v8/src/arm/full-codegen-arm.cc +3 -102
  24. data/vendor/v8/src/arm/ic-arm.cc +30 -33
  25. data/vendor/v8/src/arm/lithium-arm.cc +20 -7
  26. data/vendor/v8/src/arm/lithium-arm.h +10 -4
  27. data/vendor/v8/src/arm/lithium-codegen-arm.cc +106 -60
  28. data/vendor/v8/src/arm/macro-assembler-arm.cc +49 -39
  29. data/vendor/v8/src/arm/macro-assembler-arm.h +5 -4
  30. data/vendor/v8/src/arm/regexp-macro-assembler-arm.cc +115 -55
  31. data/vendor/v8/src/arm/regexp-macro-assembler-arm.h +7 -6
  32. data/vendor/v8/src/arm/simulator-arm.h +6 -6
  33. data/vendor/v8/src/arm/stub-cache-arm.cc +64 -19
  34. data/vendor/v8/src/array.js +7 -3
  35. data/vendor/v8/src/ast.cc +11 -6
  36. data/vendor/v8/src/bootstrapper.cc +9 -11
  37. data/vendor/v8/src/builtins.cc +61 -31
  38. data/vendor/v8/src/code-stubs.cc +23 -9
  39. data/vendor/v8/src/code-stubs.h +1 -0
  40. data/vendor/v8/src/codegen.h +3 -3
  41. data/vendor/v8/src/compiler.cc +1 -1
  42. data/vendor/v8/src/contexts.h +2 -18
  43. data/vendor/v8/src/d8.cc +94 -93
  44. data/vendor/v8/src/d8.h +1 -1
  45. data/vendor/v8/src/debug-agent.cc +3 -3
  46. data/vendor/v8/src/debug.cc +41 -1
  47. data/vendor/v8/src/debug.h +50 -0
  48. data/vendor/v8/src/elements-kind.cc +134 -0
  49. data/vendor/v8/src/elements-kind.h +210 -0
  50. data/vendor/v8/src/elements.cc +356 -190
  51. data/vendor/v8/src/elements.h +36 -28
  52. data/vendor/v8/src/factory.cc +44 -4
  53. data/vendor/v8/src/factory.h +11 -7
  54. data/vendor/v8/src/flag-definitions.h +3 -0
  55. data/vendor/v8/src/frames.h +3 -0
  56. data/vendor/v8/src/full-codegen.cc +2 -1
  57. data/vendor/v8/src/func-name-inferrer.h +2 -0
  58. data/vendor/v8/src/globals.h +3 -0
  59. data/vendor/v8/src/heap-inl.h +16 -4
  60. data/vendor/v8/src/heap.cc +38 -32
  61. data/vendor/v8/src/heap.h +3 -17
  62. data/vendor/v8/src/hydrogen-instructions.cc +28 -5
  63. data/vendor/v8/src/hydrogen-instructions.h +142 -44
  64. data/vendor/v8/src/hydrogen.cc +160 -55
  65. data/vendor/v8/src/hydrogen.h +2 -0
  66. data/vendor/v8/src/ia32/assembler-ia32.h +3 -0
  67. data/vendor/v8/src/ia32/builtins-ia32.cc +5 -4
  68. data/vendor/v8/src/ia32/code-stubs-ia32.cc +22 -16
  69. data/vendor/v8/src/ia32/codegen-ia32.cc +2 -2
  70. data/vendor/v8/src/ia32/debug-ia32.cc +29 -2
  71. data/vendor/v8/src/ia32/full-codegen-ia32.cc +8 -101
  72. data/vendor/v8/src/ia32/ic-ia32.cc +23 -19
  73. data/vendor/v8/src/ia32/lithium-codegen-ia32.cc +126 -80
  74. data/vendor/v8/src/ia32/lithium-codegen-ia32.h +2 -1
  75. data/vendor/v8/src/ia32/lithium-ia32.cc +15 -9
  76. data/vendor/v8/src/ia32/lithium-ia32.h +14 -6
  77. data/vendor/v8/src/ia32/macro-assembler-ia32.cc +50 -40
  78. data/vendor/v8/src/ia32/macro-assembler-ia32.h +5 -4
  79. data/vendor/v8/src/ia32/regexp-macro-assembler-ia32.cc +113 -43
  80. data/vendor/v8/src/ia32/regexp-macro-assembler-ia32.h +9 -4
  81. data/vendor/v8/src/ia32/simulator-ia32.h +4 -4
  82. data/vendor/v8/src/ia32/stub-cache-ia32.cc +52 -14
  83. data/vendor/v8/src/ic.cc +77 -20
  84. data/vendor/v8/src/ic.h +18 -2
  85. data/vendor/v8/src/incremental-marking-inl.h +21 -5
  86. data/vendor/v8/src/incremental-marking.cc +35 -8
  87. data/vendor/v8/src/incremental-marking.h +12 -3
  88. data/vendor/v8/src/isolate.cc +12 -2
  89. data/vendor/v8/src/isolate.h +1 -1
  90. data/vendor/v8/src/jsregexp.cc +66 -26
  91. data/vendor/v8/src/jsregexp.h +60 -31
  92. data/vendor/v8/src/list-inl.h +8 -0
  93. data/vendor/v8/src/list.h +3 -0
  94. data/vendor/v8/src/lithium.cc +5 -2
  95. data/vendor/v8/src/liveedit.cc +57 -5
  96. data/vendor/v8/src/mark-compact-inl.h +17 -11
  97. data/vendor/v8/src/mark-compact.cc +100 -143
  98. data/vendor/v8/src/mark-compact.h +44 -20
  99. data/vendor/v8/src/messages.js +131 -99
  100. data/vendor/v8/src/mips/builtins-mips.cc +5 -4
  101. data/vendor/v8/src/mips/code-stubs-mips.cc +23 -15
  102. data/vendor/v8/src/mips/codegen-mips.cc +2 -2
  103. data/vendor/v8/src/mips/debug-mips.cc +3 -1
  104. data/vendor/v8/src/mips/full-codegen-mips.cc +4 -102
  105. data/vendor/v8/src/mips/ic-mips.cc +34 -36
  106. data/vendor/v8/src/mips/lithium-codegen-mips.cc +116 -68
  107. data/vendor/v8/src/mips/lithium-mips.cc +20 -7
  108. data/vendor/v8/src/mips/lithium-mips.h +11 -4
  109. data/vendor/v8/src/mips/macro-assembler-mips.cc +50 -39
  110. data/vendor/v8/src/mips/macro-assembler-mips.h +5 -4
  111. data/vendor/v8/src/mips/regexp-macro-assembler-mips.cc +110 -50
  112. data/vendor/v8/src/mips/regexp-macro-assembler-mips.h +6 -5
  113. data/vendor/v8/src/mips/simulator-mips.h +5 -5
  114. data/vendor/v8/src/mips/stub-cache-mips.cc +66 -20
  115. data/vendor/v8/src/mksnapshot.cc +5 -1
  116. data/vendor/v8/src/objects-debug.cc +103 -6
  117. data/vendor/v8/src/objects-inl.h +215 -116
  118. data/vendor/v8/src/objects-printer.cc +13 -8
  119. data/vendor/v8/src/objects.cc +608 -331
  120. data/vendor/v8/src/objects.h +129 -94
  121. data/vendor/v8/src/parser.cc +16 -4
  122. data/vendor/v8/src/platform-freebsd.cc +1 -0
  123. data/vendor/v8/src/platform-linux.cc +9 -30
  124. data/vendor/v8/src/platform-posix.cc +28 -7
  125. data/vendor/v8/src/platform-win32.cc +15 -3
  126. data/vendor/v8/src/platform.h +2 -1
  127. data/vendor/v8/src/profile-generator-inl.h +25 -2
  128. data/vendor/v8/src/profile-generator.cc +300 -822
  129. data/vendor/v8/src/profile-generator.h +97 -214
  130. data/vendor/v8/src/regexp-macro-assembler-irregexp.cc +2 -1
  131. data/vendor/v8/src/regexp-macro-assembler-irregexp.h +2 -2
  132. data/vendor/v8/src/regexp-macro-assembler-tracer.cc +6 -5
  133. data/vendor/v8/src/regexp-macro-assembler-tracer.h +1 -1
  134. data/vendor/v8/src/regexp-macro-assembler.cc +7 -3
  135. data/vendor/v8/src/regexp-macro-assembler.h +10 -2
  136. data/vendor/v8/src/regexp.js +6 -0
  137. data/vendor/v8/src/runtime.cc +265 -212
  138. data/vendor/v8/src/runtime.h +6 -5
  139. data/vendor/v8/src/scopes.cc +20 -0
  140. data/vendor/v8/src/scopes.h +6 -3
  141. data/vendor/v8/src/spaces.cc +0 -2
  142. data/vendor/v8/src/string-stream.cc +2 -2
  143. data/vendor/v8/src/v8-counters.h +0 -2
  144. data/vendor/v8/src/v8natives.js +2 -2
  145. data/vendor/v8/src/v8utils.h +6 -3
  146. data/vendor/v8/src/version.cc +1 -1
  147. data/vendor/v8/src/x64/assembler-x64.h +2 -1
  148. data/vendor/v8/src/x64/builtins-x64.cc +5 -4
  149. data/vendor/v8/src/x64/code-stubs-x64.cc +25 -16
  150. data/vendor/v8/src/x64/codegen-x64.cc +2 -2
  151. data/vendor/v8/src/x64/debug-x64.cc +14 -1
  152. data/vendor/v8/src/x64/disasm-x64.cc +1 -1
  153. data/vendor/v8/src/x64/full-codegen-x64.cc +10 -106
  154. data/vendor/v8/src/x64/ic-x64.cc +20 -16
  155. data/vendor/v8/src/x64/lithium-codegen-x64.cc +156 -79
  156. data/vendor/v8/src/x64/lithium-codegen-x64.h +2 -1
  157. data/vendor/v8/src/x64/lithium-x64.cc +18 -8
  158. data/vendor/v8/src/x64/lithium-x64.h +7 -2
  159. data/vendor/v8/src/x64/macro-assembler-x64.cc +50 -40
  160. data/vendor/v8/src/x64/macro-assembler-x64.h +5 -4
  161. data/vendor/v8/src/x64/regexp-macro-assembler-x64.cc +122 -51
  162. data/vendor/v8/src/x64/regexp-macro-assembler-x64.h +17 -8
  163. data/vendor/v8/src/x64/simulator-x64.h +4 -4
  164. data/vendor/v8/src/x64/stub-cache-x64.cc +55 -17
  165. data/vendor/v8/test/cctest/cctest.status +1 -0
  166. data/vendor/v8/test/cctest/test-api.cc +24 -0
  167. data/vendor/v8/test/cctest/test-func-name-inference.cc +38 -0
  168. data/vendor/v8/test/cctest/test-heap-profiler.cc +21 -77
  169. data/vendor/v8/test/cctest/test-heap.cc +164 -3
  170. data/vendor/v8/test/cctest/test-list.cc +12 -0
  171. data/vendor/v8/test/cctest/test-mark-compact.cc +5 -5
  172. data/vendor/v8/test/cctest/test-regexp.cc +14 -8
  173. data/vendor/v8/test/cctest/testcfg.py +2 -0
  174. data/vendor/v8/test/mjsunit/accessor-map-sharing.js +176 -0
  175. data/vendor/v8/test/mjsunit/array-construct-transition.js +3 -3
  176. data/vendor/v8/test/mjsunit/array-literal-transitions.js +10 -10
  177. data/vendor/v8/test/mjsunit/big-array-literal.js +3 -0
  178. data/vendor/v8/test/mjsunit/compiler/inline-construct.js +4 -2
  179. data/vendor/v8/test/mjsunit/debug-liveedit-stack-padding.js +88 -0
  180. data/vendor/v8/test/mjsunit/elements-kind.js +4 -4
  181. data/vendor/v8/test/mjsunit/elements-transition-hoisting.js +2 -2
  182. data/vendor/v8/test/mjsunit/elements-transition.js +5 -5
  183. data/vendor/v8/test/mjsunit/error-constructors.js +68 -33
  184. data/vendor/v8/test/mjsunit/harmony/proxies.js +14 -6
  185. data/vendor/v8/test/mjsunit/mjsunit.status +1 -0
  186. data/vendor/v8/test/mjsunit/packed-elements.js +112 -0
  187. data/vendor/v8/test/mjsunit/regexp-capture-3.js +6 -0
  188. data/vendor/v8/test/mjsunit/regexp-global.js +132 -0
  189. data/vendor/v8/test/mjsunit/regexp.js +11 -0
  190. data/vendor/v8/test/mjsunit/regress/regress-117409.js +52 -0
  191. data/vendor/v8/test/mjsunit/regress/regress-126412.js +33 -0
  192. data/vendor/v8/test/mjsunit/regress/regress-128018.js +35 -0
  193. data/vendor/v8/test/mjsunit/regress/regress-128146.js +33 -0
  194. data/vendor/v8/test/mjsunit/regress/regress-1639-2.js +4 -1
  195. data/vendor/v8/test/mjsunit/regress/regress-1639.js +14 -8
  196. data/vendor/v8/test/mjsunit/regress/regress-1849.js +3 -3
  197. data/vendor/v8/test/mjsunit/regress/regress-1878.js +2 -2
  198. data/vendor/v8/test/mjsunit/regress/regress-2071.js +79 -0
  199. data/vendor/v8/test/mjsunit/regress/regress-2153.js +32 -0
  200. data/vendor/v8/test/mjsunit/regress/regress-crbug-122271.js +4 -4
  201. data/vendor/v8/test/mjsunit/regress/regress-crbug-126414.js +32 -0
  202. data/vendor/v8/test/mjsunit/regress/regress-smi-only-concat.js +2 -2
  203. data/vendor/v8/test/mjsunit/regress/regress-transcendental.js +49 -0
  204. data/vendor/v8/test/mjsunit/stack-traces.js +14 -0
  205. data/vendor/v8/test/mjsunit/unbox-double-arrays.js +4 -3
  206. data/vendor/v8/test/test262/testcfg.py +6 -1
  207. data/vendor/v8/tools/check-static-initializers.sh +11 -3
  208. data/vendor/v8/tools/fuzz-harness.sh +92 -0
  209. data/vendor/v8/tools/grokdump.py +658 -67
  210. data/vendor/v8/tools/gyp/v8.gyp +21 -39
  211. data/vendor/v8/tools/js2c.py +3 -3
  212. data/vendor/v8/tools/jsmin.py +2 -2
  213. data/vendor/v8/tools/presubmit.py +2 -1
  214. data/vendor/v8/tools/test-wrapper-gypbuild.py +25 -11
  215. metadata +624 -612
@@ -318,7 +318,9 @@ void JSObject::PrintElements(FILE* out) {
318
318
  // Don't call GetElementsKind, its validation code can cause the printer to
319
319
  // fail when debugging.
320
320
  switch (map()->elements_kind()) {
321
- case FAST_SMI_ONLY_ELEMENTS:
321
+ case FAST_HOLEY_SMI_ELEMENTS:
322
+ case FAST_SMI_ELEMENTS:
323
+ case FAST_HOLEY_ELEMENTS:
322
324
  case FAST_ELEMENTS: {
323
325
  // Print in array notation for non-sparse arrays.
324
326
  FixedArray* p = FixedArray::cast(elements());
@@ -329,16 +331,19 @@ void JSObject::PrintElements(FILE* out) {
329
331
  }
330
332
  break;
331
333
  }
334
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
332
335
  case FAST_DOUBLE_ELEMENTS: {
333
336
  // Print in array notation for non-sparse arrays.
334
- FixedDoubleArray* p = FixedDoubleArray::cast(elements());
335
- for (int i = 0; i < p->length(); i++) {
336
- if (p->is_the_hole(i)) {
337
- PrintF(out, " %d: <the hole>", i);
338
- } else {
339
- PrintF(out, " %d: %g", i, p->get_scalar(i));
337
+ if (elements()->length() > 0) {
338
+ FixedDoubleArray* p = FixedDoubleArray::cast(elements());
339
+ for (int i = 0; i < p->length(); i++) {
340
+ if (p->is_the_hole(i)) {
341
+ PrintF(out, " %d: <the hole>", i);
342
+ } else {
343
+ PrintF(out, " %d: %g", i, p->get_scalar(i));
344
+ }
345
+ PrintF(out, "\n");
340
346
  }
341
- PrintF(out, "\n");
342
347
  }
343
348
  break;
344
349
  }
@@ -56,11 +56,6 @@
56
56
  namespace v8 {
57
57
  namespace internal {
58
58
 
59
- void PrintElementsKind(FILE* out, ElementsKind kind) {
60
- ElementsAccessor* accessor = ElementsAccessor::ForKind(kind);
61
- PrintF(out, "%s", accessor->name());
62
- }
63
-
64
59
 
65
60
  MUST_USE_RESULT static MaybeObject* CreateJSValue(JSFunction* constructor,
66
61
  Object* value) {
@@ -253,13 +248,14 @@ MaybeObject* JSProxy::GetElementWithHandler(Object* receiver,
253
248
  }
254
249
 
255
250
 
256
- MaybeObject* JSProxy::SetElementWithHandler(uint32_t index,
251
+ MaybeObject* JSProxy::SetElementWithHandler(JSReceiver* receiver,
252
+ uint32_t index,
257
253
  Object* value,
258
254
  StrictModeFlag strict_mode) {
259
255
  String* name;
260
256
  MaybeObject* maybe = GetHeap()->Uint32ToString(index);
261
257
  if (!maybe->To<String>(&name)) return maybe;
262
- return SetPropertyWithHandler(name, value, NONE, strict_mode);
258
+ return SetPropertyWithHandler(receiver, name, value, NONE, strict_mode);
263
259
  }
264
260
 
265
261
 
@@ -543,7 +539,7 @@ bool JSObject::IsDirty() {
543
539
  // If the object is fully fast case and has the same map it was
544
540
  // created with then no changes can have been made to it.
545
541
  return map() != fun->initial_map()
546
- || !HasFastElements()
542
+ || !HasFastObjectElements()
547
543
  || !HasFastProperties();
548
544
  }
549
545
 
@@ -1067,7 +1063,9 @@ void String::StringShortPrint(StringStream* accumulator) {
1067
1063
  void JSObject::JSObjectShortPrint(StringStream* accumulator) {
1068
1064
  switch (map()->instance_type()) {
1069
1065
  case JS_ARRAY_TYPE: {
1070
- double length = JSArray::cast(this)->length()->Number();
1066
+ double length = JSArray::cast(this)->length()->IsUndefined()
1067
+ ? 0
1068
+ : JSArray::cast(this)->length()->Number();
1071
1069
  accumulator->Add("<JS Array[%u]>", static_cast<uint32_t>(length));
1072
1070
  break;
1073
1071
  }
@@ -1604,6 +1602,7 @@ MaybeObject* JSObject::AddFastProperty(String* name,
1604
1602
  // We have now allocated all the necessary objects.
1605
1603
  // All the changes can be applied at once, so they are atomic.
1606
1604
  map()->set_instance_descriptors(old_descriptors);
1605
+ new_map->SetBackPointer(map());
1607
1606
  new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1608
1607
  set_map(new_map);
1609
1608
  return FastPropertyAtPut(index, value);
@@ -1664,6 +1663,7 @@ MaybeObject* JSObject::AddConstantFunctionProperty(
1664
1663
  }
1665
1664
  }
1666
1665
  old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1666
+ Map::cast(new_map)->SetBackPointer(old_map);
1667
1667
 
1668
1668
  return function;
1669
1669
  }
@@ -1824,6 +1824,7 @@ MaybeObject* JSObject::ConvertDescriptorToFieldAndMapTransition(
1824
1824
  }
1825
1825
  }
1826
1826
  old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1827
+ map()->SetBackPointer(old_map);
1827
1828
  return result;
1828
1829
  }
1829
1830
 
@@ -2085,7 +2086,7 @@ MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(
2085
2086
  return maybe;
2086
2087
  }
2087
2088
  return JSProxy::cast(pt)->SetPropertyWithHandlerIfDefiningSetter(
2088
- name, value, NONE, strict_mode, found);
2089
+ this, name, value, NONE, strict_mode, found);
2089
2090
  }
2090
2091
  if (!JSObject::cast(pt)->HasDictionaryElements()) {
2091
2092
  continue;
@@ -2140,7 +2141,7 @@ MaybeObject* JSObject::SetPropertyWithCallbackSetterInPrototypes(
2140
2141
  Handle<Object> hvalue(value);
2141
2142
  MaybeObject* result =
2142
2143
  accessor_result.proxy()->SetPropertyWithHandlerIfDefiningSetter(
2143
- name, value, attributes, strict_mode, &found);
2144
+ this, name, value, attributes, strict_mode, &found);
2144
2145
  if (found) return result;
2145
2146
  // The proxy does not define the property as an accessor.
2146
2147
  // Consequently, it has no effect on setting the receiver.
@@ -2199,34 +2200,29 @@ static Handle<T> MaybeNull(T* p) {
2199
2200
 
2200
2201
 
2201
2202
  Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) {
2202
- ElementsKind elms_kind = elements_kind();
2203
- if (elms_kind == FAST_DOUBLE_ELEMENTS) {
2204
- bool dummy = true;
2205
- Handle<Map> fast_map =
2206
- MaybeNull(LookupElementsTransitionMap(FAST_ELEMENTS, &dummy));
2207
- if (!fast_map.is_null() && ContainsMap(candidates, fast_map)) {
2208
- return fast_map;
2209
- }
2210
- return Handle<Map>::null();
2211
- }
2212
- if (elms_kind == FAST_SMI_ONLY_ELEMENTS) {
2213
- bool dummy = true;
2214
- Handle<Map> double_map =
2215
- MaybeNull(LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, &dummy));
2216
- // In the current implementation, if the DOUBLE map doesn't exist, the
2217
- // FAST map can't exist either.
2218
- if (double_map.is_null()) return Handle<Map>::null();
2219
- Handle<Map> fast_map =
2220
- MaybeNull(double_map->LookupElementsTransitionMap(FAST_ELEMENTS,
2221
- &dummy));
2222
- if (!fast_map.is_null() && ContainsMap(candidates, fast_map)) {
2223
- return fast_map;
2224
- }
2225
- if (ContainsMap(candidates, double_map)) return double_map;
2226
- }
2227
- return Handle<Map>::null();
2203
+ ElementsKind kind = elements_kind();
2204
+ Handle<Map> transitioned_map = Handle<Map>::null();
2205
+ Handle<Map> current_map(this);
2206
+ bool packed = IsFastPackedElementsKind(kind);
2207
+ if (IsTransitionableFastElementsKind(kind)) {
2208
+ while (CanTransitionToMoreGeneralFastElementsKind(kind, false)) {
2209
+ kind = GetNextMoreGeneralFastElementsKind(kind, false);
2210
+ bool dummy = true;
2211
+ Handle<Map> maybe_transitioned_map =
2212
+ MaybeNull(current_map->LookupElementsTransitionMap(kind, &dummy));
2213
+ if (maybe_transitioned_map.is_null()) break;
2214
+ if (ContainsMap(candidates, maybe_transitioned_map) &&
2215
+ (packed || !IsFastPackedElementsKind(kind))) {
2216
+ transitioned_map = maybe_transitioned_map;
2217
+ if (!IsFastPackedElementsKind(kind)) packed = false;
2218
+ }
2219
+ current_map = maybe_transitioned_map;
2220
+ }
2221
+ }
2222
+ return transitioned_map;
2228
2223
  }
2229
2224
 
2225
+
2230
2226
  static Map* GetElementsTransitionMapFromDescriptor(Object* descriptor_contents,
2231
2227
  ElementsKind elements_kind) {
2232
2228
  if (descriptor_contents->IsMap()) {
@@ -2335,24 +2331,36 @@ Object* Map::GetDescriptorContents(String* sentinel_name,
2335
2331
  }
2336
2332
 
2337
2333
 
2338
- Map* Map::LookupElementsTransitionMap(ElementsKind elements_kind,
2334
+ Map* Map::LookupElementsTransitionMap(ElementsKind to_kind,
2339
2335
  bool* safe_to_add_transition) {
2340
- // Special case: indirect SMI->FAST transition (cf. comment in
2341
- // AddElementsTransition()).
2342
- if (this->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
2343
- elements_kind == FAST_ELEMENTS) {
2344
- Map* double_map = this->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS,
2345
- safe_to_add_transition);
2346
- if (double_map == NULL) return double_map;
2347
- return double_map->LookupElementsTransitionMap(FAST_ELEMENTS,
2336
+ ElementsKind from_kind = elements_kind();
2337
+ if (IsFastElementsKind(from_kind) && IsFastElementsKind(to_kind)) {
2338
+ if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) {
2339
+ if (safe_to_add_transition) *safe_to_add_transition = false;
2340
+ return NULL;
2341
+ }
2342
+ ElementsKind transitioned_from_kind =
2343
+ GetNextMoreGeneralFastElementsKind(from_kind, false);
2344
+
2345
+
2346
+ // If the transition is a single step in the transition sequence, fall
2347
+ // through to looking it up and returning it. If it requires several steps,
2348
+ // divide and conquer.
2349
+ if (transitioned_from_kind != to_kind) {
2350
+ // If the transition is several steps in the lattice, divide and conquer.
2351
+ Map* from_map = LookupElementsTransitionMap(transitioned_from_kind,
2352
+ safe_to_add_transition);
2353
+ if (from_map == NULL) return NULL;
2354
+ return from_map->LookupElementsTransitionMap(to_kind,
2348
2355
  safe_to_add_transition);
2356
+ }
2349
2357
  }
2350
2358
  Object* descriptor_contents = GetDescriptorContents(
2351
2359
  elements_transition_sentinel_name(), safe_to_add_transition);
2352
2360
  if (descriptor_contents != NULL) {
2353
2361
  Map* maybe_transition_map =
2354
2362
  GetElementsTransitionMapFromDescriptor(descriptor_contents,
2355
- elements_kind);
2363
+ to_kind);
2356
2364
  ASSERT(maybe_transition_map == NULL || maybe_transition_map->IsMap());
2357
2365
  return maybe_transition_map;
2358
2366
  }
@@ -2360,29 +2368,35 @@ Map* Map::LookupElementsTransitionMap(ElementsKind elements_kind,
2360
2368
  }
2361
2369
 
2362
2370
 
2363
- MaybeObject* Map::AddElementsTransition(ElementsKind elements_kind,
2371
+ MaybeObject* Map::AddElementsTransition(ElementsKind to_kind,
2364
2372
  Map* transitioned_map) {
2365
- // The map transition graph should be a tree, therefore the transition
2366
- // from SMI to FAST elements is not done directly, but by going through
2367
- // DOUBLE elements first.
2368
- if (this->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
2369
- elements_kind == FAST_ELEMENTS) {
2370
- bool safe_to_add = true;
2371
- Map* double_map = this->LookupElementsTransitionMap(
2372
- FAST_DOUBLE_ELEMENTS, &safe_to_add);
2373
- // This method is only called when safe_to_add_transition has been found
2374
- // to be true earlier.
2375
- ASSERT(safe_to_add);
2376
-
2377
- if (double_map == NULL) {
2378
- MaybeObject* maybe_map = this->CopyDropTransitions();
2379
- if (!maybe_map->To(&double_map)) return maybe_map;
2380
- double_map->set_elements_kind(FAST_DOUBLE_ELEMENTS);
2381
- MaybeObject* maybe_double_transition = this->AddElementsTransition(
2382
- FAST_DOUBLE_ELEMENTS, double_map);
2383
- if (maybe_double_transition->IsFailure()) return maybe_double_transition;
2384
- }
2385
- return double_map->AddElementsTransition(FAST_ELEMENTS, transitioned_map);
2373
+ ElementsKind from_kind = elements_kind();
2374
+ if (IsFastElementsKind(from_kind) && IsFastElementsKind(to_kind)) {
2375
+ ASSERT(IsMoreGeneralElementsKindTransition(from_kind, to_kind));
2376
+ ElementsKind transitioned_from_kind =
2377
+ GetNextMoreGeneralFastElementsKind(from_kind, false);
2378
+ // The map transitions graph should be a tree, therefore transitions to
2379
+ // ElementsKind that are not adjacent in the ElementsKind sequence are not
2380
+ // done directly, but instead by going through intermediate ElementsKinds
2381
+ // first.
2382
+ if (to_kind != transitioned_from_kind) {
2383
+ bool safe_to_add = true;
2384
+ Map* intermediate_map = LookupElementsTransitionMap(
2385
+ transitioned_from_kind, &safe_to_add);
2386
+ // This method is only called when safe_to_add has been found to be true
2387
+ // earlier.
2388
+ ASSERT(safe_to_add);
2389
+
2390
+ if (intermediate_map == NULL) {
2391
+ MaybeObject* maybe_map = CopyDropTransitions();
2392
+ if (!maybe_map->To(&intermediate_map)) return maybe_map;
2393
+ intermediate_map->set_elements_kind(transitioned_from_kind);
2394
+ MaybeObject* maybe_transition = AddElementsTransition(
2395
+ transitioned_from_kind, intermediate_map);
2396
+ if (maybe_transition->IsFailure()) return maybe_transition;
2397
+ }
2398
+ return intermediate_map->AddElementsTransition(to_kind, transitioned_map);
2399
+ }
2386
2400
  }
2387
2401
 
2388
2402
  bool safe_to_add_transition = true;
@@ -2408,6 +2422,7 @@ MaybeObject* Map::AddElementsTransition(ElementsKind elements_kind,
2408
2422
  return maybe_new_descriptors;
2409
2423
  }
2410
2424
  set_instance_descriptors(DescriptorArray::cast(new_descriptors));
2425
+ transitioned_map->SetBackPointer(this);
2411
2426
  return this;
2412
2427
  }
2413
2428
 
@@ -2433,10 +2448,11 @@ MaybeObject* JSObject::GetElementsTransitionMapSlow(ElementsKind to_kind) {
2433
2448
  !current_map->IsUndefined() &&
2434
2449
  !current_map->is_shared();
2435
2450
 
2436
- // Prevent long chains of DICTIONARY -> FAST_ELEMENTS maps caused by objects
2451
+ // Prevent long chains of DICTIONARY -> FAST_*_ELEMENTS maps caused by objects
2437
2452
  // with elements that switch back and forth between dictionary and fast
2438
- // element mode.
2439
- if (from_kind == DICTIONARY_ELEMENTS && to_kind == FAST_ELEMENTS) {
2453
+ // element modes.
2454
+ if (from_kind == DICTIONARY_ELEMENTS &&
2455
+ IsFastElementsKind(to_kind)) {
2440
2456
  safe_to_add_transition = false;
2441
2457
  }
2442
2458
 
@@ -2609,7 +2625,7 @@ MaybeObject* JSReceiver::SetProperty(LookupResult* result,
2609
2625
  StrictModeFlag strict_mode) {
2610
2626
  if (result->IsFound() && result->type() == HANDLER) {
2611
2627
  return result->proxy()->SetPropertyWithHandler(
2612
- key, value, attributes, strict_mode);
2628
+ this, key, value, attributes, strict_mode);
2613
2629
  } else {
2614
2630
  return JSObject::cast(this)->SetPropertyForResult(
2615
2631
  result, key, value, attributes, strict_mode);
@@ -2633,13 +2649,14 @@ bool JSProxy::HasPropertyWithHandler(String* name_raw) {
2633
2649
 
2634
2650
 
2635
2651
  MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler(
2652
+ JSReceiver* receiver_raw,
2636
2653
  String* name_raw,
2637
2654
  Object* value_raw,
2638
2655
  PropertyAttributes attributes,
2639
2656
  StrictModeFlag strict_mode) {
2640
2657
  Isolate* isolate = GetIsolate();
2641
2658
  HandleScope scope(isolate);
2642
- Handle<Object> receiver(this);
2659
+ Handle<JSReceiver> receiver(receiver_raw);
2643
2660
  Handle<Object> name(name_raw);
2644
2661
  Handle<Object> value(value_raw);
2645
2662
 
@@ -2652,6 +2669,7 @@ MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler(
2652
2669
 
2653
2670
 
2654
2671
  MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandlerIfDefiningSetter(
2672
+ JSReceiver* receiver_raw,
2655
2673
  String* name_raw,
2656
2674
  Object* value_raw,
2657
2675
  PropertyAttributes attributes,
@@ -2659,6 +2677,7 @@ MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandlerIfDefiningSetter(
2659
2677
  bool* found) {
2660
2678
  *found = true; // except where defined otherwise...
2661
2679
  Isolate* isolate = GetHeap()->isolate();
2680
+ Handle<JSReceiver> receiver(receiver_raw);
2662
2681
  Handle<JSProxy> proxy(this);
2663
2682
  Handle<Object> handler(this->handler()); // Trap might morph proxy.
2664
2683
  Handle<String> name(name_raw);
@@ -2700,7 +2719,7 @@ MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandlerIfDefiningSetter(
2700
2719
  if (!setter->IsUndefined()) {
2701
2720
  // We have a setter -- invoke it.
2702
2721
  // TODO(rossberg): nicer would be to cast to some JSCallable here...
2703
- return proxy->SetPropertyWithDefinedSetter(
2722
+ return receiver->SetPropertyWithDefinedSetter(
2704
2723
  JSReceiver::cast(*setter), *value);
2705
2724
  } else {
2706
2725
  Handle<String> get_name = isolate->factory()->LookupAsciiSymbol("get_");
@@ -2963,12 +2982,18 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
2963
2982
  // Preserve the attributes of this existing property.
2964
2983
  attributes = result->GetAttributes();
2965
2984
  return ConvertDescriptorToField(name, value, attributes);
2966
- case CALLBACKS:
2967
- return SetPropertyWithCallback(result->GetCallbackObject(),
2985
+ case CALLBACKS: {
2986
+ Object* callback_object = result->GetCallbackObject();
2987
+ if (callback_object->IsAccessorPair() &&
2988
+ !AccessorPair::cast(callback_object)->ContainsAccessor()) {
2989
+ return ConvertDescriptorToField(name, value, attributes);
2990
+ }
2991
+ return SetPropertyWithCallback(callback_object,
2968
2992
  name,
2969
2993
  value,
2970
2994
  result->holder(),
2971
2995
  strict_mode);
2996
+ }
2972
2997
  case INTERCEPTOR:
2973
2998
  return SetPropertyWithInterceptor(name, value, attributes, strict_mode);
2974
2999
  case CONSTANT_TRANSITION: {
@@ -3472,8 +3497,7 @@ MaybeObject* JSObject::NormalizeElements() {
3472
3497
  }
3473
3498
  if (array->IsDictionary()) return array;
3474
3499
 
3475
- ASSERT(HasFastElements() ||
3476
- HasFastSmiOnlyElements() ||
3500
+ ASSERT(HasFastSmiOrObjectElements() ||
3477
3501
  HasFastDoubleElements() ||
3478
3502
  HasFastArgumentsElements());
3479
3503
  // Compute the effective length and allocate a new backing store.
@@ -3508,8 +3532,7 @@ MaybeObject* JSObject::NormalizeElements() {
3508
3532
  if (!maybe_value_object->ToObject(&value)) return maybe_value_object;
3509
3533
  }
3510
3534
  } else {
3511
- ASSERT(old_map->has_fast_elements() ||
3512
- old_map->has_fast_smi_only_elements());
3535
+ ASSERT(old_map->has_fast_smi_or_object_elements());
3513
3536
  value = FixedArray::cast(array)->get(i);
3514
3537
  }
3515
3538
  PropertyDetails details = PropertyDetails(NONE, NORMAL);
@@ -3996,9 +4019,9 @@ MaybeObject* JSReceiver::DeleteProperty(String* name, DeleteMode mode) {
3996
4019
  bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
3997
4020
  ElementsKind kind,
3998
4021
  Object* object) {
3999
- ASSERT(kind == FAST_ELEMENTS ||
4022
+ ASSERT(IsFastObjectElementsKind(kind) ||
4000
4023
  kind == DICTIONARY_ELEMENTS);
4001
- if (kind == FAST_ELEMENTS) {
4024
+ if (IsFastObjectElementsKind(kind)) {
4002
4025
  int length = IsJSArray()
4003
4026
  ? Smi::cast(JSArray::cast(this)->length())->value()
4004
4027
  : elements->length();
@@ -4050,12 +4073,15 @@ bool JSObject::ReferencesObject(Object* obj) {
4050
4073
  case EXTERNAL_FLOAT_ELEMENTS:
4051
4074
  case EXTERNAL_DOUBLE_ELEMENTS:
4052
4075
  case FAST_DOUBLE_ELEMENTS:
4076
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
4053
4077
  // Raw pixels and external arrays do not reference other
4054
4078
  // objects.
4055
4079
  break;
4056
- case FAST_SMI_ONLY_ELEMENTS:
4080
+ case FAST_SMI_ELEMENTS:
4081
+ case FAST_HOLEY_SMI_ELEMENTS:
4057
4082
  break;
4058
4083
  case FAST_ELEMENTS:
4084
+ case FAST_HOLEY_ELEMENTS:
4059
4085
  case DICTIONARY_ELEMENTS: {
4060
4086
  FixedArray* elements = FixedArray::cast(this->elements());
4061
4087
  if (ReferencesObjectFromElements(elements, kind, obj)) return true;
@@ -4071,7 +4097,8 @@ bool JSObject::ReferencesObject(Object* obj) {
4071
4097
  }
4072
4098
  // Check the arguments.
4073
4099
  FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
4074
- kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : FAST_ELEMENTS;
4100
+ kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS :
4101
+ FAST_HOLEY_ELEMENTS;
4075
4102
  if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
4076
4103
  break;
4077
4104
  }
@@ -4305,7 +4332,7 @@ void JSReceiver::Lookup(String* name, LookupResult* result) {
4305
4332
  }
4306
4333
 
4307
4334
 
4308
- // Search object and it's prototype chain for callback properties.
4335
+ // Search object and its prototype chain for callback properties.
4309
4336
  void JSObject::LookupCallback(String* name, LookupResult* result) {
4310
4337
  Heap* heap = GetHeap();
4311
4338
  for (Object* current = this;
@@ -4349,9 +4376,12 @@ MaybeObject* JSObject::DefineElementAccessor(uint32_t index,
4349
4376
  Object* setter,
4350
4377
  PropertyAttributes attributes) {
4351
4378
  switch (GetElementsKind()) {
4352
- case FAST_SMI_ONLY_ELEMENTS:
4379
+ case FAST_SMI_ELEMENTS:
4353
4380
  case FAST_ELEMENTS:
4354
4381
  case FAST_DOUBLE_ELEMENTS:
4382
+ case FAST_HOLEY_SMI_ELEMENTS:
4383
+ case FAST_HOLEY_ELEMENTS:
4384
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
4355
4385
  break;
4356
4386
  case EXTERNAL_PIXEL_ELEMENTS:
4357
4387
  case EXTERNAL_BYTE_ELEMENTS:
@@ -4413,7 +4443,12 @@ MaybeObject* JSObject::CreateAccessorPairFor(String* name) {
4413
4443
  LookupResult result(GetHeap()->isolate());
4414
4444
  LocalLookupRealNamedProperty(name, &result);
4415
4445
  if (result.IsProperty() && result.type() == CALLBACKS) {
4416
- ASSERT(!result.IsDontDelete());
4446
+ // Note that the result can actually have IsDontDelete() == true when we
4447
+ // e.g. have to fall back to the slow case while adding a setter after
4448
+ // successfully reusing a map transition for a getter. Nevertheless, this is
4449
+ // OK, because the assertion only holds for the whole addition of both
4450
+ // accessors, not for the addition of each part. See first comment in
4451
+ // DefinePropertyAccessor below.
4417
4452
  Object* obj = result.GetCallbackObject();
4418
4453
  if (obj->IsAccessorPair()) {
4419
4454
  return AccessorPair::cast(obj)->CopyWithoutTransitions();
@@ -4427,6 +4462,28 @@ MaybeObject* JSObject::DefinePropertyAccessor(String* name,
4427
4462
  Object* getter,
4428
4463
  Object* setter,
4429
4464
  PropertyAttributes attributes) {
4465
+ // We could assert that the property is configurable here, but we would need
4466
+ // to do a lookup, which seems to be a bit of overkill.
4467
+ Heap* heap = GetHeap();
4468
+ bool only_attribute_changes = getter->IsNull() && setter->IsNull();
4469
+ if (HasFastProperties() && !only_attribute_changes) {
4470
+ MaybeObject* getterOk = heap->undefined_value();
4471
+ if (!getter->IsNull()) {
4472
+ getterOk = DefineFastAccessor(name, ACCESSOR_GETTER, getter, attributes);
4473
+ if (getterOk->IsFailure()) return getterOk;
4474
+ }
4475
+
4476
+ MaybeObject* setterOk = heap->undefined_value();
4477
+ if (getterOk != heap->null_value() && !setter->IsNull()) {
4478
+ setterOk = DefineFastAccessor(name, ACCESSOR_SETTER, setter, attributes);
4479
+ if (setterOk->IsFailure()) return setterOk;
4480
+ }
4481
+
4482
+ if (getterOk != heap->null_value() && setterOk != heap->null_value()) {
4483
+ return heap->undefined_value();
4484
+ }
4485
+ }
4486
+
4430
4487
  AccessorPair* accessors;
4431
4488
  { MaybeObject* maybe_accessors = CreateAccessorPairFor(name);
4432
4489
  if (!maybe_accessors->To(&accessors)) return maybe_accessors;
@@ -4441,7 +4498,7 @@ bool JSObject::CanSetCallback(String* name) {
4441
4498
  GetIsolate()->MayNamedAccess(this, name, v8::ACCESS_SET));
4442
4499
 
4443
4500
  // Check if there is an API defined callback object which prohibits
4444
- // callback overwriting in this object or it's prototype chain.
4501
+ // callback overwriting in this object or its prototype chain.
4445
4502
  // This mechanism is needed for instance in a browser setting, where
4446
4503
  // certain accessors such as window.location should not be allowed
4447
4504
  // to be overwritten because allowing overwriting could potentially
@@ -4576,6 +4633,159 @@ MaybeObject* JSObject::DefineAccessor(String* name,
4576
4633
  }
4577
4634
 
4578
4635
 
4636
+ static MaybeObject* CreateFreshAccessor(JSObject* obj,
4637
+ String* name,
4638
+ AccessorComponent component,
4639
+ Object* accessor,
4640
+ PropertyAttributes attributes) {
4641
+ // step 1: create a new getter/setter pair with only the accessor in it
4642
+ Heap* heap = obj->GetHeap();
4643
+ AccessorPair* accessors2;
4644
+ { MaybeObject* maybe_accessors2 = heap->AllocateAccessorPair();
4645
+ if (!maybe_accessors2->To(&accessors2)) return maybe_accessors2;
4646
+ }
4647
+ accessors2->set(component, accessor);
4648
+
4649
+ // step 2: create a copy of the descriptors, incl. the new getter/setter pair
4650
+ Map* map1 = obj->map();
4651
+ CallbacksDescriptor callbacks_descr2(name, accessors2, attributes);
4652
+ DescriptorArray* descriptors2;
4653
+ { MaybeObject* maybe_descriptors2 =
4654
+ map1->instance_descriptors()->CopyInsert(&callbacks_descr2,
4655
+ REMOVE_TRANSITIONS);
4656
+ if (!maybe_descriptors2->To(&descriptors2)) return maybe_descriptors2;
4657
+ }
4658
+
4659
+ // step 3: create a new map with the new descriptors
4660
+ Map* map2;
4661
+ { MaybeObject* maybe_map2 = map1->CopyDropDescriptors();
4662
+ if (!maybe_map2->To(&map2)) return maybe_map2;
4663
+ }
4664
+ map2->set_instance_descriptors(descriptors2);
4665
+
4666
+ // step 4: create a new getter/setter pair with a transition to the new map
4667
+ AccessorPair* accessors1;
4668
+ { MaybeObject* maybe_accessors1 = heap->AllocateAccessorPair();
4669
+ if (!maybe_accessors1->To(&accessors1)) return maybe_accessors1;
4670
+ }
4671
+ accessors1->set(component, map2);
4672
+
4673
+ // step 5: create a copy of the descriptors, incl. the new getter/setter pair
4674
+ // with the transition
4675
+ CallbacksDescriptor callbacks_descr1(name, accessors1, attributes);
4676
+ DescriptorArray* descriptors1;
4677
+ { MaybeObject* maybe_descriptors1 =
4678
+ map1->instance_descriptors()->CopyInsert(&callbacks_descr1,
4679
+ KEEP_TRANSITIONS);
4680
+ if (!maybe_descriptors1->To(&descriptors1)) return maybe_descriptors1;
4681
+ }
4682
+
4683
+ // step 6: everything went well so far, so we make our changes visible
4684
+ obj->set_map(map2);
4685
+ map1->set_instance_descriptors(descriptors1);
4686
+ map2->SetBackPointer(map1);
4687
+ return obj;
4688
+ }
4689
+
4690
+
4691
+ static bool TransitionToSameAccessor(Object* map,
4692
+ String* name,
4693
+ AccessorComponent component,
4694
+ Object* accessor,
4695
+ PropertyAttributes attributes ) {
4696
+ DescriptorArray* descs = Map::cast(map)->instance_descriptors();
4697
+ int number = descs->SearchWithCache(name);
4698
+ ASSERT(number != DescriptorArray::kNotFound);
4699
+ Object* target_accessor =
4700
+ AccessorPair::cast(descs->GetCallbacksObject(number))->get(component);
4701
+ PropertyAttributes target_attributes = descs->GetDetails(number).attributes();
4702
+ return target_accessor == accessor && target_attributes == attributes;
4703
+ }
4704
+
4705
+
4706
+ static MaybeObject* NewCallbackTransition(JSObject* obj,
4707
+ String* name,
4708
+ AccessorComponent component,
4709
+ Object* accessor,
4710
+ PropertyAttributes attributes,
4711
+ AccessorPair* accessors2) {
4712
+ // step 1: copy the old getter/setter pair and set the new accessor
4713
+ AccessorPair* accessors3;
4714
+ { MaybeObject* maybe_accessors3 = accessors2->CopyWithoutTransitions();
4715
+ if (!maybe_accessors3->To(&accessors3)) return maybe_accessors3;
4716
+ }
4717
+ accessors3->set(component, accessor);
4718
+
4719
+ // step 2: create a copy of the descriptors, incl. the new getter/setter pair
4720
+ Map* map2 = obj->map();
4721
+ CallbacksDescriptor callbacks_descr3(name, accessors3, attributes);
4722
+ DescriptorArray* descriptors3;
4723
+ { MaybeObject* maybe_descriptors3 =
4724
+ map2->instance_descriptors()->CopyInsert(&callbacks_descr3,
4725
+ REMOVE_TRANSITIONS);
4726
+ if (!maybe_descriptors3->To(&descriptors3)) return maybe_descriptors3;
4727
+ }
4728
+
4729
+ // step 3: create a new map with the new descriptors
4730
+ Map* map3;
4731
+ { MaybeObject* maybe_map3 = map2->CopyDropDescriptors();
4732
+ if (!maybe_map3->To(&map3)) return maybe_map3;
4733
+ }
4734
+ map3->set_instance_descriptors(descriptors3);
4735
+
4736
+ // step 4: everything went well so far, so we make our changes visible
4737
+ obj->set_map(map3);
4738
+ accessors2->set(component, map3);
4739
+ map3->SetBackPointer(map2);
4740
+ return obj;
4741
+ }
4742
+
4743
+
4744
+ MaybeObject* JSObject::DefineFastAccessor(String* name,
4745
+ AccessorComponent component,
4746
+ Object* accessor,
4747
+ PropertyAttributes attributes) {
4748
+ ASSERT(accessor->IsSpecFunction() || accessor->IsUndefined());
4749
+ LookupResult result(GetIsolate());
4750
+ LocalLookup(name, &result);
4751
+
4752
+ // If we have a new property, create a fresh accessor plus a transition to it.
4753
+ if (!result.IsFound()) {
4754
+ return CreateFreshAccessor(this, name, component, accessor, attributes);
4755
+ }
4756
+
4757
+ // If the property is not a JavaScript accessor, fall back to the slow case.
4758
+ if (result.type() != CALLBACKS) return GetHeap()->null_value();
4759
+ Object* callback_value = result.GetCallbackObject();
4760
+ if (!callback_value->IsAccessorPair()) return GetHeap()->null_value();
4761
+ AccessorPair* accessors = AccessorPair::cast(callback_value);
4762
+
4763
+ // Follow a callback transition, if there is a fitting one.
4764
+ Object* entry = accessors->get(component);
4765
+ if (entry->IsMap() &&
4766
+ TransitionToSameAccessor(entry, name, component, accessor, attributes)) {
4767
+ set_map(Map::cast(entry));
4768
+ return this;
4769
+ }
4770
+
4771
+ // When we re-add the same accessor again, there is nothing to do.
4772
+ if (entry == accessor && result.GetAttributes() == attributes) return this;
4773
+
4774
+ // Only the other accessor has been set so far, create a new transition.
4775
+ if (entry->IsTheHole()) {
4776
+ return NewCallbackTransition(this,
4777
+ name,
4778
+ component,
4779
+ accessor,
4780
+ attributes,
4781
+ accessors);
4782
+ }
4783
+
4784
+ // Nothing from the above worked, so we have to fall back to the slow case.
4785
+ return GetHeap()->null_value();
4786
+ }
4787
+
4788
+
4579
4789
  MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
4580
4790
  Isolate* isolate = GetIsolate();
4581
4791
  String* name = String::cast(info->name());
@@ -4612,9 +4822,12 @@ MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
4612
4822
 
4613
4823
  // Accessors overwrite previous callbacks (cf. with getters/setters).
4614
4824
  switch (GetElementsKind()) {
4615
- case FAST_SMI_ONLY_ELEMENTS:
4825
+ case FAST_SMI_ELEMENTS:
4616
4826
  case FAST_ELEMENTS:
4617
4827
  case FAST_DOUBLE_ELEMENTS:
4828
+ case FAST_HOLEY_SMI_ELEMENTS:
4829
+ case FAST_HOLEY_ELEMENTS:
4830
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
4618
4831
  break;
4619
4832
  case EXTERNAL_PIXEL_ELEMENTS:
4620
4833
  case EXTERNAL_BYTE_ELEMENTS:
@@ -4885,39 +5098,46 @@ class IntrusiveMapTransitionIterator {
4885
5098
 
4886
5099
  void Start() {
4887
5100
  ASSERT(!IsIterating());
4888
- if (HasContentArray()) *ContentHeader() = Smi::FromInt(0);
5101
+ if (HasDescriptors()) *DescriptorArrayHeader() = Smi::FromInt(0);
4889
5102
  }
4890
5103
 
4891
5104
  bool IsIterating() {
4892
- return HasContentArray() && (*ContentHeader())->IsSmi();
5105
+ return HasDescriptors() && (*DescriptorArrayHeader())->IsSmi();
4893
5106
  }
4894
5107
 
4895
5108
  Map* Next() {
4896
5109
  ASSERT(IsIterating());
4897
- FixedArray* contents = ContentArray();
4898
- // Attention, tricky index manipulation ahead: Every entry in the contents
4899
- // array consists of a value/details pair, so the index is typically even.
4900
- // An exception is made for CALLBACKS entries: An even index means we look
4901
- // at its getter, and an odd index means we look at its setter.
4902
- int index = Smi::cast(*ContentHeader())->value();
4903
- while (index < contents->length()) {
4904
- PropertyDetails details(Smi::cast(contents->get(index | 1)));
5110
+ // Attention, tricky index manipulation ahead: Two consecutive indices are
5111
+ // assigned to each descriptor. Most descriptors directly advance to the
5112
+ // next descriptor by adding 2 to the index. The exceptions are the
5113
+ // CALLBACKS entries: An even index means we look at its getter, and an odd
5114
+ // index means we look at its setter.
5115
+ int raw_index = Smi::cast(*DescriptorArrayHeader())->value();
5116
+ int index = raw_index / 2;
5117
+ int number_of_descriptors = descriptor_array_->number_of_descriptors();
5118
+ while (index < number_of_descriptors) {
5119
+ PropertyDetails details(RawGetDetails(index));
4905
5120
  switch (details.type()) {
4906
5121
  case MAP_TRANSITION:
4907
5122
  case CONSTANT_TRANSITION:
4908
5123
  case ELEMENTS_TRANSITION:
4909
5124
  // We definitely have a map transition.
4910
- *ContentHeader() = Smi::FromInt(index + 2);
4911
- return static_cast<Map*>(contents->get(index));
5125
+ *DescriptorArrayHeader() = Smi::FromInt(raw_index + 2);
5126
+ return static_cast<Map*>(RawGetValue(index));
4912
5127
  case CALLBACKS: {
4913
5128
  // We might have a map transition in a getter or in a setter.
4914
5129
  AccessorPair* accessors =
4915
- static_cast<AccessorPair*>(contents->get(index & ~1));
4916
- Object* accessor =
4917
- ((index & 1) == 0) ? accessors->getter() : accessors->setter();
4918
- index++;
5130
+ static_cast<AccessorPair*>(RawGetValue(index));
5131
+ Object* accessor;
5132
+ if ((raw_index & 1) == 0) {
5133
+ accessor = accessors->setter();
5134
+ } else {
5135
+ ++index;
5136
+ accessor = accessors->getter();
5137
+ }
5138
+ ++raw_index;
4919
5139
  if (accessor->IsMap()) {
4920
- *ContentHeader() = Smi::FromInt(index);
5140
+ *DescriptorArrayHeader() = Smi::FromInt(raw_index);
4921
5141
  return static_cast<Map*>(accessor);
4922
5142
  }
4923
5143
  break;
@@ -4929,28 +5149,42 @@ class IntrusiveMapTransitionIterator {
4929
5149
  case INTERCEPTOR:
4930
5150
  case NULL_DESCRIPTOR:
4931
5151
  // We definitely have no map transition.
4932
- index += 2;
5152
+ raw_index += 2;
5153
+ ++index;
4933
5154
  break;
4934
5155
  }
4935
5156
  }
4936
- *ContentHeader() = descriptor_array_->GetHeap()->fixed_array_map();
5157
+ *DescriptorArrayHeader() = descriptor_array_->GetHeap()->fixed_array_map();
4937
5158
  return NULL;
4938
5159
  }
4939
5160
 
4940
5161
  private:
4941
- bool HasContentArray() {
4942
- return descriptor_array_-> length() > DescriptorArray::kContentArrayIndex;
5162
+ bool HasDescriptors() {
5163
+ return descriptor_array_->length() > DescriptorArray::kFirstIndex;
5164
+ }
5165
+
5166
+ Object** DescriptorArrayHeader() {
5167
+ return HeapObject::RawField(descriptor_array_, DescriptorArray::kMapOffset);
5168
+ }
5169
+
5170
+ FixedArray* RawGetContentArray() {
5171
+ Object* array =
5172
+ descriptor_array_->get(DescriptorArray::kContentArrayIndex);
5173
+ return static_cast<FixedArray*>(array);
4943
5174
  }
4944
5175
 
4945
- FixedArray* ContentArray() {
4946
- Object* array = descriptor_array_->get(DescriptorArray::kContentArrayIndex);
4947
- return static_cast<FixedArray*>(array);
5176
+ Object* RawGetValue(int descriptor_number) {
5177
+ return RawGetContentArray()->get(
5178
+ DescriptorArray::ToValueIndex(descriptor_number));
4948
5179
  }
4949
5180
 
4950
- Object** ContentHeader() {
4951
- return HeapObject::RawField(ContentArray(), DescriptorArray::kMapOffset);
5181
+ PropertyDetails RawGetDetails(int descriptor_number) {
5182
+ Object* details = RawGetContentArray()->get(
5183
+ DescriptorArray::ToDetailsIndex(descriptor_number));
5184
+ return PropertyDetails(Smi::cast(details));
4952
5185
  }
4953
5186
 
5187
+
4954
5188
  DescriptorArray* descriptor_array_;
4955
5189
  };
4956
5190
 
@@ -4959,7 +5193,7 @@ class IntrusiveMapTransitionIterator {
4959
5193
  // underlying array while it is running.
4960
5194
  class IntrusivePrototypeTransitionIterator {
4961
5195
  public:
4962
- explicit IntrusivePrototypeTransitionIterator(FixedArray* proto_trans)
5196
+ explicit IntrusivePrototypeTransitionIterator(HeapObject* proto_trans)
4963
5197
  : proto_trans_(proto_trans) { }
4964
5198
 
4965
5199
  void Start() {
@@ -4984,7 +5218,7 @@ class IntrusivePrototypeTransitionIterator {
4984
5218
 
4985
5219
  private:
4986
5220
  bool HasTransitions() {
4987
- return proto_trans_->length() >= Map::kProtoTransitionHeaderSize;
5221
+ return proto_trans_->map()->IsSmi() || proto_trans_->IsFixedArray();
4988
5222
  }
4989
5223
 
4990
5224
  Object** Header() {
@@ -4992,12 +5226,16 @@ class IntrusivePrototypeTransitionIterator {
4992
5226
  }
4993
5227
 
4994
5228
  int NumberOfTransitions() {
4995
- Object* num = proto_trans_->get(Map::kProtoTransitionNumberOfEntriesOffset);
5229
+ ASSERT(HasTransitions());
5230
+ FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_);
5231
+ Object* num = proto_trans->get(Map::kProtoTransitionNumberOfEntriesOffset);
4996
5232
  return Smi::cast(num)->value();
4997
5233
  }
4998
5234
 
4999
5235
  Map* GetTransition(int transitionNumber) {
5000
- return Map::cast(proto_trans_->get(IndexFor(transitionNumber)));
5236
+ ASSERT(HasTransitions());
5237
+ FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_);
5238
+ return Map::cast(proto_trans->get(IndexFor(transitionNumber)));
5001
5239
  }
5002
5240
 
5003
5241
  int IndexFor(int transitionNumber) {
@@ -5006,7 +5244,7 @@ class IntrusivePrototypeTransitionIterator {
5006
5244
  transitionNumber * Map::kProtoTransitionElementsPerEntry;
5007
5245
  }
5008
5246
 
5009
- FixedArray* proto_trans_;
5247
+ HeapObject* proto_trans_;
5010
5248
  };
5011
5249
 
5012
5250
 
@@ -5045,6 +5283,20 @@ class TraversableMap : public Map {
5045
5283
  return old_parent;
5046
5284
  }
5047
5285
 
5286
+ // Can either be Smi (no instance descriptors), or a descriptor array with the
5287
+ // header overwritten as a Smi (thus iterating).
5288
+ DescriptorArray* MutatedInstanceDescriptors() {
5289
+ Object* object =
5290
+ *HeapObject::RawField(this, kInstanceDescriptorsOrBitField3Offset);
5291
+ if (object->IsSmi()) {
5292
+ return GetHeap()->empty_descriptor_array();
5293
+ } else {
5294
+ DescriptorArray* descriptor_array =
5295
+ static_cast<DescriptorArray*>(object);
5296
+ return descriptor_array;
5297
+ }
5298
+ }
5299
+
5048
5300
  // Start iterating over this map's children, possibly destroying a FixedArray
5049
5301
  // map (see explanation above).
5050
5302
  void ChildIteratorStart() {
@@ -5056,17 +5308,18 @@ class TraversableMap : public Map {
5056
5308
  // If we have an unvisited child map, return that one and advance. If we have
5057
5309
  // none, return NULL and reset any destroyed FixedArray maps.
5058
5310
  TraversableMap* ChildIteratorNext() {
5059
- IntrusiveMapTransitionIterator descriptor_iterator(instance_descriptors());
5060
- if (descriptor_iterator.IsIterating()) {
5061
- Map* next = descriptor_iterator.Next();
5062
- if (next != NULL) return static_cast<TraversableMap*>(next);
5063
- }
5064
5311
  IntrusivePrototypeTransitionIterator
5065
5312
  proto_iterator(unchecked_prototype_transitions());
5066
5313
  if (proto_iterator.IsIterating()) {
5067
5314
  Map* next = proto_iterator.Next();
5068
5315
  if (next != NULL) return static_cast<TraversableMap*>(next);
5069
5316
  }
5317
+ IntrusiveMapTransitionIterator
5318
+ descriptor_iterator(MutatedInstanceDescriptors());
5319
+ if (descriptor_iterator.IsIterating()) {
5320
+ Map* next = descriptor_iterator.Next();
5321
+ if (next != NULL) return static_cast<TraversableMap*>(next);
5322
+ }
5070
5323
  return NULL;
5071
5324
  }
5072
5325
  };
@@ -5727,21 +5980,15 @@ MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
5727
5980
  int index = Search(descriptor->GetKey());
5728
5981
  const bool replacing = (index != kNotFound);
5729
5982
  bool keep_enumeration_index = false;
5730
- if (replacing) {
5731
- // We are replacing an existing descriptor. We keep the enumeration
5732
- // index of a visible property.
5733
- PropertyType t = GetDetails(index).type();
5734
- if (t == CONSTANT_FUNCTION ||
5735
- t == FIELD ||
5736
- t == CALLBACKS ||
5737
- t == INTERCEPTOR) {
5738
- keep_enumeration_index = true;
5739
- } else if (remove_transitions) {
5740
- // Replaced descriptor has been counted as removed if it is
5741
- // a transition that will be replaced. Adjust count in this case.
5742
- ++new_size;
5743
- }
5744
- } else {
5983
+ if (!replacing) {
5984
+ ++new_size;
5985
+ } else if (!IsTransitionOnly(index)) {
5986
+ // We are replacing an existing descriptor. We keep the enumeration index
5987
+ // of a visible property.
5988
+ keep_enumeration_index = true;
5989
+ } else if (remove_transitions) {
5990
+ // Replaced descriptor has been counted as removed if it is a transition
5991
+ // that will be replaced. Adjust count in this case.
5745
5992
  ++new_size;
5746
5993
  }
5747
5994
 
@@ -5821,7 +6068,10 @@ MaybeObject* DescriptorArray::RemoveTransitions() {
5821
6068
  return new_descriptors;
5822
6069
  }
5823
6070
 
5824
-
6071
+ // We need the whiteness witness since sort will reshuffle the entries in the
6072
+ // descriptor array. If the descriptor array were to be black, the shuffling
6073
+ // would move a slot that was already recorded as pointing into an evacuation
6074
+ // candidate. This would result in missing updates upon evacuation.
5825
6075
  void DescriptorArray::SortUnchecked(const WhitenessWitness& witness) {
5826
6076
  // In-place heap sort.
5827
6077
  int len = number_of_descriptors();
@@ -5939,8 +6189,8 @@ MaybeObject* AccessorPair::CopyWithoutTransitions() {
5939
6189
 
5940
6190
 
5941
6191
  Object* AccessorPair::GetComponent(AccessorComponent component) {
5942
- Object* accessor = (component == ACCESSOR_GETTER) ? getter() : setter();
5943
- return accessor->IsTheHole() ? GetHeap()->undefined_value() : accessor;
6192
+ Object* accessor = get(component);
6193
+ return accessor->IsTheHole() ? GetHeap()->undefined_value() : accessor;
5944
6194
  }
5945
6195
 
5946
6196
 
@@ -7168,85 +7418,23 @@ void String::PrintOn(FILE* file) {
7168
7418
  }
7169
7419
 
7170
7420
 
7171
- void Map::CreateOneBackPointer(Object* transition_target) {
7172
- if (!transition_target->IsMap()) return;
7173
- Map* target = Map::cast(transition_target);
7174
- #ifdef DEBUG
7175
- // Verify target.
7176
- Object* source_prototype = prototype();
7177
- Object* target_prototype = target->prototype();
7178
- ASSERT(source_prototype->IsJSReceiver() ||
7179
- source_prototype->IsMap() ||
7180
- source_prototype->IsNull());
7181
- ASSERT(target_prototype->IsJSReceiver() ||
7182
- target_prototype->IsNull());
7183
- ASSERT(source_prototype->IsMap() ||
7184
- source_prototype == target_prototype);
7185
- #endif
7186
- // Point target back to source. set_prototype() will not let us set
7187
- // the prototype to a map, as we do here.
7188
- *RawField(target, kPrototypeOffset) = this;
7189
- }
7190
-
7191
-
7192
- void Map::CreateBackPointers() {
7193
- DescriptorArray* descriptors = instance_descriptors();
7194
- for (int i = 0; i < descriptors->number_of_descriptors(); i++) {
7195
- switch (descriptors->GetType(i)) {
7196
- case MAP_TRANSITION:
7197
- case CONSTANT_TRANSITION:
7198
- CreateOneBackPointer(descriptors->GetValue(i));
7199
- break;
7200
- case ELEMENTS_TRANSITION: {
7201
- Object* object = descriptors->GetValue(i);
7202
- if (object->IsMap()) {
7203
- CreateOneBackPointer(object);
7204
- } else {
7205
- FixedArray* array = FixedArray::cast(object);
7206
- for (int i = 0; i < array->length(); ++i) {
7207
- CreateOneBackPointer(array->get(i));
7208
- }
7209
- }
7210
- break;
7211
- }
7212
- case CALLBACKS: {
7213
- Object* object = descriptors->GetValue(i);
7214
- if (object->IsAccessorPair()) {
7215
- AccessorPair* accessors = AccessorPair::cast(object);
7216
- CreateOneBackPointer(accessors->getter());
7217
- CreateOneBackPointer(accessors->setter());
7218
- }
7219
- break;
7220
- }
7221
- case NORMAL:
7222
- case FIELD:
7223
- case CONSTANT_FUNCTION:
7224
- case HANDLER:
7225
- case INTERCEPTOR:
7226
- case NULL_DESCRIPTOR:
7227
- break;
7228
- }
7229
- }
7230
- }
7231
-
7232
-
7233
- bool Map::RestoreOneBackPointer(Object* object,
7234
- Object* real_prototype,
7235
- bool* keep_entry) {
7236
- if (!object->IsMap()) return false;
7237
- Map* map = Map::cast(object);
7421
+ // Clear a possible back pointer in case the transition leads to a dead map.
7422
+ // Return true in case a back pointer has been cleared and false otherwise.
7423
+ // Set *keep_entry to true when a live map transition has been found.
7424
+ static bool ClearBackPointer(Heap* heap, Object* target, bool* keep_entry) {
7425
+ if (!target->IsMap()) return false;
7426
+ Map* map = Map::cast(target);
7238
7427
  if (Marking::MarkBitFrom(map).Get()) {
7239
7428
  *keep_entry = true;
7240
7429
  return false;
7430
+ } else {
7431
+ map->SetBackPointer(heap->undefined_value(), SKIP_WRITE_BARRIER);
7432
+ return true;
7241
7433
  }
7242
- ASSERT(map->prototype() == this || map->prototype() == real_prototype);
7243
- // Getter prototype() is read-only, set_prototype() has side effects.
7244
- *RawField(map, Map::kPrototypeOffset) = real_prototype;
7245
- return true;
7246
7434
  }
7247
7435
 
7248
7436
 
7249
- void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
7437
+ void Map::ClearNonLiveTransitions(Heap* heap) {
7250
7438
  DescriptorArray* d = DescriptorArray::cast(
7251
7439
  *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset));
7252
7440
  if (d->IsEmpty()) return;
@@ -7259,24 +7447,22 @@ void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
7259
7447
  // If the pair (value, details) is a map transition, check if the target is
7260
7448
  // live. If not, null the descriptor. Also drop the back pointer for that
7261
7449
  // map transition, so that this map is not reached again by following a back
7262
- // pointer from a non-live object.
7450
+ // pointer from that non-live map.
7263
7451
  bool keep_entry = false;
7264
7452
  PropertyDetails details(Smi::cast(contents->get(i + 1)));
7265
7453
  switch (details.type()) {
7266
7454
  case MAP_TRANSITION:
7267
7455
  case CONSTANT_TRANSITION:
7268
- RestoreOneBackPointer(contents->get(i), real_prototype, &keep_entry);
7456
+ ClearBackPointer(heap, contents->get(i), &keep_entry);
7269
7457
  break;
7270
7458
  case ELEMENTS_TRANSITION: {
7271
7459
  Object* object = contents->get(i);
7272
7460
  if (object->IsMap()) {
7273
- RestoreOneBackPointer(object, real_prototype, &keep_entry);
7461
+ ClearBackPointer(heap, object, &keep_entry);
7274
7462
  } else {
7275
7463
  FixedArray* array = FixedArray::cast(object);
7276
7464
  for (int j = 0; j < array->length(); ++j) {
7277
- if (RestoreOneBackPointer(array->get(j),
7278
- real_prototype,
7279
- &keep_entry)) {
7465
+ if (ClearBackPointer(heap, array->get(j), &keep_entry)) {
7280
7466
  array->set_undefined(j);
7281
7467
  }
7282
7468
  }
@@ -7287,14 +7473,10 @@ void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
7287
7473
  Object* object = contents->get(i);
7288
7474
  if (object->IsAccessorPair()) {
7289
7475
  AccessorPair* accessors = AccessorPair::cast(object);
7290
- if (RestoreOneBackPointer(accessors->getter(),
7291
- real_prototype,
7292
- &keep_entry)) {
7476
+ if (ClearBackPointer(heap, accessors->getter(), &keep_entry)) {
7293
7477
  accessors->set_getter(heap->the_hole_value());
7294
7478
  }
7295
- if (RestoreOneBackPointer(accessors->setter(),
7296
- real_prototype,
7297
- &keep_entry)) {
7479
+ if (ClearBackPointer(heap, accessors->setter(), &keep_entry)) {
7298
7480
  accessors->set_setter(heap->the_hole_value());
7299
7481
  }
7300
7482
  } else {
@@ -8142,6 +8324,20 @@ void Code::ClearInlineCaches() {
8142
8324
  }
8143
8325
 
8144
8326
 
8327
+ void Code::ClearTypeFeedbackCells(Heap* heap) {
8328
+ Object* raw_info = type_feedback_info();
8329
+ if (raw_info->IsTypeFeedbackInfo()) {
8330
+ TypeFeedbackCells* type_feedback_cells =
8331
+ TypeFeedbackInfo::cast(raw_info)->type_feedback_cells();
8332
+ for (int i = 0; i < type_feedback_cells->CellCount(); i++) {
8333
+ ASSERT(type_feedback_cells->AstId(i)->IsSmi());
8334
+ JSGlobalPropertyCell* cell = type_feedback_cells->Cell(i);
8335
+ cell->set_value(TypeFeedbackCells::RawUninitializedSentinel(heap));
8336
+ }
8337
+ }
8338
+ }
8339
+
8340
+
8145
8341
  #ifdef ENABLE_DISASSEMBLER
8146
8342
 
8147
8343
  void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
@@ -8378,6 +8574,10 @@ void Code::Disassemble(const char* name, FILE* out) {
8378
8574
  CompareIC::State state = CompareIC::ComputeState(this);
8379
8575
  PrintF(out, "compare_state = %s\n", CompareIC::GetStateName(state));
8380
8576
  }
8577
+ if (is_compare_ic_stub() && major_key() == CodeStub::CompareIC) {
8578
+ Token::Value op = CompareIC::ComputeOperation(this);
8579
+ PrintF(out, "compare_operation = %s\n", Token::Name(op));
8580
+ }
8381
8581
  }
8382
8582
  if ((name != NULL) && (name[0] != '\0')) {
8383
8583
  PrintF(out, "name = %s\n", name);
@@ -8449,7 +8649,7 @@ void Code::Disassemble(const char* name, FILE* out) {
8449
8649
  MaybeObject* JSObject::SetFastElementsCapacityAndLength(
8450
8650
  int capacity,
8451
8651
  int length,
8452
- SetFastElementsCapacityMode set_capacity_mode) {
8652
+ SetFastElementsCapacitySmiMode smi_mode) {
8453
8653
  Heap* heap = GetHeap();
8454
8654
  // We should never end in here with a pixel or external array.
8455
8655
  ASSERT(!HasExternalArrayElements());
@@ -8460,32 +8660,40 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength(
8460
8660
  if (!maybe->To(&new_elements)) return maybe;
8461
8661
  }
8462
8662
 
8463
- // Find the new map to use for this object if there is a map change.
8464
- Map* new_map = NULL;
8465
- if (elements()->map() != heap->non_strict_arguments_elements_map()) {
8466
- // The resized array has FAST_SMI_ONLY_ELEMENTS if the capacity mode forces
8467
- // it, or if it's allowed and the old elements array contained only SMIs.
8468
- bool has_fast_smi_only_elements =
8469
- (set_capacity_mode == kForceSmiOnlyElements) ||
8470
- ((set_capacity_mode == kAllowSmiOnlyElements) &&
8471
- (elements()->map()->has_fast_smi_only_elements() ||
8472
- elements() == heap->empty_fixed_array()));
8473
- ElementsKind elements_kind = has_fast_smi_only_elements
8474
- ? FAST_SMI_ONLY_ELEMENTS
8475
- : FAST_ELEMENTS;
8476
- MaybeObject* maybe = GetElementsTransitionMap(GetIsolate(), elements_kind);
8477
- if (!maybe->To(&new_map)) return maybe;
8663
+ ElementsKind elements_kind = GetElementsKind();
8664
+ ElementsKind new_elements_kind;
8665
+ // The resized array has FAST_*_SMI_ELEMENTS if the capacity mode forces it,
8666
+ // or if it's allowed and the old elements array contained only SMIs.
8667
+ bool has_fast_smi_elements =
8668
+ (smi_mode == kForceSmiElements) ||
8669
+ ((smi_mode == kAllowSmiElements) && HasFastSmiElements());
8670
+ if (has_fast_smi_elements) {
8671
+ if (IsHoleyElementsKind(elements_kind)) {
8672
+ new_elements_kind = FAST_HOLEY_SMI_ELEMENTS;
8673
+ } else {
8674
+ new_elements_kind = FAST_SMI_ELEMENTS;
8675
+ }
8676
+ } else {
8677
+ if (IsHoleyElementsKind(elements_kind)) {
8678
+ new_elements_kind = FAST_HOLEY_ELEMENTS;
8679
+ } else {
8680
+ new_elements_kind = FAST_ELEMENTS;
8681
+ }
8478
8682
  }
8479
-
8480
8683
  FixedArrayBase* old_elements = elements();
8481
- ElementsKind elements_kind = GetElementsKind();
8482
8684
  ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
8483
- ElementsKind to_kind = (elements_kind == FAST_SMI_ONLY_ELEMENTS)
8484
- ? FAST_SMI_ONLY_ELEMENTS
8485
- : FAST_ELEMENTS;
8486
- // int copy_size = Min(old_elements_raw->length(), new_elements->length());
8487
- accessor->CopyElements(this, new_elements, to_kind);
8685
+ { MaybeObject* maybe_obj =
8686
+ accessor->CopyElements(this, new_elements, new_elements_kind);
8687
+ if (maybe_obj->IsFailure()) return maybe_obj;
8688
+ }
8488
8689
  if (elements_kind != NON_STRICT_ARGUMENTS_ELEMENTS) {
8690
+ Map* new_map = map();
8691
+ if (new_elements_kind != elements_kind) {
8692
+ MaybeObject* maybe =
8693
+ GetElementsTransitionMap(GetIsolate(), new_elements_kind);
8694
+ if (!maybe->To(&new_map)) return maybe;
8695
+ }
8696
+ ValidateElements();
8489
8697
  set_map_and_elements(new_map, new_elements);
8490
8698
  } else {
8491
8699
  FixedArray* parameter_map = FixedArray::cast(old_elements);
@@ -8497,11 +8705,9 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength(
8497
8705
  GetElementsKind(), new_elements);
8498
8706
  }
8499
8707
 
8500
- // Update the length if necessary.
8501
8708
  if (IsJSArray()) {
8502
8709
  JSArray::cast(this)->set_length(Smi::FromInt(length));
8503
8710
  }
8504
-
8505
8711
  return new_elements;
8506
8712
  }
8507
8713
 
@@ -8513,23 +8719,34 @@ MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength(
8513
8719
  // We should never end in here with a pixel or external array.
8514
8720
  ASSERT(!HasExternalArrayElements());
8515
8721
 
8516
- FixedDoubleArray* elems;
8722
+ FixedArrayBase* elems;
8517
8723
  { MaybeObject* maybe_obj =
8518
8724
  heap->AllocateUninitializedFixedDoubleArray(capacity);
8519
8725
  if (!maybe_obj->To(&elems)) return maybe_obj;
8520
8726
  }
8521
8727
 
8728
+ ElementsKind elements_kind = GetElementsKind();
8729
+ ElementsKind new_elements_kind = elements_kind;
8730
+ if (IsHoleyElementsKind(elements_kind)) {
8731
+ new_elements_kind = FAST_HOLEY_DOUBLE_ELEMENTS;
8732
+ } else {
8733
+ new_elements_kind = FAST_DOUBLE_ELEMENTS;
8734
+ }
8735
+
8522
8736
  Map* new_map;
8523
8737
  { MaybeObject* maybe_obj =
8524
- GetElementsTransitionMap(heap->isolate(), FAST_DOUBLE_ELEMENTS);
8738
+ GetElementsTransitionMap(heap->isolate(), new_elements_kind);
8525
8739
  if (!maybe_obj->To(&new_map)) return maybe_obj;
8526
8740
  }
8527
8741
 
8528
8742
  FixedArrayBase* old_elements = elements();
8529
- ElementsKind elements_kind = GetElementsKind();
8530
8743
  ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
8531
- accessor->CopyElements(this, elems, FAST_DOUBLE_ELEMENTS);
8744
+ { MaybeObject* maybe_obj =
8745
+ accessor->CopyElements(this, elems, FAST_DOUBLE_ELEMENTS);
8746
+ if (maybe_obj->IsFailure()) return maybe_obj;
8747
+ }
8532
8748
  if (elements_kind != NON_STRICT_ARGUMENTS_ELEMENTS) {
8749
+ ValidateElements();
8533
8750
  set_map_and_elements(new_map, elems);
8534
8751
  } else {
8535
8752
  FixedArray* parameter_map = FixedArray::cast(old_elements);
@@ -8538,7 +8755,7 @@ MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength(
8538
8755
 
8539
8756
  if (FLAG_trace_elements_transitions) {
8540
8757
  PrintElementsTransition(stdout, elements_kind, old_elements,
8541
- FAST_DOUBLE_ELEMENTS, elems);
8758
+ GetElementsKind(), elems);
8542
8759
  }
8543
8760
 
8544
8761
  if (IsJSArray()) {
@@ -8818,8 +9035,10 @@ JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) {
8818
9035
  }
8819
9036
 
8820
9037
  switch (GetElementsKind()) {
8821
- case FAST_SMI_ONLY_ELEMENTS:
8822
- case FAST_ELEMENTS: {
9038
+ case FAST_SMI_ELEMENTS:
9039
+ case FAST_ELEMENTS:
9040
+ case FAST_HOLEY_SMI_ELEMENTS:
9041
+ case FAST_HOLEY_ELEMENTS: {
8823
9042
  uint32_t length = IsJSArray() ?
8824
9043
  static_cast<uint32_t>
8825
9044
  (Smi::cast(JSArray::cast(this)->length())->value()) :
@@ -8830,7 +9049,8 @@ JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) {
8830
9049
  }
8831
9050
  break;
8832
9051
  }
8833
- case FAST_DOUBLE_ELEMENTS: {
9052
+ case FAST_DOUBLE_ELEMENTS:
9053
+ case FAST_HOLEY_DOUBLE_ELEMENTS: {
8834
9054
  uint32_t length = IsJSArray() ?
8835
9055
  static_cast<uint32_t>
8836
9056
  (Smi::cast(JSArray::cast(this)->length())->value()) :
@@ -9114,7 +9334,7 @@ MaybeObject* JSObject::SetFastElement(uint32_t index,
9114
9334
  Object* value,
9115
9335
  StrictModeFlag strict_mode,
9116
9336
  bool check_prototype) {
9117
- ASSERT(HasFastTypeElements() ||
9337
+ ASSERT(HasFastSmiOrObjectElements() ||
9118
9338
  HasFastArgumentsElements());
9119
9339
 
9120
9340
  FixedArray* backing_store = FixedArray::cast(elements());
@@ -9140,13 +9360,29 @@ MaybeObject* JSObject::SetFastElement(uint32_t index,
9140
9360
  // Check if the length property of this object needs to be updated.
9141
9361
  uint32_t array_length = 0;
9142
9362
  bool must_update_array_length = false;
9363
+ bool introduces_holes = true;
9143
9364
  if (IsJSArray()) {
9144
9365
  CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
9366
+ introduces_holes = index > array_length;
9145
9367
  if (index >= array_length) {
9146
9368
  must_update_array_length = true;
9147
9369
  array_length = index + 1;
9148
9370
  }
9371
+ } else {
9372
+ introduces_holes = index >= capacity;
9149
9373
  }
9374
+
9375
+ // If the array is growing, and it's not growth by a single element at the
9376
+ // end, make sure that the ElementsKind is HOLEY.
9377
+ ElementsKind elements_kind = GetElementsKind();
9378
+ if (introduces_holes &&
9379
+ IsFastElementsKind(elements_kind) &&
9380
+ !IsFastHoleyElementsKind(elements_kind)) {
9381
+ ElementsKind transitioned_kind = GetHoleyElementsKind(elements_kind);
9382
+ MaybeObject* maybe = TransitionElementsKind(transitioned_kind);
9383
+ if (maybe->IsFailure()) return maybe;
9384
+ }
9385
+
9150
9386
  // Check if the capacity of the backing store needs to be increased, or if
9151
9387
  // a transition to slow elements is necessary.
9152
9388
  if (index >= capacity) {
@@ -9166,42 +9402,44 @@ MaybeObject* JSObject::SetFastElement(uint32_t index,
9166
9402
  }
9167
9403
  }
9168
9404
  // Convert to fast double elements if appropriate.
9169
- if (HasFastSmiOnlyElements() && !value->IsSmi() && value->IsNumber()) {
9405
+ if (HasFastSmiElements() && !value->IsSmi() && value->IsNumber()) {
9170
9406
  MaybeObject* maybe =
9171
9407
  SetFastDoubleElementsCapacityAndLength(new_capacity, array_length);
9172
9408
  if (maybe->IsFailure()) return maybe;
9173
9409
  FixedDoubleArray::cast(elements())->set(index, value->Number());
9410
+ ValidateElements();
9174
9411
  return value;
9175
9412
  }
9176
- // Change elements kind from SMI_ONLY to generic FAST if necessary.
9177
- if (HasFastSmiOnlyElements() && !value->IsSmi()) {
9413
+ // Change elements kind from Smi-only to generic FAST if necessary.
9414
+ if (HasFastSmiElements() && !value->IsSmi()) {
9178
9415
  Map* new_map;
9179
- { MaybeObject* maybe_new_map = GetElementsTransitionMap(GetIsolate(),
9180
- FAST_ELEMENTS);
9181
- if (!maybe_new_map->To(&new_map)) return maybe_new_map;
9182
- }
9416
+ ElementsKind kind = HasFastHoleyElements()
9417
+ ? FAST_HOLEY_ELEMENTS
9418
+ : FAST_ELEMENTS;
9419
+ MaybeObject* maybe_new_map = GetElementsTransitionMap(GetIsolate(),
9420
+ kind);
9421
+ if (!maybe_new_map->To(&new_map)) return maybe_new_map;
9422
+
9183
9423
  set_map(new_map);
9184
- if (FLAG_trace_elements_transitions) {
9185
- PrintElementsTransition(stdout, FAST_SMI_ONLY_ELEMENTS, elements(),
9186
- FAST_ELEMENTS, elements());
9187
- }
9188
9424
  }
9189
9425
  // Increase backing store capacity if that's been decided previously.
9190
9426
  if (new_capacity != capacity) {
9191
9427
  FixedArray* new_elements;
9192
- SetFastElementsCapacityMode set_capacity_mode =
9193
- value->IsSmi() && HasFastSmiOnlyElements()
9194
- ? kAllowSmiOnlyElements
9195
- : kDontAllowSmiOnlyElements;
9428
+ SetFastElementsCapacitySmiMode smi_mode =
9429
+ value->IsSmi() && HasFastSmiElements()
9430
+ ? kAllowSmiElements
9431
+ : kDontAllowSmiElements;
9196
9432
  { MaybeObject* maybe =
9197
9433
  SetFastElementsCapacityAndLength(new_capacity,
9198
9434
  array_length,
9199
- set_capacity_mode);
9435
+ smi_mode);
9200
9436
  if (!maybe->To(&new_elements)) return maybe;
9201
9437
  }
9202
9438
  new_elements->set(index, value);
9439
+ ValidateElements();
9203
9440
  return value;
9204
9441
  }
9442
+
9205
9443
  // Finally, set the new element and length.
9206
9444
  ASSERT(elements()->IsFixedArray());
9207
9445
  backing_store->set(index, value);
@@ -9325,20 +9563,21 @@ MaybeObject* JSObject::SetDictionaryElement(uint32_t index,
9325
9563
  } else {
9326
9564
  new_length = dictionary->max_number_key() + 1;
9327
9565
  }
9328
- SetFastElementsCapacityMode set_capacity_mode = FLAG_smi_only_arrays
9329
- ? kAllowSmiOnlyElements
9330
- : kDontAllowSmiOnlyElements;
9566
+ SetFastElementsCapacitySmiMode smi_mode = FLAG_smi_only_arrays
9567
+ ? kAllowSmiElements
9568
+ : kDontAllowSmiElements;
9331
9569
  bool has_smi_only_elements = false;
9332
9570
  bool should_convert_to_fast_double_elements =
9333
9571
  ShouldConvertToFastDoubleElements(&has_smi_only_elements);
9334
9572
  if (has_smi_only_elements) {
9335
- set_capacity_mode = kForceSmiOnlyElements;
9573
+ smi_mode = kForceSmiElements;
9336
9574
  }
9337
9575
  MaybeObject* result = should_convert_to_fast_double_elements
9338
9576
  ? SetFastDoubleElementsCapacityAndLength(new_length, new_length)
9339
9577
  : SetFastElementsCapacityAndLength(new_length,
9340
9578
  new_length,
9341
- set_capacity_mode);
9579
+ smi_mode);
9580
+ ValidateElements();
9342
9581
  if (result->IsFailure()) return result;
9343
9582
  #ifdef DEBUG
9344
9583
  if (FLAG_trace_normalization) {
@@ -9377,27 +9616,40 @@ MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement(
9377
9616
  // If the value object is not a heap number, switch to fast elements and try
9378
9617
  // again.
9379
9618
  bool value_is_smi = value->IsSmi();
9619
+ bool introduces_holes = true;
9620
+ uint32_t length = elms_length;
9621
+ if (IsJSArray()) {
9622
+ CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
9623
+ introduces_holes = index > length;
9624
+ } else {
9625
+ introduces_holes = index >= elms_length;
9626
+ }
9627
+
9380
9628
  if (!value->IsNumber()) {
9381
- Object* obj;
9382
- uint32_t length = elms_length;
9383
- if (IsJSArray()) {
9384
- CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
9385
- }
9386
9629
  MaybeObject* maybe_obj = SetFastElementsCapacityAndLength(
9387
9630
  elms_length,
9388
9631
  length,
9389
- kDontAllowSmiOnlyElements);
9390
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9391
- return SetFastElement(index,
9392
- value,
9393
- strict_mode,
9394
- check_prototype);
9632
+ kDontAllowSmiElements);
9633
+ if (maybe_obj->IsFailure()) return maybe_obj;
9634
+ maybe_obj = SetFastElement(index, value, strict_mode, check_prototype);
9635
+ if (maybe_obj->IsFailure()) return maybe_obj;
9636
+ ValidateElements();
9637
+ return maybe_obj;
9395
9638
  }
9396
9639
 
9397
9640
  double double_value = value_is_smi
9398
9641
  ? static_cast<double>(Smi::cast(value)->value())
9399
9642
  : HeapNumber::cast(value)->value();
9400
9643
 
9644
+ // If the array is growing, and it's not growth by a single element at the
9645
+ // end, make sure that the ElementsKind is HOLEY.
9646
+ ElementsKind elements_kind = GetElementsKind();
9647
+ if (introduces_holes && !IsFastHoleyElementsKind(elements_kind)) {
9648
+ ElementsKind transitioned_kind = GetHoleyElementsKind(elements_kind);
9649
+ MaybeObject* maybe = TransitionElementsKind(transitioned_kind);
9650
+ if (maybe->IsFailure()) return maybe;
9651
+ }
9652
+
9401
9653
  // Check whether there is extra space in the fixed array.
9402
9654
  if (index < elms_length) {
9403
9655
  FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
@@ -9419,13 +9671,11 @@ MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement(
9419
9671
  int new_capacity = NewElementsCapacity(index+1);
9420
9672
  if (!ShouldConvertToSlowElements(new_capacity)) {
9421
9673
  ASSERT(static_cast<uint32_t>(new_capacity) > index);
9422
- Object* obj;
9423
- { MaybeObject* maybe_obj =
9424
- SetFastDoubleElementsCapacityAndLength(new_capacity,
9425
- index + 1);
9426
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9427
- }
9674
+ MaybeObject* maybe_obj =
9675
+ SetFastDoubleElementsCapacityAndLength(new_capacity, index + 1);
9676
+ if (maybe_obj->IsFailure()) return maybe_obj;
9428
9677
  FixedDoubleArray::cast(elements())->set(index, double_value);
9678
+ ValidateElements();
9429
9679
  return value;
9430
9680
  }
9431
9681
  }
@@ -9450,7 +9700,7 @@ MaybeObject* JSReceiver::SetElement(uint32_t index,
9450
9700
  bool check_proto) {
9451
9701
  if (IsJSProxy()) {
9452
9702
  return JSProxy::cast(this)->SetElementWithHandler(
9453
- index, value, strict_mode);
9703
+ this, index, value, strict_mode);
9454
9704
  } else {
9455
9705
  return JSObject::cast(this)->SetElement(
9456
9706
  index, value, attributes, strict_mode, check_proto);
@@ -9569,10 +9819,13 @@ MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
9569
9819
  (attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) == 0);
9570
9820
  Isolate* isolate = GetIsolate();
9571
9821
  switch (GetElementsKind()) {
9572
- case FAST_SMI_ONLY_ELEMENTS:
9822
+ case FAST_SMI_ELEMENTS:
9573
9823
  case FAST_ELEMENTS:
9824
+ case FAST_HOLEY_SMI_ELEMENTS:
9825
+ case FAST_HOLEY_ELEMENTS:
9574
9826
  return SetFastElement(index, value, strict_mode, check_prototype);
9575
9827
  case FAST_DOUBLE_ELEMENTS:
9828
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
9576
9829
  return SetFastDoubleElement(index, value, strict_mode, check_prototype);
9577
9830
  case EXTERNAL_PIXEL_ELEMENTS: {
9578
9831
  ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
@@ -9663,10 +9916,19 @@ Handle<Object> JSObject::TransitionElementsKind(Handle<JSObject> object,
9663
9916
  MaybeObject* JSObject::TransitionElementsKind(ElementsKind to_kind) {
9664
9917
  ElementsKind from_kind = map()->elements_kind();
9665
9918
 
9919
+ if (IsFastHoleyElementsKind(from_kind)) {
9920
+ to_kind = GetHoleyElementsKind(to_kind);
9921
+ }
9922
+
9666
9923
  Isolate* isolate = GetIsolate();
9667
- if (from_kind == FAST_SMI_ONLY_ELEMENTS &&
9668
- (to_kind == FAST_ELEMENTS ||
9669
- elements() == isolate->heap()->empty_fixed_array())) {
9924
+ if (elements() == isolate->heap()->empty_fixed_array() ||
9925
+ (IsFastSmiOrObjectElementsKind(from_kind) &&
9926
+ IsFastSmiOrObjectElementsKind(to_kind)) ||
9927
+ (from_kind == FAST_DOUBLE_ELEMENTS &&
9928
+ to_kind == FAST_HOLEY_DOUBLE_ELEMENTS)) {
9929
+ ASSERT(from_kind != TERMINAL_FAST_ELEMENTS_KIND);
9930
+ // No change is needed to the elements() buffer, the transition
9931
+ // only requires a map change.
9670
9932
  MaybeObject* maybe_new_map = GetElementsTransitionMap(isolate, to_kind);
9671
9933
  Map* new_map;
9672
9934
  if (!maybe_new_map->To(&new_map)) return maybe_new_map;
@@ -9693,18 +9955,21 @@ MaybeObject* JSObject::TransitionElementsKind(ElementsKind to_kind) {
9693
9955
  }
9694
9956
  }
9695
9957
 
9696
- if (from_kind == FAST_SMI_ONLY_ELEMENTS &&
9697
- to_kind == FAST_DOUBLE_ELEMENTS) {
9958
+ if (IsFastSmiElementsKind(from_kind) &&
9959
+ IsFastDoubleElementsKind(to_kind)) {
9698
9960
  MaybeObject* maybe_result =
9699
9961
  SetFastDoubleElementsCapacityAndLength(capacity, length);
9700
9962
  if (maybe_result->IsFailure()) return maybe_result;
9963
+ ValidateElements();
9701
9964
  return this;
9702
9965
  }
9703
9966
 
9704
- if (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS) {
9967
+ if (IsFastDoubleElementsKind(from_kind) &&
9968
+ IsFastObjectElementsKind(to_kind)) {
9705
9969
  MaybeObject* maybe_result = SetFastElementsCapacityAndLength(
9706
- capacity, length, kDontAllowSmiOnlyElements);
9970
+ capacity, length, kDontAllowSmiElements);
9707
9971
  if (maybe_result->IsFailure()) return maybe_result;
9972
+ ValidateElements();
9708
9973
  return this;
9709
9974
  }
9710
9975
 
@@ -9718,10 +9983,14 @@ MaybeObject* JSObject::TransitionElementsKind(ElementsKind to_kind) {
9718
9983
  // static
9719
9984
  bool Map::IsValidElementsTransition(ElementsKind from_kind,
9720
9985
  ElementsKind to_kind) {
9721
- return
9722
- (from_kind == FAST_SMI_ONLY_ELEMENTS &&
9723
- (to_kind == FAST_DOUBLE_ELEMENTS || to_kind == FAST_ELEMENTS)) ||
9724
- (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS);
9986
+ // Transitions can't go backwards.
9987
+ if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) {
9988
+ return false;
9989
+ }
9990
+
9991
+ // Transitions from HOLEY -> PACKED are not allowed.
9992
+ return !IsFastHoleyElementsKind(from_kind) ||
9993
+ IsFastHoleyElementsKind(to_kind);
9725
9994
  }
9726
9995
 
9727
9996
 
@@ -9812,8 +10081,10 @@ void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) {
9812
10081
  break;
9813
10082
  }
9814
10083
  // Fall through.
9815
- case FAST_SMI_ONLY_ELEMENTS:
10084
+ case FAST_SMI_ELEMENTS:
9816
10085
  case FAST_ELEMENTS:
10086
+ case FAST_HOLEY_SMI_ELEMENTS:
10087
+ case FAST_HOLEY_ELEMENTS:
9817
10088
  backing_store = FixedArray::cast(backing_store_base);
9818
10089
  *capacity = backing_store->length();
9819
10090
  for (int i = 0; i < *capacity; ++i) {
@@ -9827,7 +10098,8 @@ void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) {
9827
10098
  *used = dictionary->NumberOfElements();
9828
10099
  break;
9829
10100
  }
9830
- case FAST_DOUBLE_ELEMENTS: {
10101
+ case FAST_DOUBLE_ELEMENTS:
10102
+ case FAST_HOLEY_DOUBLE_ELEMENTS: {
9831
10103
  FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
9832
10104
  *capacity = elms->length();
9833
10105
  for (int i = 0; i < *capacity; i++) {
@@ -10097,16 +10369,19 @@ bool JSObject::HasRealElementProperty(uint32_t index) {
10097
10369
  if (this->IsStringObjectWithCharacterAt(index)) return true;
10098
10370
 
10099
10371
  switch (GetElementsKind()) {
10100
- case FAST_SMI_ONLY_ELEMENTS:
10101
- case FAST_ELEMENTS: {
10102
- uint32_t length = IsJSArray() ?
10372
+ case FAST_SMI_ELEMENTS:
10373
+ case FAST_ELEMENTS:
10374
+ case FAST_HOLEY_SMI_ELEMENTS:
10375
+ case FAST_HOLEY_ELEMENTS: {
10376
+ uint32_t length = IsJSArray() ?
10103
10377
  static_cast<uint32_t>(
10104
10378
  Smi::cast(JSArray::cast(this)->length())->value()) :
10105
10379
  static_cast<uint32_t>(FixedArray::cast(elements())->length());
10106
10380
  return (index < length) &&
10107
10381
  !FixedArray::cast(elements())->get(index)->IsTheHole();
10108
10382
  }
10109
- case FAST_DOUBLE_ELEMENTS: {
10383
+ case FAST_DOUBLE_ELEMENTS:
10384
+ case FAST_HOLEY_DOUBLE_ELEMENTS: {
10110
10385
  uint32_t length = IsJSArray() ?
10111
10386
  static_cast<uint32_t>(
10112
10387
  Smi::cast(JSArray::cast(this)->length())->value()) :
@@ -10306,7 +10581,7 @@ int JSObject::NumberOfLocalElements(PropertyAttributes filter) {
10306
10581
 
10307
10582
  int JSObject::NumberOfEnumElements() {
10308
10583
  // Fast case for objects with no elements.
10309
- if (!IsJSValue() && HasFastElements()) {
10584
+ if (!IsJSValue() && HasFastObjectElements()) {
10310
10585
  uint32_t length = IsJSArray() ?
10311
10586
  static_cast<uint32_t>(
10312
10587
  Smi::cast(JSArray::cast(this)->length())->value()) :
@@ -10322,8 +10597,10 @@ int JSObject::GetLocalElementKeys(FixedArray* storage,
10322
10597
  PropertyAttributes filter) {
10323
10598
  int counter = 0;
10324
10599
  switch (GetElementsKind()) {
10325
- case FAST_SMI_ONLY_ELEMENTS:
10326
- case FAST_ELEMENTS: {
10600
+ case FAST_SMI_ELEMENTS:
10601
+ case FAST_ELEMENTS:
10602
+ case FAST_HOLEY_SMI_ELEMENTS:
10603
+ case FAST_HOLEY_ELEMENTS: {
10327
10604
  int length = IsJSArray() ?
10328
10605
  Smi::cast(JSArray::cast(this)->length())->value() :
10329
10606
  FixedArray::cast(elements())->length();
@@ -10338,7 +10615,8 @@ int JSObject::GetLocalElementKeys(FixedArray* storage,
10338
10615
  ASSERT(!storage || storage->length() >= counter);
10339
10616
  break;
10340
10617
  }
10341
- case FAST_DOUBLE_ELEMENTS: {
10618
+ case FAST_DOUBLE_ELEMENTS:
10619
+ case FAST_HOLEY_DOUBLE_ELEMENTS: {
10342
10620
  int length = IsJSArray() ?
10343
10621
  Smi::cast(JSArray::cast(this)->length())->value() :
10344
10622
  FixedDoubleArray::cast(elements())->length();
@@ -11271,10 +11549,9 @@ MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
11271
11549
  // Convert to fast elements.
11272
11550
 
11273
11551
  Object* obj;
11274
- { MaybeObject* maybe_obj = GetElementsTransitionMap(GetIsolate(),
11275
- FAST_ELEMENTS);
11276
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11277
- }
11552
+ MaybeObject* maybe_obj = GetElementsTransitionMap(GetIsolate(),
11553
+ FAST_HOLEY_ELEMENTS);
11554
+ if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11278
11555
  Map* new_map = Map::cast(obj);
11279
11556
 
11280
11557
  PretenureFlag tenure = heap->InNewSpace(this) ? NOT_TENURED: TENURED;
@@ -11285,9 +11562,9 @@ MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
11285
11562
  }
11286
11563
  FixedArray* fast_elements = FixedArray::cast(new_array);
11287
11564
  dict->CopyValuesTo(fast_elements);
11565
+ ValidateElements();
11288
11566
 
11289
- set_map(new_map);
11290
- set_elements(fast_elements);
11567
+ set_map_and_elements(new_map, fast_elements);
11291
11568
  } else if (HasExternalArrayElements()) {
11292
11569
  // External arrays cannot have holes or undefined elements.
11293
11570
  return Smi::FromInt(ExternalArray::cast(elements())->length());
@@ -11297,7 +11574,7 @@ MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
11297
11574
  if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11298
11575
  }
11299
11576
  }
11300
- ASSERT(HasFastTypeElements() || HasFastDoubleElements());
11577
+ ASSERT(HasFastSmiOrObjectElements() || HasFastDoubleElements());
11301
11578
 
11302
11579
  // Collect holes at the end, undefined before that and the rest at the
11303
11580
  // start, and return the number of non-hole, non-undefined values.
@@ -12844,7 +13121,7 @@ int BreakPointInfo::GetBreakPointCount() {
12844
13121
  #endif // ENABLE_DEBUGGER_SUPPORT
12845
13122
 
12846
13123
 
12847
- MaybeObject* JSDate::GetField(Object* object, Smi* index) {
13124
+ Object* JSDate::GetField(Object* object, Smi* index) {
12848
13125
  return JSDate::cast(object)->DoGetField(
12849
13126
  static_cast<FieldIndex>(index->value()));
12850
13127
  }