| Index: src/hydrogen.cc
|
| ===================================================================
|
| --- src/hydrogen.cc (revision 8778)
|
| +++ src/hydrogen.cc (working copy)
|
| @@ -736,6 +736,8 @@
|
| HPhase phase("Assign dominators", this);
|
| for (int i = 0; i < blocks_.length(); ++i) {
|
| if (blocks_[i]->IsLoopHeader()) {
|
| + // Only the first predecessor of a loop header is from outside the loop.
|
| + // All others are back edges, and thus cannot dominate the loop header.
|
| blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->first());
|
| } else {
|
| for (int j = 0; j < blocks_[i]->predecessors()->length(); ++j) {
|
| @@ -743,13 +745,15 @@
|
| }
|
| }
|
| }
|
| +}
|
|
|
| - // Propagate flag marking blocks containing unconditional deoptimize.
|
| +// Mark all blocks that are dominated by an unconditional soft deoptimize to
|
| +// prevent code motion across those blocks.
|
| +void HGraph::PropagateDeoptimizingMark() {
|
| + HPhase phase("Propagate deoptimizing mark", this);
|
| MarkAsDeoptimizingRecursively(entry_block());
|
| }
|
|
|
| -
|
| -// Mark all blocks that are dominated by an unconditional deoptimize.
|
| void HGraph::MarkAsDeoptimizingRecursively(HBasicBlock* block) {
|
| for (int i = 0; i < block->dominated_blocks()->length(); ++i) {
|
| HBasicBlock* dominated = block->dominated_blocks()->at(i);
|
| @@ -836,6 +840,19 @@
|
| }
|
|
|
|
|
| +bool HGraph::CheckPhis() {
|
| + int block_count = blocks_.length();
|
| + for (int i = 0; i < block_count; ++i) {
|
| + for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
|
| + HPhi* phi = blocks_[i]->phis()->at(j);
|
| + // We don't support phi uses of arguments for now.
|
| + if (phi->CheckFlag(HValue::kIsArguments)) return false;
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +
|
| bool HGraph::CollectPhis() {
|
| int block_count = blocks_.length();
|
| phi_list_ = new ZoneList<HPhi*>(block_count);
|
| @@ -843,8 +860,6 @@
|
| for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
|
| HPhi* phi = blocks_[i]->phis()->at(j);
|
| phi_list_->Add(phi);
|
| - // We don't support phi uses of arguments for now.
|
| - if (phi->CheckFlag(HValue::kIsArguments)) return false;
|
| // Check for the hole value (from an uninitialized const).
|
| for (int k = 0; k < phi->OperandCount(); k++) {
|
| if (phi->OperandAt(k) == GetConstantHole()) return false;
|
| @@ -1666,8 +1681,8 @@
|
| HValue* use = it.value();
|
| if (use->IsPhi()) {
|
| int id = HPhi::cast(use)->phi_id();
|
| - change = change ||
|
| - connected_phis[i]->UnionIsChanged(*connected_phis[id]);
|
| + if (connected_phis[i]->UnionIsChanged(*connected_phis[id]))
|
| + change = true;
|
| }
|
| }
|
| }
|
| @@ -2158,7 +2173,9 @@
|
| }
|
| HBasicBlock* empty_true = builder->graph()->CreateBasicBlock();
|
| HBasicBlock* empty_false = builder->graph()->CreateBasicBlock();
|
| - HBranch* test = new(zone()) HBranch(value, empty_true, empty_false);
|
| + unsigned test_id = condition()->test_id();
|
| + ToBooleanStub::Types expected(builder->oracle()->ToBooleanTypes(test_id));
|
| + HBranch* test = new(zone()) HBranch(value, empty_true, empty_false, expected);
|
| builder->current_block()->Finish(test);
|
|
|
| empty_true->Goto(if_true());
|
| @@ -2293,10 +2310,15 @@
|
|
|
| graph()->OrderBlocks();
|
| graph()->AssignDominators();
|
| + graph()->PropagateDeoptimizingMark();
|
| + if (!graph()->CheckPhis()) {
|
| + Bailout("Unsupported phi use of arguments object");
|
| + return NULL;
|
| + }
|
| graph()->EliminateRedundantPhis();
|
| if (FLAG_eliminate_dead_phis) graph()->EliminateUnreachablePhis();
|
| if (!graph()->CollectPhis()) {
|
| - Bailout("Unsupported phi-use");
|
| + Bailout("Unsupported phi use of uninitialized constant");
|
| return NULL;
|
| }
|
|
|
| @@ -3274,8 +3296,8 @@
|
|
|
| // Load the elements array before the first store.
|
| if (elements == NULL) {
|
| - elements = new(zone()) HLoadElements(literal);
|
| - AddInstruction(elements);
|
| + elements = new(zone()) HLoadElements(literal);
|
| + AddInstruction(elements);
|
| }
|
|
|
| HValue* key = AddInstruction(
|
| @@ -3901,17 +3923,23 @@
|
| bool is_store) {
|
| ASSERT(expr->IsMonomorphic());
|
| Handle<Map> map = expr->GetMonomorphicReceiverType();
|
| - if (!map->has_fast_elements() && !map->has_external_array_elements()) {
|
| + if (!map->has_fast_elements() &&
|
| + !map->has_fast_double_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));
|
| - HInstruction* elements = new(zone()) HLoadElements(object);
|
| + HInstruction* mapcheck = AddInstruction(new(zone()) HCheckMap(object, map));
|
| + HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object));
|
| + bool fast_double_elements = map->has_fast_double_elements();
|
| + if (is_store && map->has_fast_elements()) {
|
| + AddInstruction(new(zone()) HCheckMap(
|
| + elements, isolate()->factory()->fixed_array_map()));
|
| + }
|
| HInstruction* length = NULL;
|
| HInstruction* checked_key = NULL;
|
| 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 =
|
| @@ -3920,20 +3948,27 @@
|
| return BuildExternalArrayElementAccess(external_elements, checked_key,
|
| val, map->elements_kind(), is_store);
|
| }
|
| - ASSERT(map->has_fast_elements());
|
| + ASSERT(map->has_fast_elements() || fast_double_elements);
|
| if (map->instance_type() == JS_ARRAY_TYPE) {
|
| - length = AddInstruction(new(zone()) HJSArrayLength(object));
|
| - checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
|
| - AddInstruction(elements);
|
| + length = AddInstruction(new(zone()) HJSArrayLength(object, mapcheck));
|
| } else {
|
| - AddInstruction(elements);
|
| length = AddInstruction(new(zone()) HFixedArrayLength(elements));
|
| - checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
|
| }
|
| + checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
|
| if (is_store) {
|
| - return new(zone()) HStoreKeyedFastElement(elements, checked_key, val);
|
| + if (fast_double_elements) {
|
| + return new(zone()) HStoreKeyedFastDoubleElement(elements,
|
| + checked_key,
|
| + val);
|
| + } else {
|
| + return new(zone()) HStoreKeyedFastElement(elements, checked_key, val);
|
| + }
|
| } else {
|
| - return new(zone()) HLoadKeyedFastElement(elements, checked_key);
|
| + if (fast_double_elements) {
|
| + return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key);
|
| + } else {
|
| + return new(zone()) HLoadKeyedFastElement(elements, checked_key);
|
| + }
|
| }
|
| }
|
|
|
| @@ -3966,14 +4001,13 @@
|
| todo_external_array = true;
|
| }
|
| }
|
| - // 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;
|
| + HCompareConstantEqAndBranch* elements_kind_branch = NULL;
|
| + HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object));
|
| HLoadExternalArrayPointer* external_elements = NULL;
|
| HInstruction* checked_key = NULL;
|
|
|
| @@ -3989,14 +4023,6 @@
|
| JSObject::LAST_ELEMENTS_KIND);
|
| if (elements_kind == JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND
|
| && todo_external_array) {
|
| - 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));
|
| @@ -4006,17 +4032,23 @@
|
| if (type_todo[elements_kind]) {
|
| HBasicBlock* if_true = graph()->CreateBasicBlock();
|
| HBasicBlock* if_false = graph()->CreateBasicBlock();
|
| - HCompareConstantEqAndBranch* compare =
|
| - new(zone()) HCompareConstantEqAndBranch(elements_kind_instr,
|
| - elements_kind,
|
| - Token::EQ_STRICT);
|
| - compare->SetSuccessorAt(0, if_true);
|
| - compare->SetSuccessorAt(1, if_false);
|
| - current_block()->Finish(compare);
|
| + elements_kind_branch = new(zone()) HCompareConstantEqAndBranch(
|
| + elements_kind_instr, elements_kind, Token::EQ_STRICT);
|
| + elements_kind_branch->SetSuccessorAt(0, if_true);
|
| + elements_kind_branch->SetSuccessorAt(1, if_false);
|
| + current_block()->Finish(elements_kind_branch);
|
|
|
| set_current_block(if_true);
|
| HInstruction* access;
|
| - if (elements_kind == JSObject::FAST_ELEMENTS) {
|
| + if (elements_kind == JSObject::FAST_ELEMENTS ||
|
| + elements_kind == JSObject::FAST_DOUBLE_ELEMENTS) {
|
| + bool fast_double_elements =
|
| + elements_kind == JSObject::FAST_DOUBLE_ELEMENTS;
|
| + if (is_store && elements_kind == JSObject::FAST_ELEMENTS) {
|
| + AddInstruction(new(zone()) HCheckMap(
|
| + elements, isolate()->factory()->fixed_array_map(),
|
| + elements_kind_branch));
|
| + }
|
| HBasicBlock* if_jsarray = graph()->CreateBasicBlock();
|
| HBasicBlock* if_fastobject = graph()->CreateBasicBlock();
|
| HHasInstanceTypeAndBranch* typecheck =
|
| @@ -4026,18 +4058,27 @@
|
| current_block()->Finish(typecheck);
|
|
|
| set_current_block(if_jsarray);
|
| - HInstruction* length = new(zone()) HJSArrayLength(object);
|
| + HInstruction* length = new(zone()) HJSArrayLength(object, typecheck);
|
| 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));
|
| + if (fast_double_elements) {
|
| + access = AddInstruction(
|
| + new(zone()) HStoreKeyedFastDoubleElement(elements,
|
| + checked_key,
|
| + val));
|
| + } else {
|
| + access = AddInstruction(
|
| + new(zone()) HStoreKeyedFastElement(elements, checked_key, val));
|
| + }
|
| } else {
|
| - access = AddInstruction(
|
| - new(zone()) HLoadKeyedFastElement(elements, checked_key));
|
| + if (fast_double_elements) {
|
| + access = AddInstruction(
|
| + new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key));
|
| + } else {
|
| + access = AddInstruction(
|
| + new(zone()) HLoadKeyedFastElement(elements, checked_key));
|
| + }
|
| Push(access);
|
| }
|
| *has_side_effects |= access->HasSideEffects();
|
| @@ -4047,16 +4088,26 @@
|
| 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));
|
| + if (fast_double_elements) {
|
| + access = AddInstruction(
|
| + new(zone()) HStoreKeyedFastDoubleElement(elements,
|
| + checked_key,
|
| + val));
|
| + } else {
|
| + access = AddInstruction(
|
| + new(zone()) HStoreKeyedFastElement(elements, checked_key, val));
|
| + }
|
| } else {
|
| - access = AddInstruction(
|
| - new(zone()) HLoadKeyedFastElement(elements, checked_key));
|
| + if (fast_double_elements) {
|
| + access = AddInstruction(
|
| + new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key));
|
| + } else {
|
| + access = AddInstruction(
|
| + new(zone()) HLoadKeyedFastElement(elements, checked_key));
|
| + }
|
| }
|
| } else if (elements_kind == JSObject::DICTIONARY_ELEMENTS) {
|
| if (is_store) {
|
| @@ -4181,8 +4232,9 @@
|
| if (expr->IsArrayLength()) {
|
| HValue* array = Pop();
|
| AddInstruction(new(zone()) HCheckNonSmi(array));
|
| - AddInstruction(HCheckInstanceType::NewIsJSArray(array));
|
| - instr = new(zone()) HJSArrayLength(array);
|
| + HInstruction* mapcheck =
|
| + AddInstruction(HCheckInstanceType::NewIsJSArray(array));
|
| + instr = new(zone()) HJSArrayLength(array, mapcheck);
|
|
|
| } else if (expr->IsStringLength()) {
|
| HValue* string = Pop();
|
| @@ -5474,9 +5526,11 @@
|
| // We need an extra block to maintain edge-split form.
|
| HBasicBlock* empty_block = graph()->CreateBasicBlock();
|
| HBasicBlock* eval_right = graph()->CreateBasicBlock();
|
| + unsigned test_id = expr->left()->test_id();
|
| + ToBooleanStub::Types expected(oracle()->ToBooleanTypes(test_id));
|
| HBranch* test = is_logical_and
|
| - ? new(zone()) HBranch(Top(), eval_right, empty_block)
|
| - : new(zone()) HBranch(Top(), empty_block, eval_right);
|
| + ? new(zone()) HBranch(Top(), eval_right, empty_block, expected)
|
| + : new(zone()) HBranch(Top(), empty_block, eval_right, expected);
|
| current_block()->Finish(test);
|
|
|
| set_current_block(eval_right);
|
|
|