Enable optimization of top-level code and generate deoptimization support lazily.
This change enables optimization of top-level and eval-code. For this to work, it adds support for declaring global variables in optimized code. At the same time it disables the eager generation of deoptimization support data in the full code generator (originally introduced in r10040). This speeds up initial compilation and saves memory for functions that won't be optimized. It requires recompiling the function with deoptimization support when we decide to optimize it. Review URL: https://chromiumcodereview.appspot.com/9187005 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10700 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
4233bf8348
commit
0be449d684
@ -123,10 +123,8 @@ class JumpPatchSite BASE_EMBEDDED {
|
||||
//
|
||||
// The function builds a JS frame. Please see JavaScriptFrameConstants in
|
||||
// frames-arm.h for its layout.
|
||||
void FullCodeGenerator::Generate(CompilationInfo* info) {
|
||||
ASSERT(info_ == NULL);
|
||||
info_ = info;
|
||||
scope_ = info->scope();
|
||||
void FullCodeGenerator::Generate() {
|
||||
CompilationInfo* info = info_;
|
||||
handler_table_ =
|
||||
isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
|
||||
SetFunctionPosition(function());
|
||||
|
@ -1125,6 +1125,11 @@ LInstruction* LChunkBuilder::DoOuterContext(HOuterContext* instr) {
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) {
|
||||
return MarkAsCall(new LDeclareGlobals, instr);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
|
||||
LOperand* context = UseRegisterAtStart(instr->value());
|
||||
return DefineAsRegister(new LGlobalObject(context));
|
||||
|
@ -87,6 +87,7 @@ class LCodeGen;
|
||||
V(ConstantI) \
|
||||
V(ConstantT) \
|
||||
V(Context) \
|
||||
V(DeclareGlobals) \
|
||||
V(DeleteProperty) \
|
||||
V(Deoptimize) \
|
||||
V(DivI) \
|
||||
@ -1346,6 +1347,13 @@ class LOuterContext: public LTemplateInstruction<1, 1, 0> {
|
||||
};
|
||||
|
||||
|
||||
class LDeclareGlobals: public LTemplateInstruction<0, 0, 0> {
|
||||
public:
|
||||
DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals, "declare-globals")
|
||||
DECLARE_HYDROGEN_ACCESSOR(DeclareGlobals)
|
||||
};
|
||||
|
||||
|
||||
class LGlobalObject: public LTemplateInstruction<1, 1, 0> {
|
||||
public:
|
||||
explicit LGlobalObject(LOperand* context) {
|
||||
|
@ -2873,6 +2873,16 @@ void LCodeGen::DoOuterContext(LOuterContext* instr) {
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
|
||||
__ push(cp); // The context is the first argument.
|
||||
__ LoadHeapObject(scratch0(), instr->hydrogen()->pairs());
|
||||
__ push(scratch0());
|
||||
__ mov(scratch0(), Operand(Smi::FromInt(instr->hydrogen()->flags())));
|
||||
__ push(scratch0());
|
||||
CallRuntime(Runtime::kDeclareGlobals, 3, instr);
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
|
||||
Register result = ToRegister(instr->result());
|
||||
__ ldr(result, ContextOperand(cp, Context::GLOBAL_INDEX));
|
||||
|
33
src/ast.h
33
src/ast.h
@ -223,8 +223,6 @@ class AstNode: public ZoneObject {
|
||||
virtual IterationStatement* AsIterationStatement() { return NULL; }
|
||||
virtual MaterializedLiteral* AsMaterializedLiteral() { return NULL; }
|
||||
|
||||
static void ResetIds() { Isolate::Current()->set_ast_node_id(0); }
|
||||
|
||||
protected:
|
||||
static int GetNextId(Isolate* isolate) {
|
||||
return ReserveIdRange(isolate, 1);
|
||||
@ -1905,6 +1903,16 @@ class FunctionLiteral: public Expression {
|
||||
DECLARATION
|
||||
};
|
||||
|
||||
enum ParameterFlag {
|
||||
kNoDuplicateParameters = 0,
|
||||
kHasDuplicateParameters = 1
|
||||
};
|
||||
|
||||
enum IsFunctionFlag {
|
||||
kGlobalOrEval,
|
||||
kIsFunction
|
||||
};
|
||||
|
||||
DECLARE_NODE_TYPE(FunctionLiteral)
|
||||
|
||||
Handle<String> name() const { return name_; }
|
||||
@ -1914,6 +1922,7 @@ class FunctionLiteral: public Expression {
|
||||
int function_token_position() const { return function_token_position_; }
|
||||
int start_position() const;
|
||||
int end_position() const;
|
||||
int SourceSize() const { return end_position() - start_position(); }
|
||||
bool is_expression() const { return IsExpression::decode(bitfield_); }
|
||||
bool is_anonymous() const { return IsAnonymous::decode(bitfield_); }
|
||||
bool is_classic_mode() const { return language_mode() == CLASSIC_MODE; }
|
||||
@ -1949,6 +1958,8 @@ class FunctionLiteral: public Expression {
|
||||
return HasDuplicateParameters::decode(bitfield_);
|
||||
}
|
||||
|
||||
bool is_function() { return IsFunction::decode(bitfield_) == kIsFunction; }
|
||||
|
||||
int ast_node_count() { return ast_properties_.node_count(); }
|
||||
AstProperties::Flags* flags() { return ast_properties_.flags(); }
|
||||
void set_ast_properties(AstProperties* ast_properties) {
|
||||
@ -1969,7 +1980,8 @@ class FunctionLiteral: public Expression {
|
||||
Handle<FixedArray> this_property_assignments,
|
||||
int parameter_count,
|
||||
Type type,
|
||||
bool has_duplicate_parameters)
|
||||
ParameterFlag has_duplicate_parameters,
|
||||
IsFunctionFlag is_function)
|
||||
: Expression(isolate),
|
||||
name_(name),
|
||||
scope_(scope),
|
||||
@ -1987,7 +1999,8 @@ class FunctionLiteral: public Expression {
|
||||
IsExpression::encode(type != DECLARATION) |
|
||||
IsAnonymous::encode(type == ANONYMOUS_EXPRESSION) |
|
||||
Pretenure::encode(false) |
|
||||
HasDuplicateParameters::encode(has_duplicate_parameters);
|
||||
HasDuplicateParameters::encode(has_duplicate_parameters) |
|
||||
IsFunction::encode(is_function);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -2009,7 +2022,8 @@ class FunctionLiteral: public Expression {
|
||||
class IsExpression: public BitField<bool, 1, 1> {};
|
||||
class IsAnonymous: public BitField<bool, 2, 1> {};
|
||||
class Pretenure: public BitField<bool, 3, 1> {};
|
||||
class HasDuplicateParameters: public BitField<bool, 4, 1> {};
|
||||
class HasDuplicateParameters: public BitField<ParameterFlag, 4, 1> {};
|
||||
class IsFunction: public BitField<IsFunctionFlag, 5, 1> {};
|
||||
};
|
||||
|
||||
|
||||
@ -2778,15 +2792,16 @@ class AstNodeFactory BASE_EMBEDDED {
|
||||
bool has_only_simple_this_property_assignments,
|
||||
Handle<FixedArray> this_property_assignments,
|
||||
int parameter_count,
|
||||
bool has_duplicate_parameters,
|
||||
FunctionLiteral::ParameterFlag has_duplicate_parameters,
|
||||
FunctionLiteral::Type type,
|
||||
bool visit_with_visitor) {
|
||||
FunctionLiteral::IsFunctionFlag is_function) {
|
||||
FunctionLiteral* lit = new(zone_) FunctionLiteral(
|
||||
isolate_, name, scope, body,
|
||||
materialized_literal_count, expected_property_count, handler_count,
|
||||
has_only_simple_this_property_assignments, this_property_assignments,
|
||||
parameter_count, type, has_duplicate_parameters);
|
||||
if (visit_with_visitor) {
|
||||
parameter_count, type, has_duplicate_parameters, is_function);
|
||||
// Top-level literal doesn't count for the AST's properties.
|
||||
if (is_function == FunctionLiteral::kIsFunction) {
|
||||
visitor_.VisitFunctionLiteral(lit);
|
||||
}
|
||||
return lit;
|
||||
|
@ -61,7 +61,7 @@ CompilationInfo::CompilationInfo(Handle<Script> script)
|
||||
extension_(NULL),
|
||||
pre_parse_data_(NULL),
|
||||
osr_ast_id_(AstNode::kNoNumber) {
|
||||
Initialize(NONOPT);
|
||||
Initialize(BASE);
|
||||
}
|
||||
|
||||
|
||||
@ -182,10 +182,8 @@ static void FinishOptimization(Handle<JSFunction> function, int64_t start) {
|
||||
static bool MakeCrankshaftCode(CompilationInfo* info) {
|
||||
// Test if we can optimize this function when asked to. We can only
|
||||
// do this after the scopes are computed.
|
||||
if (!info->AllowOptimize()) {
|
||||
if (!V8::UseCrankshaft()) {
|
||||
info->DisableOptimization();
|
||||
} else if (info->IsOptimizable()) {
|
||||
info->EnableDeoptimizationSupport();
|
||||
}
|
||||
|
||||
// In case we are not optimizing simply return the code from
|
||||
@ -218,7 +216,7 @@ static bool MakeCrankshaftCode(CompilationInfo* info) {
|
||||
if (info->shared_info()->opt_count() > kMaxOptCount) {
|
||||
info->AbortOptimization();
|
||||
Handle<JSFunction> closure = info->closure();
|
||||
info->shared_info()->DisableOptimization(*closure);
|
||||
info->shared_info()->DisableOptimization();
|
||||
// True indicates the compilation pipeline is still going, not
|
||||
// necessarily that we optimized the code.
|
||||
return true;
|
||||
@ -239,7 +237,7 @@ static bool MakeCrankshaftCode(CompilationInfo* info) {
|
||||
scope->num_parameters() + 1 + scope->num_stack_slots() > locals_limit)) {
|
||||
info->AbortOptimization();
|
||||
Handle<JSFunction> closure = info->closure();
|
||||
info->shared_info()->DisableOptimization(*closure);
|
||||
info->shared_info()->DisableOptimization();
|
||||
// True indicates the compilation pipeline is still going, not
|
||||
// necessarily that we optimized the code.
|
||||
return true;
|
||||
@ -318,7 +316,7 @@ static bool MakeCrankshaftCode(CompilationInfo* info) {
|
||||
// Mark the shared code as unoptimizable unless it was an inlined
|
||||
// function that bailed out.
|
||||
Handle<JSFunction> closure = info->closure();
|
||||
info->shared_info()->DisableOptimization(*closure);
|
||||
info->shared_info()->DisableOptimization();
|
||||
}
|
||||
// True indicates the compilation pipeline is still going, not necessarily
|
||||
// that we optimized the code.
|
||||
@ -573,6 +571,10 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
|
||||
info.SetCallingContext(context);
|
||||
result = MakeFunctionInfo(&info);
|
||||
if (!result.is_null()) {
|
||||
// Explicitly disable optimization for eval code. We're not yet prepared
|
||||
// to handle eval-code in the optimizing compiler.
|
||||
result->DisableOptimization();
|
||||
|
||||
// If caller is strict mode, the result must be in strict mode or
|
||||
// extended mode as well, but not the other way around. Consider:
|
||||
// eval("'use strict'; ...");
|
||||
@ -664,11 +666,13 @@ bool Compiler::CompileLazy(CompilationInfo* info) {
|
||||
// Check the function has compiled code.
|
||||
ASSERT(shared->is_compiled());
|
||||
shared->set_code_age(0);
|
||||
shared->set_dont_crankshaft(lit->flags()->Contains(kDontOptimize));
|
||||
shared->set_dont_optimize(lit->flags()->Contains(kDontOptimize));
|
||||
shared->set_dont_inline(lit->flags()->Contains(kDontInline));
|
||||
shared->set_ast_node_count(lit->ast_node_count());
|
||||
|
||||
if (info->AllowOptimize() && !shared->optimization_disabled()) {
|
||||
if (V8::UseCrankshaft()&&
|
||||
!function.is_null() &&
|
||||
!shared->optimization_disabled()) {
|
||||
// If we're asked to always optimize, we compile the optimized
|
||||
// version of the function right away - unless the debugger is
|
||||
// active as it makes no sense to compile optimized code then.
|
||||
@ -766,7 +770,8 @@ void Compiler::SetFunctionInfo(Handle<SharedFunctionInfo> function_info,
|
||||
function_info->set_uses_arguments(lit->scope()->arguments() != NULL);
|
||||
function_info->set_has_duplicate_parameters(lit->has_duplicate_parameters());
|
||||
function_info->set_ast_node_count(lit->ast_node_count());
|
||||
function_info->set_dont_crankshaft(lit->flags()->Contains(kDontOptimize));
|
||||
function_info->set_is_function(lit->is_function());
|
||||
function_info->set_dont_optimize(lit->flags()->Contains(kDontOptimize));
|
||||
function_info->set_dont_inline(lit->flags()->Contains(kDontInline));
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2011 the V8 project authors. All rights reserved.
|
||||
// Copyright 2012 the V8 project authors. All rights reserved.
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
@ -163,11 +163,6 @@ class CompilationInfo BASE_EMBEDDED {
|
||||
flags_ |= SupportsDeoptimization::encode(true);
|
||||
}
|
||||
|
||||
// Determine whether or not we can adaptively optimize.
|
||||
bool AllowOptimize() {
|
||||
return V8::UseCrankshaft() && !closure_.is_null();
|
||||
}
|
||||
|
||||
// Determines whether or not to insert a self-optimization header.
|
||||
bool ShouldSelfOptimize();
|
||||
|
||||
@ -181,9 +176,8 @@ class CompilationInfo BASE_EMBEDDED {
|
||||
// Compilation mode.
|
||||
// BASE is generated by the full codegen, optionally prepared for bailouts.
|
||||
// OPTIMIZE is optimized code generated by the Hydrogen-based backend.
|
||||
// NONOPT is generated by the full codegen or the classic backend
|
||||
// and is not prepared for recompilation/bailouts. These functions
|
||||
// are never recompiled.
|
||||
// NONOPT is generated by the full codegen and is not prepared for
|
||||
// recompilation/bailouts. These functions are never recompiled.
|
||||
enum Mode {
|
||||
BASE,
|
||||
OPTIMIZE,
|
||||
|
@ -291,8 +291,8 @@ bool FullCodeGenerator::MakeCode(CompilationInfo* info) {
|
||||
masm.positions_recorder()->StartGDBJITLineInfoRecording();
|
||||
#endif
|
||||
|
||||
FullCodeGenerator cgen(&masm);
|
||||
cgen.Generate(info);
|
||||
FullCodeGenerator cgen(&masm, info);
|
||||
cgen.Generate();
|
||||
if (cgen.HasStackOverflow()) {
|
||||
ASSERT(!isolate->has_pending_exception());
|
||||
return false;
|
||||
@ -404,6 +404,7 @@ void FullCodeGenerator::PrepareForBailoutForId(unsigned id, State state) {
|
||||
if (!info_->HasDeoptimizationSupport()) return;
|
||||
unsigned pc_and_state =
|
||||
StateField::encode(state) | PcField::encode(masm_->pc_offset());
|
||||
ASSERT(Smi::IsValid(pc_and_state));
|
||||
BailoutEntry entry = { id, pc_and_state };
|
||||
#ifdef DEBUG
|
||||
if (FLAG_enable_slow_asserts) {
|
||||
|
@ -77,29 +77,32 @@ class FullCodeGenerator: public AstVisitor {
|
||||
TOS_REG
|
||||
};
|
||||
|
||||
explicit FullCodeGenerator(MacroAssembler* masm)
|
||||
FullCodeGenerator(MacroAssembler* masm, CompilationInfo* info)
|
||||
: masm_(masm),
|
||||
info_(NULL),
|
||||
scope_(NULL),
|
||||
info_(info),
|
||||
scope_(info->scope()),
|
||||
nesting_stack_(NULL),
|
||||
loop_depth_(0),
|
||||
global_count_(0),
|
||||
context_(NULL),
|
||||
bailout_entries_(0),
|
||||
bailout_entries_(info->HasDeoptimizationSupport()
|
||||
? info->function()->ast_node_count() : 0),
|
||||
stack_checks_(2), // There's always at least one.
|
||||
type_feedback_cells_(0) {
|
||||
}
|
||||
type_feedback_cells_(info->HasDeoptimizationSupport()
|
||||
? info->function()->ast_node_count() : 0) { }
|
||||
|
||||
static bool MakeCode(CompilationInfo* info);
|
||||
|
||||
void Generate(CompilationInfo* info);
|
||||
void Generate();
|
||||
void PopulateDeoptimizationData(Handle<Code> code);
|
||||
void PopulateTypeFeedbackCells(Handle<Code> code);
|
||||
|
||||
Handle<FixedArray> handler_table() { return handler_table_; }
|
||||
|
||||
class StateField : public BitField<State, 0, 8> { };
|
||||
class PcField : public BitField<unsigned, 8, 32-8> { };
|
||||
// Encode state and pc-offset as a BitField<type, start, size>.
|
||||
// Only use 30 bits because we encode the result as a smi.
|
||||
class StateField : public BitField<State, 0, 1> { };
|
||||
class PcField : public BitField<unsigned, 1, 30-1> { };
|
||||
|
||||
static const char* State2String(State state) {
|
||||
switch (state) {
|
||||
|
@ -97,6 +97,7 @@ class LChunkBuilder;
|
||||
V(CompareConstantEqAndBranch) \
|
||||
V(Constant) \
|
||||
V(Context) \
|
||||
V(DeclareGlobals) \
|
||||
V(DeleteProperty) \
|
||||
V(Deoptimize) \
|
||||
V(Div) \
|
||||
@ -1486,6 +1487,33 @@ class HOuterContext: public HUnaryOperation {
|
||||
};
|
||||
|
||||
|
||||
class HDeclareGlobals: public HUnaryOperation {
|
||||
public:
|
||||
HDeclareGlobals(HValue* context,
|
||||
Handle<FixedArray> pairs,
|
||||
int flags)
|
||||
: HUnaryOperation(context),
|
||||
pairs_(pairs),
|
||||
flags_(flags) {
|
||||
set_representation(Representation::Tagged());
|
||||
SetAllSideEffects();
|
||||
}
|
||||
|
||||
HValue* context() { return OperandAt(0); }
|
||||
Handle<FixedArray> pairs() const { return pairs_; }
|
||||
int flags() const { return flags_; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals)
|
||||
|
||||
virtual Representation RequiredInputRepresentation(int index) {
|
||||
return Representation::Tagged();
|
||||
}
|
||||
private:
|
||||
Handle<FixedArray> pairs_;
|
||||
int flags_;
|
||||
};
|
||||
|
||||
|
||||
class HGlobalObject: public HUnaryOperation {
|
||||
public:
|
||||
explicit HGlobalObject(HValue* context) : HUnaryOperation(context) {
|
||||
|
@ -2443,7 +2443,7 @@ HGraph* HGraphBuilder::CreateGraph() {
|
||||
// Handle implicit declaration of the function name in named function
|
||||
// expressions before other declarations.
|
||||
if (scope->is_function_scope() && scope->function() != NULL) {
|
||||
HandleVariableDeclaration(scope->function(), CONST, NULL);
|
||||
HandleVariableDeclaration(scope->function(), CONST, NULL, NULL);
|
||||
}
|
||||
VisitDeclarations(scope->declarations());
|
||||
AddSimulate(AstNode::kDeclarationsId);
|
||||
@ -4917,7 +4917,7 @@ bool HGraphBuilder::TryInline(Call* expr, bool drop_extra) {
|
||||
TraceInline(target, caller, "target not inlineable");
|
||||
return false;
|
||||
}
|
||||
if (target_shared->dont_inline() || target_shared->dont_crankshaft()) {
|
||||
if (target_shared->dont_inline() || target_shared->dont_optimize()) {
|
||||
TraceInline(target, caller, "target contains unsupported syntax [early]");
|
||||
return false;
|
||||
}
|
||||
@ -4979,7 +4979,7 @@ bool HGraphBuilder::TryInline(Call* expr, bool drop_extra) {
|
||||
if (target_info.isolate()->has_pending_exception()) {
|
||||
// Parse or scope error, never optimize this function.
|
||||
SetStackOverflow();
|
||||
target_shared->DisableOptimization(*target);
|
||||
target_shared->DisableOptimization();
|
||||
}
|
||||
TraceInline(target, caller, "parse failure");
|
||||
return false;
|
||||
@ -5092,7 +5092,7 @@ bool HGraphBuilder::TryInline(Call* expr, bool drop_extra) {
|
||||
// Bail out if the inline function did, as we cannot residualize a call
|
||||
// instead.
|
||||
TraceInline(target, caller, "inline graph construction failed");
|
||||
target_shared->DisableOptimization(*target);
|
||||
target_shared->DisableOptimization();
|
||||
inline_bailout_ = true;
|
||||
delete target_state;
|
||||
return true;
|
||||
@ -6541,26 +6541,81 @@ void HGraphBuilder::VisitThisFunction(ThisFunction* expr) {
|
||||
|
||||
|
||||
void HGraphBuilder::VisitVariableDeclaration(VariableDeclaration* decl) {
|
||||
HandleVariableDeclaration(decl->proxy(), decl->mode(), decl->fun());
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void HGraphBuilder::VisitDeclarations(ZoneList<Declaration*>* declarations) {
|
||||
int length = declarations->length();
|
||||
int global_count = 0;
|
||||
for (int i = 0; i < declarations->length(); i++) {
|
||||
VariableDeclaration* decl = declarations->at(i)->AsVariableDeclaration();
|
||||
if (decl == NULL) continue;
|
||||
HandleVariableDeclaration(decl->proxy(),
|
||||
decl->mode(),
|
||||
decl->fun(),
|
||||
&global_count);
|
||||
}
|
||||
|
||||
// Batch declare global functions and variables.
|
||||
if (global_count > 0) {
|
||||
Handle<FixedArray> array =
|
||||
isolate()->factory()->NewFixedArray(2 * global_count, TENURED);
|
||||
for (int j = 0, i = 0; i < length; i++) {
|
||||
VariableDeclaration* decl = declarations->at(i)->AsVariableDeclaration();
|
||||
if (decl == NULL) continue;
|
||||
Variable* var = decl->proxy()->var();
|
||||
|
||||
if (var->IsUnallocated()) {
|
||||
array->set(j++, *(var->name()));
|
||||
if (decl->fun() == NULL) {
|
||||
if (var->binding_needs_init()) {
|
||||
// In case this binding needs initialization use the hole.
|
||||
array->set_the_hole(j++);
|
||||
} else {
|
||||
array->set_undefined(j++);
|
||||
}
|
||||
} else {
|
||||
Handle<SharedFunctionInfo> function =
|
||||
Compiler::BuildFunctionInfo(decl->fun(), info()->script());
|
||||
// Check for stack-overflow exception.
|
||||
if (function.is_null()) {
|
||||
SetStackOverflow();
|
||||
return;
|
||||
}
|
||||
array->set(j++, *function);
|
||||
}
|
||||
}
|
||||
}
|
||||
int flags = DeclareGlobalsEvalFlag::encode(info()->is_eval()) |
|
||||
DeclareGlobalsNativeFlag::encode(info()->is_native()) |
|
||||
DeclareGlobalsLanguageMode::encode(info()->language_mode());
|
||||
HInstruction* result =
|
||||
new(zone()) HDeclareGlobals(environment()->LookupContext(),
|
||||
array,
|
||||
flags);
|
||||
AddInstruction(result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::HandleVariableDeclaration(VariableProxy* proxy,
|
||||
VariableMode mode,
|
||||
FunctionLiteral* function) {
|
||||
FunctionLiteral* function,
|
||||
int* global_count) {
|
||||
Variable* var = proxy->var();
|
||||
bool binding_needs_init =
|
||||
(mode == CONST || mode == CONST_HARMONY || mode == LET);
|
||||
switch (var->location()) {
|
||||
case Variable::UNALLOCATED:
|
||||
return Bailout("unsupported global declaration");
|
||||
++(*global_count);
|
||||
return;
|
||||
case Variable::PARAMETER:
|
||||
case Variable::LOCAL:
|
||||
case Variable::CONTEXT:
|
||||
if (binding_needs_init || function != NULL) {
|
||||
HValue* value = NULL;
|
||||
if (function != NULL) {
|
||||
VisitForValue(function);
|
||||
CHECK_ALIVE(VisitForValue(function));
|
||||
value = Pop();
|
||||
} else {
|
||||
value = graph()->GetConstantHole();
|
||||
|
@ -780,6 +780,8 @@ class HGraphBuilder: public AstVisitor {
|
||||
|
||||
FunctionState* function_state() const { return function_state_; }
|
||||
|
||||
void VisitDeclarations(ZoneList<Declaration*>* declarations);
|
||||
|
||||
private:
|
||||
// Type of a member function that generates inline code for a native function.
|
||||
typedef void (HGraphBuilder::*InlineFunctionGenerator)(CallRuntime* call);
|
||||
@ -841,7 +843,8 @@ class HGraphBuilder: public AstVisitor {
|
||||
|
||||
void HandleVariableDeclaration(VariableProxy* proxy,
|
||||
VariableMode mode,
|
||||
FunctionLiteral* function);
|
||||
FunctionLiteral* function,
|
||||
int* global_count);
|
||||
|
||||
void VisitDelete(UnaryOperation* expr);
|
||||
void VisitVoid(UnaryOperation* expr);
|
||||
|
@ -113,10 +113,8 @@ class JumpPatchSite BASE_EMBEDDED {
|
||||
//
|
||||
// The function builds a JS frame. Please see JavaScriptFrameConstants in
|
||||
// frames-ia32.h for its layout.
|
||||
void FullCodeGenerator::Generate(CompilationInfo* info) {
|
||||
ASSERT(info_ == NULL);
|
||||
info_ = info;
|
||||
scope_ = info->scope();
|
||||
void FullCodeGenerator::Generate() {
|
||||
CompilationInfo* info = info_;
|
||||
handler_table_ =
|
||||
isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
|
||||
profiling_counter_ = isolate()->factory()->NewJSGlobalPropertyCell(
|
||||
|
@ -2690,6 +2690,15 @@ void LCodeGen::DoOuterContext(LOuterContext* instr) {
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
|
||||
ASSERT(ToRegister(instr->InputAt(0)).is(esi));
|
||||
__ push(esi); // The context is the first argument.
|
||||
__ push(Immediate(instr->hydrogen()->pairs()));
|
||||
__ push(Immediate(Smi::FromInt(instr->hydrogen()->flags())));
|
||||
CallRuntime(Runtime::kDeclareGlobals, 3, instr);
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
|
||||
Register context = ToRegister(instr->context());
|
||||
Register result = ToRegister(instr->result());
|
||||
|
@ -1150,6 +1150,12 @@ LInstruction* LChunkBuilder::DoOuterContext(HOuterContext* instr) {
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) {
|
||||
LOperand* context = UseFixed(instr->context(), esi);
|
||||
return MarkAsCall(new(zone()) LDeclareGlobals(context), instr);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
|
||||
LOperand* context = UseRegisterAtStart(instr->value());
|
||||
return DefineAsRegister(new(zone()) LGlobalObject(context));
|
||||
|
@ -81,6 +81,7 @@ class LCodeGen;
|
||||
V(ConstantI) \
|
||||
V(ConstantT) \
|
||||
V(Context) \
|
||||
V(DeclareGlobals) \
|
||||
V(DeleteProperty) \
|
||||
V(Deoptimize) \
|
||||
V(DivI) \
|
||||
@ -1385,6 +1386,17 @@ class LOuterContext: public LTemplateInstruction<1, 1, 0> {
|
||||
};
|
||||
|
||||
|
||||
class LDeclareGlobals: public LTemplateInstruction<0, 1, 0> {
|
||||
public:
|
||||
explicit LDeclareGlobals(LOperand* context) {
|
||||
inputs_[0] = context;
|
||||
}
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals, "declare-globals")
|
||||
DECLARE_HYDROGEN_ACCESSOR(DeclareGlobals)
|
||||
};
|
||||
|
||||
|
||||
class LGlobalObject: public LTemplateInstruction<1, 1, 0> {
|
||||
public:
|
||||
explicit LGlobalObject(LOperand* context) {
|
||||
|
@ -3706,8 +3706,9 @@ BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints,
|
||||
kNameShouldPrintAsAnonymous)
|
||||
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, bound, kBoundFunction)
|
||||
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_anonymous, kIsAnonymous)
|
||||
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, dont_crankshaft,
|
||||
kDontCrankshaft)
|
||||
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_function, kIsFunction)
|
||||
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, dont_optimize,
|
||||
kDontOptimize)
|
||||
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, dont_inline, kDontInline)
|
||||
|
||||
ACCESSORS(CodeCache, default_cache, FixedArray, kDefaultCacheOffset)
|
||||
|
@ -7852,7 +7852,7 @@ void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
|
||||
}
|
||||
|
||||
|
||||
void SharedFunctionInfo::DisableOptimization(JSFunction* function) {
|
||||
void SharedFunctionInfo::DisableOptimization() {
|
||||
// Disable optimization for the shared function info and mark the
|
||||
// code as non-optimizable. The marker on the shared function info
|
||||
// is there because we flush non-optimized code thereby loosing the
|
||||
@ -7869,16 +7869,13 @@ void SharedFunctionInfo::DisableOptimization(JSFunction* function) {
|
||||
}
|
||||
if (FLAG_trace_opt) {
|
||||
PrintF("[disabled optimization for: ");
|
||||
function->PrintName();
|
||||
PrintF(" / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
|
||||
DebugName()->ShortPrint();
|
||||
PrintF("]\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool SharedFunctionInfo::VerifyBailoutId(int id) {
|
||||
// TODO(srdjan): debugging ARM crashes in hydrogen. OK to disable while
|
||||
// we are always bailing out on ARM.
|
||||
|
||||
ASSERT(id != AstNode::kNoNumber);
|
||||
Code* unoptimized = code();
|
||||
DeoptimizationOutputData* data =
|
||||
|
@ -5313,8 +5313,11 @@ class SharedFunctionInfo: public HeapObject {
|
||||
// through the API, which does not change this flag).
|
||||
DECL_BOOLEAN_ACCESSORS(is_anonymous)
|
||||
|
||||
// Indicates that the function cannot be crankshafted.
|
||||
DECL_BOOLEAN_ACCESSORS(dont_crankshaft)
|
||||
// Is this a function or top-level/eval code.
|
||||
DECL_BOOLEAN_ACCESSORS(is_function)
|
||||
|
||||
// Indicates that the function cannot be optimized.
|
||||
DECL_BOOLEAN_ACCESSORS(dont_optimize)
|
||||
|
||||
// Indicates that the function cannot be inlined.
|
||||
DECL_BOOLEAN_ACCESSORS(dont_inline)
|
||||
@ -5327,9 +5330,8 @@ class SharedFunctionInfo: public HeapObject {
|
||||
void EnableDeoptimizationSupport(Code* recompiled);
|
||||
|
||||
// Disable (further) attempted optimization of all functions sharing this
|
||||
// shared function info. The function is the one we actually tried to
|
||||
// optimize.
|
||||
void DisableOptimization(JSFunction* function);
|
||||
// shared function info.
|
||||
void DisableOptimization();
|
||||
|
||||
// Lookup the bailout ID and ASSERT that it exists in the non-optimized
|
||||
// code, returns whether it asserted (i.e., always true if assertions are
|
||||
@ -5527,7 +5529,8 @@ class SharedFunctionInfo: public HeapObject {
|
||||
kBoundFunction,
|
||||
kIsAnonymous,
|
||||
kNameShouldPrintAsAnonymous,
|
||||
kDontCrankshaft,
|
||||
kIsFunction,
|
||||
kDontOptimize,
|
||||
kDontInline,
|
||||
kCompilerHintsCount // Pseudo entry
|
||||
};
|
||||
|
@ -503,7 +503,9 @@ Parser::FunctionState::FunctionState(Parser* parser,
|
||||
Parser::FunctionState::~FunctionState() {
|
||||
parser_->top_scope_ = outer_scope_;
|
||||
parser_->current_function_state_ = outer_function_state_;
|
||||
parser_->isolate()->set_ast_node_id(saved_ast_node_id_);
|
||||
if (outer_function_state_ != NULL) {
|
||||
parser_->isolate()->set_ast_node_id(saved_ast_node_id_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -550,7 +552,7 @@ Parser::Parser(Handle<Script> script,
|
||||
allow_modules_((parser_flags & kAllowModules) != 0),
|
||||
stack_overflow_(false),
|
||||
parenthesized_function_(false) {
|
||||
AstNode::ResetIds();
|
||||
isolate_->set_ast_node_id(0);
|
||||
if ((parser_flags & kLanguageModeMask) == EXTENDED_MODE) {
|
||||
scanner().SetHarmonyScoping(true);
|
||||
}
|
||||
@ -602,7 +604,8 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info,
|
||||
FunctionLiteral* result = NULL;
|
||||
{ Scope* scope = NewScope(top_scope_, GLOBAL_SCOPE);
|
||||
info->SetGlobalScope(scope);
|
||||
if (!info->is_global()) {
|
||||
if (!info->is_global() &&
|
||||
(info->shared_info().is_null() || info->shared_info()->is_function())) {
|
||||
scope = Scope::DeserializeScopeChain(*info->calling_context(), scope);
|
||||
scope = NewScope(scope, EVAL_SCOPE);
|
||||
}
|
||||
@ -633,9 +636,9 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info,
|
||||
function_state.only_simple_this_property_assignments(),
|
||||
function_state.this_property_assignments(),
|
||||
0,
|
||||
false, // Does not have duplicate parameters.
|
||||
FunctionLiteral::kNoDuplicateParameters,
|
||||
FunctionLiteral::ANONYMOUS_EXPRESSION,
|
||||
false); // Top-level literal doesn't count for the AST's properties.
|
||||
FunctionLiteral::kGlobalOrEval);
|
||||
result->set_ast_properties(factory()->visitor()->ast_properties());
|
||||
} else if (stack_overflow_) {
|
||||
isolate()->StackOverflow();
|
||||
@ -4015,7 +4018,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
|
||||
int handler_count = 0;
|
||||
bool only_simple_this_property_assignments;
|
||||
Handle<FixedArray> this_property_assignments;
|
||||
bool has_duplicate_parameters = false;
|
||||
FunctionLiteral::ParameterFlag duplicate_parameters =
|
||||
FunctionLiteral::kNoDuplicateParameters;
|
||||
AstProperties ast_properties;
|
||||
// Parse function body.
|
||||
{ FunctionState function_state(this, scope, isolate());
|
||||
@ -4041,7 +4045,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
|
||||
name_loc = scanner().location();
|
||||
}
|
||||
if (!dupe_loc.IsValid() && top_scope_->IsDeclared(param_name)) {
|
||||
has_duplicate_parameters = true;
|
||||
duplicate_parameters = FunctionLiteral::kHasDuplicateParameters;
|
||||
dupe_loc = scanner().location();
|
||||
}
|
||||
if (!reserved_loc.IsValid() && is_strict_reserved) {
|
||||
@ -4252,9 +4256,9 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
|
||||
only_simple_this_property_assignments,
|
||||
this_property_assignments,
|
||||
num_parameters,
|
||||
has_duplicate_parameters,
|
||||
duplicate_parameters,
|
||||
type,
|
||||
true);
|
||||
FunctionLiteral::kIsFunction);
|
||||
function_literal->set_function_token_position(function_token_position);
|
||||
function_literal->set_ast_properties(&ast_properties);
|
||||
|
||||
@ -5594,7 +5598,11 @@ bool ParserApi::Parse(CompilationInfo* info, int parsing_flags) {
|
||||
if (info->is_lazy()) {
|
||||
ASSERT(!info->is_eval());
|
||||
Parser parser(script, parsing_flags, NULL, NULL);
|
||||
result = parser.ParseLazy(info);
|
||||
if (info->shared_info()->is_function()) {
|
||||
result = parser.ParseLazy(info);
|
||||
} else {
|
||||
result = parser.ParseProgram(info);
|
||||
}
|
||||
} else {
|
||||
ScriptDataImpl* pre_data = info->pre_parse_data();
|
||||
Parser parser(script, parsing_flags, info->extension(), pre_data);
|
||||
|
@ -239,6 +239,16 @@ void RuntimeProfiler::OptimizeNow() {
|
||||
// Do not record non-optimizable functions.
|
||||
if (!function->IsOptimizable()) continue;
|
||||
|
||||
// Only record top-level code on top of the execution stack and
|
||||
// avoid optimizing excessively large scripts since top-level code
|
||||
// will be executed only once.
|
||||
const int kMaxToplevelSourceSize = 10 * 1024;
|
||||
if (function->shared()->is_toplevel()
|
||||
&& (frame_count > 1
|
||||
|| function->shared()->SourceSize() > kMaxToplevelSourceSize)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (FLAG_watch_ic_patching) {
|
||||
int ticks = function->shared()->profiler_ticks();
|
||||
|
||||
|
@ -113,10 +113,8 @@ class JumpPatchSite BASE_EMBEDDED {
|
||||
//
|
||||
// The function builds a JS frame. Please see JavaScriptFrameConstants in
|
||||
// frames-x64.h for its layout.
|
||||
void FullCodeGenerator::Generate(CompilationInfo* info) {
|
||||
ASSERT(info_ == NULL);
|
||||
info_ = info;
|
||||
scope_ = info->scope();
|
||||
void FullCodeGenerator::Generate() {
|
||||
CompilationInfo* info = info_;
|
||||
handler_table_ =
|
||||
isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
|
||||
SetFunctionPosition(function());
|
||||
|
@ -2605,6 +2605,14 @@ void LCodeGen::DoOuterContext(LOuterContext* instr) {
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
|
||||
__ push(rsi); // The context is the first argument.
|
||||
__ PushHeapObject(instr->hydrogen()->pairs());
|
||||
__ Push(Smi::FromInt(instr->hydrogen()->flags()));
|
||||
CallRuntime(Runtime::kDeclareGlobals, 3, instr);
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
|
||||
Register result = ToRegister(instr->result());
|
||||
__ movq(result, GlobalObjectOperand());
|
||||
|
@ -1121,6 +1121,11 @@ LInstruction* LChunkBuilder::DoOuterContext(HOuterContext* instr) {
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) {
|
||||
return MarkAsCall(new LDeclareGlobals, instr);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
|
||||
return DefineAsRegister(new LGlobalObject);
|
||||
}
|
||||
|
@ -87,6 +87,7 @@ class LCodeGen;
|
||||
V(ConstantI) \
|
||||
V(ConstantT) \
|
||||
V(Context) \
|
||||
V(DeclareGlobals) \
|
||||
V(DeleteProperty) \
|
||||
V(Deoptimize) \
|
||||
V(DivI) \
|
||||
@ -1345,6 +1346,13 @@ class LOuterContext: public LTemplateInstruction<1, 1, 0> {
|
||||
};
|
||||
|
||||
|
||||
class LDeclareGlobals: public LTemplateInstruction<0, 0, 0> {
|
||||
public:
|
||||
DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals, "declare-globals")
|
||||
DECLARE_HYDROGEN_ACCESSOR(DeclareGlobals)
|
||||
};
|
||||
|
||||
|
||||
class LGlobalObject: public LTemplateInstruction<1, 0, 0> {
|
||||
public:
|
||||
DECLARE_CONCRETE_INSTRUCTION(GlobalObject, "global-object")
|
||||
|
Loading…
Reference in New Issue
Block a user