Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(159)

Unified Diff: src/code-stubs-hydrogen.cc

Issue 1816553002: Introduce a code stub version of Array.prototype.push (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Cleanup Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/code-stubs.h ('k') | src/crankshaft/hydrogen-instructions.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/code-stubs-hydrogen.cc
diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc
index a968c90c22fe500bfaba8c030cbbdad23f467d2d..db01dd50654398309731cdaa007a6086e879c0a3 100644
--- a/src/code-stubs-hydrogen.cc
+++ b/src/code-stubs-hydrogen.cc
@@ -78,6 +78,8 @@ class CodeStubGraphBuilderBase : public HGraphBuilder {
Representation representation,
bool transition_to_field);
+ HValue* BuildPushElement(HValue* object, HValue* value, ElementsKind kind);
+
enum ArgumentClass {
NONE,
SINGLE,
@@ -780,6 +782,184 @@ Handle<Code> StoreScriptContextFieldStub::GenerateCode() {
return DoGenerateCode(this);
}
+HValue* CodeStubGraphBuilderBase::BuildPushElement(HValue* object,
+ HValue* value,
+ ElementsKind kind) {
+ HValue* length = Add<HLoadNamedField>(object, nullptr,
+ HObjectAccess::ForArrayLength(kind));
+ HValue* key = length;
+ HValue* elements = Add<HLoadNamedField>(object, nullptr,
+ HObjectAccess::ForElementsPointer());
+ elements = BuildCheckForCapacityGrow(object, elements, kind, length, key,
+ true, STORE);
+ AddElementAccess(elements, key, value, object, nullptr, kind, STORE);
+ return key;
+}
+
+template <>
+HValue* CodeStubGraphBuilder<FastArrayPushStub>::BuildCodeStub() {
+ // TODO(verwaest): Fix deoptimizer messages.
+ HValue* argc = GetArgumentsLength();
+ IfBuilder arg_check(this);
+ arg_check.If<HCompareNumericAndBranch>(argc, graph()->GetConstant1(),
+ Token::NE);
+ arg_check.ThenDeopt(Deoptimizer::kFastArrayPushFailed);
+ arg_check.End();
+
+ HInstruction* argument_elements = Add<HArgumentsElements>(false, false);
+ HInstruction* object = Add<HAccessArgumentsAt>(argument_elements, argc,
+ graph()->GetConstantMinus1());
+ HInstruction* value =
+ Add<HAccessArgumentsAt>(argument_elements, argc, graph()->GetConstant0());
+
+ BuildCheckHeapObject(object);
+ HValue* map = Add<HLoadNamedField>(object, nullptr, HObjectAccess::ForMap());
+ Add<HCheckInstanceType>(object, HCheckInstanceType::IS_JS_ARRAY);
+
+ // Disallow pushing onto prototypes. It might be the JSArray prototype.
+ // Disallow pushing onto non-extensible objects.
+ {
+ HValue* bit_field2 =
+ Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField2());
+ HValue* mask =
+ Add<HConstant>(static_cast<int>(Map::IsPrototypeMapBits::kMask) |
+ (1 << Map::kIsExtensible));
+ HValue* bit = AddUncasted<HBitwise>(Token::BIT_AND, bit_field2, mask);
Jakob Kummerow 2016/03/21 15:12:51 nit: call it "bits", could be more than one.
+ IfBuilder check(this);
+ check.If<HCompareNumericAndBranch>(
+ bit, Add<HConstant>(1 << Map::kIsExtensible), Token::NE);
+ check.ThenDeopt(Deoptimizer::kFastArrayPushFailed);
+ check.End();
+ }
+
+ // Disallow pushing onto observed objects.
+ {
+ HValue* bit_field =
+ Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField());
+ HValue* mask = Add<HConstant>(1 << Map::kIsObserved);
+ HValue* bit = AddUncasted<HBitwise>(Token::BIT_AND, bit_field, mask);
+ IfBuilder check(this);
+ check.If<HCompareNumericAndBranch>(bit, mask, Token::EQ);
+ check.ThenDeopt(Deoptimizer::kFastArrayPushFailed);
+ check.End();
+ }
+
+ // Disallow pushing onto arrays in dictionary named property mode. We need to
+ // figure out whether the length property is still writable.
+ {
+ HValue* bit_field3 =
+ Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField3());
+ HValue* mask = Add<HConstant>(static_cast<int>(Map::DictionaryMap::kMask));
+ HValue* bit = AddUncasted<HBitwise>(Token::BIT_AND, bit_field3, mask);
+ IfBuilder check(this);
+ check.If<HCompareNumericAndBranch>(bit, mask, Token::EQ);
+ check.ThenDeopt(Deoptimizer::kFastArrayPushFailed);
+ check.End();
+ }
+
+ // Check whether the length property is writable. The length property is the
+ // only default named properties on arrays. It's nonconfigurable, hence is
Jakob Kummerow 2016/03/21 15:12:51 nit: s/properties/property/
+ // guaranteed to stay the first property.
+ {
+ HValue* descriptors =
+ Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapDescriptors());
+ HValue* details = Add<HLoadKeyed>(
+ descriptors, Add<HConstant>(DescriptorArray::ToDetailsIndex(0)),
+ nullptr, nullptr, FAST_SMI_ELEMENTS);
+ HValue* mask =
+ Add<HConstant>(READ_ONLY << PropertyDetails::AttributesField::kShift);
+ HValue* bit = AddUncasted<HBitwise>(Token::BIT_AND, details, mask);
+ IfBuilder writable(this);
Jakob Kummerow 2016/03/21 15:12:51 nit: this should be called "readonly" (to make the
+ writable.If<HCompareNumericAndBranch>(bit, mask, Token::EQ);
+ writable.ThenDeopt(Deoptimizer::kFastArrayPushFailed);
+ writable.End();
+ }
+
+ environment()->Push(map);
+ LoopBuilder check_prototypes(this);
+ check_prototypes.BeginBody(1);
+ {
+ HValue* parent_map = environment()->Pop();
+ HValue* prototype = Add<HLoadNamedField>(parent_map, nullptr,
+ HObjectAccess::ForPrototype());
+
+ IfBuilder is_null(this);
+ is_null.If<HCompareObjectEqAndBranch>(prototype,
+ graph()->GetConstantNull());
+ is_null.Then();
+ check_prototypes.Break();
+ is_null.End();
+
+ HValue* prototype_map =
+ Add<HLoadNamedField>(prototype, nullptr, HObjectAccess::ForMap());
+ HValue* instance_type = Add<HLoadNamedField>(
+ prototype_map, nullptr, HObjectAccess::ForMapInstanceType());
+ IfBuilder check_instance_type(this);
+ check_instance_type.If<HCompareNumericAndBranch>(
+ instance_type, Add<HConstant>(JS_VALUE_TYPE), Token::LTE);
Jakob Kummerow 2016/03/21 15:12:51 This looks like a use case for the recently introd
+ check_instance_type.ThenDeopt(Deoptimizer::kFastArrayPushFailed);
+ check_instance_type.End();
+
+ HValue* elements = Add<HLoadNamedField>(
+ prototype, nullptr, HObjectAccess::ForElementsPointer());
+ IfBuilder no_elements(this);
+ no_elements.If<HCompareObjectEqAndBranch>(
+ elements, Add<HConstant>(isolate()->factory()->empty_fixed_array()));
+ no_elements.Then();
+ no_elements.ElseDeopt(Deoptimizer::kFastArrayPushFailed);
Jakob Kummerow 2016/03/21 15:12:51 nit: you could also use IfNot/ThenDeopt. Up to you
+ no_elements.End();
+
+ environment()->Push(prototype_map);
+ }
+ check_prototypes.EndBody();
+
+ HValue* bit_field2 =
+ Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField2());
Jakob Kummerow 2016/03/21 15:12:51 This is duplicated from line 823. Suggestion: hois
+ HValue* kind = BuildDecodeField<Map::ElementsKindBits>(bit_field2);
+
+ IfBuilder is_smi(this);
Jakob Kummerow 2016/03/21 15:12:51 nit: I'd prefer the name "has_smi_elements".
+ is_smi.If<HCompareNumericAndBranch>(
+ kind, Add<HConstant>(FAST_HOLEY_SMI_ELEMENTS), Token::LTE);
Jakob Kummerow 2016/03/21 15:12:51 nit: a comment and a check would be nice, roughly:
+ is_smi.Then();
+ {
+ HValue* smi_value =
+ AddUncasted<HForceRepresentation>(value, Representation::Smi());
+ HValue* key = BuildPushElement(object, smi_value, FAST_HOLEY_SMI_ELEMENTS);
+ environment()->Push(key);
+ }
+ is_smi.Else();
+ {
+ IfBuilder is_object(this);
Jakob Kummerow 2016/03/21 15:12:50 nit: has_object_elements
+ is_object.If<HCompareNumericAndBranch>(
+ kind, Add<HConstant>(FAST_HOLEY_ELEMENTS), Token::LTE);
+ is_object.Then();
+ {
+ HValue* key = BuildPushElement(object, value, FAST_HOLEY_ELEMENTS);
+ environment()->Push(key);
+ }
+ is_object.Else();
+ {
+ IfBuilder is_double(this);
+ is_double.If<HCompareNumericAndBranch>(
+ kind, Add<HConstant>(FAST_HOLEY_DOUBLE_ELEMENTS), Token::GT);
+ is_double.ThenDeopt(Deoptimizer::kFastArrayPushFailed);
+ is_double.End();
+
+ HValue* double_value =
+ AddUncasted<HForceRepresentation>(value, Representation::Double());
+ HValue* key =
+ BuildPushElement(object, double_value, FAST_HOLEY_DOUBLE_ELEMENTS);
+ environment()->Push(key);
+ }
+ is_object.End();
+ }
+ is_smi.End();
+
+ HValue* key = environment()->Pop();
+ return AddUncasted<HAdd>(key, graph()->GetConstant1());
+}
+
+Handle<Code> FastArrayPushStub::GenerateCode() { return DoGenerateCode(this); }
template <>
HValue* CodeStubGraphBuilder<GrowArrayElementsStub>::BuildCodeStub() {
« no previous file with comments | « src/code-stubs.h ('k') | src/crankshaft/hydrogen-instructions.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698