}
-bool FunctionLiteral::uses_super_property() const {
- DCHECK_NOT_NULL(scope());
- return scope()->uses_super_property();
+bool FunctionLiteral::NeedsHomeObject(Expression* expr) {
+ if (expr == nullptr || !expr->IsFunctionLiteral()) return false;
+ DCHECK_NOT_NULL(expr->AsFunctionLiteral()->scope());
+ return expr->AsFunctionLiteral()->scope()->NeedsHomeObject();
}
bool is_expression() const { return IsExpression::decode(bitfield_); }
bool is_anonymous() const { return IsAnonymous::decode(bitfield_); }
LanguageMode language_mode() const;
- bool uses_super_property() const;
- static bool NeedsHomeObject(Expression* literal) {
- return literal != NULL && literal->IsFunctionLiteral() &&
- literal->AsFunctionLiteral()->uses_super_property();
- }
+ static bool NeedsHomeObject(Expression* expr);
int materialized_literal_count() { return materialized_literal_count_; }
int expected_property_count() { return expected_property_count_; }
bitfield_ = ShouldBeUsedOnceHintBit::update(bitfield_, kShouldBeUsedOnce);
}
- FunctionKind kind() { return FunctionKindBits::decode(bitfield_); }
+ FunctionKind kind() const { return FunctionKindBits::decode(bitfield_); }
int ast_node_count() { return ast_properties_.node_count(); }
AstProperties::Flags* flags() { return ast_properties_.flags(); }
Variable* rest_parameter = scope->rest_parameter(&rest_index);
BuildRestArgumentsArray(rest_parameter, rest_index);
+ if (scope->this_function_var() != nullptr ||
+ scope->new_target_var() != nullptr) {
+ SetStackOverflow();
+ }
+
// Emit tracing call if requested to do so.
if (FLAG_trace) {
NewNode(javascript()->CallRuntime(Runtime::kTraceEnter, 0));
if (rest) {
return Bailout(kRestParameter);
}
+
+ if (scope->this_function_var() != nullptr ||
+ scope->new_target_var() != nullptr) {
+ return Bailout(kSuperReference);
+ }
}
}
-BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, uses_super_property,
- kUsesSuperProperty)
+BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, needs_home_object,
+ kNeedsHomeObject)
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, native, kNative)
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, force_inline, kForceInline)
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints,
shared_info->set_dont_cache(
lit->flags()->Contains(AstPropertiesFlag::kDontCache));
shared_info->set_kind(lit->kind());
- shared_info->set_uses_super_property(lit->uses_super_property());
+ shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject());
shared_info->set_asm_function(lit->scope()->asm_function());
}
// False if the function definitely does not allocate an arguments object.
DECL_BOOLEAN_ACCESSORS(uses_arguments)
- // Indicates that this function uses a super property.
+ // Indicates that this function uses a super property (or an eval that may
+ // use a super property).
// This is needed to set up the [[HomeObject]] on the function instance.
- DECL_BOOLEAN_ACCESSORS(uses_super_property)
+ DECL_BOOLEAN_ACCESSORS(needs_home_object)
// True if the function has any duplicated parameter names.
DECL_BOOLEAN_ACCESSORS(has_duplicate_parameters)
kStrictModeFunction,
kStrongModeFunction,
kUsesArguments,
- kUsesSuperProperty,
+ kNeedsHomeObject,
kHasDuplicateParameters,
kNative,
kForceInline,
*expected_property_count = entry.property_count();
scope_->SetLanguageMode(entry.language_mode());
if (entry.uses_super_property()) scope_->RecordSuperPropertyUsage();
+ if (entry.calls_eval()) scope_->RecordEvalCall();
return;
}
cached_parse_data_->Reject();
*materialized_literal_count = logger.literals();
*expected_property_count = logger.properties();
scope_->SetLanguageMode(logger.language_mode());
- if (logger.scope_uses_super_property()) {
+ if (logger.uses_super_property()) {
scope_->RecordSuperPropertyUsage();
}
+ if (logger.calls_eval()) {
+ scope_->RecordEvalCall();
+ }
if (produce_cached_parse_data()) {
DCHECK(log_);
// Position right after terminal '}'.
int body_end = scanner()->location().end_pos;
log_->LogFunction(function_block_pos, body_end, *materialized_literal_count,
*expected_property_count, scope_->language_mode(),
- scope_->uses_super_property());
+ scope_->uses_super_property(), scope_->calls_eval());
}
}
kPropertyCountIndex,
kLanguageModeIndex,
kUsesSuperPropertyIndex,
+ kCallsEvalIndex,
kSize
};
return static_cast<LanguageMode>(backing_[kLanguageModeIndex]);
}
bool uses_super_property() { return backing_[kUsesSuperPropertyIndex]; }
+ bool calls_eval() { return backing_[kCallsEvalIndex]; }
bool is_valid() { return !backing_.is_empty(); }
public:
// Layout and constants of the preparse data exchange format.
static const unsigned kMagicNumber = 0xBadDead;
- static const unsigned kCurrentVersion = 10;
+ static const unsigned kCurrentVersion = 11;
static const int kMagicOffset = 0;
static const int kVersionOffset = 1;
// Logs the scope and some details of a function literal in the source.
virtual void LogFunction(int start, int end, int literals, int properties,
- LanguageMode language_mode,
- bool uses_super_property) = 0;
+ LanguageMode language_mode, bool uses_super_property,
+ bool calls_eval) = 0;
// Logs an error message and marks the log as containing an error.
// Further logging will be ignored, and ExtractData will return a vector
void Reset() { has_error_ = false; }
virtual void LogFunction(int start, int end, int literals, int properties,
- LanguageMode language_mode,
- bool scope_uses_super_property) {
+ LanguageMode language_mode, bool uses_super_property,
+ bool calls_eval) {
DCHECK(!has_error_);
start_ = start;
end_ = end;
literals_ = literals;
properties_ = properties;
language_mode_ = language_mode;
- scope_uses_super_property_ = scope_uses_super_property;
+ uses_super_property_ = uses_super_property;
+ calls_eval_ = calls_eval;
}
// Logs an error message and marks the log as containing an error.
DCHECK(!has_error_);
return language_mode_;
}
- bool scope_uses_super_property() const {
+ bool uses_super_property() const {
DCHECK(!has_error_);
- return scope_uses_super_property_;
+ return uses_super_property_;
+ }
+ bool calls_eval() const {
+ DCHECK(!has_error_);
+ return calls_eval_;
}
ParseErrorType error_type() const {
DCHECK(has_error_);
int literals_;
int properties_;
LanguageMode language_mode_;
- bool scope_uses_super_property_;
+ bool uses_super_property_;
+ bool calls_eval_;
// For error messages.
MessageTemplate::Template message_;
const char* argument_opt_;
virtual ~CompleteParserRecorder() {}
virtual void LogFunction(int start, int end, int literals, int properties,
- LanguageMode language_mode,
- bool scope_uses_super_property) {
+ LanguageMode language_mode, bool uses_super_property,
+ bool calls_eval) {
function_store_.Add(start);
function_store_.Add(end);
function_store_.Add(literals);
function_store_.Add(properties);
function_store_.Add(language_mode);
- function_store_.Add(scope_uses_super_property);
+ function_store_.Add(uses_super_property);
+ function_store_.Add(calls_eval);
}
// Logs an error message and marks the log as containing an error.
log_->LogFunction(body_start, body_end,
function_state_->materialized_literal_count(),
function_state_->expected_property_count(), language_mode(),
- scope_->uses_super_property());
+ scope_->uses_super_property(), scope_->calls_eval());
}
static void CheckAssigningFunctionLiteralToProperty(
PreParserExpression left, PreParserExpression right) {}
- // PreParser doesn't need to keep track of eval calls.
static void CheckPossibleEvalCall(PreParserExpression expression,
- Scope* scope) {}
+ Scope* scope) {
+ if (IsIdentifier(expression) && IsEval(AsIdentifier(expression))) {
+ scope->DeclarationScope()->RecordEvalCall();
+ scope->RecordEvalCall();
+ }
+ }
static PreParserExpression MarkExpressionAsAssigned(
PreParserExpression expression) {
bool inner_uses_arguments() const { return inner_scope_uses_arguments_; }
// Does this scope access "super" property (super.foo).
bool uses_super_property() const { return scope_uses_super_property_; }
- // Does any inner scope access "super" property.
- bool inner_uses_super_property() const {
- return inner_scope_uses_super_property_;
+
+ bool NeedsHomeObject() const {
+ return scope_uses_super_property_ ||
+ (scope_calls_eval_ && (IsConciseMethod(function_kind()) ||
+ IsAccessorFunction(function_kind()) ||
+ IsConstructor(function_kind())));
}
const Scope* NearestOuterEvalScope() const {
bool outer_scope_calls_sloppy_eval_;
bool inner_scope_calls_eval_;
bool inner_scope_uses_arguments_;
- bool inner_scope_uses_super_property_;
bool force_eager_compilation_;
bool force_context_allocation_;
SUPER_PROPERTY = 1 << 1,
THIS = 1 << 2,
INNER_ARGUMENTS = 1 << 3,
+ EVAL = 1 << 4
};
// clang-format off
" let x; return { m() { return this + super.m() + arguments } }"
"}",
NONE},
+ {"eval(42)", EVAL},
+ {"if (1) { eval(42) }", EVAL},
+ {"eval('super.x')", EVAL},
+ {"eval('this.x')", EVAL},
+ {"eval('arguments')", EVAL},
};
// clang-format on
}
CHECK_EQ((source_data[i].expected & INNER_ARGUMENTS) != 0,
scope->inner_uses_arguments());
+ CHECK_EQ((source_data[i].expected & EVAL) != 0, scope->calls_eval());
}
}
}
m() {
return super.m();
}
+ evalM() {
+ return eval('super.m()');
+ }
}
assertEquals(42, new Derived().m());
+assertEquals(42, new Derived().evalM());
+
+
+class LazyDerived extends Base {
+ constructor() {
+ eval('super()');
+ }
+}
+assertInstanceof(new LazyDerived(), LazyDerived);
+assertInstanceof(new LazyDerived(), Base);
};
var o = {
__proto__: p,
- eval() {
- assertSame(super.x, eval('super.x'));
- assertSame(super.m(), eval('super.m()'));
- // Global eval.
+ evalM() {
+ assertEquals(1, eval('super.m()'));
+ },
+ evalX() {
+ assertEquals(2, eval('super.x'));
+ },
+ globalEval1() {
+ assertThrows('super.x', SyntaxError);
+ assertThrows('super.m()', SyntaxError);
+ },
+ globalEval2() {
+ super.x;
assertThrows('super.x', SyntaxError);
assertThrows('super.m()', SyntaxError);
- return eval('super.m()');
}
};
- assertSame(1, o.eval());
+ o.evalM();
+ o.evalX();
+ o.globalEval1();
+ o.globalEval2();
})();
get x() { return 2; }
}
class Derived extends Base {
- eval() {
- assertSame(super.x, eval('super.x'));
- assertSame(super.m(), eval('super.m()'));
- // Global eval.
+ evalM() {
+ assertEquals(1, eval('super.m()'));
+ }
+ evalX() {
+ assertEquals(2, eval('super.x'));
+ }
+ globalEval1() {
+ assertThrows('super.x', SyntaxError);
+ assertThrows('super.m()', SyntaxError);
+ }
+ globalEval2() {
+ super.x;
assertThrows('super.x', SyntaxError);
assertThrows('super.m()', SyntaxError);
- return eval('super.m()');
}
}
let d = new Derived();
- assertSame(1, d.eval());
+ d.globalEval1();
+ d.globalEval2();
+ d.evalM();
+ d.evalX();
})();