Index: src/code-stubs-hydrogen.cc |
diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc |
index 3a9688a899f8d43597eb95a54a07719207b7da2f..1c43049cb746ad2b9068c765c49451344e112609 100644 |
--- a/src/code-stubs-hydrogen.cc |
+++ b/src/code-stubs-hydrogen.cc |
@@ -71,6 +71,8 @@ class CodeStubGraphBuilderBase : public HGraphBuilder { |
MULTIPLE |
}; |
+ HValue* UnmappedCase(HValue* elements, HValue* key); |
+ |
HValue* BuildArrayConstructor(ElementsKind kind, |
AllocationSiteOverrideMode override_mode, |
ArgumentClass argument_class); |
@@ -600,6 +602,122 @@ HValue* CodeStubGraphBuilder<LoadConstantStub>::BuildCodeStub() { |
Handle<Code> LoadConstantStub::GenerateCode() { return DoGenerateCode(this); } |
+HValue* CodeStubGraphBuilderBase::UnmappedCase(HValue* elements, HValue* key) { |
+ HValue* result; |
+ HInstruction* backing_store = Add<HLoadKeyed>( |
+ elements, graph()->GetConstant1(), static_cast<HValue*>(NULL), |
+ FAST_ELEMENTS, ALLOW_RETURN_HOLE); |
+ Add<HCheckMaps>(backing_store, isolate()->factory()->fixed_array_map()); |
+ HValue* backing_store_length = |
+ Add<HLoadNamedField>(backing_store, static_cast<HValue*>(NULL), |
+ HObjectAccess::ForFixedArrayLength()); |
+ IfBuilder in_unmapped_range(this); |
+ in_unmapped_range.If<HCompareNumericAndBranch>(key, backing_store_length, |
+ Token::LT); |
+ in_unmapped_range.Then(); |
+ { |
+ result = Add<HLoadKeyed>(backing_store, key, static_cast<HValue*>(NULL), |
+ FAST_HOLEY_ELEMENTS, NEVER_RETURN_HOLE); |
+ } |
+ in_unmapped_range.ElseDeopt("Outside of range"); |
+ in_unmapped_range.End(); |
+ return result; |
+} |
+ |
+ |
+template <> |
+HValue* CodeStubGraphBuilder<KeyedLoadSloppyArgumentsStub>::BuildCodeStub() { |
+ HValue* receiver = GetParameter(LoadDescriptor::kReceiverIndex); |
+ HValue* key = GetParameter(LoadDescriptor::kNameIndex); |
+ |
+ // Mapped arguments are actual arguments. Unmapped arguments are values added |
+ // to the arguments object after it was created for the call. Mapped arguments |
+ // are stored in the context at indexes given by elements[key + 2]. Unmapped |
+ // arguments are stored as regular indexed properties in the arguments array, |
+ // held at elements[1]. See NewSloppyArguments() in runtime.cc for a detailed |
+ // look at argument object construction. |
+ // |
+ // The sloppy arguments elements array has a special format: |
+ // |
+ // 0: context |
+ // 1: unmapped arguments array |
+ // 2: mapped_index0, |
+ // 3: mapped_index1, |
+ // ... |
+ // |
+ // length is 2 + min(number_of_actual_arguments, number_of_formal_arguments). |
+ // If key + 2 >= elements.length then attempt to look in the unmapped |
+ // arguments array (given by elements[1]) and return the value at key, missing |
+ // to the runtime if the unmapped arguments array is not a fixed array or if |
+ // key >= unmapped_arguments_array.length. |
+ // |
+ // Otherwise, t = elements[key + 2]. If t is the hole, then look up the value |
+ // in the unmapped arguments array, as described above. Otherwise, t is a Smi |
+ // index into the context array given at elements[0]. Return the value at |
+ // context[t]. |
+ |
+ key = AddUncasted<HForceRepresentation>(key, Representation::Smi()); |
+ IfBuilder positive_smi(this); |
+ positive_smi.If<HCompareNumericAndBranch>(key, graph()->GetConstant0(), |
+ Token::LT); |
+ positive_smi.ThenDeopt("key is negative"); |
+ positive_smi.End(); |
+ |
+ HValue* constant_two = Add<HConstant>(2); |
+ HValue* elements = AddLoadElements(receiver, static_cast<HValue*>(NULL)); |
+ HValue* elements_length = |
+ Add<HLoadNamedField>(elements, static_cast<HValue*>(NULL), |
+ HObjectAccess::ForFixedArrayLength()); |
+ HValue* adjusted_length = AddUncasted<HSub>(elements_length, constant_two); |
+ IfBuilder in_range(this); |
+ in_range.If<HCompareNumericAndBranch>(key, adjusted_length, Token::LT); |
+ in_range.Then(); |
+ { |
+ HValue* index = AddUncasted<HAdd>(key, constant_two); |
+ HInstruction* mapped_index = |
+ Add<HLoadKeyed>(elements, index, static_cast<HValue*>(NULL), |
+ FAST_HOLEY_ELEMENTS, ALLOW_RETURN_HOLE); |
+ |
+ IfBuilder is_valid(this); |
+ is_valid.IfNot<HCompareObjectEqAndBranch>(mapped_index, |
+ graph()->GetConstantHole()); |
+ is_valid.Then(); |
+ { |
+ // TODO(mvstanton): I'd like to assert from this point, that if the |
+ // mapped_index is not the hole that it is indeed, a smi. An unnecessary |
+ // smi check is being emitted. |
+ HValue* the_context = |
+ Add<HLoadKeyed>(elements, graph()->GetConstant0(), |
+ static_cast<HValue*>(NULL), FAST_ELEMENTS); |
+ DCHECK(Context::kHeaderSize == FixedArray::kHeaderSize); |
+ HValue* result = |
+ Add<HLoadKeyed>(the_context, mapped_index, static_cast<HValue*>(NULL), |
+ FAST_ELEMENTS, ALLOW_RETURN_HOLE); |
+ environment()->Push(result); |
+ } |
+ is_valid.Else(); |
+ { |
+ HValue* result = UnmappedCase(elements, key); |
+ environment()->Push(result); |
+ } |
+ is_valid.End(); |
+ } |
+ in_range.Else(); |
+ { |
+ HValue* result = UnmappedCase(elements, key); |
+ environment()->Push(result); |
+ } |
+ in_range.End(); |
+ |
+ return environment()->Pop(); |
+} |
+ |
+ |
+Handle<Code> KeyedLoadSloppyArgumentsStub::GenerateCode() { |
+ return DoGenerateCode(this); |
+} |
+ |
+ |
void CodeStubGraphBuilderBase::BuildStoreNamedField( |
HValue* object, HValue* value, FieldIndex index, |
Representation representation) { |
@@ -1092,7 +1210,6 @@ Handle<Code> ToBooleanStub::GenerateCode() { |
template <> |
HValue* CodeStubGraphBuilder<StoreGlobalStub>::BuildCodeInitializedStub() { |
StoreGlobalStub* stub = casted_stub(); |
- Handle<Object> hole(isolate()->heap()->the_hole_value(), isolate()); |
Handle<Object> placeholer_value(Smi::FromInt(0), isolate()); |
Handle<PropertyCell> placeholder_cell = |
isolate()->factory()->NewPropertyCell(placeholer_value); |
@@ -1124,7 +1241,7 @@ HValue* CodeStubGraphBuilder<StoreGlobalStub>::BuildCodeInitializedStub() { |
// property has been deleted and that the store must be handled by the |
// runtime. |
IfBuilder builder(this); |
- HValue* hole_value = Add<HConstant>(hole); |
+ HValue* hole_value = graph()->GetConstantHole(); |
builder.If<HCompareObjectEqAndBranch>(cell_contents, hole_value); |
builder.Then(); |
builder.Deopt("Unexpected cell contents in global store"); |