Update V8 to version 4.1.0.21
This is a cherry-pick of all commits up to and including the
4.1.0.21 cherry-pick in Chromium.
Original commit message:
Version 4.1.0.21 (cherry-pick)
Merged 206e9136bde0f2b5ae8cb77afbb1e7833e5bd412
Unlink pages from the space page list after evacuation.
BUG=430201
LOG=N
R=jkummerow@chromium.org
Review URL: https://codereview.chromium.org/953813002
Cr-Commit-Position: refs/branch-heads/4.1@{#22}
Cr-Branched-From: 2e08d2a7aa9d65d269d8c57aba82eb38a8cb0a18-refs/heads/candidates@{#25353}
---
FPIIM-449
Change-Id: I8c23c7bbb70772b4858fe8a47b64fa97ee0d1f8c
diff --git a/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc
index 74fb0ae..cde5e71 100644
--- a/src/compiler/ast-graph-builder.cc
+++ b/src/compiler/ast-graph-builder.cc
@@ -5,10 +5,12 @@
#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"
@@ -17,14 +19,16 @@
namespace internal {
namespace compiler {
-AstGraphBuilder::AstGraphBuilder(CompilationInfo* info, JSGraph* jsgraph)
- : StructuredGraphBuilder(jsgraph->graph(), jsgraph->common()),
+AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info,
+ JSGraph* jsgraph, LoopAssignmentAnalysis* loop)
+ : 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_(loop) {
+ InitializeAstVisitor(local_zone);
}
@@ -62,20 +66,29 @@
Environment env(this, scope, graph()->start());
set_environment(&env);
+ // Initialize the incoming context.
+ Node* outer_context = GetFunctionContext();
+ set_current_context(outer_context);
+
+ // Build receiver check for sloppy mode if necessary.
+ // TODO(mstarzinger/verwaest): Should this be moved back into the CallIC?
+ Node* original_receiver = env.Lookup(scope->receiver());
+ Node* patched_receiver = BuildPatchReceiverToGlobalProxy(original_receiver);
+ env.Bind(scope->receiver(), patched_receiver);
+
// Build node to initialize local function context.
Node* closure = GetFunctionClosure();
- Node* outer = GetFunctionContext();
- Node* inner = BuildLocalFunctionContext(outer, closure);
+ Node* inner_context = BuildLocalFunctionContext(outer_context, closure);
// Push top-level function scope for the function body.
- ContextScope top_context(this, scope, inner);
+ ContextScope top_context(this, scope, inner_context);
// Build the arguments object if it is used.
BuildArgumentsObject(scope->arguments());
// 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.
@@ -86,8 +99,8 @@
// 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.
@@ -98,7 +111,7 @@
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.
@@ -129,26 +142,6 @@
}
-// Helper to find an existing shared function info in the baseline code for the
-// given function literal. Used to canonicalize SharedFunctionInfo objects.
-static Handle<SharedFunctionInfo> SearchSharedFunctionInfo(
- Code* unoptimized_code, FunctionLiteral* expr) {
- int start_position = expr->start_position();
- for (RelocIterator it(unoptimized_code); !it.done(); it.next()) {
- RelocInfo* rinfo = it.rinfo();
- if (rinfo->rmode() != RelocInfo::EMBEDDED_OBJECT) continue;
- Object* obj = rinfo->target_object();
- if (obj->IsSharedFunctionInfo()) {
- SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
- if (shared->start_position() == start_position) {
- return Handle<SharedFunctionInfo>(shared);
- }
- }
- }
- return Handle<SharedFunctionInfo>();
-}
-
-
StructuredGraphBuilder::Environment* AstGraphBuilder::CopyEnvironment(
StructuredGraphBuilder::Environment* env) {
return new (zone()) Environment(*reinterpret_cast<Environment*>(env));
@@ -329,24 +322,40 @@
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());
}
}
@@ -360,8 +369,8 @@
Handle<Oddball> value = variable->binding_needs_init()
? isolate()->factory()->the_hole_value()
: isolate()->factory()->undefined_value();
- globals()->Add(variable->name(), zone());
- globals()->Add(value, zone());
+ globals()->push_back(variable->name());
+ globals()->push_back(value);
break;
}
case Variable::PARAMETER:
@@ -392,8 +401,8 @@
Compiler::BuildFunctionInfo(decl->fun(), info()->script(), info());
// Check for stack-overflow exception.
if (function.is_null()) return SetStackOverflow();
- globals()->Add(variable->name(), zone());
- globals()->Add(function, zone());
+ globals()->push_back(variable->name());
+ globals()->push_back(function);
break;
}
case Variable::PARAMETER:
@@ -580,7 +589,7 @@
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());
@@ -592,7 +601,7 @@
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);
@@ -605,11 +614,13 @@
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();
@@ -639,24 +650,27 @@
// 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.
@@ -676,7 +690,7 @@
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 =
@@ -692,8 +706,8 @@
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);
@@ -719,7 +733,7 @@
// 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,
@@ -785,7 +799,7 @@
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());
}
@@ -795,8 +809,8 @@
// Build a new shared function info if we cannot find one in the baseline
// code. We also have a stack overflow if the recursive compilation did.
- Handle<SharedFunctionInfo> shared_info =
- SearchSharedFunctionInfo(info()->shared_info()->code(), expr);
+ expr->InitializeSharedInfo(handle(info()->shared_info()->code()));
+ Handle<SharedFunctionInfo> shared_info = expr->shared_info();
if (shared_info.is_null()) {
shared_info = Compiler::BuildFunctionInfo(expr, info()->script(), info());
CHECK(!shared_info.is_null()); // TODO(mstarzinger): Set stack overflow?
@@ -804,16 +818,14 @@
// 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();
}
@@ -838,7 +850,8 @@
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);
}
@@ -859,8 +872,9 @@
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);
}
@@ -875,8 +889,11 @@
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.
@@ -924,7 +941,8 @@
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;
@@ -935,8 +953,12 @@
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;
}
@@ -961,14 +983,16 @@
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);
}
@@ -986,7 +1010,8 @@
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
@@ -1086,23 +1111,31 @@
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;
}
}
@@ -1111,7 +1144,8 @@
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());
@@ -1122,8 +1156,8 @@
switch (assign_type) {
case VARIABLE: {
Variable* variable = expr->target()->AsVariableProxy()->var();
- BuildVariableAssignment(variable, value, expr->op(),
- expr->AssignmentId());
+ BuildVariableAssignment(variable, value, expr->op(), expr->AssignmentId(),
+ ast_context()->GetStateCombine());
break;
}
case NAMED_PROPERTY: {
@@ -1132,7 +1166,8 @@
MakeUnique(property->key()->AsLiteral()->AsPropertyName());
Node* store =
NewNode(javascript()->StoreNamed(strict_mode(), name), object, value);
- PrepareFrameState(store, expr->AssignmentId());
+ PrepareFrameState(store, expr->AssignmentId(),
+ ast_context()->GetStateCombine());
break;
}
case KEYED_PROPERTY: {
@@ -1140,7 +1175,8 @@
Node* object = environment()->Pop();
Node* store = NewNode(javascript()->StoreProperty(strict_mode()), object,
key, value);
- PrepareFrameState(store, expr->AssignmentId());
+ PrepareFrameState(store, expr->AssignmentId(),
+ ast_context()->GetStateCombine());
break;
}
}
@@ -1162,25 +1198,27 @@
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);
@@ -1199,8 +1237,10 @@
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;
}
@@ -1208,26 +1248,33 @@
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,
@@ -1235,6 +1282,11 @@
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.
@@ -1270,9 +1322,11 @@
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);
@@ -1282,7 +1336,7 @@
}
// 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);
@@ -1297,7 +1351,7 @@
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);
@@ -1312,10 +1366,13 @@
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);
@@ -1324,7 +1381,7 @@
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);
@@ -1347,7 +1404,7 @@
// 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);
@@ -1386,8 +1443,10 @@
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;
}
@@ -1396,8 +1455,11 @@
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;
}
@@ -1406,8 +1468,11 @@
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;
}
@@ -1548,20 +1613,21 @@
void AstGraphBuilder::VisitDeclarations(ZoneList<Declaration*>* declarations) {
- DCHECK(globals()->is_empty());
+ DCHECK(globals()->empty());
AstVisitor::VisitDeclarations(declarations);
- if (globals()->is_empty()) return;
- Handle<FixedArray> data =
- isolate()->factory()->NewFixedArray(globals()->length(), TENURED);
- for (int i = 0; i < globals()->length(); ++i) data->set(i, *globals()->at(i));
+ if (globals()->empty()) return;
+ int array_index = 0;
+ Handle<FixedArray> data = isolate()->factory()->NewFixedArray(
+ static_cast<int>(globals()->size()), TENURED);
+ for (Handle<Object> obj : *globals()) data->set(array_index++, *obj);
int encoded_flags = DeclareGlobalsEvalFlag::encode(info()->is_eval()) |
DeclareGlobalsNativeFlag::encode(info()->is_native()) |
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);
+ globals()->clear();
}
@@ -1585,7 +1651,8 @@
// 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());
@@ -1593,6 +1660,7 @@
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();
@@ -1613,9 +1681,10 @@
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();
@@ -1666,6 +1735,17 @@
}
+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);
@@ -1677,10 +1757,36 @@
}
+Node* AstGraphBuilder::BuildPatchReceiverToGlobalProxy(Node* receiver) {
+ // Sloppy mode functions and builtins need to replace the receiver with the
+ // global proxy when called as functions (without an explicit receiver
+ // object). Otherwise there is nothing left to do here.
+ if (info()->strict_mode() != SLOPPY || info()->is_native()) return receiver;
+
+ // There is no need to perform patching if the receiver is never used. Note
+ // that scope predicates are purely syntactical, a call to eval might still
+ // inspect the receiver value.
+ if (!info()->scope()->uses_this() && !info()->scope()->inner_uses_this() &&
+ !info()->scope()->calls_sloppy_eval()) {
+ return receiver;
+ }
+
+ IfBuilder receiver_check(this);
+ Node* undefined = jsgraph()->UndefinedConstant();
+ Node* check = NewNode(javascript()->StrictEqual(), receiver, undefined);
+ receiver_check.If(check);
+ receiver_check.Then();
+ environment()->Push(BuildLoadGlobalProxy());
+ receiver_check.Else();
+ environment()->Push(receiver);
+ receiver_check.End();
+ return environment()->Pop();
+}
+
+
Node* AstGraphBuilder::BuildLocalFunctionContext(Node* context, Node* closure) {
int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
if (heap_slots <= 0) return context;
- set_current_context(context);
// Allocate a new local context.
const Operator* op = javascript()->CreateFunctionContext();
@@ -1710,7 +1816,7 @@
// 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.
@@ -1738,13 +1844,14 @@
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();
@@ -1754,6 +1861,7 @@
Node* AstGraphBuilder::BuildVariableLoad(Variable* variable,
BailoutId bailout_id,
+ const VectorSlotPair& feedback,
ContextualMode contextual_mode) {
Node* the_hole = jsgraph()->TheHoleConstant();
VariableMode mode = variable->mode();
@@ -1762,9 +1870,10 @@
// 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:
@@ -1782,9 +1891,9 @@
} 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;
@@ -1805,7 +1914,7 @@
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;
}
@@ -1816,8 +1925,9 @@
(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);
}
}
@@ -1826,26 +1936,32 @@
}
-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();
@@ -1853,9 +1969,9 @@
}
-Node* AstGraphBuilder::BuildVariableAssignment(Variable* variable, Node* value,
- Token::Value op,
- BailoutId bailout_id) {
+Node* AstGraphBuilder::BuildVariableAssignment(
+ Variable* variable, Node* value, Token::Value op, BailoutId bailout_id,
+ OutputFrameStateCombine combine) {
Node* the_hole = jsgraph()->TheHoleConstant();
VariableMode mode = variable->mode();
switch (variable->location()) {
@@ -1865,7 +1981,7 @@
Unique<Name> name = MakeUnique(variable->name());
const Operator* op = javascript()->StoreNamed(strict_mode(), name);
Node* store = NewNode(op, global, value);
- PrepareFrameState(store, bailout_id);
+ PrepareFrameState(store, bailout_id, combine);
return store;
}
case Variable::PARAMETER:
@@ -1878,7 +1994,12 @@
value = BuildHoleCheckSilent(current, value, current);
}
} else if (mode == CONST_LEGACY && op != Token::INIT_CONST_LEGACY) {
- // Non-initializing assignments to legacy const is ignored.
+ // Non-initializing assignments to legacy const is
+ // - exception in strict mode.
+ // - ignored in sloppy mode.
+ if (strict_mode() == STRICT) {
+ return BuildThrowConstAssignError(bailout_id);
+ }
return value;
} else if (mode == LET && op != Token::INIT_LET) {
// Perform an initialization check for let declared variables.
@@ -1887,13 +2008,13 @@
// 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.
- UNREACHABLE();
+ // Non-initializing assignments to const is exception in all modes.
+ return BuildThrowConstAssignError(bailout_id);
}
environment()->Bind(variable, value);
return value;
@@ -1907,17 +2028,22 @@
Node* current = NewNode(op, current_context());
value = BuildHoleCheckSilent(current, value, current);
} else if (mode == CONST_LEGACY && op != Token::INIT_CONST_LEGACY) {
- // Non-initializing assignments to legacy const is ignored.
+ // Non-initializing assignments to legacy const is
+ // - exception in strict mode.
+ // - ignored in sloppy mode.
+ if (strict_mode() == STRICT) {
+ return BuildThrowConstAssignError(bailout_id);
+ }
return value;
} else if (mode == LET && op != Token::INIT_LET) {
// Perform an initialization check for let declared variables.
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();
+ // Non-initializing assignments to const is exception in all modes.
+ return BuildThrowConstAssignError(bailout_id);
}
const Operator* op = javascript()->StoreContext(depth, variable->index());
return NewNode(op, current_context(), value);
@@ -1928,8 +2054,11 @@
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, combine);
+ return store;
}
}
UNREACHABLE();
@@ -1938,7 +2067,6 @@
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;
@@ -1961,17 +2089,61 @@
}
-Node* AstGraphBuilder::BuildToBoolean(Node* value) {
- // TODO(mstarzinger): Possible optimization is to NOP for boolean values.
- return NewNode(javascript()->ToBoolean(), value);
+Node* AstGraphBuilder::BuildLoadGlobalProxy() {
+ Node* global = BuildLoadGlobalObject();
+ Node* proxy =
+ BuildLoadObjectField(global, JSGlobalObject::kGlobalProxyOffset);
+ return proxy;
}
-Node* AstGraphBuilder::BuildThrowReferenceError(Variable* variable) {
+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,
+ 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::BuildThrowConstAssignError(BailoutId bailout_id) {
+ // TODO(mstarzinger): Should be unified with the VisitThrow implementation.
+ const Operator* op =
+ javascript()->CallRuntime(Runtime::kThrowConstAssignError, 0);
+ Node* call = NewNode(op);
+ PrepareFrameState(call, bailout_id);
+ return call;
}
@@ -2019,6 +2191,24 @@
}
+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())) {
@@ -2029,6 +2219,13 @@
}
}
+
+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