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

Unified Diff: src/hydrogen.cc

Issue 7170012: Crankshaft support for polymorphic array handling (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: address comments; add implemention for ARM and x64 Created 9 years, 6 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
Index: src/hydrogen.cc
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 7ad556476ecb873cd3ee6d143111e0360d534618..5000c14511ba6d30cb11cad3378bc6047258a6de 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -3449,7 +3449,16 @@ void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
value = Pop();
HValue* key = Pop();
HValue* object = Pop();
- instr = BuildStoreKeyed(object, key, value, expr);
+ bool has_side_effects = false;
+ HandleKeyedElementAccess(object, key, value, expr, expr->AssignmentId(),
+ expr->position(),
+ true, // is_store
+ &has_side_effects);
+ Push(value);
+ ASSERT(has_side_effects); // Stores always have side effects.
+ AddSimulate(expr->AssignmentId());
+ ast_context()->ReturnValue(Pop());
+ return;
}
Push(value);
instr->set_position(expr->position());
@@ -3573,9 +3582,14 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
HValue* obj = environment()->ExpressionStackAt(1);
HValue* key = environment()->ExpressionStackAt(0);
- HInstruction* load = BuildLoadKeyed(obj, key, prop);
- PushAndAdd(load);
- if (load->HasSideEffects()) AddSimulate(expr->CompoundLoadId());
+ bool has_side_effects = false;
+ HValue* load = HandleKeyedElementAccess(
+ obj, key, NULL, prop, expr->CompoundLoadId(), RelocInfo::kNoPosition,
+ false, // is_store
+ &has_side_effects);
+ Push(load);
+ if (has_side_effects) AddSimulate(expr->CompoundLoadId());
+
CHECK_ALIVE(VisitForValue(expr->value()));
HValue* right = Pop();
@@ -3586,12 +3600,16 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
if (instr->HasSideEffects()) AddSimulate(operation->id());
expr->RecordTypeFeedback(oracle());
- HInstruction* store = BuildStoreKeyed(obj, key, instr, expr);
- AddInstruction(store);
+ HandleKeyedElementAccess(obj, key, instr, expr, expr->AssignmentId(),
+ RelocInfo::kNoPosition,
+ true, // is_store
+ &has_side_effects);
+
// Drop the simulated receiver, key, and value. Return the value.
Drop(3);
Push(instr);
- if (store->HasSideEffects()) AddSimulate(expr->AssignmentId());
+ ASSERT(has_side_effects); // Stores always have side effects.
+ AddSimulate(expr->AssignmentId());
ast_context()->ReturnValue(Pop());
}
@@ -3755,19 +3773,78 @@ HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object,
}
-HInstruction* HGraphBuilder::BuildLoadKeyedFastElement(HValue* object,
- HValue* key,
- Property* expr) {
- ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic());
- AddInstruction(new(zone()) HCheckNonSmi(object));
+HInstruction* HGraphBuilder::BuildExternalArrayElementAccess(
+ HValue* external_elements,
+ HValue* checked_key,
+ HValue* val,
+ JSObject::ElementsKind elements_kind,
+ bool is_store) {
+ if (is_store) {
+ ASSERT(val != NULL);
+ switch (elements_kind) {
+ case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
+ HClampToUint8* clamp = new(zone()) HClampToUint8(val);
+ AddInstruction(clamp);
+ val = clamp;
+ break;
+ }
+ case JSObject::EXTERNAL_BYTE_ELEMENTS:
+ case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case JSObject::EXTERNAL_SHORT_ELEMENTS:
+ case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case JSObject::EXTERNAL_INT_ELEMENTS:
+ case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
+ HToInt32* floor_val = new(zone()) HToInt32(val);
+ AddInstruction(floor_val);
+ val = floor_val;
+ break;
+ }
+ case JSObject::EXTERNAL_FLOAT_ELEMENTS:
+ case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
+ break;
+ case JSObject::FAST_ELEMENTS:
+ case JSObject::FAST_DOUBLE_ELEMENTS:
+ case JSObject::DICTIONARY_ELEMENTS:
+ UNREACHABLE();
+ break;
+ }
+ return new(zone()) HStoreKeyedSpecializedArrayElement(
+ external_elements, checked_key, val, elements_kind);
+ } else {
+ return new(zone()) HLoadKeyedSpecializedArrayElement(
+ external_elements, checked_key, elements_kind);
+ }
+}
+
+
+HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object,
+ HValue* key,
+ HValue* val,
+ Expression* expr,
+ bool is_store) {
+ ASSERT(expr->IsMonomorphic());
Handle<Map> map = expr->GetMonomorphicReceiverType();
- ASSERT(map->has_fast_elements());
+ if (!map->has_fast_elements() && !map->has_external_array_elements()) {
+ return is_store ? BuildStoreKeyedGeneric(object, key, val)
+ : BuildLoadKeyedGeneric(object, key);
+ }
+ AddInstruction(new(zone()) HCheckNonSmi(object));
AddInstruction(new(zone()) HCheckMap(object, map));
- bool is_array = (map->instance_type() == JS_ARRAY_TYPE);
- HLoadElements* elements = new(zone()) HLoadElements(object);
+ HInstruction* elements = new(zone()) HLoadElements(object);
HInstruction* length = NULL;
HInstruction* checked_key = NULL;
- if (is_array) {
+ if (map->has_external_array_elements()) {
+ AddInstruction(elements);
+ length = AddInstruction(new(zone()) HExternalArrayLength(elements));
+ checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
+ HLoadExternalArrayPointer* external_elements =
+ new(zone()) HLoadExternalArrayPointer(elements);
+ AddInstruction(external_elements);
+ return BuildExternalArrayElementAccess(external_elements, checked_key,
+ val, map->elements_kind(), is_store);
+ }
+ ASSERT(map->has_fast_elements());
+ if (map->instance_type() == JS_ARRAY_TYPE) {
length = AddInstruction(new(zone()) HJSArrayLength(object));
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
AddInstruction(elements);
@@ -3776,51 +3853,181 @@ HInstruction* HGraphBuilder::BuildLoadKeyedFastElement(HValue* object,
length = AddInstruction(new(zone()) HFixedArrayLength(elements));
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
}
- return new(zone()) HLoadKeyedFastElement(elements, checked_key);
+ if (is_store) {
+ return new(zone()) HStoreKeyedFastElement(elements, checked_key, val);
+ } else {
+ return new(zone()) HLoadKeyedFastElement(elements, checked_key);
+ }
}
-HInstruction* HGraphBuilder::BuildLoadKeyedSpecializedArrayElement(
- HValue* object,
- HValue* key,
- Property* expr) {
- ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic());
+HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
+ HValue* key,
+ HValue* val,
+ Expression* prop,
+ int ast_id,
+ int position,
+ bool is_store,
+ bool* has_side_effects) {
+ *has_side_effects = false;
AddInstruction(new(zone()) HCheckNonSmi(object));
- Handle<Map> map = expr->GetMonomorphicReceiverType();
- ASSERT(!map->has_fast_elements());
- ASSERT(map->has_external_array_elements());
- AddInstruction(new(zone()) HCheckMap(object, map));
- HLoadElements* elements = new(zone()) HLoadElements(object);
- AddInstruction(elements);
- HInstruction* length = new(zone()) HExternalArrayLength(elements);
- AddInstruction(length);
- HInstruction* checked_key =
- AddInstruction(new(zone()) HBoundsCheck(key, length));
- HLoadExternalArrayPointer* external_elements =
- new(zone()) HLoadExternalArrayPointer(elements);
- AddInstruction(external_elements);
- HLoadKeyedSpecializedArrayElement* pixel_array_value =
- new(zone()) HLoadKeyedSpecializedArrayElement(
- external_elements, checked_key, map->elements_kind());
- return pixel_array_value;
+ AddInstruction(HCheckInstanceType::NewIsSpecObject(object));
+ ZoneMapList* maps = prop->GetReceiverTypes();
+ bool todo_external_array = false;
+
+ static const int kNumElementTypes = JSObject::kElementsKindCount;
+ bool type_todo[kNumElementTypes];
+ for (int i = 0; i < kNumElementTypes; ++i) {
+ type_todo[i] = false;
+ }
+
+ for (int i = 0; i < maps->length(); ++i) {
+ ASSERT(maps->at(i)->IsMap());
+ type_todo[maps->at(i)->elements_kind()] = true;
+ if (maps->at(i)->elements_kind()
+ >= JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND) {
+ todo_external_array = true;
+ }
+ }
+ // We can't treat dictionary elements here (need to deopt instead).
+ type_todo[JSObject::DICTIONARY_ELEMENTS] = false;
+ // Support for FAST_DOUBLE_ELEMENTS isn't implemented yet, so we deopt.
+ type_todo[JSObject::FAST_DOUBLE_ELEMENTS] = false;
+
+ HBasicBlock* join = graph()->CreateBasicBlock();
+
+ HInstruction* elements_kind_instr =
+ AddInstruction(new(zone()) HElementsKind(object));
+ HInstruction* elements = NULL;
+ HLoadExternalArrayPointer* external_elements = NULL;
+ HInstruction* checked_key = NULL;
+
+ // FAST_ELEMENTS is assumed to be the first case.
+ STATIC_ASSERT(JSObject::FAST_ELEMENTS == 0);
+
+ for (JSObject::ElementsKind elements_kind = JSObject::FAST_ELEMENTS;
+ elements_kind <= JSObject::LAST_ELEMENTS_KIND;
+ elements_kind = JSObject::ElementsKind(elements_kind + 1)) {
+ // After having handled FAST_ELEMENTS in the first run of the loop, we
+ // need to add some code that's executed for all other cases.
+ if (elements_kind == 1 && todo_external_array) {
Søren Thygesen Gjesse 2011/06/21 07:09:04 Shouldn't the constant 1 here be JSObject::FAST_EL
Jakob Kummerow 2011/06/21 07:49:23 No. FAST_ELEMENTS == 0. As the comment indicates,
Søren Thygesen Gjesse 2011/06/21 10:01:53 I see. I think it should stay at the beginning of
+ elements = AddInstruction(new(zone()) HLoadElements(object));
+ // We need to forcibly prevent some ElementsKind-dependent instructions
+ // from being hoisted out of any loops they might occur in, because
+ // the current loop-invariant-code-motion algorithm isn't clever enough
+ // to deal with them properly.
+ // There's some performance to be gained by developing a smarter
+ // solution for this.
+ elements->ClearFlag(HValue::kUseGVN);
+ HInstruction* length =
+ AddInstruction(new(zone()) HExternalArrayLength(elements));
+ checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
+ external_elements = new(zone()) HLoadExternalArrayPointer(elements);
+ AddInstruction(external_elements);
+ }
+ if (type_todo[elements_kind]) {
+ HBasicBlock* if_true = graph()->CreateBasicBlock();
+ HBasicBlock* if_false = graph()->CreateBasicBlock();
+ HCompareConstantEq* compare = new(zone()) HCompareConstantEq(
+ elements_kind_instr,
+ elements_kind,
+ Token::EQ_STRICT);
+ AddInstruction(compare);
+ HTest* branch = new(zone()) HTest(compare, if_true, if_false);
+ current_block()->Finish(branch);
+
+ set_current_block(if_true);
+ HInstruction* access;
+ if (elements_kind == JSObject::FAST_ELEMENTS) {
+ HBasicBlock* if_jsarray = graph()->CreateBasicBlock();
+ HBasicBlock* if_fastobject = graph()->CreateBasicBlock();
+ HInstruction* typecheck =
+ AddInstruction(new(zone()) HHasInstanceType(object, JS_ARRAY_TYPE));
+ HTest* test = new(zone()) HTest(typecheck, if_jsarray, if_fastobject);
+ current_block()->Finish(test);
+
+ set_current_block(if_jsarray);
+ HInstruction* length = new(zone()) HJSArrayLength(object);
+ AddInstruction(length);
+ length->ClearFlag(HValue::kUseGVN);
+ checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
+ elements = AddInstruction(new(zone()) HLoadElements(object));
+ elements->ClearFlag(HValue::kUseGVN);
+ if (is_store) {
+ access = AddInstruction(
+ new(zone()) HStoreKeyedFastElement(elements, checked_key, val));
+ } else {
+ access = AddInstruction(
+ new(zone()) HLoadKeyedFastElement(elements, checked_key));
+ Push(access);
+ }
+ *has_side_effects |= access->HasSideEffects();
+ if (position != -1) {
+ access->set_position(position);
+ }
+ if_jsarray->Goto(join);
+
+ set_current_block(if_fastobject);
+ elements = AddInstruction(new(zone()) HLoadElements(object));
+ elements->ClearFlag(HValue::kUseGVN);
+ length = AddInstruction(new(zone()) HFixedArrayLength(elements));
+ checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
+ if (is_store) {
+ access = AddInstruction(
+ new(zone()) HStoreKeyedFastElement(elements, checked_key, val));
+ } else {
+ access = AddInstruction(
+ new(zone()) HLoadKeyedFastElement(elements, checked_key));
+ }
+ } else { // External array elements.
+ access = AddInstruction(BuildExternalArrayElementAccess(
+ external_elements, checked_key, val, elements_kind, is_store));
+ }
+ *has_side_effects |= access->HasSideEffects();
+ access->set_position(position);
+ if (!is_store) {
+ Push(access);
+ }
+ current_block()->Goto(join);
+ set_current_block(if_false);
+ }
+ }
+
+ // Deopt if none of the cases matched.
+ current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses);
+ join->SetJoinId(ast_id);
+ set_current_block(join);
+ return is_store ? NULL : Pop();
}
-HInstruction* HGraphBuilder::BuildLoadKeyed(HValue* obj,
- HValue* key,
- Property* prop) {
- if (prop->IsMonomorphic()) {
- Handle<Map> receiver_type(prop->GetMonomorphicReceiverType());
- // An object has either fast elements or pixel array elements, but never
- // both. Pixel array maps that are assigned to pixel array elements are
- // always created with the fast elements flag cleared.
- if (receiver_type->has_external_array_elements()) {
- return BuildLoadKeyedSpecializedArrayElement(obj, key, prop);
- } else if (receiver_type->has_fast_elements()) {
- return BuildLoadKeyedFastElement(obj, key, prop);
+HValue* HGraphBuilder::HandleKeyedElementAccess(HValue* obj,
+ HValue* key,
+ HValue* val,
+ Expression* expr,
+ int ast_id,
+ int position,
+ bool is_store,
+ bool* has_side_effects) {
+ ASSERT(!expr->IsPropertyName());
+ HInstruction* instr = NULL;
+ if (expr->IsMonomorphic()) {
+ instr = BuildMonomorphicElementAccess(obj, key, val, expr, is_store);
+ } else if (expr->GetReceiverTypes() != NULL &&
+ !expr->GetReceiverTypes()->is_empty()) {
+ return HandlePolymorphicElementAccess(
+ obj, key, val, expr, ast_id, position, is_store, has_side_effects);
+ } else {
+ if (is_store) {
+ instr = BuildStoreKeyedGeneric(obj, key, val);
+ } else {
+ instr = BuildLoadKeyedGeneric(obj, key);
}
}
- return BuildLoadKeyedGeneric(obj, key);
+ instr->set_position(position);
+ AddInstruction(instr);
+ *has_side_effects = instr->HasSideEffects();
+ return instr;
}
@@ -3836,111 +4043,6 @@ HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object,
function_strict_mode());
}
-
-HInstruction* HGraphBuilder::BuildStoreKeyedFastElement(HValue* object,
- HValue* key,
- HValue* val,
- Expression* expr) {
- ASSERT(expr->IsMonomorphic());
- AddInstruction(new(zone()) HCheckNonSmi(object));
- Handle<Map> map = expr->GetMonomorphicReceiverType();
- ASSERT(map->has_fast_elements());
- AddInstruction(new(zone()) HCheckMap(object, map));
- HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object));
- AddInstruction(new(zone()) HCheckMap(
- elements, isolate()->factory()->fixed_array_map()));
- bool is_array = (map->instance_type() == JS_ARRAY_TYPE);
- HInstruction* length = NULL;
- if (is_array) {
- length = AddInstruction(new(zone()) HJSArrayLength(object));
- } else {
- length = AddInstruction(new(zone()) HFixedArrayLength(elements));
- }
- HInstruction* checked_key =
- AddInstruction(new(zone()) HBoundsCheck(key, length));
- return new(zone()) HStoreKeyedFastElement(elements, checked_key, val);
-}
-
-
-HInstruction* HGraphBuilder::BuildStoreKeyedSpecializedArrayElement(
- HValue* object,
- HValue* key,
- HValue* val,
- Expression* expr) {
- ASSERT(expr->IsMonomorphic());
- AddInstruction(new(zone()) HCheckNonSmi(object));
- Handle<Map> map = expr->GetMonomorphicReceiverType();
- ASSERT(!map->has_fast_elements());
- ASSERT(map->has_external_array_elements());
- AddInstruction(new(zone()) HCheckMap(object, map));
- HLoadElements* elements = new(zone()) HLoadElements(object);
- AddInstruction(elements);
- HInstruction* length = AddInstruction(
- new(zone()) HExternalArrayLength(elements));
- HInstruction* checked_key =
- AddInstruction(new(zone()) HBoundsCheck(key, length));
- HLoadExternalArrayPointer* external_elements =
- new(zone()) HLoadExternalArrayPointer(elements);
- AddInstruction(external_elements);
- JSObject::ElementsKind elements_kind = map->elements_kind();
- switch (elements_kind) {
- case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
- HClampToUint8* clamp = new(zone()) HClampToUint8(val);
- AddInstruction(clamp);
- val = clamp;
- break;
- }
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
- HToInt32* floor_val = new(zone()) HToInt32(val);
- AddInstruction(floor_val);
- val = floor_val;
- break;
- }
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- break;
-
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- UNREACHABLE();
- break;
- }
- return new(zone()) HStoreKeyedSpecializedArrayElement(
- external_elements,
- checked_key,
- val,
- map->elements_kind());
-}
-
-
-HInstruction* HGraphBuilder::BuildStoreKeyed(HValue* object,
- HValue* key,
- HValue* value,
- Expression* expr) {
- if (expr->IsMonomorphic()) {
- Handle<Map> receiver_type(expr->GetMonomorphicReceiverType());
- // An object has either fast elements or external array elements, but
- // never both. Pixel array maps that are assigned to pixel array elements
- // are always created with the fast elements flag cleared.
- if (receiver_type->has_external_array_elements()) {
- return BuildStoreKeyedSpecializedArrayElement(object,
- key,
- value,
- expr);
- } else if (receiver_type->has_fast_elements()) {
- return BuildStoreKeyedFastElement(object, key, value, expr);
- }
- }
- return BuildStoreKeyedGeneric(object, key, value);
-}
-
-
bool HGraphBuilder::TryArgumentsAccess(Property* expr) {
VariableProxy* proxy = expr->obj()->AsVariableProxy();
if (proxy == NULL) return false;
@@ -4034,7 +4136,23 @@ void HGraphBuilder::VisitProperty(Property* expr) {
HValue* key = Pop();
HValue* obj = Pop();
- instr = BuildLoadKeyed(obj, key, expr);
+
+ bool has_side_effects = false;
+ HValue* load = HandleKeyedElementAccess(
+ obj, key, NULL, expr, expr->id(), expr->position(),
+ false, // is_store
+ &has_side_effects);
+ if (has_side_effects) {
+ if (ast_context()->IsEffect()) {
+ AddSimulate(expr->id());
+ } else {
+ Push(load);
+ AddSimulate(expr->id());
+ Drop(1);
+ }
+ }
+ ast_context()->ReturnValue(load);
+ return;
}
instr->set_position(expr->position());
ast_context()->ReturnInstruction(instr, expr->id());
@@ -5044,16 +5162,22 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
HValue* obj = environment()->ExpressionStackAt(1);
HValue* key = environment()->ExpressionStackAt(0);
- HInstruction* load = BuildLoadKeyed(obj, key, prop);
- PushAndAdd(load);
- if (load->HasSideEffects()) AddSimulate(expr->CountId());
+ bool has_side_effects = false;
+ HValue* load = HandleKeyedElementAccess(
+ obj, key, NULL, prop, expr->CountId(), RelocInfo::kNoPosition,
+ false, // is_store
+ &has_side_effects);
+ Push(load);
+ if (has_side_effects) AddSimulate(expr->CountId());
after = BuildIncrement(returns_original_input, expr);
input = Pop();
expr->RecordTypeFeedback(oracle());
- HInstruction* store = BuildStoreKeyed(obj, key, after, expr);
- AddInstruction(store);
+ HandleKeyedElementAccess(obj, key, after, expr, expr->AssignmentId(),
+ RelocInfo::kNoPosition,
+ true, // is_store
+ &has_side_effects);
// Drop the key from the bailout environment. Overwrite the receiver
// with the result of the operation, and the placeholder with the
@@ -5061,7 +5185,8 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
Drop(1);
environment()->SetExpressionStackAt(0, after);
if (returns_original_input) environment()->SetExpressionStackAt(1, input);
- if (store->HasSideEffects()) AddSimulate(expr->AssignmentId());
+ ASSERT(has_side_effects); // Stores always have side effects.
+ AddSimulate(expr->AssignmentId());
}
}
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-instructions.h » ('j') | src/objects-inl.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698