2012-02-14 14:14:51 +00:00
|
|
|
// Copyright 2012 the V8 project authors. All rights reserved.
|
2014-04-29 06:42:26 +00:00
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
2008-07-03 15:10:15 +00:00
|
|
|
|
|
|
|
#ifndef V8_COMPILER_H_
|
|
|
|
#define V8_COMPILER_H_
|
|
|
|
|
2011-05-06 06:50:20 +00:00
|
|
|
#include "allocation.h"
|
2010-02-08 14:33:34 +00:00
|
|
|
#include "ast.h"
|
2009-05-14 12:18:25 +00:00
|
|
|
#include "zone.h"
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2009-05-25 10:05:56 +00:00
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2014-04-11 11:44:49 +00:00
|
|
|
class ScriptData;
|
2012-12-18 16:25:45 +00:00
|
|
|
class HydrogenCodeStub;
|
2010-10-01 14:10:47 +00:00
|
|
|
|
2013-03-07 15:46:14 +00:00
|
|
|
// ParseRestriction is used to restrict the set of valid statements in a
|
|
|
|
// unit of compilation. Restriction violations cause a syntax error.
|
|
|
|
enum ParseRestriction {
|
|
|
|
NO_PARSE_RESTRICTION, // All expressions are allowed.
|
|
|
|
ONLY_SINGLE_FUNCTION_LITERAL // Only a single FunctionLiteral expression.
|
|
|
|
};
|
|
|
|
|
2014-03-19 13:24:13 +00:00
|
|
|
enum CachedDataMode {
|
|
|
|
NO_CACHED_DATA,
|
|
|
|
CONSUME_CACHED_DATA,
|
|
|
|
PRODUCE_CACHED_DATA
|
|
|
|
};
|
|
|
|
|
2013-05-14 22:51:33 +00:00
|
|
|
struct OffsetRange {
|
|
|
|
OffsetRange(int from, int to) : from(from), to(to) {}
|
|
|
|
int from;
|
|
|
|
int to;
|
|
|
|
};
|
|
|
|
|
2010-02-03 16:12:55 +00:00
|
|
|
// CompilationInfo encapsulates some information known at compile time. It
|
|
|
|
// is constructed based on the resources available at compile-time.
|
2012-07-19 18:58:23 +00:00
|
|
|
class CompilationInfo {
|
2010-01-29 11:55:40 +00:00
|
|
|
public:
|
2013-06-27 13:03:01 +00:00
|
|
|
CompilationInfo(Handle<JSFunction> closure, Zone* zone);
|
2013-06-12 09:43:22 +00:00
|
|
|
virtual ~CompilationInfo();
|
2012-07-06 09:31:31 +00:00
|
|
|
|
2013-09-05 11:27:22 +00:00
|
|
|
Isolate* isolate() const {
|
2011-03-18 20:35:07 +00:00
|
|
|
return isolate_;
|
|
|
|
}
|
2013-09-09 16:34:40 +00:00
|
|
|
Zone* zone() { return zone_; }
|
|
|
|
bool is_osr() const { return !osr_ast_id_.IsNone(); }
|
2011-09-12 10:50:50 +00:00
|
|
|
bool is_lazy() const { return IsLazy::decode(flags_); }
|
|
|
|
bool is_eval() const { return IsEval::decode(flags_); }
|
|
|
|
bool is_global() const { return IsGlobal::decode(flags_); }
|
2014-03-11 14:41:22 +00:00
|
|
|
StrictMode strict_mode() const { return StrictModeField::decode(flags_); }
|
2010-10-04 11:35:46 +00:00
|
|
|
FunctionLiteral* function() const { return function_; }
|
2010-10-04 14:30:43 +00:00
|
|
|
Scope* scope() const { return scope_; }
|
2011-11-15 13:48:40 +00:00
|
|
|
Scope* global_scope() const { return global_scope_; }
|
2010-10-04 14:30:43 +00:00
|
|
|
Handle<Code> code() const { return code_; }
|
2010-10-04 11:35:46 +00:00
|
|
|
Handle<JSFunction> closure() const { return closure_; }
|
|
|
|
Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
|
|
|
|
Handle<Script> script() const { return script_; }
|
2013-04-18 09:50:46 +00:00
|
|
|
HydrogenCodeStub* code_stub() const {return code_stub_; }
|
2010-10-04 11:35:46 +00:00
|
|
|
v8::Extension* extension() const { return extension_; }
|
2014-04-11 11:44:49 +00:00
|
|
|
ScriptData** cached_data() const { return cached_data_; }
|
2014-03-19 13:24:13 +00:00
|
|
|
CachedDataMode cached_data_mode() const {
|
|
|
|
return cached_data_mode_;
|
|
|
|
}
|
2012-08-28 11:25:08 +00:00
|
|
|
Handle<Context> context() const { return context_; }
|
2012-08-06 14:13:09 +00:00
|
|
|
BailoutId osr_ast_id() const { return osr_ast_id_; }
|
2013-12-23 14:30:35 +00:00
|
|
|
Handle<Code> unoptimized_code() const { return unoptimized_code_; }
|
2013-01-23 13:52:00 +00:00
|
|
|
int opt_count() const { return opt_count_; }
|
2012-12-18 16:25:45 +00:00
|
|
|
int num_parameters() const;
|
|
|
|
int num_heap_slots() const;
|
|
|
|
Code::Flags flags() const;
|
2010-10-04 11:35:46 +00:00
|
|
|
|
|
|
|
void MarkAsEval() {
|
|
|
|
ASSERT(!is_lazy());
|
|
|
|
flags_ |= IsEval::encode(true);
|
2010-02-03 16:12:55 +00:00
|
|
|
}
|
2010-10-04 11:35:46 +00:00
|
|
|
void MarkAsGlobal() {
|
|
|
|
ASSERT(!is_lazy());
|
|
|
|
flags_ |= IsGlobal::encode(true);
|
2010-02-05 13:57:18 +00:00
|
|
|
}
|
2013-11-15 10:52:05 +00:00
|
|
|
void set_parameter_count(int parameter_count) {
|
|
|
|
ASSERT(IsStub());
|
|
|
|
parameter_count_ = parameter_count;
|
|
|
|
}
|
2014-01-14 12:04:10 +00:00
|
|
|
|
|
|
|
void set_this_has_uses(bool has_no_uses) {
|
|
|
|
this_has_uses_ = has_no_uses;
|
|
|
|
}
|
|
|
|
bool this_has_uses() {
|
|
|
|
return this_has_uses_;
|
|
|
|
}
|
2014-03-11 14:41:22 +00:00
|
|
|
void SetStrictMode(StrictMode strict_mode) {
|
|
|
|
ASSERT(this->strict_mode() == SLOPPY || this->strict_mode() == strict_mode);
|
|
|
|
flags_ = StrictModeField::update(flags_, strict_mode);
|
2011-02-04 18:15:49 +00:00
|
|
|
}
|
2011-05-30 13:49:22 +00:00
|
|
|
void MarkAsNative() {
|
|
|
|
flags_ |= IsNative::encode(true);
|
|
|
|
}
|
2012-12-18 16:25:45 +00:00
|
|
|
|
2011-05-30 13:49:22 +00:00
|
|
|
bool is_native() const {
|
|
|
|
return IsNative::decode(flags_);
|
|
|
|
}
|
2012-12-18 16:25:45 +00:00
|
|
|
|
|
|
|
bool is_calling() const {
|
|
|
|
return is_deferred_calling() || is_non_deferred_calling();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MarkAsDeferredCalling() {
|
|
|
|
flags_ |= IsDeferredCalling::encode(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_deferred_calling() const {
|
|
|
|
return IsDeferredCalling::decode(flags_);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MarkAsNonDeferredCalling() {
|
|
|
|
flags_ |= IsNonDeferredCalling::encode(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_non_deferred_calling() const {
|
|
|
|
return IsNonDeferredCalling::decode(flags_);
|
|
|
|
}
|
|
|
|
|
2013-02-04 12:01:59 +00:00
|
|
|
void MarkAsSavesCallerDoubles() {
|
|
|
|
flags_ |= SavesCallerDoubles::encode(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool saves_caller_doubles() const {
|
|
|
|
return SavesCallerDoubles::decode(flags_);
|
|
|
|
}
|
|
|
|
|
2013-04-18 15:44:38 +00:00
|
|
|
void MarkAsRequiresFrame() {
|
|
|
|
flags_ |= RequiresFrame::encode(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool requires_frame() const {
|
|
|
|
return RequiresFrame::decode(flags_);
|
|
|
|
}
|
|
|
|
|
2014-05-12 07:49:11 +00:00
|
|
|
void MarkMustNotHaveEagerFrame() {
|
|
|
|
flags_ |= MustNotHaveEagerFrame::encode(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool GetMustNotHaveEagerFrame() const {
|
|
|
|
return MustNotHaveEagerFrame::decode(flags_);
|
|
|
|
}
|
|
|
|
|
2014-05-12 13:47:01 +00:00
|
|
|
void MarkAsDebug() {
|
|
|
|
flags_ |= IsDebug::encode(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_debug() const {
|
|
|
|
return IsDebug::decode(flags_);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsCodePreAgingActive() const {
|
|
|
|
return FLAG_optimize_for_size && FLAG_age_code && !is_debug();
|
|
|
|
}
|
|
|
|
|
2013-03-07 15:46:14 +00:00
|
|
|
void SetParseRestriction(ParseRestriction restriction) {
|
|
|
|
flags_ = ParseRestricitonField::update(flags_, restriction);
|
|
|
|
}
|
|
|
|
|
|
|
|
ParseRestriction parse_restriction() const {
|
|
|
|
return ParseRestricitonField::decode(flags_);
|
|
|
|
}
|
|
|
|
|
2010-10-04 11:35:46 +00:00
|
|
|
void SetFunction(FunctionLiteral* literal) {
|
|
|
|
ASSERT(function_ == NULL);
|
|
|
|
function_ = literal;
|
2010-09-30 08:48:37 +00:00
|
|
|
}
|
2014-02-10 21:38:17 +00:00
|
|
|
void PrepareForCompilation(Scope* scope);
|
2011-11-15 13:48:40 +00:00
|
|
|
void SetGlobalScope(Scope* global_scope) {
|
|
|
|
ASSERT(global_scope_ == NULL);
|
|
|
|
global_scope_ = global_scope;
|
|
|
|
}
|
2014-04-30 10:51:01 +00:00
|
|
|
Handle<FixedArray> feedback_vector() const {
|
|
|
|
return feedback_vector_;
|
|
|
|
}
|
2010-10-04 14:30:43 +00:00
|
|
|
void SetCode(Handle<Code> code) { code_ = code; }
|
2010-10-04 11:35:46 +00:00
|
|
|
void SetExtension(v8::Extension* extension) {
|
|
|
|
ASSERT(!is_lazy());
|
|
|
|
extension_ = extension;
|
2010-09-30 08:48:37 +00:00
|
|
|
}
|
2014-04-11 11:44:49 +00:00
|
|
|
void SetCachedData(ScriptData** cached_data,
|
2014-03-19 13:24:13 +00:00
|
|
|
CachedDataMode cached_data_mode) {
|
|
|
|
cached_data_mode_ = cached_data_mode;
|
|
|
|
if (cached_data_mode == NO_CACHED_DATA) {
|
|
|
|
cached_data_ = NULL;
|
|
|
|
} else {
|
|
|
|
ASSERT(!is_lazy());
|
|
|
|
cached_data_ = cached_data;
|
|
|
|
}
|
2010-09-30 08:48:37 +00:00
|
|
|
}
|
2012-08-28 11:25:08 +00:00
|
|
|
void SetContext(Handle<Context> context) {
|
|
|
|
context_ = context;
|
2010-10-04 14:30:43 +00:00
|
|
|
}
|
2013-12-23 14:30:35 +00:00
|
|
|
|
|
|
|
void MarkCompilingForDebugging() {
|
2011-10-18 13:40:33 +00:00
|
|
|
flags_ |= IsCompilingForDebugging::encode(true);
|
|
|
|
}
|
|
|
|
bool IsCompilingForDebugging() {
|
|
|
|
return IsCompilingForDebugging::decode(flags_);
|
|
|
|
}
|
2013-12-23 14:30:35 +00:00
|
|
|
void MarkNonOptimizable() {
|
|
|
|
SetMode(CompilationInfo::NONOPT);
|
|
|
|
}
|
2010-12-07 11:31:57 +00:00
|
|
|
|
2013-08-09 08:24:29 +00:00
|
|
|
bool ShouldTrapOnDeopt() const {
|
|
|
|
return (FLAG_trap_on_deopt && IsOptimizing()) ||
|
|
|
|
(FLAG_trap_on_stub_deopt && IsStub());
|
|
|
|
}
|
|
|
|
|
2010-12-07 11:31:57 +00:00
|
|
|
bool has_global_object() const {
|
2012-08-17 12:59:00 +00:00
|
|
|
return !closure().is_null() &&
|
|
|
|
(closure()->context()->global_object() != NULL);
|
2010-12-07 11:31:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GlobalObject* global_object() const {
|
2012-08-17 12:59:00 +00:00
|
|
|
return has_global_object() ? closure()->context()->global_object() : NULL;
|
2010-12-07 11:31:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Accessors for the different compilation modes.
|
|
|
|
bool IsOptimizing() const { return mode_ == OPTIMIZE; }
|
|
|
|
bool IsOptimizable() const { return mode_ == BASE; }
|
2012-12-18 16:25:45 +00:00
|
|
|
bool IsStub() const { return mode_ == STUB; }
|
2013-12-23 14:30:35 +00:00
|
|
|
void SetOptimizing(BailoutId osr_ast_id, Handle<Code> unoptimized) {
|
|
|
|
ASSERT(!shared_info_.is_null());
|
2010-12-07 11:31:57 +00:00
|
|
|
SetMode(OPTIMIZE);
|
|
|
|
osr_ast_id_ = osr_ast_id;
|
2013-12-23 14:30:35 +00:00
|
|
|
unoptimized_code_ = unoptimized;
|
2014-02-13 16:09:28 +00:00
|
|
|
optimization_id_ = isolate()->NextOptimizationId();
|
2010-12-07 11:31:57 +00:00
|
|
|
}
|
2011-01-17 08:11:03 +00:00
|
|
|
void DisableOptimization();
|
2010-12-07 11:31:57 +00:00
|
|
|
|
|
|
|
// Deoptimization support.
|
2011-10-18 13:40:33 +00:00
|
|
|
bool HasDeoptimizationSupport() const {
|
|
|
|
return SupportsDeoptimization::decode(flags_);
|
|
|
|
}
|
2010-12-07 11:31:57 +00:00
|
|
|
void EnableDeoptimizationSupport() {
|
|
|
|
ASSERT(IsOptimizable());
|
2011-10-18 13:40:33 +00:00
|
|
|
flags_ |= SupportsDeoptimization::encode(true);
|
2010-12-07 11:31:57 +00:00
|
|
|
}
|
|
|
|
|
2012-02-09 10:19:46 +00:00
|
|
|
// Determines whether or not to insert a self-optimization header.
|
|
|
|
bool ShouldSelfOptimize();
|
|
|
|
|
2012-07-06 09:31:31 +00:00
|
|
|
void set_deferred_handles(DeferredHandles* deferred_handles) {
|
|
|
|
ASSERT(deferred_handles_ == NULL);
|
|
|
|
deferred_handles_ = deferred_handles;
|
|
|
|
}
|
|
|
|
|
2013-06-26 16:17:12 +00:00
|
|
|
ZoneList<Handle<HeapObject> >* dependencies(
|
|
|
|
DependentCode::DependencyGroup group) {
|
|
|
|
if (dependencies_[group] == NULL) {
|
|
|
|
dependencies_[group] = new(zone_) ZoneList<Handle<HeapObject> >(2, zone_);
|
2013-06-12 09:43:22 +00:00
|
|
|
}
|
2013-06-26 16:17:12 +00:00
|
|
|
return dependencies_[group];
|
2013-06-12 09:43:22 +00:00
|
|
|
}
|
|
|
|
|
2013-06-26 16:17:12 +00:00
|
|
|
void CommitDependencies(Handle<Code> code);
|
2013-06-12 09:43:22 +00:00
|
|
|
|
2013-06-26 16:17:12 +00:00
|
|
|
void RollbackDependencies();
|
2013-06-12 09:43:22 +00:00
|
|
|
|
2012-07-19 18:58:23 +00:00
|
|
|
void SaveHandles() {
|
|
|
|
SaveHandle(&closure_);
|
|
|
|
SaveHandle(&shared_info_);
|
2012-08-28 11:25:08 +00:00
|
|
|
SaveHandle(&context_);
|
2012-07-19 18:58:23 +00:00
|
|
|
SaveHandle(&script_);
|
2013-12-23 14:30:35 +00:00
|
|
|
SaveHandle(&unoptimized_code_);
|
2012-07-19 18:58:23 +00:00
|
|
|
}
|
|
|
|
|
2013-08-02 09:53:11 +00:00
|
|
|
BailoutReason bailout_reason() const { return bailout_reason_; }
|
|
|
|
void set_bailout_reason(BailoutReason reason) { bailout_reason_ = reason; }
|
2012-08-28 07:18:06 +00:00
|
|
|
|
2012-11-29 07:38:00 +00:00
|
|
|
int prologue_offset() const {
|
2013-10-23 13:48:04 +00:00
|
|
|
ASSERT_NE(Code::kPrologueOffsetNotSet, prologue_offset_);
|
2012-11-29 07:38:00 +00:00
|
|
|
return prologue_offset_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_prologue_offset(int prologue_offset) {
|
2013-10-23 13:48:04 +00:00
|
|
|
ASSERT_EQ(Code::kPrologueOffsetNotSet, prologue_offset_);
|
2012-11-29 07:38:00 +00:00
|
|
|
prologue_offset_ = prologue_offset;
|
|
|
|
}
|
|
|
|
|
2013-05-14 22:51:33 +00:00
|
|
|
// Adds offset range [from, to) where fp register does not point
|
|
|
|
// to the current frame base. Used in CPU profiler to detect stack
|
|
|
|
// samples where top frame is not set up.
|
|
|
|
inline void AddNoFrameRange(int from, int to) {
|
|
|
|
if (no_frame_ranges_) no_frame_ranges_->Add(OffsetRange(from, to));
|
|
|
|
}
|
|
|
|
|
|
|
|
List<OffsetRange>* ReleaseNoFrameRanges() {
|
|
|
|
List<OffsetRange>* result = no_frame_ranges_;
|
|
|
|
no_frame_ranges_ = NULL;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2013-06-12 09:43:22 +00:00
|
|
|
Handle<Foreign> object_wrapper() {
|
|
|
|
if (object_wrapper_.is_null()) {
|
|
|
|
object_wrapper_ =
|
|
|
|
isolate()->factory()->NewForeign(reinterpret_cast<Address>(this));
|
|
|
|
}
|
|
|
|
return object_wrapper_;
|
|
|
|
}
|
|
|
|
|
2013-06-26 16:17:12 +00:00
|
|
|
void AbortDueToDependencyChange() {
|
2013-11-19 11:52:47 +00:00
|
|
|
ASSERT(!OptimizingCompilerThread::IsOptimizerThread(isolate()));
|
2013-08-12 14:10:25 +00:00
|
|
|
abort_due_to_dependency_ = true;
|
2013-06-12 09:43:22 +00:00
|
|
|
}
|
|
|
|
|
2013-06-26 16:17:12 +00:00
|
|
|
bool HasAbortedDueToDependencyChange() {
|
2013-11-19 11:52:47 +00:00
|
|
|
ASSERT(!OptimizingCompilerThread::IsOptimizerThread(isolate()));
|
2013-08-12 14:10:25 +00:00
|
|
|
return abort_due_to_dependency_;
|
2013-06-12 09:43:22 +00:00
|
|
|
}
|
|
|
|
|
2013-12-23 14:30:35 +00:00
|
|
|
bool HasSameOsrEntry(Handle<JSFunction> function, BailoutId osr_ast_id) {
|
|
|
|
return osr_ast_id_ == osr_ast_id && function.is_identical_to(closure_);
|
2013-09-04 12:55:59 +00:00
|
|
|
}
|
|
|
|
|
2014-02-13 16:09:28 +00:00
|
|
|
int optimization_id() const { return optimization_id_; }
|
|
|
|
|
2013-06-12 09:43:22 +00:00
|
|
|
protected:
|
2013-06-24 13:37:46 +00:00
|
|
|
CompilationInfo(Handle<Script> script,
|
2013-06-27 13:03:01 +00:00
|
|
|
Zone* zone);
|
2013-06-24 13:37:46 +00:00
|
|
|
CompilationInfo(Handle<SharedFunctionInfo> shared_info,
|
2013-06-27 13:03:01 +00:00
|
|
|
Zone* zone);
|
2013-06-24 13:37:46 +00:00
|
|
|
CompilationInfo(HydrogenCodeStub* stub,
|
|
|
|
Isolate* isolate,
|
2013-06-27 13:03:01 +00:00
|
|
|
Zone* zone);
|
2013-05-14 22:51:33 +00:00
|
|
|
|
2010-10-04 11:35:46 +00:00
|
|
|
private:
|
2011-03-18 20:35:07 +00:00
|
|
|
Isolate* isolate_;
|
|
|
|
|
2010-12-07 11:31:57 +00:00
|
|
|
// Compilation mode.
|
|
|
|
// BASE is generated by the full codegen, optionally prepared for bailouts.
|
|
|
|
// OPTIMIZE is optimized code generated by the Hydrogen-based backend.
|
2012-02-14 14:14:51 +00:00
|
|
|
// NONOPT is generated by the full codegen and is not prepared for
|
|
|
|
// recompilation/bailouts. These functions are never recompiled.
|
2010-12-07 11:31:57 +00:00
|
|
|
enum Mode {
|
|
|
|
BASE,
|
|
|
|
OPTIMIZE,
|
2012-12-18 16:25:45 +00:00
|
|
|
NONOPT,
|
2013-08-12 14:10:25 +00:00
|
|
|
STUB
|
2010-12-07 11:31:57 +00:00
|
|
|
};
|
|
|
|
|
2013-06-27 13:03:01 +00:00
|
|
|
void Initialize(Isolate* isolate, Mode mode, Zone* zone);
|
2010-12-07 11:31:57 +00:00
|
|
|
|
|
|
|
void SetMode(Mode mode) {
|
2013-09-03 08:49:44 +00:00
|
|
|
ASSERT(isolate()->use_crankshaft());
|
2010-12-07 11:31:57 +00:00
|
|
|
mode_ = mode;
|
|
|
|
}
|
|
|
|
|
2010-10-04 11:35:46 +00:00
|
|
|
// Flags using template class BitField<type, start, length>. All are
|
|
|
|
// false by default.
|
|
|
|
//
|
|
|
|
// Compilation is either eager or lazy.
|
|
|
|
class IsLazy: public BitField<bool, 0, 1> {};
|
|
|
|
// Flags that can be set for eager compilation.
|
|
|
|
class IsEval: public BitField<bool, 1, 1> {};
|
|
|
|
class IsGlobal: public BitField<bool, 2, 1> {};
|
2014-05-12 13:47:01 +00:00
|
|
|
// If the function is being compiled for the debugger.
|
|
|
|
class IsDebug: public BitField<bool, 3, 1> {};
|
2011-02-04 18:15:49 +00:00
|
|
|
// Strict mode - used in eager compilation.
|
2014-03-11 14:41:22 +00:00
|
|
|
class StrictModeField: public BitField<StrictMode, 4, 1> {};
|
2011-05-30 13:49:22 +00:00
|
|
|
// Is this a function from our natives.
|
2014-03-11 14:41:22 +00:00
|
|
|
class IsNative: public BitField<bool, 5, 1> {};
|
2011-10-18 13:40:33 +00:00
|
|
|
// Is this code being compiled with support for deoptimization..
|
2014-03-11 14:41:22 +00:00
|
|
|
class SupportsDeoptimization: public BitField<bool, 6, 1> {};
|
2011-10-18 13:40:33 +00:00
|
|
|
// If compiling for debugging produce just full code matching the
|
|
|
|
// initial mode setting.
|
2014-03-11 14:41:22 +00:00
|
|
|
class IsCompilingForDebugging: public BitField<bool, 7, 1> {};
|
2012-12-18 16:25:45 +00:00
|
|
|
// If the compiled code contains calls that require building a frame
|
2014-03-11 14:41:22 +00:00
|
|
|
class IsCalling: public BitField<bool, 8, 1> {};
|
2012-12-18 16:25:45 +00:00
|
|
|
// If the compiled code contains calls that require building a frame
|
2014-03-11 14:41:22 +00:00
|
|
|
class IsDeferredCalling: public BitField<bool, 9, 1> {};
|
2012-12-18 16:25:45 +00:00
|
|
|
// If the compiled code contains calls that require building a frame
|
2014-03-11 14:41:22 +00:00
|
|
|
class IsNonDeferredCalling: public BitField<bool, 10, 1> {};
|
2013-02-04 12:01:59 +00:00
|
|
|
// If the compiled code saves double caller registers that it clobbers.
|
2014-03-11 14:41:22 +00:00
|
|
|
class SavesCallerDoubles: public BitField<bool, 11, 1> {};
|
2013-03-07 15:46:14 +00:00
|
|
|
// If the set of valid statements is restricted.
|
2014-03-11 14:41:22 +00:00
|
|
|
class ParseRestricitonField: public BitField<ParseRestriction, 12, 1> {};
|
2013-04-18 15:44:38 +00:00
|
|
|
// If the function requires a frame (for unspecified reasons)
|
2014-03-11 14:41:22 +00:00
|
|
|
class RequiresFrame: public BitField<bool, 13, 1> {};
|
2014-05-12 07:49:11 +00:00
|
|
|
// If the function cannot build a frame (for unspecified reasons)
|
|
|
|
class MustNotHaveEagerFrame: public BitField<bool, 14, 1> {};
|
2010-10-04 11:35:46 +00:00
|
|
|
|
|
|
|
unsigned flags_;
|
|
|
|
|
|
|
|
// Fields filled in by the compilation pipeline.
|
2010-10-04 14:30:43 +00:00
|
|
|
// AST filled in by the parser.
|
2010-10-04 11:35:46 +00:00
|
|
|
FunctionLiteral* function_;
|
2010-10-27 09:19:43 +00:00
|
|
|
// The scope of the function literal as a convenience. Set to indicate
|
2010-10-04 14:30:43 +00:00
|
|
|
// that scopes have been analyzed.
|
2010-10-04 11:35:46 +00:00
|
|
|
Scope* scope_;
|
2011-11-15 13:48:40 +00:00
|
|
|
// The global scope provided as a convenience.
|
|
|
|
Scope* global_scope_;
|
2012-12-18 16:25:45 +00:00
|
|
|
// For compiled stubs, the stub object
|
|
|
|
HydrogenCodeStub* code_stub_;
|
2010-10-04 14:30:43 +00:00
|
|
|
// The compiled code.
|
|
|
|
Handle<Code> code_;
|
2010-09-30 08:48:37 +00:00
|
|
|
|
2010-10-04 11:35:46 +00:00
|
|
|
// Possible initial inputs to the compilation process.
|
|
|
|
Handle<JSFunction> closure_;
|
|
|
|
Handle<SharedFunctionInfo> shared_info_;
|
|
|
|
Handle<Script> script_;
|
2010-09-30 08:48:37 +00:00
|
|
|
|
2010-10-04 11:35:46 +00:00
|
|
|
// Fields possibly needed for eager compilation, NULL by default.
|
|
|
|
v8::Extension* extension_;
|
2014-04-11 11:44:49 +00:00
|
|
|
ScriptData** cached_data_;
|
2014-03-19 13:24:13 +00:00
|
|
|
CachedDataMode cached_data_mode_;
|
2010-09-30 08:48:37 +00:00
|
|
|
|
2012-08-28 11:25:08 +00:00
|
|
|
// The context of the caller for eval code, and the global context for a
|
|
|
|
// global script. Will be a null handle otherwise.
|
|
|
|
Handle<Context> context_;
|
2010-10-04 14:30:43 +00:00
|
|
|
|
2014-04-30 10:51:01 +00:00
|
|
|
// Used by codegen, ultimately kept rooted by the SharedFunctionInfo.
|
|
|
|
Handle<FixedArray> feedback_vector_;
|
|
|
|
|
2010-12-07 11:31:57 +00:00
|
|
|
// Compilation mode flag and whether deoptimization is allowed.
|
|
|
|
Mode mode_;
|
2012-08-06 14:13:09 +00:00
|
|
|
BailoutId osr_ast_id_;
|
2013-12-05 16:17:44 +00:00
|
|
|
// The unoptimized code we patched for OSR may not be the shared code
|
|
|
|
// afterwards, since we may need to compile it again to include deoptimization
|
|
|
|
// data. Keep track which code we patched.
|
2013-12-23 14:30:35 +00:00
|
|
|
Handle<Code> unoptimized_code_;
|
2010-12-07 11:31:57 +00:00
|
|
|
|
2013-08-12 14:10:25 +00:00
|
|
|
// Flag whether compilation needs to be aborted due to dependency change.
|
|
|
|
bool abort_due_to_dependency_;
|
|
|
|
|
2012-06-20 08:58:41 +00:00
|
|
|
// The zone from which the compilation pipeline working on this
|
|
|
|
// CompilationInfo allocates.
|
|
|
|
Zone* zone_;
|
|
|
|
|
2012-07-06 09:31:31 +00:00
|
|
|
DeferredHandles* deferred_handles_;
|
|
|
|
|
2013-06-26 16:17:12 +00:00
|
|
|
ZoneList<Handle<HeapObject> >* dependencies_[DependentCode::kGroupCount];
|
2013-06-12 09:43:22 +00:00
|
|
|
|
2012-07-19 18:58:23 +00:00
|
|
|
template<typename T>
|
|
|
|
void SaveHandle(Handle<T> *object) {
|
|
|
|
if (!object->is_null()) {
|
|
|
|
Handle<T> handle(*(*object));
|
|
|
|
*object = handle;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-02 09:53:11 +00:00
|
|
|
BailoutReason bailout_reason_;
|
2012-08-28 07:18:06 +00:00
|
|
|
|
2012-11-29 07:38:00 +00:00
|
|
|
int prologue_offset_;
|
|
|
|
|
2013-05-14 22:51:33 +00:00
|
|
|
List<OffsetRange>* no_frame_ranges_;
|
|
|
|
|
2013-01-23 13:52:00 +00:00
|
|
|
// A copy of shared_info()->opt_count() to avoid handle deref
|
|
|
|
// during graph optimization.
|
|
|
|
int opt_count_;
|
|
|
|
|
2013-11-15 10:52:05 +00:00
|
|
|
// Number of parameters used for compilation of stubs that require arguments.
|
|
|
|
int parameter_count_;
|
|
|
|
|
2014-01-14 12:04:10 +00:00
|
|
|
bool this_has_uses_;
|
|
|
|
|
2013-06-12 09:43:22 +00:00
|
|
|
Handle<Foreign> object_wrapper_;
|
|
|
|
|
2014-02-13 16:09:28 +00:00
|
|
|
int optimization_id_;
|
|
|
|
|
2010-10-04 11:35:46 +00:00
|
|
|
DISALLOW_COPY_AND_ASSIGN(CompilationInfo);
|
2010-01-29 11:55:40 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2012-06-20 08:58:41 +00:00
|
|
|
// Exactly like a CompilationInfo, except also creates and enters a
|
|
|
|
// Zone on construction and deallocates it on exit.
|
|
|
|
class CompilationInfoWithZone: public CompilationInfo {
|
|
|
|
public:
|
|
|
|
explicit CompilationInfoWithZone(Handle<Script> script)
|
2013-06-27 13:03:01 +00:00
|
|
|
: CompilationInfo(script, &zone_),
|
|
|
|
zone_(script->GetIsolate()) {}
|
2012-06-20 08:58:41 +00:00
|
|
|
explicit CompilationInfoWithZone(Handle<SharedFunctionInfo> shared_info)
|
2013-06-27 13:03:01 +00:00
|
|
|
: CompilationInfo(shared_info, &zone_),
|
|
|
|
zone_(shared_info->GetIsolate()) {}
|
2012-06-20 08:58:41 +00:00
|
|
|
explicit CompilationInfoWithZone(Handle<JSFunction> closure)
|
2013-06-27 13:03:01 +00:00
|
|
|
: CompilationInfo(closure, &zone_),
|
|
|
|
zone_(closure->GetIsolate()) {}
|
2013-06-12 09:43:22 +00:00
|
|
|
CompilationInfoWithZone(HydrogenCodeStub* stub, Isolate* isolate)
|
2013-06-27 13:03:01 +00:00
|
|
|
: CompilationInfo(stub, isolate, &zone_),
|
|
|
|
zone_(isolate) {}
|
2012-06-20 08:58:41 +00:00
|
|
|
|
2013-06-12 09:43:22 +00:00
|
|
|
// Virtual destructor because a CompilationInfoWithZone has to exit the
|
|
|
|
// zone scope and get rid of dependent maps even when the destructor is
|
|
|
|
// called when cast as a CompilationInfo.
|
|
|
|
virtual ~CompilationInfoWithZone() {
|
2013-06-26 16:17:12 +00:00
|
|
|
RollbackDependencies();
|
2013-06-12 09:43:22 +00:00
|
|
|
}
|
|
|
|
|
2012-06-20 08:58:41 +00:00
|
|
|
private:
|
|
|
|
Zone zone_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2012-07-06 09:31:31 +00:00
|
|
|
// A wrapper around a CompilationInfo that detaches the Handles from
|
|
|
|
// the underlying DeferredHandleScope and stores them in info_ on
|
|
|
|
// destruction.
|
|
|
|
class CompilationHandleScope BASE_EMBEDDED {
|
|
|
|
public:
|
|
|
|
explicit CompilationHandleScope(CompilationInfo* info)
|
|
|
|
: deferred_(info->isolate()), info_(info) {}
|
|
|
|
~CompilationHandleScope() {
|
|
|
|
info_->set_deferred_handles(deferred_.Detach());
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
DeferredHandleScope deferred_;
|
|
|
|
CompilationInfo* info_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2012-07-17 16:24:40 +00:00
|
|
|
class HGraph;
|
2012-12-18 16:25:45 +00:00
|
|
|
class HOptimizedGraphBuilder;
|
2012-07-17 16:24:40 +00:00
|
|
|
class LChunk;
|
|
|
|
|
|
|
|
// A helper class that calls the three compilation phases in
|
|
|
|
// Crankshaft and keeps track of its state. The three phases
|
|
|
|
// CreateGraph, OptimizeGraph and GenerateAndInstallCode can either
|
|
|
|
// fail, bail-out to the full code generator or succeed. Apart from
|
|
|
|
// their return value, the status of the phase last run can be checked
|
|
|
|
// using last_status().
|
2013-12-23 14:30:35 +00:00
|
|
|
class OptimizedCompileJob: public ZoneObject {
|
2012-07-17 16:24:40 +00:00
|
|
|
public:
|
2013-12-23 14:30:35 +00:00
|
|
|
explicit OptimizedCompileJob(CompilationInfo* info)
|
2012-07-17 16:24:40 +00:00
|
|
|
: info_(info),
|
|
|
|
graph_builder_(NULL),
|
|
|
|
graph_(NULL),
|
|
|
|
chunk_(NULL),
|
2013-10-01 08:40:33 +00:00
|
|
|
last_status_(FAILED),
|
|
|
|
awaiting_install_(false) { }
|
2012-07-17 16:24:40 +00:00
|
|
|
|
|
|
|
enum Status {
|
|
|
|
FAILED, BAILED_OUT, SUCCEEDED
|
|
|
|
};
|
|
|
|
|
|
|
|
MUST_USE_RESULT Status CreateGraph();
|
|
|
|
MUST_USE_RESULT Status OptimizeGraph();
|
2013-12-23 14:30:35 +00:00
|
|
|
MUST_USE_RESULT Status GenerateCode();
|
2012-07-17 16:24:40 +00:00
|
|
|
|
|
|
|
Status last_status() const { return last_status_; }
|
|
|
|
CompilationInfo* info() const { return info_; }
|
2013-02-25 14:46:09 +00:00
|
|
|
Isolate* isolate() const { return info()->isolate(); }
|
2012-07-17 16:24:40 +00:00
|
|
|
|
2013-12-23 14:30:35 +00:00
|
|
|
MUST_USE_RESULT Status AbortOptimization(
|
|
|
|
BailoutReason reason = kNoReason) {
|
|
|
|
if (reason != kNoReason) info_->set_bailout_reason(reason);
|
|
|
|
return SetLastStatus(BAILED_OUT);
|
|
|
|
}
|
|
|
|
|
|
|
|
MUST_USE_RESULT Status AbortAndDisableOptimization(
|
|
|
|
BailoutReason reason = kNoReason) {
|
|
|
|
if (reason != kNoReason) info_->set_bailout_reason(reason);
|
2014-05-02 08:08:23 +00:00
|
|
|
// Reference to shared function info does not change between phases.
|
|
|
|
AllowDeferredHandleDereference allow_handle_dereference;
|
2012-08-28 07:18:06 +00:00
|
|
|
info_->shared_info()->DisableOptimization(info_->bailout_reason());
|
2012-07-19 18:58:23 +00:00
|
|
|
return SetLastStatus(BAILED_OUT);
|
|
|
|
}
|
|
|
|
|
2013-09-25 08:26:11 +00:00
|
|
|
void WaitForInstall() {
|
2013-09-27 09:37:18 +00:00
|
|
|
ASSERT(info_->is_osr());
|
2013-09-25 08:26:11 +00:00
|
|
|
awaiting_install_ = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsWaitingForInstall() { return awaiting_install_; }
|
|
|
|
|
2012-07-17 16:24:40 +00:00
|
|
|
private:
|
|
|
|
CompilationInfo* info_;
|
2012-12-18 16:25:45 +00:00
|
|
|
HOptimizedGraphBuilder* graph_builder_;
|
2012-07-17 16:24:40 +00:00
|
|
|
HGraph* graph_;
|
|
|
|
LChunk* chunk_;
|
2013-08-29 09:15:13 +00:00
|
|
|
TimeDelta time_taken_to_create_graph_;
|
|
|
|
TimeDelta time_taken_to_optimize_;
|
|
|
|
TimeDelta time_taken_to_codegen_;
|
2012-07-17 16:24:40 +00:00
|
|
|
Status last_status_;
|
2013-09-25 08:26:11 +00:00
|
|
|
bool awaiting_install_;
|
2012-07-17 16:24:40 +00:00
|
|
|
|
|
|
|
MUST_USE_RESULT Status SetLastStatus(Status status) {
|
|
|
|
last_status_ = status;
|
|
|
|
return last_status_;
|
|
|
|
}
|
|
|
|
void RecordOptimizationStats();
|
|
|
|
|
|
|
|
struct Timer {
|
2013-12-23 14:30:35 +00:00
|
|
|
Timer(OptimizedCompileJob* job, TimeDelta* location)
|
2013-09-25 10:01:18 +00:00
|
|
|
: job_(job), location_(location) {
|
2013-08-29 09:15:13 +00:00
|
|
|
ASSERT(location_ != NULL);
|
|
|
|
timer_.Start();
|
|
|
|
}
|
2012-07-17 16:24:40 +00:00
|
|
|
|
|
|
|
~Timer() {
|
2013-08-29 09:15:13 +00:00
|
|
|
*location_ += timer_.Elapsed();
|
2012-07-17 16:24:40 +00:00
|
|
|
}
|
|
|
|
|
2013-12-23 14:30:35 +00:00
|
|
|
OptimizedCompileJob* job_;
|
2013-08-29 09:15:13 +00:00
|
|
|
ElapsedTimer timer_;
|
|
|
|
TimeDelta* location_;
|
2012-07-17 16:24:40 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
// The V8 compiler
|
|
|
|
//
|
|
|
|
// General strategy: Source code is translated into an anonymous function w/o
|
|
|
|
// parameters which then can be executed. If the source code contains other
|
|
|
|
// functions, they will be compiled and allocated as part of the compilation
|
|
|
|
// of the source code.
|
|
|
|
|
2010-10-04 14:30:43 +00:00
|
|
|
// Please note this interface returns shared function infos. This means you
|
|
|
|
// need to call Factory::NewFunctionFromSharedFunctionInfo before you have a
|
|
|
|
// real function with a context.
|
2008-07-03 15:10:15 +00:00
|
|
|
|
|
|
|
class Compiler : public AllStatic {
|
|
|
|
public:
|
2014-04-22 14:55:47 +00:00
|
|
|
MUST_USE_RESULT static MaybeHandle<Code> GetUnoptimizedCode(
|
|
|
|
Handle<JSFunction> function);
|
|
|
|
MUST_USE_RESULT static MaybeHandle<Code> GetUnoptimizedCode(
|
|
|
|
Handle<SharedFunctionInfo> shared);
|
2013-12-23 14:30:35 +00:00
|
|
|
static bool EnsureCompiled(Handle<JSFunction> function,
|
|
|
|
ClearExceptionFlag flag);
|
2014-04-22 14:55:47 +00:00
|
|
|
MUST_USE_RESULT static MaybeHandle<Code> GetCodeForDebugging(
|
|
|
|
Handle<JSFunction> function);
|
2012-02-09 10:19:46 +00:00
|
|
|
|
2013-12-23 14:30:35 +00:00
|
|
|
static void CompileForLiveEdit(Handle<Script> script);
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2013-12-23 14:30:35 +00:00
|
|
|
// Compile a String source within a context for eval.
|
2014-04-17 05:41:58 +00:00
|
|
|
MUST_USE_RESULT static MaybeHandle<JSFunction> GetFunctionFromEval(
|
|
|
|
Handle<String> source,
|
|
|
|
Handle<Context> context,
|
|
|
|
StrictMode strict_mode,
|
|
|
|
ParseRestriction restriction,
|
|
|
|
int scope_position);
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2013-12-23 14:30:35 +00:00
|
|
|
// Compile a String source within a context.
|
2014-03-19 13:24:13 +00:00
|
|
|
static Handle<SharedFunctionInfo> CompileScript(
|
|
|
|
Handle<String> source,
|
|
|
|
Handle<Object> script_name,
|
|
|
|
int line_offset,
|
|
|
|
int column_offset,
|
|
|
|
bool is_shared_cross_origin,
|
|
|
|
Handle<Context> context,
|
|
|
|
v8::Extension* extension,
|
2014-04-11 11:44:49 +00:00
|
|
|
ScriptData** cached_data,
|
2014-03-19 13:24:13 +00:00
|
|
|
CachedDataMode cached_data_mode,
|
|
|
|
NativesFlag is_natives_code);
|
2013-12-23 14:30:35 +00:00
|
|
|
|
|
|
|
// Create a shared function info object (the code may be lazily compiled).
|
2010-03-23 06:04:44 +00:00
|
|
|
static Handle<SharedFunctionInfo> BuildFunctionInfo(FunctionLiteral* node,
|
2010-10-04 14:30:43 +00:00
|
|
|
Handle<Script> script);
|
2009-11-04 17:59:24 +00:00
|
|
|
|
2013-12-23 14:30:35 +00:00
|
|
|
enum ConcurrencyMode { NOT_CONCURRENT, CONCURRENT };
|
2010-02-04 15:35:42 +00:00
|
|
|
|
2013-12-23 14:30:35 +00:00
|
|
|
// Generate and return optimized code or start a concurrent optimization job.
|
|
|
|
// In the latter case, return the InOptimizationQueue builtin. On failure,
|
|
|
|
// return the empty handle.
|
2014-04-22 14:55:47 +00:00
|
|
|
MUST_USE_RESULT static MaybeHandle<Code> GetOptimizedCode(
|
2013-12-23 14:30:35 +00:00
|
|
|
Handle<JSFunction> function,
|
|
|
|
Handle<Code> current_code,
|
|
|
|
ConcurrencyMode mode,
|
|
|
|
BailoutId osr_ast_id = BailoutId::None());
|
2013-09-04 12:55:59 +00:00
|
|
|
|
2013-12-23 14:30:35 +00:00
|
|
|
// Generate and return code from previously queued optimization job.
|
|
|
|
// On failure, return the empty handle.
|
|
|
|
static Handle<Code> GetConcurrentlyOptimizedCode(OptimizedCompileJob* job);
|
2010-10-04 14:30:43 +00:00
|
|
|
|
2010-03-25 14:55:53 +00:00
|
|
|
static void RecordFunctionCompilation(Logger::LogEventsAndTags tag,
|
2011-02-22 16:31:24 +00:00
|
|
|
CompilationInfo* info,
|
|
|
|
Handle<SharedFunctionInfo> shared);
|
2008-07-03 15:10:15 +00:00
|
|
|
};
|
|
|
|
|
2009-05-14 12:18:25 +00:00
|
|
|
|
2013-06-25 12:22:26 +00:00
|
|
|
class CompilationPhase BASE_EMBEDDED {
|
|
|
|
public:
|
2013-06-27 13:03:01 +00:00
|
|
|
CompilationPhase(const char* name, CompilationInfo* info);
|
2013-06-25 12:22:26 +00:00
|
|
|
~CompilationPhase();
|
|
|
|
|
|
|
|
protected:
|
|
|
|
bool ShouldProduceTraceOutput() const;
|
|
|
|
|
|
|
|
const char* name() const { return name_; }
|
2013-06-27 13:09:08 +00:00
|
|
|
CompilationInfo* info() const { return info_; }
|
|
|
|
Isolate* isolate() const { return info()->isolate(); }
|
2013-06-27 13:03:01 +00:00
|
|
|
Zone* zone() { return &zone_; }
|
2013-06-25 12:22:26 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
const char* name_;
|
2013-06-27 13:03:01 +00:00
|
|
|
CompilationInfo* info_;
|
|
|
|
Zone zone_;
|
|
|
|
unsigned info_zone_start_allocation_size_;
|
2013-08-29 09:15:13 +00:00
|
|
|
ElapsedTimer timer_;
|
2013-06-25 12:22:26 +00:00
|
|
|
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(CompilationPhase);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
} } // namespace v8::internal
|
|
|
|
|
|
|
|
#endif // V8_COMPILER_H_
|