Collect AstNode type information
Review URL: https://chromiumcodereview.appspot.com/9221011 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10631 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
9463c00d64
commit
d795b7c620
397
src/ast.cc
397
src/ast.cc
@ -126,18 +126,7 @@ Assignment::Assignment(Isolate* isolate,
|
||||
assignment_id_(GetNextId(isolate)),
|
||||
block_start_(false),
|
||||
block_end_(false),
|
||||
is_monomorphic_(false) {
|
||||
ASSERT(Token::IsAssignmentOp(op));
|
||||
if (is_compound()) {
|
||||
binary_operation_ =
|
||||
new(isolate->zone()) BinaryOperation(isolate,
|
||||
binary_op(),
|
||||
target,
|
||||
value,
|
||||
pos + 1);
|
||||
compound_load_id_ = GetNextId(isolate);
|
||||
}
|
||||
}
|
||||
is_monomorphic_(false) { }
|
||||
|
||||
|
||||
Token::Value Assignment::binary_op() const {
|
||||
@ -179,6 +168,11 @@ LanguageMode FunctionLiteral::language_mode() const {
|
||||
}
|
||||
|
||||
|
||||
bool FunctionLiteral::ShouldSelfOptimize() {
|
||||
return !flags()->Contains(kDontSelfOptimize);
|
||||
}
|
||||
|
||||
|
||||
ObjectLiteral::Property::Property(Literal* key, Expression* value) {
|
||||
emit_store_ = true;
|
||||
key_ = key;
|
||||
@ -197,9 +191,7 @@ ObjectLiteral::Property::Property(Literal* key, Expression* value) {
|
||||
|
||||
|
||||
ObjectLiteral::Property::Property(bool is_getter, FunctionLiteral* value) {
|
||||
Isolate* isolate = Isolate::Current();
|
||||
emit_store_ = true;
|
||||
key_ = new(isolate->zone()) Literal(isolate, value->name());
|
||||
value_ = value;
|
||||
kind_ = is_getter ? GETTER : SETTER;
|
||||
}
|
||||
@ -431,223 +423,6 @@ bool Declaration::IsInlineable() const {
|
||||
}
|
||||
|
||||
|
||||
bool TargetCollector::IsInlineable() const {
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool ForInStatement::IsInlineable() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool WithStatement::IsInlineable() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SwitchStatement::IsInlineable() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool TryStatement::IsInlineable() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool TryCatchStatement::IsInlineable() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool TryFinallyStatement::IsInlineable() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool DebuggerStatement::IsInlineable() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Throw::IsInlineable() const {
|
||||
return exception()->IsInlineable();
|
||||
}
|
||||
|
||||
|
||||
bool MaterializedLiteral::IsInlineable() const {
|
||||
// TODO(1322): Allow materialized literals.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool FunctionLiteral::IsInlineable() const {
|
||||
// TODO(1322): Allow materialized literals.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool ThisFunction::IsInlineable() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SharedFunctionInfoLiteral::IsInlineable() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool ForStatement::IsInlineable() const {
|
||||
return (init() == NULL || init()->IsInlineable())
|
||||
&& (cond() == NULL || cond()->IsInlineable())
|
||||
&& (next() == NULL || next()->IsInlineable())
|
||||
&& body()->IsInlineable();
|
||||
}
|
||||
|
||||
|
||||
bool WhileStatement::IsInlineable() const {
|
||||
return cond()->IsInlineable()
|
||||
&& body()->IsInlineable();
|
||||
}
|
||||
|
||||
|
||||
bool DoWhileStatement::IsInlineable() const {
|
||||
return cond()->IsInlineable()
|
||||
&& body()->IsInlineable();
|
||||
}
|
||||
|
||||
|
||||
bool ContinueStatement::IsInlineable() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool BreakStatement::IsInlineable() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool EmptyStatement::IsInlineable() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Literal::IsInlineable() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Block::IsInlineable() const {
|
||||
const int count = statements_.length();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (!statements_[i]->IsInlineable()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool ExpressionStatement::IsInlineable() const {
|
||||
return expression()->IsInlineable();
|
||||
}
|
||||
|
||||
|
||||
bool IfStatement::IsInlineable() const {
|
||||
return condition()->IsInlineable()
|
||||
&& then_statement()->IsInlineable()
|
||||
&& else_statement()->IsInlineable();
|
||||
}
|
||||
|
||||
|
||||
bool ReturnStatement::IsInlineable() const {
|
||||
return expression()->IsInlineable();
|
||||
}
|
||||
|
||||
|
||||
bool Conditional::IsInlineable() const {
|
||||
return condition()->IsInlineable() && then_expression()->IsInlineable() &&
|
||||
else_expression()->IsInlineable();
|
||||
}
|
||||
|
||||
|
||||
bool VariableProxy::IsInlineable() const {
|
||||
return var()->IsUnallocated()
|
||||
|| var()->IsStackAllocated()
|
||||
|| var()->IsContextSlot();
|
||||
}
|
||||
|
||||
|
||||
bool Assignment::IsInlineable() const {
|
||||
return target()->IsInlineable() && value()->IsInlineable();
|
||||
}
|
||||
|
||||
|
||||
bool Property::IsInlineable() const {
|
||||
return obj()->IsInlineable() && key()->IsInlineable();
|
||||
}
|
||||
|
||||
|
||||
bool Call::IsInlineable() const {
|
||||
if (!expression()->IsInlineable()) return false;
|
||||
const int count = arguments()->length();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (!arguments()->at(i)->IsInlineable()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CallNew::IsInlineable() const {
|
||||
if (!expression()->IsInlineable()) return false;
|
||||
const int count = arguments()->length();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (!arguments()->at(i)->IsInlineable()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CallRuntime::IsInlineable() const {
|
||||
// Don't try to inline JS runtime calls because we don't (currently) even
|
||||
// optimize them.
|
||||
if (is_jsruntime()) return false;
|
||||
// Don't inline the %_ArgumentsLength or %_Arguments because their
|
||||
// implementation will not work. There is no stack frame to get them
|
||||
// from.
|
||||
if (function()->intrinsic_type == Runtime::INLINE &&
|
||||
(name()->IsEqualTo(CStrVector("_ArgumentsLength")) ||
|
||||
name()->IsEqualTo(CStrVector("_Arguments")))) {
|
||||
return false;
|
||||
}
|
||||
const int count = arguments()->length();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (!arguments()->at(i)->IsInlineable()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool UnaryOperation::IsInlineable() const {
|
||||
return expression()->IsInlineable();
|
||||
}
|
||||
|
||||
|
||||
bool BinaryOperation::IsInlineable() const {
|
||||
return left()->IsInlineable() && right()->IsInlineable();
|
||||
}
|
||||
|
||||
|
||||
bool CompareOperation::IsInlineable() const {
|
||||
return left()->IsInlineable() && right()->IsInlineable();
|
||||
}
|
||||
|
||||
|
||||
bool CountOperation::IsInlineable() const {
|
||||
return expression()->IsInlineable();
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Recording of type feedback
|
||||
|
||||
@ -1214,4 +989,164 @@ CaseClause::CaseClause(Isolate* isolate,
|
||||
entry_id_(AstNode::GetNextId(isolate)) {
|
||||
}
|
||||
|
||||
|
||||
#define INCREASE_NODE_COUNT(NodeType) \
|
||||
void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
|
||||
increase_node_count(); \
|
||||
}
|
||||
|
||||
INCREASE_NODE_COUNT(Declaration)
|
||||
INCREASE_NODE_COUNT(Block)
|
||||
INCREASE_NODE_COUNT(ExpressionStatement)
|
||||
INCREASE_NODE_COUNT(EmptyStatement)
|
||||
INCREASE_NODE_COUNT(IfStatement)
|
||||
INCREASE_NODE_COUNT(ContinueStatement)
|
||||
INCREASE_NODE_COUNT(BreakStatement)
|
||||
INCREASE_NODE_COUNT(ReturnStatement)
|
||||
INCREASE_NODE_COUNT(Conditional)
|
||||
INCREASE_NODE_COUNT(Literal)
|
||||
INCREASE_NODE_COUNT(Assignment)
|
||||
INCREASE_NODE_COUNT(Throw)
|
||||
INCREASE_NODE_COUNT(Property)
|
||||
INCREASE_NODE_COUNT(UnaryOperation)
|
||||
INCREASE_NODE_COUNT(CountOperation)
|
||||
INCREASE_NODE_COUNT(BinaryOperation)
|
||||
INCREASE_NODE_COUNT(CompareOperation)
|
||||
INCREASE_NODE_COUNT(ThisFunction)
|
||||
|
||||
#undef INCREASE_NODE_COUNT
|
||||
|
||||
|
||||
void AstConstructionVisitor::VisitWithStatement(WithStatement* node) {
|
||||
increase_node_count();
|
||||
add_flag(kDontOptimize);
|
||||
add_flag(kDontInline);
|
||||
}
|
||||
|
||||
|
||||
void AstConstructionVisitor::VisitSwitchStatement(SwitchStatement* node) {
|
||||
increase_node_count();
|
||||
add_flag(kDontInline);
|
||||
}
|
||||
|
||||
|
||||
void AstConstructionVisitor::VisitDoWhileStatement(DoWhileStatement* node) {
|
||||
increase_node_count();
|
||||
add_flag(kDontSelfOptimize);
|
||||
}
|
||||
|
||||
|
||||
void AstConstructionVisitor::VisitWhileStatement(WhileStatement* node) {
|
||||
increase_node_count();
|
||||
add_flag(kDontSelfOptimize);
|
||||
}
|
||||
|
||||
|
||||
void AstConstructionVisitor::VisitForStatement(ForStatement* node) {
|
||||
increase_node_count();
|
||||
add_flag(kDontSelfOptimize);
|
||||
}
|
||||
|
||||
|
||||
void AstConstructionVisitor::VisitForInStatement(ForInStatement* node) {
|
||||
increase_node_count();
|
||||
add_flag(kDontOptimize);
|
||||
add_flag(kDontInline);
|
||||
add_flag(kDontSelfOptimize);
|
||||
}
|
||||
|
||||
|
||||
void AstConstructionVisitor::VisitTryCatchStatement(TryCatchStatement* node) {
|
||||
increase_node_count();
|
||||
add_flag(kDontOptimize);
|
||||
add_flag(kDontInline);
|
||||
}
|
||||
|
||||
|
||||
void AstConstructionVisitor::VisitTryFinallyStatement(
|
||||
TryFinallyStatement* node) {
|
||||
increase_node_count();
|
||||
add_flag(kDontOptimize);
|
||||
add_flag(kDontInline);
|
||||
}
|
||||
|
||||
|
||||
void AstConstructionVisitor::VisitDebuggerStatement(DebuggerStatement* node) {
|
||||
increase_node_count();
|
||||
add_flag(kDontOptimize);
|
||||
add_flag(kDontInline);
|
||||
}
|
||||
|
||||
|
||||
void AstConstructionVisitor::VisitFunctionLiteral(FunctionLiteral* node) {
|
||||
increase_node_count();
|
||||
add_flag(kDontInline);
|
||||
}
|
||||
|
||||
|
||||
void AstConstructionVisitor::VisitSharedFunctionInfoLiteral(
|
||||
SharedFunctionInfoLiteral* node) {
|
||||
increase_node_count();
|
||||
add_flag(kDontOptimize);
|
||||
add_flag(kDontInline);
|
||||
}
|
||||
|
||||
|
||||
void AstConstructionVisitor::VisitVariableProxy(VariableProxy* node) {
|
||||
increase_node_count();
|
||||
// In theory, we'd have to add:
|
||||
// if(node->var()->IsLookupSlot()) { add_flag(kDontInline); }
|
||||
// However, node->var() is usually not bound yet at VariableProxy creation
|
||||
// time, and LOOKUP variables only result from constructs that cannot
|
||||
// be inlined anyway.
|
||||
}
|
||||
|
||||
|
||||
void AstConstructionVisitor::VisitRegExpLiteral(RegExpLiteral* node) {
|
||||
increase_node_count();
|
||||
add_flag(kDontInline); // TODO(1322): Allow materialized literals.
|
||||
}
|
||||
|
||||
|
||||
void AstConstructionVisitor::VisitObjectLiteral(ObjectLiteral* node) {
|
||||
increase_node_count();
|
||||
add_flag(kDontInline); // TODO(1322): Allow materialized literals.
|
||||
}
|
||||
|
||||
|
||||
void AstConstructionVisitor::VisitArrayLiteral(ArrayLiteral* node) {
|
||||
increase_node_count();
|
||||
add_flag(kDontInline); // TODO(1322): Allow materialized literals.
|
||||
}
|
||||
|
||||
|
||||
void AstConstructionVisitor::VisitCall(Call* node) {
|
||||
increase_node_count();
|
||||
add_flag(kDontSelfOptimize);
|
||||
}
|
||||
|
||||
|
||||
void AstConstructionVisitor::VisitCallNew(CallNew* node) {
|
||||
increase_node_count();
|
||||
add_flag(kDontSelfOptimize);
|
||||
}
|
||||
|
||||
|
||||
void AstConstructionVisitor::VisitCallRuntime(CallRuntime* node) {
|
||||
increase_node_count();
|
||||
add_flag(kDontSelfOptimize);
|
||||
if (node->is_jsruntime()) {
|
||||
// Don't try to inline JS runtime calls because we don't (currently) even
|
||||
// optimize them.
|
||||
add_flag(kDontInline);
|
||||
} else if (node->function()->intrinsic_type == Runtime::INLINE &&
|
||||
(node->name()->IsEqualTo(CStrVector("_ArgumentsLength")) ||
|
||||
node->name()->IsEqualTo(CStrVector("_Arguments")))) {
|
||||
// Don't inline the %_ArgumentsLength or %_Arguments because their
|
||||
// implementation will not work. There is no stack frame to get them
|
||||
// from.
|
||||
add_flag(kDontInline);
|
||||
}
|
||||
}
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
@ -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:
|
||||
@ -652,6 +652,8 @@ 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_inline(lit->flags()->Contains(kDontInline));
|
||||
|
||||
if (info->AllowOptimize() && !shared->optimization_disabled()) {
|
||||
// If we're asked to always optimize, we compile the optimized
|
||||
@ -750,6 +752,9 @@ void Compiler::SetFunctionInfo(Handle<SharedFunctionInfo> function_info,
|
||||
function_info->set_language_mode(lit->language_mode());
|
||||
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_dont_inline(lit->flags()->Contains(kDontInline));
|
||||
}
|
||||
|
||||
|
||||
|
@ -2865,7 +2865,8 @@ MaybeObject* Heap::AllocateSharedFunctionInfo(Object* name) {
|
||||
share->set_inferred_name(empty_string(), SKIP_WRITE_BARRIER);
|
||||
share->set_initial_map(undefined_value(), SKIP_WRITE_BARRIER);
|
||||
share->set_this_property_assignments(undefined_value(), SKIP_WRITE_BARRIER);
|
||||
share->set_deopt_counter(Smi::FromInt(FLAG_deopt_every_n_times));
|
||||
share->set_deopt_counter(FLAG_deopt_every_n_times);
|
||||
share->set_ast_node_count(0);
|
||||
|
||||
// Set integer fields (smi or int, depending on the architecture).
|
||||
share->set_length(0);
|
||||
|
@ -4796,8 +4796,8 @@ bool HGraphBuilder::TryInline(Call* expr, bool drop_extra) {
|
||||
|
||||
// Do a quick check on source code length to avoid parsing large
|
||||
// inlining candidates.
|
||||
if ((FLAG_limit_inlining && target->shared()->SourceSize() > kMaxSourceSize)
|
||||
|| target->shared()->SourceSize() > kUnlimitedMaxSourceSize) {
|
||||
if ((FLAG_limit_inlining && target_shared->SourceSize() > kMaxSourceSize)
|
||||
|| target_shared->SourceSize() > kUnlimitedMaxSourceSize) {
|
||||
TraceInline(target, caller, "target text too big");
|
||||
return false;
|
||||
}
|
||||
@ -4807,6 +4807,17 @@ 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()) {
|
||||
TraceInline(target, caller, "target contains unsupported syntax [early]");
|
||||
return false;
|
||||
}
|
||||
|
||||
int nodes_added = target_shared->ast_node_count();
|
||||
if ((FLAG_limit_inlining && nodes_added > kMaxInlinedSize) ||
|
||||
nodes_added > kUnlimitedMaxInlinedSize) {
|
||||
TraceInline(target, caller, "target AST is too large [early]");
|
||||
return false;
|
||||
}
|
||||
|
||||
#if !defined(V8_TARGET_ARCH_IA32)
|
||||
// Target must be able to use caller's context.
|
||||
@ -4851,8 +4862,6 @@ bool HGraphBuilder::TryInline(Call* expr, bool drop_extra) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int count_before = AstNode::Count();
|
||||
|
||||
// Parse and allocate variables.
|
||||
CompilationInfo target_info(target);
|
||||
if (!ParserApi::Parse(&target_info, kNoParsingFlags) ||
|
||||
@ -4872,11 +4881,17 @@ bool HGraphBuilder::TryInline(Call* expr, bool drop_extra) {
|
||||
}
|
||||
FunctionLiteral* function = target_info.function();
|
||||
|
||||
// Count the number of AST nodes added by inlining this call.
|
||||
int nodes_added = AstNode::Count() - count_before;
|
||||
// The following conditions must be checked again after re-parsing, because
|
||||
// earlier the information might not have been complete due to lazy parsing.
|
||||
nodes_added = function->ast_node_count();
|
||||
if ((FLAG_limit_inlining && nodes_added > kMaxInlinedSize) ||
|
||||
nodes_added > kUnlimitedMaxInlinedSize) {
|
||||
TraceInline(target, caller, "target AST is too large");
|
||||
TraceInline(target, caller, "target AST is too large [late]");
|
||||
return false;
|
||||
}
|
||||
AstProperties::Flags* flags(function->flags());
|
||||
if (flags->Contains(kDontInline) || flags->Contains(kDontOptimize)) {
|
||||
TraceInline(target, caller, "target contains unsupported syntax [late]");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -4895,13 +4910,6 @@ bool HGraphBuilder::TryInline(Call* expr, bool drop_extra) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// All statements in the body must be inlineable.
|
||||
for (int i = 0, count = function->body()->length(); i < count; ++i) {
|
||||
if (!function->body()->at(i)->IsInlineable()) {
|
||||
TraceInline(target, caller, "target contains unsupported syntax");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the deoptimization data for the unoptimized version of
|
||||
// the target function if we don't already have it.
|
||||
|
@ -362,7 +362,7 @@ typedef List<HeapObject*, PreallocatedStorage> DebugObjectCache;
|
||||
/* Serializer state. */ \
|
||||
V(ExternalReferenceTable*, external_reference_table, NULL) \
|
||||
/* AstNode state. */ \
|
||||
V(unsigned, ast_node_id, 0) \
|
||||
V(int, ast_node_id, 0) \
|
||||
V(unsigned, ast_node_count, 0) \
|
||||
/* SafeStackFrameIterator activations count. */ \
|
||||
V(int, safe_stack_iterator_counter, 0) \
|
||||
|
@ -3576,6 +3576,8 @@ SMI_ACCESSORS(SharedFunctionInfo, compiler_hints,
|
||||
SMI_ACCESSORS(SharedFunctionInfo, this_property_assignments_count,
|
||||
kThisPropertyAssignmentsCountOffset)
|
||||
SMI_ACCESSORS(SharedFunctionInfo, opt_count, kOptCountOffset)
|
||||
SMI_ACCESSORS(SharedFunctionInfo, ast_node_count, kAstNodeCountOffset)
|
||||
SMI_ACCESSORS(SharedFunctionInfo, deopt_counter, kDeoptCounterOffset)
|
||||
#else
|
||||
|
||||
#define PSEUDO_SMI_ACCESSORS_LO(holder, name, offset) \
|
||||
@ -3626,6 +3628,9 @@ PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo,
|
||||
this_property_assignments_count,
|
||||
kThisPropertyAssignmentsCountOffset)
|
||||
PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo, opt_count, kOptCountOffset)
|
||||
|
||||
PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, ast_node_count, kAstNodeCountOffset)
|
||||
PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo, deopt_counter, kDeoptCounterOffset)
|
||||
#endif
|
||||
|
||||
|
||||
@ -3708,6 +3713,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, dont_inline, kDontInline)
|
||||
|
||||
ACCESSORS(CodeCache, default_cache, FixedArray, kDefaultCacheOffset)
|
||||
ACCESSORS(CodeCache, normal_type_cache, Object, kNormalTypeCacheOffset)
|
||||
@ -3777,16 +3785,6 @@ void SharedFunctionInfo::set_scope_info(ScopeInfo* value,
|
||||
}
|
||||
|
||||
|
||||
Smi* SharedFunctionInfo::deopt_counter() {
|
||||
return reinterpret_cast<Smi*>(READ_FIELD(this, kDeoptCounterOffset));
|
||||
}
|
||||
|
||||
|
||||
void SharedFunctionInfo::set_deopt_counter(Smi* value) {
|
||||
WRITE_FIELD(this, kDeoptCounterOffset, value);
|
||||
}
|
||||
|
||||
|
||||
bool SharedFunctionInfo::is_compiled() {
|
||||
return code() !=
|
||||
Isolate::Current()->builtins()->builtin(Builtins::kLazyCompile);
|
||||
|
@ -5203,8 +5203,11 @@ class SharedFunctionInfo: public HeapObject {
|
||||
|
||||
// A counter used to determine when to stress the deoptimizer with a
|
||||
// deopt.
|
||||
inline Smi* deopt_counter();
|
||||
inline void set_deopt_counter(Smi* counter);
|
||||
inline int deopt_counter();
|
||||
inline void set_deopt_counter(int counter);
|
||||
|
||||
inline int ast_node_count();
|
||||
inline void set_ast_node_count(int count);
|
||||
|
||||
// Add information on assignments of the form this.x = ...;
|
||||
void SetThisPropertyAssignmentsInfo(
|
||||
@ -5278,6 +5281,12 @@ 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)
|
||||
|
||||
// Indicates that the function cannot be inlined.
|
||||
DECL_BOOLEAN_ACCESSORS(dont_inline)
|
||||
|
||||
// Indicates whether or not the code in the shared function support
|
||||
// deoptimization.
|
||||
inline bool has_deoptimization_support();
|
||||
@ -5372,12 +5381,10 @@ class SharedFunctionInfo: public HeapObject {
|
||||
kInferredNameOffset + kPointerSize;
|
||||
static const int kThisPropertyAssignmentsOffset =
|
||||
kInitialMapOffset + kPointerSize;
|
||||
static const int kDeoptCounterOffset =
|
||||
kThisPropertyAssignmentsOffset + kPointerSize;
|
||||
#if V8_HOST_ARCH_32_BIT
|
||||
// Smi fields.
|
||||
static const int kLengthOffset =
|
||||
kDeoptCounterOffset + kPointerSize;
|
||||
kThisPropertyAssignmentsOffset + kPointerSize;
|
||||
static const int kFormalParameterCountOffset = kLengthOffset + kPointerSize;
|
||||
static const int kExpectedNofPropertiesOffset =
|
||||
kFormalParameterCountOffset + kPointerSize;
|
||||
@ -5395,8 +5402,11 @@ class SharedFunctionInfo: public HeapObject {
|
||||
kCompilerHintsOffset + kPointerSize;
|
||||
static const int kOptCountOffset =
|
||||
kThisPropertyAssignmentsCountOffset + kPointerSize;
|
||||
static const int kAstNodeCountOffset = kOptCountOffset + kPointerSize;
|
||||
static const int kDeoptCounterOffset =
|
||||
kAstNodeCountOffset + kPointerSize;
|
||||
// Total size.
|
||||
static const int kSize = kOptCountOffset + kPointerSize;
|
||||
static const int kSize = kDeoptCounterOffset + kPointerSize;
|
||||
#else
|
||||
// The only reason to use smi fields instead of int fields
|
||||
// is to allow iteration without maps decoding during
|
||||
@ -5408,7 +5418,7 @@ class SharedFunctionInfo: public HeapObject {
|
||||
// word is not set and thus this word cannot be treated as pointer
|
||||
// to HeapObject during old space traversal.
|
||||
static const int kLengthOffset =
|
||||
kDeoptCounterOffset + kPointerSize;
|
||||
kThisPropertyAssignmentsOffset + kPointerSize;
|
||||
static const int kFormalParameterCountOffset =
|
||||
kLengthOffset + kIntSize;
|
||||
|
||||
@ -5432,8 +5442,11 @@ class SharedFunctionInfo: public HeapObject {
|
||||
static const int kOptCountOffset =
|
||||
kThisPropertyAssignmentsCountOffset + kIntSize;
|
||||
|
||||
static const int kAstNodeCountOffset = kOptCountOffset + kIntSize;
|
||||
static const int kDeoptCounterOffset = kAstNodeCountOffset + kIntSize;
|
||||
|
||||
// Total size.
|
||||
static const int kSize = kOptCountOffset + kIntSize;
|
||||
static const int kSize = kDeoptCounterOffset + kIntSize;
|
||||
|
||||
#endif
|
||||
|
||||
@ -5480,6 +5493,8 @@ class SharedFunctionInfo: public HeapObject {
|
||||
kBoundFunction,
|
||||
kIsAnonymous,
|
||||
kNameShouldPrintAsAnonymous,
|
||||
kDontCrankshaft,
|
||||
kDontInline,
|
||||
kCompilerHintsCount // Pseudo entry
|
||||
};
|
||||
|
||||
|
443
src/parser.cc
443
src/parser.cc
@ -481,62 +481,6 @@ class Parser::BlockState BASE_EMBEDDED {
|
||||
};
|
||||
|
||||
|
||||
class Parser::FunctionState BASE_EMBEDDED {
|
||||
public:
|
||||
FunctionState(Parser* parser, Scope* scope, Isolate* isolate);
|
||||
~FunctionState();
|
||||
|
||||
int NextMaterializedLiteralIndex() {
|
||||
return next_materialized_literal_index_++;
|
||||
}
|
||||
int materialized_literal_count() {
|
||||
return next_materialized_literal_index_ - JSFunction::kLiteralsPrefixSize;
|
||||
}
|
||||
|
||||
int NextHandlerIndex() { return next_handler_index_++; }
|
||||
int handler_count() { return next_handler_index_; }
|
||||
|
||||
void SetThisPropertyAssignmentInfo(
|
||||
bool only_simple_this_property_assignments,
|
||||
Handle<FixedArray> this_property_assignments) {
|
||||
only_simple_this_property_assignments_ =
|
||||
only_simple_this_property_assignments;
|
||||
this_property_assignments_ = this_property_assignments;
|
||||
}
|
||||
bool only_simple_this_property_assignments() {
|
||||
return only_simple_this_property_assignments_;
|
||||
}
|
||||
Handle<FixedArray> this_property_assignments() {
|
||||
return this_property_assignments_;
|
||||
}
|
||||
|
||||
void AddProperty() { expected_property_count_++; }
|
||||
int expected_property_count() { return expected_property_count_; }
|
||||
|
||||
private:
|
||||
// Used to assign an index to each literal that needs materialization in
|
||||
// the function. Includes regexp literals, and boilerplate for object and
|
||||
// array literals.
|
||||
int next_materialized_literal_index_;
|
||||
|
||||
// Used to assign a per-function index to try and catch handlers.
|
||||
int next_handler_index_;
|
||||
|
||||
// Properties count estimation.
|
||||
int expected_property_count_;
|
||||
|
||||
// Keeps track of assignments to properties of this. Used for
|
||||
// optimizing constructors.
|
||||
bool only_simple_this_property_assignments_;
|
||||
Handle<FixedArray> this_property_assignments_;
|
||||
|
||||
Parser* parser_;
|
||||
FunctionState* outer_function_state_;
|
||||
Scope* outer_scope_;
|
||||
unsigned saved_ast_node_id_;
|
||||
};
|
||||
|
||||
|
||||
Parser::FunctionState::FunctionState(Parser* parser,
|
||||
Scope* scope,
|
||||
Isolate* isolate)
|
||||
@ -548,7 +492,8 @@ Parser::FunctionState::FunctionState(Parser* parser,
|
||||
parser_(parser),
|
||||
outer_function_state_(parser->current_function_state_),
|
||||
outer_scope_(parser->top_scope_),
|
||||
saved_ast_node_id_(isolate->ast_node_id()) {
|
||||
saved_ast_node_id_(isolate->ast_node_id()),
|
||||
factory_(isolate) {
|
||||
parser->top_scope_ = scope;
|
||||
parser->current_function_state_ = this;
|
||||
isolate->set_ast_node_id(AstNode::kDeclarationsId + 1);
|
||||
@ -674,8 +619,7 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info,
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
result = new(zone()) FunctionLiteral(
|
||||
isolate(),
|
||||
result = factory()->NewFunctionLiteral(
|
||||
no_name,
|
||||
top_scope_,
|
||||
body,
|
||||
@ -685,8 +629,10 @@ 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::ANONYMOUS_EXPRESSION,
|
||||
false); // Does not have duplicate parameters.
|
||||
false); // Top-level literal doesn't count for the AST's properties.
|
||||
result->set_ast_properties(factory()->visitor()->ast_properties());
|
||||
} else if (stack_overflow_) {
|
||||
isolate()->StackOverflow();
|
||||
}
|
||||
@ -1274,7 +1220,7 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) {
|
||||
|
||||
case Token::SEMICOLON:
|
||||
Next();
|
||||
return EmptyStatement();
|
||||
return factory()->NewEmptyStatement();
|
||||
|
||||
case Token::IF:
|
||||
stmt = ParseIfStatement(labels, ok);
|
||||
@ -1322,7 +1268,7 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) {
|
||||
// one must take great care not to treat it as a
|
||||
// fall-through. It is much easier just to wrap the entire
|
||||
// try-statement in a statement block and put the labels there
|
||||
Block* result = new(zone()) Block(isolate(), labels, 1, false);
|
||||
Block* result = factory()->NewBlock(labels, 1, false);
|
||||
Target target(&this->target_stack_, result);
|
||||
TryStatement* statement = ParseTryStatement(CHECK_OK);
|
||||
if (statement) {
|
||||
@ -1454,9 +1400,9 @@ VariableProxy* Parser::Declare(Handle<String> name,
|
||||
// a performance issue since it may lead to repeated
|
||||
// Runtime::DeclareContextSlot() calls.
|
||||
VariableProxy* proxy = declaration_scope->NewUnresolved(
|
||||
name, scanner().location().beg_pos);
|
||||
factory(), name, scanner().location().beg_pos);
|
||||
declaration_scope->AddDeclaration(
|
||||
new(zone()) Declaration(proxy, mode, fun, top_scope_));
|
||||
factory()->NewDeclaration(proxy, mode, fun, top_scope_));
|
||||
|
||||
if ((mode == CONST || mode == CONST_HARMONY) &&
|
||||
declaration_scope->is_global_scope()) {
|
||||
@ -1564,10 +1510,11 @@ Statement* Parser::ParseNativeDeclaration(bool* ok) {
|
||||
// introduced dynamically when we meet their declarations, whereas
|
||||
// other functions are set up when entering the surrounding scope.
|
||||
SharedFunctionInfoLiteral* lit =
|
||||
new(zone()) SharedFunctionInfoLiteral(isolate(), shared);
|
||||
factory()->NewSharedFunctionInfoLiteral(shared);
|
||||
VariableProxy* var = Declare(name, VAR, NULL, true, CHECK_OK);
|
||||
return new(zone()) ExpressionStatement(new(zone()) Assignment(
|
||||
isolate(), Token::INIT_VAR, var, lit, RelocInfo::kNoPosition));
|
||||
return factory()->NewExpressionStatement(
|
||||
factory()->NewAssignment(
|
||||
Token::INIT_VAR, var, lit, RelocInfo::kNoPosition));
|
||||
}
|
||||
|
||||
|
||||
@ -1589,7 +1536,7 @@ Statement* Parser::ParseFunctionDeclaration(bool* ok) {
|
||||
// initial value upon entering the corresponding scope.
|
||||
VariableMode mode = is_extended_mode() ? LET : VAR;
|
||||
Declare(name, mode, fun, true, CHECK_OK);
|
||||
return EmptyStatement();
|
||||
return factory()->NewEmptyStatement();
|
||||
}
|
||||
|
||||
|
||||
@ -1603,7 +1550,7 @@ Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) {
|
||||
// (ECMA-262, 3rd, 12.2)
|
||||
//
|
||||
// Construct block expecting 16 statements.
|
||||
Block* result = new(zone()) Block(isolate(), labels, 16, false);
|
||||
Block* result = factory()->NewBlock(labels, 16, false);
|
||||
Target target(&this->target_stack_, result);
|
||||
Expect(Token::LBRACE, CHECK_OK);
|
||||
InitializationBlockFinder block_finder(top_scope_, target_stack_);
|
||||
@ -1626,7 +1573,7 @@ Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) {
|
||||
// '{' SourceElement* '}'
|
||||
|
||||
// Construct block expecting 16 statements.
|
||||
Block* body = new(zone()) Block(isolate(), labels, 16, false);
|
||||
Block* body = factory()->NewBlock(labels, 16, false);
|
||||
Scope* block_scope = NewScope(top_scope_, BLOCK_SCOPE);
|
||||
|
||||
// Parse the statements and collect escaping labels.
|
||||
@ -1786,7 +1733,7 @@ Block* Parser::ParseVariableDeclarations(
|
||||
// is inside an initializer block, it is ignored.
|
||||
//
|
||||
// Create new block with one expected declaration.
|
||||
Block* block = new(zone()) Block(isolate(), NULL, 1, true);
|
||||
Block* block = factory()->NewBlock(NULL, 1, true);
|
||||
int nvars = 0; // the number of variables declared
|
||||
Handle<String> name;
|
||||
do {
|
||||
@ -1907,7 +1854,7 @@ Block* Parser::ParseVariableDeclarations(
|
||||
// Compute the arguments for the runtime call.
|
||||
ZoneList<Expression*>* arguments = new(zone()) ZoneList<Expression*>(3);
|
||||
// We have at least 1 parameter.
|
||||
arguments->Add(NewLiteral(name));
|
||||
arguments->Add(factory()->NewLiteral(name));
|
||||
CallRuntime* initialize;
|
||||
|
||||
if (is_const) {
|
||||
@ -1918,17 +1865,15 @@ Block* Parser::ParseVariableDeclarations(
|
||||
// and add it to the initialization statement block.
|
||||
// Note that the function does different things depending on
|
||||
// the number of arguments (1 or 2).
|
||||
initialize =
|
||||
new(zone()) CallRuntime(
|
||||
isolate(),
|
||||
isolate()->factory()->InitializeConstGlobal_symbol(),
|
||||
Runtime::FunctionForId(Runtime::kInitializeConstGlobal),
|
||||
arguments);
|
||||
initialize = factory()->NewCallRuntime(
|
||||
isolate()->factory()->InitializeConstGlobal_symbol(),
|
||||
Runtime::FunctionForId(Runtime::kInitializeConstGlobal),
|
||||
arguments);
|
||||
} else {
|
||||
// Add strict mode.
|
||||
// We may want to pass singleton to avoid Literal allocations.
|
||||
LanguageMode language_mode = initialization_scope->language_mode();
|
||||
arguments->Add(NewNumberLiteral(language_mode));
|
||||
arguments->Add(factory()->NewNumberLiteral(language_mode));
|
||||
|
||||
// Be careful not to assign a value to the global variable if
|
||||
// we're in a with. The initialization value should not
|
||||
@ -1943,15 +1888,13 @@ Block* Parser::ParseVariableDeclarations(
|
||||
// and add it to the initialization statement block.
|
||||
// Note that the function does different things depending on
|
||||
// the number of arguments (2 or 3).
|
||||
initialize =
|
||||
new(zone()) CallRuntime(
|
||||
isolate(),
|
||||
isolate()->factory()->InitializeVarGlobal_symbol(),
|
||||
Runtime::FunctionForId(Runtime::kInitializeVarGlobal),
|
||||
arguments);
|
||||
initialize = factory()->NewCallRuntime(
|
||||
isolate()->factory()->InitializeVarGlobal_symbol(),
|
||||
Runtime::FunctionForId(Runtime::kInitializeVarGlobal),
|
||||
arguments);
|
||||
}
|
||||
|
||||
block->AddStatement(new(zone()) ExpressionStatement(initialize));
|
||||
block->AddStatement(factory()->NewExpressionStatement(initialize));
|
||||
} else if (needs_init) {
|
||||
// Constant initializations always assign to the declared constant which
|
||||
// is always at the function scope level. This is only relevant for
|
||||
@ -1964,8 +1907,8 @@ Block* Parser::ParseVariableDeclarations(
|
||||
ASSERT(proxy->var() != NULL);
|
||||
ASSERT(value != NULL);
|
||||
Assignment* assignment =
|
||||
new(zone()) Assignment(isolate(), init_op, proxy, value, position);
|
||||
block->AddStatement(new(zone()) ExpressionStatement(assignment));
|
||||
factory()->NewAssignment(init_op, proxy, value, position);
|
||||
block->AddStatement(factory()->NewExpressionStatement(assignment));
|
||||
value = NULL;
|
||||
}
|
||||
|
||||
@ -1976,10 +1919,11 @@ Block* Parser::ParseVariableDeclarations(
|
||||
// 'var' initializations are simply assignments (with all the consequences
|
||||
// if they are inside a 'with' statement - they may change a 'with' object
|
||||
// property).
|
||||
VariableProxy* proxy = initialization_scope->NewUnresolved(name);
|
||||
VariableProxy* proxy =
|
||||
initialization_scope->NewUnresolved(factory(), name);
|
||||
Assignment* assignment =
|
||||
new(zone()) Assignment(isolate(), init_op, proxy, value, position);
|
||||
block->AddStatement(new(zone()) ExpressionStatement(assignment));
|
||||
factory()->NewAssignment(init_op, proxy, value, position);
|
||||
block->AddStatement(factory()->NewExpressionStatement(assignment));
|
||||
}
|
||||
|
||||
if (fni_ != NULL) fni_->Leave();
|
||||
@ -2059,7 +2003,7 @@ Statement* Parser::ParseExpressionOrLabelledStatement(ZoneStringList* labels,
|
||||
|
||||
// Parsed expression statement.
|
||||
ExpectSemicolon(CHECK_OK);
|
||||
return new(zone()) ExpressionStatement(expr);
|
||||
return factory()->NewExpressionStatement(expr);
|
||||
}
|
||||
|
||||
|
||||
@ -2077,10 +2021,9 @@ IfStatement* Parser::ParseIfStatement(ZoneStringList* labels, bool* ok) {
|
||||
Next();
|
||||
else_statement = ParseStatement(labels, CHECK_OK);
|
||||
} else {
|
||||
else_statement = EmptyStatement();
|
||||
else_statement = factory()->NewEmptyStatement();
|
||||
}
|
||||
return new(zone()) IfStatement(
|
||||
isolate(), condition, then_statement, else_statement);
|
||||
return factory()->NewIfStatement(condition, then_statement, else_statement);
|
||||
}
|
||||
|
||||
|
||||
@ -2110,7 +2053,7 @@ Statement* Parser::ParseContinueStatement(bool* ok) {
|
||||
return NULL;
|
||||
}
|
||||
ExpectSemicolon(CHECK_OK);
|
||||
return new(zone()) ContinueStatement(target);
|
||||
return factory()->NewContinueStatement(target);
|
||||
}
|
||||
|
||||
|
||||
@ -2129,7 +2072,7 @@ Statement* Parser::ParseBreakStatement(ZoneStringList* labels, bool* ok) {
|
||||
// empty statements, e.g. 'l1: l2: l3: break l2;'
|
||||
if (!label.is_null() && ContainsLabel(labels, label)) {
|
||||
ExpectSemicolon(CHECK_OK);
|
||||
return EmptyStatement();
|
||||
return factory()->NewEmptyStatement();
|
||||
}
|
||||
BreakableStatement* target = NULL;
|
||||
target = LookupBreakTarget(label, CHECK_OK);
|
||||
@ -2146,7 +2089,7 @@ Statement* Parser::ParseBreakStatement(ZoneStringList* labels, bool* ok) {
|
||||
return NULL;
|
||||
}
|
||||
ExpectSemicolon(CHECK_OK);
|
||||
return new(zone()) BreakStatement(target);
|
||||
return factory()->NewBreakStatement(target);
|
||||
}
|
||||
|
||||
|
||||
@ -2166,11 +2109,11 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
|
||||
tok == Token::RBRACE ||
|
||||
tok == Token::EOS) {
|
||||
ExpectSemicolon(CHECK_OK);
|
||||
result = new(zone()) ReturnStatement(GetLiteralUndefined());
|
||||
result = factory()->NewReturnStatement(GetLiteralUndefined());
|
||||
} else {
|
||||
Expression* expr = ParseExpression(true, CHECK_OK);
|
||||
ExpectSemicolon(CHECK_OK);
|
||||
result = new(zone()) ReturnStatement(expr);
|
||||
result = factory()->NewReturnStatement(expr);
|
||||
}
|
||||
|
||||
// An ECMAScript program is considered syntactically incorrect if it
|
||||
@ -2183,7 +2126,7 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
|
||||
declaration_scope->is_eval_scope()) {
|
||||
Handle<String> type = isolate()->factory()->illegal_return_symbol();
|
||||
Expression* throw_error = NewThrowSyntaxError(type, Handle<Object>::null());
|
||||
return new(zone()) ExpressionStatement(throw_error);
|
||||
return factory()->NewExpressionStatement(throw_error);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -2213,7 +2156,7 @@ Statement* Parser::ParseWithStatement(ZoneStringList* labels, bool* ok) {
|
||||
stmt = ParseStatement(labels, CHECK_OK);
|
||||
with_scope->set_end_position(scanner().location().end_pos);
|
||||
}
|
||||
return new(zone()) WithStatement(expr, stmt);
|
||||
return factory()->NewWithStatement(expr, stmt);
|
||||
}
|
||||
|
||||
|
||||
@ -2255,7 +2198,7 @@ SwitchStatement* Parser::ParseSwitchStatement(ZoneStringList* labels,
|
||||
// SwitchStatement ::
|
||||
// 'switch' '(' Expression ')' '{' CaseClause* '}'
|
||||
|
||||
SwitchStatement* statement = new(zone()) SwitchStatement(isolate(), labels);
|
||||
SwitchStatement* statement = factory()->NewSwitchStatement(labels);
|
||||
Target target(&this->target_stack_, statement);
|
||||
|
||||
Expect(Token::SWITCH, CHECK_OK);
|
||||
@ -2291,8 +2234,7 @@ Statement* Parser::ParseThrowStatement(bool* ok) {
|
||||
Expression* exception = ParseExpression(true, CHECK_OK);
|
||||
ExpectSemicolon(CHECK_OK);
|
||||
|
||||
return new(zone()) ExpressionStatement(
|
||||
new(zone()) Throw(isolate(), exception, pos));
|
||||
return factory()->NewExpressionStatement(factory()->NewThrow(exception, pos));
|
||||
}
|
||||
|
||||
|
||||
@ -2379,13 +2321,10 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
|
||||
// If we have both, create an inner try/catch.
|
||||
ASSERT(catch_scope != NULL && catch_variable != NULL);
|
||||
int index = current_function_state_->NextHandlerIndex();
|
||||
TryCatchStatement* statement = new(zone()) TryCatchStatement(index,
|
||||
try_block,
|
||||
catch_scope,
|
||||
catch_variable,
|
||||
catch_block);
|
||||
TryCatchStatement* statement = factory()->NewTryCatchStatement(
|
||||
index, try_block, catch_scope, catch_variable, catch_block);
|
||||
statement->set_escaping_targets(try_collector.targets());
|
||||
try_block = new(zone()) Block(isolate(), NULL, 1, false);
|
||||
try_block = factory()->NewBlock(NULL, 1, false);
|
||||
try_block->AddStatement(statement);
|
||||
catch_block = NULL; // Clear to indicate it's been handled.
|
||||
}
|
||||
@ -2395,17 +2334,12 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
|
||||
ASSERT(finally_block == NULL);
|
||||
ASSERT(catch_scope != NULL && catch_variable != NULL);
|
||||
int index = current_function_state_->NextHandlerIndex();
|
||||
result = new(zone()) TryCatchStatement(index,
|
||||
try_block,
|
||||
catch_scope,
|
||||
catch_variable,
|
||||
catch_block);
|
||||
result = factory()->NewTryCatchStatement(
|
||||
index, try_block, catch_scope, catch_variable, catch_block);
|
||||
} else {
|
||||
ASSERT(finally_block != NULL);
|
||||
int index = current_function_state_->NextHandlerIndex();
|
||||
result = new(zone()) TryFinallyStatement(index,
|
||||
try_block,
|
||||
finally_block);
|
||||
result = factory()->NewTryFinallyStatement(index, try_block, finally_block);
|
||||
// Combine the jump targets of the try block and the possible catch block.
|
||||
try_collector.targets()->AddAll(*catch_collector.targets());
|
||||
}
|
||||
@ -2420,7 +2354,7 @@ DoWhileStatement* Parser::ParseDoWhileStatement(ZoneStringList* labels,
|
||||
// DoStatement ::
|
||||
// 'do' Statement 'while' '(' Expression ')' ';'
|
||||
|
||||
DoWhileStatement* loop = new(zone()) DoWhileStatement(isolate(), labels);
|
||||
DoWhileStatement* loop = factory()->NewDoWhileStatement(labels);
|
||||
Target target(&this->target_stack_, loop);
|
||||
|
||||
Expect(Token::DO, CHECK_OK);
|
||||
@ -2451,7 +2385,7 @@ WhileStatement* Parser::ParseWhileStatement(ZoneStringList* labels, bool* ok) {
|
||||
// WhileStatement ::
|
||||
// 'while' '(' Expression ')' Statement
|
||||
|
||||
WhileStatement* loop = new(zone()) WhileStatement(isolate(), labels);
|
||||
WhileStatement* loop = factory()->NewWhileStatement(labels);
|
||||
Target target(&this->target_stack_, loop);
|
||||
|
||||
Expect(Token::WHILE, CHECK_OK);
|
||||
@ -2486,8 +2420,8 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
|
||||
ParseVariableDeclarations(kForStatement, NULL, &name, CHECK_OK);
|
||||
|
||||
if (peek() == Token::IN && !name.is_null()) {
|
||||
VariableProxy* each = top_scope_->NewUnresolved(name);
|
||||
ForInStatement* loop = new(zone()) ForInStatement(isolate(), labels);
|
||||
VariableProxy* each = top_scope_->NewUnresolved(factory(), name);
|
||||
ForInStatement* loop = factory()->NewForInStatement(labels);
|
||||
Target target(&this->target_stack_, loop);
|
||||
|
||||
Expect(Token::IN, CHECK_OK);
|
||||
@ -2496,7 +2430,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
|
||||
|
||||
Statement* body = ParseStatement(NULL, CHECK_OK);
|
||||
loop->Initialize(each, enumerable, body);
|
||||
Block* result = new(zone()) Block(isolate(), NULL, 2, false);
|
||||
Block* result = factory()->NewBlock(NULL, 2, false);
|
||||
result->AddStatement(variable_statement);
|
||||
result->AddStatement(loop);
|
||||
top_scope_ = saved_scope;
|
||||
@ -2534,9 +2468,9 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
|
||||
// TODO(keuchel): Move the temporary variable to the block scope, after
|
||||
// implementing stack allocated block scoped variables.
|
||||
Variable* temp = top_scope_->DeclarationScope()->NewTemporary(name);
|
||||
VariableProxy* temp_proxy = new(zone()) VariableProxy(isolate(), temp);
|
||||
VariableProxy* each = top_scope_->NewUnresolved(name);
|
||||
ForInStatement* loop = new(zone()) ForInStatement(isolate(), labels);
|
||||
VariableProxy* temp_proxy = factory()->NewVariableProxy(temp);
|
||||
VariableProxy* each = top_scope_->NewUnresolved(factory(), name);
|
||||
ForInStatement* loop = factory()->NewForInStatement(labels);
|
||||
Target target(&this->target_stack_, loop);
|
||||
|
||||
Expect(Token::IN, CHECK_OK);
|
||||
@ -2544,14 +2478,11 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
|
||||
Expect(Token::RPAREN, CHECK_OK);
|
||||
|
||||
Statement* body = ParseStatement(NULL, CHECK_OK);
|
||||
Block* body_block = new(zone()) Block(isolate(), NULL, 3, false);
|
||||
Assignment* assignment = new(zone()) Assignment(isolate(),
|
||||
Token::ASSIGN,
|
||||
each,
|
||||
temp_proxy,
|
||||
RelocInfo::kNoPosition);
|
||||
Block* body_block = factory()->NewBlock(NULL, 3, false);
|
||||
Assignment* assignment = factory()->NewAssignment(
|
||||
Token::ASSIGN, each, temp_proxy, RelocInfo::kNoPosition);
|
||||
Statement* assignment_statement =
|
||||
new(zone()) ExpressionStatement(assignment);
|
||||
factory()->NewExpressionStatement(assignment);
|
||||
body_block->AddStatement(variable_statement);
|
||||
body_block->AddStatement(assignment_statement);
|
||||
body_block->AddStatement(body);
|
||||
@ -2578,7 +2509,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
|
||||
isolate()->factory()->invalid_lhs_in_for_in_symbol();
|
||||
expression = NewThrowReferenceError(type);
|
||||
}
|
||||
ForInStatement* loop = new(zone()) ForInStatement(isolate(), labels);
|
||||
ForInStatement* loop = factory()->NewForInStatement(labels);
|
||||
Target target(&this->target_stack_, loop);
|
||||
|
||||
Expect(Token::IN, CHECK_OK);
|
||||
@ -2595,13 +2526,13 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
|
||||
return loop;
|
||||
|
||||
} else {
|
||||
init = new(zone()) ExpressionStatement(expression);
|
||||
init = factory()->NewExpressionStatement(expression);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Standard 'for' loop
|
||||
ForStatement* loop = new(zone()) ForStatement(isolate(), labels);
|
||||
ForStatement* loop = factory()->NewForStatement(labels);
|
||||
Target target(&this->target_stack_, loop);
|
||||
|
||||
// Parsed initializer at this point.
|
||||
@ -2616,7 +2547,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
|
||||
Statement* next = NULL;
|
||||
if (peek() != Token::RPAREN) {
|
||||
Expression* exp = ParseExpression(true, CHECK_OK);
|
||||
next = new(zone()) ExpressionStatement(exp);
|
||||
next = factory()->NewExpressionStatement(exp);
|
||||
}
|
||||
Expect(Token::RPAREN, CHECK_OK);
|
||||
|
||||
@ -2636,7 +2567,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
|
||||
// for (; c; n) b
|
||||
// }
|
||||
ASSERT(init != NULL);
|
||||
Block* result = new(zone()) Block(isolate(), NULL, 2, false);
|
||||
Block* result = factory()->NewBlock(NULL, 2, false);
|
||||
result->AddStatement(init);
|
||||
result->AddStatement(loop);
|
||||
result->set_block_scope(for_scope);
|
||||
@ -2660,8 +2591,8 @@ Expression* Parser::ParseExpression(bool accept_IN, bool* ok) {
|
||||
Expect(Token::COMMA, CHECK_OK);
|
||||
int position = scanner().location().beg_pos;
|
||||
Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
|
||||
result = new(zone()) BinaryOperation(
|
||||
isolate(), Token::COMMA, result, right, position);
|
||||
result =
|
||||
factory()->NewBinaryOperation(Token::COMMA, result, right, position);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -2736,7 +2667,7 @@ Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) {
|
||||
fni_->Leave();
|
||||
}
|
||||
|
||||
return new(zone()) Assignment(isolate(), op, expression, right, pos);
|
||||
return factory()->NewAssignment(op, expression, right, pos);
|
||||
}
|
||||
|
||||
|
||||
@ -2758,8 +2689,8 @@ Expression* Parser::ParseConditionalExpression(bool accept_IN, bool* ok) {
|
||||
Expect(Token::COLON, CHECK_OK);
|
||||
int right_position = scanner().peek_location().beg_pos;
|
||||
Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
|
||||
return new(zone()) Conditional(
|
||||
isolate(), expression, left, right, left_position, right_position);
|
||||
return factory()->NewConditional(
|
||||
expression, left, right, left_position, right_position);
|
||||
}
|
||||
|
||||
|
||||
@ -2790,41 +2721,47 @@ Expression* Parser::ParseBinaryExpression(int prec, bool accept_IN, bool* ok) {
|
||||
|
||||
switch (op) {
|
||||
case Token::ADD:
|
||||
x = NewNumberLiteral(x_val + y_val);
|
||||
x = factory()->NewNumberLiteral(x_val + y_val);
|
||||
continue;
|
||||
case Token::SUB:
|
||||
x = NewNumberLiteral(x_val - y_val);
|
||||
x = factory()->NewNumberLiteral(x_val - y_val);
|
||||
continue;
|
||||
case Token::MUL:
|
||||
x = NewNumberLiteral(x_val * y_val);
|
||||
x = factory()->NewNumberLiteral(x_val * y_val);
|
||||
continue;
|
||||
case Token::DIV:
|
||||
x = NewNumberLiteral(x_val / y_val);
|
||||
x = factory()->NewNumberLiteral(x_val / y_val);
|
||||
continue;
|
||||
case Token::BIT_OR:
|
||||
x = NewNumberLiteral(DoubleToInt32(x_val) | DoubleToInt32(y_val));
|
||||
case Token::BIT_OR: {
|
||||
int value = DoubleToInt32(x_val) | DoubleToInt32(y_val);
|
||||
x = factory()->NewNumberLiteral(value);
|
||||
continue;
|
||||
case Token::BIT_AND:
|
||||
x = NewNumberLiteral(DoubleToInt32(x_val) & DoubleToInt32(y_val));
|
||||
}
|
||||
case Token::BIT_AND: {
|
||||
int value = DoubleToInt32(x_val) & DoubleToInt32(y_val);
|
||||
x = factory()->NewNumberLiteral(value);
|
||||
continue;
|
||||
case Token::BIT_XOR:
|
||||
x = NewNumberLiteral(DoubleToInt32(x_val) ^ DoubleToInt32(y_val));
|
||||
}
|
||||
case Token::BIT_XOR: {
|
||||
int value = DoubleToInt32(x_val) ^ DoubleToInt32(y_val);
|
||||
x = factory()->NewNumberLiteral(value);
|
||||
continue;
|
||||
}
|
||||
case Token::SHL: {
|
||||
int value = DoubleToInt32(x_val) << (DoubleToInt32(y_val) & 0x1f);
|
||||
x = NewNumberLiteral(value);
|
||||
x = factory()->NewNumberLiteral(value);
|
||||
continue;
|
||||
}
|
||||
case Token::SHR: {
|
||||
uint32_t shift = DoubleToInt32(y_val) & 0x1f;
|
||||
uint32_t value = DoubleToUint32(x_val) >> shift;
|
||||
x = NewNumberLiteral(value);
|
||||
x = factory()->NewNumberLiteral(value);
|
||||
continue;
|
||||
}
|
||||
case Token::SAR: {
|
||||
uint32_t shift = DoubleToInt32(y_val) & 0x1f;
|
||||
int value = ArithmeticShiftRight(DoubleToInt32(x_val), shift);
|
||||
x = NewNumberLiteral(value);
|
||||
x = factory()->NewNumberLiteral(value);
|
||||
continue;
|
||||
}
|
||||
default:
|
||||
@ -2843,15 +2780,15 @@ Expression* Parser::ParseBinaryExpression(int prec, bool accept_IN, bool* ok) {
|
||||
case Token::NE_STRICT: cmp = Token::EQ_STRICT; break;
|
||||
default: break;
|
||||
}
|
||||
x = new(zone()) CompareOperation(isolate(), cmp, x, y, position);
|
||||
x = factory()->NewCompareOperation(cmp, x, y, position);
|
||||
if (cmp != op) {
|
||||
// The comparison was negated - add a NOT.
|
||||
x = new(zone()) UnaryOperation(isolate(), Token::NOT, x, position);
|
||||
x = factory()->NewUnaryOperation(Token::NOT, x, position);
|
||||
}
|
||||
|
||||
} else {
|
||||
// We have a "normal" binary operation.
|
||||
x = new(zone()) BinaryOperation(isolate(), op, x, y, position);
|
||||
x = factory()->NewBinaryOperation(op, x, y, position);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2884,7 +2821,7 @@ Expression* Parser::ParseUnaryExpression(bool* ok) {
|
||||
// Convert the literal to a boolean condition and negate it.
|
||||
bool condition = literal->ToBoolean()->IsTrue();
|
||||
Handle<Object> result(isolate()->heap()->ToBoolean(!condition));
|
||||
return NewLiteral(result);
|
||||
return factory()->NewLiteral(result);
|
||||
} else if (literal->IsNumber()) {
|
||||
// Compute some expressions involving only number literals.
|
||||
double value = literal->Number();
|
||||
@ -2892,9 +2829,9 @@ Expression* Parser::ParseUnaryExpression(bool* ok) {
|
||||
case Token::ADD:
|
||||
return expression;
|
||||
case Token::SUB:
|
||||
return NewNumberLiteral(-value);
|
||||
return factory()->NewNumberLiteral(-value);
|
||||
case Token::BIT_NOT:
|
||||
return NewNumberLiteral(~DoubleToInt32(value));
|
||||
return factory()->NewNumberLiteral(~DoubleToInt32(value));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -2911,7 +2848,7 @@ Expression* Parser::ParseUnaryExpression(bool* ok) {
|
||||
}
|
||||
}
|
||||
|
||||
return new(zone()) UnaryOperation(isolate(), op, expression, position);
|
||||
return factory()->NewUnaryOperation(op, expression, position);
|
||||
|
||||
} else if (Token::IsCountOp(op)) {
|
||||
op = Next();
|
||||
@ -2933,11 +2870,10 @@ Expression* Parser::ParseUnaryExpression(bool* ok) {
|
||||
MarkAsLValue(expression);
|
||||
|
||||
int position = scanner().location().beg_pos;
|
||||
return new(zone()) CountOperation(isolate(),
|
||||
op,
|
||||
true /* prefix */,
|
||||
expression,
|
||||
position);
|
||||
return factory()->NewCountOperation(op,
|
||||
true /* prefix */,
|
||||
expression,
|
||||
position);
|
||||
|
||||
} else {
|
||||
return ParsePostfixExpression(ok);
|
||||
@ -2971,11 +2907,10 @@ Expression* Parser::ParsePostfixExpression(bool* ok) {
|
||||
Token::Value next = Next();
|
||||
int position = scanner().location().beg_pos;
|
||||
expression =
|
||||
new(zone()) CountOperation(isolate(),
|
||||
next,
|
||||
false /* postfix */,
|
||||
expression,
|
||||
position);
|
||||
factory()->NewCountOperation(next,
|
||||
false /* postfix */,
|
||||
expression,
|
||||
position);
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
@ -2998,7 +2933,7 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
|
||||
Consume(Token::LBRACK);
|
||||
int pos = scanner().location().beg_pos;
|
||||
Expression* index = ParseExpression(true, CHECK_OK);
|
||||
result = new(zone()) Property(isolate(), result, index, pos);
|
||||
result = factory()->NewProperty(result, index, pos);
|
||||
Expect(Token::RBRACK, CHECK_OK);
|
||||
break;
|
||||
}
|
||||
@ -3031,7 +2966,7 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
|
||||
callee->IsVariable(isolate()->factory()->eval_symbol())) {
|
||||
top_scope_->DeclarationScope()->RecordEvalCall();
|
||||
}
|
||||
result = NewCall(result, args, pos);
|
||||
result = factory()->NewCall(result, args, pos);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -3039,10 +2974,8 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
|
||||
Consume(Token::PERIOD);
|
||||
int pos = scanner().location().beg_pos;
|
||||
Handle<String> name = ParseIdentifierName(CHECK_OK);
|
||||
result = new(zone()) Property(isolate(),
|
||||
result,
|
||||
NewLiteral(name),
|
||||
pos);
|
||||
result =
|
||||
factory()->NewProperty(result, factory()->NewLiteral(name), pos);
|
||||
if (fni_ != NULL) fni_->PushLiteralName(name);
|
||||
break;
|
||||
}
|
||||
@ -3078,10 +3011,8 @@ Expression* Parser::ParseNewPrefix(PositionStack* stack, bool* ok) {
|
||||
|
||||
if (!stack->is_empty()) {
|
||||
int last = stack->pop();
|
||||
result = new(zone()) CallNew(isolate(),
|
||||
result,
|
||||
new(zone()) ZoneList<Expression*>(0),
|
||||
last);
|
||||
result = factory()->NewCallNew(
|
||||
result, new(zone()) ZoneList<Expression*>(0), last);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -3133,7 +3064,7 @@ Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack,
|
||||
Consume(Token::LBRACK);
|
||||
int pos = scanner().location().beg_pos;
|
||||
Expression* index = ParseExpression(true, CHECK_OK);
|
||||
result = new(zone()) Property(isolate(), result, index, pos);
|
||||
result = factory()->NewProperty(result, index, pos);
|
||||
if (fni_ != NULL) {
|
||||
if (index->IsPropertyName()) {
|
||||
fni_->PushLiteralName(index->AsLiteral()->AsPropertyName());
|
||||
@ -3149,10 +3080,8 @@ Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack,
|
||||
Consume(Token::PERIOD);
|
||||
int pos = scanner().location().beg_pos;
|
||||
Handle<String> name = ParseIdentifierName(CHECK_OK);
|
||||
result = new(zone()) Property(isolate(),
|
||||
result,
|
||||
NewLiteral(name),
|
||||
pos);
|
||||
result =
|
||||
factory()->NewProperty(result, factory()->NewLiteral(name), pos);
|
||||
if (fni_ != NULL) fni_->PushLiteralName(name);
|
||||
break;
|
||||
}
|
||||
@ -3161,7 +3090,7 @@ Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack,
|
||||
// Consume one of the new prefixes (already parsed).
|
||||
ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
|
||||
int last = stack->pop();
|
||||
result = new(zone()) CallNew(isolate(), result, args, last);
|
||||
result = factory()->NewCallNew(result, args, last);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -3180,7 +3109,7 @@ DebuggerStatement* Parser::ParseDebuggerStatement(bool* ok) {
|
||||
|
||||
Expect(Token::DEBUGGER, CHECK_OK);
|
||||
ExpectSemicolon(CHECK_OK);
|
||||
return new(zone()) DebuggerStatement();
|
||||
return factory()->NewDebuggerStatement();
|
||||
}
|
||||
|
||||
|
||||
@ -3245,33 +3174,31 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) {
|
||||
switch (peek()) {
|
||||
case Token::THIS: {
|
||||
Consume(Token::THIS);
|
||||
result = new(zone()) VariableProxy(isolate(), top_scope_->receiver());
|
||||
result = factory()->NewVariableProxy(top_scope_->receiver());
|
||||
break;
|
||||
}
|
||||
|
||||
case Token::NULL_LITERAL:
|
||||
Consume(Token::NULL_LITERAL);
|
||||
result = new(zone()) Literal(
|
||||
isolate(), isolate()->factory()->null_value());
|
||||
result = factory()->NewLiteral(isolate()->factory()->null_value());
|
||||
break;
|
||||
|
||||
case Token::TRUE_LITERAL:
|
||||
Consume(Token::TRUE_LITERAL);
|
||||
result = new(zone()) Literal(
|
||||
isolate(), isolate()->factory()->true_value());
|
||||
result = factory()->NewLiteral(isolate()->factory()->true_value());
|
||||
break;
|
||||
|
||||
case Token::FALSE_LITERAL:
|
||||
Consume(Token::FALSE_LITERAL);
|
||||
result = new(zone()) Literal(
|
||||
isolate(), isolate()->factory()->false_value());
|
||||
result = factory()->NewLiteral(isolate()->factory()->false_value());
|
||||
break;
|
||||
|
||||
case Token::IDENTIFIER:
|
||||
case Token::FUTURE_STRICT_RESERVED_WORD: {
|
||||
Handle<String> name = ParseIdentifier(CHECK_OK);
|
||||
if (fni_ != NULL) fni_->PushVariableName(name);
|
||||
result = top_scope_->NewUnresolved(name, scanner().location().beg_pos);
|
||||
result = top_scope_->NewUnresolved(
|
||||
factory(), name, scanner().location().beg_pos);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -3281,14 +3208,14 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) {
|
||||
double value = StringToDouble(isolate()->unicode_cache(),
|
||||
scanner().literal_ascii_string(),
|
||||
ALLOW_HEX | ALLOW_OCTALS);
|
||||
result = NewNumberLiteral(value);
|
||||
result = factory()->NewNumberLiteral(value);
|
||||
break;
|
||||
}
|
||||
|
||||
case Token::STRING: {
|
||||
Consume(Token::STRING);
|
||||
Handle<String> symbol = GetSymbol(CHECK_OK);
|
||||
result = NewLiteral(symbol);
|
||||
result = factory()->NewLiteral(symbol);
|
||||
if (fni_ != NULL) fni_->PushLiteralName(symbol);
|
||||
break;
|
||||
}
|
||||
@ -3482,8 +3409,8 @@ Expression* Parser::ParseArrayLiteral(bool* ok) {
|
||||
literals->set(0, Smi::FromInt(elements_kind));
|
||||
literals->set(1, *element_values);
|
||||
|
||||
return new(zone()) ArrayLiteral(
|
||||
isolate(), literals, values, literal_index, is_simple, depth);
|
||||
return factory()->NewArrayLiteral(
|
||||
literals, values, literal_index, is_simple, depth);
|
||||
}
|
||||
|
||||
|
||||
@ -3760,9 +3687,7 @@ ObjectLiteral::Property* Parser::ParseObjectLiteralGetSet(bool is_getter,
|
||||
CHECK_OK);
|
||||
// Allow any number of parameters for compatibilty with JSC.
|
||||
// Specification only allows zero parameters for get and one for set.
|
||||
ObjectLiteral::Property* property =
|
||||
new(zone()) ObjectLiteral::Property(is_getter, value);
|
||||
return property;
|
||||
return factory()->NewObjectLiteralProperty(is_getter, value);
|
||||
} else {
|
||||
ReportUnexpectedToken(next);
|
||||
*ok = false;
|
||||
@ -3827,7 +3752,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
|
||||
}
|
||||
// Failed to parse as get/set property, so it's just a property
|
||||
// called "get" or "set".
|
||||
key = NewLiteral(id);
|
||||
key = factory()->NewLiteral(id);
|
||||
break;
|
||||
}
|
||||
case Token::STRING: {
|
||||
@ -3836,10 +3761,10 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
|
||||
if (fni_ != NULL) fni_->PushLiteralName(string);
|
||||
uint32_t index;
|
||||
if (!string.is_null() && string->AsArrayIndex(&index)) {
|
||||
key = NewNumberLiteral(index);
|
||||
key = factory()->NewNumberLiteral(index);
|
||||
break;
|
||||
}
|
||||
key = NewLiteral(string);
|
||||
key = factory()->NewLiteral(string);
|
||||
break;
|
||||
}
|
||||
case Token::NUMBER: {
|
||||
@ -3848,14 +3773,14 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
|
||||
double value = StringToDouble(isolate()->unicode_cache(),
|
||||
scanner().literal_ascii_string(),
|
||||
ALLOW_HEX | ALLOW_OCTALS);
|
||||
key = NewNumberLiteral(value);
|
||||
key = factory()->NewNumberLiteral(value);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (Token::IsKeyword(next)) {
|
||||
Consume(next);
|
||||
Handle<String> string = GetSymbol(CHECK_OK);
|
||||
key = NewLiteral(string);
|
||||
key = factory()->NewLiteral(string);
|
||||
} else {
|
||||
// Unexpected token.
|
||||
Token::Value next = Next();
|
||||
@ -3910,14 +3835,13 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
|
||||
&is_simple,
|
||||
&fast_elements,
|
||||
&depth);
|
||||
return new(zone()) ObjectLiteral(isolate(),
|
||||
constant_properties,
|
||||
properties,
|
||||
literal_index,
|
||||
is_simple,
|
||||
fast_elements,
|
||||
depth,
|
||||
has_function);
|
||||
return factory()->NewObjectLiteral(constant_properties,
|
||||
properties,
|
||||
literal_index,
|
||||
is_simple,
|
||||
fast_elements,
|
||||
depth,
|
||||
has_function);
|
||||
}
|
||||
|
||||
|
||||
@ -3936,8 +3860,7 @@ Expression* Parser::ParseRegExpLiteral(bool seen_equal, bool* ok) {
|
||||
Handle<String> js_flags = NextLiteralString(TENURED);
|
||||
Next();
|
||||
|
||||
return new(zone()) RegExpLiteral(
|
||||
isolate(), js_pattern, js_flags, literal_index);
|
||||
return factory()->NewRegExpLiteral(js_pattern, js_flags, literal_index);
|
||||
}
|
||||
|
||||
|
||||
@ -3968,7 +3891,7 @@ ZoneList<Expression*>* Parser::ParseArguments(bool* ok) {
|
||||
class SingletonLogger : public ParserRecorder {
|
||||
public:
|
||||
SingletonLogger() : has_error_(false), start_(-1), end_(-1) { }
|
||||
~SingletonLogger() { }
|
||||
virtual ~SingletonLogger() { }
|
||||
|
||||
void Reset() { has_error_ = false; }
|
||||
|
||||
@ -4089,6 +4012,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
|
||||
bool only_simple_this_property_assignments;
|
||||
Handle<FixedArray> this_property_assignments;
|
||||
bool has_duplicate_parameters = false;
|
||||
AstProperties ast_properties;
|
||||
// Parse function body.
|
||||
{ FunctionState function_state(this, scope, isolate());
|
||||
top_scope_->SetScopeName(function_name);
|
||||
@ -4151,7 +4075,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
|
||||
} else {
|
||||
fvar_mode = CONST;
|
||||
}
|
||||
fvar = top_scope_->DeclareFunctionVar(function_name, fvar_mode);
|
||||
fvar =
|
||||
top_scope_->DeclareFunctionVar(function_name, fvar_mode, factory());
|
||||
}
|
||||
|
||||
// Determine whether the function will be lazily compiled.
|
||||
@ -4238,14 +4163,14 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
|
||||
if (!is_lazily_compiled) {
|
||||
body = new(zone()) ZoneList<Statement*>(8);
|
||||
if (fvar != NULL) {
|
||||
VariableProxy* fproxy = top_scope_->NewUnresolved(function_name);
|
||||
VariableProxy* fproxy =
|
||||
top_scope_->NewUnresolved(factory(), function_name);
|
||||
fproxy->BindTo(fvar);
|
||||
body->Add(new(zone()) ExpressionStatement(
|
||||
new(zone()) Assignment(isolate(),
|
||||
fvar_init_op,
|
||||
fproxy,
|
||||
new(zone()) ThisFunction(isolate()),
|
||||
RelocInfo::kNoPosition)));
|
||||
body->Add(factory()->NewExpressionStatement(
|
||||
factory()->NewAssignment(fvar_init_op,
|
||||
fproxy,
|
||||
factory()->NewThisFunction(),
|
||||
RelocInfo::kNoPosition)));
|
||||
}
|
||||
ParseSourceElements(body, Token::RBRACE, CHECK_OK);
|
||||
|
||||
@ -4306,6 +4231,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
|
||||
scope->end_position(),
|
||||
CHECK_OK);
|
||||
}
|
||||
ast_properties = *factory()->visitor()->ast_properties();
|
||||
}
|
||||
|
||||
if (is_extended_mode()) {
|
||||
@ -4313,19 +4239,20 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
|
||||
}
|
||||
|
||||
FunctionLiteral* function_literal =
|
||||
new(zone()) FunctionLiteral(isolate(),
|
||||
function_name,
|
||||
scope,
|
||||
body,
|
||||
materialized_literal_count,
|
||||
expected_property_count,
|
||||
handler_count,
|
||||
only_simple_this_property_assignments,
|
||||
this_property_assignments,
|
||||
num_parameters,
|
||||
type,
|
||||
has_duplicate_parameters);
|
||||
factory()->NewFunctionLiteral(function_name,
|
||||
scope,
|
||||
body,
|
||||
materialized_literal_count,
|
||||
expected_property_count,
|
||||
handler_count,
|
||||
only_simple_this_property_assignments,
|
||||
this_property_assignments,
|
||||
num_parameters,
|
||||
has_duplicate_parameters,
|
||||
type,
|
||||
true);
|
||||
function_literal->set_function_token_position(function_token_position);
|
||||
function_literal->set_ast_properties(&ast_properties);
|
||||
|
||||
if (fni_ != NULL && should_infer_name) fni_->AddFunction(function_literal);
|
||||
return function_literal;
|
||||
@ -4395,7 +4322,7 @@ Expression* Parser::ParseV8Intrinsic(bool* ok) {
|
||||
}
|
||||
|
||||
// We have a valid intrinsics call or a call to a builtin.
|
||||
return new(zone()) CallRuntime(isolate(), name, function, args);
|
||||
return factory()->NewCallRuntime(name, function, args);
|
||||
}
|
||||
|
||||
|
||||
@ -4451,17 +4378,12 @@ void Parser::ExpectSemicolon(bool* ok) {
|
||||
|
||||
|
||||
Literal* Parser::GetLiteralUndefined() {
|
||||
return NewLiteral(isolate()->factory()->undefined_value());
|
||||
return factory()->NewLiteral(isolate()->factory()->undefined_value());
|
||||
}
|
||||
|
||||
|
||||
Literal* Parser::GetLiteralTheHole() {
|
||||
return NewLiteral(isolate()->factory()->the_hole_value());
|
||||
}
|
||||
|
||||
|
||||
Literal* Parser::GetLiteralNumber(double value) {
|
||||
return NewNumberLiteral(value);
|
||||
return factory()->NewLiteral(isolate()->factory()->the_hole_value());
|
||||
}
|
||||
|
||||
|
||||
@ -4639,11 +4561,6 @@ void Parser::RegisterTargetUse(Label* target, Target* stop) {
|
||||
}
|
||||
|
||||
|
||||
Literal* Parser::NewNumberLiteral(double number) {
|
||||
return NewLiteral(isolate()->factory()->NewNumber(number, TENURED));
|
||||
}
|
||||
|
||||
|
||||
Expression* Parser::NewThrowReferenceError(Handle<String> type) {
|
||||
return NewThrowError(isolate()->factory()->MakeReferenceError_symbol(),
|
||||
type, HandleVector<Object>(NULL, 0));
|
||||
@ -4687,15 +4604,11 @@ Expression* Parser::NewThrowError(Handle<String> constructor,
|
||||
elements, FAST_ELEMENTS, TENURED);
|
||||
|
||||
ZoneList<Expression*>* args = new(zone()) ZoneList<Expression*>(2);
|
||||
args->Add(NewLiteral(type));
|
||||
args->Add(NewLiteral(array));
|
||||
CallRuntime* call_constructor = new(zone()) CallRuntime(isolate(),
|
||||
constructor,
|
||||
NULL,
|
||||
args);
|
||||
return new(zone()) Throw(isolate(),
|
||||
call_constructor,
|
||||
scanner().location().beg_pos);
|
||||
args->Add(factory()->NewLiteral(type));
|
||||
args->Add(factory()->NewLiteral(array));
|
||||
CallRuntime* call_constructor =
|
||||
factory()->NewCallRuntime(constructor, NULL, args);
|
||||
return factory()->NewThrow(call_constructor, scanner().location().beg_pos);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -5667,7 +5580,7 @@ bool ParserApi::Parse(CompilationInfo* info, int parsing_flags) {
|
||||
parsing_flags |= EXTENDED_MODE;
|
||||
}
|
||||
if (FLAG_allow_natives_syntax || info->is_native()) {
|
||||
// We requre %identifier(..) syntax.
|
||||
// We require %identifier(..) syntax.
|
||||
parsing_flags |= kAllowNativesSyntax;
|
||||
}
|
||||
if (info->is_lazy()) {
|
||||
|
95
src/parser.h
95
src/parser.h
@ -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:
|
||||
@ -435,9 +435,8 @@ class Parser {
|
||||
v8::Extension* extension,
|
||||
ScriptDataImpl* pre_data);
|
||||
virtual ~Parser() {
|
||||
if (reusable_preparser_ != NULL) {
|
||||
delete reusable_preparser_;
|
||||
}
|
||||
delete reusable_preparser_;
|
||||
reusable_preparser_ = NULL;
|
||||
}
|
||||
|
||||
// Returns NULL if parsing failed.
|
||||
@ -477,7 +476,69 @@ class Parser {
|
||||
};
|
||||
|
||||
class BlockState;
|
||||
class FunctionState;
|
||||
|
||||
class FunctionState BASE_EMBEDDED {
|
||||
public:
|
||||
FunctionState(Parser* parser,
|
||||
Scope* scope,
|
||||
Isolate* isolate);
|
||||
~FunctionState();
|
||||
|
||||
int NextMaterializedLiteralIndex() {
|
||||
return next_materialized_literal_index_++;
|
||||
}
|
||||
int materialized_literal_count() {
|
||||
return next_materialized_literal_index_ - JSFunction::kLiteralsPrefixSize;
|
||||
}
|
||||
|
||||
int NextHandlerIndex() { return next_handler_index_++; }
|
||||
int handler_count() { return next_handler_index_; }
|
||||
|
||||
void SetThisPropertyAssignmentInfo(
|
||||
bool only_simple_this_property_assignments,
|
||||
Handle<FixedArray> this_property_assignments) {
|
||||
only_simple_this_property_assignments_ =
|
||||
only_simple_this_property_assignments;
|
||||
this_property_assignments_ = this_property_assignments;
|
||||
}
|
||||
bool only_simple_this_property_assignments() {
|
||||
return only_simple_this_property_assignments_;
|
||||
}
|
||||
Handle<FixedArray> this_property_assignments() {
|
||||
return this_property_assignments_;
|
||||
}
|
||||
|
||||
void AddProperty() { expected_property_count_++; }
|
||||
int expected_property_count() { return expected_property_count_; }
|
||||
|
||||
AstNodeFactory<AstConstructionVisitor>* factory() { return &factory_; }
|
||||
|
||||
private:
|
||||
// Used to assign an index to each literal that needs materialization in
|
||||
// the function. Includes regexp literals, and boilerplate for object and
|
||||
// array literals.
|
||||
int next_materialized_literal_index_;
|
||||
|
||||
// Used to assign a per-function index to try and catch handlers.
|
||||
int next_handler_index_;
|
||||
|
||||
// Properties count estimation.
|
||||
int expected_property_count_;
|
||||
|
||||
// Keeps track of assignments to properties of this. Used for
|
||||
// optimizing constructors.
|
||||
bool only_simple_this_property_assignments_;
|
||||
Handle<FixedArray> this_property_assignments_;
|
||||
|
||||
Parser* parser_;
|
||||
FunctionState* outer_function_state_;
|
||||
Scope* outer_scope_;
|
||||
int saved_ast_node_id_;
|
||||
AstNodeFactory<AstConstructionVisitor> factory_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
FunctionLiteral* ParseLazy(CompilationInfo* info,
|
||||
UC16CharacterStream* source,
|
||||
@ -651,7 +712,6 @@ class Parser {
|
||||
// Get odd-ball literals.
|
||||
Literal* GetLiteralUndefined();
|
||||
Literal* GetLiteralTheHole();
|
||||
Literal* GetLiteralNumber(double value);
|
||||
|
||||
Handle<String> ParseIdentifier(bool* ok);
|
||||
Handle<String> ParseIdentifierOrStrictReservedWord(
|
||||
@ -699,31 +759,12 @@ class Parser {
|
||||
|
||||
// Factory methods.
|
||||
|
||||
Statement* EmptyStatement() {
|
||||
static v8::internal::EmptyStatement* empty =
|
||||
::new v8::internal::EmptyStatement();
|
||||
return empty;
|
||||
}
|
||||
|
||||
Scope* NewScope(Scope* parent, ScopeType type);
|
||||
|
||||
Handle<String> LookupSymbol(int symbol_id);
|
||||
|
||||
Handle<String> LookupCachedSymbol(int symbol_id);
|
||||
|
||||
Expression* NewCall(Expression* expression,
|
||||
ZoneList<Expression*>* arguments,
|
||||
int pos) {
|
||||
return new(zone()) Call(isolate(), expression, arguments, pos);
|
||||
}
|
||||
|
||||
inline Literal* NewLiteral(Handle<Object> handle) {
|
||||
return new(zone()) Literal(isolate(), handle);
|
||||
}
|
||||
|
||||
// Create a number literal.
|
||||
Literal* NewNumberLiteral(double value);
|
||||
|
||||
// Generate AST node that throw a ReferenceError with the given type.
|
||||
Expression* NewThrowReferenceError(Handle<String> type);
|
||||
|
||||
@ -746,6 +787,10 @@ class Parser {
|
||||
preparser::PreParser::PreParseResult LazyParseFunctionLiteral(
|
||||
SingletonLogger* logger);
|
||||
|
||||
AstNodeFactory<AstConstructionVisitor>* factory() {
|
||||
return current_function_state_->factory();
|
||||
}
|
||||
|
||||
Isolate* isolate_;
|
||||
ZoneList<Handle<String> > symbol_cache_;
|
||||
|
||||
|
@ -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:
|
||||
@ -42,12 +42,18 @@ class Processor: public AstVisitor {
|
||||
: result_(result),
|
||||
result_assigned_(false),
|
||||
is_set_(false),
|
||||
in_try_(false) {
|
||||
}
|
||||
in_try_(false),
|
||||
factory_(isolate()) { }
|
||||
|
||||
virtual ~Processor() { }
|
||||
|
||||
void Process(ZoneList<Statement*>* statements);
|
||||
bool result_assigned() const { return result_assigned_; }
|
||||
|
||||
AstNodeFactory<AstNullVisitor>* factory() {
|
||||
return &factory_;
|
||||
}
|
||||
|
||||
private:
|
||||
Variable* result_;
|
||||
|
||||
@ -64,15 +70,13 @@ class Processor: public AstVisitor {
|
||||
bool is_set_;
|
||||
bool in_try_;
|
||||
|
||||
AstNodeFactory<AstNullVisitor> factory_;
|
||||
|
||||
Expression* SetResult(Expression* value) {
|
||||
result_assigned_ = true;
|
||||
Zone* zone = isolate()->zone();
|
||||
VariableProxy* result_proxy = new(zone) VariableProxy(isolate(), result_);
|
||||
return new(zone) Assignment(isolate(),
|
||||
Token::ASSIGN,
|
||||
result_proxy,
|
||||
value,
|
||||
RelocInfo::kNoPosition);
|
||||
VariableProxy* result_proxy = factory()->NewVariableProxy(result_);
|
||||
return factory()->NewAssignment(
|
||||
Token::ASSIGN, result_proxy, value, RelocInfo::kNoPosition);
|
||||
}
|
||||
|
||||
// Node visitors.
|
||||
@ -237,8 +241,6 @@ bool Rewriter::Rewrite(CompilationInfo* info) {
|
||||
|
||||
if (processor.result_assigned()) {
|
||||
ASSERT(function->end_position() != RelocInfo::kNoPosition);
|
||||
Isolate* isolate = info->isolate();
|
||||
Zone* zone = isolate->zone();
|
||||
// Set the position of the assignment statement one character past the
|
||||
// source code, such that it definitely is not in the source code range
|
||||
// of an immediate inner scope. For example in
|
||||
@ -246,10 +248,11 @@ bool Rewriter::Rewrite(CompilationInfo* info) {
|
||||
// the end position of the function generated for executing the eval code
|
||||
// coincides with the end of the with scope which is the position of '1'.
|
||||
int position = function->end_position();
|
||||
VariableProxy* result_proxy = new(zone) VariableProxy(
|
||||
isolate, result->name(), false, position);
|
||||
VariableProxy* result_proxy = processor.factory()->NewVariableProxy(
|
||||
result->name(), false, position);
|
||||
result_proxy->BindTo(result);
|
||||
Statement* result_statement = new(zone) ReturnStatement(result_proxy);
|
||||
Statement* result_statement =
|
||||
processor.factory()->NewReturnStatement(result_proxy);
|
||||
result_statement->set_statement_pos(position);
|
||||
body->Add(result_statement);
|
||||
}
|
||||
|
@ -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:
|
||||
@ -272,8 +272,11 @@ bool Scope::Analyze(CompilationInfo* info) {
|
||||
top = top->outer_scope();
|
||||
}
|
||||
|
||||
// Allocated the variables.
|
||||
top->AllocateVariables(info->global_scope());
|
||||
// Allocate the variables.
|
||||
{
|
||||
AstNodeFactory<AstNullVisitor> ast_node_factory(info->isolate());
|
||||
top->AllocateVariables(info->global_scope(), &ast_node_factory);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (info->isolate()->bootstrapper()->IsActive()
|
||||
@ -415,7 +418,8 @@ Variable* Scope::LocalLookup(Handle<String> name) {
|
||||
}
|
||||
|
||||
|
||||
Variable* Scope::LookupFunctionVar(Handle<String> name) {
|
||||
Variable* Scope::LookupFunctionVar(Handle<String> name,
|
||||
AstNodeFactory<AstNullVisitor>* factory) {
|
||||
if (function_ != NULL && function_->name().is_identical_to(name)) {
|
||||
return function_->var();
|
||||
} else if (!scope_info_.is_null()) {
|
||||
@ -423,7 +427,7 @@ Variable* Scope::LookupFunctionVar(Handle<String> name) {
|
||||
VariableMode mode;
|
||||
int index = scope_info_->FunctionContextSlotIndex(*name, &mode);
|
||||
if (index < 0) return NULL;
|
||||
Variable* var = DeclareFunctionVar(name, mode);
|
||||
Variable* var = DeclareFunctionVar(name, mode, factory);
|
||||
var->AllocateTo(Variable::CONTEXT, index);
|
||||
return var;
|
||||
} else {
|
||||
@ -443,15 +447,6 @@ Variable* Scope::Lookup(Handle<String> name) {
|
||||
}
|
||||
|
||||
|
||||
Variable* Scope::DeclareFunctionVar(Handle<String> name, VariableMode mode) {
|
||||
ASSERT(is_function_scope() && function_ == NULL);
|
||||
Variable* function_var = new Variable(
|
||||
this, name, mode, true, Variable::NORMAL, kCreatedInitialized);
|
||||
function_ = new(isolate_->zone()) VariableProxy(isolate_, function_var);
|
||||
return function_var;
|
||||
}
|
||||
|
||||
|
||||
void Scope::DeclareParameter(Handle<String> name, VariableMode mode) {
|
||||
ASSERT(!already_resolved());
|
||||
ASSERT(is_function_scope());
|
||||
@ -489,18 +484,6 @@ Variable* Scope::DeclareGlobal(Handle<String> name) {
|
||||
}
|
||||
|
||||
|
||||
VariableProxy* Scope::NewUnresolved(Handle<String> name, int position) {
|
||||
// Note that we must not share the unresolved variables with
|
||||
// the same name because they may be removed selectively via
|
||||
// RemoveUnresolved().
|
||||
ASSERT(!already_resolved());
|
||||
VariableProxy* proxy = new(isolate_->zone()) VariableProxy(
|
||||
isolate_, name, false, position);
|
||||
unresolved_.Add(proxy);
|
||||
return proxy;
|
||||
}
|
||||
|
||||
|
||||
void Scope::RemoveUnresolved(VariableProxy* var) {
|
||||
// Most likely (always?) any variable we want to remove
|
||||
// was just added before, so we search backwards.
|
||||
@ -623,7 +606,8 @@ void Scope::CollectStackAndContextLocals(ZoneList<Variable*>* stack_locals,
|
||||
}
|
||||
|
||||
|
||||
void Scope::AllocateVariables(Scope* global_scope) {
|
||||
void Scope::AllocateVariables(Scope* global_scope,
|
||||
AstNodeFactory<AstNullVisitor>* factory) {
|
||||
// 1) Propagate scope information.
|
||||
bool outer_scope_calls_non_strict_eval = false;
|
||||
if (outer_scope_ != NULL) {
|
||||
@ -634,7 +618,7 @@ void Scope::AllocateVariables(Scope* global_scope) {
|
||||
PropagateScopeInfo(outer_scope_calls_non_strict_eval);
|
||||
|
||||
// 2) Resolve variables.
|
||||
ResolveVariablesRecursively(global_scope);
|
||||
ResolveVariablesRecursively(global_scope, factory);
|
||||
|
||||
// 3) Allocate variables.
|
||||
AllocateVariablesRecursively();
|
||||
@ -897,7 +881,8 @@ Variable* Scope::NonLocal(Handle<String> name, VariableMode mode) {
|
||||
|
||||
|
||||
Variable* Scope::LookupRecursive(Handle<String> name,
|
||||
BindingKind* binding_kind) {
|
||||
BindingKind* binding_kind,
|
||||
AstNodeFactory<AstNullVisitor>* factory) {
|
||||
ASSERT(binding_kind != NULL);
|
||||
// Try to find the variable in this scope.
|
||||
Variable* var = LocalLookup(name);
|
||||
@ -914,11 +899,11 @@ Variable* Scope::LookupRecursive(Handle<String> name,
|
||||
// if any. We can do this for all scopes, since the function variable is
|
||||
// only present - if at all - for function scopes.
|
||||
*binding_kind = UNBOUND;
|
||||
var = LookupFunctionVar(name);
|
||||
var = LookupFunctionVar(name, factory);
|
||||
if (var != NULL) {
|
||||
*binding_kind = BOUND;
|
||||
} else if (outer_scope_ != NULL) {
|
||||
var = outer_scope_->LookupRecursive(name, binding_kind);
|
||||
var = outer_scope_->LookupRecursive(name, binding_kind, factory);
|
||||
if (*binding_kind == BOUND && (is_function_scope() || is_with_scope())) {
|
||||
var->ForceContextAllocation();
|
||||
}
|
||||
@ -951,7 +936,8 @@ Variable* Scope::LookupRecursive(Handle<String> name,
|
||||
|
||||
|
||||
void Scope::ResolveVariable(Scope* global_scope,
|
||||
VariableProxy* proxy) {
|
||||
VariableProxy* proxy,
|
||||
AstNodeFactory<AstNullVisitor>* factory) {
|
||||
ASSERT(global_scope == NULL || global_scope->is_global_scope());
|
||||
|
||||
// If the proxy is already resolved there's nothing to do
|
||||
@ -960,7 +946,7 @@ void Scope::ResolveVariable(Scope* global_scope,
|
||||
|
||||
// Otherwise, try to resolve the variable.
|
||||
BindingKind binding_kind;
|
||||
Variable* var = LookupRecursive(proxy->name(), &binding_kind);
|
||||
Variable* var = LookupRecursive(proxy->name(), &binding_kind, factory);
|
||||
switch (binding_kind) {
|
||||
case BOUND:
|
||||
// We found a variable binding.
|
||||
@ -1001,17 +987,19 @@ void Scope::ResolveVariable(Scope* global_scope,
|
||||
}
|
||||
|
||||
|
||||
void Scope::ResolveVariablesRecursively(Scope* global_scope) {
|
||||
void Scope::ResolveVariablesRecursively(
|
||||
Scope* global_scope,
|
||||
AstNodeFactory<AstNullVisitor>* factory) {
|
||||
ASSERT(global_scope == NULL || global_scope->is_global_scope());
|
||||
|
||||
// Resolve unresolved variables for this scope.
|
||||
for (int i = 0; i < unresolved_.length(); i++) {
|
||||
ResolveVariable(global_scope, unresolved_[i]);
|
||||
ResolveVariable(global_scope, unresolved_[i], factory);
|
||||
}
|
||||
|
||||
// Resolve unresolved variables for inner scopes.
|
||||
for (int i = 0; i < inner_scopes_.length(); i++) {
|
||||
inner_scopes_[i]->ResolveVariablesRecursively(global_scope);
|
||||
inner_scopes_[i]->ResolveVariablesRecursively(global_scope, factory);
|
||||
}
|
||||
}
|
||||
|
||||
|
42
src/scopes.h
42
src/scopes.h
@ -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:
|
||||
@ -115,7 +115,8 @@ class Scope: public ZoneObject {
|
||||
// between this scope and the outer scope. (ECMA-262, 3rd., requires that
|
||||
// the name of named function literal is kept in an intermediate scope
|
||||
// in between this scope and the next outer scope.)
|
||||
Variable* LookupFunctionVar(Handle<String> name);
|
||||
Variable* LookupFunctionVar(Handle<String> name,
|
||||
AstNodeFactory<AstNullVisitor>* factory);
|
||||
|
||||
// Lookup a variable in this scope or outer scopes.
|
||||
// Returns the variable or NULL if not found.
|
||||
@ -124,7 +125,16 @@ class Scope: public ZoneObject {
|
||||
// Declare the function variable for a function literal. This variable
|
||||
// is in an intermediate scope between this function scope and the the
|
||||
// outer scope. Only possible for function scopes; at most one variable.
|
||||
Variable* DeclareFunctionVar(Handle<String> name, VariableMode mode);
|
||||
template<class Visitor>
|
||||
Variable* DeclareFunctionVar(Handle<String> name,
|
||||
VariableMode mode,
|
||||
AstNodeFactory<Visitor>* factory) {
|
||||
ASSERT(is_function_scope() && function_ == NULL);
|
||||
Variable* function_var = new Variable(
|
||||
this, name, mode, true, Variable::NORMAL, kCreatedInitialized);
|
||||
function_ = factory->NewVariableProxy(function_var);
|
||||
return function_var;
|
||||
}
|
||||
|
||||
// Declare a parameter in this scope. When there are duplicated
|
||||
// parameters the rightmost one 'wins'. However, the implementation
|
||||
@ -144,8 +154,18 @@ class Scope: public ZoneObject {
|
||||
Variable* DeclareGlobal(Handle<String> name);
|
||||
|
||||
// Create a new unresolved variable.
|
||||
VariableProxy* NewUnresolved(Handle<String> name,
|
||||
int position = RelocInfo::kNoPosition);
|
||||
template<class Visitor>
|
||||
VariableProxy* NewUnresolved(AstNodeFactory<Visitor>* factory,
|
||||
Handle<String> name,
|
||||
int position = RelocInfo::kNoPosition) {
|
||||
// Note that we must not share the unresolved variables with
|
||||
// the same name because they may be removed selectively via
|
||||
// RemoveUnresolved().
|
||||
ASSERT(!already_resolved());
|
||||
VariableProxy* proxy = factory->NewVariableProxy(name, false, position);
|
||||
unresolved_.Add(proxy);
|
||||
return proxy;
|
||||
}
|
||||
|
||||
// Remove a unresolved variable. During parsing, an unresolved variable
|
||||
// may have been added optimistically, but then only the variable name
|
||||
@ -332,7 +352,8 @@ class Scope: public ZoneObject {
|
||||
// In the case of code compiled and run using 'eval', the context
|
||||
// parameter is the context in which eval was called. In all other
|
||||
// cases the context parameter is an empty handle.
|
||||
void AllocateVariables(Scope* global_scope);
|
||||
void AllocateVariables(Scope* global_scope,
|
||||
AstNodeFactory<AstNullVisitor>* factory);
|
||||
|
||||
// Current number of var or const locals.
|
||||
int num_var_or_const() { return num_var_or_const_; }
|
||||
@ -519,10 +540,13 @@ class Scope: public ZoneObject {
|
||||
// scope. If the code is executed because of a call to 'eval', the context
|
||||
// parameter should be set to the calling context of 'eval'.
|
||||
Variable* LookupRecursive(Handle<String> name,
|
||||
BindingKind* binding_kind);
|
||||
BindingKind* binding_kind,
|
||||
AstNodeFactory<AstNullVisitor>* factory);
|
||||
void ResolveVariable(Scope* global_scope,
|
||||
VariableProxy* proxy);
|
||||
void ResolveVariablesRecursively(Scope* global_scope);
|
||||
VariableProxy* proxy,
|
||||
AstNodeFactory<AstNullVisitor>* factory);
|
||||
void ResolveVariablesRecursively(Scope* global_scope,
|
||||
AstNodeFactory<AstNullVisitor>* factory);
|
||||
|
||||
// Scope analysis.
|
||||
bool PropagateScopeInfo(bool outer_scope_calls_non_strict_eval);
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2006-2008 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:
|
||||
@ -40,7 +40,8 @@ TEST(List) {
|
||||
CHECK_EQ(0, list->length());
|
||||
|
||||
ZoneScope zone_scope(Isolate::Current(), DELETE_ON_EXIT);
|
||||
AstNode* node = new(ZONE) EmptyStatement();
|
||||
AstNodeFactory<AstNullVisitor> factory(Isolate::Current());
|
||||
AstNode* node = factory.NewEmptyStatement();
|
||||
list->Add(node);
|
||||
CHECK_EQ(1, list->length());
|
||||
CHECK_EQ(node, list->at(0));
|
||||
|
Loading…
Reference in New Issue
Block a user