#include "src/compiler/ast-graph-builder.h"
#include "src/compiler.h"
+#include "src/compiler/ast-loop-assignment-analyzer.h"
#include "src/compiler/control-builders.h"
#include "src/compiler/machine-operator.h"
-#include "src/compiler/node-properties.h"
+#include "src/compiler/node-matchers.h"
#include "src/compiler/node-properties-inl.h"
+#include "src/compiler/node-properties.h"
#include "src/full-codegen.h"
#include "src/parser.h"
#include "src/scopes.h"
namespace internal {
namespace compiler {
-AstGraphBuilder::AstGraphBuilder(CompilationInfo* info, JSGraph* jsgraph)
- : StructuredGraphBuilder(jsgraph->graph(), jsgraph->common()),
+AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info,
+ JSGraph* jsgraph)
+ : StructuredGraphBuilder(local_zone, jsgraph->graph(), jsgraph->common()),
info_(info),
jsgraph_(jsgraph),
- globals_(0, info->zone()),
+ globals_(0, local_zone),
breakable_(NULL),
- execution_context_(NULL) {
- InitializeAstVisitor(info->zone());
+ execution_context_(NULL),
+ loop_assignment_analysis_(NULL) {
+ InitializeAstVisitor(local_zone);
}
int parameter_count = info()->num_parameters();
graph()->SetStart(graph()->NewNode(common()->Start(parameter_count)));
+ if (FLAG_loop_assignment_analysis) {
+ // TODO(turbofan): use a temporary zone for the loop assignment analysis.
+ AstLoopAssignmentAnalyzer analyzer(zone(), info());
+ loop_assignment_analysis_ = analyzer.Analyze();
+ }
+
// Initialize the top-level environment.
Environment env(this, scope, graph()->start());
set_environment(&env);
// Emit tracing call if requested to do so.
if (FLAG_trace) {
- NewNode(javascript()->Runtime(Runtime::kTraceEnter, 0));
+ NewNode(javascript()->CallRuntime(Runtime::kTraceEnter, 0));
}
// Visit implicit declaration of the function name.
// Visit declarations within the function scope.
VisitDeclarations(scope->declarations());
- // TODO(mstarzinger): This should do an inlined stack check.
- Node* node = NewNode(javascript()->Runtime(Runtime::kStackGuard, 0));
+ // Build a stack-check before the body.
+ Node* node = BuildStackCheck();
PrepareFrameState(node, BailoutId::FunctionEntry());
// Visit statements in the function body.
if (FLAG_trace) {
// TODO(mstarzinger): Only traces implicit return.
Node* return_value = jsgraph()->UndefinedConstant();
- NewNode(javascript()->Runtime(Runtime::kTraceExit, 1), return_value);
+ NewNode(javascript()->CallRuntime(Runtime::kTraceExit, 1), return_value);
}
// Return 'undefined' in case we can fall off the end.
void AstGraphBuilder::VisitForValue(Expression* expr) {
AstValueContext for_value(this);
- if (!HasStackOverflow()) {
+ if (!CheckStackOverflow()) {
expr->Accept(this);
+ } else {
+ ast_context()->ProduceValue(jsgraph()->UndefinedConstant());
}
}
void AstGraphBuilder::VisitForEffect(Expression* expr) {
AstEffectContext for_effect(this);
- if (!HasStackOverflow()) {
+ if (!CheckStackOverflow()) {
expr->Accept(this);
+ } else {
+ ast_context()->ProduceValue(jsgraph()->UndefinedConstant());
}
}
void AstGraphBuilder::VisitForTest(Expression* expr) {
AstTestContext for_condition(this);
- if (!HasStackOverflow()) {
+ if (!CheckStackOverflow()) {
expr->Accept(this);
+ } else {
+ ast_context()->ProduceValue(jsgraph()->UndefinedConstant());
+ }
+}
+
+
+void AstGraphBuilder::Visit(Expression* expr) {
+ // Reuses enclosing AstContext.
+ if (!CheckStackOverflow()) {
+ expr->Accept(this);
+ } else {
+ ast_context()->ProduceValue(jsgraph()->UndefinedConstant());
}
}
void AstGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
LoopBuilder while_loop(this);
- while_loop.BeginLoop();
+ while_loop.BeginLoop(GetVariablesAssignedInLoop(stmt));
VisitIterationBody(stmt, &while_loop, 0);
while_loop.EndBody();
VisitForTest(stmt->cond());
void AstGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
LoopBuilder while_loop(this);
- while_loop.BeginLoop();
+ while_loop.BeginLoop(GetVariablesAssignedInLoop(stmt));
VisitForTest(stmt->cond());
Node* condition = environment()->Pop();
while_loop.BreakUnless(condition);
void AstGraphBuilder::VisitForStatement(ForStatement* stmt) {
LoopBuilder for_loop(this);
VisitIfNotNull(stmt->init());
- for_loop.BeginLoop();
+ for_loop.BeginLoop(GetVariablesAssignedInLoop(stmt));
if (stmt->cond() != NULL) {
VisitForTest(stmt->cond());
Node* condition = environment()->Pop();
for_loop.BreakUnless(condition);
+ } else {
+ for_loop.BreakUnless(jsgraph()->TrueConstant());
}
VisitIterationBody(stmt, &for_loop, 0);
for_loop.EndBody();
// Convert object to jsobject.
// PrepareForBailoutForId(stmt->PrepareId(), TOS_REG);
obj = NewNode(javascript()->ToObject(), obj);
+ PrepareFrameState(obj, stmt->ToObjectId(), OutputFrameStateCombine::Push());
environment()->Push(obj);
// TODO(dcarney): should do a fast enum cache check here to skip runtime.
environment()->Push(obj);
Node* cache_type = ProcessArguments(
- javascript()->Runtime(Runtime::kGetPropertyNamesFast, 1), 1);
+ javascript()->CallRuntime(Runtime::kGetPropertyNamesFast, 1), 1);
+ PrepareFrameState(cache_type, stmt->EnumId(),
+ OutputFrameStateCombine::Push());
// TODO(dcarney): these next runtime calls should be removed in favour of
// a few simplified instructions.
environment()->Push(obj);
environment()->Push(cache_type);
Node* cache_pair =
- ProcessArguments(javascript()->Runtime(Runtime::kForInInit, 2), 2);
+ ProcessArguments(javascript()->CallRuntime(Runtime::kForInInit, 2), 2);
// cache_type may have been replaced.
Node* cache_array = NewNode(common()->Projection(0), cache_pair);
cache_type = NewNode(common()->Projection(1), cache_pair);
environment()->Push(cache_type);
environment()->Push(cache_array);
Node* cache_length = ProcessArguments(
- javascript()->Runtime(Runtime::kForInCacheArrayLength, 2), 2);
+ javascript()->CallRuntime(Runtime::kForInCacheArrayLength, 2), 2);
{
// TODO(dcarney): this check is actually supposed to be for the
// empty enum case only.
environment()->Push(jsgraph()->ZeroConstant());
// PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
LoopBuilder for_loop(this);
- for_loop.BeginLoop();
+ for_loop.BeginLoop(GetVariablesAssignedInLoop(stmt));
// Check loop termination condition.
Node* index = environment()->Peek(0);
Node* exit_cond =
environment()->Push(cache_array);
environment()->Push(cache_type);
environment()->Push(index);
- Node* pair =
- ProcessArguments(javascript()->Runtime(Runtime::kForInNext, 4), 4);
+ Node* pair = ProcessArguments(
+ javascript()->CallRuntime(Runtime::kForInNext, 4), 4);
Node* value = NewNode(common()->Projection(0), pair);
Node* should_filter = NewNode(common()->Projection(1), pair);
environment()->Push(value);
// result is either the string key or Smi(0) indicating the property
// is gone.
Node* res = ProcessArguments(
- javascript()->Call(3, NO_CALL_FUNCTION_FLAGS), 3);
+ javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS), 3);
// TODO(jarin): provide real bailout id.
PrepareFrameState(res, BailoutId::None());
Node* property_missing = NewNode(javascript()->StrictEqual(), res,
void AstGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
// TODO(turbofan): Do we really need a separate reloc-info for this?
- Node* node = NewNode(javascript()->Runtime(Runtime::kDebugBreak, 0));
+ Node* node = NewNode(javascript()->CallRuntime(Runtime::kDebugBreak, 0));
PrepareFrameState(node, stmt->DebugBreakId());
}
// Create node to instantiate a new closure.
Node* info = jsgraph()->Constant(shared_info);
- Node* pretenure = expr->pretenure() ? jsgraph()->TrueConstant()
- : jsgraph()->FalseConstant();
- const Operator* op = javascript()->Runtime(Runtime::kNewClosure, 3);
+ Node* pretenure = jsgraph()->BooleanConstant(expr->pretenure());
+ const Operator* op = javascript()->CallRuntime(Runtime::kNewClosure, 3);
Node* value = NewNode(op, context, info, pretenure);
ast_context()->ProduceValue(value);
}
void AstGraphBuilder::VisitClassLiteral(ClassLiteral* expr) {
- // TODO(arv): Implement.
UNREACHABLE();
}
void AstGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
- Node* value = BuildVariableLoad(expr->var(), expr->id());
+ VectorSlotPair pair = CreateVectorSlotPair(expr->VariableFeedbackSlot());
+ Node* value = BuildVariableLoad(expr->var(), expr->id(), pair);
ast_context()->ProduceValue(value);
}
Node* pattern = jsgraph()->Constant(expr->pattern());
Node* flags = jsgraph()->Constant(expr->flags());
const Operator* op =
- javascript()->Runtime(Runtime::kMaterializeRegExpLiteral, 4);
+ javascript()->CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
Node* literal = NewNode(op, literals_array, literal_index, pattern, flags);
+ PrepareFrameState(literal, expr->id(), ast_context()->GetStateCombine());
ast_context()->ProduceValue(literal);
}
Node* literal_index = jsgraph()->Constant(expr->literal_index());
Node* constants = jsgraph()->Constant(expr->constant_properties());
Node* flags = jsgraph()->Constant(expr->ComputeFlags());
- const Operator* op = javascript()->Runtime(Runtime::kCreateObjectLiteral, 4);
+ const Operator* op =
+ javascript()->CallRuntime(Runtime::kCreateObjectLiteral, 4);
Node* literal = NewNode(op, literals_array, literal_index, constants, flags);
+ PrepareFrameState(literal, expr->CreateLiteralId(),
+ OutputFrameStateCombine::Push());
// The object is expected on the operand stack during computation of the
// property values and is the value of the entire expression.
Node* receiver = environment()->Pop();
if (property->emit_store()) {
Node* strict = jsgraph()->Constant(SLOPPY);
- const Operator* op = javascript()->Runtime(Runtime::kSetProperty, 4);
+ const Operator* op =
+ javascript()->CallRuntime(Runtime::kSetProperty, 4);
NewNode(op, receiver, key, value, strict);
}
break;
Node* value = environment()->Pop();
Node* receiver = environment()->Pop();
if (property->emit_store()) {
- const Operator* op = javascript()->Runtime(Runtime::kSetPrototype, 2);
- NewNode(op, receiver, value);
+ const Operator* op =
+ javascript()->CallRuntime(Runtime::kInternalSetPrototype, 2);
+ Node* set_prototype = NewNode(op, receiver, value);
+ // SetPrototype should not lazy deopt on an object
+ // literal.
+ PrepareFrameState(set_prototype, BailoutId::None());
}
break;
}
Node* name = environment()->Pop();
Node* attr = jsgraph()->Constant(NONE);
const Operator* op =
- javascript()->Runtime(Runtime::kDefineAccessorPropertyUnchecked, 5);
+ javascript()->CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
Node* call = NewNode(op, literal, name, getter, setter, attr);
- PrepareFrameState(call, it->first->id());
+ // This should not lazy deopt on a new literal.
+ PrepareFrameState(call, BailoutId::None());
}
// Transform literals that contain functions to fast properties.
if (expr->has_function()) {
- const Operator* op = javascript()->Runtime(Runtime::kToFastProperties, 1);
+ const Operator* op =
+ javascript()->CallRuntime(Runtime::kToFastProperties, 1);
NewNode(op, literal);
}
Node* literal_index = jsgraph()->Constant(expr->literal_index());
Node* constants = jsgraph()->Constant(expr->constant_elements());
Node* flags = jsgraph()->Constant(expr->ComputeFlags());
- const Operator* op = javascript()->Runtime(Runtime::kCreateArrayLiteral, 4);
+ const Operator* op =
+ javascript()->CallRuntime(Runtime::kCreateArrayLiteral, 4);
Node* literal = NewNode(op, literals_array, literal_index, constants, flags);
// The array and the literal index are both expected on the operand stack
Node* old_value = NULL;
switch (assign_type) {
case VARIABLE: {
- Variable* variable = expr->target()->AsVariableProxy()->var();
- old_value = BuildVariableLoad(variable, expr->target()->id());
+ VariableProxy* proxy = expr->target()->AsVariableProxy();
+ VectorSlotPair pair =
+ CreateVectorSlotPair(proxy->VariableFeedbackSlot());
+ old_value = BuildVariableLoad(proxy->var(), expr->target()->id(), pair);
break;
}
case NAMED_PROPERTY: {
Node* object = environment()->Top();
Unique<Name> name =
MakeUnique(property->key()->AsLiteral()->AsPropertyName());
- old_value = NewNode(javascript()->LoadNamed(name), object);
- PrepareFrameState(old_value, property->LoadId(), kPushOutput);
+ VectorSlotPair pair =
+ CreateVectorSlotPair(property->PropertyFeedbackSlot());
+ old_value = NewNode(javascript()->LoadNamed(name, pair), object);
+ PrepareFrameState(old_value, property->LoadId(),
+ OutputFrameStateCombine::Push());
break;
}
case KEYED_PROPERTY: {
Node* key = environment()->Top();
Node* object = environment()->Peek(1);
- old_value = NewNode(javascript()->LoadProperty(), object, key);
- PrepareFrameState(old_value, property->LoadId(), kPushOutput);
+ VectorSlotPair pair =
+ CreateVectorSlotPair(property->PropertyFeedbackSlot());
+ old_value = NewNode(javascript()->LoadProperty(pair), object, key);
+ PrepareFrameState(old_value, property->LoadId(),
+ OutputFrameStateCombine::Push());
break;
}
}
Node* right = environment()->Pop();
Node* left = environment()->Pop();
Node* value = BuildBinaryOp(left, right, expr->binary_op());
- PrepareFrameState(value, expr->binary_operation()->id(), kPushOutput);
+ PrepareFrameState(value, expr->binary_operation()->id(),
+ OutputFrameStateCombine::Push());
environment()->Push(value);
} else {
VisitForValue(expr->value());
void AstGraphBuilder::VisitThrow(Throw* expr) {
VisitForValue(expr->exception());
Node* exception = environment()->Pop();
- const Operator* op = javascript()->Runtime(Runtime::kThrow, 1);
+ const Operator* op = javascript()->CallRuntime(Runtime::kThrow, 1);
Node* value = NewNode(op, exception);
+ PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
ast_context()->ProduceValue(value);
}
void AstGraphBuilder::VisitProperty(Property* expr) {
Node* value;
+ VectorSlotPair pair = CreateVectorSlotPair(expr->PropertyFeedbackSlot());
if (expr->key()->IsPropertyName()) {
VisitForValue(expr->obj());
Node* object = environment()->Pop();
Unique<Name> name = MakeUnique(expr->key()->AsLiteral()->AsPropertyName());
- value = NewNode(javascript()->LoadNamed(name), object);
+ value = NewNode(javascript()->LoadNamed(name, pair), object);
} else {
VisitForValue(expr->obj());
VisitForValue(expr->key());
Node* key = environment()->Pop();
Node* object = environment()->Pop();
- value = NewNode(javascript()->LoadProperty(), object, key);
+ value = NewNode(javascript()->LoadProperty(pair), object, key);
}
PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
ast_context()->ProduceValue(value);
bool possibly_eval = false;
switch (call_type) {
case Call::GLOBAL_CALL: {
- Variable* variable = callee->AsVariableProxy()->var();
- callee_value = BuildVariableLoad(variable, expr->expression()->id());
+ VariableProxy* proxy = callee->AsVariableProxy();
+ VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot());
+ callee_value =
+ BuildVariableLoad(proxy->var(), expr->expression()->id(), pair);
receiver_value = jsgraph()->UndefinedConstant();
break;
}
Variable* variable = callee->AsVariableProxy()->var();
DCHECK(variable->location() == Variable::LOOKUP);
Node* name = jsgraph()->Constant(variable->name());
- const Operator* op = javascript()->Runtime(Runtime::kLoadLookupSlot, 2);
+ const Operator* op =
+ javascript()->CallRuntime(Runtime::kLoadLookupSlot, 2);
Node* pair = NewNode(op, current_context(), name);
callee_value = NewNode(common()->Projection(0), pair);
receiver_value = NewNode(common()->Projection(1), pair);
+
+ PrepareFrameState(pair, expr->EvalOrLookupId(),
+ OutputFrameStateCombine::Push(2));
break;
}
case Call::PROPERTY_CALL: {
Property* property = callee->AsProperty();
VisitForValue(property->obj());
Node* object = environment()->Top();
+ VectorSlotPair pair =
+ CreateVectorSlotPair(property->PropertyFeedbackSlot());
if (property->key()->IsPropertyName()) {
Unique<Name> name =
MakeUnique(property->key()->AsLiteral()->AsPropertyName());
- callee_value = NewNode(javascript()->LoadNamed(name), object);
+ callee_value = NewNode(javascript()->LoadNamed(name, pair), object);
} else {
VisitForValue(property->key());
Node* key = environment()->Pop();
- callee_value = NewNode(javascript()->LoadProperty(), object, key);
+ callee_value = NewNode(javascript()->LoadProperty(pair), object, key);
}
- PrepareFrameState(callee_value, property->LoadId(), kPushOutput);
+ PrepareFrameState(callee_value, property->LoadId(),
+ OutputFrameStateCombine::Push());
receiver_value = environment()->Pop();
// Note that a PROPERTY_CALL requires the receiver to be wrapped into an
// object for sloppy callees. This could also be modeled explicitly here,
flags = CALL_AS_METHOD;
break;
}
+ case Call::SUPER_CALL: {
+ // todo(dslomov): implement super calls in turbofan.
+ UNIMPLEMENTED();
+ break;
+ }
case Call::POSSIBLY_EVAL_CALL:
possibly_eval = true;
// Fall through.
Node* strict = jsgraph()->Constant(strict_mode());
Node* position = jsgraph()->Constant(info()->scope()->start_position());
const Operator* op =
- javascript()->Runtime(Runtime::kResolvePossiblyDirectEval, 6);
+ javascript()->CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
Node* pair =
NewNode(op, callee, source, function, receiver, strict, position);
+ PrepareFrameState(pair, expr->EvalOrLookupId(),
+ OutputFrameStateCombine::PokeAt(arg_count + 1));
Node* new_callee = NewNode(common()->Projection(0), pair);
Node* new_receiver = NewNode(common()->Projection(1), pair);
}
// Create node to perform the function call.
- const Operator* call = javascript()->Call(args->length() + 2, flags);
+ const Operator* call = javascript()->CallFunction(args->length() + 2, flags);
Node* value = ProcessArguments(call, args->length() + 2);
PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
ast_context()->ProduceValue(value);
VisitForValues(args);
// Create node to perform the construct call.
- const Operator* call = javascript()->CallNew(args->length() + 1);
+ const Operator* call = javascript()->CallConstruct(args->length() + 1);
Node* value = ProcessArguments(call, args->length() + 1);
PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
ast_context()->ProduceValue(value);
CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS;
Node* receiver_value = BuildLoadBuiltinsObject();
Unique<String> unique = MakeUnique(name);
- Node* callee_value = NewNode(javascript()->LoadNamed(unique), receiver_value);
+ VectorSlotPair pair = CreateVectorSlotPair(expr->CallRuntimeFeedbackSlot());
+ Node* callee_value =
+ NewNode(javascript()->LoadNamed(unique, pair), receiver_value);
// TODO(jarin): Find/create a bailout id to deoptimize to (crankshaft
// refuses to optimize functions with jsruntime calls).
- PrepareFrameState(callee_value, BailoutId::None(), kPushOutput);
+ PrepareFrameState(callee_value, BailoutId::None(),
+ OutputFrameStateCombine::Push());
environment()->Push(callee_value);
environment()->Push(receiver_value);
VisitForValues(args);
// Create node to perform the JS runtime call.
- const Operator* call = javascript()->Call(args->length() + 2, flags);
+ const Operator* call = javascript()->CallFunction(args->length() + 2, flags);
Node* value = ProcessArguments(call, args->length() + 2);
PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
ast_context()->ProduceValue(value);
// Create node to perform the runtime call.
Runtime::FunctionId functionId = function->function_id;
- const Operator* call = javascript()->Runtime(functionId, args->length());
+ const Operator* call = javascript()->CallRuntime(functionId, args->length());
Node* value = ProcessArguments(call, args->length());
PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
ast_context()->ProduceValue(value);
int stack_depth = -1;
switch (assign_type) {
case VARIABLE: {
- Variable* variable = expr->expression()->AsVariableProxy()->var();
- old_value = BuildVariableLoad(variable, expr->expression()->id());
+ VariableProxy* proxy = expr->expression()->AsVariableProxy();
+ VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot());
+ old_value =
+ BuildVariableLoad(proxy->var(), expr->expression()->id(), pair);
stack_depth = 0;
break;
}
Node* object = environment()->Top();
Unique<Name> name =
MakeUnique(property->key()->AsLiteral()->AsPropertyName());
- old_value = NewNode(javascript()->LoadNamed(name), object);
- PrepareFrameState(old_value, property->LoadId(), kPushOutput);
+ VectorSlotPair pair =
+ CreateVectorSlotPair(property->PropertyFeedbackSlot());
+ old_value = NewNode(javascript()->LoadNamed(name, pair), object);
+ PrepareFrameState(old_value, property->LoadId(),
+ OutputFrameStateCombine::Push());
stack_depth = 1;
break;
}
VisitForValue(property->key());
Node* key = environment()->Top();
Node* object = environment()->Peek(1);
- old_value = NewNode(javascript()->LoadProperty(), object, key);
- PrepareFrameState(old_value, property->LoadId(), kPushOutput);
+ VectorSlotPair pair =
+ CreateVectorSlotPair(property->PropertyFeedbackSlot());
+ old_value = NewNode(javascript()->LoadProperty(pair), object, key);
+ PrepareFrameState(old_value, property->LoadId(),
+ OutputFrameStateCombine::Push());
stack_depth = 2;
break;
}
DeclareGlobalsStrictMode::encode(strict_mode());
Node* flags = jsgraph()->Constant(encoded_flags);
Node* pairs = jsgraph()->Constant(data);
- const Operator* op = javascript()->Runtime(Runtime::kDeclareGlobals, 3);
+ const Operator* op = javascript()->CallRuntime(Runtime::kDeclareGlobals, 3);
NewNode(op, current_context(), pairs, flags);
globals()->Rewind(0);
}
// deleting "this" is allowed in all language modes.
Variable* variable = expr->expression()->AsVariableProxy()->var();
DCHECK(strict_mode() == SLOPPY || variable->is_this());
- value = BuildVariableDelete(variable);
+ value = BuildVariableDelete(variable, expr->id(),
+ ast_context()->GetStateCombine());
} else if (expr->expression()->IsProperty()) {
Property* property = expr->expression()->AsProperty();
VisitForValue(property->obj());
Node* key = environment()->Pop();
Node* object = environment()->Pop();
value = NewNode(javascript()->DeleteProperty(strict_mode()), object, key);
+ PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
} else {
VisitForEffect(expr->expression());
value = jsgraph()->TrueConstant();
if (expr->expression()->IsVariableProxy()) {
// Typeof does not throw a reference error on global variables, hence we
// perform a non-contextual load in case the operand is a variable proxy.
- Variable* variable = expr->expression()->AsVariableProxy()->var();
- operand =
- BuildVariableLoad(variable, expr->expression()->id(), NOT_CONTEXTUAL);
+ VariableProxy* proxy = expr->expression()->AsVariableProxy();
+ VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot());
+ operand = BuildVariableLoad(proxy->var(), expr->expression()->id(), pair,
+ NOT_CONTEXTUAL);
} else {
VisitForValue(expr->expression());
operand = environment()->Pop();
}
+StrictMode AstGraphBuilder::strict_mode() const {
+ return info()->strict_mode();
+}
+
+
+VectorSlotPair AstGraphBuilder::CreateVectorSlotPair(
+ FeedbackVectorICSlot slot) const {
+ return VectorSlotPair(handle(info()->shared_info()->feedback_vector()), slot);
+}
+
+
Node* AstGraphBuilder::ProcessArguments(const Operator* op, int arity) {
DCHECK(environment()->stack_height() >= arity);
Node** all = info()->zone()->NewArray<Node*>(arity);
// Allocate and initialize a new arguments object.
Node* callee = GetFunctionClosure();
- const Operator* op = javascript()->Runtime(Runtime::kNewArguments, 1);
+ const Operator* op = javascript()->CallRuntime(Runtime::kNewArguments, 1);
Node* object = NewNode(op, callee);
// Assign the object to the arguments variable.
Node* AstGraphBuilder::BuildHoleCheckThrow(Node* value, Variable* variable,
- Node* not_hole) {
+ Node* not_hole,
+ BailoutId bailout_id) {
IfBuilder hole_check(this);
Node* the_hole = jsgraph()->TheHoleConstant();
Node* check = NewNode(javascript()->StrictEqual(), value, the_hole);
hole_check.If(check);
hole_check.Then();
- environment()->Push(BuildThrowReferenceError(variable));
+ environment()->Push(BuildThrowReferenceError(variable, bailout_id));
hole_check.Else();
environment()->Push(not_hole);
hole_check.End();
Node* AstGraphBuilder::BuildVariableLoad(Variable* variable,
BailoutId bailout_id,
+ const VectorSlotPair& feedback,
ContextualMode contextual_mode) {
Node* the_hole = jsgraph()->TheHoleConstant();
VariableMode mode = variable->mode();
// Global var, const, or let variable.
Node* global = BuildLoadGlobalObject();
Unique<Name> name = MakeUnique(variable->name());
- const Operator* op = javascript()->LoadNamed(name, contextual_mode);
+ const Operator* op =
+ javascript()->LoadNamed(name, feedback, contextual_mode);
Node* node = NewNode(op, global);
- PrepareFrameState(node, bailout_id, kPushOutput);
+ PrepareFrameState(node, bailout_id, OutputFrameStateCombine::Push());
return node;
}
case Variable::PARAMETER:
} else if (mode == LET || mode == CONST) {
// Perform check for uninitialized let/const variables.
if (value->op() == the_hole->op()) {
- value = BuildThrowReferenceError(variable);
+ value = BuildThrowReferenceError(variable, bailout_id);
} else if (value->opcode() == IrOpcode::kPhi) {
- value = BuildHoleCheckThrow(value, variable, value);
+ value = BuildHoleCheckThrow(value, variable, value, bailout_id);
}
}
return value;
value = BuildHoleCheckSilent(value, undefined, value);
} else if (mode == LET || mode == CONST) {
// Perform check for uninitialized let/const variables.
- value = BuildHoleCheckThrow(value, variable, value);
+ value = BuildHoleCheckThrow(value, variable, value, bailout_id);
}
return value;
}
(contextual_mode == CONTEXTUAL)
? Runtime::kLoadLookupSlot
: Runtime::kLoadLookupSlotNoReferenceError;
- const Operator* op = javascript()->Runtime(function_id, 2);
+ const Operator* op = javascript()->CallRuntime(function_id, 2);
Node* pair = NewNode(op, current_context(), name);
+ PrepareFrameState(pair, bailout_id, OutputFrameStateCombine::Push(1));
return NewNode(common()->Projection(0), pair);
}
}
}
-Node* AstGraphBuilder::BuildVariableDelete(Variable* variable) {
+Node* AstGraphBuilder::BuildVariableDelete(
+ Variable* variable, BailoutId bailout_id,
+ OutputFrameStateCombine state_combine) {
switch (variable->location()) {
case Variable::UNALLOCATED: {
// Global var, const, or let variable.
Node* global = BuildLoadGlobalObject();
Node* name = jsgraph()->Constant(variable->name());
const Operator* op = javascript()->DeleteProperty(strict_mode());
- return NewNode(op, global, name);
+ Node* result = NewNode(op, global, name);
+ PrepareFrameState(result, bailout_id, state_combine);
+ return result;
}
case Variable::PARAMETER:
case Variable::LOCAL:
case Variable::CONTEXT:
// Local var, const, or let variable or context variable.
- return variable->is_this() ? jsgraph()->TrueConstant()
- : jsgraph()->FalseConstant();
+ return jsgraph()->BooleanConstant(variable->is_this());
case Variable::LOOKUP: {
// Dynamic lookup of context variable (anywhere in the chain).
Node* name = jsgraph()->Constant(variable->name());
- const Operator* op = javascript()->Runtime(Runtime::kDeleteLookupSlot, 2);
- return NewNode(op, current_context(), name);
+ const Operator* op =
+ javascript()->CallRuntime(Runtime::kDeleteLookupSlot, 2);
+ Node* result = NewNode(op, current_context(), name);
+ PrepareFrameState(result, bailout_id, state_combine);
+ return result;
}
}
UNREACHABLE();
// temporal dead zone of a let declared variable.
Node* current = environment()->Lookup(variable);
if (current->op() == the_hole->op()) {
- value = BuildThrowReferenceError(variable);
+ value = BuildThrowReferenceError(variable, bailout_id);
} else if (value->opcode() == IrOpcode::kPhi) {
- value = BuildHoleCheckThrow(current, variable, value);
+ value = BuildHoleCheckThrow(current, variable, value, bailout_id);
}
} else if (mode == CONST && op != Token::INIT_CONST) {
// All assignments to const variables are early errors.
const Operator* op =
javascript()->LoadContext(depth, variable->index(), false);
Node* current = NewNode(op, current_context());
- value = BuildHoleCheckThrow(current, variable, value);
+ value = BuildHoleCheckThrow(current, variable, value, bailout_id);
} else if (mode == CONST && op != Token::INIT_CONST) {
// All assignments to const variables are early errors.
UNREACHABLE();
Node* strict = jsgraph()->Constant(strict_mode());
// TODO(mstarzinger): Use Runtime::kInitializeLegacyConstLookupSlot for
// initializations of const declarations.
- const Operator* op = javascript()->Runtime(Runtime::kStoreLookupSlot, 4);
- return NewNode(op, value, current_context(), name, strict);
+ const Operator* op =
+ javascript()->CallRuntime(Runtime::kStoreLookupSlot, 4);
+ Node* store = NewNode(op, value, current_context(), name, strict);
+ PrepareFrameState(store, bailout_id);
+ return store;
}
}
UNREACHABLE();
Node* AstGraphBuilder::BuildLoadObjectField(Node* object, int offset) {
- // TODO(sigurds) Use simplified load here once it is ready.
Node* field_load = NewNode(jsgraph()->machine()->Load(kMachAnyTagged), object,
jsgraph()->Int32Constant(offset - kHeapObjectTag));
return field_load;
}
-Node* AstGraphBuilder::BuildToBoolean(Node* value) {
- // TODO(mstarzinger): Possible optimization is to NOP for boolean values.
- return NewNode(javascript()->ToBoolean(), value);
+Node* AstGraphBuilder::BuildToBoolean(Node* input) {
+ // TODO(titzer): this should be in a JSOperatorReducer.
+ switch (input->opcode()) {
+ case IrOpcode::kInt32Constant:
+ return jsgraph_->BooleanConstant(!Int32Matcher(input).Is(0));
+ case IrOpcode::kFloat64Constant:
+ return jsgraph_->BooleanConstant(!Float64Matcher(input).Is(0));
+ case IrOpcode::kNumberConstant:
+ return jsgraph_->BooleanConstant(!NumberMatcher(input).Is(0));
+ case IrOpcode::kHeapConstant: {
+ Handle<Object> object = HeapObjectMatcher<Object>(input).Value().handle();
+ if (object->IsTrue()) return jsgraph_->TrueConstant();
+ if (object->IsFalse()) return jsgraph_->FalseConstant();
+ // TODO(turbofan): other constants.
+ break;
+ }
+ default:
+ break;
+ }
+ if (NodeProperties::IsTyped(input)) {
+ Type* upper = NodeProperties::GetBounds(input).upper;
+ if (upper->Is(Type::Boolean())) return input;
+ }
+
+ return NewNode(javascript()->ToBoolean(), input);
}
-Node* AstGraphBuilder::BuildThrowReferenceError(Variable* variable) {
+Node* AstGraphBuilder::BuildThrowReferenceError(Variable* variable,
+ BailoutId bailout_id) {
// TODO(mstarzinger): Should be unified with the VisitThrow implementation.
Node* variable_name = jsgraph()->Constant(variable->name());
- const Operator* op = javascript()->Runtime(Runtime::kThrowReferenceError, 1);
- return NewNode(op, variable_name);
+ const Operator* op =
+ javascript()->CallRuntime(Runtime::kThrowReferenceError, 1);
+ Node* call = NewNode(op, variable_name);
+ PrepareFrameState(call, bailout_id);
+ return call;
}
}
+Node* AstGraphBuilder::BuildStackCheck() {
+ IfBuilder stack_check(this);
+ Node* limit =
+ NewNode(jsgraph()->machine()->Load(kMachPtr),
+ jsgraph()->ExternalConstant(
+ ExternalReference::address_of_stack_limit(isolate())),
+ jsgraph()->ZeroConstant());
+ Node* stack = NewNode(jsgraph()->machine()->LoadStackPointer());
+ Node* tag = NewNode(jsgraph()->machine()->UintLessThan(), limit, stack);
+ stack_check.If(tag, BranchHint::kTrue);
+ stack_check.Then();
+ stack_check.Else();
+ Node* guard = NewNode(javascript()->CallRuntime(Runtime::kStackGuard, 0));
+ stack_check.End();
+ return guard;
+}
+
+
void AstGraphBuilder::PrepareFrameState(Node* node, BailoutId ast_id,
OutputFrameStateCombine combine) {
if (OperatorProperties::HasFrameStateInput(node->op())) {
}
}
+
+BitVector* AstGraphBuilder::GetVariablesAssignedInLoop(
+ IterationStatement* stmt) {
+ if (loop_assignment_analysis_ == NULL) return NULL;
+ return loop_assignment_analysis_->GetVariablesAssignedInLoop(stmt);
}
-}
-} // namespace v8::internal::compiler
+
+} // namespace compiler
+} // namespace internal
+} // namespace v8