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

Unified Diff: src/hydrogen.cc

Issue 7060010: Merge bleeding edge into the GC branch up to 7948. The asserts (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/gc/
Patch Set: Created 9 years, 7 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/hydrogen.h ('k') | src/hydrogen-instructions.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/hydrogen.cc
===================================================================
--- src/hydrogen.cc (revision 7948)
+++ src/hydrogen.cc (working copy)
@@ -115,12 +115,13 @@
}
-HDeoptimize* HBasicBlock::CreateDeoptimize() {
+HDeoptimize* HBasicBlock::CreateDeoptimize(
+ HDeoptimize::UseEnvironment has_uses) {
ASSERT(HasEnvironment());
+ if (has_uses == HDeoptimize::kNoUses) return new(zone()) HDeoptimize(0);
+
HEnvironment* environment = last_environment();
-
HDeoptimize* instr = new(zone()) HDeoptimize(environment->length());
-
for (int i = 0; i < environment->length(); i++) {
HValue* val = environment->values()->at(i);
instr->AddEnvironmentValue(val);
@@ -1020,13 +1021,13 @@
}
-HValueMap::HValueMap(const HValueMap* other)
+HValueMap::HValueMap(Zone* zone, const HValueMap* other)
: array_size_(other->array_size_),
lists_size_(other->lists_size_),
count_(other->count_),
present_flags_(other->present_flags_),
- array_(ZONE->NewArray<HValueMapListElement>(other->array_size_)),
- lists_(ZONE->NewArray<HValueMapListElement>(other->lists_size_)),
+ array_(zone->NewArray<HValueMapListElement>(other->array_size_)),
+ lists_(zone->NewArray<HValueMapListElement>(other->lists_size_)),
free_list_head_(other->free_list_head_) {
memcpy(array_, other->array_, array_size_ * sizeof(HValueMapListElement));
memcpy(lists_, other->lists_, lists_size_ * sizeof(HValueMapListElement));
@@ -1239,13 +1240,49 @@
}
+// Simple sparse set with O(1) add, contains, and clear.
+class SparseSet {
+ public:
+ SparseSet(Zone* zone, int capacity)
+ : capacity_(capacity),
+ length_(0),
+ dense_(zone->NewArray<int>(capacity)),
+ sparse_(zone->NewArray<int>(capacity)) {}
+
+ bool Contains(int n) const {
+ ASSERT(0 <= n && n < capacity_);
+ int d = sparse_[n];
+ return 0 <= d && d < length_ && dense_[d] == n;
+ }
+
+ bool Add(int n) {
+ if (Contains(n)) return false;
+ dense_[length_] = n;
+ sparse_[n] = length_;
+ ++length_;
+ return true;
+ }
+
+ void Clear() { length_ = 0; }
+
+ private:
+ int capacity_;
+ int length_;
+ int* dense_;
+ int* sparse_;
+
+ DISALLOW_COPY_AND_ASSIGN(SparseSet);
+};
+
+
class HGlobalValueNumberer BASE_EMBEDDED {
public:
explicit HGlobalValueNumberer(HGraph* graph, CompilationInfo* info)
: graph_(graph),
info_(info),
- block_side_effects_(graph_->blocks()->length()),
- loop_side_effects_(graph_->blocks()->length()) {
+ block_side_effects_(graph->blocks()->length()),
+ loop_side_effects_(graph->blocks()->length()),
+ visited_on_paths_(graph->zone(), graph->blocks()->length()) {
ASSERT(info->isolate()->heap()->allow_allocation(false));
block_side_effects_.AddBlock(0, graph_->blocks()->length());
loop_side_effects_.AddBlock(0, graph_->blocks()->length());
@@ -1257,6 +1294,8 @@
void Analyze();
private:
+ int CollectSideEffectsOnPathsToDominatedBlock(HBasicBlock* dominator,
+ HBasicBlock* dominated);
void AnalyzeBlock(HBasicBlock* block, HValueMap* map);
void ComputeBlockSideEffects();
void LoopInvariantCodeMotion();
@@ -1278,6 +1317,10 @@
// A map of loop header block IDs to their loop's side effects.
ZoneList<int> loop_side_effects_;
+
+ // Used when collecting side effects on paths from dominator to
+ // dominated.
+ SparseSet visited_on_paths_;
};
@@ -1413,8 +1456,27 @@
}
+int HGlobalValueNumberer::CollectSideEffectsOnPathsToDominatedBlock(
+ HBasicBlock* dominator, HBasicBlock* dominated) {
+ int side_effects = 0;
+ for (int i = 0; i < dominated->predecessors()->length(); ++i) {
+ HBasicBlock* block = dominated->predecessors()->at(i);
+ if (dominator->block_id() < block->block_id() &&
+ block->block_id() < dominated->block_id() &&
+ visited_on_paths_.Add(block->block_id())) {
+ side_effects |= block_side_effects_[block->block_id()];
+ side_effects |= CollectSideEffectsOnPathsToDominatedBlock(
+ dominator, block);
+ }
+ }
+ return side_effects;
+}
+
+
void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) {
- TraceGVN("Analyzing block B%d\n", block->block_id());
+ TraceGVN("Analyzing block B%d%s\n",
+ block->block_id(),
+ block->IsLoopHeader() ? " (loop header)" : "");
// If this is a loop header kill everything killed by the loop.
if (block->IsLoopHeader()) {
@@ -1455,23 +1517,18 @@
// No need to copy the map for the last child in the dominator tree.
HValueMap* successor_map = (i == length - 1) ? map : map->Copy(zone());
- // If the dominated block is not a successor to this block we have to
- // kill everything killed on any path between this block and the
- // dominated block. Note we rely on the block ordering.
- bool is_successor = false;
- int predecessor_count = dominated->predecessors()->length();
- for (int j = 0; !is_successor && j < predecessor_count; ++j) {
- is_successor = (dominated->predecessors()->at(j) == block);
+ // Kill everything killed on any path between this block and the
+ // dominated block.
+ // We don't have to traverse these paths if the value map is
+ // already empty.
+ // If the range of block ids (block_id, dominated_id) is empty
+ // there are no such paths.
+ if (!successor_map->IsEmpty() &&
+ block->block_id() + 1 < dominated->block_id()) {
+ visited_on_paths_.Clear();
+ successor_map->Kill(CollectSideEffectsOnPathsToDominatedBlock(block,
+ dominated));
}
-
- if (!is_successor) {
- int side_effects = 0;
- for (int j = block->block_id() + 1; j < dominated->block_id(); ++j) {
- side_effects |= block_side_effects_[j];
- }
- successor_map->Kill(side_effects);
- }
-
AnalyzeBlock(dominated, successor_map);
}
}
@@ -1802,6 +1859,12 @@
ASSERT(value->IsConstant());
value->DeleteAndReplaceWith(NULL);
}
+
+ // The only purpose of a HForceRepresentation is to represent the value
+ // after the (possible) HChange instruction. We make it disappear.
+ if (value->IsForceRepresentation()) {
+ value->DeleteAndReplaceWith(HForceRepresentation::cast(value)->value());
+ }
}
@@ -2229,14 +2292,21 @@
// Set the initial values of parameters including "this". "This" has
// parameter index 0.
- int count = scope->num_parameters() + 1;
- for (int i = 0; i < count; ++i) {
+ ASSERT_EQ(scope->num_parameters() + 1, environment()->parameter_count());
+
+ for (int i = 0; i < environment()->parameter_count(); ++i) {
HInstruction* parameter = AddInstruction(new(zone()) HParameter(i));
environment()->Bind(i, parameter);
}
- // Set the initial values of stack-allocated locals.
- for (int i = count; i < environment()->length(); ++i) {
+ // First special is HContext.
+ HInstruction* context = AddInstruction(new(zone()) HContext);
+ environment()->BindContext(context);
+
+ // Initialize specials and locals to undefined.
+ for (int i = environment()->parameter_count() + 1;
+ i < environment()->length();
+ ++i) {
environment()->Bind(i, undefined_constant);
}
@@ -2483,7 +2553,9 @@
// Unconditionally deoptimize on the first non-smi compare.
clause->RecordTypeFeedback(oracle());
if (!clause->IsSmiCompare()) {
- current_block()->FinishExitWithDeoptimization();
+ // Finish with deoptimize and add uses of enviroment values to
+ // account for invisible uses.
+ current_block()->FinishExitWithDeoptimization(HDeoptimize::kUseAll);
set_current_block(NULL);
break;
}
@@ -2519,9 +2591,11 @@
// Identify the block where normal (non-fall-through) control flow
// goes to.
HBasicBlock* normal_block = NULL;
- if (clause->is_default() && last_block != NULL) {
- normal_block = last_block;
- last_block = NULL; // Cleared to indicate we've handled it.
+ if (clause->is_default()) {
+ if (last_block != NULL) {
+ normal_block = last_block;
+ last_block = NULL; // Cleared to indicate we've handled it.
+ }
} else if (!curr_test_block->end()->IsDeoptimize()) {
normal_block = curr_test_block->end()->FirstSuccessor();
curr_test_block = curr_test_block->end()->SecondSuccessor();
@@ -2593,17 +2667,18 @@
int osr_entry_id = statement->OsrEntryId();
// We want the correct environment at the OsrEntry instruction. Build
// it explicitly. The expression stack should be empty.
- int count = environment()->length();
- ASSERT(count ==
- (environment()->parameter_count() + environment()->local_count()));
- for (int i = 0; i < count; ++i) {
- HUnknownOSRValue* unknown = new(zone()) HUnknownOSRValue;
- AddInstruction(unknown);
- environment()->Bind(i, unknown);
+ ASSERT(environment()->ExpressionStackIsEmpty());
+ for (int i = 0; i < environment()->length(); ++i) {
+ HUnknownOSRValue* osr_value = new(zone()) HUnknownOSRValue;
+ AddInstruction(osr_value);
+ environment()->Bind(i, osr_value);
}
AddSimulate(osr_entry_id);
AddInstruction(new(zone()) HOsrEntry(osr_entry_id));
+ HContext* context = new(zone()) HContext;
+ AddInstruction(context);
+ environment()->BindContext(context);
current_block()->Goto(loop_predecessor);
loop_predecessor->SetJoinId(statement->EntryId());
set_current_block(loop_predecessor);
@@ -2886,12 +2961,12 @@
HValue* HGraphBuilder::BuildContextChainWalk(Variable* var) {
ASSERT(var->IsContextSlot());
- HInstruction* context = new(zone()) HContext;
- AddInstruction(context);
+ HValue* context = environment()->LookupContext();
int length = info()->scope()->ContextChainLength(var->scope());
while (length-- > 0) {
- context = new(zone()) HOuterContext(context);
- AddInstruction(context);
+ HInstruction* context_instruction = new(zone()) HOuterContext(context);
+ AddInstruction(context_instruction);
+ context = context_instruction;
}
return context;
}
@@ -2930,8 +3005,7 @@
HLoadGlobalCell* instr = new(zone()) HLoadGlobalCell(cell, check_hole);
ast_context()->ReturnInstruction(instr, expr->id());
} else {
- HContext* context = new(zone()) HContext;
- AddInstruction(context);
+ HValue* context = environment()->LookupContext();
HGlobalObject* global_object = new(zone()) HGlobalObject(context);
AddInstruction(global_object);
HLoadGlobalGeneric* instr =
@@ -2974,8 +3048,7 @@
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
- HContext* context = new(zone()) HContext;
- AddInstruction(context);
+ HValue* context = environment()->LookupContext();
HObjectLiteral* literal =
new(zone()) HObjectLiteral(context,
expr->constant_properties(),
@@ -3157,8 +3230,7 @@
HInstruction* HGraphBuilder::BuildStoreNamedGeneric(HValue* object,
Handle<String> name,
HValue* value) {
- HContext* context = new(zone()) HContext;
- AddInstruction(context);
+ HValue* context = environment()->LookupContext();
return new(zone()) HStoreNamedGeneric(
context,
object,
@@ -3232,7 +3304,7 @@
// know about and do not want to handle ones we've never seen. Otherwise
// use a generic IC.
if (count == types->length() && FLAG_deoptimize_uncommon_cases) {
- current_block()->FinishExitWithDeoptimization();
+ current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses);
} else {
HInstruction* instr = BuildStoreNamedGeneric(object, name, value);
instr->set_position(expr->position());
@@ -3334,8 +3406,7 @@
AddInstruction(instr);
if (instr->HasSideEffects()) AddSimulate(ast_id);
} else {
- HContext* context = new(zone()) HContext;
- AddInstruction(context);
+ HValue* context = environment()->LookupContext();
HGlobalObject* global_object = new(zone()) HGlobalObject(context);
AddInstruction(global_object);
HStoreGlobalGeneric* instr =
@@ -3560,8 +3631,7 @@
Property* expr) {
ASSERT(expr->key()->IsPropertyName());
Handle<Object> name = expr->key()->AsLiteral()->handle();
- HContext* context = new(zone()) HContext;
- AddInstruction(context);
+ HValue* context = environment()->LookupContext();
return new(zone()) HLoadNamedGeneric(context, obj, name);
}
@@ -3591,8 +3661,7 @@
HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object,
HValue* key) {
- HContext* context = new(zone()) HContext;
- AddInstruction(context);
+ HValue* context = environment()->LookupContext();
return new(zone()) HLoadKeyedGeneric(context, object, key);
}
@@ -3667,8 +3736,7 @@
HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object,
HValue* key,
HValue* value) {
- HContext* context = new(zone()) HContext;
- AddInstruction(context);
+ HValue* context = environment()->LookupContext();
return new(zone()) HStoreKeyedGeneric(
context,
object,
@@ -3721,6 +3789,11 @@
HLoadExternalArrayPointer* external_elements =
new(zone()) HLoadExternalArrayPointer(elements);
AddInstruction(external_elements);
+ if (expr->external_array_type() == kExternalPixelArray) {
+ HClampToUint8* clamp = new(zone()) HClampToUint8(val);
+ AddInstruction(clamp);
+ val = clamp;
+ }
return new(zone()) HStoreKeyedSpecializedArrayElement(
external_elements,
key,
@@ -3796,17 +3869,13 @@
if (expr->IsArrayLength()) {
HValue* array = Pop();
AddInstruction(new(zone()) HCheckNonSmi(array));
- AddInstruction(new(zone()) HCheckInstanceType(array,
- JS_ARRAY_TYPE,
- JS_ARRAY_TYPE));
+ AddInstruction(HCheckInstanceType::NewIsJSArray(array));
instr = new(zone()) HJSArrayLength(array);
} else if (expr->IsStringLength()) {
HValue* string = Pop();
AddInstruction(new(zone()) HCheckNonSmi(string));
- AddInstruction(new(zone()) HCheckInstanceType(string,
- FIRST_STRING_TYPE,
- LAST_STRING_TYPE));
+ AddInstruction(HCheckInstanceType::NewIsString(string));
instr = new(zone()) HStringLength(string);
} else if (expr->IsStringAccess()) {
CHECK_ALIVE(VisitForValue(expr->key()));
@@ -3919,10 +3988,9 @@
// know about and do not want to handle ones we've never seen. Otherwise
// use a generic IC.
if (count == types->length() && FLAG_deoptimize_uncommon_cases) {
- current_block()->FinishExitWithDeoptimization();
+ current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses);
} else {
- HContext* context = new(zone()) HContext;
- AddInstruction(context);
+ HValue* context = environment()->LookupContext();
HCallNamed* call = new(zone()) HCallNamed(context, name, argument_count);
call->set_position(expr->position());
PreProcessCall(call);
@@ -4349,8 +4417,7 @@
CHECK_ALIVE(VisitExpressions(expr->arguments()));
- HContext* context = new(zone()) HContext;
- AddInstruction(context);
+ HValue* context = environment()->LookupContext();
call = PreProcessCall(
new(zone()) HCallKeyed(context, key, argument_count));
call->set_position(expr->position());
@@ -4389,8 +4456,7 @@
// When the target has a custom call IC generator, use the IC,
// because it is likely to generate better code. Also use the IC
// when a primitive receiver check is required.
- HContext* context = new(zone()) HContext;
- AddInstruction(context);
+ HValue* context = environment()->LookupContext();
call = PreProcessCall(
new(zone()) HCallNamed(context, name, argument_count));
} else {
@@ -4407,8 +4473,7 @@
return;
} else {
- HContext* context = new(zone()) HContext;
- AddInstruction(context);
+ HValue* context = environment()->LookupContext();
call = PreProcessCall(
new(zone()) HCallNamed(context, name, argument_count));
}
@@ -4437,9 +4502,8 @@
if (known_global_function) {
// Push the global object instead of the global receiver because
// code generated by the full code generator expects it.
- HContext* context = new(zone()) HContext;
+ HValue* context = environment()->LookupContext();
HGlobalObject* global_object = new(zone()) HGlobalObject(context);
- AddInstruction(context);
PushAndAdd(global_object);
CHECK_ALIVE(VisitExpressions(expr->arguments()));
@@ -4461,8 +4525,7 @@
call = PreProcessCall(new(zone()) HCallKnownGlobal(expr->target(),
argument_count));
} else {
- HContext* context = new(zone()) HContext;
- AddInstruction(context);
+ HValue* context = environment()->LookupContext();
PushAndAdd(new(zone()) HGlobalObject(context));
CHECK_ALIVE(VisitExpressions(expr->arguments()));
@@ -4472,9 +4535,8 @@
}
} else {
- HContext* context = new(zone()) HContext;
+ HValue* context = environment()->LookupContext();
HGlobalObject* global_object = new(zone()) HGlobalObject(context);
- AddInstruction(context);
AddInstruction(global_object);
PushAndAdd(new(zone()) HGlobalReceiver(global_object));
CHECK_ALIVE(VisitExpressions(expr->arguments()));
@@ -4497,8 +4559,7 @@
CHECK_ALIVE(VisitForValue(expr->expression()));
CHECK_ALIVE(VisitExpressions(expr->arguments()));
- HContext* context = new(zone()) HContext;
- AddInstruction(context);
+ HValue* context = environment()->LookupContext();
// The constructor is both an operand to the instruction and an argument
// to the construct call.
@@ -4568,121 +4629,169 @@
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
- Token::Value op = expr->op();
- if (op == Token::VOID) {
+ switch (expr->op()) {
+ case Token::DELETE: return VisitDelete(expr);
+ case Token::VOID: return VisitVoid(expr);
+ case Token::TYPEOF: return VisitTypeof(expr);
+ case Token::ADD: return VisitAdd(expr);
+ case Token::SUB: return VisitSub(expr);
+ case Token::BIT_NOT: return VisitBitNot(expr);
+ case Token::NOT: return VisitNot(expr);
+ default: UNREACHABLE();
+ }
+}
+
+void HGraphBuilder::VisitDelete(UnaryOperation* expr) {
+ Property* prop = expr->expression()->AsProperty();
+ Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
+ if (prop == NULL && var == NULL) {
+ // Result of deleting non-property, non-variable reference is true.
+ // Evaluate the subexpression for side effects.
CHECK_ALIVE(VisitForEffect(expr->expression()));
- ast_context()->ReturnValue(graph()->GetConstantUndefined());
- } else if (op == Token::DELETE) {
- Property* prop = expr->expression()->AsProperty();
- Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
- if (prop == NULL && var == NULL) {
- // Result of deleting non-property, non-variable reference is true.
- // Evaluate the subexpression for side effects.
- CHECK_ALIVE(VisitForEffect(expr->expression()));
- ast_context()->ReturnValue(graph()->GetConstantTrue());
- } else if (var != NULL &&
- !var->is_global() &&
- var->AsSlot() != NULL &&
- var->AsSlot()->type() != Slot::LOOKUP) {
- // Result of deleting non-global, non-dynamic variables is false.
- // The subexpression does not have side effects.
+ ast_context()->ReturnValue(graph()->GetConstantTrue());
+ } else if (var != NULL &&
+ !var->is_global() &&
+ var->AsSlot() != NULL &&
+ var->AsSlot()->type() != Slot::LOOKUP) {
+ // Result of deleting non-global, non-dynamic variables is false.
+ // The subexpression does not have side effects.
+ ast_context()->ReturnValue(graph()->GetConstantFalse());
+ } else if (prop != NULL) {
+ if (prop->is_synthetic()) {
+ // Result of deleting parameters is false, even when they rewrite
+ // to accesses on the arguments object.
ast_context()->ReturnValue(graph()->GetConstantFalse());
- } else if (prop != NULL) {
- if (prop->is_synthetic()) {
- // Result of deleting parameters is false, even when they rewrite
- // to accesses on the arguments object.
- ast_context()->ReturnValue(graph()->GetConstantFalse());
- } else {
- CHECK_ALIVE(VisitForValue(prop->obj()));
- CHECK_ALIVE(VisitForValue(prop->key()));
- HValue* key = Pop();
- HValue* obj = Pop();
- HDeleteProperty* instr = new(zone()) HDeleteProperty(obj, key);
- ast_context()->ReturnInstruction(instr, expr->id());
- }
- } else if (var->is_global()) {
- return Bailout("delete with global variable");
} else {
- return Bailout("delete with non-global variable");
+ CHECK_ALIVE(VisitForValue(prop->obj()));
+ CHECK_ALIVE(VisitForValue(prop->key()));
+ HValue* key = Pop();
+ HValue* obj = Pop();
+ HDeleteProperty* instr = new(zone()) HDeleteProperty(obj, key);
+ ast_context()->ReturnInstruction(instr, expr->id());
}
- } else if (op == Token::NOT) {
- if (ast_context()->IsTest()) {
- TestContext* context = TestContext::cast(ast_context());
- VisitForControl(expr->expression(),
- context->if_false(),
- context->if_true());
- } else if (ast_context()->IsValue()) {
- HBasicBlock* materialize_false = graph()->CreateBasicBlock();
- HBasicBlock* materialize_true = graph()->CreateBasicBlock();
- CHECK_BAILOUT(VisitForControl(expr->expression(),
- materialize_false,
- materialize_true));
+ } else if (var->is_global()) {
+ Bailout("delete with global variable");
+ } else {
+ Bailout("delete with non-global variable");
+ }
+}
- if (materialize_false->HasPredecessor()) {
- materialize_false->SetJoinId(expr->expression()->id());
- set_current_block(materialize_false);
- Push(graph()->GetConstantFalse());
- } else {
- materialize_false = NULL;
- }
- if (materialize_true->HasPredecessor()) {
- materialize_true->SetJoinId(expr->expression()->id());
- set_current_block(materialize_true);
- Push(graph()->GetConstantTrue());
- } else {
- materialize_true = NULL;
- }
+void HGraphBuilder::VisitVoid(UnaryOperation* expr) {
+ CHECK_ALIVE(VisitForEffect(expr->expression()));
+ ast_context()->ReturnValue(graph()->GetConstantUndefined());
+}
- HBasicBlock* join =
- CreateJoin(materialize_false, materialize_true, expr->id());
- set_current_block(join);
- if (join != NULL) ast_context()->ReturnValue(Pop());
- } else {
- ASSERT(ast_context()->IsEffect());
- VisitForEffect(expr->expression());
- }
- } else if (op == Token::TYPEOF) {
- CHECK_ALIVE(VisitForTypeOf(expr->expression()));
- HValue* value = Pop();
- ast_context()->ReturnInstruction(new(zone()) HTypeof(value), expr->id());
+void HGraphBuilder::VisitTypeof(UnaryOperation* expr) {
+ CHECK_ALIVE(VisitForTypeOf(expr->expression()));
+ HValue* value = Pop();
+ ast_context()->ReturnInstruction(new(zone()) HTypeof(value), expr->id());
+}
+
+void HGraphBuilder::VisitAdd(UnaryOperation* expr) {
+ CHECK_ALIVE(VisitForValue(expr->expression()));
+ HValue* value = Pop();
+ HInstruction* instr = new(zone()) HMul(value, graph_->GetConstant1());
+ ast_context()->ReturnInstruction(instr, expr->id());
+}
+
+
+void HGraphBuilder::VisitSub(UnaryOperation* expr) {
+ CHECK_ALIVE(VisitForValue(expr->expression()));
+ HValue* value = Pop();
+ HInstruction* instr = new(zone()) HMul(value, graph_->GetConstantMinus1());
+ TypeInfo info = oracle()->UnaryType(expr);
+ Representation rep = ToRepresentation(info);
+ TraceRepresentation(expr->op(), info, instr, rep);
+ instr->AssumeRepresentation(rep);
+ ast_context()->ReturnInstruction(instr, expr->id());
+}
+
+
+void HGraphBuilder::VisitBitNot(UnaryOperation* expr) {
+ CHECK_ALIVE(VisitForValue(expr->expression()));
+ HValue* value = Pop();
+ HInstruction* instr = new(zone()) HBitNot(value);
+ ast_context()->ReturnInstruction(instr, expr->id());
+}
+
+
+void HGraphBuilder::VisitNot(UnaryOperation* expr) {
+ // TODO(svenpanne) Perhaps a switch/virtual function is nicer here.
+ if (ast_context()->IsTest()) {
+ TestContext* context = TestContext::cast(ast_context());
+ VisitForControl(expr->expression(),
+ context->if_false(),
+ context->if_true());
+ return;
+ }
+
+ if (ast_context()->IsEffect()) {
+ VisitForEffect(expr->expression());
+ return;
+ }
+
+ ASSERT(ast_context()->IsValue());
+ HBasicBlock* materialize_false = graph()->CreateBasicBlock();
+ HBasicBlock* materialize_true = graph()->CreateBasicBlock();
+ CHECK_BAILOUT(VisitForControl(expr->expression(),
+ materialize_false,
+ materialize_true));
+
+ if (materialize_false->HasPredecessor()) {
+ materialize_false->SetJoinId(expr->expression()->id());
+ set_current_block(materialize_false);
+ Push(graph()->GetConstantFalse());
} else {
- CHECK_ALIVE(VisitForValue(expr->expression()));
- HValue* value = Pop();
- HInstruction* instr = NULL;
- switch (op) {
- case Token::BIT_NOT:
- instr = new(zone()) HBitNot(value);
- break;
- case Token::SUB:
- instr = new(zone()) HMul(value, graph_->GetConstantMinus1());
- break;
- case Token::ADD:
- instr = new(zone()) HMul(value, graph_->GetConstant1());
- break;
- default:
- return Bailout("Value: unsupported unary operation");
- break;
- }
- ast_context()->ReturnInstruction(instr, expr->id());
+ materialize_false = NULL;
}
+
+ if (materialize_true->HasPredecessor()) {
+ materialize_true->SetJoinId(expr->expression()->id());
+ set_current_block(materialize_true);
+ Push(graph()->GetConstantTrue());
+ } else {
+ materialize_true = NULL;
+ }
+
+ HBasicBlock* join =
+ CreateJoin(materialize_false, materialize_true, expr->id());
+ set_current_block(join);
+ if (join != NULL) ast_context()->ReturnValue(Pop());
}
-HInstruction* HGraphBuilder::BuildIncrement(HValue* value,
- bool increment,
+HInstruction* HGraphBuilder::BuildIncrement(bool returns_original_input,
CountOperation* expr) {
- HConstant* delta = increment
- ? graph_->GetConstant1()
- : graph_->GetConstantMinus1();
- HInstruction* instr = new(zone()) HAdd(value, delta);
- Representation rep = ToRepresentation(oracle()->IncrementType(expr));
+ // The input to the count operation is on top of the expression stack.
+ TypeInfo info = oracle()->IncrementType(expr);
+ Representation rep = ToRepresentation(info);
if (rep.IsTagged()) {
rep = Representation::Integer32();
}
- AssumeRepresentation(instr, rep);
+
+ if (returns_original_input) {
+ // We need an explicit HValue representing ToNumber(input). The
+ // actual HChange instruction we need is (sometimes) added in a later
+ // phase, so it is not available now to be used as an input to HAdd and
+ // as the return value.
+ HInstruction* number_input = new(zone()) HForceRepresentation(Pop(), rep);
+ AddInstruction(number_input);
+ Push(number_input);
+ }
+
+ // The addition has no side effects, so we do not need
+ // to simulate the expression stack after this instruction.
+ // Any later failures deopt to the load of the input or earlier.
+ HConstant* delta = (expr->op() == Token::INC)
+ ? graph_->GetConstant1()
+ : graph_->GetConstantMinus1();
+ HInstruction* instr = new(zone()) HAdd(Top(), delta);
+ TraceRepresentation(expr->op(), info, instr, rep);
+ instr->AssumeRepresentation(rep);
+ AddInstruction(instr);
return instr;
}
@@ -4695,18 +4804,25 @@
VariableProxy* proxy = target->AsVariableProxy();
Variable* var = proxy->AsVariable();
Property* prop = target->AsProperty();
- ASSERT(var == NULL || prop == NULL);
- bool inc = expr->op() == Token::INC;
+ if (var == NULL && prop == NULL) {
+ return Bailout("invalid lhs in count operation");
+ }
+ // Match the full code generator stack by simulating an extra stack
+ // element for postfix operations in a non-effect context. The return
+ // value is ToNumber(input).
+ bool returns_original_input =
+ expr->is_postfix() && !ast_context()->IsEffect();
+ HValue* input = NULL; // ToNumber(original_input).
+ HValue* after = NULL; // The result after incrementing or decrementing.
+
if (var != NULL) {
+ // Argument of the count operation is a variable, not a property.
+ ASSERT(prop == NULL);
CHECK_ALIVE(VisitForValue(target));
- // Match the full code generator stack by simulating an extra stack
- // element for postfix operations in a non-effect context.
- bool has_extra = expr->is_postfix() && !ast_context()->IsEffect();
- HValue* before = has_extra ? Top() : Pop();
- HInstruction* after = BuildIncrement(before, inc, expr);
- AddInstruction(after);
+ after = BuildIncrement(returns_original_input, expr);
+ input = returns_original_input ? Top() : Pop();
Push(after);
if (var->is_global()) {
@@ -4726,20 +4842,16 @@
} else {
return Bailout("lookup variable in count operation");
}
- Drop(has_extra ? 2 : 1);
- ast_context()->ReturnValue(expr->is_postfix() ? before : after);
- } else if (prop != NULL) {
+ } else {
+ // Argument of the count operation is a property.
+ ASSERT(prop != NULL);
prop->RecordTypeFeedback(oracle());
if (prop->key()->IsPropertyName()) {
// Named property.
+ if (returns_original_input) Push(graph_->GetConstantUndefined());
- // Match the full code generator stack by simulating an extra stack
- // element for postfix operations in a non-effect context.
- bool has_extra = expr->is_postfix() && !ast_context()->IsEffect();
- if (has_extra) Push(graph_->GetConstantUndefined());
-
CHECK_ALIVE(VisitForValue(prop->obj()));
HValue* obj = Top();
@@ -4754,11 +4866,8 @@
PushAndAdd(load);
if (load->HasSideEffects()) AddSimulate(expr->CountId());
- HValue* before = Pop();
- // There is no deoptimization to after the increment, so we don't need
- // to simulate the expression stack after this instruction.
- HInstruction* after = BuildIncrement(before, inc, expr);
- AddInstruction(after);
+ after = BuildIncrement(returns_original_input, expr);
+ input = Pop();
HInstruction* store = BuildStoreNamed(obj, after, prop);
AddInstruction(store);
@@ -4767,20 +4876,13 @@
// of the operation, and the placeholder with the original value if
// necessary.
environment()->SetExpressionStackAt(0, after);
- if (has_extra) environment()->SetExpressionStackAt(1, before);
+ if (returns_original_input) environment()->SetExpressionStackAt(1, input);
if (store->HasSideEffects()) AddSimulate(expr->AssignmentId());
- Drop(has_extra ? 2 : 1);
- ast_context()->ReturnValue(expr->is_postfix() ? before : after);
-
} else {
// Keyed property.
+ if (returns_original_input) Push(graph_->GetConstantUndefined());
- // Match the full code generator stack by simulate an extra stack element
- // for postfix operations in a non-effect context.
- bool has_extra = expr->is_postfix() && !ast_context()->IsEffect();
- if (has_extra) Push(graph_->GetConstantUndefined());
-
CHECK_ALIVE(VisitForValue(prop->obj()));
CHECK_ALIVE(VisitForValue(prop->key()));
HValue* obj = environment()->ExpressionStackAt(1);
@@ -4790,11 +4892,8 @@
PushAndAdd(load);
if (load->HasSideEffects()) AddSimulate(expr->CountId());
- HValue* before = Pop();
- // There is no deoptimization to after the increment, so we don't need
- // to simulate the expression stack after this instruction.
- HInstruction* after = BuildIncrement(before, inc, expr);
- AddInstruction(after);
+ after = BuildIncrement(returns_original_input, expr);
+ input = Pop();
expr->RecordTypeFeedback(oracle());
HInstruction* store = BuildStoreKeyed(obj, key, after, expr);
@@ -4805,24 +4904,32 @@
// original value if necessary.
Drop(1);
environment()->SetExpressionStackAt(0, after);
- if (has_extra) environment()->SetExpressionStackAt(1, before);
+ if (returns_original_input) environment()->SetExpressionStackAt(1, input);
if (store->HasSideEffects()) AddSimulate(expr->AssignmentId());
- Drop(has_extra ? 2 : 1);
-
- ast_context()->ReturnValue(expr->is_postfix() ? before : after);
}
+ }
- } else {
- return Bailout("invalid lhs in count operation");
- }
+ Drop(returns_original_input ? 2 : 1);
+ ast_context()->ReturnValue(expr->is_postfix() ? input : after);
}
+HCompareSymbolEq* HGraphBuilder::BuildSymbolCompare(HValue* left,
+ HValue* right,
+ Token::Value op) {
+ ASSERT(op == Token::EQ || op == Token::EQ_STRICT);
+ AddInstruction(new(zone()) HCheckNonSmi(left));
+ AddInstruction(HCheckInstanceType::NewIsSymbol(left));
+ AddInstruction(new(zone()) HCheckNonSmi(right));
+ AddInstruction(HCheckInstanceType::NewIsSymbol(right));
+ return new(zone()) HCompareSymbolEq(left, right, op);
+}
+
+
HStringCharCodeAt* HGraphBuilder::BuildStringCharCodeAt(HValue* string,
HValue* index) {
AddInstruction(new(zone()) HCheckNonSmi(string));
- AddInstruction(new(zone()) HCheckInstanceType(
- string, FIRST_STRING_TYPE, LAST_STRING_TYPE));
+ AddInstruction(HCheckInstanceType::NewIsString(string));
HStringLength* length = new(zone()) HStringLength(string);
AddInstruction(length);
AddInstruction(new(zone()) HBoundsCheck(index, length));
@@ -4834,54 +4941,7 @@
HValue* left,
HValue* right) {
TypeInfo info = oracle()->BinaryType(expr);
- HInstruction* instr = NULL;
- switch (expr->op()) {
- case Token::ADD:
- if (info.IsString()) {
- AddInstruction(new(zone()) HCheckNonSmi(left));
- AddInstruction(new(zone()) HCheckInstanceType(
- left, FIRST_STRING_TYPE, LAST_STRING_TYPE));
- AddInstruction(new(zone()) HCheckNonSmi(right));
- AddInstruction(new(zone()) HCheckInstanceType(
- right, FIRST_STRING_TYPE, LAST_STRING_TYPE));
- instr = new(zone()) HStringAdd(left, right);
- } else {
- instr = new(zone()) HAdd(left, right);
- }
- break;
- case Token::SUB:
- instr = new(zone()) HSub(left, right);
- break;
- case Token::MUL:
- instr = new(zone()) HMul(left, right);
- break;
- case Token::MOD:
- instr = new(zone()) HMod(left, right);
- break;
- case Token::DIV:
- instr = new(zone()) HDiv(left, right);
- break;
- case Token::BIT_XOR:
- instr = new(zone()) HBitXor(left, right);
- break;
- case Token::BIT_AND:
- instr = new(zone()) HBitAnd(left, right);
- break;
- case Token::BIT_OR:
- instr = new(zone()) HBitOr(left, right);
- break;
- case Token::SAR:
- instr = new(zone()) HSar(left, right);
- break;
- case Token::SHR:
- instr = new(zone()) HShr(left, right);
- break;
- case Token::SHL:
- instr = new(zone()) HShl(left, right);
- break;
- default:
- UNREACHABLE();
- }
+ HInstruction* instr = BuildBinaryOperation(expr->op(), left, right, info);
// If we hit an uninitialized binary op stub we will get type info
// for a smi operation. If one of the operands is a constant string
// do not generate code assuming it is a smi operation.
@@ -4890,19 +4950,47 @@
(right->IsConstant() && HConstant::cast(right)->HasStringValue()))) {
return instr;
}
- if (FLAG_trace_representation) {
- PrintF("Info: %s/%s\n", info.ToString(), ToRepresentation(info).Mnemonic());
- }
Representation rep = ToRepresentation(info);
// We only generate either int32 or generic tagged bitwise operations.
if (instr->IsBitwiseBinaryOperation() && rep.IsDouble()) {
rep = Representation::Integer32();
}
- AssumeRepresentation(instr, rep);
+ TraceRepresentation(expr->op(), info, instr, rep);
+ instr->AssumeRepresentation(rep);
return instr;
}
+HInstruction* HGraphBuilder::BuildBinaryOperation(
+ Token::Value op, HValue* left, HValue* right, TypeInfo info) {
+ switch (op) {
+ case Token::ADD:
+ if (info.IsString()) {
+ AddInstruction(new(zone()) HCheckNonSmi(left));
+ AddInstruction(HCheckInstanceType::NewIsString(left));
+ AddInstruction(new(zone()) HCheckNonSmi(right));
+ AddInstruction(HCheckInstanceType::NewIsString(right));
+ return new(zone()) HStringAdd(left, right);
+ } else {
+ return new(zone()) HAdd(left, right);
+ }
+ case Token::SUB: return new(zone()) HSub(left, right);
+ case Token::MUL: return new(zone()) HMul(left, right);
+ case Token::MOD: return new(zone()) HMod(left, right);
+ case Token::DIV: return new(zone()) HDiv(left, right);
+ case Token::BIT_XOR: return new(zone()) HBitXor(left, right);
+ case Token::BIT_AND: return new(zone()) HBitAnd(left, right);
+ case Token::BIT_OR: return new(zone()) HBitOr(left, right);
+ case Token::SAR: return new(zone()) HSar(left, right);
+ case Token::SHR: return new(zone()) HShr(left, right);
+ case Token::SHL: return new(zone()) HShl(left, right);
+ default:
+ UNREACHABLE();
+ return NULL;
+ }
+}
+
+
// Check for the form (%_ClassOf(foo) === 'BarClass').
static bool IsClassOfTest(CompareOperation* expr) {
if (expr->op() != Token::EQ_STRICT) return false;
@@ -4921,128 +5009,141 @@
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
- if (expr->op() == Token::COMMA) {
- CHECK_ALIVE(VisitForEffect(expr->left()));
- // Visit the right subexpression in the same AST context as the entire
- // expression.
- Visit(expr->right());
+ switch (expr->op()) {
+ case Token::COMMA: return VisitComma(expr);
+ case Token::OR: return VisitAndOr(expr, false);
+ case Token::AND: return VisitAndOr(expr, true);
+ default: return VisitCommon(expr);
+ }
+}
- } else if (expr->op() == Token::AND || expr->op() == Token::OR) {
- bool is_logical_and = (expr->op() == Token::AND);
- if (ast_context()->IsTest()) {
- TestContext* context = TestContext::cast(ast_context());
- // Translate left subexpression.
- HBasicBlock* eval_right = graph()->CreateBasicBlock();
- if (is_logical_and) {
- CHECK_BAILOUT(VisitForControl(expr->left(),
- eval_right,
- context->if_false()));
- } else {
- CHECK_BAILOUT(VisitForControl(expr->left(),
- context->if_true(),
- eval_right));
- }
- // Translate right subexpression by visiting it in the same AST
- // context as the entire expression.
- if (eval_right->HasPredecessor()) {
- eval_right->SetJoinId(expr->RightId());
- set_current_block(eval_right);
- Visit(expr->right());
- }
+void HGraphBuilder::VisitComma(BinaryOperation* expr) {
+ CHECK_ALIVE(VisitForEffect(expr->left()));
+ // Visit the right subexpression in the same AST context as the entire
+ // expression.
+ Visit(expr->right());
+}
- } else if (ast_context()->IsValue()) {
- CHECK_ALIVE(VisitForValue(expr->left()));
- ASSERT(current_block() != NULL);
- // We need an extra block to maintain edge-split form.
- HBasicBlock* empty_block = graph()->CreateBasicBlock();
- HBasicBlock* eval_right = graph()->CreateBasicBlock();
- HTest* test = is_logical_and
- ? new(zone()) HTest(Top(), eval_right, empty_block)
- : new(zone()) HTest(Top(), empty_block, eval_right);
- current_block()->Finish(test);
+void HGraphBuilder::VisitAndOr(BinaryOperation* expr, bool is_logical_and) {
+ if (ast_context()->IsTest()) {
+ TestContext* context = TestContext::cast(ast_context());
+ // Translate left subexpression.
+ HBasicBlock* eval_right = graph()->CreateBasicBlock();
+ if (is_logical_and) {
+ CHECK_BAILOUT(VisitForControl(expr->left(),
+ eval_right,
+ context->if_false()));
+ } else {
+ CHECK_BAILOUT(VisitForControl(expr->left(),
+ context->if_true(),
+ eval_right));
+ }
+ // Translate right subexpression by visiting it in the same AST
+ // context as the entire expression.
+ if (eval_right->HasPredecessor()) {
+ eval_right->SetJoinId(expr->RightId());
set_current_block(eval_right);
- Drop(1); // Value of the left subexpression.
- CHECK_BAILOUT(VisitForValue(expr->right()));
+ Visit(expr->right());
+ }
- HBasicBlock* join_block =
- CreateJoin(empty_block, current_block(), expr->id());
- set_current_block(join_block);
- ast_context()->ReturnValue(Pop());
+ } else if (ast_context()->IsValue()) {
+ CHECK_ALIVE(VisitForValue(expr->left()));
+ ASSERT(current_block() != NULL);
+ // We need an extra block to maintain edge-split form.
+ HBasicBlock* empty_block = graph()->CreateBasicBlock();
+ HBasicBlock* eval_right = graph()->CreateBasicBlock();
+ HTest* test = is_logical_and
+ ? new(zone()) HTest(Top(), eval_right, empty_block)
+ : new(zone()) HTest(Top(), empty_block, eval_right);
+ current_block()->Finish(test);
+
+ set_current_block(eval_right);
+ Drop(1); // Value of the left subexpression.
+ CHECK_BAILOUT(VisitForValue(expr->right()));
+
+ HBasicBlock* join_block =
+ CreateJoin(empty_block, current_block(), expr->id());
+ set_current_block(join_block);
+ ast_context()->ReturnValue(Pop());
+
+ } else {
+ ASSERT(ast_context()->IsEffect());
+ // In an effect context, we don't need the value of the left subexpression,
+ // only its control flow and side effects. We need an extra block to
+ // maintain edge-split form.
+ HBasicBlock* empty_block = graph()->CreateBasicBlock();
+ HBasicBlock* right_block = graph()->CreateBasicBlock();
+ if (is_logical_and) {
+ CHECK_BAILOUT(VisitForControl(expr->left(), right_block, empty_block));
} else {
- ASSERT(ast_context()->IsEffect());
- // In an effect context, we don't need the value of the left
- // subexpression, only its control flow and side effects. We need an
- // extra block to maintain edge-split form.
- HBasicBlock* empty_block = graph()->CreateBasicBlock();
- HBasicBlock* right_block = graph()->CreateBasicBlock();
- if (is_logical_and) {
- CHECK_BAILOUT(VisitForControl(expr->left(), right_block, empty_block));
- } else {
- CHECK_BAILOUT(VisitForControl(expr->left(), empty_block, right_block));
- }
+ CHECK_BAILOUT(VisitForControl(expr->left(), empty_block, right_block));
+ }
- // TODO(kmillikin): Find a way to fix this. It's ugly that there are
- // actually two empty blocks (one here and one inserted by
- // TestContext::BuildBranch, and that they both have an HSimulate
- // though the second one is not a merge node, and that we really have
- // no good AST ID to put on that first HSimulate.
- if (empty_block->HasPredecessor()) {
- empty_block->SetJoinId(expr->id());
- } else {
- empty_block = NULL;
- }
+ // TODO(kmillikin): Find a way to fix this. It's ugly that there are
+ // actually two empty blocks (one here and one inserted by
+ // TestContext::BuildBranch, and that they both have an HSimulate though the
+ // second one is not a merge node, and that we really have no good AST ID to
+ // put on that first HSimulate.
- if (right_block->HasPredecessor()) {
- right_block->SetJoinId(expr->RightId());
- set_current_block(right_block);
- CHECK_BAILOUT(VisitForEffect(expr->right()));
- right_block = current_block();
- } else {
- right_block = NULL;
- }
+ if (empty_block->HasPredecessor()) {
+ empty_block->SetJoinId(expr->id());
+ } else {
+ empty_block = NULL;
+ }
- HBasicBlock* join_block =
- CreateJoin(empty_block, right_block, expr->id());
- set_current_block(join_block);
- // We did not materialize any value in the predecessor environments,
- // so there is no need to handle it here.
+ if (right_block->HasPredecessor()) {
+ right_block->SetJoinId(expr->RightId());
+ set_current_block(right_block);
+ CHECK_BAILOUT(VisitForEffect(expr->right()));
+ right_block = current_block();
+ } else {
+ right_block = NULL;
}
- } else {
- CHECK_ALIVE(VisitForValue(expr->left()));
- CHECK_ALIVE(VisitForValue(expr->right()));
-
- HValue* right = Pop();
- HValue* left = Pop();
- HInstruction* instr = BuildBinaryOperation(expr, left, right);
- instr->set_position(expr->position());
- ast_context()->ReturnInstruction(instr, expr->id());
+ HBasicBlock* join_block =
+ CreateJoin(empty_block, right_block, expr->id());
+ set_current_block(join_block);
+ // We did not materialize any value in the predecessor environments,
+ // so there is no need to handle it here.
}
}
-void HGraphBuilder::AssumeRepresentation(HValue* value, Representation r) {
- if (value->CheckFlag(HValue::kFlexibleRepresentation)) {
- if (FLAG_trace_representation) {
- PrintF("Assume representation for %s to be %s (%d)\n",
- value->Mnemonic(),
- r.Mnemonic(),
- graph_->GetMaximumValueID());
- }
- value->ChangeRepresentation(r);
- // The representation of the value is dictated by type feedback and
- // will not be changed later.
- value->ClearFlag(HValue::kFlexibleRepresentation);
- } else if (FLAG_trace_representation) {
- PrintF("No representation assumed\n");
- }
+void HGraphBuilder::VisitCommon(BinaryOperation* expr) {
+ CHECK_ALIVE(VisitForValue(expr->left()));
+ CHECK_ALIVE(VisitForValue(expr->right()));
+ HValue* right = Pop();
+ HValue* left = Pop();
+ HInstruction* instr = BuildBinaryOperation(expr, left, right);
+ instr->set_position(expr->position());
+ ast_context()->ReturnInstruction(instr, expr->id());
}
+void HGraphBuilder::TraceRepresentation(Token::Value op,
+ TypeInfo info,
+ HValue* value,
+ Representation rep) {
+ if (!FLAG_trace_representation) return;
+ // TODO(svenpanne) Under which circumstances are we actually not flexible?
+ // At first glance, this looks a bit weird...
+ bool flexible = value->CheckFlag(HValue::kFlexibleRepresentation);
+ PrintF("Operation %s has type info %s, %schange representation assumption "
+ "for %s (ID %d) from %s to %s\n",
+ Token::Name(op),
+ info.ToString(),
+ flexible ? "" : " DO NOT ",
+ value->Mnemonic(),
+ graph_->GetMaximumValueID(),
+ value->representation().Mnemonic(),
+ rep.Mnemonic());
+}
+
+
Representation HGraphBuilder::ToRepresentation(TypeInfo info) {
if (info.IsSmi()) return Representation::Integer32();
if (info.IsInteger32()) return Representation::Integer32();
@@ -5121,8 +5222,7 @@
// If the target is not null we have found a known global function that is
// assumed to stay the same for this instanceof.
if (target.is_null()) {
- HContext* context = new(zone()) HContext;
- AddInstruction(context);
+ HValue* context = environment()->LookupContext();
instr = new(zone()) HInstanceOf(context, left, right);
} else {
AddInstruction(new(zone()) HCheckFunction(right, target));
@@ -5145,6 +5245,9 @@
return Bailout("Unsupported non-primitive compare");
break;
}
+ } else if (type_info.IsString() && oracle()->IsSymbolCompare(expr) &&
+ (op == Token::EQ || op == Token::EQ_STRICT)) {
+ instr = BuildSymbolCompare(left, right, op);
} else {
HCompare* compare = new(zone()) HCompare(left, right, op);
Representation r = ToRepresentation(type_info);
@@ -5266,7 +5369,11 @@
void HGraphBuilder::GenerateIsUndetectableObject(CallRuntime* call) {
- return Bailout("inlined runtime function: IsUndetectableObject");
+ ASSERT(call->arguments()->length() == 1);
+ CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
+ HValue* value = Pop();
+ ast_context()->ReturnInstruction(new(zone()) HIsUndetectable(value),
+ call->id());
}
@@ -5398,8 +5505,7 @@
void HGraphBuilder::GenerateStringAdd(CallRuntime* call) {
ASSERT_EQ(2, call->arguments()->length());
CHECK_ALIVE(VisitArgumentList(call->arguments()));
- HContext* context = new(zone()) HContext;
- AddInstruction(context);
+ HValue* context = environment()->LookupContext();
HCallStub* result = new(zone()) HCallStub(context, CodeStub::StringAdd, 2);
Drop(2);
ast_context()->ReturnInstruction(result, call->id());
@@ -5410,8 +5516,7 @@
void HGraphBuilder::GenerateSubString(CallRuntime* call) {
ASSERT_EQ(3, call->arguments()->length());
CHECK_ALIVE(VisitArgumentList(call->arguments()));
- HContext* context = new(zone()) HContext;
- AddInstruction(context);
+ HValue* context = environment()->LookupContext();
HCallStub* result = new(zone()) HCallStub(context, CodeStub::SubString, 3);
Drop(3);
ast_context()->ReturnInstruction(result, call->id());
@@ -5422,8 +5527,7 @@
void HGraphBuilder::GenerateStringCompare(CallRuntime* call) {
ASSERT_EQ(2, call->arguments()->length());
CHECK_ALIVE(VisitArgumentList(call->arguments()));
- HContext* context = new(zone()) HContext;
- AddInstruction(context);
+ HValue* context = environment()->LookupContext();
HCallStub* result =
new(zone()) HCallStub(context, CodeStub::StringCompare, 2);
Drop(2);
@@ -5435,8 +5539,7 @@
void HGraphBuilder::GenerateRegExpExec(CallRuntime* call) {
ASSERT_EQ(4, call->arguments()->length());
CHECK_ALIVE(VisitArgumentList(call->arguments()));
- HContext* context = new(zone()) HContext;
- AddInstruction(context);
+ HValue* context = environment()->LookupContext();
HCallStub* result = new(zone()) HCallStub(context, CodeStub::RegExpExec, 4);
Drop(4);
ast_context()->ReturnInstruction(result, call->id());
@@ -5447,8 +5550,7 @@
void HGraphBuilder::GenerateRegExpConstructResult(CallRuntime* call) {
ASSERT_EQ(3, call->arguments()->length());
CHECK_ALIVE(VisitArgumentList(call->arguments()));
- HContext* context = new(zone()) HContext;
- AddInstruction(context);
+ HValue* context = environment()->LookupContext();
HCallStub* result =
new(zone()) HCallStub(context, CodeStub::RegExpConstructResult, 3);
Drop(3);
@@ -5466,8 +5568,7 @@
void HGraphBuilder::GenerateNumberToString(CallRuntime* call) {
ASSERT_EQ(1, call->arguments()->length());
CHECK_ALIVE(VisitArgumentList(call->arguments()));
- HContext* context = new(zone()) HContext;
- AddInstruction(context);
+ HValue* context = environment()->LookupContext();
HCallStub* result =
new(zone()) HCallStub(context, CodeStub::NumberToString, 1);
Drop(1);
@@ -5494,8 +5595,7 @@
}
CHECK_ALIVE(VisitForValue(call->arguments()->last()));
HValue* function = Pop();
- HContext* context = new HContext;
- AddInstruction(context);
+ HValue* context = environment()->LookupContext();
HInvokeFunction* result =
new(zone()) HInvokeFunction(context, function, arg_count);
Drop(arg_count);
@@ -5518,8 +5618,7 @@
void HGraphBuilder::GenerateMathSin(CallRuntime* call) {
ASSERT_EQ(1, call->arguments()->length());
CHECK_ALIVE(VisitArgumentList(call->arguments()));
- HContext* context = new(zone()) HContext;
- AddInstruction(context);
+ HValue* context = environment()->LookupContext();
HCallStub* result =
new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1);
result->set_transcendental_type(TranscendentalCache::SIN);
@@ -5531,8 +5630,7 @@
void HGraphBuilder::GenerateMathCos(CallRuntime* call) {
ASSERT_EQ(1, call->arguments()->length());
CHECK_ALIVE(VisitArgumentList(call->arguments()));
- HContext* context = new(zone()) HContext;
- AddInstruction(context);
+ HValue* context = environment()->LookupContext();
HCallStub* result =
new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1);
result->set_transcendental_type(TranscendentalCache::COS);
@@ -5544,8 +5642,7 @@
void HGraphBuilder::GenerateMathLog(CallRuntime* call) {
ASSERT_EQ(1, call->arguments()->length());
CHECK_ALIVE(VisitArgumentList(call->arguments()));
- HContext* context = new(zone()) HContext;
- AddInstruction(context);
+ HValue* context = environment()->LookupContext();
HCallStub* result =
new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1);
result->set_transcendental_type(TranscendentalCache::LOG);
@@ -5590,6 +5687,7 @@
values_(0),
assigned_variables_(4),
parameter_count_(0),
+ specials_count_(1),
local_count_(0),
outer_(outer),
pop_count_(0),
@@ -5603,6 +5701,7 @@
: values_(0),
assigned_variables_(0),
parameter_count_(0),
+ specials_count_(1),
local_count_(0),
outer_(NULL),
pop_count_(0),
@@ -5619,7 +5718,7 @@
local_count_ = local_count;
// Avoid reallocating the temporaries' backing store on the first Push.
- int total = parameter_count + local_count + stack_height;
+ int total = parameter_count + specials_count_ + local_count + stack_height;
values_.Initialize(total + 4);
for (int i = 0; i < total; ++i) values_.Add(NULL);
}
@@ -5678,12 +5777,12 @@
bool HEnvironment::HasExpressionAt(int index) const {
- return index >= parameter_count_ + local_count_;
+ return index >= parameter_count_ + specials_count_ + local_count_;
}
bool HEnvironment::ExpressionStackIsEmpty() const {
- int first_expression = parameter_count() + local_count();
+ int first_expression = parameter_count() + specials_count() + local_count();
ASSERT(length() >= first_expression);
return length() == first_expression;
}
@@ -5761,12 +5860,9 @@
inner->SetValueAt(i, push);
}
}
-
- // Initialize the stack-allocated locals to undefined.
- int local_base = arity + 1;
- int local_count = function->scope()->num_stack_slots();
- for (int i = 0; i < local_count; ++i) {
- inner->SetValueAt(local_base + i, undefined);
+ inner->SetValueAt(arity + 1, outer->LookupContext());
+ for (int i = arity + 2; i < inner->length(); ++i) {
+ inner->SetValueAt(i, undefined);
}
inner->set_ast_id(AstNode::kFunctionEntryId);
@@ -5777,8 +5873,11 @@
void HEnvironment::PrintTo(StringStream* stream) {
for (int i = 0; i < length(); i++) {
if (i == 0) stream->Add("parameters\n");
- if (i == parameter_count()) stream->Add("locals\n");
- if (i == parameter_count() + local_count()) stream->Add("expressions");
+ if (i == parameter_count()) stream->Add("specials\n");
+ if (i == parameter_count() + specials_count()) stream->Add("locals\n");
+ if (i == parameter_count() + specials_count() + local_count()) {
+ stream->Add("expressions");
+ }
HValue* val = values_.at(i);
stream->Add("%d: ", i);
if (val != NULL) {
@@ -5873,10 +5972,11 @@
Tag states_tag(this, "states");
Tag locals_tag(this, "locals");
int total = current->phis()->length();
- trace_.Add("size %d\n", total);
- trace_.Add("method \"None\"");
+ PrintIntProperty("size", current->phis()->length());
+ PrintStringProperty("method", "None");
for (int j = 0; j < total; ++j) {
HPhi* phi = current->phis()->at(j);
+ PrintIndent();
trace_.Add("%d ", phi->merged_index());
phi->PrintNameTo(&trace_);
trace_.Add(" ");
@@ -5891,6 +5991,7 @@
while (instruction != NULL) {
int bci = 0;
int uses = instruction->UseCount();
+ PrintIndent();
trace_.Add("%d %d ", bci, uses);
instruction->PrintNameTo(&trace_);
trace_.Add(" ");
@@ -5910,6 +6011,7 @@
for (int i = first_index; i <= last_index; ++i) {
LInstruction* linstr = instructions->at(i);
if (linstr != NULL) {
+ PrintIndent();
trace_.Add("%d ",
LifetimePosition::FromInstructionIndex(i).Value());
linstr->PrintTo(&trace_);
@@ -5945,6 +6047,7 @@
void HTracer::TraceLiveRange(LiveRange* range, const char* type) {
if (range != NULL && !range->IsEmpty()) {
+ PrintIndent();
trace_.Add("%d %s", range->id(), type);
if (range->HasRegisterAssigned()) {
LOperand* op = range->CreateAssignedOperand();
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-instructions.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698