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.
- data/Rakefile +10 -3
- data/ext/libv8/compiler.rb +46 -0
- data/ext/libv8/extconf.rb +5 -1
- data/ext/libv8/make.rb +13 -0
- data/lib/libv8/version.rb +1 -1
- data/patches/add-freebsd9-and-freebsd10-to-gyp-GetFlavor.patch +11 -0
- data/patches/src_platform-freebsd.cc.patch +10 -0
- data/vendor/v8/ChangeLog +124 -0
- data/vendor/v8/DEPS +27 -0
- data/vendor/v8/Makefile +7 -0
- data/vendor/v8/SConstruct +15 -2
- data/vendor/v8/build/common.gypi +129 -157
- data/vendor/v8/build/gyp_v8 +11 -25
- data/vendor/v8/build/standalone.gypi +9 -3
- data/vendor/v8/include/v8.h +5 -3
- data/vendor/v8/src/SConscript +1 -0
- data/vendor/v8/src/api.cc +4 -33
- data/vendor/v8/src/api.h +2 -2
- data/vendor/v8/src/arm/builtins-arm.cc +5 -4
- data/vendor/v8/src/arm/code-stubs-arm.cc +21 -14
- data/vendor/v8/src/arm/codegen-arm.cc +2 -2
- data/vendor/v8/src/arm/debug-arm.cc +3 -1
- data/vendor/v8/src/arm/full-codegen-arm.cc +3 -102
- data/vendor/v8/src/arm/ic-arm.cc +30 -33
- data/vendor/v8/src/arm/lithium-arm.cc +20 -7
- data/vendor/v8/src/arm/lithium-arm.h +10 -4
- data/vendor/v8/src/arm/lithium-codegen-arm.cc +106 -60
- data/vendor/v8/src/arm/macro-assembler-arm.cc +49 -39
- data/vendor/v8/src/arm/macro-assembler-arm.h +5 -4
- data/vendor/v8/src/arm/regexp-macro-assembler-arm.cc +115 -55
- data/vendor/v8/src/arm/regexp-macro-assembler-arm.h +7 -6
- data/vendor/v8/src/arm/simulator-arm.h +6 -6
- data/vendor/v8/src/arm/stub-cache-arm.cc +64 -19
- data/vendor/v8/src/array.js +7 -3
- data/vendor/v8/src/ast.cc +11 -6
- data/vendor/v8/src/bootstrapper.cc +9 -11
- data/vendor/v8/src/builtins.cc +61 -31
- data/vendor/v8/src/code-stubs.cc +23 -9
- data/vendor/v8/src/code-stubs.h +1 -0
- data/vendor/v8/src/codegen.h +3 -3
- data/vendor/v8/src/compiler.cc +1 -1
- data/vendor/v8/src/contexts.h +2 -18
- data/vendor/v8/src/d8.cc +94 -93
- data/vendor/v8/src/d8.h +1 -1
- data/vendor/v8/src/debug-agent.cc +3 -3
- data/vendor/v8/src/debug.cc +41 -1
- data/vendor/v8/src/debug.h +50 -0
- data/vendor/v8/src/elements-kind.cc +134 -0
- data/vendor/v8/src/elements-kind.h +210 -0
- data/vendor/v8/src/elements.cc +356 -190
- data/vendor/v8/src/elements.h +36 -28
- data/vendor/v8/src/factory.cc +44 -4
- data/vendor/v8/src/factory.h +11 -7
- data/vendor/v8/src/flag-definitions.h +3 -0
- data/vendor/v8/src/frames.h +3 -0
- data/vendor/v8/src/full-codegen.cc +2 -1
- data/vendor/v8/src/func-name-inferrer.h +2 -0
- data/vendor/v8/src/globals.h +3 -0
- data/vendor/v8/src/heap-inl.h +16 -4
- data/vendor/v8/src/heap.cc +38 -32
- data/vendor/v8/src/heap.h +3 -17
- data/vendor/v8/src/hydrogen-instructions.cc +28 -5
- data/vendor/v8/src/hydrogen-instructions.h +142 -44
- data/vendor/v8/src/hydrogen.cc +160 -55
- data/vendor/v8/src/hydrogen.h +2 -0
- data/vendor/v8/src/ia32/assembler-ia32.h +3 -0
- data/vendor/v8/src/ia32/builtins-ia32.cc +5 -4
- data/vendor/v8/src/ia32/code-stubs-ia32.cc +22 -16
- data/vendor/v8/src/ia32/codegen-ia32.cc +2 -2
- data/vendor/v8/src/ia32/debug-ia32.cc +29 -2
- data/vendor/v8/src/ia32/full-codegen-ia32.cc +8 -101
- data/vendor/v8/src/ia32/ic-ia32.cc +23 -19
- data/vendor/v8/src/ia32/lithium-codegen-ia32.cc +126 -80
- data/vendor/v8/src/ia32/lithium-codegen-ia32.h +2 -1
- data/vendor/v8/src/ia32/lithium-ia32.cc +15 -9
- data/vendor/v8/src/ia32/lithium-ia32.h +14 -6
- data/vendor/v8/src/ia32/macro-assembler-ia32.cc +50 -40
- data/vendor/v8/src/ia32/macro-assembler-ia32.h +5 -4
- data/vendor/v8/src/ia32/regexp-macro-assembler-ia32.cc +113 -43
- data/vendor/v8/src/ia32/regexp-macro-assembler-ia32.h +9 -4
- data/vendor/v8/src/ia32/simulator-ia32.h +4 -4
- data/vendor/v8/src/ia32/stub-cache-ia32.cc +52 -14
- data/vendor/v8/src/ic.cc +77 -20
- data/vendor/v8/src/ic.h +18 -2
- data/vendor/v8/src/incremental-marking-inl.h +21 -5
- data/vendor/v8/src/incremental-marking.cc +35 -8
- data/vendor/v8/src/incremental-marking.h +12 -3
- data/vendor/v8/src/isolate.cc +12 -2
- data/vendor/v8/src/isolate.h +1 -1
- data/vendor/v8/src/jsregexp.cc +66 -26
- data/vendor/v8/src/jsregexp.h +60 -31
- data/vendor/v8/src/list-inl.h +8 -0
- data/vendor/v8/src/list.h +3 -0
- data/vendor/v8/src/lithium.cc +5 -2
- data/vendor/v8/src/liveedit.cc +57 -5
- data/vendor/v8/src/mark-compact-inl.h +17 -11
- data/vendor/v8/src/mark-compact.cc +100 -143
- data/vendor/v8/src/mark-compact.h +44 -20
- data/vendor/v8/src/messages.js +131 -99
- data/vendor/v8/src/mips/builtins-mips.cc +5 -4
- data/vendor/v8/src/mips/code-stubs-mips.cc +23 -15
- data/vendor/v8/src/mips/codegen-mips.cc +2 -2
- data/vendor/v8/src/mips/debug-mips.cc +3 -1
- data/vendor/v8/src/mips/full-codegen-mips.cc +4 -102
- data/vendor/v8/src/mips/ic-mips.cc +34 -36
- data/vendor/v8/src/mips/lithium-codegen-mips.cc +116 -68
- data/vendor/v8/src/mips/lithium-mips.cc +20 -7
- data/vendor/v8/src/mips/lithium-mips.h +11 -4
- data/vendor/v8/src/mips/macro-assembler-mips.cc +50 -39
- data/vendor/v8/src/mips/macro-assembler-mips.h +5 -4
- data/vendor/v8/src/mips/regexp-macro-assembler-mips.cc +110 -50
- data/vendor/v8/src/mips/regexp-macro-assembler-mips.h +6 -5
- data/vendor/v8/src/mips/simulator-mips.h +5 -5
- data/vendor/v8/src/mips/stub-cache-mips.cc +66 -20
- data/vendor/v8/src/mksnapshot.cc +5 -1
- data/vendor/v8/src/objects-debug.cc +103 -6
- data/vendor/v8/src/objects-inl.h +215 -116
- data/vendor/v8/src/objects-printer.cc +13 -8
- data/vendor/v8/src/objects.cc +608 -331
- data/vendor/v8/src/objects.h +129 -94
- data/vendor/v8/src/parser.cc +16 -4
- data/vendor/v8/src/platform-freebsd.cc +1 -0
- data/vendor/v8/src/platform-linux.cc +9 -30
- data/vendor/v8/src/platform-posix.cc +28 -7
- data/vendor/v8/src/platform-win32.cc +15 -3
- data/vendor/v8/src/platform.h +2 -1
- data/vendor/v8/src/profile-generator-inl.h +25 -2
- data/vendor/v8/src/profile-generator.cc +300 -822
- data/vendor/v8/src/profile-generator.h +97 -214
- data/vendor/v8/src/regexp-macro-assembler-irregexp.cc +2 -1
- data/vendor/v8/src/regexp-macro-assembler-irregexp.h +2 -2
- data/vendor/v8/src/regexp-macro-assembler-tracer.cc +6 -5
- data/vendor/v8/src/regexp-macro-assembler-tracer.h +1 -1
- data/vendor/v8/src/regexp-macro-assembler.cc +7 -3
- data/vendor/v8/src/regexp-macro-assembler.h +10 -2
- data/vendor/v8/src/regexp.js +6 -0
- data/vendor/v8/src/runtime.cc +265 -212
- data/vendor/v8/src/runtime.h +6 -5
- data/vendor/v8/src/scopes.cc +20 -0
- data/vendor/v8/src/scopes.h +6 -3
- data/vendor/v8/src/spaces.cc +0 -2
- data/vendor/v8/src/string-stream.cc +2 -2
- data/vendor/v8/src/v8-counters.h +0 -2
- data/vendor/v8/src/v8natives.js +2 -2
- data/vendor/v8/src/v8utils.h +6 -3
- data/vendor/v8/src/version.cc +1 -1
- data/vendor/v8/src/x64/assembler-x64.h +2 -1
- data/vendor/v8/src/x64/builtins-x64.cc +5 -4
- data/vendor/v8/src/x64/code-stubs-x64.cc +25 -16
- data/vendor/v8/src/x64/codegen-x64.cc +2 -2
- data/vendor/v8/src/x64/debug-x64.cc +14 -1
- data/vendor/v8/src/x64/disasm-x64.cc +1 -1
- data/vendor/v8/src/x64/full-codegen-x64.cc +10 -106
- data/vendor/v8/src/x64/ic-x64.cc +20 -16
- data/vendor/v8/src/x64/lithium-codegen-x64.cc +156 -79
- data/vendor/v8/src/x64/lithium-codegen-x64.h +2 -1
- data/vendor/v8/src/x64/lithium-x64.cc +18 -8
- data/vendor/v8/src/x64/lithium-x64.h +7 -2
- data/vendor/v8/src/x64/macro-assembler-x64.cc +50 -40
- data/vendor/v8/src/x64/macro-assembler-x64.h +5 -4
- data/vendor/v8/src/x64/regexp-macro-assembler-x64.cc +122 -51
- data/vendor/v8/src/x64/regexp-macro-assembler-x64.h +17 -8
- data/vendor/v8/src/x64/simulator-x64.h +4 -4
- data/vendor/v8/src/x64/stub-cache-x64.cc +55 -17
- data/vendor/v8/test/cctest/cctest.status +1 -0
- data/vendor/v8/test/cctest/test-api.cc +24 -0
- data/vendor/v8/test/cctest/test-func-name-inference.cc +38 -0
- data/vendor/v8/test/cctest/test-heap-profiler.cc +21 -77
- data/vendor/v8/test/cctest/test-heap.cc +164 -3
- data/vendor/v8/test/cctest/test-list.cc +12 -0
- data/vendor/v8/test/cctest/test-mark-compact.cc +5 -5
- data/vendor/v8/test/cctest/test-regexp.cc +14 -8
- data/vendor/v8/test/cctest/testcfg.py +2 -0
- data/vendor/v8/test/mjsunit/accessor-map-sharing.js +176 -0
- data/vendor/v8/test/mjsunit/array-construct-transition.js +3 -3
- data/vendor/v8/test/mjsunit/array-literal-transitions.js +10 -10
- data/vendor/v8/test/mjsunit/big-array-literal.js +3 -0
- data/vendor/v8/test/mjsunit/compiler/inline-construct.js +4 -2
- data/vendor/v8/test/mjsunit/debug-liveedit-stack-padding.js +88 -0
- data/vendor/v8/test/mjsunit/elements-kind.js +4 -4
- data/vendor/v8/test/mjsunit/elements-transition-hoisting.js +2 -2
- data/vendor/v8/test/mjsunit/elements-transition.js +5 -5
- data/vendor/v8/test/mjsunit/error-constructors.js +68 -33
- data/vendor/v8/test/mjsunit/harmony/proxies.js +14 -6
- data/vendor/v8/test/mjsunit/mjsunit.status +1 -0
- data/vendor/v8/test/mjsunit/packed-elements.js +112 -0
- data/vendor/v8/test/mjsunit/regexp-capture-3.js +6 -0
- data/vendor/v8/test/mjsunit/regexp-global.js +132 -0
- data/vendor/v8/test/mjsunit/regexp.js +11 -0
- data/vendor/v8/test/mjsunit/regress/regress-117409.js +52 -0
- data/vendor/v8/test/mjsunit/regress/regress-126412.js +33 -0
- data/vendor/v8/test/mjsunit/regress/regress-128018.js +35 -0
- data/vendor/v8/test/mjsunit/regress/regress-128146.js +33 -0
- data/vendor/v8/test/mjsunit/regress/regress-1639-2.js +4 -1
- data/vendor/v8/test/mjsunit/regress/regress-1639.js +14 -8
- data/vendor/v8/test/mjsunit/regress/regress-1849.js +3 -3
- data/vendor/v8/test/mjsunit/regress/regress-1878.js +2 -2
- data/vendor/v8/test/mjsunit/regress/regress-2071.js +79 -0
- data/vendor/v8/test/mjsunit/regress/regress-2153.js +32 -0
- data/vendor/v8/test/mjsunit/regress/regress-crbug-122271.js +4 -4
- data/vendor/v8/test/mjsunit/regress/regress-crbug-126414.js +32 -0
- data/vendor/v8/test/mjsunit/regress/regress-smi-only-concat.js +2 -2
- data/vendor/v8/test/mjsunit/regress/regress-transcendental.js +49 -0
- data/vendor/v8/test/mjsunit/stack-traces.js +14 -0
- data/vendor/v8/test/mjsunit/unbox-double-arrays.js +4 -3
- data/vendor/v8/test/test262/testcfg.py +6 -1
- data/vendor/v8/tools/check-static-initializers.sh +11 -3
- data/vendor/v8/tools/fuzz-harness.sh +92 -0
- data/vendor/v8/tools/grokdump.py +658 -67
- data/vendor/v8/tools/gyp/v8.gyp +21 -39
- data/vendor/v8/tools/js2c.py +3 -3
- data/vendor/v8/tools/jsmin.py +2 -2
- data/vendor/v8/tools/presubmit.py +2 -1
- data/vendor/v8/tools/test-wrapper-gypbuild.py +25 -11
- 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
|
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
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
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
|
}
|
data/vendor/v8/src/objects.cc
CHANGED
@@ -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(
|
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
|
-
|| !
|
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()->
|
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
|
2203
|
-
|
2204
|
-
|
2205
|
-
|
2206
|
-
|
2207
|
-
|
2208
|
-
|
2209
|
-
|
2210
|
-
|
2211
|
-
|
2212
|
-
|
2213
|
-
|
2214
|
-
|
2215
|
-
|
2216
|
-
|
2217
|
-
|
2218
|
-
|
2219
|
-
|
2220
|
-
|
2221
|
-
|
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
|
2334
|
+
Map* Map::LookupElementsTransitionMap(ElementsKind to_kind,
|
2339
2335
|
bool* safe_to_add_transition) {
|
2340
|
-
|
2341
|
-
|
2342
|
-
|
2343
|
-
|
2344
|
-
|
2345
|
-
|
2346
|
-
|
2347
|
-
|
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
|
-
|
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
|
2371
|
+
MaybeObject* Map::AddElementsTransition(ElementsKind to_kind,
|
2364
2372
|
Map* transitioned_map) {
|
2365
|
-
|
2366
|
-
|
2367
|
-
|
2368
|
-
|
2369
|
-
|
2370
|
-
|
2371
|
-
|
2372
|
-
|
2373
|
-
//
|
2374
|
-
|
2375
|
-
|
2376
|
-
|
2377
|
-
|
2378
|
-
|
2379
|
-
|
2380
|
-
|
2381
|
-
|
2382
|
-
|
2383
|
-
|
2384
|
-
|
2385
|
-
|
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 ->
|
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
|
2439
|
-
if (from_kind == DICTIONARY_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<
|
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
|
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
|
-
|
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(
|
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->
|
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
|
4022
|
+
ASSERT(IsFastObjectElementsKind(kind) ||
|
4000
4023
|
kind == DICTIONARY_ELEMENTS);
|
4001
|
-
if (kind
|
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
|
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 :
|
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
|
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
|
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
|
-
|
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
|
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
|
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 (
|
5101
|
+
if (HasDescriptors()) *DescriptorArrayHeader() = Smi::FromInt(0);
|
4889
5102
|
}
|
4890
5103
|
|
4891
5104
|
bool IsIterating() {
|
4892
|
-
return
|
5105
|
+
return HasDescriptors() && (*DescriptorArrayHeader())->IsSmi();
|
4893
5106
|
}
|
4894
5107
|
|
4895
5108
|
Map* Next() {
|
4896
5109
|
ASSERT(IsIterating());
|
4897
|
-
|
4898
|
-
//
|
4899
|
-
//
|
4900
|
-
//
|
4901
|
-
//
|
4902
|
-
int
|
4903
|
-
|
4904
|
-
|
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
|
-
*
|
4911
|
-
return static_cast<Map*>(
|
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*>(
|
4916
|
-
Object* accessor
|
4917
|
-
|
4918
|
-
|
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
|
-
*
|
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
|
-
|
5152
|
+
raw_index += 2;
|
5153
|
+
++index;
|
4933
5154
|
break;
|
4934
5155
|
}
|
4935
5156
|
}
|
4936
|
-
*
|
5157
|
+
*DescriptorArrayHeader() = descriptor_array_->GetHeap()->fixed_array_map();
|
4937
5158
|
return NULL;
|
4938
5159
|
}
|
4939
5160
|
|
4940
5161
|
private:
|
4941
|
-
bool
|
4942
|
-
return descriptor_array_->
|
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
|
-
|
4946
|
-
|
4947
|
-
|
5176
|
+
Object* RawGetValue(int descriptor_number) {
|
5177
|
+
return RawGetContentArray()->get(
|
5178
|
+
DescriptorArray::ToValueIndex(descriptor_number));
|
4948
5179
|
}
|
4949
5180
|
|
4950
|
-
|
4951
|
-
|
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(
|
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_->
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
5732
|
-
|
5733
|
-
|
5734
|
-
|
5735
|
-
|
5736
|
-
|
5737
|
-
|
5738
|
-
|
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
|
-
|
5943
|
-
|
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
|
-
|
7172
|
-
|
7173
|
-
|
7174
|
-
|
7175
|
-
|
7176
|
-
|
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
|
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
|
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
|
-
|
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
|
-
|
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 (
|
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 (
|
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 (
|
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
|
-
|
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
|
-
|
8464
|
-
|
8465
|
-
if
|
8466
|
-
|
8467
|
-
|
8468
|
-
|
8469
|
-
|
8470
|
-
|
8471
|
-
|
8472
|
-
|
8473
|
-
|
8474
|
-
|
8475
|
-
|
8476
|
-
|
8477
|
-
if (
|
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
|
-
|
8484
|
-
|
8485
|
-
|
8486
|
-
|
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
|
-
|
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(),
|
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
|
-
|
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
|
-
|
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
|
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(
|
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 (
|
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
|
9177
|
-
if (
|
9413
|
+
// Change elements kind from Smi-only to generic FAST if necessary.
|
9414
|
+
if (HasFastSmiElements() && !value->IsSmi()) {
|
9178
9415
|
Map* new_map;
|
9179
|
-
|
9180
|
-
|
9181
|
-
|
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
|
-
|
9193
|
-
value->IsSmi() &&
|
9194
|
-
?
|
9195
|
-
:
|
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
|
-
|
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
|
-
|
9329
|
-
?
|
9330
|
-
:
|
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
|
-
|
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
|
-
|
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
|
-
|
9390
|
-
if (
|
9391
|
-
|
9392
|
-
|
9393
|
-
|
9394
|
-
|
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
|
-
|
9423
|
-
|
9424
|
-
|
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
|
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 (
|
9668
|
-
(
|
9669
|
-
|
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
|
9697
|
-
to_kind
|
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
|
9967
|
+
if (IsFastDoubleElementsKind(from_kind) &&
|
9968
|
+
IsFastObjectElementsKind(to_kind)) {
|
9705
9969
|
MaybeObject* maybe_result = SetFastElementsCapacityAndLength(
|
9706
|
-
capacity, length,
|
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
|
-
|
9722
|
-
|
9723
|
-
|
9724
|
-
|
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
|
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
|
10101
|
-
case FAST_ELEMENTS:
|
10102
|
-
|
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() &&
|
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
|
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
|
-
|
11275
|
-
|
11276
|
-
|
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
|
-
|
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(
|
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
|
-
|
13124
|
+
Object* JSDate::GetField(Object* object, Smi* index) {
|
12848
13125
|
return JSDate::cast(object)->DoGetField(
|
12849
13126
|
static_cast<FieldIndex>(index->value()));
|
12850
13127
|
}
|