Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index c17c5f1d9c9e9edf37bb433f3c868fd9736e621e..756c6ee6d4b3e967190bd4db0bc8020f4bbd8651 100644 |
--- a/src/hydrogen.cc |
+++ b/src/hydrogen.cc |
@@ -2434,6 +2434,23 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( |
} |
if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) { |
NoObservableSideEffectsScope no_effects(this); |
+ if (IsExternalArrayElementsKind(elements_kind)) { |
+ HInstruction* buffer = |
+ Add<HLoadNamedField>(checked_object, nullptr, |
+ HObjectAccess::ForJSArrayBufferViewBuffer()); |
+ HInstruction* flags = Add<HLoadNamedField>( |
+ buffer, nullptr, HObjectAccess::ForJSArrayBufferFlag()); |
+ HValue* was_neutered_mask = |
+ Add<HConstant>(1 << JSArrayBuffer::kWasNeuteredBit); |
+ HValue* was_neutered_test = |
+ AddUncasted<HBitwise>(Token::BIT_AND, flags, was_neutered_mask); |
+ |
+ IfBuilder if_was_neutered(this); |
+ if_was_neutered.If<HCompareNumericAndBranch>( |
+ was_neutered_test, graph()->GetConstant0(), Token::NE); |
+ if_was_neutered.ThenDeopt(Deoptimizer::kOutOfBounds); |
+ if_was_neutered.End(); |
+ } |
IfBuilder length_checker(this); |
length_checker.If<HCompareNumericAndBranch>(key, length, Token::LT); |
length_checker.Then(); |
@@ -2448,6 +2465,14 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( |
length_checker.End(); |
return result; |
} else { |
+ if (IsExternalArrayElementsKind(elements_kind)) { |
+ HInstruction* buffer = |
+ Add<HLoadNamedField>(checked_object, nullptr, |
+ HObjectAccess::ForJSArrayBufferViewBuffer()); |
+ HInstruction* buffer_length = Add<HLoadNamedField>( |
+ buffer, nullptr, HObjectAccess::ForJSArrayBufferByteLength()); |
+ Add<HBoundsCheck>(graph()->GetConstant0(), buffer_length); |
+ } |
DCHECK(store_mode == STANDARD_STORE); |
checked_key = Add<HBoundsCheck>(key, length); |
return AddElementAccess( |
@@ -3155,6 +3180,44 @@ HInstruction* HGraphBuilder::BuildGetArrayFunction() { |
} |
+HValue* HGraphBuilder::BuildArrayBufferViewFieldAccessor(HValue* object, |
+ HValue* checked_object, |
+ FieldIndex index) { |
+ NoObservableSideEffectsScope scope(this); |
+ HObjectAccess access = HObjectAccess::ForObservableJSObjectOffset( |
+ index.offset(), Representation::Tagged()); |
+ HInstruction* buffer = Add<HLoadNamedField>( |
+ object, checked_object, HObjectAccess::ForJSArrayBufferViewBuffer()); |
+ HInstruction* field = Add<HLoadNamedField>(object, checked_object, access); |
+ |
+ IfBuilder if_has_buffer(this); |
+ HValue* has_buffer = if_has_buffer.IfNot<HIsSmiAndBranch>(buffer); |
+ if_has_buffer.Then(); |
+ { |
+ HInstruction* flags = Add<HLoadNamedField>( |
+ buffer, has_buffer, HObjectAccess::ForJSArrayBufferFlag()); |
+ HValue* was_neutered_mask = |
+ Add<HConstant>(1 << JSArrayBuffer::kWasNeuteredBit); |
+ HValue* was_neutered_test = |
+ AddUncasted<HBitwise>(Token::BIT_AND, flags, was_neutered_mask); |
+ |
+ IfBuilder if_was_neutered(this); |
+ if_was_neutered.If<HCompareNumericAndBranch>( |
+ was_neutered_test, graph()->GetConstant0(), Token::NE); |
+ if_was_neutered.Then(); |
+ Push(graph()->GetConstant0()); |
+ if_was_neutered.Else(); |
+ Push(field); |
+ if_was_neutered.End(); |
+ } |
+ if_has_buffer.Else(); |
+ Push(field); |
+ if_has_buffer.End(); |
+ |
+ return Pop(); |
+} |
+ |
+ |
HGraphBuilder::JSArrayBuilder::JSArrayBuilder(HGraphBuilder* builder, |
ElementsKind kind, |
HValue* allocation_site_payload, |
@@ -5654,7 +5717,7 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { |
Handle<Map> map = property->GetReceiverType(); |
Handle<String> name = key->AsPropertyName(); |
- HInstruction* store; |
+ HValue* store; |
if (map.is_null()) { |
// If we don't know the monomorphic type, do a generic store. |
CHECK_ALIVE(store = BuildNamedGeneric( |
@@ -5672,7 +5735,9 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { |
STORE, NULL, literal, name, value)); |
} |
} |
- AddInstruction(store); |
+ if (store->IsInstruction()) { |
+ AddInstruction(HInstruction::cast(store)); |
+ } |
DCHECK(store->HasObservableSideEffects()); |
Add<HSimulate>(key->id(), REMOVABLE_SIMULATE); |
} else { |
@@ -6133,6 +6198,7 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::IsIntegerIndexedExotic() { |
bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() { |
if (!CanInlinePropertyAccess(map_)) return false; |
if (IsJSObjectFieldAccessor()) return IsLoad(); |
+ if (IsJSArrayBufferViewFieldAccessor()) return IsLoad(); |
if (map_->function_with_prototype() && !map_->has_non_instance_prototype() && |
name_.is_identical_to(isolate()->factory()->prototype_string())) { |
return IsLoad(); |
@@ -6181,6 +6247,18 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessAsMonomorphic( |
return true; |
} |
+ if (GetJSArrayBufferViewFieldAccess(&access)) { |
+ for (int i = 1; i < maps->length(); ++i) { |
+ PropertyAccessInfo test_info(builder_, access_type_, maps->at(i), name_); |
+ HObjectAccess test_access = HObjectAccess::ForMap(); // bogus default |
+ if (!test_info.GetJSArrayBufferViewFieldAccess(&test_access)) { |
+ return false; |
+ } |
+ if (!access.Equals(test_access)) return false; |
+ } |
+ return true; |
+ } |
+ |
// Currently only handle numbers as a polymorphic case. |
// TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber |
// instruction. |
@@ -6220,21 +6298,22 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::NeedsWrappingFor( |
} |
-HInstruction* HOptimizedGraphBuilder::BuildMonomorphicAccess( |
- PropertyAccessInfo* info, |
- HValue* object, |
- HValue* checked_object, |
- HValue* value, |
- BailoutId ast_id, |
- BailoutId return_id, |
+HValue* HOptimizedGraphBuilder::BuildMonomorphicAccess( |
+ PropertyAccessInfo* info, HValue* object, HValue* checked_object, |
+ HValue* value, BailoutId ast_id, BailoutId return_id, |
bool can_inline_accessor) { |
- |
HObjectAccess access = HObjectAccess::ForMap(); // bogus default |
if (info->GetJSObjectFieldAccess(&access)) { |
DCHECK(info->IsLoad()); |
return New<HLoadNamedField>(object, checked_object, access); |
} |
+ if (info->GetJSArrayBufferViewFieldAccess(&access)) { |
+ DCHECK(info->IsLoad()); |
+ return BuildArrayBufferViewFieldAccessor( |
+ object, checked_object, FieldIndex::ForInObjectOffset(access.offset())); |
+ } |
+ |
if (info->name().is_identical_to(isolate()->factory()->prototype_string()) && |
info->map()->function_with_prototype()) { |
DCHECK(!info->map()->has_non_instance_prototype()); |
@@ -6384,9 +6463,9 @@ void HOptimizedGraphBuilder::HandlePolymorphicNamedFieldAccess( |
set_current_block(if_true); |
- HInstruction* access = BuildMonomorphicAccess( |
- &info, object, dependency, value, ast_id, |
- return_id, FLAG_polymorphic_inlining); |
+ HValue* access = |
+ BuildMonomorphicAccess(&info, object, dependency, value, ast_id, |
+ return_id, FLAG_polymorphic_inlining); |
HValue* result = NULL; |
switch (access_type) { |
@@ -6401,7 +6480,10 @@ void HOptimizedGraphBuilder::HandlePolymorphicNamedFieldAccess( |
if (access == NULL) { |
if (HasStackOverflow()) return; |
} else { |
- if (!access->IsLinked()) AddInstruction(access); |
+ if (access->IsInstruction()) { |
+ HInstruction* instr = HInstruction::cast(access); |
+ if (!instr->IsLinked()) AddInstruction(instr); |
+ } |
if (!ast_context()->IsEffect()) Push(result); |
} |
@@ -6495,13 +6577,13 @@ void HOptimizedGraphBuilder::BuildStore(Expression* expr, |
Handle<String> name = Handle<String>::cast(key->value()); |
DCHECK(!name.is_null()); |
- HInstruction* instr = BuildNamedAccess(STORE, ast_id, return_id, expr, |
- object, name, value, is_uninitialized); |
- if (instr == NULL) return; |
+ HValue* access = BuildNamedAccess(STORE, ast_id, return_id, expr, object, |
+ name, value, is_uninitialized); |
+ if (access == NULL) return; |
if (!ast_context()->IsEffect()) Push(value); |
- AddInstruction(instr); |
- if (instr->HasObservableSideEffects()) { |
+ if (access->IsInstruction()) AddInstruction(HInstruction::cast(access)); |
+ if (access->HasObservableSideEffects()) { |
Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); |
} |
if (!ast_context()->IsEffect()) Drop(1); |
@@ -7257,16 +7339,18 @@ HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess( |
constant = isolate()->factory()->InternalizeString( |
Handle<String>::cast(constant)); |
} |
- HInstruction* instr = |
+ HValue* access = |
BuildNamedAccess(access_type, ast_id, return_id, expr, obj, |
Handle<String>::cast(constant), val, false); |
- if (instr == NULL || instr->IsLinked()) { |
+ if (access == NULL || access->IsPhi() || |
+ HInstruction::cast(access)->IsLinked()) { |
*has_side_effects = false; |
} else { |
+ HInstruction* instr = HInstruction::cast(access); |
AddInstruction(instr); |
*has_side_effects = instr->HasObservableSideEffects(); |
} |
- return instr; |
+ return access; |
} |
} |
@@ -7425,14 +7509,9 @@ bool HOptimizedGraphBuilder::TryArgumentsAccess(Property* expr) { |
} |
-HInstruction* HOptimizedGraphBuilder::BuildNamedAccess( |
- PropertyAccessType access, |
- BailoutId ast_id, |
- BailoutId return_id, |
- Expression* expr, |
- HValue* object, |
- Handle<String> name, |
- HValue* value, |
+HValue* HOptimizedGraphBuilder::BuildNamedAccess( |
+ PropertyAccessType access, BailoutId ast_id, BailoutId return_id, |
+ Expression* expr, HValue* object, Handle<String> name, HValue* value, |
bool is_uninitialized) { |
SmallMapList* maps; |
ComputeReceiverTypes(expr, object, &maps, zone()); |
@@ -7488,9 +7567,11 @@ void HOptimizedGraphBuilder::BuildLoad(Property* expr, |
Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); |
HValue* object = Pop(); |
- instr = BuildNamedAccess(LOAD, ast_id, expr->LoadId(), expr, |
- object, name, NULL, expr->IsUninitialized()); |
- if (instr == NULL) return; |
+ HValue* value = BuildNamedAccess(LOAD, ast_id, expr->LoadId(), expr, object, |
+ name, NULL, expr->IsUninitialized()); |
+ if (value == NULL) return; |
+ if (value->IsPhi()) return ast_context()->ReturnValue(value); |
+ instr = HInstruction::cast(value); |
if (instr->IsLinked()) return ast_context()->ReturnValue(instr); |
} else { |
@@ -9624,20 +9705,11 @@ void HGraphBuilder::BuildArrayBufferViewInitialization( |
Add<HStoreNamedField>( |
obj, |
HObjectAccess::ForJSArrayBufferViewBuffer(), buffer); |
- HObjectAccess weak_first_view_access = |
- HObjectAccess::ForJSArrayBufferWeakFirstView(); |
- Add<HStoreNamedField>( |
- obj, HObjectAccess::ForJSArrayBufferViewWeakNext(), |
- Add<HLoadNamedField>(buffer, nullptr, weak_first_view_access)); |
- Add<HStoreNamedField>(buffer, weak_first_view_access, obj); |
} else { |
Add<HStoreNamedField>( |
obj, |
HObjectAccess::ForJSArrayBufferViewBuffer(), |
Add<HConstant>(static_cast<int32_t>(0))); |
- Add<HStoreNamedField>(obj, |
- HObjectAccess::ForJSArrayBufferViewWeakNext(), |
- graph()->GetConstantUndefined()); |
} |
} |
@@ -9933,34 +10005,40 @@ void HOptimizedGraphBuilder::GenerateArrayBufferGetByteLength( |
void HOptimizedGraphBuilder::GenerateArrayBufferViewGetByteLength( |
CallRuntime* expr) { |
+ NoObservableSideEffectsScope scope(this); |
DCHECK(expr->arguments()->length() == 1); |
CHECK_ALIVE(VisitForValue(expr->arguments()->at(0))); |
- HValue* buffer = Pop(); |
- HInstruction* result = New<HLoadNamedField>( |
- buffer, nullptr, HObjectAccess::ForJSArrayBufferViewByteLength()); |
- return ast_context()->ReturnInstruction(result, expr->id()); |
+ HValue* view = Pop(); |
+ |
+ return ast_context()->ReturnValue(BuildArrayBufferViewFieldAccessor( |
+ view, nullptr, |
+ FieldIndex::ForInObjectOffset(JSArrayBufferView::kByteLengthOffset))); |
} |
void HOptimizedGraphBuilder::GenerateArrayBufferViewGetByteOffset( |
CallRuntime* expr) { |
+ NoObservableSideEffectsScope scope(this); |
DCHECK(expr->arguments()->length() == 1); |
CHECK_ALIVE(VisitForValue(expr->arguments()->at(0))); |
- HValue* buffer = Pop(); |
- HInstruction* result = New<HLoadNamedField>( |
- buffer, nullptr, HObjectAccess::ForJSArrayBufferViewByteOffset()); |
- return ast_context()->ReturnInstruction(result, expr->id()); |
+ HValue* view = Pop(); |
+ |
+ return ast_context()->ReturnValue(BuildArrayBufferViewFieldAccessor( |
+ view, nullptr, |
+ FieldIndex::ForInObjectOffset(JSArrayBufferView::kByteOffsetOffset))); |
} |
void HOptimizedGraphBuilder::GenerateTypedArrayGetLength( |
CallRuntime* expr) { |
+ NoObservableSideEffectsScope scope(this); |
DCHECK(expr->arguments()->length() == 1); |
CHECK_ALIVE(VisitForValue(expr->arguments()->at(0))); |
- HValue* buffer = Pop(); |
- HInstruction* result = New<HLoadNamedField>( |
- buffer, nullptr, HObjectAccess::ForJSTypedArrayLength()); |
- return ast_context()->ReturnInstruction(result, expr->id()); |
+ HValue* view = Pop(); |
+ |
+ return ast_context()->ReturnValue(BuildArrayBufferViewFieldAccessor( |
+ view, nullptr, |
+ FieldIndex::ForInObjectOffset(JSTypedArray::kLengthOffset))); |
} |