| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 554fa24 commit 2db2857
6 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -104,6 +104,17 @@ class V8_EXPORT_PRIVATE Graph final : public NON_EXPORTED_BASE(ZoneObject) { | |||
| 104 | 104 | Node* nodes[] = {n1, n2, n3, n4, n5, n6, n7, n8, n9}; | |
| 105 | 105 | return NewNode(op, arraysize(nodes), nodes); | |
| 106 | 106 | } | |
| 107 | + Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3, Node* n4, | ||
| 108 | + Node* n5, Node* n6, Node* n7, Node* n8, Node* n9, Node* n10) { | ||
| 109 | + Node* nodes[] = {n1, n2, n3, n4, n5, n6, n7, n8, n9, n10}; | ||
| 110 | + return NewNode(op, arraysize(nodes), nodes); | ||
| 111 | + } | ||
| 112 | + Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3, Node* n4, | ||
| 113 | + Node* n5, Node* n6, Node* n7, Node* n8, Node* n9, Node* n10, | ||
| 114 | + Node* n11) { | ||
| 115 | + Node* nodes[] = {n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11}; | ||
| 116 | + return NewNode(op, arraysize(nodes), nodes); | ||
| 117 | + } | ||
| 107 | 118 | ||
| 108 | 119 | // Clone the {node}, and assign a new node id to the copy. | |
| 109 | 120 | Node* CloneNode(const Node* node); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -5,6 +5,7 @@ | |||
| 5 | 5 | #include "src/compiler/js-builtin-reducer.h" | |
| 6 | 6 | ||
| 7 | 7 | #include "src/base/bits.h" | |
| 8 | + #include "src/builtins/builtins-utils.h" | ||
| 8 | 9 | #include "src/code-factory.h" | |
| 9 | 10 | #include "src/compilation-dependencies.h" | |
| 10 | 11 | #include "src/compiler/access-builder.h" | |
@@ -1005,6 +1006,179 @@ Reduction JSBuiltinReducer::ReduceArrayPush(Node* node) { | |||
| 1005 | 1006 | return NoChange(); | |
| 1006 | 1007 | } | |
| 1007 | 1008 | ||
| 1009 | + // ES6 section 22.1.3.22 Array.prototype.shift ( ) | ||
| 1010 | + Reduction JSBuiltinReducer::ReduceArrayShift(Node* node) { | ||
| 1011 | + Node* target = NodeProperties::GetValueInput(node, 0); | ||
| 1012 | + Node* receiver = NodeProperties::GetValueInput(node, 1); | ||
| 1013 | + Node* context = NodeProperties::GetContextInput(node); | ||
| 1014 | + Node* frame_state = NodeProperties::GetFrameStateInput(node); | ||
| 1015 | + Node* effect = NodeProperties::GetEffectInput(node); | ||
| 1016 | + Node* control = NodeProperties::GetControlInput(node); | ||
| 1017 | + | ||
| 1018 | + // TODO(turbofan): Extend this to also handle fast holey double elements | ||
| 1019 | + // once we got the hole NaN mess sorted out in TurboFan/V8. | ||
| 1020 | + Handle<Map> receiver_map; | ||
| 1021 | + if (GetMapWitness(node).ToHandle(&receiver_map) && | ||
| 1022 | + CanInlineArrayResizeOperation(receiver_map) && | ||
| 1023 | + receiver_map->elements_kind() != FAST_HOLEY_DOUBLE_ELEMENTS) { | ||
| 1024 | + // Install code dependencies on the {receiver} prototype maps and the | ||
| 1025 | + // global array protector cell. | ||
| 1026 | + dependencies()->AssumePropertyCell(factory()->array_protector()); | ||
| 1027 | + dependencies()->AssumePrototypeMapsStable(receiver_map); | ||
| 1028 | + | ||
| 1029 | + // Load length of the {receiver}. | ||
| 1030 | + Node* length = effect = graph()->NewNode( | ||
| 1031 | + simplified()->LoadField( | ||
| 1032 | + AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())), | ||
| 1033 | + receiver, effect, control); | ||
| 1034 | + | ||
| 1035 | + // Return undefined if {receiver} has no elements. | ||
| 1036 | + Node* check0 = graph()->NewNode(simplified()->NumberEqual(), length, | ||
| 1037 | + jsgraph()->ZeroConstant()); | ||
| 1038 | + Node* branch0 = | ||
| 1039 | + graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control); | ||
| 1040 | + | ||
| 1041 | + Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); | ||
| 1042 | + Node* etrue0 = effect; | ||
| 1043 | + Node* vtrue0 = jsgraph()->UndefinedConstant(); | ||
| 1044 | + | ||
| 1045 | + Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); | ||
| 1046 | + Node* efalse0 = effect; | ||
| 1047 | + Node* vfalse0; | ||
| 1048 | + { | ||
| 1049 | + // Check if we should take the fast-path. | ||
| 1050 | + Node* check1 = | ||
| 1051 | + graph()->NewNode(simplified()->NumberLessThanOrEqual(), length, | ||
| 1052 | + jsgraph()->Constant(JSArray::kMaxCopyElements)); | ||
| 1053 | + Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue), | ||
| 1054 | + check1, if_false0); | ||
| 1055 | + | ||
| 1056 | + Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); | ||
| 1057 | + Node* etrue1 = efalse0; | ||
| 1058 | + Node* vtrue1; | ||
| 1059 | + { | ||
| 1060 | + Node* elements = etrue1 = graph()->NewNode( | ||
| 1061 | + simplified()->LoadField(AccessBuilder::ForJSObjectElements()), | ||
| 1062 | + receiver, etrue1, if_true1); | ||
| 1063 | + | ||
| 1064 | + // Load the first element here, which we return below. | ||
| 1065 | + vtrue1 = etrue1 = graph()->NewNode( | ||
| 1066 | + simplified()->LoadElement(AccessBuilder::ForFixedArrayElement( | ||
| 1067 | + receiver_map->elements_kind())), | ||
| 1068 | + elements, jsgraph()->ZeroConstant(), etrue1, if_true1); | ||
| 1069 | + | ||
| 1070 | + // Ensure that we aren't shifting a copy-on-write backing store. | ||
| 1071 | + if (IsFastSmiOrObjectElementsKind(receiver_map->elements_kind())) { | ||
| 1072 | + elements = etrue1 = | ||
| 1073 | + graph()->NewNode(simplified()->EnsureWritableFastElements(), | ||
| 1074 | + receiver, elements, etrue1, if_true1); | ||
| 1075 | + } | ||
| 1076 | + | ||
| 1077 | + // Shift the remaining {elements} by one towards the start. | ||
| 1078 | + Node* loop = graph()->NewNode(common()->Loop(2), if_true1, if_true1); | ||
| 1079 | + Node* eloop = | ||
| 1080 | + graph()->NewNode(common()->EffectPhi(2), etrue1, etrue1, loop); | ||
| 1081 | + Node* index = graph()->NewNode( | ||
| 1082 | + common()->Phi(MachineRepresentation::kTagged, 2), | ||
| 1083 | + jsgraph()->OneConstant(), | ||
| 1084 | + jsgraph()->Constant(JSArray::kMaxCopyElements - 1), loop); | ||
| 1085 | + | ||
| 1086 | + { | ||
| 1087 | + Node* check2 = | ||
| 1088 | + graph()->NewNode(simplified()->NumberLessThan(), index, length); | ||
| 1089 | + Node* branch2 = graph()->NewNode(common()->Branch(), check2, loop); | ||
| 1090 | + | ||
| 1091 | + if_true1 = graph()->NewNode(common()->IfFalse(), branch2); | ||
| 1092 | + etrue1 = eloop; | ||
| 1093 | + | ||
| 1094 | + Node* control = graph()->NewNode(common()->IfTrue(), branch2); | ||
| 1095 | + Node* effect = etrue1; | ||
| 1096 | + | ||
| 1097 | + ElementAccess const access = AccessBuilder::ForFixedArrayElement( | ||
| 1098 | + receiver_map->elements_kind()); | ||
| 1099 | + Node* value = effect = | ||
| 1100 | + graph()->NewNode(simplified()->LoadElement(access), elements, | ||
| 1101 | + index, effect, control); | ||
| 1102 | + effect = graph()->NewNode( | ||
| 1103 | + simplified()->StoreElement(access), elements, | ||
| 1104 | + graph()->NewNode(simplified()->NumberSubtract(), index, | ||
| 1105 | + jsgraph()->OneConstant()), | ||
| 1106 | + value, effect, control); | ||
| 1107 | + | ||
| 1108 | + loop->ReplaceInput(1, control); | ||
| 1109 | + eloop->ReplaceInput(1, effect); | ||
| 1110 | + index->ReplaceInput(1, | ||
| 1111 | + graph()->NewNode(simplified()->NumberAdd(), index, | ||
| 1112 | + jsgraph()->OneConstant())); | ||
| 1113 | + } | ||
| 1114 | + | ||
| 1115 | + // Compute the new {length}. | ||
| 1116 | + length = graph()->NewNode(simplified()->NumberSubtract(), length, | ||
| 1117 | + jsgraph()->OneConstant()); | ||
| 1118 | + | ||
| 1119 | + // Store the new {length} to the {receiver}. | ||
| 1120 | + etrue1 = graph()->NewNode( | ||
| 1121 | + simplified()->StoreField( | ||
| 1122 | + AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())), | ||
| 1123 | + receiver, length, etrue1, if_true1); | ||
| 1124 | + | ||
| 1125 | + // Store a hole to the element we just removed from the {receiver}. | ||
| 1126 | + etrue1 = graph()->NewNode( | ||
| 1127 | + simplified()->StoreElement(AccessBuilder::ForFixedArrayElement( | ||
| 1128 | + GetHoleyElementsKind(receiver_map->elements_kind()))), | ||
| 1129 | + elements, length, jsgraph()->TheHoleConstant(), etrue1, if_true1); | ||
| 1130 | + } | ||
| 1131 | + | ||
| 1132 | + Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); | ||
| 1133 | + Node* efalse1 = efalse0; | ||
| 1134 | + Node* vfalse1; | ||
| 1135 | + { | ||
| 1136 | + // Call the generic C++ implementation. | ||
| 1137 | + const int builtin_index = Builtins::kArrayShift; | ||
| 1138 | + CallDescriptor const* const desc = Linkage::GetCEntryStubCallDescriptor( | ||
| 1139 | + graph()->zone(), 1, BuiltinArguments::kNumExtraArgsWithReceiver, | ||
| 1140 | + Builtins::name(builtin_index), node->op()->properties(), | ||
| 1141 | + CallDescriptor::kNeedsFrameState); | ||
| 1142 | + Node* stub_code = jsgraph()->CEntryStubConstant(1, kDontSaveFPRegs, | ||
| 1143 | + kArgvOnStack, true); | ||
| 1144 | + Address builtin_entry = Builtins::CppEntryOf(builtin_index); | ||
| 1145 | + Node* entry = jsgraph()->ExternalConstant( | ||
| 1146 | + ExternalReference(builtin_entry, isolate())); | ||
| 1147 | + Node* argc = | ||
| 1148 | + jsgraph()->Constant(BuiltinArguments::kNumExtraArgsWithReceiver); | ||
| 1149 | + if_false1 = efalse1 = vfalse1 = | ||
| 1150 | + graph()->NewNode(common()->Call(desc), stub_code, receiver, argc, | ||
| 1151 | + target, jsgraph()->UndefinedConstant(), entry, | ||
| 1152 | + argc, context, frame_state, efalse1, if_false1); | ||
| 1153 | + } | ||
| 1154 | + | ||
| 1155 | + if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); | ||
| 1156 | + efalse0 = | ||
| 1157 | + graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0); | ||
| 1158 | + vfalse0 = | ||
| 1159 | + graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), | ||
| 1160 | + vtrue1, vfalse1, if_false0); | ||
| 1161 | + } | ||
| 1162 | + | ||
| 1163 | + control = graph()->NewNode(common()->Merge(2), if_true0, if_false0); | ||
| 1164 | + effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control); | ||
| 1165 | + Node* value = | ||
| 1166 | + graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), | ||
| 1167 | + vtrue0, vfalse0, control); | ||
| 1168 | + | ||
| 1169 | + // Convert the hole to undefined. Do this last, so that we can optimize | ||
| 1170 | + // conversion operator via some smart strength reduction in many cases. | ||
| 1171 | + if (IsFastHoleyElementsKind(receiver_map->elements_kind())) { | ||
| 1172 | + value = | ||
| 1173 | + graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(), value); | ||
| 1174 | + } | ||
| 1175 | + | ||
| 1176 | + ReplaceWithValue(node, value, effect, control); | ||
| 1177 | + return Replace(value); | ||
| 1178 | + } | ||
| 1179 | + return NoChange(); | ||
| 1180 | + } | ||
| 1181 | + | ||
| 1008 | 1182 | namespace { | |
| 1009 | 1183 | ||
| 1010 | 1184 | bool HasInstanceTypeWitness(Node* receiver, Node* effect, | |
@@ -2125,6 +2299,8 @@ Reduction JSBuiltinReducer::Reduce(Node* node) { | |||
| 2125 | 2299 | return ReduceArrayPop(node); | |
| 2126 | 2300 | case kArrayPush: | |
| 2127 | 2301 | return ReduceArrayPush(node); | |
| 2302 | + case kArrayShift: | ||
| 2303 | + return ReduceArrayShift(node); | ||
| 2128 | 2304 | case kDateNow: | |
| 2129 | 2305 | return ReduceDateNow(node); | |
| 2130 | 2306 | case kDateGetTime: | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -58,6 +58,7 @@ class V8_EXPORT_PRIVATE JSBuiltinReducer final | |||
| 58 | 58 | Reduction ReduceArrayIsArray(Node* node); | |
| 59 | 59 | Reduction ReduceArrayPop(Node* node); | |
| 60 | 60 | Reduction ReduceArrayPush(Node* node); | |
| 61 | + Reduction ReduceArrayShift(Node* node); | ||
| 61 | 62 | Reduction ReduceDateNow(Node* node); | |
| 62 | 63 | Reduction ReduceDateGetTime(Node* node); | |
| 63 | 64 | Reduction ReduceGlobalIsFinite(Node* node); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -8821,7 +8821,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( | |||
| 8821 | 8821 | Handle<JSObject>::null(), true); | |
| 8822 | 8822 | ||
| 8823 | 8823 | // Threshold for fast inlined Array.shift(). | |
| 8824 | - HConstant* inline_threshold = Add<HConstant>(static_cast<int32_t>(16)); | ||
| 8824 | + HConstant* inline_threshold = Add<HConstant>(JSArray::kMaxCopyElements); | ||
| 8825 | 8825 | ||
| 8826 | 8826 | Drop(args_count_no_receiver); | |
| 8827 | 8827 | HValue* result; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -9608,6 +9608,9 @@ class JSArray: public JSObject { | |||
| 9608 | 9608 | static const int kLengthOffset = JSObject::kHeaderSize; | |
| 9609 | 9609 | static const int kSize = kLengthOffset + kPointerSize; | |
| 9610 | 9610 | ||
| 9611 | + // Max. number of elements being copied in Array builtins. | ||
| 9612 | + static const int kMaxCopyElements = 16; | ||
| 9613 | + | ||
| 9611 | 9614 | static const int kInitialMaxFastElementArray = | |
| 9612 | 9615 | (kMaxRegularHeapObjectSize - FixedArray::kHeaderSize - kSize - | |
| 9613 | 9616 | AllocationMemento::kSize) / | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,50 @@ | |||
| 1 | + // Copyright 2017 the V8 project authors. All rights reserved. | ||
| 2 | + // Use of this source code is governed by a BSD-style license that can be | ||
| 3 | + // found in the LICENSE file. | ||
| 4 | + | ||
| 5 | + // Flags: --allow-natives-syntax | ||
| 6 | + | ||
| 7 | + (function() { | ||
| 8 | + function doShift(a) { return a.shift(); } | ||
| 9 | + | ||
| 10 | + function test() { | ||
| 11 | + var a = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]; | ||
| 12 | + assertEquals(0, doShift(a)); | ||
| 13 | + assertEquals([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16], a); | ||
| 14 | + } | ||
| 15 | + | ||
| 16 | + test(); | ||
| 17 | + test(); | ||
| 18 | + %OptimizeFunctionOnNextCall(doShift); | ||
| 19 | + test(); | ||
| 20 | + })(); | ||
| 21 | + | ||
| 22 | + (function() { | ||
| 23 | + function doShift(a) { return a.shift(); } | ||
| 24 | + | ||
| 25 | + function test() { | ||
| 26 | + var a = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16.1]; | ||
| 27 | + assertEquals(0, doShift(a)); | ||
| 28 | + assertEquals([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16.1], a); | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + test(); | ||
| 32 | + test(); | ||
| 33 | + %OptimizeFunctionOnNextCall(doShift); | ||
| 34 | + test(); | ||
| 35 | + })(); | ||
| 36 | + | ||
| 37 | + (function() { | ||
| 38 | + function doShift(a) { return a.shift(); } | ||
| 39 | + | ||
| 40 | + function test() { | ||
| 41 | + var a = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,"16"]; | ||
| 42 | + assertEquals(0, doShift(a)); | ||
| 43 | + assertEquals([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,"16"], a); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + test(); | ||
| 47 | + test(); | ||
| 48 | + %OptimizeFunctionOnNextCall(doShift); | ||
| 49 | + test(); | ||
| 50 | + })(); | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments