#include "src/compiler.h"
#include "src/compiler/control-builders.h"
+#include "src/compiler/machine-operator.h"
#include "src/compiler/node-properties.h"
#include "src/compiler/node-properties-inl.h"
#include "src/full-codegen.h"
Node* AstGraphBuilder::GetFunctionClosure() {
if (!function_closure_.is_set()) {
// Parameter -1 is special for the function closure
- Operator* op = common()->Parameter(-1);
+ const Operator* op = common()->Parameter(-1);
Node* node = NewNode(op, graph()->start());
function_closure_.set(node);
}
Node* AstGraphBuilder::GetFunctionContext() {
if (!function_context_.is_set()) {
// Parameter (arity + 1) is special for the outer context of the function
- Operator* op = common()->Parameter(info()->num_parameters() + 1);
+ const Operator* op = common()->Parameter(info()->num_parameters() + 1);
Node* node = NewNode(op, graph()->start());
function_context_.set(node);
}
VisitDeclarations(scope->declarations());
// TODO(mstarzinger): This should do an inlined stack check.
- NewNode(javascript()->Runtime(Runtime::kStackGuard, 0));
+ Node* node = NewNode(javascript()->Runtime(Runtime::kStackGuard, 0));
+ PrepareFrameState(node, BailoutId::FunctionEntry());
// Visit statements in the function body.
VisitStatements(info()->function()->body());
locals_count_(scope->num_stack_slots()),
parameters_node_(NULL),
locals_node_(NULL),
- stack_node_(NULL),
- parameters_dirty_(true),
- locals_dirty_(true),
- stack_dirty_(true) {
+ stack_node_(NULL) {
DCHECK_EQ(scope->num_parameters() + 1, parameters_count());
// Bind the receiver variable.
locals_count_(copy.locals_count_),
parameters_node_(copy.parameters_node_),
locals_node_(copy.locals_node_),
- stack_node_(copy.stack_node_),
- parameters_dirty_(copy.parameters_dirty_),
- locals_dirty_(copy.locals_dirty_),
- stack_dirty_(copy.stack_dirty_) {}
-
-
-Node* AstGraphBuilder::Environment::Checkpoint(BailoutId ast_id) {
- if (parameters_dirty_) {
- Operator* op = common()->StateValues(parameters_count());
- if (parameters_count() != 0) {
- Node** parameters = &values()->front();
- parameters_node_ = graph()->NewNode(op, parameters_count(), parameters);
- } else {
- parameters_node_ = graph()->NewNode(op);
- }
- parameters_dirty_ = false;
- }
- if (locals_dirty_) {
- Operator* op = common()->StateValues(locals_count());
- if (locals_count() != 0) {
- Node** locals = &values()->at(parameters_count_);
- locals_node_ = graph()->NewNode(op, locals_count(), locals);
- } else {
- locals_node_ = graph()->NewNode(op);
+ stack_node_(copy.stack_node_) {}
+
+
+void AstGraphBuilder::Environment::UpdateStateValues(Node** state_values,
+ int offset, int count) {
+ bool should_update = false;
+ Node** env_values = (count == 0) ? NULL : &values()->at(offset);
+ if (*state_values == NULL || (*state_values)->InputCount() != count) {
+ should_update = true;
+ } else {
+ DCHECK(static_cast<size_t>(offset + count) <= values()->size());
+ for (int i = 0; i < count; i++) {
+ if ((*state_values)->InputAt(i) != env_values[i]) {
+ should_update = true;
+ break;
+ }
}
- locals_dirty_ = false;
}
- if (stack_dirty_) {
- Operator* op = common()->StateValues(stack_height());
- if (stack_height() != 0) {
- Node** stack = &values()->at(parameters_count_ + locals_count_);
- stack_node_ = graph()->NewNode(op, stack_height(), stack);
- } else {
- stack_node_ = graph()->NewNode(op);
- }
- stack_dirty_ = false;
+ if (should_update) {
+ const Operator* op = common()->StateValues(count);
+ (*state_values) = graph()->NewNode(op, count, env_values);
}
+}
- Operator* op = common()->FrameState(ast_id);
- return graph()->NewNode(op, parameters_node_, locals_node_, stack_node_);
+Node* AstGraphBuilder::Environment::Checkpoint(
+ BailoutId ast_id, OutputFrameStateCombine combine) {
+ UpdateStateValues(¶meters_node_, 0, parameters_count());
+ UpdateStateValues(&locals_node_, parameters_count(), locals_count());
+ UpdateStateValues(&stack_node_, parameters_count() + locals_count(),
+ stack_height());
+
+ const Operator* op = common()->FrameState(JS_FRAME, ast_id, combine);
+
+ return graph()->NewNode(op, parameters_node_, locals_node_, stack_node_,
+ GetContext(),
+ builder()->jsgraph()->UndefinedConstant());
}
AstGraphBuilder::AstContext::AstContext(AstGraphBuilder* own,
- Expression::Context kind,
- BailoutId bailout_id)
- : bailout_id_(bailout_id),
- kind_(kind),
- owner_(own),
- outer_(own->ast_context()) {
+ Expression::Context kind)
+ : kind_(kind), owner_(own), outer_(own->ast_context()) {
owner()->set_ast_context(this); // Push.
#ifdef DEBUG
original_height_ = environment()->stack_height();
}
-void AstGraphBuilder::AstEffectContext::ProduceValueWithLazyBailout(
- Node* value) {
- ProduceValue(value);
- owner()->BuildLazyBailout(value, bailout_id_);
-}
-
-
-void AstGraphBuilder::AstValueContext::ProduceValueWithLazyBailout(
- Node* value) {
- ProduceValue(value);
- owner()->BuildLazyBailout(value, bailout_id_);
-}
-
-
-void AstGraphBuilder::AstTestContext::ProduceValueWithLazyBailout(Node* value) {
- environment()->Push(value);
- owner()->BuildLazyBailout(value, bailout_id_);
- environment()->Pop();
- ProduceValue(value);
-}
-
-
void AstGraphBuilder::AstEffectContext::ProduceValue(Node* value) {
// The value is ignored.
}
void AstGraphBuilder::VisitForValue(Expression* expr) {
- AstValueContext for_value(this, expr->id());
+ AstValueContext for_value(this);
if (!HasStackOverflow()) {
expr->Accept(this);
}
void AstGraphBuilder::VisitForEffect(Expression* expr) {
- AstEffectContext for_effect(this, expr->id());
+ AstEffectContext for_effect(this);
if (!HasStackOverflow()) {
expr->Accept(this);
}
void AstGraphBuilder::VisitForTest(Expression* expr) {
- AstTestContext for_condition(this, expr->id());
+ AstTestContext for_condition(this);
if (!HasStackOverflow()) {
expr->Accept(this);
}
case Variable::CONTEXT:
if (hole_init) {
Node* value = jsgraph()->TheHoleConstant();
- Operator* op = javascript()->StoreContext(0, variable->index());
+ const Operator* op = javascript()->StoreContext(0, variable->index());
NewNode(op, current_context(), value);
}
break;
case Variable::CONTEXT: {
VisitForValue(decl->fun());
Node* value = environment()->Pop();
- Operator* op = javascript()->StoreContext(0, variable->index());
+ const Operator* op = javascript()->StoreContext(0, variable->index());
NewNode(op, current_context(), value);
break;
}
// Visit statements in the same scope, no declarations.
VisitStatements(stmt->statements());
} else {
- Operator* op = javascript()->CreateBlockContext();
+ const Operator* op = javascript()->CreateBlockContext();
Node* scope_info = jsgraph()->Constant(stmt->scope()->GetScopeInfo());
Node* context = NewNode(op, scope_info, GetFunctionClosure());
ContextScope scope(this, stmt->scope(), context);
void AstGraphBuilder::VisitWithStatement(WithStatement* stmt) {
VisitForValue(stmt->expression());
Node* value = environment()->Pop();
- Operator* op = javascript()->CreateWithContext();
+ const Operator* op = javascript()->CreateWithContext();
Node* context = NewNode(op, value, GetFunctionClosure());
ContextScope scope(this, stmt->scope(), context);
Visit(stmt->statement());
// value is still on the operand stack while the label is evaluated.
VisitForValue(clause->label());
Node* label = environment()->Pop();
- Operator* op = javascript()->StrictEqual();
+ const Operator* op = javascript()->StrictEqual();
Node* condition = NewNode(op, tag, label);
compare_switch.BeginLabel(i, condition);
Node* exit_cond =
NewNode(javascript()->LessThan(), index, cache_length);
// TODO(jarin): provide real bailout id.
- BuildLazyBailout(exit_cond, BailoutId::None());
+ PrepareFrameState(exit_cond, BailoutId::None());
for_loop.BreakUnless(exit_cond);
// TODO(dcarney): this runtime call should be a handful of
// simplified instructions that
test_should_filter.If(should_filter_cond);
test_should_filter.Then();
value = environment()->Pop();
- // TODO(dcarney): Better load from function context.
- // See comment in BuildLoadBuiltinsObject.
- Handle<JSFunction> function(JSFunction::cast(
- info()->context()->builtins()->javascript_builtin(
- Builtins::FILTER_KEY)));
+ Node* builtins = BuildLoadBuiltinsObject();
+ Node* function = BuildLoadObjectField(
+ builtins,
+ JSBuiltinsObject::OffsetOfFunctionWithId(Builtins::FILTER_KEY));
// Callee.
- environment()->Push(jsgraph()->HeapConstant(function));
+ environment()->Push(function);
// Receiver.
environment()->Push(obj);
// Args.
Node* res = ProcessArguments(
javascript()->Call(3, NO_CALL_FUNCTION_FLAGS), 3);
// TODO(jarin): provide real bailout id.
- BuildLazyBailout(res, BailoutId::None());
+ PrepareFrameState(res, BailoutId::None());
Node* property_missing = NewNode(javascript()->StrictEqual(), res,
jsgraph()->ZeroConstant());
{
// Inc counter and continue.
Node* index_inc =
NewNode(javascript()->Add(), index, jsgraph()->OneConstant());
- environment()->Poke(0, index_inc);
// TODO(jarin): provide real bailout id.
- BuildLazyBailout(index_inc, BailoutId::None());
+ PrepareFrameState(index_inc, BailoutId::None());
+ environment()->Poke(0, index_inc);
for_loop.Continue();
is_property_missing.Else();
is_property_missing.End();
// Bind value and do loop body.
VisitForInAssignment(stmt->each(), value);
VisitIterationBody(stmt, &for_loop, 5);
+ for_loop.EndBody();
// Inc counter and continue.
Node* index_inc =
NewNode(javascript()->Add(), index, jsgraph()->OneConstant());
- environment()->Poke(0, index_inc);
// TODO(jarin): provide real bailout id.
- BuildLazyBailout(index_inc, BailoutId::None());
- for_loop.EndBody();
+ PrepareFrameState(index_inc, BailoutId::None());
+ environment()->Poke(0, index_inc);
for_loop.EndLoop();
environment()->Drop(5);
// PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
void AstGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
// TODO(turbofan): Do we really need a separate reloc-info for this?
- NewNode(javascript()->Runtime(Runtime::kDebugBreak, 0));
+ Node* node = NewNode(javascript()->Runtime(Runtime::kDebugBreak, 0));
+ PrepareFrameState(node, stmt->DebugBreakId());
}
Node* info = jsgraph()->Constant(shared_info);
Node* pretenure = expr->pretenure() ? jsgraph()->TrueConstant()
: jsgraph()->FalseConstant();
- Operator* op = javascript()->Runtime(Runtime::kNewClosure, 3);
+ const Operator* op = javascript()->Runtime(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::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
UNREACHABLE();
}
void AstGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
- Handle<JSFunction> closure = info()->closure();
+ Node* closure = GetFunctionClosure();
// Create node to materialize a regular expression literal.
- Node* literals_array = jsgraph()->Constant(handle(closure->literals()));
+ Node* literals_array =
+ BuildLoadObjectField(closure, JSFunction::kLiteralsOffset);
Node* literal_index = jsgraph()->Constant(expr->literal_index());
Node* pattern = jsgraph()->Constant(expr->pattern());
Node* flags = jsgraph()->Constant(expr->flags());
- Operator* op = javascript()->Runtime(Runtime::kMaterializeRegExpLiteral, 4);
+ const Operator* op =
+ javascript()->Runtime(Runtime::kMaterializeRegExpLiteral, 4);
Node* literal = NewNode(op, literals_array, literal_index, pattern, flags);
ast_context()->ProduceValue(literal);
}
void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
- Handle<JSFunction> closure = info()->closure();
+ Node* closure = GetFunctionClosure();
// Create node to deep-copy the literal boilerplate.
expr->BuildConstantProperties(isolate());
- Node* literals_array = jsgraph()->Constant(handle(closure->literals()));
+ Node* literals_array =
+ BuildLoadObjectField(closure, JSFunction::kLiteralsOffset);
Node* literal_index = jsgraph()->Constant(expr->literal_index());
Node* constants = jsgraph()->Constant(expr->constant_properties());
Node* flags = jsgraph()->Constant(expr->ComputeFlags());
- Operator* op = javascript()->Runtime(Runtime::kCreateObjectLiteral, 4);
+ const Operator* op = javascript()->Runtime(Runtime::kCreateObjectLiteral, 4);
Node* literal = NewNode(op, literals_array, literal_index, constants, flags);
// The object is expected on the operand stack during computation of the
if (property->emit_store()) {
VisitForValue(property->value());
Node* value = environment()->Pop();
- PrintableUnique<Name> name = MakeUnique(key->AsPropertyName());
- Node* store =
- NewNode(javascript()->StoreNamed(name), literal, value);
- BuildLazyBailout(store, key->id());
+ Unique<Name> name = MakeUnique(key->AsPropertyName());
+ Node* store = NewNode(javascript()->StoreNamed(strict_mode(), name),
+ literal, value);
+ PrepareFrameState(store, key->id());
} else {
VisitForEffect(property->value());
}
Node* receiver = environment()->Pop();
if (property->emit_store()) {
Node* strict = jsgraph()->Constant(SLOPPY);
- Operator* op = javascript()->Runtime(Runtime::kSetProperty, 4);
+ const Operator* op = javascript()->Runtime(Runtime::kSetProperty, 4);
NewNode(op, receiver, key, value, strict);
}
break;
Node* value = environment()->Pop();
Node* receiver = environment()->Pop();
if (property->emit_store()) {
- Operator* op = javascript()->Runtime(Runtime::kSetPrototype, 2);
+ const Operator* op = javascript()->Runtime(Runtime::kSetPrototype, 2);
NewNode(op, receiver, value);
}
break;
Node* getter = environment()->Pop();
Node* name = environment()->Pop();
Node* attr = jsgraph()->Constant(NONE);
- Operator* op =
+ const Operator* op =
javascript()->Runtime(Runtime::kDefineAccessorPropertyUnchecked, 5);
- NewNode(op, literal, name, getter, setter, attr);
+ Node* call = NewNode(op, literal, name, getter, setter, attr);
+ PrepareFrameState(call, it->first->id());
}
// Transform literals that contain functions to fast properties.
if (expr->has_function()) {
- Operator* op = javascript()->Runtime(Runtime::kToFastProperties, 1);
+ const Operator* op = javascript()->Runtime(Runtime::kToFastProperties, 1);
NewNode(op, literal);
}
void AstGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
- Handle<JSFunction> closure = info()->closure();
+ Node* closure = GetFunctionClosure();
// Create node to deep-copy the literal boilerplate.
expr->BuildConstantElements(isolate());
- Node* literals_array = jsgraph()->Constant(handle(closure->literals()));
+ Node* literals_array =
+ BuildLoadObjectField(closure, JSFunction::kLiteralsOffset);
Node* literal_index = jsgraph()->Constant(expr->literal_index());
Node* constants = jsgraph()->Constant(expr->constant_elements());
Node* flags = jsgraph()->Constant(expr->ComputeFlags());
- Operator* op = javascript()->Runtime(Runtime::kCreateArrayLiteral, 4);
+ const Operator* op = javascript()->Runtime(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
VisitForValue(subexpr);
Node* value = environment()->Pop();
Node* index = jsgraph()->Constant(i);
- Node* store = NewNode(javascript()->StoreProperty(), literal, index, value);
- BuildLazyBailout(store, expr->GetIdForElement(i));
+ Node* store = NewNode(javascript()->StoreProperty(strict_mode()), literal,
+ index, value);
+ PrepareFrameState(store, expr->GetIdForElement(i));
}
environment()->Pop(); // Array literal index.
VisitForValue(property->obj());
Node* object = environment()->Pop();
value = environment()->Pop();
- PrintableUnique<Name> name =
+ Unique<Name> name =
MakeUnique(property->key()->AsLiteral()->AsPropertyName());
- Node* store = NewNode(javascript()->StoreNamed(name), object, value);
+ Node* store =
+ NewNode(javascript()->StoreNamed(strict_mode(), name), object, value);
// TODO(jarin) Fill in the correct bailout id.
- BuildLazyBailout(store, BailoutId::None());
+ PrepareFrameState(store, BailoutId::None());
break;
}
case KEYED_PROPERTY: {
Node* key = environment()->Pop();
Node* object = environment()->Pop();
value = environment()->Pop();
- Node* store = NewNode(javascript()->StoreProperty(), object, key, value);
+ Node* store = NewNode(javascript()->StoreProperty(strict_mode()), object,
+ key, value);
// TODO(jarin) Fill in the correct bailout id.
- BuildLazyBailout(store, BailoutId::None());
+ PrepareFrameState(store, BailoutId::None());
break;
}
}
}
case NAMED_PROPERTY: {
Node* object = environment()->Top();
- PrintableUnique<Name> name =
+ Unique<Name> name =
MakeUnique(property->key()->AsLiteral()->AsPropertyName());
old_value = NewNode(javascript()->LoadNamed(name), object);
- BuildLazyBailoutWithPushedNode(old_value, property->LoadId());
+ PrepareFrameState(old_value, property->LoadId(), kPushOutput);
break;
}
case KEYED_PROPERTY: {
Node* key = environment()->Top();
Node* object = environment()->Peek(1);
old_value = NewNode(javascript()->LoadProperty(), object, key);
- BuildLazyBailoutWithPushedNode(old_value, property->LoadId());
+ PrepareFrameState(old_value, property->LoadId(), kPushOutput);
break;
}
}
Node* right = environment()->Pop();
Node* left = environment()->Pop();
Node* value = BuildBinaryOp(left, right, expr->binary_op());
+ PrepareFrameState(value, expr->binary_operation()->id(), kPushOutput);
environment()->Push(value);
- BuildLazyBailout(value, expr->binary_operation()->id());
} else {
VisitForValue(expr->value());
}
}
case NAMED_PROPERTY: {
Node* object = environment()->Pop();
- PrintableUnique<Name> name =
+ Unique<Name> name =
MakeUnique(property->key()->AsLiteral()->AsPropertyName());
- Node* store = NewNode(javascript()->StoreNamed(name), object, value);
- BuildLazyBailout(store, expr->AssignmentId());
+ Node* store =
+ NewNode(javascript()->StoreNamed(strict_mode(), name), object, value);
+ PrepareFrameState(store, expr->AssignmentId());
break;
}
case KEYED_PROPERTY: {
Node* key = environment()->Pop();
Node* object = environment()->Pop();
- Node* store = NewNode(javascript()->StoreProperty(), object, key, value);
- BuildLazyBailout(store, expr->AssignmentId());
+ Node* store = NewNode(javascript()->StoreProperty(strict_mode()), object,
+ key, value);
+ PrepareFrameState(store, expr->AssignmentId());
break;
}
}
void AstGraphBuilder::VisitThrow(Throw* expr) {
VisitForValue(expr->exception());
Node* exception = environment()->Pop();
- Operator* op = javascript()->Runtime(Runtime::kThrow, 1);
+ const Operator* op = javascript()->Runtime(Runtime::kThrow, 1);
Node* value = NewNode(op, exception);
ast_context()->ProduceValue(value);
}
if (expr->key()->IsPropertyName()) {
VisitForValue(expr->obj());
Node* object = environment()->Pop();
- PrintableUnique<Name> name =
- MakeUnique(expr->key()->AsLiteral()->AsPropertyName());
+ Unique<Name> name = MakeUnique(expr->key()->AsLiteral()->AsPropertyName());
value = NewNode(javascript()->LoadNamed(name), object);
} else {
VisitForValue(expr->obj());
Node* object = environment()->Pop();
value = NewNode(javascript()->LoadProperty(), object, key);
}
- ast_context()->ProduceValueWithLazyBailout(value);
+ PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
+ ast_context()->ProduceValue(value);
}
Variable* variable = callee->AsVariableProxy()->var();
DCHECK(variable->location() == Variable::LOOKUP);
Node* name = jsgraph()->Constant(variable->name());
- Operator* op = javascript()->Runtime(Runtime::kLoadLookupSlot, 2);
+ const Operator* op = javascript()->Runtime(Runtime::kLoadLookupSlot, 2);
Node* pair = NewNode(op, current_context(), name);
callee_value = NewNode(common()->Projection(0), pair);
receiver_value = NewNode(common()->Projection(1), pair);
VisitForValue(property->obj());
Node* object = environment()->Top();
if (property->key()->IsPropertyName()) {
- PrintableUnique<Name> name =
+ Unique<Name> name =
MakeUnique(property->key()->AsLiteral()->AsPropertyName());
callee_value = NewNode(javascript()->LoadNamed(name), object);
} else {
Node* key = environment()->Pop();
callee_value = NewNode(javascript()->LoadProperty(), object, key);
}
- BuildLazyBailoutWithPushedNode(callee_value, property->LoadId());
+ PrepareFrameState(callee_value, property->LoadId(), kPushOutput);
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,
Node* receiver = environment()->Lookup(info()->scope()->receiver());
Node* strict = jsgraph()->Constant(strict_mode());
Node* position = jsgraph()->Constant(info()->scope()->start_position());
- Operator* op =
+ const Operator* op =
javascript()->Runtime(Runtime::kResolvePossiblyDirectEval, 5);
Node* pair = NewNode(op, callee, source, receiver, strict, position);
Node* new_callee = NewNode(common()->Projection(0), pair);
}
// Create node to perform the function call.
- Operator* call = javascript()->Call(args->length() + 2, flags);
+ const Operator* call = javascript()->Call(args->length() + 2, flags);
Node* value = ProcessArguments(call, args->length() + 2);
- ast_context()->ProduceValueWithLazyBailout(value);
+ PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
+ ast_context()->ProduceValue(value);
}
VisitForValues(args);
// Create node to perform the construct call.
- Operator* call = javascript()->CallNew(args->length() + 1);
+ const Operator* call = javascript()->CallNew(args->length() + 1);
Node* value = ProcessArguments(call, args->length() + 1);
- ast_context()->ProduceValueWithLazyBailout(value);
+ PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
+ ast_context()->ProduceValue(value);
}
// before arguments are being evaluated.
CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS;
Node* receiver_value = BuildLoadBuiltinsObject();
- PrintableUnique<String> unique = MakeUnique(name);
+ Unique<String> unique = MakeUnique(name);
Node* callee_value = NewNode(javascript()->LoadNamed(unique), receiver_value);
- environment()->Push(callee_value);
// TODO(jarin): Find/create a bailout id to deoptimize to (crankshaft
// refuses to optimize functions with jsruntime calls).
- BuildLazyBailout(callee_value, BailoutId::None());
+ PrepareFrameState(callee_value, BailoutId::None(), kPushOutput);
+ environment()->Push(callee_value);
environment()->Push(receiver_value);
// Evaluate all arguments to the JS runtime call.
VisitForValues(args);
// Create node to perform the JS runtime call.
- Operator* call = javascript()->Call(args->length() + 2, flags);
+ const Operator* call = javascript()->Call(args->length() + 2, flags);
Node* value = ProcessArguments(call, args->length() + 2);
- ast_context()->ProduceValueWithLazyBailout(value);
+ PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
+ ast_context()->ProduceValue(value);
}
// Create node to perform the runtime call.
Runtime::FunctionId functionId = function->function_id;
- Operator* call = javascript()->Runtime(functionId, args->length());
+ const Operator* call = javascript()->Runtime(functionId, args->length());
Node* value = ProcessArguments(call, args->length());
- ast_context()->ProduceValueWithLazyBailout(value);
+ PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
+ ast_context()->ProduceValue(value);
}
case NAMED_PROPERTY: {
VisitForValue(property->obj());
Node* object = environment()->Top();
- PrintableUnique<Name> name =
+ Unique<Name> name =
MakeUnique(property->key()->AsLiteral()->AsPropertyName());
old_value = NewNode(javascript()->LoadNamed(name), object);
- BuildLazyBailoutWithPushedNode(old_value, property->LoadId());
+ PrepareFrameState(old_value, property->LoadId(), kPushOutput);
stack_depth = 1;
break;
}
Node* key = environment()->Top();
Node* object = environment()->Peek(1);
old_value = NewNode(javascript()->LoadProperty(), object, key);
- BuildLazyBailoutWithPushedNode(old_value, property->LoadId());
+ PrepareFrameState(old_value, property->LoadId(), kPushOutput);
stack_depth = 2;
break;
}
BuildBinaryOp(old_value, jsgraph()->OneConstant(), expr->binary_op());
// TODO(jarin) Insert proper bailout id here (will need to change
// full code generator).
- BuildLazyBailout(value, BailoutId::None());
+ PrepareFrameState(value, BailoutId::None());
// Store the value.
switch (assign_type) {
case VARIABLE: {
Variable* variable = expr->expression()->AsVariableProxy()->var();
+ environment()->Push(value);
BuildVariableAssignment(variable, value, expr->op(),
expr->AssignmentId());
+ environment()->Pop();
break;
}
case NAMED_PROPERTY: {
Node* object = environment()->Pop();
- PrintableUnique<Name> name =
+ Unique<Name> name =
MakeUnique(property->key()->AsLiteral()->AsPropertyName());
- Node* store = NewNode(javascript()->StoreNamed(name), object, value);
- BuildLazyBailout(store, expr->AssignmentId());
+ Node* store =
+ NewNode(javascript()->StoreNamed(strict_mode(), name), object, value);
+ environment()->Push(value);
+ PrepareFrameState(store, expr->AssignmentId());
+ environment()->Pop();
break;
}
case KEYED_PROPERTY: {
Node* key = environment()->Pop();
Node* object = environment()->Pop();
- Node* store = NewNode(javascript()->StoreProperty(), object, key, value);
- BuildLazyBailout(store, expr->AssignmentId());
+ Node* store = NewNode(javascript()->StoreProperty(strict_mode()), object,
+ key, value);
+ environment()->Push(value);
+ PrepareFrameState(store, expr->AssignmentId());
+ environment()->Pop();
break;
}
}
Node* right = environment()->Pop();
Node* left = environment()->Pop();
Node* value = BuildBinaryOp(left, right, expr->op());
- ast_context()->ProduceValueWithLazyBailout(value);
+ PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
+ ast_context()->ProduceValue(value);
}
}
}
void AstGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
- Operator* op;
+ const Operator* op;
switch (expr->op()) {
case Token::EQ:
op = javascript()->Equal();
Node* right = environment()->Pop();
Node* left = environment()->Pop();
Node* value = NewNode(op, left, right);
+ PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
ast_context()->ProduceValue(value);
-
- BuildLazyBailout(value, expr->id());
}
}
+void AstGraphBuilder::VisitSuperReference(SuperReference* expr) {
+ UNREACHABLE();
+}
+
+
void AstGraphBuilder::VisitCaseClause(CaseClause* expr) { UNREACHABLE(); }
for (int i = 0; i < globals()->length(); ++i) data->set(i, *globals()->at(i));
int encoded_flags = DeclareGlobalsEvalFlag::encode(info()->is_eval()) |
DeclareGlobalsNativeFlag::encode(info()->is_native()) |
- DeclareGlobalsStrictMode::encode(info()->strict_mode());
+ DeclareGlobalsStrictMode::encode(strict_mode());
Node* flags = jsgraph()->Constant(encoded_flags);
Node* pairs = jsgraph()->Constant(data);
- Operator* op = javascript()->Runtime(Runtime::kDeclareGlobals, 3);
+ const Operator* op = javascript()->Runtime(Runtime::kDeclareGlobals, 3);
NewNode(op, current_context(), pairs, flags);
globals()->Rewind(0);
}
}
-Node* AstGraphBuilder::ProcessArguments(Operator* op, int arity) {
+Node* AstGraphBuilder::ProcessArguments(const Operator* op, int arity) {
DCHECK(environment()->stack_height() >= arity);
- Node** all = info()->zone()->NewArray<Node*>(arity); // XXX: alloca?
+ Node** all = info()->zone()->NewArray<Node*>(arity);
for (int i = arity - 1; i >= 0; --i) {
all[i] = environment()->Pop();
}
set_current_context(context);
// Allocate a new local context.
- Operator* op = javascript()->CreateFunctionContext();
+ const Operator* op = javascript()->CreateFunctionContext();
Node* local_context = NewNode(op, closure);
set_current_context(local_context);
Node* parameter = NewNode(common()->Parameter(i + 1), graph()->start());
// Context variable (at bottom of the context chain).
DCHECK_EQ(0, info()->scope()->ContextChainLength(variable->scope()));
- Operator* op = javascript()->StoreContext(0, variable->index());
+ const Operator* op = javascript()->StoreContext(0, variable->index());
NewNode(op, local_context, parameter);
}
// Allocate and initialize a new arguments object.
Node* callee = GetFunctionClosure();
- Operator* op = javascript()->Runtime(Runtime::kNewArguments, 1);
+ const Operator* op = javascript()->Runtime(Runtime::kNewArguments, 1);
Node* object = NewNode(op, callee);
// Assign the object to the arguments variable.
case Variable::UNALLOCATED: {
// Global var, const, or let variable.
Node* global = BuildLoadGlobalObject();
- PrintableUnique<Name> name = MakeUnique(variable->name());
- Operator* op = javascript()->LoadNamed(name, contextual_mode);
+ Unique<Name> name = MakeUnique(variable->name());
+ const Operator* op = javascript()->LoadNamed(name, contextual_mode);
Node* node = NewNode(op, global);
- BuildLazyBailoutWithPushedNode(node, bailout_id);
+ PrepareFrameState(node, bailout_id, kPushOutput);
return node;
}
case Variable::PARAMETER:
// Context variable (potentially up the context chain).
int depth = current_scope()->ContextChainLength(variable->scope());
bool immutable = variable->maybe_assigned() == kNotAssigned;
- Operator* op =
+ const Operator* op =
javascript()->LoadContext(depth, variable->index(), immutable);
Node* value = NewNode(op, current_context());
// TODO(titzer): initialization checks are redundant for already
(contextual_mode == CONTEXTUAL)
? Runtime::kLoadLookupSlot
: Runtime::kLoadLookupSlotNoReferenceError;
- Operator* op = javascript()->Runtime(function_id, 2);
+ const Operator* op = javascript()->Runtime(function_id, 2);
Node* pair = NewNode(op, current_context(), name);
return NewNode(common()->Projection(0), pair);
}
// Global var, const, or let variable.
Node* global = BuildLoadGlobalObject();
Node* name = jsgraph()->Constant(variable->name());
- Operator* op = javascript()->DeleteProperty(strict_mode());
+ const Operator* op = javascript()->DeleteProperty(strict_mode());
return NewNode(op, global, name);
}
case Variable::PARAMETER:
case Variable::LOOKUP: {
// Dynamic lookup of context variable (anywhere in the chain).
Node* name = jsgraph()->Constant(variable->name());
- Operator* op = javascript()->Runtime(Runtime::kDeleteLookupSlot, 2);
+ const Operator* op = javascript()->Runtime(Runtime::kDeleteLookupSlot, 2);
return NewNode(op, current_context(), name);
}
}
case Variable::UNALLOCATED: {
// Global var, const, or let variable.
Node* global = BuildLoadGlobalObject();
- PrintableUnique<Name> name = MakeUnique(variable->name());
- Operator* op = javascript()->StoreNamed(name);
+ Unique<Name> name = MakeUnique(variable->name());
+ const Operator* op = javascript()->StoreNamed(strict_mode(), name);
Node* store = NewNode(op, global, value);
- BuildLazyBailout(store, bailout_id);
+ PrepareFrameState(store, bailout_id);
return store;
}
case Variable::PARAMETER:
int depth = current_scope()->ContextChainLength(variable->scope());
if (mode == CONST_LEGACY && op == Token::INIT_CONST_LEGACY) {
// Perform an initialization check for legacy const variables.
- Operator* op =
+ const Operator* op =
javascript()->LoadContext(depth, variable->index(), false);
Node* current = NewNode(op, current_context());
value = BuildHoleCheckSilent(current, value, current);
return value;
} else if (mode == LET && op != Token::INIT_LET) {
// Perform an initialization check for let declared variables.
- Operator* op =
+ const Operator* op =
javascript()->LoadContext(depth, variable->index(), false);
Node* current = NewNode(op, current_context());
value = BuildHoleCheckThrow(current, variable, value);
// All assignments to const variables are early errors.
UNREACHABLE();
}
- Operator* op = javascript()->StoreContext(depth, variable->index());
+ const Operator* op = javascript()->StoreContext(depth, variable->index());
return NewNode(op, current_context(), value);
}
case Variable::LOOKUP: {
Node* strict = jsgraph()->Constant(strict_mode());
// TODO(mstarzinger): Use Runtime::kInitializeLegacyConstLookupSlot for
// initializations of const declarations.
- Operator* op = javascript()->Runtime(Runtime::kStoreLookupSlot, 4);
+ const Operator* op = javascript()->Runtime(Runtime::kStoreLookupSlot, 4);
return NewNode(op, value, current_context(), name, strict);
}
}
}
+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::BuildLoadBuiltinsObject() {
- // TODO(mstarzinger): Better load from function context, otherwise optimized
- // code cannot be shared across native contexts.
- return jsgraph()->Constant(handle(info()->context()->builtins()));
+ Node* global = BuildLoadGlobalObject();
+ Node* builtins =
+ BuildLoadObjectField(global, JSGlobalObject::kBuiltinsOffset);
+ return builtins;
}
Node* AstGraphBuilder::BuildLoadGlobalObject() {
-#if 0
Node* context = GetFunctionContext();
- // TODO(mstarzinger): Use mid-level operator on FixedArray instead of the
- // JS-level operator that targets JSObject.
- Node* index = jsgraph()->Constant(Context::GLOBAL_OBJECT_INDEX);
- return NewNode(javascript()->LoadProperty(), context, index);
-#else
- // TODO(mstarzinger): Better load from function context, otherwise optimized
- // code cannot be shared across native contexts. See unused code above.
- return jsgraph()->Constant(handle(info()->context()->global_object()));
-#endif
+ const Operator* load_op =
+ javascript()->LoadContext(0, Context::GLOBAL_OBJECT_INDEX, true);
+ return NewNode(load_op, context);
}
Node* AstGraphBuilder::BuildThrowReferenceError(Variable* variable) {
// TODO(mstarzinger): Should be unified with the VisitThrow implementation.
Node* variable_name = jsgraph()->Constant(variable->name());
- Operator* op = javascript()->Runtime(Runtime::kThrowReferenceError, 1);
+ const Operator* op = javascript()->Runtime(Runtime::kThrowReferenceError, 1);
return NewNode(op, variable_name);
}
Node* AstGraphBuilder::BuildBinaryOp(Node* left, Node* right, Token::Value op) {
- Operator* js_op;
+ const Operator* js_op;
switch (op) {
case Token::BIT_OR:
js_op = javascript()->BitwiseOr();
}
-void AstGraphBuilder::BuildLazyBailout(Node* node, BailoutId ast_id) {
- if (OperatorProperties::CanLazilyDeoptimize(node->op())) {
- // The deopting node should have an outgoing control dependency.
- DCHECK(environment()->GetControlDependency() == node);
-
- StructuredGraphBuilder::Environment* continuation_env = environment();
- // Create environment for the deoptimization block, and build the block.
- StructuredGraphBuilder::Environment* deopt_env =
- CopyEnvironment(continuation_env);
- set_environment(deopt_env);
-
- NewNode(common()->LazyDeoptimization());
-
- // TODO(jarin) If ast_id.IsNone(), perhaps we should generate an empty
- // deopt block and make sure there is no patch entry for this (so
- // that the deoptimizer dies when trying to deoptimize here).
-
- Node* state_node = environment()->Checkpoint(ast_id);
-
- Node* deoptimize_node = NewNode(common()->Deoptimize(), state_node);
-
- UpdateControlDependencyToLeaveFunction(deoptimize_node);
-
- // Continue with the original environment.
- set_environment(continuation_env);
-
- NewNode(common()->Continuation());
+void AstGraphBuilder::PrepareFrameState(Node* node, BailoutId ast_id,
+ OutputFrameStateCombine combine) {
+ if (OperatorProperties::HasFrameStateInput(node->op())) {
+ DCHECK(NodeProperties::GetFrameStateInput(node)->opcode() ==
+ IrOpcode::kDead);
+ NodeProperties::ReplaceFrameStateInput(
+ node, environment()->Checkpoint(ast_id, combine));
}
}
-
-void AstGraphBuilder::BuildLazyBailoutWithPushedNode(Node* node,
- BailoutId ast_id) {
- environment()->Push(node);
- BuildLazyBailout(node, ast_id);
- environment()->Pop();
-}
}
}
} // namespace v8::internal::compiler