Version 3.21.10
Fixed Eternal::IsEmpty logic (issue 2870).
Performance and stability improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@16532 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/api.cc b/src/api.cc
index 4b80555..c95def1 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -53,6 +53,7 @@
#endif
#include "parser.h"
#include "platform.h"
+#include "platform/time.h"
#include "profile-generator-inl.h"
#include "property-details.h"
#include "property.h"
@@ -1438,55 +1439,95 @@
// Ensure that the object template has a constructor. If no
// constructor is available we create one.
-static void EnsureConstructor(ObjectTemplate* object_template) {
- if (Utils::OpenHandle(object_template)->constructor()->IsUndefined()) {
- Local<FunctionTemplate> templ = FunctionTemplate::New();
- i::Handle<i::FunctionTemplateInfo> constructor = Utils::OpenHandle(*templ);
- constructor->set_instance_template(*Utils::OpenHandle(object_template));
- Utils::OpenHandle(object_template)->set_constructor(*constructor);
+static i::Handle<i::FunctionTemplateInfo> EnsureConstructor(
+ ObjectTemplate* object_template) {
+ i::Object* obj = Utils::OpenHandle(object_template)->constructor();
+ if (!obj ->IsUndefined()) {
+ i::FunctionTemplateInfo* info = i::FunctionTemplateInfo::cast(obj);
+ return i::Handle<i::FunctionTemplateInfo>(info, info->GetIsolate());
}
+ Local<FunctionTemplate> templ = FunctionTemplate::New();
+ i::Handle<i::FunctionTemplateInfo> constructor = Utils::OpenHandle(*templ);
+ constructor->set_instance_template(*Utils::OpenHandle(object_template));
+ Utils::OpenHandle(object_template)->set_constructor(*constructor);
+ return constructor;
}
-static inline void AddPropertyToFunctionTemplate(
- i::Handle<i::FunctionTemplateInfo> cons,
+static inline void AddPropertyToTemplate(
+ i::Handle<i::TemplateInfo> info,
i::Handle<i::AccessorInfo> obj) {
- i::Handle<i::Object> list(cons->property_accessors(), cons->GetIsolate());
+ i::Handle<i::Object> list(info->property_accessors(), info->GetIsolate());
if (list->IsUndefined()) {
list = NeanderArray().value();
- cons->set_property_accessors(*list);
+ info->set_property_accessors(*list);
}
NeanderArray array(list);
array.add(obj);
}
-template<typename Setter, typename Getter, typename Data>
-static bool ObjectTemplateSetAccessor(
- ObjectTemplate* object_template,
- v8::Handle<String> name,
+static inline i::Handle<i::TemplateInfo> GetTemplateInfo(
+ Template* template_obj) {
+ return Utils::OpenHandle(template_obj);
+}
+
+
+// TODO(dcarney): remove this with ObjectTemplate::SetAccessor
+static inline i::Handle<i::TemplateInfo> GetTemplateInfo(
+ ObjectTemplate* object_template) {
+ EnsureConstructor(object_template);
+ return Utils::OpenHandle(object_template);
+}
+
+
+template<typename Setter, typename Getter, typename Data, typename Template>
+static bool TemplateSetAccessor(
+ Template* template_obj,
+ v8::Local<String> name,
Getter getter,
Setter setter,
Data data,
AccessControl settings,
PropertyAttribute attribute,
- v8::Handle<AccessorSignature> signature) {
- i::Isolate* isolate = Utils::OpenHandle(object_template)->GetIsolate();
+ v8::Local<AccessorSignature> signature) {
+ i::Isolate* isolate = Utils::OpenHandle(template_obj)->GetIsolate();
if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetAccessor()")) return false;
ENTER_V8(isolate);
i::HandleScope scope(isolate);
- EnsureConstructor(object_template);
- i::FunctionTemplateInfo* constructor = i::FunctionTemplateInfo::cast(
- Utils::OpenHandle(object_template)->constructor());
- i::Handle<i::FunctionTemplateInfo> cons(constructor);
i::Handle<i::AccessorInfo> obj = MakeAccessorInfo(
name, getter, setter, data, settings, attribute, signature);
if (obj.is_null()) return false;
- AddPropertyToFunctionTemplate(cons, obj);
+ i::Handle<i::TemplateInfo> info = GetTemplateInfo(template_obj);
+ AddPropertyToTemplate(info, obj);
return true;
}
+bool Template::SetDeclaredAccessor(
+ Local<String> name,
+ Local<DeclaredAccessorDescriptor> descriptor,
+ PropertyAttribute attribute,
+ Local<AccessorSignature> signature,
+ AccessControl settings) {
+ void* null = NULL;
+ return TemplateSetAccessor(
+ this, name, descriptor, null, null, settings, attribute, signature);
+}
+
+
+void Template::SetNativeDataProperty(v8::Local<String> name,
+ AccessorGetterCallback getter,
+ AccessorSetterCallback setter,
+ v8::Handle<Value> data,
+ PropertyAttribute attribute,
+ v8::Local<AccessorSignature> signature,
+ AccessControl settings) {
+ TemplateSetAccessor(
+ this, name, getter, setter, data, settings, attribute, signature);
+}
+
+
void ObjectTemplate::SetAccessor(v8::Handle<String> name,
AccessorGetterCallback getter,
AccessorSetterCallback setter,
@@ -1494,22 +1535,11 @@
AccessControl settings,
PropertyAttribute attribute,
v8::Handle<AccessorSignature> signature) {
- ObjectTemplateSetAccessor(
+ TemplateSetAccessor(
this, name, getter, setter, data, settings, attribute, signature);
}
-bool ObjectTemplate::SetAccessor(Handle<String> name,
- Handle<DeclaredAccessorDescriptor> descriptor,
- AccessControl settings,
- PropertyAttribute attribute,
- Handle<AccessorSignature> signature) {
- void* null = NULL;
- return ObjectTemplateSetAccessor(
- this, name, descriptor, null, null, settings, attribute, signature);
-}
-
-
void ObjectTemplate::SetNamedPropertyHandler(
NamedPropertyGetterCallback getter,
NamedPropertySetterCallback setter,
@@ -1683,19 +1713,20 @@
ScriptData* ScriptData::PreCompile(const char* input, int length) {
i::Utf8ToUtf16CharacterStream stream(
reinterpret_cast<const unsigned char*>(input), length);
- return i::PreParserApi::PreParse(&stream);
+ return i::PreParserApi::PreParse(i::Isolate::Current(), &stream);
}
ScriptData* ScriptData::PreCompile(v8::Handle<String> source) {
i::Handle<i::String> str = Utils::OpenHandle(*source);
+ i::Isolate* isolate = str->GetIsolate();
if (str->IsExternalTwoByteString()) {
i::ExternalTwoByteStringUtf16CharacterStream stream(
i::Handle<i::ExternalTwoByteString>::cast(str), 0, str->length());
- return i::PreParserApi::PreParse(&stream);
+ return i::PreParserApi::PreParse(isolate, &stream);
} else {
i::GenericStringUtf16CharacterStream stream(str, 0, str->length());
- return i::PreParserApi::PreParse(&stream);
+ return i::PreParserApi::PreParse(isolate, &stream);
}
}
@@ -2289,7 +2320,7 @@
ENTER_V8(isolate);
HandleScope scope(reinterpret_cast<Isolate*>(isolate));
i::Handle<i::JSArray> self = Utils::OpenHandle(this);
- i::Object* raw_object = self->GetElementNoExceptionThrown(index);
+ i::Object* raw_object = self->GetElementNoExceptionThrown(isolate, index);
i::Handle<i::JSObject> obj(i::JSObject::cast(raw_object));
return scope.Close(Utils::StackFrameToLocal(obj));
}
@@ -3362,7 +3393,7 @@
ENTER_V8(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
EXCEPTION_PREAMBLE(isolate);
- i::Handle<i::Object> result = i::Object::GetElement(self, index);
+ i::Handle<i::Object> result = i::Object::GetElement(isolate, self, index);
has_pending_exception = result.is_null();
EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>());
return Utils::ToLocal(result);
@@ -3637,10 +3668,10 @@
}
-bool Object::SetAccessor(Handle<String> name,
- Handle<DeclaredAccessorDescriptor> descriptor,
- AccessControl settings,
- PropertyAttribute attributes) {
+bool Object::SetDeclaredAccessor(Local<String> name,
+ Local<DeclaredAccessorDescriptor> descriptor,
+ PropertyAttribute attributes,
+ AccessControl settings) {
void* null = NULL;
return ObjectSetAccessor(
this, name, descriptor, null, null, settings, attributes);
@@ -5285,7 +5316,8 @@
// continue to call IdleNotification.
i::Isolate* isolate = i::Isolate::Current();
if (isolate == NULL || !isolate->IsInitialized()) return true;
- return i::V8::IdleNotification(hint);
+ if (!i::FLAG_use_idle_notification) return true;
+ return isolate->heap()->IdleNotification(hint);
}
@@ -5313,18 +5345,6 @@
}
-static i::Handle<i::FunctionTemplateInfo>
- EnsureConstructor(i::Handle<i::ObjectTemplateInfo> templ) {
- if (templ->constructor()->IsUndefined()) {
- Local<FunctionTemplate> constructor = FunctionTemplate::New();
- Utils::OpenHandle(*constructor)->set_instance_template(*templ);
- templ->set_constructor(*Utils::OpenHandle(*constructor));
- }
- return i::Handle<i::FunctionTemplateInfo>(
- i::FunctionTemplateInfo::cast(templ->constructor()));
-}
-
-
static i::Handle<i::Context> CreateEnvironment(
i::Isolate* isolate,
v8::ExtensionConfiguration* extensions,
@@ -5341,13 +5361,11 @@
if (!global_template.IsEmpty()) {
// Make sure that the global_template has a constructor.
- global_constructor =
- EnsureConstructor(Utils::OpenHandle(*global_template));
+ global_constructor = EnsureConstructor(*global_template);
// Create a fresh template for the global proxy object.
proxy_template = ObjectTemplate::New();
- proxy_constructor =
- EnsureConstructor(Utils::OpenHandle(*proxy_template));
+ proxy_constructor = EnsureConstructor(*proxy_template);
// Set the global template to be the prototype template of
// global proxy template.
@@ -7332,6 +7350,13 @@
}
+void CpuProfiler::SetSamplingInterval(int us) {
+ ASSERT(us >= 0);
+ return reinterpret_cast<i::CpuProfiler*>(this)->set_sampling_interval(
+ i::TimeDelta::FromMicroseconds(us));
+}
+
+
const CpuProfile* CpuProfiler::GetCpuProfile(int index) {
return reinterpret_cast<const CpuProfile*>(
reinterpret_cast<i::CpuProfiler*>(this)->GetProfile(index));
diff --git a/src/assembler.cc b/src/assembler.cc
index a9587f3..44d5f22 100644
--- a/src/assembler.cc
+++ b/src/assembler.cc
@@ -798,7 +798,7 @@
target_object()->ShortPrint(out);
PrintF(out, ")");
} else if (rmode_ == EXTERNAL_REFERENCE) {
- ExternalReferenceEncoder ref_encoder;
+ ExternalReferenceEncoder ref_encoder(isolate);
PrintF(out, " (%s) (%p)",
ref_encoder.NameOfAddress(*target_reference_address()),
*target_reference_address());
diff --git a/src/ast.h b/src/ast.h
index f22c96c..0f01a3e 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -2038,7 +2038,8 @@
op_(op),
left_(left),
right_(right),
- pos_(pos) {
+ pos_(pos),
+ combined_type_(Type::Null(), isolate) {
ASSERT(Token::IsCompareOp(op));
}
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index ace134b..b7991d3 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -2604,7 +2604,7 @@
// We can only de-serialize a context if the isolate was initialized from
// a snapshot. Otherwise we have to build the context from scratch.
if (isolate->initialized_from_snapshot()) {
- native_context_ = Snapshot::NewContextFromSnapshot();
+ native_context_ = Snapshot::NewContextFromSnapshot(isolate);
} else {
native_context_ = Handle<Context>();
}
diff --git a/src/builtins.cc b/src/builtins.cc
index fea503b..b481483 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -594,7 +594,7 @@
if (accessor->HasElement(array, array, new_length, elms_obj)) {
maybe_result = accessor->Get(array, array, new_length, elms_obj);
} else {
- maybe_result = array->GetPrototype()->GetElement(len - 1);
+ maybe_result = array->GetPrototype()->GetElement(isolate, len - 1);
}
if (maybe_result->IsFailure()) return maybe_result;
MaybeObject* maybe_failure =
@@ -1461,6 +1461,16 @@
}
+static void Generate_StoreIC_PreMonomorphic(MacroAssembler* masm) {
+ StoreIC::GeneratePreMonomorphic(masm);
+}
+
+
+static void Generate_StoreIC_PreMonomorphic_Strict(MacroAssembler* masm) {
+ StoreIC::GeneratePreMonomorphic(masm);
+}
+
+
static void Generate_StoreIC_Miss(MacroAssembler* masm) {
StoreIC::GenerateMiss(masm);
}
@@ -1546,6 +1556,16 @@
}
+static void Generate_KeyedStoreIC_PreMonomorphic(MacroAssembler* masm) {
+ KeyedStoreIC::GeneratePreMonomorphic(masm);
+}
+
+
+static void Generate_KeyedStoreIC_PreMonomorphic_Strict(MacroAssembler* masm) {
+ KeyedStoreIC::GeneratePreMonomorphic(masm);
+}
+
+
static void Generate_KeyedStoreIC_NonStrictArguments(MacroAssembler* masm) {
KeyedStoreIC::GenerateNonStrictArguments(masm);
}
diff --git a/src/builtins.h b/src/builtins.h
index b7be785..cbfa1d7 100644
--- a/src/builtins.h
+++ b/src/builtins.h
@@ -162,6 +162,8 @@
\
V(StoreIC_Initialize, STORE_IC, UNINITIALIZED, \
Code::kNoExtraICState) \
+ V(StoreIC_PreMonomorphic, STORE_IC, PREMONOMORPHIC, \
+ Code::kNoExtraICState) \
V(StoreIC_Normal, STORE_IC, MONOMORPHIC, \
Code::kNoExtraICState) \
V(StoreIC_Megamorphic, STORE_IC, MEGAMORPHIC, \
@@ -174,6 +176,8 @@
Code::kNoExtraICState) \
V(StoreIC_Initialize_Strict, STORE_IC, UNINITIALIZED, \
kStrictMode) \
+ V(StoreIC_PreMonomorphic_Strict, STORE_IC, PREMONOMORPHIC, \
+ kStrictMode) \
V(StoreIC_Normal_Strict, STORE_IC, MONOMORPHIC, \
kStrictMode) \
V(StoreIC_Megamorphic_Strict, STORE_IC, MEGAMORPHIC, \
@@ -185,11 +189,15 @@
\
V(KeyedStoreIC_Initialize, KEYED_STORE_IC, UNINITIALIZED, \
Code::kNoExtraICState) \
+ V(KeyedStoreIC_PreMonomorphic, KEYED_STORE_IC, PREMONOMORPHIC, \
+ Code::kNoExtraICState) \
V(KeyedStoreIC_Generic, KEYED_STORE_IC, GENERIC, \
Code::kNoExtraICState) \
\
V(KeyedStoreIC_Initialize_Strict, KEYED_STORE_IC, UNINITIALIZED, \
kStrictMode) \
+ V(KeyedStoreIC_PreMonomorphic_Strict, KEYED_STORE_IC, PREMONOMORPHIC, \
+ kStrictMode) \
V(KeyedStoreIC_Generic_Strict, KEYED_STORE_IC, GENERIC, \
kStrictMode) \
V(KeyedStoreIC_NonStrictArguments, KEYED_STORE_IC, MONOMORPHIC, \
diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc
index 131fe31..23d4269 100644
--- a/src/code-stubs-hydrogen.cc
+++ b/src/code-stubs-hydrogen.cc
@@ -888,8 +888,7 @@
if (FLAG_trace_elements_transitions) {
// Tracing elements transitions is the job of the runtime.
- Add<HDeoptimize>("Deopt due to --trace-elements-transitions",
- Deoptimizer::EAGER);
+ Add<HDeoptimize>("Tracing elements transitions", Deoptimizer::EAGER);
} else {
info()->MarkAsSavesCallerDoubles();
diff --git a/src/compiler.cc b/src/compiler.cc
index bc65b1f..2bf012e 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -58,7 +58,8 @@
Zone* zone)
: flags_(LanguageModeField::encode(CLASSIC_MODE)),
script_(script),
- osr_ast_id_(BailoutId::None()) {
+ osr_ast_id_(BailoutId::None()),
+ osr_pc_offset_(0) {
Initialize(script->GetIsolate(), BASE, zone);
}
@@ -68,7 +69,8 @@
: flags_(LanguageModeField::encode(CLASSIC_MODE) | IsLazy::encode(true)),
shared_info_(shared_info),
script_(Handle<Script>(Script::cast(shared_info->script()))),
- osr_ast_id_(BailoutId::None()) {
+ osr_ast_id_(BailoutId::None()),
+ osr_pc_offset_(0) {
Initialize(script_->GetIsolate(), BASE, zone);
}
@@ -80,7 +82,8 @@
shared_info_(Handle<SharedFunctionInfo>(closure->shared())),
script_(Handle<Script>(Script::cast(shared_info_->script()))),
context_(closure->context()),
- osr_ast_id_(BailoutId::None()) {
+ osr_ast_id_(BailoutId::None()),
+ osr_pc_offset_(0) {
Initialize(script_->GetIsolate(), BASE, zone);
}
@@ -90,7 +93,8 @@
Zone* zone)
: flags_(LanguageModeField::encode(CLASSIC_MODE) |
IsLazy::encode(true)),
- osr_ast_id_(BailoutId::None()) {
+ osr_ast_id_(BailoutId::None()),
+ osr_pc_offset_(0) {
Initialize(isolate, STUB, zone);
code_stub_ = stub;
}
@@ -494,6 +498,8 @@
info()->SetCode(optimized_code);
}
RecordOptimizationStats();
+ // Add to the weak list of optimized code objects.
+ info()->context()->native_context()->AddOptimizedCode(*info()->code());
return SetLastStatus(SUCCEEDED);
}
@@ -875,9 +881,10 @@
static void InsertCodeIntoOptimizedCodeMap(CompilationInfo* info) {
Handle<Code> code = info->code();
- if (FLAG_cache_optimized_code &&
- info->osr_ast_id().IsNone() &&
- code->kind() == Code::OPTIMIZED_FUNCTION) {
+ if (code->kind() != Code::OPTIMIZED_FUNCTION) return; // Nothing to do.
+
+ // Cache non-OSR optimized code.
+ if (FLAG_cache_optimized_code && info->osr_ast_id().IsNone()) {
Handle<JSFunction> function = info->closure();
Handle<SharedFunctionInfo> shared(function->shared());
Handle<FixedArray> literals(function->literals());
@@ -889,9 +896,10 @@
static bool InstallCodeFromOptimizedCodeMap(CompilationInfo* info) {
- if (FLAG_cache_optimized_code &&
- info->osr_ast_id().IsNone() &&
- info->IsOptimizing()) {
+ if (!info->IsOptimizing()) return false; // Nothing to look up.
+
+ // Lookup non-OSR optimized code.
+ if (FLAG_cache_optimized_code && info->osr_ast_id().IsNone()) {
Handle<SharedFunctionInfo> shared = info->shared_info();
Handle<JSFunction> function = info->closure();
ASSERT(!function.is_null());
@@ -963,8 +971,9 @@
}
-void Compiler::RecompileConcurrent(Handle<JSFunction> closure) {
- ASSERT(closure->IsMarkedForConcurrentRecompilation());
+bool Compiler::RecompileConcurrent(Handle<JSFunction> closure,
+ uint32_t osr_pc_offset) {
+ bool compiling_for_osr = (osr_pc_offset != 0);
Isolate* isolate = closure->GetIsolate();
// Here we prepare compile data for the concurrent recompilation thread, but
@@ -978,23 +987,39 @@
closure->PrintName();
PrintF(" on next run.\n");
}
- return;
+ return false;
}
SmartPointer<CompilationInfo> info(new CompilationInfoWithZone(closure));
+ Handle<SharedFunctionInfo> shared = info->shared_info();
+
+ if (compiling_for_osr) {
+ BailoutId osr_ast_id =
+ shared->code()->TranslatePcOffsetToAstId(osr_pc_offset);
+ ASSERT(!osr_ast_id.IsNone());
+ info->SetOptimizing(osr_ast_id);
+ info->set_osr_pc_offset(osr_pc_offset);
+
+ if (FLAG_trace_osr) {
+ PrintF("[COSR - attempt to queue ");
+ closure->PrintName();
+ PrintF(" at AST id %d]\n", osr_ast_id.ToInt());
+ }
+ } else {
+ info->SetOptimizing(BailoutId::None());
+ }
+
VMState<COMPILER> state(isolate);
PostponeInterruptsScope postpone(isolate);
- Handle<SharedFunctionInfo> shared = info->shared_info();
int compiled_size = shared->end_position() - shared->start_position();
isolate->counters()->total_compile_size()->Increment(compiled_size);
- info->SetOptimizing(BailoutId::None());
{
CompilationHandleScope handle_scope(*info);
- if (InstallCodeFromOptimizedCodeMap(*info)) {
- return;
+ if (!compiling_for_osr && InstallCodeFromOptimizedCodeMap(*info)) {
+ return true;
}
if (Parser::Parse(*info)) {
@@ -1011,6 +1036,8 @@
info.Detach();
shared->code()->set_profiler_ticks(0);
isolate->optimizing_compiler_thread()->QueueForOptimization(compiler);
+ ASSERT(!isolate->has_pending_exception());
+ return true;
} else if (status == OptimizingCompiler::BAILED_OUT) {
isolate->clear_pending_exception();
InstallFullCode(*info);
@@ -1019,19 +1046,12 @@
}
}
- if (shared->code()->back_edges_patched_for_osr()) {
- // At this point we either put the function on recompilation queue or
- // aborted optimization. In either case we want to continue executing
- // the unoptimized code without running into OSR. If the unoptimized
- // code has been patched for OSR, unpatch it.
- Deoptimizer::RevertInterruptCode(isolate, shared->code());
- }
-
if (isolate->has_pending_exception()) isolate->clear_pending_exception();
+ return false;
}
-void Compiler::InstallOptimizedCode(OptimizingCompiler* optimizing_compiler) {
+bool Compiler::InstallOptimizedCode(OptimizingCompiler* optimizing_compiler) {
SmartPointer<CompilationInfo> info(optimizing_compiler->info());
// The function may have already been optimized by OSR. Simply continue.
// Except when OSR already disabled optimization for some reason.
@@ -1044,7 +1064,7 @@
PrintF(" as it has been disabled.\n");
}
ASSERT(!info->closure()->IsMarkedForInstallingRecompiledCode());
- return;
+ return false;
}
Isolate* isolate = info->isolate();
@@ -1091,6 +1111,168 @@
// profiler ticks to prevent too soon re-opt after a deopt.
info->shared_info()->code()->set_profiler_ticks(0);
ASSERT(!info->closure()->IsMarkedForInstallingRecompiledCode());
+ return status == OptimizingCompiler::SUCCEEDED;
+}
+
+
+static uint32_t CurrentPcOffset(Isolate* isolate,
+ Handle<JSFunction> function,
+ Handle<Code> unoptimized) {
+ JavaScriptFrameIterator it(isolate);
+ JavaScriptFrame* frame = it.frame();
+ ASSERT(frame->function() == *function);
+ ASSERT(frame->LookupCode() == *unoptimized);
+ ASSERT(unoptimized->contains(frame->pc()));
+
+ // Use linear search of the unoptimized code's back edge table to find
+ // the AST id matching the PC.
+ return static_cast<uint32_t>(frame->pc() - unoptimized->instruction_start());
+}
+
+
+static bool IsSuitableForOnStackReplacement(Isolate* isolate,
+ Handle<JSFunction> function,
+ Handle<Code> unoptimized) {
+ // Keep track of whether we've succeeded in optimizing.
+ if (!unoptimized->optimizable()) return false;
+ // If we are trying to do OSR when there are already optimized
+ // activations of the function, it means (a) the function is directly or
+ // indirectly recursive and (b) an optimized invocation has been
+ // deoptimized so that we are currently in an unoptimized activation.
+ // Check for optimized activations of this function.
+ for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
+ JavaScriptFrame* frame = it.frame();
+ if (frame->is_optimized() && frame->function() == *function) return false;
+ }
+
+ return true;
+}
+
+
+BailoutId Compiler::CompileForOnStackReplacement(Handle<JSFunction> function) {
+ Isolate* isolate = function->GetIsolate();
+ // We have hit a back edge in an unoptimized frame for a function that was
+ // selected for on-stack replacement. Find the unoptimized code object.
+ Handle<Code> unoptimized(function->shared()->code(), isolate);
+
+ Deoptimizer::RevertInterruptCode(isolate, *unoptimized);
+ if (FLAG_trace_osr) {
+ PrintF("[OSR - restored original interrupt calls in ");
+ function->PrintName();
+ PrintF("]\n");
+ }
+
+ if (!IsSuitableForOnStackReplacement(isolate, function, unoptimized)) {
+ return BailoutId::None();
+ }
+
+ uint32_t pc_offset = CurrentPcOffset(isolate, function, unoptimized);
+
+ BailoutId ast_id = unoptimized->TranslatePcOffsetToAstId(pc_offset);
+ ASSERT(!ast_id.IsNone());
+ if (FLAG_trace_osr) {
+ PrintF("[OSR - replacing at AST id %d in ", ast_id.ToInt());
+ function->PrintName();
+ PrintF("]\n");
+ }
+
+ // Try to compile the optimized code. A true return value from
+ // CompileOptimized means that compilation succeeded, not necessarily
+ // that optimization succeeded.
+ if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
+ function->IsOptimized()) {
+ DeoptimizationInputData* data = DeoptimizationInputData::cast(
+ function->code()->deoptimization_data());
+ if (data->OsrPcOffset()->value() >= 0) {
+ if (FLAG_trace_osr) {
+ PrintF("[OSR - entry, offset %d in optimized code]\n",
+ data->OsrPcOffset()->value());
+ }
+ ASSERT(BailoutId(data->OsrAstId()->value()) == ast_id);
+ return ast_id;
+ }
+ } else {
+ if (FLAG_trace_osr) {
+ PrintF("[OSR - optimization failed for ");
+ function->PrintName();
+ PrintF("]\n");
+ }
+ }
+ return BailoutId::None();
+}
+
+
+BailoutId Compiler::CompileForConcurrentOSR(Handle<JSFunction> function) {
+ Isolate* isolate = function->GetIsolate();
+ Handle<Code> unoptimized(function->shared()->code(), isolate);
+
+ uint32_t pc_offset = CurrentPcOffset(isolate, function, unoptimized);
+
+ if (isolate->optimizing_compiler_thread()->
+ IsQueuedForOSR(function, pc_offset)) {
+ // Still waiting for the optimizing compiler thread to finish. Carry on.
+ if (FLAG_trace_osr) {
+ PrintF("[COSR - polling recompile tasks for ");
+ function->PrintName();
+ PrintF("]\n");
+ }
+ return BailoutId::None();
+ }
+
+ OptimizingCompiler* compiler = isolate->optimizing_compiler_thread()->
+ FindReadyOSRCandidate(function, pc_offset);
+
+ if (compiler != NULL) {
+ if (FLAG_trace_osr) {
+ PrintF("[COSR - optimization complete for ");
+ function->PrintName();
+ PrintF(", restoring interrupt calls]\n");
+ }
+ Deoptimizer::RevertInterruptCode(isolate, *unoptimized);
+
+ BailoutId ast_id = compiler->info()->osr_ast_id();
+
+ bool succeeded = InstallOptimizedCode(compiler);
+
+ isolate->optimizing_compiler_thread()->RemoveStaleOSRCandidates();
+
+ if (!succeeded) {
+ if (FLAG_trace_osr) {
+ PrintF("[COSR - optimization failed for ");
+ function->PrintName();
+ PrintF("]\n");
+ }
+ return BailoutId::None();
+ }
+
+ DeoptimizationInputData* data = DeoptimizationInputData::cast(
+ function->code()->deoptimization_data());
+
+ if (data->OsrPcOffset()->value() >= 0) {
+ ASSERT(BailoutId(data->OsrAstId()->value()) == ast_id);
+ if (FLAG_trace_osr) {
+ PrintF("[COSR - entry at AST id %d, offset %d in optimized code]\n",
+ ast_id.ToInt(), data->OsrPcOffset()->value());
+ }
+ return ast_id;
+ }
+ return BailoutId::None();
+ }
+
+ if (!IsSuitableForOnStackReplacement(isolate, function, unoptimized)) {
+ if (FLAG_trace_osr) {
+ PrintF("[COSR - ");
+ function->PrintName();
+ PrintF(" is unsuitable, restoring interrupt calls]\n");
+ }
+ Deoptimizer::RevertInterruptCode(isolate, *unoptimized);
+ return BailoutId::None();
+ }
+
+ if (!RecompileConcurrent(function, pc_offset)) {
+ Deoptimizer::RevertInterruptCode(isolate, *unoptimized);
+ }
+ return BailoutId::None();
}
diff --git a/src/compiler.h b/src/compiler.h
index 4f6a472..98b93d3 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -308,6 +308,14 @@
return abort_due_to_dependency_;
}
+ void set_osr_pc_offset(uint32_t pc_offset) {
+ osr_pc_offset_ = pc_offset;
+ }
+
+ bool HasSameOsrEntry(Handle<JSFunction> function, uint32_t pc_offset) {
+ return osr_pc_offset_ == pc_offset && function.is_identical_to(closure_);
+ }
+
protected:
CompilationInfo(Handle<Script> script,
Zone* zone);
@@ -402,6 +410,9 @@
// Compilation mode flag and whether deoptimization is allowed.
Mode mode_;
BailoutId osr_ast_id_;
+ // The pc_offset corresponding to osr_ast_id_ in unoptimized code.
+ // We can look this up in the back edge table, but cache it for quick access.
+ uint32_t osr_pc_offset_;
// Flag whether compilation needs to be aborted due to dependency change.
bool abort_due_to_dependency_;
@@ -600,7 +611,8 @@
// success and false if the compilation resulted in a stack overflow.
static bool CompileLazy(CompilationInfo* info);
- static void RecompileConcurrent(Handle<JSFunction> function);
+ static bool RecompileConcurrent(Handle<JSFunction> function,
+ uint32_t osr_pc_offset = 0);
// Compile a shared function info object (the function is possibly lazily
// compiled).
@@ -613,7 +625,11 @@
bool is_toplevel,
Handle<Script> script);
- static void InstallOptimizedCode(OptimizingCompiler* info);
+ static bool InstallOptimizedCode(OptimizingCompiler* info);
+
+ static BailoutId CompileForOnStackReplacement(Handle<JSFunction> function);
+
+ static BailoutId CompileForConcurrentOSR(Handle<JSFunction> function);
#ifdef ENABLE_DEBUGGER_SUPPORT
static bool MakeCodeForLiveEdit(CompilationInfo* info);
diff --git a/src/contexts.cc b/src/contexts.cc
index 5981fd6..441ef9d 100644
--- a/src/contexts.cc
+++ b/src/contexts.cc
@@ -319,14 +319,48 @@
}
+void Context::SetOptimizedFunctionsListHead(Object* head) {
+ ASSERT(IsNativeContext());
+ set(OPTIMIZED_FUNCTIONS_LIST, head);
+}
+
+
Object* Context::OptimizedFunctionsListHead() {
ASSERT(IsNativeContext());
return get(OPTIMIZED_FUNCTIONS_LIST);
}
-void Context::ClearOptimizedFunctions() {
- set(OPTIMIZED_FUNCTIONS_LIST, GetHeap()->undefined_value());
+void Context::AddOptimizedCode(Code* code) {
+ ASSERT(IsNativeContext());
+ ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION);
+ ASSERT(code->next_code_link()->IsUndefined());
+ code->set_next_code_link(get(OPTIMIZED_CODE_LIST));
+ set(OPTIMIZED_CODE_LIST, code);
+}
+
+
+void Context::SetOptimizedCodeListHead(Object* head) {
+ ASSERT(IsNativeContext());
+ set(OPTIMIZED_CODE_LIST, head);
+}
+
+
+Object* Context::OptimizedCodeListHead() {
+ ASSERT(IsNativeContext());
+ return get(OPTIMIZED_CODE_LIST);
+}
+
+
+void Context::SetDeoptimizedCodeListHead(Object* head) {
+ ASSERT(IsNativeContext());
+ set(DEOPTIMIZED_CODE_LIST, head);
+}
+
+
+Object* Context::DeoptimizedCodeListHead() {
+ ASSERT(IsNativeContext());
+ return get(DEOPTIMIZED_CODE_LIST);
}
diff --git a/src/contexts.h b/src/contexts.h
index 88c3cd9..189c215 100644
--- a/src/contexts.h
+++ b/src/contexts.h
@@ -337,8 +337,10 @@
// Properties from here are treated as weak references by the full GC.
// Scavenge treats them as strong references.
OPTIMIZED_FUNCTIONS_LIST, // Weak.
- MAP_CACHE_INDEX, // Weak.
- NEXT_CONTEXT_LINK, // Weak.
+ OPTIMIZED_CODE_LIST, // Weak.
+ DEOPTIMIZED_CODE_LIST, // Weak.
+ MAP_CACHE_INDEX, // Weak.
+ NEXT_CONTEXT_LINK, // Weak.
// Total number of slots.
NATIVE_CONTEXT_SLOTS,
@@ -428,11 +430,19 @@
// Mark the native context with out of memory.
inline void mark_out_of_memory();
- // A native context hold a list of all functions which have been optimized.
+ // A native context holds a list of all functions with optimized code.
void AddOptimizedFunction(JSFunction* function);
void RemoveOptimizedFunction(JSFunction* function);
+ void SetOptimizedFunctionsListHead(Object* head);
Object* OptimizedFunctionsListHead();
- void ClearOptimizedFunctions();
+
+ // The native context also stores a list of all optimized code and a
+ // list of all deoptimized code, which are needed by the deoptimizer.
+ void AddOptimizedCode(Code* code);
+ void SetOptimizedCodeListHead(Object* head);
+ Object* OptimizedCodeListHead();
+ void SetDeoptimizedCodeListHead(Object* head);
+ Object* DeoptimizedCodeListHead();
Handle<Object> ErrorMessageForCodeGenerationFromStrings();
diff --git a/src/cpu-profiler.cc b/src/cpu-profiler.cc
index 34bebb8..35fe788 100644
--- a/src/cpu-profiler.cc
+++ b/src/cpu-profiler.cc
@@ -363,6 +363,8 @@
CpuProfiler::CpuProfiler(Isolate* isolate)
: isolate_(isolate),
+ sampling_interval_(TimeDelta::FromMicroseconds(
+ FLAG_cpu_profiler_sampling_interval)),
profiles_(new CpuProfilesCollection()),
next_profile_uid_(1),
generator_(NULL),
@@ -376,6 +378,8 @@
ProfileGenerator* test_generator,
ProfilerEventsProcessor* test_processor)
: isolate_(isolate),
+ sampling_interval_(TimeDelta::FromMicroseconds(
+ FLAG_cpu_profiler_sampling_interval)),
profiles_(test_profiles),
next_profile_uid_(1),
generator_(test_generator),
@@ -390,6 +394,12 @@
}
+void CpuProfiler::set_sampling_interval(TimeDelta value) {
+ ASSERT(!is_profiling_);
+ sampling_interval_ = value;
+}
+
+
void CpuProfiler::ResetProfiles() {
delete profiles_;
profiles_ = new CpuProfilesCollection();
@@ -418,8 +428,7 @@
generator_ = new ProfileGenerator(profiles_);
Sampler* sampler = logger->sampler();
processor_ = new ProfilerEventsProcessor(
- generator_, sampler,
- TimeDelta::FromMicroseconds(FLAG_cpu_profiler_sampling_interval));
+ generator_, sampler, sampling_interval_);
is_profiling_ = true;
// Enumerate stuff we already have in the heap.
ASSERT(isolate_->heap()->HasBeenSetUp());
diff --git a/src/cpu-profiler.h b/src/cpu-profiler.h
index a6eccff..e36c301 100644
--- a/src/cpu-profiler.h
+++ b/src/cpu-profiler.h
@@ -31,6 +31,7 @@
#include "allocation.h"
#include "atomicops.h"
#include "circular-queue.h"
+#include "platform/time.h"
#include "sampler.h"
#include "unbound-queue.h"
@@ -203,6 +204,7 @@
virtual ~CpuProfiler();
+ void set_sampling_interval(TimeDelta value);
void StartProfiling(const char* title, bool record_samples = false);
void StartProfiling(String* title, bool record_samples);
CpuProfile* StopProfiling(const char* title);
@@ -260,6 +262,7 @@
void LogBuiltins();
Isolate* isolate_;
+ TimeDelta sampling_interval_;
CpuProfilesCollection* profiles_;
unsigned next_profile_uid_;
ProfileGenerator* generator_;
diff --git a/src/d8-debug.cc b/src/d8-debug.cc
index 2905500..602ae16 100644
--- a/src/d8-debug.cc
+++ b/src/d8-debug.cc
@@ -29,8 +29,9 @@
#include "d8.h"
#include "d8-debug.h"
-#include "platform.h"
#include "debug-agent.h"
+#include "platform.h"
+#include "platform/socket.h"
namespace v8 {
@@ -171,21 +172,14 @@
void RemoteDebugger::Run() {
bool ok;
- // Make sure that socket support is initialized.
- ok = i::Socket::SetUp();
- if (!ok) {
- printf("Unable to initialize socket support %d\n", i::Socket::LastError());
- return;
- }
-
// Connect to the debugger agent.
- conn_ = i::OS::CreateSocket();
+ conn_ = new i::Socket;
static const int kPortStrSize = 6;
char port_str[kPortStrSize];
i::OS::SNPrintF(i::Vector<char>(port_str, kPortStrSize), "%d", port_);
ok = conn_->Connect("localhost", port_str);
if (!ok) {
- printf("Unable to connect to debug agent %d\n", i::Socket::LastError());
+ printf("Unable to connect to debug agent %d\n", i::Socket::GetLastError());
return;
}
diff --git a/src/debug-agent.cc b/src/debug-agent.cc
index 51bd4b1..aad3608 100644
--- a/src/debug-agent.cc
+++ b/src/debug-agent.cc
@@ -25,12 +25,12 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#ifdef ENABLE_DEBUGGER_SUPPORT
#include "v8.h"
#include "debug.h"
#include "debug-agent.h"
-
-#ifdef ENABLE_DEBUGGER_SUPPORT
+#include "platform/socket.h"
namespace v8 {
namespace internal {
@@ -44,6 +44,27 @@
}
+DebuggerAgent::DebuggerAgent(Isolate* isolate, const char* name, int port)
+ : Thread(name),
+ isolate_(isolate),
+ name_(StrDup(name)),
+ port_(port),
+ server_(new Socket),
+ terminate_(false),
+ session_(NULL),
+ terminate_now_(0),
+ listening_(0) {
+ ASSERT(isolate_->debugger_agent_instance() == NULL);
+ isolate_->set_debugger_agent_instance(this);
+}
+
+
+DebuggerAgent::~DebuggerAgent() {
+ isolate_->set_debugger_agent_instance(NULL);
+ delete server_;
+}
+
+
// Debugger agent main thread.
void DebuggerAgent::Run() {
// Allow this socket to reuse port even if still in TIME_WAIT.
@@ -112,8 +133,10 @@
// If another session is already established terminate this one.
if (session_ != NULL) {
- client->Send(kCreateSessionMessage, StrLength(kCreateSessionMessage));
+ int len = StrLength(kCreateSessionMessage);
+ int res = client->Send(kCreateSessionMessage, len);
delete client;
+ USE(res);
return;
}
@@ -228,7 +251,7 @@
const char* const DebuggerAgentUtil::kContentLength = "Content-Length";
-SmartArrayPointer<char> DebuggerAgentUtil::ReceiveMessage(const Socket* conn) {
+SmartArrayPointer<char> DebuggerAgentUtil::ReceiveMessage(Socket* conn) {
int received;
// Read header.
@@ -245,7 +268,7 @@
prev_c = c;
received = conn->Receive(&c, 1);
if (received == 0) {
- PrintF("Error %d\n", Socket::LastError());
+ PrintF("Error %d\n", Socket::GetLastError());
return SmartArrayPointer<char>();
}
@@ -307,7 +330,7 @@
char* buffer = NewArray<char>(content_length + 1);
received = ReceiveAll(conn, buffer, content_length);
if (received < content_length) {
- PrintF("Error %d\n", Socket::LastError());
+ PrintF("Error %d\n", Socket::GetLastError());
return SmartArrayPointer<char>();
}
buffer[content_length] = '\0';
@@ -316,7 +339,7 @@
}
-bool DebuggerAgentUtil::SendConnectMessage(const Socket* conn,
+bool DebuggerAgentUtil::SendConnectMessage(Socket* conn,
const char* embedding_host) {
static const int kBufferSize = 80;
char buffer[kBufferSize]; // Sending buffer.
@@ -362,7 +385,7 @@
}
-bool DebuggerAgentUtil::SendMessage(const Socket* conn,
+bool DebuggerAgentUtil::SendMessage(Socket* conn,
const Vector<uint16_t> message) {
static const int kBufferSize = 80;
char buffer[kBufferSize]; // Sending buffer both for header and body.
@@ -377,14 +400,17 @@
}
// Send the header.
- int len;
- len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
- "%s: %d\r\n", kContentLength, utf8_len);
- conn->Send(buffer, len);
+ int len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
+ "%s: %d\r\n", kContentLength, utf8_len);
+ if (conn->Send(buffer, len) < len) {
+ return false;
+ }
// Terminate header with empty line.
len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n");
- conn->Send(buffer, len);
+ if (conn->Send(buffer, len) < len) {
+ return false;
+ }
// Send message body as UTF-8.
int buffer_position = 0; // Current buffer position.
@@ -404,13 +430,19 @@
const int kEncodedSurrogateLength =
unibrow::Utf16::kUtf8BytesToCodeASurrogate;
ASSERT(buffer_position >= kEncodedSurrogateLength);
- conn->Send(buffer, buffer_position - kEncodedSurrogateLength);
+ len = buffer_position - kEncodedSurrogateLength;
+ if (conn->Send(buffer, len) < len) {
+ return false;
+ }
for (int i = 0; i < kEncodedSurrogateLength; i++) {
buffer[i] = buffer[buffer_position + i];
}
buffer_position = kEncodedSurrogateLength;
} else {
- conn->Send(buffer, buffer_position);
+ len = buffer_position;
+ if (conn->Send(buffer, len) < len) {
+ return false;
+ }
buffer_position = 0;
}
}
@@ -421,7 +453,7 @@
}
-bool DebuggerAgentUtil::SendMessage(const Socket* conn,
+bool DebuggerAgentUtil::SendMessage(Socket* conn,
const v8::Handle<v8::String> request) {
static const int kBufferSize = 80;
char buffer[kBufferSize]; // Sending buffer both for header and body.
@@ -430,24 +462,30 @@
v8::String::Utf8Value utf8_request(request);
// Send the header.
- int len;
- len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
- "Content-Length: %d\r\n", utf8_request.length());
- conn->Send(buffer, len);
+ int len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
+ "Content-Length: %d\r\n", utf8_request.length());
+ if (conn->Send(buffer, len) < len) {
+ return false;
+ }
// Terminate header with empty line.
len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n");
- conn->Send(buffer, len);
+ if (conn->Send(buffer, len) < len) {
+ return false;
+ }
// Send message body as UTF-8.
- conn->Send(*utf8_request, utf8_request.length());
+ len = utf8_request.length();
+ if (conn->Send(*utf8_request, len) < len) {
+ return false;
+ }
return true;
}
// Receive the full buffer before returning unless an error occours.
-int DebuggerAgentUtil::ReceiveAll(const Socket* conn, char* data, int len) {
+int DebuggerAgentUtil::ReceiveAll(Socket* conn, char* data, int len) {
int total_received = 0;
while (total_received < len) {
int received = conn->Receive(data + total_received, len - total_received);
diff --git a/src/debug-agent.h b/src/debug-agent.h
index 9d7c62b..138e51a 100644
--- a/src/debug-agent.h
+++ b/src/debug-agent.h
@@ -37,27 +37,15 @@
// Forward decelrations.
class DebuggerAgentSession;
+class Socket;
// Debugger agent which starts a socket listener on the debugger port and
// handles connection from a remote debugger.
class DebuggerAgent: public Thread {
public:
- DebuggerAgent(Isolate* isolate, const char* name, int port)
- : Thread(name),
- isolate_(isolate),
- name_(StrDup(name)), port_(port),
- server_(OS::CreateSocket()), terminate_(false),
- session_(NULL),
- terminate_now_(0),
- listening_(0) {
- ASSERT(isolate_->debugger_agent_instance() == NULL);
- isolate_->set_debugger_agent_instance(this);
- }
- ~DebuggerAgent() {
- isolate_->set_debugger_agent_instance(NULL);
- delete server_;
- }
+ DebuggerAgent(Isolate* isolate, const char* name, int port);
+ ~DebuggerAgent();
void Shutdown();
void WaitUntilListening();
@@ -116,13 +104,11 @@
public:
static const char* const kContentLength;
- static SmartArrayPointer<char> ReceiveMessage(const Socket* conn);
- static bool SendConnectMessage(const Socket* conn,
- const char* embedding_host);
- static bool SendMessage(const Socket* conn, const Vector<uint16_t> message);
- static bool SendMessage(const Socket* conn,
- const v8::Handle<v8::String> message);
- static int ReceiveAll(const Socket* conn, char* data, int len);
+ static SmartArrayPointer<char> ReceiveMessage(Socket* conn);
+ static bool SendConnectMessage(Socket* conn, const char* embedding_host);
+ static bool SendMessage(Socket* conn, const Vector<uint16_t> message);
+ static bool SendMessage(Socket* conn, const v8::Handle<v8::String> message);
+ static int ReceiveAll(Socket* conn, char* data, int len);
};
} } // namespace v8::internal
diff --git a/src/debug.cc b/src/debug.cc
index 9f38601..c3d737e 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -3433,15 +3433,11 @@
v8::Debug::DebugBreak();
}
- if (Socket::SetUp()) {
- if (agent_ == NULL) {
- agent_ = new DebuggerAgent(isolate_, name, port);
- agent_->Start();
- }
- return true;
+ if (agent_ == NULL) {
+ agent_ = new DebuggerAgent(isolate_, name, port);
+ agent_->Start();
}
-
- return false;
+ return true;
}
diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc
index 49d046b..61ce780 100644
--- a/src/deoptimizer.cc
+++ b/src/deoptimizer.cc
@@ -56,11 +56,10 @@
DeoptimizerData::DeoptimizerData(MemoryAllocator* allocator)
: allocator_(allocator),
- current_(NULL),
#ifdef ENABLE_DEBUGGER_SUPPORT
deoptimized_frame_info_(NULL),
#endif
- deoptimizing_code_list_(NULL) {
+ current_(NULL) {
for (int i = 0; i < Deoptimizer::kBailoutTypesWithCodeEntry; ++i) {
deopt_entry_code_entries_[i] = -1;
deopt_entry_code_[i] = AllocateCodeChunk(allocator);
@@ -73,14 +72,6 @@
allocator_->Free(deopt_entry_code_[i]);
deopt_entry_code_[i] = NULL;
}
-
- DeoptimizingCodeListNode* current = deoptimizing_code_list_;
- while (current != NULL) {
- DeoptimizingCodeListNode* prev = current;
- current = current->next();
- delete prev;
- }
- deoptimizing_code_list_ = NULL;
}
@@ -93,33 +84,19 @@
#endif
-Code* DeoptimizerData::FindDeoptimizingCode(Address addr) {
- for (DeoptimizingCodeListNode* node = deoptimizing_code_list_;
- node != NULL;
- node = node->next()) {
- if (node->code()->contains(addr)) return *node->code();
- }
- return NULL;
-}
-
-
-void DeoptimizerData::RemoveDeoptimizingCode(Code* code) {
- for (DeoptimizingCodeListNode *prev = NULL, *cur = deoptimizing_code_list_;
- cur != NULL;
- prev = cur, cur = cur->next()) {
- if (*cur->code() == code) {
- if (prev == NULL) {
- deoptimizing_code_list_ = cur->next();
- } else {
- prev->set_next(cur->next());
- }
- delete cur;
- return;
+Code* Deoptimizer::FindDeoptimizingCode(Address addr) {
+ if (function_->IsHeapObject()) {
+ // Search all deoptimizing code in the native context of the function.
+ Context* native_context = function_->context()->native_context();
+ Object* element = native_context->DeoptimizedCodeListHead();
+ while (!element->IsUndefined()) {
+ Code* code = Code::cast(element);
+ ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION);
+ if (code->contains(addr)) return code;
+ element = code->next_code_link();
}
}
- // Deoptimizing code is removed through weak callback. Each object is expected
- // to be removed once and only once.
- UNREACHABLE();
+ return NULL;
}
@@ -289,27 +266,42 @@
void Deoptimizer::VisitAllOptimizedFunctionsForContext(
Context* context, OptimizedFunctionVisitor* visitor) {
- Isolate* isolate = context->GetIsolate();
- Zone zone(isolate);
DisallowHeapAllocation no_allocation;
ASSERT(context->IsNativeContext());
visitor->EnterContext(context);
- // Create a snapshot of the optimized functions list. This is needed because
- // visitors might remove more than one link from the list at once.
- ZoneList<JSFunction*> snapshot(1, &zone);
+ // Visit the list of optimized functions, removing elements that
+ // no longer refer to optimized code.
+ JSFunction* prev = NULL;
Object* element = context->OptimizedFunctionsListHead();
while (!element->IsUndefined()) {
- JSFunction* element_function = JSFunction::cast(element);
- snapshot.Add(element_function, &zone);
- element = element_function->next_function_link();
- }
-
- // Run through the snapshot of optimized functions and visit them.
- for (int i = 0; i < snapshot.length(); ++i) {
- visitor->VisitFunction(snapshot.at(i));
+ JSFunction* function = JSFunction::cast(element);
+ Object* next = function->next_function_link();
+ if (function->code()->kind() != Code::OPTIMIZED_FUNCTION ||
+ (visitor->VisitFunction(function),
+ function->code()->kind() != Code::OPTIMIZED_FUNCTION)) {
+ // The function no longer refers to optimized code, or the visitor
+ // changed the code to which it refers to no longer be optimized code.
+ // Remove the function from this list.
+ if (prev != NULL) {
+ prev->set_next_function_link(next);
+ } else {
+ context->SetOptimizedFunctionsListHead(next);
+ }
+ // The visitor should not alter the link directly.
+ ASSERT(function->next_function_link() == next);
+ // Set the next function link to undefined to indicate it is no longer
+ // in the optimized functions list.
+ function->set_next_function_link(context->GetHeap()->undefined_value());
+ } else {
+ // The visitor should not alter the link directly.
+ ASSERT(function->next_function_link() == next);
+ // preserve this element.
+ prev = function;
+ }
+ element = next;
}
visitor->LeaveContext(context);
@@ -321,7 +313,7 @@
OptimizedFunctionVisitor* visitor) {
DisallowHeapAllocation no_allocation;
- // Run through the list of all native contexts and deoptimize.
+ // Run through the list of all native contexts.
Object* context = isolate->heap()->native_contexts_list();
while (!context->IsUndefined()) {
VisitAllOptimizedFunctionsForContext(Context::cast(context), visitor);
@@ -330,220 +322,164 @@
}
-// Removes the functions selected by the given filter from the optimized
-// function list of the given context and adds their code to the list of
-// code objects to be deoptimized.
-static void SelectCodeToDeoptimize(Context* context,
- OptimizedFunctionFilter* filter,
- ZoneList<Code*>* codes,
- Zone* zone,
- Object* undefined) {
+// Unlink functions referring to code marked for deoptimization, then move
+// marked code from the optimized code list to the deoptimized code list,
+// and patch code for lazy deopt.
+void Deoptimizer::DeoptimizeMarkedCodeForContext(Context* context) {
DisallowHeapAllocation no_allocation;
- Object* current = context->get(Context::OPTIMIZED_FUNCTIONS_LIST);
- Object* remainder_head = undefined;
- Object* remainder_tail = undefined;
- // TODO(titzer): rewrite to not modify unselected functions.
- while (current != undefined) {
- JSFunction* function = JSFunction::cast(current);
- current = function->next_function_link();
- if (filter->TakeFunction(function)) {
- // Extract this function from the context's list and remember the code.
+ // A "closure" that unlinks optimized code that is going to be
+ // deoptimized from the functions that refer to it.
+ class SelectedCodeUnlinker: public OptimizedFunctionVisitor {
+ public:
+ virtual void EnterContext(Context* context) { } // Don't care.
+ virtual void LeaveContext(Context* context) { } // Don't care.
+ virtual void VisitFunction(JSFunction* function) {
Code* code = function->code();
- ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION);
- if (code->marked_for_deoptimization()) {
- ASSERT(codes->Contains(code));
- } else {
- code->set_marked_for_deoptimization(true);
- codes->Add(code, zone);
- }
+ if (!code->marked_for_deoptimization()) return;
+
+ // Unlink this function and evict from optimized code map.
SharedFunctionInfo* shared = function->shared();
- // Replace the function's code with the shared code.
function->set_code(shared->code());
- // Evict the code from the optimized code map.
shared->EvictFromOptimizedCodeMap(code, "deoptimized function");
- // Remove the function from the optimized functions list.
- function->set_next_function_link(undefined);
if (FLAG_trace_deopt) {
- PrintF("[forced deoptimization: ");
+ PrintF("[deoptimizer unlinked: ");
function->PrintName();
PrintF(" / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
}
- } else {
- // Don't select this function; link it back into the list.
- if (remainder_head == undefined) {
- remainder_head = function;
- } else {
- JSFunction::cast(remainder_tail)->set_next_function_link(function);
- }
- remainder_tail = function;
}
+ };
+
+ // Unlink all functions that refer to marked code.
+ SelectedCodeUnlinker unlinker;
+ VisitAllOptimizedFunctionsForContext(context, &unlinker);
+
+ // Move marked code from the optimized code list to the deoptimized
+ // code list, collecting them into a ZoneList.
+ Isolate* isolate = context->GetHeap()->isolate();
+ Zone zone(isolate);
+ ZoneList<Code*> codes(10, &zone);
+
+ // Walk over all optimized code objects in this native context.
+ Code* prev = NULL;
+ Object* element = context->OptimizedCodeListHead();
+ while (!element->IsUndefined()) {
+ Code* code = Code::cast(element);
+ ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION);
+ Object* next = code->next_code_link();
+ if (code->marked_for_deoptimization()) {
+ // Put the code into the list for later patching.
+ codes.Add(code, &zone);
+
+ if (prev != NULL) {
+ // Skip this code in the optimized code list.
+ prev->set_next_code_link(next);
+ } else {
+ // There was no previous node, the next node is the new head.
+ context->SetOptimizedCodeListHead(next);
+ }
+
+ // Move the code to the _deoptimized_ code list.
+ code->set_next_code_link(context->DeoptimizedCodeListHead());
+ context->SetDeoptimizedCodeListHead(code);
+ } else {
+ // Not marked; preserve this element.
+ prev = code;
+ }
+ element = next;
}
- if (remainder_tail != undefined) {
- JSFunction::cast(remainder_tail)->set_next_function_link(undefined);
+
+ // TODO(titzer): we need a handle scope only because of the macro assembler,
+ // which is only used in EnsureCodeForDeoptimizationEntry.
+ HandleScope scope(isolate);
+ // Now patch all the codes for deoptimization.
+ for (int i = 0; i < codes.length(); i++) {
+ // It is finally time to die, code object.
+ // Do platform-specific patching to force any activations to lazy deopt.
+ PatchCodeForDeoptimization(isolate, codes[i]);
+
+ // We might be in the middle of incremental marking with compaction.
+ // Tell collector to treat this code object in a special way and
+ // ignore all slots that might have been recorded on it.
+ isolate->heap()->mark_compact_collector()->InvalidateCode(codes[i]);
}
- context->set(Context::OPTIMIZED_FUNCTIONS_LIST, remainder_head);
}
-class DeoptimizeAllFilter : public OptimizedFunctionFilter {
- public:
- virtual bool TakeFunction(JSFunction* function) {
- return true;
- }
-};
-
-
-class DeoptimizeWithMatchingCodeFilter : public OptimizedFunctionFilter {
- public:
- explicit DeoptimizeWithMatchingCodeFilter(Code* code) : code_(code) {}
- virtual bool TakeFunction(JSFunction* function) {
- return function->code() == code_;
- }
- private:
- Code* code_;
-};
-
-
-class DeoptimizeMarkedCodeFilter : public OptimizedFunctionFilter {
- public:
- virtual bool TakeFunction(JSFunction* function) {
- return function->code()->marked_for_deoptimization();
- }
-};
-
-
void Deoptimizer::DeoptimizeAll(Isolate* isolate) {
- DisallowHeapAllocation no_allocation;
-
if (FLAG_trace_deopt) {
- PrintF("[deoptimize all contexts]\n");
+ PrintF("[deoptimize all code in all contexts]\n");
}
+ DisallowHeapAllocation no_allocation;
+ // For all contexts, mark all code, then deoptimize.
+ Object* context = isolate->heap()->native_contexts_list();
+ while (!context->IsUndefined()) {
+ Context* native_context = Context::cast(context);
+ MarkAllCodeForContext(native_context);
+ DeoptimizeMarkedCodeForContext(native_context);
+ context = native_context->get(Context::NEXT_CONTEXT_LINK);
+ }
+}
- DeoptimizeAllFilter filter;
- DeoptimizeAllFunctionsWith(isolate, &filter);
+
+void Deoptimizer::DeoptimizeMarkedCode(Isolate* isolate) {
+ if (FLAG_trace_deopt) {
+ PrintF("[deoptimize marked code in all contexts]\n");
+ }
+ DisallowHeapAllocation no_allocation;
+ // For all contexts, deoptimize code already marked.
+ Object* context = isolate->heap()->native_contexts_list();
+ while (!context->IsUndefined()) {
+ Context* native_context = Context::cast(context);
+ DeoptimizeMarkedCodeForContext(native_context);
+ context = native_context->get(Context::NEXT_CONTEXT_LINK);
+ }
}
void Deoptimizer::DeoptimizeGlobalObject(JSObject* object) {
- DisallowHeapAllocation no_allocation;
- DeoptimizeAllFilter filter;
+ if (FLAG_trace_deopt) {
+ PrintF("[deoptimize global object @ 0x%08" V8PRIxPTR "]\n",
+ reinterpret_cast<intptr_t>(object));
+ }
if (object->IsJSGlobalProxy()) {
Object* proto = object->GetPrototype();
ASSERT(proto->IsJSGlobalObject());
- DeoptimizeAllFunctionsForContext(
- GlobalObject::cast(proto)->native_context(), &filter);
+ Context* native_context = GlobalObject::cast(proto)->native_context();
+ MarkAllCodeForContext(native_context);
+ DeoptimizeMarkedCodeForContext(native_context);
} else if (object->IsGlobalObject()) {
- DeoptimizeAllFunctionsForContext(
- GlobalObject::cast(object)->native_context(), &filter);
+ Context* native_context = GlobalObject::cast(object)->native_context();
+ MarkAllCodeForContext(native_context);
+ DeoptimizeMarkedCodeForContext(native_context);
+ }
+}
+
+
+void Deoptimizer::MarkAllCodeForContext(Context* context) {
+ Object* element = context->OptimizedCodeListHead();
+ while (!element->IsUndefined()) {
+ Code* code = Code::cast(element);
+ ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION);
+ code->set_marked_for_deoptimization(true);
+ element = code->next_code_link();
}
}
void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
Code* code = function->code();
- if (code->kind() != Code::OPTIMIZED_FUNCTION) return;
- DeoptimizeWithMatchingCodeFilter filter(code);
- DeoptimizeAllFunctionsForContext(
- function->context()->native_context(), &filter);
-}
-
-
-void Deoptimizer::DeoptimizeAllFunctionsForContext(
- Context* context, OptimizedFunctionFilter* filter) {
- ASSERT(context->IsNativeContext());
- Isolate* isolate = context->GetIsolate();
- Object* undefined = isolate->heap()->undefined_value();
- Zone zone(isolate);
- ZoneList<Code*> codes(4, &zone);
- SelectCodeToDeoptimize(context, filter, &codes, &zone, undefined);
- for (int i = 0; i < codes.length(); i++) {
- DeoptimizeCode(isolate, codes.at(i));
+ if (code->kind() == Code::OPTIMIZED_FUNCTION) {
+ // Mark the code for deoptimization and unlink any functions that also
+ // refer to that code. The code cannot be shared across native contexts,
+ // so we only need to search one.
+ code->set_marked_for_deoptimization(true);
+ DeoptimizeMarkedCodeForContext(function->context()->native_context());
}
}
-void Deoptimizer::DeoptimizeAllFunctionsWith(Isolate* isolate,
- OptimizedFunctionFilter* filter) {
- DisallowHeapAllocation no_allocation;
-
- // Run through the list of all native contexts and deoptimize.
- Object* context = isolate->heap()->native_contexts_list();
- while (!context->IsUndefined()) {
- DeoptimizeAllFunctionsForContext(Context::cast(context), filter);
- context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
- }
-}
-
-
-void Deoptimizer::DeoptimizeCodeList(Isolate* isolate, ZoneList<Code*>* codes) {
- if (codes->length() == 0) return; // Nothing to do.
-
- // Mark the code; any functions refering to this code will be selected.
- for (int i = 0; i < codes->length(); i++) {
- ASSERT(!codes->at(i)->marked_for_deoptimization());
- codes->at(i)->set_marked_for_deoptimization(true);
- }
-
- // For all contexts, remove optimized functions that refer to the selected
- // code from the optimized function lists.
- Object* undefined = isolate->heap()->undefined_value();
- Zone zone(isolate);
- Object* list = isolate->heap()->native_contexts_list();
- DeoptimizeMarkedCodeFilter filter;
- while (!list->IsUndefined()) {
- Context* context = Context::cast(list);
- // Note that selecting code unlinks the functions that refer to it.
- SelectCodeToDeoptimize(context, &filter, codes, &zone, undefined);
- list = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
- }
-
- // Now deoptimize all the code.
- for (int i = 0; i < codes->length(); i++) {
- DeoptimizeCode(isolate, codes->at(i));
- }
-}
-
-
-void Deoptimizer::DeoptimizeCode(Isolate* isolate, Code* code) {
- HandleScope scope(isolate);
- DisallowHeapAllocation nha;
-
- // Do platform-specific patching of the optimized code.
- PatchCodeForDeoptimization(isolate, code);
-
- // Add the deoptimizing code to the list.
- DeoptimizingCodeListNode* node = new DeoptimizingCodeListNode(code);
- DeoptimizerData* data = isolate->deoptimizer_data();
- node->set_next(data->deoptimizing_code_list_);
- data->deoptimizing_code_list_ = node;
-
- // We might be in the middle of incremental marking with compaction.
- // Tell collector to treat this code object in a special way and
- // ignore all slots that might have been recorded on it.
- isolate->heap()->mark_compact_collector()->InvalidateCode(code);
-}
-
-
-void Deoptimizer::HandleWeakDeoptimizedCode(v8::Isolate* isolate,
- v8::Persistent<v8::Value>* obj,
- void* parameter) {
- DeoptimizingCodeListNode* node =
- reinterpret_cast<DeoptimizingCodeListNode*>(parameter);
- DeoptimizerData* data =
- reinterpret_cast<Isolate*>(isolate)->deoptimizer_data();
- data->RemoveDeoptimizingCode(*node->code());
-#ifdef DEBUG
- for (DeoptimizingCodeListNode* current = data->deoptimizing_code_list_;
- current != NULL;
- current = current->next()) {
- ASSERT(current != node);
- }
-#endif
-}
-
-
void Deoptimizer::ComputeOutputFrames(Deoptimizer* deoptimizer) {
deoptimizer->DoComputeOutputFrames();
}
@@ -647,8 +583,7 @@
case Deoptimizer::SOFT:
case Deoptimizer::EAGER:
case Deoptimizer::LAZY: {
- Code* compiled_code =
- isolate_->deoptimizer_data()->FindDeoptimizingCode(from_);
+ Code* compiled_code = FindDeoptimizingCode(from_);
return (compiled_code == NULL)
? static_cast<Code*>(isolate_->FindCodeObject(from_))
: compiled_code;
@@ -765,11 +700,18 @@
int Deoptimizer::GetDeoptimizedCodeCount(Isolate* isolate) {
int length = 0;
- DeoptimizingCodeListNode* node =
- isolate->deoptimizer_data()->deoptimizing_code_list_;
- while (node != NULL) {
- length++;
- node = node->next();
+ // Count all entries in the deoptimizing code list of every context.
+ Object* context = isolate->heap()->native_contexts_list();
+ while (!context->IsUndefined()) {
+ Context* native_context = Context::cast(context);
+ Object* element = native_context->DeoptimizedCodeListHead();
+ while (!element->IsUndefined()) {
+ Code* code = Code::cast(element);
+ ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION);
+ length++;
+ element = code->next_code_link();
+ }
+ context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
}
return length;
}
@@ -2591,71 +2533,68 @@
void Deoptimizer::PatchInterruptCode(Isolate* isolate,
- Code* unoptimized_code) {
+ Code* unoptimized) {
DisallowHeapAllocation no_gc;
Code* replacement_code =
isolate->builtins()->builtin(Builtins::kOnStackReplacement);
// Iterate over the back edge table and patch every interrupt
// call to an unconditional call to the replacement code.
- int loop_nesting_level = unoptimized_code->allow_osr_at_loop_nesting_level();
+ int loop_nesting_level = unoptimized->allow_osr_at_loop_nesting_level();
- for (FullCodeGenerator::BackEdgeTableIterator back_edges(unoptimized_code);
+ for (FullCodeGenerator::BackEdgeTableIterator back_edges(unoptimized, &no_gc);
!back_edges.Done();
back_edges.Next()) {
if (static_cast<int>(back_edges.loop_depth()) == loop_nesting_level) {
ASSERT_EQ(NOT_PATCHED, GetInterruptPatchState(isolate,
- unoptimized_code,
+ unoptimized,
back_edges.pc()));
- PatchInterruptCodeAt(unoptimized_code,
+ PatchInterruptCodeAt(unoptimized,
back_edges.pc(),
replacement_code);
}
}
- unoptimized_code->set_back_edges_patched_for_osr(true);
-#ifdef DEBUG
- Deoptimizer::VerifyInterruptCode(
- isolate, unoptimized_code, loop_nesting_level);
-#endif // DEBUG
+ unoptimized->set_back_edges_patched_for_osr(true);
+ ASSERT(Deoptimizer::VerifyInterruptCode(
+ isolate, unoptimized, loop_nesting_level));
}
void Deoptimizer::RevertInterruptCode(Isolate* isolate,
- Code* unoptimized_code) {
+ Code* unoptimized) {
DisallowHeapAllocation no_gc;
Code* interrupt_code =
isolate->builtins()->builtin(Builtins::kInterruptCheck);
// Iterate over the back edge table and revert the patched interrupt calls.
- ASSERT(unoptimized_code->back_edges_patched_for_osr());
- int loop_nesting_level = unoptimized_code->allow_osr_at_loop_nesting_level();
+ ASSERT(unoptimized->back_edges_patched_for_osr());
+ int loop_nesting_level = unoptimized->allow_osr_at_loop_nesting_level();
- for (FullCodeGenerator::BackEdgeTableIterator back_edges(unoptimized_code);
+ for (FullCodeGenerator::BackEdgeTableIterator back_edges(unoptimized, &no_gc);
!back_edges.Done();
back_edges.Next()) {
if (static_cast<int>(back_edges.loop_depth()) <= loop_nesting_level) {
ASSERT_EQ(PATCHED_FOR_OSR, GetInterruptPatchState(isolate,
- unoptimized_code,
+ unoptimized,
back_edges.pc()));
- RevertInterruptCodeAt(unoptimized_code, back_edges.pc(), interrupt_code);
+ RevertInterruptCodeAt(unoptimized, back_edges.pc(), interrupt_code);
}
}
- unoptimized_code->set_back_edges_patched_for_osr(false);
- unoptimized_code->set_allow_osr_at_loop_nesting_level(0);
-#ifdef DEBUG
+ unoptimized->set_back_edges_patched_for_osr(false);
+ unoptimized->set_allow_osr_at_loop_nesting_level(0);
// Assert that none of the back edges are patched anymore.
- Deoptimizer::VerifyInterruptCode(isolate, unoptimized_code, -1);
-#endif // DEBUG
+ ASSERT(Deoptimizer::VerifyInterruptCode(isolate, unoptimized, -1));
}
#ifdef DEBUG
-void Deoptimizer::VerifyInterruptCode(Isolate* isolate,
- Code* unoptimized_code,
+bool Deoptimizer::VerifyInterruptCode(Isolate* isolate,
+ Code* unoptimized,
int loop_nesting_level) {
- for (FullCodeGenerator::BackEdgeTableIterator back_edges(unoptimized_code);
+ DisallowHeapAllocation no_gc;
+ for (FullCodeGenerator::BackEdgeTableIterator back_edges(unoptimized, &no_gc);
!back_edges.Done();
back_edges.Next()) {
uint32_t loop_depth = back_edges.loop_depth();
@@ -2664,9 +2603,10 @@
// have already been patched.
CHECK_EQ((static_cast<int>(loop_depth) <= loop_nesting_level),
GetInterruptPatchState(isolate,
- unoptimized_code,
+ unoptimized,
back_edges.pc()) != NOT_PATCHED);
}
+ return true;
}
#endif // DEBUG
@@ -3121,22 +3061,6 @@
#endif
-DeoptimizingCodeListNode::DeoptimizingCodeListNode(Code* code): next_(NULL) {
- GlobalHandles* global_handles = code->GetIsolate()->global_handles();
- // Globalize the code object and make it weak.
- code_ = Handle<Code>::cast(global_handles->Create(code));
- global_handles->MakeWeak(reinterpret_cast<Object**>(code_.location()),
- this,
- Deoptimizer::HandleWeakDeoptimizedCode);
-}
-
-
-DeoptimizingCodeListNode::~DeoptimizingCodeListNode() {
- GlobalHandles* global_handles = code_->GetIsolate()->global_handles();
- global_handles->Destroy(reinterpret_cast<Object**>(code_.location()));
-}
-
-
// We can't intermix stack decoding and allocations because
// deoptimization infrastracture is not GC safe.
// Thus we build a temporary structure in malloced space.
diff --git a/src/deoptimizer.h b/src/deoptimizer.h
index 0d62bd0..c28b7b9 100644
--- a/src/deoptimizer.h
+++ b/src/deoptimizer.h
@@ -58,7 +58,6 @@
class FrameDescription;
class TranslationIterator;
-class DeoptimizingCodeListNode;
class DeoptimizedFrameInfo;
class HeapNumberMaterializationDescriptor BASE_EMBEDDED {
@@ -121,17 +120,6 @@
};
-class OptimizedFunctionFilter BASE_EMBEDDED {
- public:
- virtual ~OptimizedFunctionFilter() {}
-
- virtual bool TakeFunction(JSFunction* function) = 0;
-};
-
-
-class Deoptimizer;
-
-
class Deoptimizer : public Malloced {
public:
enum BailoutType {
@@ -208,28 +196,20 @@
// execution returns.
static void DeoptimizeFunction(JSFunction* function);
- // Iterate over all the functions which share the same code object
- // and make them use unoptimized version.
- static void ReplaceCodeForRelatedFunctions(JSFunction* function, Code* code);
-
- // Deoptimize all functions in the heap.
+ // Deoptimize all code in the given isolate.
static void DeoptimizeAll(Isolate* isolate);
+ // Deoptimize code associated with the given global object.
static void DeoptimizeGlobalObject(JSObject* object);
- static void DeoptimizeAllFunctionsWith(Isolate* isolate,
- OptimizedFunctionFilter* filter);
+ // Deoptimizes all optimized code that has been previously marked
+ // (via code->set_marked_for_deoptimization) and unlinks all functions that
+ // refer to that code.
+ static void DeoptimizeMarkedCode(Isolate* isolate);
- static void DeoptimizeCodeList(Isolate* isolate, ZoneList<Code*>* codes);
-
- static void DeoptimizeAllFunctionsForContext(
- Context* context, OptimizedFunctionFilter* filter);
-
- static void VisitAllOptimizedFunctionsForContext(
- Context* context, OptimizedFunctionVisitor* visitor);
-
- static void VisitAllOptimizedFunctions(Isolate* isolate,
- OptimizedFunctionVisitor* visitor);
+ // Visit all the known optimized functions in a given isolate.
+ static void VisitAllOptimizedFunctions(
+ Isolate* isolate, OptimizedFunctionVisitor* visitor);
// The size in bytes of the code required at a lazy deopt patch site.
static int patch_size();
@@ -262,7 +242,7 @@
Address pc_after);
// Verify that all back edges of a certain loop depth are patched.
- static void VerifyInterruptCode(Isolate* isolate,
+ static bool VerifyInterruptCode(Isolate* isolate,
Code* unoptimized_code,
int loop_nesting_level);
#endif // DEBUG
@@ -442,17 +422,24 @@
static void GenerateDeoptimizationEntries(
MacroAssembler* masm, int count, BailoutType type);
- // Weak handle callback for deoptimizing code objects.
- static void HandleWeakDeoptimizedCode(v8::Isolate* isolate,
- v8::Persistent<v8::Value>* obj,
- void* data);
+ // Marks all the code in the given context for deoptimization.
+ static void MarkAllCodeForContext(Context* native_context);
- // Deoptimize the given code and add to appropriate deoptimization lists.
- static void DeoptimizeCode(Isolate* isolate, Code* code);
+ // Visit all the known optimized functions in a given context.
+ static void VisitAllOptimizedFunctionsForContext(
+ Context* context, OptimizedFunctionVisitor* visitor);
+
+ // Deoptimizes all code marked in the given context.
+ static void DeoptimizeMarkedCodeForContext(Context* native_context);
// Patch the given code so that it will deoptimize itself.
static void PatchCodeForDeoptimization(Isolate* isolate, Code* code);
+ // Searches the list of known deoptimizing code for a Code object
+ // containing the given address (which is supposedly faster than
+ // searching all code objects).
+ Code* FindDeoptimizingCode(Address addr);
+
// Fill the input from from a JavaScript frame. This is used when
// the debugger needs to inspect an optimized frame. For normal
// deoptimizations the input frame is filled in generated code.
@@ -514,7 +501,6 @@
static const int table_entry_size_;
friend class FrameDescription;
- friend class DeoptimizingCodeListNode;
friend class DeoptimizedFrameInfo;
};
@@ -688,24 +674,16 @@
void Iterate(ObjectVisitor* v);
#endif
- Code* FindDeoptimizingCode(Address addr);
- void RemoveDeoptimizingCode(Code* code);
-
private:
MemoryAllocator* allocator_;
int deopt_entry_code_entries_[Deoptimizer::kBailoutTypesWithCodeEntry];
MemoryChunk* deopt_entry_code_[Deoptimizer::kBailoutTypesWithCodeEntry];
- Deoptimizer* current_;
#ifdef ENABLE_DEBUGGER_SUPPORT
DeoptimizedFrameInfo* deoptimized_frame_info_;
#endif
- // List of deoptimized code which still have references from active stack
- // frames. These code objects are needed by the deoptimizer when deoptimizing
- // a frame for which the code object for the function function has been
- // changed from the code present when deoptimizing was done.
- DeoptimizingCodeListNode* deoptimizing_code_list_;
+ Deoptimizer* current_;
friend class Deoptimizer;
@@ -823,26 +801,6 @@
};
-// Linked list holding deoptimizing code objects. The deoptimizing code objects
-// are kept as weak handles until they are no longer activated on the stack.
-class DeoptimizingCodeListNode : public Malloced {
- public:
- explicit DeoptimizingCodeListNode(Code* code);
- ~DeoptimizingCodeListNode();
-
- DeoptimizingCodeListNode* next() const { return next_; }
- void set_next(DeoptimizingCodeListNode* next) { next_ = next; }
- Handle<Code> code() const { return code_; }
-
- private:
- // Global (weak) handle to the deoptimizing code object.
- Handle<Code> code_;
-
- // Next pointer for linked list.
- DeoptimizingCodeListNode* next_;
-};
-
-
class SlotRef BASE_EMBEDDED {
public:
enum SlotRepresentation {
diff --git a/src/disassembler.cc b/src/disassembler.cc
index 55b4127..30df186 100644
--- a/src/disassembler.cc
+++ b/src/disassembler.cc
@@ -117,7 +117,7 @@
byte* end) {
SealHandleScope shs(isolate);
DisallowHeapAllocation no_alloc;
- ExternalReferenceEncoder ref_encoder;
+ ExternalReferenceEncoder ref_encoder(isolate);
Heap* heap = HEAP;
v8::internal::EmbeddedVector<char, 128> decode_buffer;
diff --git a/src/execution.cc b/src/execution.cc
index 6075624..048e6e0 100644
--- a/src/execution.cc
+++ b/src/execution.cc
@@ -708,7 +708,7 @@
int serial_number = Smi::cast(data->serial_number())->value();
Object* elm =
isolate->native_context()->function_cache()->
- GetElementNoExceptionThrown(serial_number);
+ GetElementNoExceptionThrown(isolate, serial_number);
if (elm->IsJSFunction()) return Handle<JSFunction>(JSFunction::cast(elm));
// The function has not yet been instantiated in this context; do it.
Handle<Object> args[] = { data };
diff --git a/src/extensions/statistics-extension.cc b/src/extensions/statistics-extension.cc
index 32bc07d..651d99d 100644
--- a/src/extensions/statistics-extension.cc
+++ b/src/extensions/statistics-extension.cc
@@ -60,7 +60,7 @@
void StatisticsExtension::GetCounters(
const v8::FunctionCallbackInfo<v8::Value>& args) {
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = reinterpret_cast<Isolate*>(args.GetIsolate());
Heap* heap = isolate->heap();
if (args.Length() > 0) { // GC if first argument evaluates to true.
diff --git a/src/factory.cc b/src/factory.cc
index 819e9f0..c7f7806 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -130,7 +130,8 @@
int slack) {
ASSERT(0 <= number_of_descriptors);
CALL_HEAP_FUNCTION(isolate(),
- DescriptorArray::Allocate(number_of_descriptors, slack),
+ DescriptorArray::Allocate(
+ isolate(), number_of_descriptors, slack),
DescriptorArray);
}
@@ -806,7 +807,7 @@
*p++ = ' ';
space--;
if (space > 0) {
- MaybeObject* maybe_arg = args->GetElement(i);
+ MaybeObject* maybe_arg = args->GetElement(isolate(), i);
Handle<String> arg_str(reinterpret_cast<String*>(maybe_arg));
const char* arg = *arg_str->ToCString();
Vector<char> v2(p, static_cast<int>(space));
@@ -1321,7 +1322,7 @@
Handle<Object> Factory::ToObject(Handle<Object> object) {
- CALL_HEAP_FUNCTION(isolate(), object->ToObject(), Object);
+ CALL_HEAP_FUNCTION(isolate(), object->ToObject(isolate()), Object);
}
@@ -1460,15 +1461,29 @@
result->shared()->set_construct_stub(*construct_stub);
result->shared()->DontAdaptArguments();
- // Recursively copy parent templates' accessors, 'data' may be modified.
+ // Recursively copy parent instance templates' accessors,
+ // 'data' may be modified.
int max_number_of_additional_properties = 0;
+ int max_number_of_static_properties = 0;
FunctionTemplateInfo* info = *obj;
while (true) {
- Object* props = info->property_accessors();
- if (!props->IsUndefined()) {
- Handle<Object> props_handle(props, isolate());
- NeanderArray props_array(props_handle);
- max_number_of_additional_properties += props_array.length();
+ if (!info->instance_template()->IsUndefined()) {
+ Object* props =
+ ObjectTemplateInfo::cast(
+ info->instance_template())->property_accessors();
+ if (!props->IsUndefined()) {
+ Handle<Object> props_handle(props, isolate());
+ NeanderArray props_array(props_handle);
+ max_number_of_additional_properties += props_array.length();
+ }
+ }
+ if (!info->property_accessors()->IsUndefined()) {
+ Object* props = info->property_accessors();
+ if (!props->IsUndefined()) {
+ Handle<Object> props_handle(props, isolate());
+ NeanderArray props_array(props_handle);
+ max_number_of_static_properties += props_array.length();
+ }
}
Object* parent = info->parent_template();
if (parent->IsUndefined()) break;
@@ -1477,17 +1492,44 @@
Map::EnsureDescriptorSlack(map, max_number_of_additional_properties);
+ // Use a temporary FixedArray to acculumate static accessors
+ int valid_descriptors = 0;
+ Handle<FixedArray> array;
+ if (max_number_of_static_properties > 0) {
+ array = NewFixedArray(max_number_of_static_properties);
+ }
+
while (true) {
- Handle<Object> props = Handle<Object>(obj->property_accessors(),
- isolate());
- if (!props->IsUndefined()) {
- Map::AppendCallbackDescriptors(map, props);
+ // Install instance descriptors
+ if (!obj->instance_template()->IsUndefined()) {
+ Handle<ObjectTemplateInfo> instance =
+ Handle<ObjectTemplateInfo>(
+ ObjectTemplateInfo::cast(obj->instance_template()), isolate());
+ Handle<Object> props = Handle<Object>(instance->property_accessors(),
+ isolate());
+ if (!props->IsUndefined()) {
+ Map::AppendCallbackDescriptors(map, props);
+ }
}
+ // Accumulate static accessors
+ if (!obj->property_accessors()->IsUndefined()) {
+ Handle<Object> props = Handle<Object>(obj->property_accessors(),
+ isolate());
+ valid_descriptors =
+ AccessorInfo::AppendUnique(props, array, valid_descriptors);
+ }
+ // Climb parent chain
Handle<Object> parent = Handle<Object>(obj->parent_template(), isolate());
if (parent->IsUndefined()) break;
obj = Handle<FunctionTemplateInfo>::cast(parent);
}
+ // Install accumulated static accessors
+ for (int i = 0; i < valid_descriptors; i++) {
+ Handle<AccessorInfo> accessor(AccessorInfo::cast(array->get(i)));
+ JSObject::SetAccessor(result, accessor);
+ }
+
ASSERT(result->shared()->IsApiFunction());
return result;
}
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index f19c4a6..d47e9b1 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -240,7 +240,7 @@
DEFINE_bool(use_gvn, true, "use hydrogen global value numbering")
DEFINE_bool(use_canonicalizing, true, "use hydrogen instruction canonicalizing")
DEFINE_bool(use_inlining, true, "use function inlining")
-DEFINE_bool(use_escape_analysis, true, "use hydrogen escape analysis")
+DEFINE_bool(use_escape_analysis, false, "use hydrogen escape analysis")
DEFINE_bool(use_allocation_folding, true, "use allocation folding")
DEFINE_int(max_inlining_levels, 5, "maximum number of inlining levels")
DEFINE_int(max_inlined_source_size, 600,
@@ -331,6 +331,8 @@
"the length of the concurrent compilation queue")
DEFINE_int(concurrent_recompilation_delay, 0,
"artificial compilation delay in ms")
+DEFINE_bool(concurrent_osr, false,
+ "concurrent on-stack replacement")
DEFINE_bool(omit_map_checks_for_leaf_maps, true,
"do not emit check maps for constant values that have a leaf map, "
@@ -455,16 +457,8 @@
DEFINE_bool(cache_prototype_transitions, true, "cache prototype transitions")
// cpu-profiler.cc
-#if defined(ANDROID)
-// Phones and tablets have processors that are much slower than desktop
-// and laptop computers for which current heuristics are tuned.
-#define DEFAULT_INTERVAL 5000
-#else
-#define DEFAULT_INTERVAL 1000
-#endif
-DEFINE_int(cpu_profiler_sampling_interval, DEFAULT_INTERVAL,
+DEFINE_int(cpu_profiler_sampling_interval, 1000,
"CPU profiler sampling interval in microseconds")
-#undef DEFAULT_INTERVAL
// debug.cc
DEFINE_bool(trace_debug_json, false, "trace debugging JSON request/response")
diff --git a/src/frames.cc b/src/frames.cc
index c17a9d5..5d90f06 100644
--- a/src/frames.cc
+++ b/src/frames.cc
@@ -814,8 +814,7 @@
PrintF("+%d", code_offset);
SharedFunctionInfo* shared = fun->shared();
if (print_line_number) {
- Code* code = Code::cast(
- v8::internal::Isolate::Current()->FindCodeObject(pc));
+ Code* code = Code::cast(isolate->FindCodeObject(pc));
int source_pos = code->SourcePosition(pc);
Object* maybe_script = shared->script();
if (maybe_script->IsScript()) {
diff --git a/src/full-codegen.h b/src/full-codegen.h
index ed2cc17..5580cb3 100644
--- a/src/full-codegen.h
+++ b/src/full-codegen.h
@@ -141,7 +141,8 @@
class BackEdgeTableIterator {
public:
- explicit BackEdgeTableIterator(Code* unoptimized) {
+ explicit BackEdgeTableIterator(Code* unoptimized,
+ DisallowHeapAllocation* required) {
ASSERT(unoptimized->kind() == Code::FUNCTION);
instruction_start_ = unoptimized->instruction_start();
cursor_ = instruction_start_ + unoptimized->back_edge_table_offset();
@@ -192,7 +193,6 @@
Address end_;
Address instruction_start_;
uint32_t table_length_;
- DisallowHeapAllocation no_gc_while_iterating_over_raw_addresses_;
DISALLOW_COPY_AND_ASSIGN(BackEdgeTableIterator);
};
diff --git a/src/heap-inl.h b/src/heap-inl.h
index 9d04797..8808855 100644
--- a/src/heap-inl.h
+++ b/src/heap-inl.h
@@ -766,7 +766,7 @@
MaybeObject* TranscendentalCache::Get(Type type, double input) {
SubCache* cache = caches_[type];
if (cache == NULL) {
- caches_[type] = cache = new SubCache(type);
+ caches_[type] = cache = new SubCache(isolate_, type);
}
return cache->Get(input);
}
diff --git a/src/heap-snapshot-generator.cc b/src/heap-snapshot-generator.cc
index 1c8a7b3..6a5bb63 100644
--- a/src/heap-snapshot-generator.cc
+++ b/src/heap-snapshot-generator.cc
@@ -732,7 +732,7 @@
HeapSnapshot* snapshot,
SnapshottingProgressReportingInterface* progress,
v8::HeapProfiler::ObjectNameResolver* resolver)
- : heap_(Isolate::Current()->heap()),
+ : heap_(snapshot->collection()->heap()),
snapshot_(snapshot),
collection_(snapshot_->collection()),
progress_(progress),
@@ -1852,7 +1852,7 @@
// Modifies heap. Must not be run during heap traversal.
void V8HeapExplorer::TagGlobalObjects() {
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = heap_->isolate();
HandleScope scope(isolate);
GlobalObjectsEnumerator enumerator;
isolate->global_handles()->IterateAllRoots(&enumerator);
@@ -1927,8 +1927,10 @@
NativeObjectsExplorer::NativeObjectsExplorer(
- HeapSnapshot* snapshot, SnapshottingProgressReportingInterface* progress)
- : snapshot_(snapshot),
+ HeapSnapshot* snapshot,
+ SnapshottingProgressReportingInterface* progress)
+ : isolate_(snapshot->collection()->heap()->isolate()),
+ snapshot_(snapshot),
collection_(snapshot_->collection()),
progress_(progress),
embedder_queried_(false),
@@ -1973,7 +1975,7 @@
void NativeObjectsExplorer::FillRetainedObjects() {
if (embedder_queried_) return;
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = isolate_;
const GCType major_gc_type = kGCTypeMarkSweepCompact;
// Record objects that are joined into ObjectGroups.
isolate->heap()->CallGCPrologueCallbacks(
@@ -2000,7 +2002,7 @@
void NativeObjectsExplorer::FillImplicitReferences() {
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = isolate_;
List<ImplicitRefGroup*>* groups =
isolate->global_handles()->implicit_ref_groups();
for (int i = 0; i < groups->length(); ++i) {
@@ -2157,7 +2159,7 @@
void NativeObjectsExplorer::VisitSubtreeWrapper(Object** p, uint16_t class_id) {
if (in_groups_.Contains(*p)) return;
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = isolate_;
v8::RetainedObjectInfo* info =
isolate->heap_profiler()->ExecuteWrapperClassCallback(class_id, p);
if (info == NULL) return;
@@ -2243,15 +2245,15 @@
// full GC is reachable from the root when computing dominators.
// This is not true for weakly reachable objects.
// As a temporary solution we call GC twice.
- Isolate::Current()->heap()->CollectAllGarbage(
+ heap_->CollectAllGarbage(
Heap::kMakeHeapIterableMask,
"HeapSnapshotGenerator::GenerateSnapshot");
- Isolate::Current()->heap()->CollectAllGarbage(
+ heap_->CollectAllGarbage(
Heap::kMakeHeapIterableMask,
"HeapSnapshotGenerator::GenerateSnapshot");
#ifdef VERIFY_HEAP
- Heap* debug_heap = Isolate::Current()->heap();
+ Heap* debug_heap = heap_;
CHECK(!debug_heap->old_data_space()->was_swept_conservatively());
CHECK(!debug_heap->old_pointer_space()->was_swept_conservatively());
CHECK(!debug_heap->code_space()->was_swept_conservatively());
diff --git a/src/heap-snapshot-generator.h b/src/heap-snapshot-generator.h
index cea9958..ccdcab4 100644
--- a/src/heap-snapshot-generator.h
+++ b/src/heap-snapshot-generator.h
@@ -538,7 +538,7 @@
class NativeObjectsExplorer {
public:
NativeObjectsExplorer(HeapSnapshot* snapshot,
- SnapshottingProgressReportingInterface* progress);
+ SnapshottingProgressReportingInterface* progress);
virtual ~NativeObjectsExplorer();
void AddRootEntries(SnapshotFillerInterface* filler);
int EstimateObjectsCount();
@@ -570,6 +570,7 @@
NativeGroupRetainedObjectInfo* FindOrAddGroupInfo(const char* label);
+ Isolate* isolate_;
HeapSnapshot* snapshot_;
HeapSnapshotsCollection* collection_;
SnapshottingProgressReportingInterface* progress_;
diff --git a/src/heap.cc b/src/heap.cc
index 8487857..037a7a1 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -1027,7 +1027,7 @@
isolate_->eternal_handles()->PostGarbageCollectionProcessing(this);
// Update relocatables.
- Relocatable::PostGarbageCollectionProcessing();
+ Relocatable::PostGarbageCollectionProcessing(isolate_);
if (collector == MARK_COMPACTOR) {
// Register the amount of external allocated memory.
@@ -1616,6 +1616,29 @@
template<>
+struct WeakListVisitor<Code> {
+ static void SetWeakNext(Code* code, Object* next) {
+ code->set_next_code_link(next);
+ }
+
+ static Object* WeakNext(Code* code) {
+ return code->next_code_link();
+ }
+
+ static int WeakNextOffset() {
+ return Code::kNextCodeLinkOffset;
+ }
+
+ static void VisitLiveObject(Heap*, Code*,
+ WeakObjectRetainer*, bool) {
+ }
+
+ static void VisitPhantomObject(Heap*, Code*) {
+ }
+};
+
+
+template<>
struct WeakListVisitor<Context> {
static void SetWeakNext(Context* context, Object* next) {
context->set(Context::NEXT_CONTEXT_LINK,
@@ -1631,22 +1654,34 @@
Context* context,
WeakObjectRetainer* retainer,
bool record_slots) {
- // Process the weak list of optimized functions for the context.
- Object* function_list_head =
- VisitWeakList<JSFunction>(
- heap,
- context->get(Context::OPTIMIZED_FUNCTIONS_LIST),
- retainer,
- record_slots);
- context->set(Context::OPTIMIZED_FUNCTIONS_LIST,
- function_list_head,
- UPDATE_WRITE_BARRIER);
+ // Process the three weak lists linked off the context.
+ DoWeakList<JSFunction>(heap, context, retainer, record_slots,
+ Context::OPTIMIZED_FUNCTIONS_LIST);
+ DoWeakList<Code>(heap, context, retainer, record_slots,
+ Context::OPTIMIZED_CODE_LIST);
+ DoWeakList<Code>(heap, context, retainer, record_slots,
+ Context::DEOPTIMIZED_CODE_LIST);
+ }
+
+ template<class T>
+ static void DoWeakList(Heap* heap,
+ Context* context,
+ WeakObjectRetainer* retainer,
+ bool record_slots,
+ int index) {
+ // Visit the weak list, removing dead intermediate elements.
+ Object* list_head = VisitWeakList<T>(heap, context->get(index), retainer,
+ record_slots);
+
+ // Update the list head.
+ context->set(index, list_head, UPDATE_WRITE_BARRIER);
+
if (record_slots) {
- Object** optimized_functions =
- HeapObject::RawField(
- context, FixedArray::SizeFor(Context::OPTIMIZED_FUNCTIONS_LIST));
+ // Record the updated slot if necessary.
+ Object** head_slot = HeapObject::RawField(
+ context, FixedArray::SizeFor(index));
heap->mark_compact_collector()->RecordSlot(
- optimized_functions, optimized_functions, function_list_head);
+ head_slot, head_slot, list_head);
}
}
@@ -2938,7 +2973,7 @@
{ MaybeObject* maybe_result = Allocate(oddball_map(), OLD_POINTER_SPACE);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
- return Oddball::cast(result)->Initialize(to_string, to_number, kind);
+ return Oddball::cast(result)->Initialize(this, to_string, to_number, kind);
}
@@ -3042,15 +3077,16 @@
// Finish initializing oddballs after creating the string table.
{ MaybeObject* maybe_obj =
- undefined_value()->Initialize("undefined",
+ undefined_value()->Initialize(this,
+ "undefined",
nan_value(),
Oddball::kUndefined);
if (!maybe_obj->ToObject(&obj)) return false;
}
// Initialize the null_value.
- { MaybeObject* maybe_obj =
- null_value()->Initialize("null", Smi::FromInt(0), Oddball::kNull);
+ { MaybeObject* maybe_obj = null_value()->Initialize(
+ this, "null", Smi::FromInt(0), Oddball::kNull);
if (!maybe_obj->ToObject(&obj)) return false;
}
@@ -6115,12 +6151,12 @@
void Heap::ReportCodeStatistics(const char* title) {
PrintF(">>>>>> Code Stats (%s) >>>>>>\n", title);
- PagedSpace::ResetCodeStatistics();
+ PagedSpace::ResetCodeStatistics(isolate());
// We do not look for code in new space, map space, or old space. If code
// somehow ends up in those spaces, we would miss it here.
code_space_->CollectCodeStatistics();
lo_space_->CollectCodeStatistics();
- PagedSpace::ReportCodeStatistics();
+ PagedSpace::ReportCodeStatistics(isolate());
}
@@ -6574,7 +6610,7 @@
v->Synchronize(VisitorSynchronization::kBootstrapper);
isolate_->Iterate(v);
v->Synchronize(VisitorSynchronization::kTop);
- Relocatable::Iterate(v);
+ Relocatable::Iterate(isolate_, v);
v->Synchronize(VisitorSynchronization::kRelocatable);
#ifdef ENABLE_DEBUGGER_SUPPORT
@@ -6635,7 +6671,7 @@
// serialization this does nothing, since the partial snapshot cache is
// empty. However the next thing we do is create the partial snapshot,
// filling up the partial snapshot cache with objects it needs as we go.
- SerializerDeserializer::Iterate(v);
+ SerializerDeserializer::Iterate(isolate_, v);
// We don't do a v->Synchronize call here, because in debug mode that will
// output a flag to the snapshot. However at this point the serializer and
// deserializer are deliberately a little unsynchronized (see above) so the
@@ -7239,12 +7275,12 @@
class UnreachableObjectsFilter : public HeapObjectsFilter {
public:
- UnreachableObjectsFilter() {
+ explicit UnreachableObjectsFilter(Heap* heap) : heap_(heap) {
MarkReachableObjects();
}
~UnreachableObjectsFilter() {
- Isolate::Current()->heap()->mark_compact_collector()->ClearMarkbits();
+ heap_->mark_compact_collector()->ClearMarkbits();
}
bool SkipObject(HeapObject* object) {
@@ -7281,12 +7317,12 @@
};
void MarkReachableObjects() {
- Heap* heap = Isolate::Current()->heap();
MarkingVisitor visitor;
- heap->IterateRoots(&visitor, VISIT_ALL);
+ heap_->IterateRoots(&visitor, VISIT_ALL);
visitor.TransitiveClosure();
}
+ Heap* heap_;
DisallowHeapAllocation no_allocation_;
};
@@ -7318,7 +7354,7 @@
space_iterator_ = new SpaceIterator(heap_);
switch (filtering_) {
case kFilterUnreachable:
- filter_ = new UnreachableObjectsFilter;
+ filter_ = new UnreachableObjectsFilter(heap_);
break;
default:
break;
@@ -7863,9 +7899,9 @@
#endif
-TranscendentalCache::SubCache::SubCache(Type t)
+TranscendentalCache::SubCache::SubCache(Isolate* isolate, Type t)
: type_(t),
- isolate_(Isolate::Current()) {
+ isolate_(isolate) {
uint32_t in0 = 0xffffffffu; // Bit-pattern for a NaN that isn't
uint32_t in1 = 0xffffffffu; // generated by the FPU.
for (int i = 0; i < kCacheSize; i++) {
diff --git a/src/heap.h b/src/heap.h
index 4071ef6..94fbf46 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -2881,7 +2881,7 @@
class SubCache {
static const int kCacheSize = 512;
- explicit SubCache(Type t);
+ explicit SubCache(Isolate* isolate, Type t);
MUST_USE_RESULT inline MaybeObject* Get(double input);
@@ -2918,7 +2918,7 @@
DISALLOW_COPY_AND_ASSIGN(SubCache);
};
- TranscendentalCache() {
+ explicit TranscendentalCache(Isolate* isolate) : isolate_(isolate) {
for (int i = 0; i < kNumberOfCaches; ++i) caches_[i] = NULL;
}
@@ -2936,6 +2936,7 @@
// Allow access to the caches_ array as an ExternalReference.
friend class ExternalReference;
+ Isolate* isolate_;
SubCache* caches_[kNumberOfCaches];
DISALLOW_COPY_AND_ASSIGN(TranscendentalCache);
};
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index f6ee8dc..e371277 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -3668,7 +3668,7 @@
Zone* zone, HValue* context, HValue* char_code) {
if (FLAG_fold_constants && char_code->IsConstant()) {
HConstant* c_code = HConstant::cast(char_code);
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = zone->isolate();
if (c_code->HasNumberValue()) {
if (std::isfinite(c_code->DoubleValue())) {
uint32_t code = c_code->NumberValueAsInteger32() & 0xffff;
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index 0357805..a6d8915 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -2159,7 +2159,7 @@
bool IsApplyFunction() const {
return function_->code() ==
- Isolate::Current()->builtins()->builtin(Builtins::kFunctionApply);
+ function_->GetIsolate()->builtins()->builtin(Builtins::kFunctionApply);
}
virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
@@ -2629,7 +2629,7 @@
public:
static HCheckValue* New(Zone* zone, HValue* context,
HValue* value, Handle<JSFunction> target) {
- bool in_new_space = Isolate::Current()->heap()->InNewSpace(*target);
+ bool in_new_space = zone->isolate()->heap()->InNewSpace(*target);
HCheckValue* check = new(zone) HCheckValue(value, target, in_new_space);
return check;
}
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index c42d035..25522e8 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -4554,7 +4554,6 @@
HInstruction* HOptimizedGraphBuilder::TryLoadPolymorphicAsMonomorphic(
- Property* expr,
HValue* object,
SmallMapList* types,
Handle<String> name) {
@@ -4655,15 +4654,15 @@
void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(
- Property* expr,
+ int position,
+ BailoutId ast_id,
HValue* object,
SmallMapList* types,
Handle<String> name) {
- HInstruction* instr = TryLoadPolymorphicAsMonomorphic(
- expr, object, types, name);
+ HInstruction* instr = TryLoadPolymorphicAsMonomorphic(object, types, name);
if (instr != NULL) {
- instr->set_position(expr->position());
- return ast_context()->ReturnInstruction(instr, expr->id());
+ instr->set_position(position);
+ return ast_context()->ReturnInstruction(instr, ast_id);
}
// Something did not match; must use a polymorphic load.
@@ -4695,7 +4694,7 @@
if (lookup.IsField()) {
HObjectAccess access = HObjectAccess::ForField(map, &lookup, name);
HLoadNamedField* load = BuildLoadNamedField(compare, access);
- load->set_position(expr->position());
+ load->set_position(position);
AddInstruction(load);
if (!ast_context()->IsEffect()) Push(load);
} else if (lookup.IsConstant()) {
@@ -4726,22 +4725,23 @@
if (count == types->length() && FLAG_deoptimize_uncommon_cases) {
FinishExitWithHardDeoptimization("Unknown map in polymorphic load", join);
} else {
- HInstruction* load = BuildLoadNamedGeneric(object, name, expr);
- load->set_position(expr->position());
+ HValue* context = environment()->context();
+ HInstruction* load = new(zone()) HLoadNamedGeneric(context, object, name);
+ load->set_position(position);
AddInstruction(load);
if (!ast_context()->IsEffect()) Push(load);
if (join != NULL) {
current_block()->Goto(join);
} else {
- Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE);
+ Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
return;
}
}
ASSERT(join != NULL);
- join->SetJoinId(expr->id());
+ join->SetJoinId(ast_id);
set_current_block(join);
if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
}
@@ -4751,8 +4751,7 @@
int position,
BailoutId assignment_id,
HValue* object,
- HValue* store_value,
- HValue* result_value,
+ HValue* value,
SmallMapList* types,
Handle<String> name) {
// Use monomorphic store if property lookup results in the same field index
@@ -4798,14 +4797,14 @@
HInstruction* store;
CHECK_ALIVE_OR_RETURN(
store = BuildStoreNamedField(
- checked_object, name, store_value, types->at(count - 1), &lookup),
+ checked_object, name, value, types->at(count - 1), &lookup),
true);
- if (!ast_context()->IsEffect()) Push(result_value);
+ if (!ast_context()->IsEffect()) Push(value);
store->set_position(position);
AddInstruction(store);
Add<HSimulate>(assignment_id);
if (!ast_context()->IsEffect()) Drop(1);
- ast_context()->ReturnValue(result_value);
+ ast_context()->ReturnValue(value);
return true;
}
@@ -4814,13 +4813,11 @@
int position,
BailoutId assignment_id,
HValue* object,
- HValue* store_value,
- HValue* result_value,
+ HValue* value,
SmallMapList* types,
Handle<String> name) {
if (TryStorePolymorphicAsMonomorphic(
- position, assignment_id, object,
- store_value, result_value, types, name)) {
+ position, assignment_id, object, value, types, name)) {
return;
}
@@ -4847,11 +4844,11 @@
set_current_block(if_true);
HInstruction* instr;
CHECK_ALIVE(instr = BuildStoreNamedField(
- compare, name, store_value, map, &lookup));
+ compare, name, value, map, &lookup));
instr->set_position(position);
// Goto will add the HSimulate for the store.
AddInstruction(instr);
- if (!ast_context()->IsEffect()) Push(result_value);
+ if (!ast_context()->IsEffect()) Push(value);
current_block()->Goto(join);
set_current_block(if_false);
@@ -4864,13 +4861,13 @@
if (count == types->length() && FLAG_deoptimize_uncommon_cases) {
FinishExitWithHardDeoptimization("Unknown map in polymorphic store", join);
} else {
- HInstruction* instr = BuildStoreNamedGeneric(object, name, store_value);
+ HInstruction* instr = BuildStoreNamedGeneric(object, name, value);
instr->set_position(position);
AddInstruction(instr);
if (join != NULL) {
if (!ast_context()->IsEffect()) {
- Push(result_value);
+ Push(value);
}
current_block()->Goto(join);
} else {
@@ -4881,12 +4878,12 @@
if (ast_context()->IsEffect()) {
Add<HSimulate>(assignment_id, REMOVABLE_SIMULATE);
} else {
- Push(result_value);
+ Push(value);
Add<HSimulate>(assignment_id, REMOVABLE_SIMULATE);
Drop(1);
}
}
- return ast_context()->ReturnValue(result_value);
+ return ast_context()->ReturnValue(value);
}
}
@@ -4915,7 +4912,7 @@
Deoptimizer::SOFT);
}
return BuildStoreNamed(expr, expr->id(), expr->position(),
- expr->AssignmentId(), prop, object, value, value);
+ expr->AssignmentId(), prop, object, value);
} else {
// Keyed store.
CHECK_ALIVE(VisitForValue(prop->key()));
@@ -4987,8 +4984,7 @@
BailoutId assignment_id,
Property* prop,
HValue* object,
- HValue* store_value,
- HValue* result_value) {
+ HValue* value) {
Literal* key = prop->key()->AsLiteral();
Handle<String> name = Handle<String>::cast(key->value());
ASSERT(!name.is_null());
@@ -5006,42 +5002,38 @@
Handle<JSObject> holder;
if (LookupSetter(map, name, &setter, &holder)) {
AddCheckConstantFunction(holder, object, map);
- // Don't try to inline if the result_value is different from the
- // store_value. That case isn't handled yet by the inlining.
- if (result_value == store_value &&
- FLAG_inline_accessors &&
- TryInlineSetter(setter, id, assignment_id, store_value)) {
+ if (FLAG_inline_accessors &&
+ TryInlineSetter(setter, id, assignment_id, value)) {
return;
}
Drop(2);
Add<HPushArgument>(object);
- Add<HPushArgument>(store_value);
+ Add<HPushArgument>(value);
instr = new(zone()) HCallConstantFunction(setter, 2);
} else {
Drop(2);
CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object,
name,
- store_value,
+ value,
map));
}
} else if (types != NULL && types->length() > 1) {
Drop(2);
return HandlePolymorphicStoreNamedField(
- position, id, object,
- store_value, result_value, types, name);
+ position, id, object, value, types, name);
} else {
Drop(2);
- instr = BuildStoreNamedGeneric(object, name, store_value);
+ instr = BuildStoreNamedGeneric(object, name, value);
}
- if (!ast_context()->IsEffect()) Push(result_value);
+ if (!ast_context()->IsEffect()) Push(value);
instr->set_position(position);
AddInstruction(instr);
if (instr->HasObservableSideEffects()) {
Add<HSimulate>(id, REMOVABLE_SIMULATE);
}
if (!ast_context()->IsEffect()) Drop(1);
- return ast_context()->ReturnValue(result_value);
+ return ast_context()->ReturnValue(value);
}
@@ -5130,34 +5122,7 @@
// Named property.
CHECK_ALIVE(VisitForValue(prop->obj()));
HValue* object = Top();
-
- Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
- Handle<Map> map;
- HInstruction* load = NULL;
- SmallMapList* types = prop->GetReceiverTypes();
- bool monomorphic = prop->IsMonomorphic();
- if (monomorphic) {
- map = types->first();
- // We can't generate code for a monomorphic dict mode load so
- // just pretend it is not monomorphic.
- monomorphic = CanInlinePropertyAccess(*map);
- }
- if (monomorphic) {
- Handle<JSFunction> getter;
- Handle<JSObject> holder;
- if (LookupGetter(map, name, &getter, &holder)) {
- load = BuildCallGetter(object, map, getter, holder);
- } else {
- load = BuildLoadNamedMonomorphic(object, name, prop, map);
- }
- } else if (types != NULL && types->length() > 1) {
- load = TryLoadPolymorphicAsMonomorphic(prop, object, types, name);
- }
- if (load == NULL) load = BuildLoadNamedGeneric(object, name, prop);
- PushAndAdd(load);
- if (load->HasObservableSideEffects()) {
- Add<HSimulate>(prop->LoadId(), REMOVABLE_SIMULATE);
- }
+ PushLoad(prop, object, expr->position());
CHECK_ALIVE(VisitForValue(expr->value()));
HValue* right = Pop();
@@ -5170,7 +5135,7 @@
}
return BuildStoreNamed(expr, expr->id(), expr->position(),
- expr->AssignmentId(), prop, object, instr, instr);
+ expr->AssignmentId(), prop, object, instr);
} else {
// Keyed property.
CHECK_ALIVE(VisitForValue(prop->obj()));
@@ -5396,7 +5361,7 @@
Handle<String> name,
Property* expr) {
if (expr->IsUninitialized()) {
- Add<HDeoptimize>("Insufficient feedback for generic named load",
+ Add<HDeoptimize>("Insufficient type feedback for generic named load",
Deoptimizer::SOFT);
}
HValue* context = environment()->context();
@@ -5418,7 +5383,6 @@
HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic(
HValue* object,
Handle<String> name,
- Property* expr,
Handle<Map> map) {
// Handle a load from a known field.
ASSERT(!map->is_dictionary_map());
@@ -5471,7 +5435,8 @@
}
// No luck, do a generic load.
- return BuildLoadNamedGeneric(object, name, expr);
+ HValue* context = environment()->context();
+ return new(zone()) HLoadNamedGeneric(context, object, name);
}
@@ -5710,7 +5675,7 @@
// Deopt if none of the cases matched.
NoObservableSideEffectsScope scope(this);
- FinishExitWithHardDeoptimization("Unknown type in polymorphic element access",
+ FinishExitWithHardDeoptimization("Unknown map in polymorphic element access",
join);
set_current_block(join);
return is_store ? NULL : Pop();
@@ -5747,13 +5712,13 @@
} else {
if (is_store) {
if (expr->IsAssignment() && expr->AsAssignment()->IsUninitialized()) {
- Add<HDeoptimize>("Insufficient feedback for keyed store",
+ Add<HDeoptimize>("Insufficient type feedback for keyed store",
Deoptimizer::SOFT);
}
instr = BuildStoreKeyedGeneric(obj, key, val);
} else {
if (expr->AsProperty()->IsUninitialized()) {
- Add<HDeoptimize>("Insufficient feedback for keyed load",
+ Add<HDeoptimize>("Insufficient type feedback for keyed load",
Deoptimizer::SOFT);
}
instr = BuildLoadKeyedGeneric(obj, key);
@@ -5858,15 +5823,18 @@
}
-void HOptimizedGraphBuilder::VisitProperty(Property* expr) {
- ASSERT(!HasStackOverflow());
- ASSERT(current_block() != NULL);
- ASSERT(current_block()->HasPredecessor());
+void HOptimizedGraphBuilder::PushLoad(Property* expr,
+ HValue* object,
+ int position) {
+ ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED);
+ Push(object);
+ BuildLoad(expr, position, expr->LoadId());
+}
- if (TryArgumentsAccess(expr)) return;
- CHECK_ALIVE(VisitForValue(expr->obj()));
-
+void HOptimizedGraphBuilder::BuildLoad(Property* expr,
+ int position,
+ BailoutId ast_id) {
HInstruction* instr = NULL;
if (expr->IsStringLength()) {
HValue* string = Pop();
@@ -5908,14 +5876,18 @@
Handle<JSObject> holder;
if (LookupGetter(map, name, &getter, &holder)) {
AddCheckConstantFunction(holder, Top(), map);
- if (FLAG_inline_accessors && TryInlineGetter(getter, expr)) return;
+ if (FLAG_inline_accessors &&
+ TryInlineGetter(getter, ast_id, expr->LoadId())) {
+ return;
+ }
Add<HPushArgument>(Pop());
instr = new(zone()) HCallConstantFunction(getter, 1);
} else {
- instr = BuildLoadNamedMonomorphic(Pop(), name, expr, map);
+ instr = BuildLoadNamedMonomorphic(Pop(), name, map);
}
} else if (types != NULL && types->length() > 1) {
- return HandlePolymorphicLoadNamedField(expr, Pop(), types, name);
+ return HandlePolymorphicLoadNamedField(
+ position, ast_id, Pop(), types, name);
} else {
instr = BuildLoadNamedGeneric(Pop(), name, expr);
}
@@ -5928,22 +5900,34 @@
bool has_side_effects = false;
HValue* load = HandleKeyedElementAccess(
- obj, key, NULL, expr, expr->id(), expr->position(),
+ obj, key, NULL, expr, ast_id, position,
false, // is_store
&has_side_effects);
if (has_side_effects) {
if (ast_context()->IsEffect()) {
- Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE);
+ Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
} else {
Push(load);
- Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE);
+ Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
Drop(1);
}
}
return ast_context()->ReturnValue(load);
}
- instr->set_position(expr->position());
- return ast_context()->ReturnInstruction(instr, expr->id());
+ instr->set_position(position);
+ return ast_context()->ReturnInstruction(instr, ast_id);
+}
+
+
+void HOptimizedGraphBuilder::VisitProperty(Property* expr) {
+ ASSERT(!HasStackOverflow());
+ ASSERT(current_block() != NULL);
+ ASSERT(current_block()->HasPredecessor());
+
+ if (TryArgumentsAccess(expr)) return;
+
+ CHECK_ALIVE(VisitForValue(expr->obj()));
+ BuildLoad(expr, expr->position(), expr->id());
}
@@ -6620,13 +6604,14 @@
bool HOptimizedGraphBuilder::TryInlineGetter(Handle<JSFunction> getter,
- Property* prop) {
+ BailoutId ast_id,
+ BailoutId return_id) {
return TryInline(CALL_AS_METHOD,
getter,
0,
NULL,
- prop->id(),
- prop->LoadId(),
+ ast_id,
+ return_id,
GETTER_CALL_RETURN);
}
@@ -7576,38 +7561,25 @@
CHECK_ALIVE(VisitForValue(prop->obj()));
HValue* object = Top();
-
- Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
- Handle<Map> map;
- HInstruction* load = NULL;
- bool monomorphic = prop->IsMonomorphic();
- SmallMapList* types = prop->GetReceiverTypes();
- if (monomorphic) {
- map = types->first();
- monomorphic = CanInlinePropertyAccess(*map);
- }
- if (monomorphic) {
- Handle<JSFunction> getter;
- Handle<JSObject> holder;
- if (LookupGetter(map, name, &getter, &holder)) {
- load = BuildCallGetter(object, map, getter, holder);
- } else {
- load = BuildLoadNamedMonomorphic(object, name, prop, map);
- }
- } else if (types != NULL && types->length() > 1) {
- load = TryLoadPolymorphicAsMonomorphic(prop, object, types, name);
- }
- if (load == NULL) load = BuildLoadNamedGeneric(object, name, prop);
- PushAndAdd(load);
- if (load->HasObservableSideEffects()) {
- Add<HSimulate>(prop->LoadId(), REMOVABLE_SIMULATE);
- }
+ PushLoad(prop, object, expr->position());
after = BuildIncrement(returns_original_input, expr);
- HValue* result = returns_original_input ? Pop() : after;
+
+ if (returns_original_input) {
+ HValue* result = Pop();
+ HValue* object = Pop();
+ environment()->SetExpressionStackAt(0, result);
+ {
+ EffectContext for_effect(this);
+ Push(object);
+ Push(after);
+ return BuildStoreNamed(expr, expr->id(), expr->position(),
+ expr->AssignmentId(), prop, object, after);
+ }
+ }
return BuildStoreNamed(expr, expr->id(), expr->position(),
- expr->AssignmentId(), prop, object, after, result);
+ expr->AssignmentId(), prop, object, after);
} else {
// Keyed property.
if (returns_original_input) Push(graph()->GetConstantUndefined());
@@ -7768,13 +7740,13 @@
}
if (left_type->Is(Type::None())) {
- Add<HDeoptimize>("Insufficient type feedback for left side",
+ Add<HDeoptimize>("Insufficient type feedback for LHS of binary operation",
Deoptimizer::SOFT);
// TODO(rossberg): we should be able to get rid of non-continuous defaults.
left_type = handle(Type::Any(), isolate());
}
if (right_type->Is(Type::None())) {
- Add<HDeoptimize>("Insufficient type feedback for right side",
+ Add<HDeoptimize>("Insufficient type feedback for RHS of binary operation",
Deoptimizer::SOFT);
right_type = handle(Type::Any(), isolate());
}
@@ -8125,7 +8097,8 @@
// Cases handled below depend on collected type feedback. They should
// soft deoptimize when there is no type feedback.
if (combined_type->Is(Type::None())) {
- Add<HDeoptimize>("insufficient type feedback for combined type",
+ Add<HDeoptimize>("Insufficient type feedback for combined type "
+ "of binary operation",
Deoptimizer::SOFT);
combined_type = left_type = right_type = handle(Type::Any(), isolate());
}
diff --git a/src/hydrogen.h b/src/hydrogen.h
index cdca1bd..0e1ed13 100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -1911,7 +1911,9 @@
bool TryInlineCall(Call* expr, bool drop_extra = false);
bool TryInlineConstruct(CallNew* expr, HValue* implicit_return_value);
- bool TryInlineGetter(Handle<JSFunction> getter, Property* prop);
+ bool TryInlineGetter(Handle<JSFunction> getter,
+ BailoutId ast_id,
+ BailoutId return_id);
bool TryInlineSetter(Handle<JSFunction> setter,
BailoutId id,
BailoutId assignment_id,
@@ -1939,26 +1941,24 @@
void HandlePropertyAssignment(Assignment* expr);
void HandleCompoundAssignment(Assignment* expr);
- void HandlePolymorphicLoadNamedField(Property* expr,
+ void HandlePolymorphicLoadNamedField(int position,
+ BailoutId return_id,
HValue* object,
SmallMapList* types,
Handle<String> name);
- HInstruction* TryLoadPolymorphicAsMonomorphic(Property* expr,
- HValue* object,
+ HInstruction* TryLoadPolymorphicAsMonomorphic(HValue* object,
SmallMapList* types,
Handle<String> name);
void HandlePolymorphicStoreNamedField(int position,
BailoutId assignment_id,
HValue* object,
HValue* value,
- HValue* result,
SmallMapList* types,
Handle<String> name);
bool TryStorePolymorphicAsMonomorphic(int position,
BailoutId assignment_id,
HValue* object,
HValue* value,
- HValue* result,
SmallMapList* types,
Handle<String> name);
void HandlePolymorphicCallNamed(Call* expr,
@@ -2029,19 +2029,24 @@
Handle<JSObject> holder);
HInstruction* BuildLoadNamedMonomorphic(HValue* object,
Handle<String> name,
- Property* expr,
Handle<Map> map);
HCheckMaps* AddCheckMap(HValue* object, Handle<Map> map);
+ void BuildLoad(Property* property,
+ int position,
+ BailoutId ast_id);
+ void PushLoad(Property* property,
+ HValue* object,
+ int position);
+
void BuildStoreNamed(Expression* expression,
BailoutId id,
int position,
BailoutId assignment_id,
Property* prop,
HValue* object,
- HValue* store_value,
- HValue* result_value);
+ HValue* value);
HInstruction* BuildStoreNamedField(HValue* object,
Handle<String> name,
diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc
index bd058f8..065f02c 100644
--- a/src/ia32/macro-assembler-ia32.cc
+++ b/src/ia32/macro-assembler-ia32.cc
@@ -48,6 +48,7 @@
allow_stub_calls_(true),
has_frame_(false) {
if (isolate() != NULL) {
+ // TODO(titzer): should we just use a null handle here instead?
code_object_ = Handle<Object>(isolate()->heap()->undefined_value(),
isolate());
}
diff --git a/src/ic.cc b/src/ic.cc
index 7f27d3f..190fdb1 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -375,20 +375,22 @@
}
-void IC::Clear(Address address) {
+void IC::Clear(Isolate* isolate, Address address) {
Code* target = GetTargetAtAddress(address);
// Don't clear debug break inline cache as it will remove the break point.
if (target->is_debug_stub()) return;
switch (target->kind()) {
- case Code::LOAD_IC: return LoadIC::Clear(address, target);
- case Code::KEYED_LOAD_IC: return KeyedLoadIC::Clear(address, target);
- case Code::STORE_IC: return StoreIC::Clear(address, target);
- case Code::KEYED_STORE_IC: return KeyedStoreIC::Clear(address, target);
+ case Code::LOAD_IC: return LoadIC::Clear(isolate, address, target);
+ case Code::KEYED_LOAD_IC:
+ return KeyedLoadIC::Clear(isolate, address, target);
+ case Code::STORE_IC: return StoreIC::Clear(isolate, address, target);
+ case Code::KEYED_STORE_IC:
+ return KeyedStoreIC::Clear(isolate, address, target);
case Code::CALL_IC: return CallIC::Clear(address, target);
case Code::KEYED_CALL_IC: return KeyedCallIC::Clear(address, target);
- case Code::COMPARE_IC: return CompareIC::Clear(address, target);
+ case Code::COMPARE_IC: return CompareIC::Clear(isolate, address, target);
case Code::COMPARE_NIL_IC: return CompareNilIC::Clear(address, target);
case Code::BINARY_OP_IC:
case Code::TO_BOOLEAN_IC:
@@ -404,7 +406,7 @@
if (target->ic_state() == UNINITIALIZED) return;
bool contextual = CallICBase::Contextual::decode(target->extra_ic_state());
Code* code =
- Isolate::Current()->stub_cache()->FindCallInitialize(
+ target->GetIsolate()->stub_cache()->FindCallInitialize(
target->arguments_count(),
contextual ? RelocInfo::CODE_TARGET_CONTEXT : RelocInfo::CODE_TARGET,
target->kind());
@@ -412,40 +414,40 @@
}
-void KeyedLoadIC::Clear(Address address, Code* target) {
+void KeyedLoadIC::Clear(Isolate* isolate, Address address, Code* target) {
if (target->ic_state() == UNINITIALIZED) return;
// Make sure to also clear the map used in inline fast cases. If we
// do not clear these maps, cached code can keep objects alive
// through the embedded maps.
- SetTargetAtAddress(address, *initialize_stub());
+ SetTargetAtAddress(address, *initialize_stub(isolate));
}
-void LoadIC::Clear(Address address, Code* target) {
+void LoadIC::Clear(Isolate* isolate, Address address, Code* target) {
if (target->ic_state() == UNINITIALIZED) return;
- SetTargetAtAddress(address, *initialize_stub());
+ SetTargetAtAddress(address, *initialize_stub(isolate));
}
-void StoreIC::Clear(Address address, Code* target) {
+void StoreIC::Clear(Isolate* isolate, Address address, Code* target) {
if (target->ic_state() == UNINITIALIZED) return;
SetTargetAtAddress(address,
(Code::GetStrictMode(target->extra_ic_state()) == kStrictMode)
- ? *initialize_stub_strict()
- : *initialize_stub());
+ ? *initialize_stub_strict(isolate)
+ : *initialize_stub(isolate));
}
-void KeyedStoreIC::Clear(Address address, Code* target) {
+void KeyedStoreIC::Clear(Isolate* isolate, Address address, Code* target) {
if (target->ic_state() == UNINITIALIZED) return;
SetTargetAtAddress(address,
(Code::GetStrictMode(target->extra_ic_state()) == kStrictMode)
- ? *initialize_stub_strict()
- : *initialize_stub());
+ ? *initialize_stub_strict(isolate)
+ : *initialize_stub(isolate));
}
-void CompareIC::Clear(Address address, Code* target) {
+void CompareIC::Clear(Isolate* isolate, Address address, Code* target) {
ASSERT(target->major_key() == CodeStub::CompareIC);
CompareIC::State handler_state;
Token::Value op;
@@ -453,7 +455,7 @@
&handler_state, &op);
// Only clear CompareICs that can retain objects.
if (handler_state != KNOWN_OBJECT) return;
- SetTargetAtAddress(address, GetRawUninitialized(op));
+ SetTargetAtAddress(address, GetRawUninitialized(isolate, op));
PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK);
}
@@ -564,7 +566,7 @@
// the element if so.
uint32_t index;
if (name->AsArrayIndex(&index)) {
- Handle<Object> result = Object::GetElement(object, index);
+ Handle<Object> result = Object::GetElement(isolate(), object, index);
RETURN_IF_EMPTY_HANDLE(isolate(), result);
if (result->IsJSFunction()) return *result;
@@ -1709,22 +1711,30 @@
}
LookupResult lookup(isolate());
- if (LookupForWrite(receiver, name, value, &lookup, &state)) {
- if (FLAG_use_ic) {
- UpdateCaches(&lookup, state, strict_mode, receiver, name, value);
- }
- } else if (strict_mode == kStrictMode &&
- !(lookup.IsProperty() && lookup.IsReadOnly()) &&
- IsUndeclaredGlobal(object)) {
+ bool can_store = LookupForWrite(receiver, name, value, &lookup, &state);
+ if (!can_store &&
+ strict_mode == kStrictMode &&
+ !(lookup.IsProperty() && lookup.IsReadOnly()) &&
+ IsUndeclaredGlobal(object)) {
// Strict mode doesn't allow setting non-existent global property.
return ReferenceError("not_defined", name);
- } else if (FLAG_use_ic &&
- (!name->IsCacheable(isolate()) ||
- lookup.IsNormal() ||
- (lookup.IsField() && lookup.CanHoldValue(value)))) {
- Handle<Code> stub = strict_mode == kStrictMode
- ? generic_stub_strict() : generic_stub();
- set_target(*stub);
+ }
+ if (FLAG_use_ic) {
+ if (state == UNINITIALIZED) {
+ Handle<Code> stub = (strict_mode == kStrictMode)
+ ? pre_monomorphic_stub_strict()
+ : pre_monomorphic_stub();
+ set_target(*stub);
+ TRACE_IC("StoreIC", name, state, *stub);
+ } else if (can_store) {
+ UpdateCaches(&lookup, state, strict_mode, receiver, name, value);
+ } else if (!name->IsCacheable(isolate()) ||
+ lookup.IsNormal() ||
+ (lookup.IsField() && lookup.CanHoldValue(value))) {
+ Handle<Code> stub = (strict_mode == kStrictMode) ? generic_stub_strict()
+ : generic_stub();
+ set_target(*stub);
+ }
}
// Set the property.
@@ -2771,10 +2781,10 @@
}
-Code* CompareIC::GetRawUninitialized(Token::Value op) {
+Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) {
ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED);
Code* code = NULL;
- CHECK(stub.FindCodeInCache(&code, Isolate::Current()));
+ CHECK(stub.FindCodeInCache(&code, isolate));
return code;
}
diff --git a/src/ic.h b/src/ic.h
index fcf0de5..5c883cd 100644
--- a/src/ic.h
+++ b/src/ic.h
@@ -102,7 +102,7 @@
static State StateFrom(Code* target, Object* receiver, Object* name);
// Clear the inline cache to initial state.
- static void Clear(Address address);
+ static void Clear(Isolate* isolate, Address address);
// Computes the reloc info for this IC. This is a fairly expensive
// operation as it has to search through the heap to find the code
@@ -420,14 +420,14 @@
private:
// Stub accessors.
- static Handle<Code> initialize_stub() {
- return Isolate::Current()->builtins()->LoadIC_Initialize();
+ static Handle<Code> initialize_stub(Isolate* isolate) {
+ return isolate->builtins()->LoadIC_Initialize();
}
virtual Handle<Code> pre_monomorphic_stub() {
return isolate()->builtins()->LoadIC_PreMonomorphic();
}
- static void Clear(Address address, Code* target);
+ static void Clear(Isolate* isolate, Address address, Code* target);
friend class IC;
};
@@ -496,8 +496,8 @@
private:
// Stub accessors.
- static Handle<Code> initialize_stub() {
- return Isolate::Current()->builtins()->KeyedLoadIC_Initialize();
+ static Handle<Code> initialize_stub(Isolate* isolate) {
+ return isolate->builtins()->KeyedLoadIC_Initialize();
}
virtual Handle<Code> pre_monomorphic_stub() {
return isolate()->builtins()->KeyedLoadIC_PreMonomorphic();
@@ -512,7 +512,7 @@
return isolate()->builtins()->KeyedLoadIC_String();
}
- static void Clear(Address address, Code* target);
+ static void Clear(Isolate* isolate, Address address, Code* target);
friend class IC;
};
@@ -527,6 +527,9 @@
// Code generators for stub routines. Only called once at startup.
static void GenerateSlow(MacroAssembler* masm);
static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
+ static void GeneratePreMonomorphic(MacroAssembler* masm) {
+ GenerateMiss(masm);
+ }
static void GenerateMiss(MacroAssembler* masm);
static void GenerateMegamorphic(MacroAssembler* masm,
StrictModeFlag strict_mode);
@@ -558,6 +561,12 @@
virtual Handle<Code> generic_stub_strict() const {
return isolate()->builtins()->StoreIC_Generic_Strict();
}
+ virtual Handle<Code> pre_monomorphic_stub() const {
+ return isolate()->builtins()->StoreIC_PreMonomorphic();
+ }
+ virtual Handle<Code> pre_monomorphic_stub_strict() const {
+ return isolate()->builtins()->StoreIC_PreMonomorphic_Strict();
+ }
virtual Handle<Code> global_proxy_stub() {
return isolate()->builtins()->StoreIC_GlobalProxy();
}
@@ -601,13 +610,13 @@
IC::set_target(code);
}
- static Handle<Code> initialize_stub() {
- return Isolate::Current()->builtins()->StoreIC_Initialize();
+ static Handle<Code> initialize_stub(Isolate* isolate) {
+ return isolate->builtins()->StoreIC_Initialize();
}
- static Handle<Code> initialize_stub_strict() {
- return Isolate::Current()->builtins()->StoreIC_Initialize_Strict();
+ static Handle<Code> initialize_stub_strict(Isolate* isolate) {
+ return isolate->builtins()->StoreIC_Initialize_Strict();
}
- static void Clear(Address address, Code* target);
+ static void Clear(Isolate* isolate, Address address, Code* target);
friend class IC;
};
@@ -643,6 +652,9 @@
static void GenerateInitialize(MacroAssembler* masm) {
GenerateMiss(masm, MISS);
}
+ static void GeneratePreMonomorphic(MacroAssembler* masm) {
+ GenerateMiss(masm, MISS);
+ }
static void GenerateMiss(MacroAssembler* masm, ICMissMode force_generic);
static void GenerateSlow(MacroAssembler* masm);
static void GenerateRuntimeSetProperty(MacroAssembler* masm,
@@ -660,6 +672,12 @@
Handle<Object> value);
virtual void UpdateMegamorphicCache(Map* map, Name* name, Code* code) { }
+ virtual Handle<Code> pre_monomorphic_stub() const {
+ return isolate()->builtins()->KeyedStoreIC_PreMonomorphic();
+ }
+ virtual Handle<Code> pre_monomorphic_stub_strict() const {
+ return isolate()->builtins()->KeyedStoreIC_PreMonomorphic_Strict();
+ }
virtual Handle<Code> megamorphic_stub() {
return isolate()->builtins()->KeyedStoreIC_Generic();
}
@@ -685,11 +703,11 @@
}
// Stub accessors.
- static Handle<Code> initialize_stub() {
- return Isolate::Current()->builtins()->KeyedStoreIC_Initialize();
+ static Handle<Code> initialize_stub(Isolate* isolate) {
+ return isolate->builtins()->KeyedStoreIC_Initialize();
}
- static Handle<Code> initialize_stub_strict() {
- return Isolate::Current()->builtins()->KeyedStoreIC_Initialize_Strict();
+ static Handle<Code> initialize_stub_strict(Isolate* isolate) {
+ return isolate->builtins()->KeyedStoreIC_Initialize_Strict();
}
Handle<Code> generic_stub() const {
return isolate()->builtins()->KeyedStoreIC_Generic();
@@ -701,7 +719,7 @@
return isolate()->builtins()->KeyedStoreIC_NonStrictArguments();
}
- static void Clear(Address address, Code* target);
+ static void Clear(Isolate* isolate, Address address, Code* target);
KeyedAccessStoreMode GetStoreMode(Handle<JSObject> receiver,
Handle<Object> key,
@@ -807,9 +825,9 @@
bool strict() const { return op_ == Token::EQ_STRICT; }
Condition GetCondition() const { return ComputeCondition(op_); }
- static Code* GetRawUninitialized(Token::Value op);
+ static Code* GetRawUninitialized(Isolate* isolate, Token::Value op);
- static void Clear(Address address, Code* target);
+ static void Clear(Isolate* isolate, Address address, Code* target);
Token::Value op_;
diff --git a/src/isolate-inl.h b/src/isolate-inl.h
index ddb1580..5e2c8c2 100644
--- a/src/isolate-inl.h
+++ b/src/isolate-inl.h
@@ -36,7 +36,9 @@
namespace internal {
-SaveContext::SaveContext(Isolate* isolate) : prev_(isolate->save_context()) {
+SaveContext::SaveContext(Isolate* isolate)
+ : isolate_(isolate),
+ prev_(isolate->save_context()) {
if (isolate->context() != NULL) {
context_ = Handle<Context>(isolate->context());
}
diff --git a/src/isolate.cc b/src/isolate.cc
index 39d75e2..2c15717 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -567,11 +567,11 @@
if (stack_trace_nesting_level_ == 0) {
stack_trace_nesting_level_++;
HeapStringAllocator allocator;
- StringStream::ClearMentionedObjectCache();
+ StringStream::ClearMentionedObjectCache(this);
StringStream accumulator(&allocator);
incomplete_message_ = &accumulator;
PrintStack(&accumulator);
- Handle<String> stack_trace = accumulator.ToString();
+ Handle<String> stack_trace = accumulator.ToString(this);
incomplete_message_ = NULL;
stack_trace_nesting_level_ = 0;
return stack_trace;
@@ -871,7 +871,7 @@
allocator = preallocated_message_space_;
}
- StringStream::ClearMentionedObjectCache();
+ StringStream::ClearMentionedObjectCache(this);
StringStream accumulator(allocator);
incomplete_message_ = &accumulator;
PrintStack(&accumulator);
@@ -915,7 +915,7 @@
}
// The MentionedObjectCache is not GC-proof at the moment.
DisallowHeapAllocation no_gc;
- ASSERT(StringStream::IsMentionedObjectCacheClear());
+ ASSERT(StringStream::IsMentionedObjectCacheClear(this));
// Avoid printing anything if there are no frames.
if (c_entry_fp(thread_local_top()) == 0) return;
@@ -928,7 +928,7 @@
"\n==== Details ================================================\n\n");
PrintFrames(this, accumulator, StackFrame::DETAILS);
- accumulator->PrintMentionedObjectCache();
+ accumulator->PrintMentionedObjectCache(this);
accumulator->Add("=====================\n\n");
}
@@ -2187,7 +2187,7 @@
string_tracker_ = new StringTracker();
string_tracker_->isolate_ = this;
compilation_cache_ = new CompilationCache(this);
- transcendental_cache_ = new TranscendentalCache();
+ transcendental_cache_ = new TranscendentalCache(this);
keyed_lookup_cache_ = new KeyedLookupCache();
context_slot_cache_ = new ContextSlotCache();
descriptor_lookup_cache_ = new DescriptorLookupCache();
@@ -2272,7 +2272,7 @@
// If we are deserializing, read the state into the now-empty heap.
if (!create_heap_objects) {
- des->Deserialize();
+ des->Deserialize(this);
}
stub_cache_->Initialize();
diff --git a/src/isolate.h b/src/isolate.h
index 8be8af7..741c4c0 100644
--- a/src/isolate.h
+++ b/src/isolate.h
@@ -1396,15 +1396,8 @@
inline explicit SaveContext(Isolate* isolate);
~SaveContext() {
- if (context_.is_null()) {
- Isolate* isolate = Isolate::Current();
- isolate->set_context(NULL);
- isolate->set_save_context(prev_);
- } else {
- Isolate* isolate = context_->GetIsolate();
- isolate->set_context(*context_);
- isolate->set_save_context(prev_);
- }
+ isolate_->set_context(context_.is_null() ? NULL : *context_);
+ isolate_->set_save_context(prev_);
}
Handle<Context> context() { return context_; }
@@ -1416,6 +1409,7 @@
}
private:
+ Isolate* isolate_;
Handle<Context> context_;
SaveContext* prev_;
Address c_entry_fp_;
diff --git a/src/json-stringifier.h b/src/json-stringifier.h
index 2de1401..c6ea288 100644
--- a/src/json-stringifier.h
+++ b/src/json-stringifier.h
@@ -602,12 +602,12 @@
Handle<JSArray> object, int length) {
for (int i = 0; i < length; i++) {
if (i > 0) Append(',');
- Handle<Object> element = Object::GetElement(object, i);
+ Handle<Object> element = Object::GetElement(isolate_, object, i);
RETURN_IF_EMPTY_HANDLE_VALUE(isolate_, element, EXCEPTION);
if (element->IsUndefined()) {
AppendAscii("null");
} else {
- Result result = SerializeElement(object->GetIsolate(), element, i);
+ Result result = SerializeElement(isolate_, element, i);
if (result == SUCCESS) continue;
if (result == UNCHANGED) {
AppendAscii("null");
@@ -678,9 +678,10 @@
key_handle = factory_->NumberToString(Handle<Object>(key, isolate_));
uint32_t index;
if (key->IsSmi()) {
- property = Object::GetElement(object, Smi::cast(key)->value());
+ property = Object::GetElement(
+ isolate_, object, Smi::cast(key)->value());
} else if (key_handle->AsArrayIndex(&index)) {
- property = Object::GetElement(object, index);
+ property = Object::GetElement(isolate_, object, index);
} else {
property = GetProperty(isolate_, object, key_handle);
}
diff --git a/src/jsregexp.cc b/src/jsregexp.cc
index 0ce10b8..5c79477 100644
--- a/src/jsregexp.cc
+++ b/src/jsregexp.cc
@@ -1869,7 +1869,7 @@
for (int i = j; i < kSize; i++) {
templ[i] = bit;
}
- Factory* factory = Isolate::Current()->factory();
+ Factory* factory = masm->zone()->isolate()->factory();
// TODO(erikcorry): Cache these.
Handle<ByteArray> ba = factory->NewByteArray(kSize, TENURED);
for (int i = 0; i < kSize; i++) {
@@ -2548,7 +2548,7 @@
RegExpCompiler* compiler,
int characters_filled_in,
bool not_at_start) {
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = compiler->macro_assembler()->zone()->isolate();
ASSERT(characters_filled_in < details->characters());
int characters = details->characters();
int char_mask;
@@ -3246,8 +3246,8 @@
Trace* trace,
bool first_element_checked,
int* checked_up_to) {
- Isolate* isolate = Isolate::Current();
RegExpMacroAssembler* assembler = compiler->macro_assembler();
+ Isolate* isolate = assembler->zone()->isolate();
bool ascii = compiler->ascii();
Label* backtrack = trace->backtrack();
QuickCheckDetails* quick_check = trace->quick_check_performed();
@@ -3820,7 +3820,7 @@
return true;
}
- Factory* factory = Isolate::Current()->factory();
+ Factory* factory = masm->zone()->isolate()->factory();
Handle<ByteArray> boolean_skip_table = factory->NewByteArray(kSize, TENURED);
int skip_distance = GetSkipTable(
min_lookahead, max_lookahead, boolean_skip_table);
@@ -5292,7 +5292,7 @@
void CharacterRange::AddCaseEquivalents(ZoneList<CharacterRange>* ranges,
bool is_ascii,
Zone* zone) {
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = zone->isolate();
uc16 bottom = from();
uc16 top = to();
if (is_ascii && !RangeContainsLatin1Equivalents(*this)) {
@@ -5680,7 +5680,7 @@
void Analysis::EnsureAnalyzed(RegExpNode* that) {
- StackLimitCheck check(Isolate::Current());
+ StackLimitCheck check(that->zone()->isolate());
if (check.HasOverflowed()) {
fail("Stack overflow");
return;
diff --git a/src/liveedit.cc b/src/liveedit.cc
index b260c81..7df17ed 100644
--- a/src/liveedit.cc
+++ b/src/liveedit.cc
@@ -631,8 +631,8 @@
// Wraps any object into a OpaqueReference, that will hide the object
// from JavaScript.
-static Handle<JSValue> WrapInJSValue(Handle<Object> object) {
- Isolate* isolate = Isolate::Current();
+static Handle<JSValue> WrapInJSValue(Handle<HeapObject> object) {
+ Isolate* isolate = object->GetIsolate();
Handle<JSFunction> constructor = isolate->opaque_reference_function();
Handle<JSValue> result =
Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor));
@@ -662,8 +662,8 @@
template<typename S>
class JSArrayBasedStruct {
public:
- static S Create() {
- Factory* factory = Isolate::Current()->factory();
+ static S Create(Isolate* isolate) {
+ Factory* factory = isolate->factory();
Handle<JSArray> array = factory->NewJSArray(S::kSize_);
return S(array);
}
@@ -691,7 +691,7 @@
Handle<Smi>(Smi::FromInt(value), isolate()));
}
Object* GetField(int field_position) {
- return array_->GetElementNoExceptionThrown(field_position);
+ return array_->GetElementNoExceptionThrown(isolate(), field_position);
}
int GetSmiValueField(int field_position) {
Object* res = GetField(field_position);
@@ -724,7 +724,7 @@
this->SetSmiValueField(kParentIndexOffset_, parent_index);
}
void SetFunctionCode(Handle<Code> function_code,
- Handle<Object> code_scope_info) {
+ Handle<HeapObject> code_scope_info) {
Handle<JSValue> code_wrapper = WrapInJSValue(function_code);
this->SetField(kCodeOffset_, code_wrapper);
@@ -788,7 +788,8 @@
public:
static bool IsInstance(Handle<JSArray> array) {
return array->length() == Smi::FromInt(kSize_) &&
- array->GetElementNoExceptionThrown(kSharedInfoOffset_)->IsJSValue();
+ array->GetElementNoExceptionThrown(
+ array->GetIsolate(), kSharedInfoOffset_)->IsJSValue();
}
explicit SharedInfoWrapper(Handle<JSArray> array)
@@ -832,7 +833,7 @@
void FunctionStarted(FunctionLiteral* fun) {
HandleScope scope(isolate());
- FunctionInfoWrapper info = FunctionInfoWrapper::Create();
+ FunctionInfoWrapper info = FunctionInfoWrapper::Create(isolate());
info.SetInitialProperties(fun->name(), fun->start_position(),
fun->end_position(), fun->parameter_count(),
fun->materialized_literal_count(),
@@ -846,7 +847,8 @@
HandleScope scope(isolate());
FunctionInfoWrapper info =
FunctionInfoWrapper::cast(
- result_->GetElementNoExceptionThrown(current_parent_index_));
+ result_->GetElementNoExceptionThrown(
+ isolate(), current_parent_index_));
current_parent_index_ = info.GetParentIndex();
}
@@ -855,10 +857,10 @@
void FunctionCode(Handle<Code> function_code) {
FunctionInfoWrapper info =
FunctionInfoWrapper::cast(
- result_->GetElementNoExceptionThrown(current_parent_index_));
+ result_->GetElementNoExceptionThrown(
+ isolate(), current_parent_index_));
info.SetFunctionCode(function_code,
- Handle<Object>(isolate()->heap()->null_value(),
- isolate()));
+ Handle<HeapObject>(isolate()->heap()->null_value()));
}
// Saves full information about a function: its code, its scope info
@@ -870,9 +872,10 @@
}
FunctionInfoWrapper info =
FunctionInfoWrapper::cast(
- result_->GetElementNoExceptionThrown(current_parent_index_));
+ result_->GetElementNoExceptionThrown(
+ isolate(), current_parent_index_));
info.SetFunctionCode(Handle<Code>(shared->code()),
- Handle<Object>(shared->scope_info(), isolate()));
+ Handle<HeapObject>(shared->scope_info()));
info.SetSharedFunctionInfo(shared);
Handle<Object> scope_info_list(SerializeFunctionScope(scope, zone),
@@ -935,7 +938,7 @@
JSArray* LiveEdit::GatherCompileInfo(Handle<Script> script,
Handle<String> source) {
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = script->GetIsolate();
FunctionInfoListener listener(isolate);
Handle<Object> original_source =
@@ -1001,12 +1004,14 @@
void LiveEdit::WrapSharedFunctionInfos(Handle<JSArray> array) {
- HandleScope scope(array->GetIsolate());
+ Isolate* isolate = array->GetIsolate();
+ HandleScope scope(isolate);
int len = GetArrayLength(array);
for (int i = 0; i < len; i++) {
Handle<SharedFunctionInfo> info(
- SharedFunctionInfo::cast(array->GetElementNoExceptionThrown(i)));
- SharedInfoWrapper info_wrapper = SharedInfoWrapper::Create();
+ SharedFunctionInfo::cast(
+ array->GetElementNoExceptionThrown(isolate, i)));
+ SharedInfoWrapper info_wrapper = SharedInfoWrapper::Create(isolate);
Handle<String> name_handle(String::cast(info->name()));
info_wrapper.SetProperties(name_handle, info->start_position(),
info->end_position(), info);
@@ -1242,34 +1247,48 @@
}
-class DependentFunctionFilter : public OptimizedFunctionFilter {
- public:
- explicit DependentFunctionFilter(
- SharedFunctionInfo* function_info)
- : function_info_(function_info) {}
-
- virtual bool TakeFunction(JSFunction* function) {
- return (function->shared() == function_info_ ||
- IsInlined(function, function_info_));
- }
-
- private:
- SharedFunctionInfo* function_info_;
-};
-
-
static void DeoptimizeDependentFunctions(SharedFunctionInfo* function_info) {
- DisallowHeapAllocation no_allocation;
+ // Marks code that shares the same shared function info or has inlined
+ // code that shares the same function info.
+ class DependentFunctionMarker: public OptimizedFunctionVisitor {
+ public:
+ SharedFunctionInfo* shared_info_;
+ bool found_;
- DependentFunctionFilter filter(function_info);
- Deoptimizer::DeoptimizeAllFunctionsWith(function_info->GetIsolate(), &filter);
+ explicit DependentFunctionMarker(SharedFunctionInfo* shared_info)
+ : shared_info_(shared_info), found_(false) { }
+
+ virtual void EnterContext(Context* context) { } // Don't care.
+ virtual void LeaveContext(Context* context) { } // Don't care.
+ virtual void VisitFunction(JSFunction* function) {
+ // It should be guaranteed by the iterator that everything is optimized.
+ ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
+ if (shared_info_ == function->shared() ||
+ IsInlined(function, shared_info_)) {
+ // mark the code for deoptimization
+ function->code()->set_marked_for_deoptimization(true);
+ found_ = true;
+ }
+ }
+ };
+
+
+ DisallowHeapAllocation no_allocation;
+ DependentFunctionMarker marker(function_info);
+ // TODO(titzer): need to traverse all optimized code to find OSR code here.
+ Deoptimizer::VisitAllOptimizedFunctions(function_info->GetIsolate(), &marker);
+
+ if (marker.found_) {
+ // Only go through with the deoptimization if something was found.
+ Deoptimizer::DeoptimizeMarkedCode(function_info->GetIsolate());
+ }
}
MaybeObject* LiveEdit::ReplaceFunctionCode(
Handle<JSArray> new_compile_info_array,
Handle<JSArray> shared_info_array) {
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = new_compile_info_array->GetIsolate();
HandleScope scope(isolate);
if (!SharedInfoWrapper::IsInstance(shared_info_array)) {
@@ -1343,7 +1362,7 @@
CHECK(script_handle->IsScript() || script_handle->IsUndefined());
shared_info->set_script(*script_handle);
- Isolate::Current()->compilation_cache()->Remove(shared_info);
+ function_wrapper->GetIsolate()->compilation_cache()->Remove(shared_info);
}
@@ -1360,20 +1379,24 @@
Handle<JSArray> position_change_array) {
int position_diff = 0;
int array_len = GetArrayLength(position_change_array);
+ Isolate* isolate = position_change_array->GetIsolate();
// TODO(635): binary search may be used here
for (int i = 0; i < array_len; i += 3) {
- Object* element = position_change_array->GetElementNoExceptionThrown(i);
+ Object* element =
+ position_change_array->GetElementNoExceptionThrown(isolate, i);
CHECK(element->IsSmi());
int chunk_start = Smi::cast(element)->value();
if (original_position < chunk_start) {
break;
}
- element = position_change_array->GetElementNoExceptionThrown(i + 1);
+ element = position_change_array->GetElementNoExceptionThrown(isolate,
+ i + 1);
CHECK(element->IsSmi());
int chunk_end = Smi::cast(element)->value();
// Position mustn't be inside a chunk.
ASSERT(original_position >= chunk_end);
- element = position_change_array->GetElementNoExceptionThrown(i + 2);
+ element = position_change_array->GetElementNoExceptionThrown(isolate,
+ i + 2);
CHECK(element->IsSmi());
int chunk_changed_end = Smi::cast(element)->value();
position_diff = chunk_changed_end - chunk_end;
@@ -1508,7 +1531,7 @@
MaybeObject* LiveEdit::PatchFunctionPositions(
Handle<JSArray> shared_info_array, Handle<JSArray> position_change_array) {
if (!SharedInfoWrapper::IsInstance(shared_info_array)) {
- return Isolate::Current()->ThrowIllegalOperation();
+ return shared_info_array->GetIsolate()->ThrowIllegalOperation();
}
SharedInfoWrapper shared_info_wrapper(shared_info_array);
@@ -1630,7 +1653,8 @@
Isolate* isolate = shared_info_array->GetIsolate();
int len = GetArrayLength(shared_info_array);
for (int i = 0; i < len; i++) {
- Object* element = shared_info_array->GetElementNoExceptionThrown(i);
+ Object* element =
+ shared_info_array->GetElementNoExceptionThrown(isolate, i);
CHECK(element->IsJSValue());
Handle<JSValue> jsvalue(JSValue::cast(element));
Handle<SharedFunctionInfo> shared =
@@ -1651,7 +1675,7 @@
static bool FixTryCatchHandler(StackFrame* top_frame,
StackFrame* bottom_frame) {
Address* pointer_address =
- &Memory::Address_at(Isolate::Current()->get_address_from_id(
+ &Memory::Address_at(top_frame->isolate()->get_address_from_id(
Isolate::kHandlerAddress));
while (*pointer_address < top_frame->sp()) {
@@ -1687,7 +1711,7 @@
ASSERT(bottom_js_frame->is_java_script());
// Check the nature of the top frame.
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = bottom_js_frame->isolate();
Code* pre_top_frame_code = pre_top_frame->LookupCode();
bool frame_has_padding;
if (pre_top_frame_code->is_inline_cache_stub() &&
@@ -1790,7 +1814,7 @@
// Make sure FixTryCatchHandler is idempotent.
ASSERT(!FixTryCatchHandler(pre_top_frame, bottom_js_frame));
- Handle<Code> code = Isolate::Current()->builtins()->FrameDropper_LiveEdit();
+ Handle<Code> code = isolate->builtins()->FrameDropper_LiveEdit();
*top_frame_pc_address = code->entry();
pre_top_frame->SetCallerFp(bottom_js_frame->fp());
@@ -1838,8 +1862,7 @@
// Drops all call frame matched by target and all frames above them.
template<typename TARGET>
static const char* DropActivationsInActiveThreadImpl(
- TARGET& target, bool do_drop) {
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate, TARGET& target, bool do_drop) {
Debug* debug = isolate->debug();
Zone zone(isolate);
Vector<StackFrame*> frames = CreateStackMap(isolate, &zone);
@@ -1938,8 +1961,8 @@
Handle<JSArray> shared_info_array, Handle<JSArray> result, bool do_drop) {
MultipleFunctionTarget target(shared_info_array, result);
- const char* message =
- DropActivationsInActiveThreadImpl(target, do_drop);
+ const char* message = DropActivationsInActiveThreadImpl(
+ shared_info_array->GetIsolate(), target, do_drop);
if (message) {
return message;
}
@@ -1949,7 +1972,7 @@
// Replace "blocked on active" with "replaced on active" status.
for (int i = 0; i < array_len; i++) {
- if (result->GetElement(i) ==
+ if (result->GetElement(result->GetIsolate(), i) ==
Smi::FromInt(LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) {
Handle<Object> replaced(
Smi::FromInt(LiveEdit::FUNCTION_REPLACED_ON_ACTIVE_STACK), isolate);
@@ -2004,7 +2027,7 @@
// First check inactive threads. Fail if some functions are blocked there.
InactiveThreadActivationsChecker inactive_threads_checker(shared_info_array,
result);
- Isolate::Current()->thread_manager()->IterateArchivedThreads(
+ isolate->thread_manager()->IterateArchivedThreads(
&inactive_threads_checker);
if (inactive_threads_checker.HasBlockedFunctions()) {
return result;
@@ -2056,7 +2079,8 @@
const char* LiveEdit::RestartFrame(JavaScriptFrame* frame) {
SingleFrameTarget target(frame);
- const char* result = DropActivationsInActiveThreadImpl(target, true);
+ const char* result = DropActivationsInActiveThreadImpl(
+ frame->isolate(), target, true);
if (result != NULL) {
return result;
}
diff --git a/src/log.cc b/src/log.cc
index 77bb9b3..1b3301e 100644
--- a/src/log.cc
+++ b/src/log.cc
@@ -974,7 +974,7 @@
if (c == '%' && i <= format.length() - 2) {
i++;
ASSERT('0' <= format[i] && format[i] <= '9');
- MaybeObject* maybe = args->GetElement(format[i] - '0');
+ MaybeObject* maybe = args->GetElement(isolate_, format[i] - '0');
Object* obj;
if (!maybe->ToObject(&obj)) {
msg.Append("<exception>");
@@ -1764,21 +1764,21 @@
}
-static void AddIsolateIdIfNeeded(StringStream* stream) {
- Isolate* isolate = Isolate::Current();
+static void AddIsolateIdIfNeeded(Isolate* isolate, StringStream* stream) {
if (isolate->IsDefaultIsolate()) return;
stream->Add("isolate-%p-", isolate);
}
-static SmartArrayPointer<const char> PrepareLogFileName(const char* file_name) {
+static SmartArrayPointer<const char> PrepareLogFileName(
+ Isolate* isolate, const char* file_name) {
if (strchr(file_name, '%') != NULL ||
- !Isolate::Current()->IsDefaultIsolate()) {
+ !isolate->IsDefaultIsolate()) {
// If there's a '%' in the log file name we have to expand
// placeholders.
HeapStringAllocator allocator;
StringStream stream(&allocator);
- AddIsolateIdIfNeeded(&stream);
+ AddIsolateIdIfNeeded(isolate, &stream);
for (const char* p = file_name; *p; p++) {
if (*p == '%') {
p++;
@@ -1832,7 +1832,7 @@
}
SmartArrayPointer<const char> log_file_name =
- PrepareLogFileName(FLAG_logfile);
+ PrepareLogFileName(isolate, FLAG_logfile);
log_->Initialize(*log_file_name);
if (FLAG_ll_prof) {
diff --git a/src/macros.py b/src/macros.py
index f1a2130..38b9a08 100644
--- a/src/macros.py
+++ b/src/macros.py
@@ -42,8 +42,8 @@
# These definitions must match the index of the properties in objects.h.
const kApiTagOffset = 0;
const kApiPropertyListOffset = 1;
-const kApiSerialNumberOffset = 2;
-const kApiConstructorOffset = 2;
+const kApiSerialNumberOffset = 3;
+const kApiConstructorOffset = 3;
const kApiPrototypeTemplateOffset = 5;
const kApiParentTemplateOffset = 6;
const kApiFlagOffset = 14;
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index 4eb51b5..7207f8d 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -74,7 +74,7 @@
heap_(NULL),
code_flusher_(NULL),
encountered_weak_collections_(NULL),
- code_to_deoptimize_(NULL) { }
+ have_code_to_deoptimize_(false) { }
#ifdef VERIFY_HEAP
class VerifyMarkingVisitor: public ObjectVisitor {
@@ -961,22 +961,10 @@
// objects (empty string, illegal builtin).
isolate()->stub_cache()->Clear();
- if (code_to_deoptimize_ != Smi::FromInt(0)) {
- // Convert the linked list of Code objects into a ZoneList.
- Zone zone(isolate());
- ZoneList<Code*> codes(4, &zone);
-
- Object *list = code_to_deoptimize_;
- while (list->IsCode()) {
- Code *code = Code::cast(list);
- list = code->code_to_deoptimize_link();
- codes.Add(code, &zone);
- // Destroy the link and don't ever try to deoptimize this code again.
- code->set_code_to_deoptimize_link(Smi::FromInt(0));
- }
- code_to_deoptimize_ = Smi::FromInt(0);
-
- Deoptimizer::DeoptimizeCodeList(isolate(), &codes);
+ if (have_code_to_deoptimize_) {
+ // Some code objects were marked for deoptimization during the GC.
+ Deoptimizer::DeoptimizeMarkedCode(isolate());
+ have_code_to_deoptimize_ = false;
}
}
@@ -2623,16 +2611,9 @@
ASSERT(entries->is_code_at(i));
Code* code = entries->code_at(i);
- if (IsMarked(code) && !WillBeDeoptimized(code)) {
- // Insert the code into the code_to_deoptimize linked list.
- Object* next = code_to_deoptimize_;
- if (next != Smi::FromInt(0)) {
- // Record the slot so that it is updated.
- Object** slot = code->code_to_deoptimize_link_slot();
- RecordSlot(slot, slot, next);
- }
- code->set_code_to_deoptimize_link(next);
- code_to_deoptimize_ = code;
+ if (IsMarked(code) && !code->marked_for_deoptimization()) {
+ code->set_marked_for_deoptimization(true);
+ have_code_to_deoptimize_ = true;
}
entries->clear_at(i);
}
@@ -3283,11 +3264,7 @@
// Return true if the given code is deoptimized or will be deoptimized.
bool MarkCompactCollector::WillBeDeoptimized(Code* code) {
- // We assume the code_to_deoptimize_link is initialized to undefined.
- // If it is 0, or refers to another Code object, then this code
- // is already linked, or was already linked into the list.
- return code->code_to_deoptimize_link() != heap()->undefined_value()
- || code->marked_for_deoptimization();
+ return code->marked_for_deoptimization();
}
@@ -3474,9 +3451,8 @@
}
}
- // Update the heads of the native contexts list the code to deoptimize list.
+ // Update the head of the native contexts list in the heap.
updating_visitor.VisitPointer(heap_->native_contexts_list_address());
- updating_visitor.VisitPointer(&code_to_deoptimize_);
heap_->string_table()->Iterate(&updating_visitor);
diff --git a/src/mark-compact.h b/src/mark-compact.h
index ee845a0..df2f782 100644
--- a/src/mark-compact.h
+++ b/src/mark-compact.h
@@ -949,7 +949,7 @@
MarkingDeque marking_deque_;
CodeFlusher* code_flusher_;
Object* encountered_weak_collections_;
- Object* code_to_deoptimize_;
+ bool have_code_to_deoptimize_;
List<Page*> evacuation_candidates_;
List<Code*> invalidated_code_;
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index 93f3fde..ff15738 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -567,10 +567,80 @@
Register input_low = scratch3;
__ Move(input_low, input_high, double_input);
- __ EmitOutOfInt32RangeTruncate(result_reg,
- input_high,
- input_low,
- scratch);
+ Label normal_exponent, restore_sign;
+ // Extract the biased exponent in result.
+ __ Ext(result_reg,
+ input_high,
+ HeapNumber::kExponentShift,
+ HeapNumber::kExponentBits);
+
+ // Check for Infinity and NaNs, which should return 0.
+ __ Subu(scratch, result_reg, HeapNumber::kExponentMask);
+ __ Movz(result_reg, zero_reg, scratch);
+ __ Branch(&done, eq, scratch, Operand(zero_reg));
+
+ // Express exponent as delta to (number of mantissa bits + 31).
+ __ Subu(result_reg,
+ result_reg,
+ Operand(HeapNumber::kExponentBias + HeapNumber::kMantissaBits + 31));
+
+ // If the delta is strictly positive, all bits would be shifted away,
+ // which means that we can return 0.
+ __ Branch(&normal_exponent, le, result_reg, Operand(zero_reg));
+ __ mov(result_reg, zero_reg);
+ __ Branch(&done);
+
+ __ bind(&normal_exponent);
+ const int kShiftBase = HeapNumber::kNonMantissaBitsInTopWord - 1;
+ // Calculate shift.
+ __ Addu(scratch, result_reg, Operand(kShiftBase + HeapNumber::kMantissaBits));
+
+ // Save the sign.
+ Register sign = result_reg;
+ result_reg = no_reg;
+ __ And(sign, input_high, Operand(HeapNumber::kSignMask));
+
+ // On ARM shifts > 31 bits are valid and will result in zero. On MIPS we need
+ // to check for this specific case.
+ Label high_shift_needed, high_shift_done;
+ __ Branch(&high_shift_needed, lt, scratch, Operand(32));
+ __ mov(input_high, zero_reg);
+ __ Branch(&high_shift_done);
+ __ bind(&high_shift_needed);
+
+ // Set the implicit 1 before the mantissa part in input_high.
+ __ Or(input_high,
+ input_high,
+ Operand(1 << HeapNumber::kMantissaBitsInTopWord));
+ // Shift the mantissa bits to the correct position.
+ // We don't need to clear non-mantissa bits as they will be shifted away.
+ // If they weren't, it would mean that the answer is in the 32bit range.
+ __ sllv(input_high, input_high, scratch);
+
+ __ bind(&high_shift_done);
+
+ // Replace the shifted bits with bits from the lower mantissa word.
+ Label pos_shift, shift_done;
+ __ li(at, 32);
+ __ subu(scratch, at, scratch);
+ __ Branch(&pos_shift, ge, scratch, Operand(zero_reg));
+
+ // Negate scratch.
+ __ Subu(scratch, zero_reg, scratch);
+ __ sllv(input_low, input_low, scratch);
+ __ Branch(&shift_done);
+
+ __ bind(&pos_shift);
+ __ srlv(input_low, input_low, scratch);
+
+ __ bind(&shift_done);
+ __ Or(input_high, input_high, Operand(input_low));
+ // Restore sign if necessary.
+ __ mov(scratch, sign);
+ result_reg = sign;
+ sign = no_reg;
+ __ Subu(result_reg, zero_reg, input_high);
+ __ Movz(result_reg, input_high, scratch);
__ bind(&done);
@@ -1486,7 +1556,6 @@
Register right = a0;
Register scratch1 = t3;
Register scratch2 = t5;
- Register scratch3 = t0;
ASSERT(smi_operands || (not_numbers != NULL));
if (smi_operands) {
@@ -1590,12 +1659,8 @@
__ SmiUntag(a2, right);
} else {
// Convert operands to 32-bit integers. Right in a2 and left in a3.
- __ TruncateNumberToI(
- left, a3, heap_number_map,
- scratch1, scratch2, scratch3, not_numbers);
- __ TruncateNumberToI(
- right, a2, heap_number_map,
- scratch1, scratch2, scratch3, not_numbers);
+ __ TruncateNumberToI(left, a3, heap_number_map, scratch1, not_numbers);
+ __ TruncateNumberToI(right, a2, heap_number_map, scratch1, not_numbers);
}
Label result_not_a_smi;
switch (op) {
diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc
index cd1d38e..a85b0d8 100644
--- a/src/mips/macro-assembler-mips.cc
+++ b/src/mips/macro-assembler-mips.cc
@@ -1298,60 +1298,6 @@
}
-// Tries to get a signed int32 out of a double precision floating point heap
-// number. Rounds towards 0. Branch to 'not_int32' if the double is out of the
-// 32bits signed integer range.
-// This method implementation differs from the ARM version for performance
-// reasons.
-void MacroAssembler::ConvertToInt32(Register source,
- Register dest,
- Register scratch,
- Register scratch2,
- FPURegister double_scratch,
- Label *not_int32) {
- Label right_exponent, done;
- // Get exponent word (ENDIAN issues).
- lw(scratch, FieldMemOperand(source, HeapNumber::kExponentOffset));
- // Get exponent alone in scratch2.
- And(scratch2, scratch, Operand(HeapNumber::kExponentMask));
- // Load dest with zero. We use this either for the final shift or
- // for the answer.
- mov(dest, zero_reg);
- // Check whether the exponent matches a 32 bit signed int that is not a Smi.
- // A non-Smi integer is 1.xxx * 2^30 so the exponent is 30 (biased). This is
- // the exponent that we are fastest at and also the highest exponent we can
- // handle here.
- const uint32_t non_smi_exponent =
- (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift;
- // If we have a match of the int32-but-not-Smi exponent then skip some logic.
- Branch(&right_exponent, eq, scratch2, Operand(non_smi_exponent));
- // If the exponent is higher than that then go to not_int32 case. This
- // catches numbers that don't fit in a signed int32, infinities and NaNs.
- Branch(not_int32, gt, scratch2, Operand(non_smi_exponent));
-
- // We know the exponent is smaller than 30 (biased). If it is less than
- // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, i.e.
- // it rounds to zero.
- const uint32_t zero_exponent =
- (HeapNumber::kExponentBias + 0) << HeapNumber::kExponentShift;
- Subu(scratch2, scratch2, Operand(zero_exponent));
- // Dest already has a Smi zero.
- Branch(&done, lt, scratch2, Operand(zero_reg));
- bind(&right_exponent);
-
- // MIPS FPU instructions implementing double precision to integer
- // conversion using round to zero. Since the FP value was qualified
- // above, the resulting integer should be a legal int32.
- // The original 'Exponent' word is still in scratch.
- lwc1(double_scratch, FieldMemOperand(source, HeapNumber::kMantissaOffset));
- mtc1(scratch, FPURegister::from_code(double_scratch.code() + 1));
- trunc_w_d(double_scratch, double_scratch);
- mfc1(dest, double_scratch);
-
- bind(&done);
-}
-
-
void MacroAssembler::EmitFPUTruncate(FPURoundingMode rounding_mode,
Register result,
DoubleRegister double_input,
@@ -1416,88 +1362,6 @@
}
-void MacroAssembler::EmitOutOfInt32RangeTruncate(Register result,
- Register input_high,
- Register input_low,
- Register scratch) {
- Label done, normal_exponent, restore_sign;
- // Extract the biased exponent in result.
- Ext(result,
- input_high,
- HeapNumber::kExponentShift,
- HeapNumber::kExponentBits);
-
- // Check for Infinity and NaNs, which should return 0.
- Subu(scratch, result, HeapNumber::kExponentMask);
- Movz(result, zero_reg, scratch);
- Branch(&done, eq, scratch, Operand(zero_reg));
-
- // Express exponent as delta to (number of mantissa bits + 31).
- Subu(result,
- result,
- Operand(HeapNumber::kExponentBias + HeapNumber::kMantissaBits + 31));
-
- // If the delta is strictly positive, all bits would be shifted away,
- // which means that we can return 0.
- Branch(&normal_exponent, le, result, Operand(zero_reg));
- mov(result, zero_reg);
- Branch(&done);
-
- bind(&normal_exponent);
- const int kShiftBase = HeapNumber::kNonMantissaBitsInTopWord - 1;
- // Calculate shift.
- Addu(scratch, result, Operand(kShiftBase + HeapNumber::kMantissaBits));
-
- // Save the sign.
- Register sign = result;
- result = no_reg;
- And(sign, input_high, Operand(HeapNumber::kSignMask));
-
- // On ARM shifts > 31 bits are valid and will result in zero. On MIPS we need
- // to check for this specific case.
- Label high_shift_needed, high_shift_done;
- Branch(&high_shift_needed, lt, scratch, Operand(32));
- mov(input_high, zero_reg);
- Branch(&high_shift_done);
- bind(&high_shift_needed);
-
- // Set the implicit 1 before the mantissa part in input_high.
- Or(input_high,
- input_high,
- Operand(1 << HeapNumber::kMantissaBitsInTopWord));
- // Shift the mantissa bits to the correct position.
- // We don't need to clear non-mantissa bits as they will be shifted away.
- // If they weren't, it would mean that the answer is in the 32bit range.
- sllv(input_high, input_high, scratch);
-
- bind(&high_shift_done);
-
- // Replace the shifted bits with bits from the lower mantissa word.
- Label pos_shift, shift_done;
- li(at, 32);
- subu(scratch, at, scratch);
- Branch(&pos_shift, ge, scratch, Operand(zero_reg));
-
- // Negate scratch.
- Subu(scratch, zero_reg, scratch);
- sllv(input_low, input_low, scratch);
- Branch(&shift_done);
-
- bind(&pos_shift);
- srlv(input_low, input_low, scratch);
-
- bind(&shift_done);
- Or(input_high, input_high, Operand(input_low));
- // Restore sign if necessary.
- mov(scratch, sign);
- result = sign;
- sign = no_reg;
- Subu(result, zero_reg, input_high);
- Movz(result, input_high, scratch);
- bind(&done);
-}
-
-
void MacroAssembler::TryInlineTruncateDoubleToI(Register result,
DoubleRegister double_input,
Label* done) {
@@ -1570,31 +1434,14 @@
void MacroAssembler::TruncateNumberToI(Register object,
Register result,
Register heap_number_map,
- Register scratch1,
- Register scratch2,
- Register scratch3,
+ Register scratch,
Label* not_number) {
Label done;
- Label not_in_int32_range;
- DoubleRegister double_scratch = f12;
+ ASSERT(!result.is(object));
UntagAndJumpIfSmi(result, object, &done);
- JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number);
- ConvertToInt32(object,
- result,
- scratch1,
- scratch2,
- double_scratch,
- ¬_in_int32_range);
- jmp(&done);
-
- bind(¬_in_int32_range);
- lw(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset));
- lw(scratch2, FieldMemOperand(object, HeapNumber::kMantissaOffset));
- EmitOutOfInt32RangeTruncate(result,
- scratch1,
- scratch2,
- scratch3);
+ JumpIfNotHeapNumber(object, heap_number_map, scratch, not_number);
+ TruncateHeapNumberToI(result, object);
bind(&done);
}
diff --git a/src/mips/macro-assembler-mips.h b/src/mips/macro-assembler-mips.h
index 8f0b3b1..75ded88 100644
--- a/src/mips/macro-assembler-mips.h
+++ b/src/mips/macro-assembler-mips.h
@@ -758,17 +758,6 @@
BranchF(target, nan, cc, cmp1, cmp2, bd);
};
- // Convert the HeapNumber pointed to by source to a 32bits signed integer
- // dest. If the HeapNumber does not fit into a 32bits signed integer branch
- // to not_int32 label. If FPU is available double_scratch is used but not
- // scratch2.
- void ConvertToInt32(Register source,
- Register dest,
- Register scratch,
- Register scratch2,
- FPURegister double_scratch,
- Label *not_int32);
-
// Truncates a double using a specific rounding mode, and writes the value
// to the result register.
// The except_flag will contain any exceptions caused by the instruction.
@@ -783,17 +772,6 @@
CheckForInexactConversion check_inexact
= kDontCheckForInexactConversion);
- // Helper for EmitECMATruncate.
- // This will truncate a floating-point value outside of the singed 32bit
- // integer range to a 32bit signed integer.
- // Expects the double value loaded in input_high and input_low.
- // Exits with the answer in 'result'.
- // Note that this code does not work for values in the 32bit range!
- void EmitOutOfInt32RangeTruncate(Register result,
- Register input_high,
- Register input_low,
- Register scratch);
-
// Performs a truncating conversion of a floating point number as used by
// the JS bitwise operations. See ECMA-262 9.5: ToInt32. Goes to 'done' if it
// succeeds, otherwise falls through if result is saturated. On return
@@ -821,9 +799,7 @@
void TruncateNumberToI(Register object,
Register result,
Register heap_number_map,
- Register scratch1,
- Register scratch2,
- Register scratch3,
+ Register scratch,
Label* not_int32);
// Loads the number from object into dst register.
diff --git a/src/mksnapshot.cc b/src/mksnapshot.cc
index 9e63555..156cd77 100644
--- a/src/mksnapshot.cc
+++ b/src/mksnapshot.cc
@@ -333,8 +333,9 @@
exit(1);
}
#endif
- i::Serializer::Enable();
Isolate* isolate = Isolate::GetCurrent();
+ i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
+ i::Serializer::Enable(internal_isolate);
Persistent<Context> context;
{
HandleScope handle_scope(isolate);
@@ -391,7 +392,7 @@
// Make sure all builtin scripts are cached.
{ HandleScope scope(isolate);
for (int i = 0; i < i::Natives::GetBuiltinsCount(); i++) {
- i::Isolate::Current()->bootstrapper()->NativesSourceLookup(i);
+ internal_isolate->bootstrapper()->NativesSourceLookup(i);
}
}
// If we don't do this then we end up with a stray root pointing at the
@@ -402,10 +403,11 @@
CppByteSink sink(argv[1]);
// This results in a somewhat smaller snapshot, probably because it gets rid
// of some things that are cached between garbage collections.
- i::StartupSerializer ser(&sink);
+ i::StartupSerializer ser(internal_isolate, &sink);
ser.SerializeStrongReferences();
- i::PartialSerializer partial_ser(&ser, sink.partial_sink());
+ i::PartialSerializer partial_ser(
+ internal_isolate, &ser, sink.partial_sink());
partial_ser.Serialize(&raw_context);
ser.SerializeWeakReferences();
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index a61eacf..3eb7817 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -501,7 +501,7 @@
}
if (cache_stamp()->IsSmi()) {
CHECK(Smi::cast(cache_stamp())->value() <=
- Smi::cast(Isolate::Current()->date_cache()->stamp())->value());
+ Smi::cast(GetIsolate()->date_cache()->stamp())->value());
}
}
@@ -889,6 +889,7 @@
void TemplateInfo::TemplateInfoVerify() {
VerifyPointer(tag());
VerifyPointer(property_list());
+ VerifyPointer(property_accessors());
}
@@ -897,7 +898,6 @@
TemplateInfoVerify();
VerifyPointer(serial_number());
VerifyPointer(call_code());
- VerifyPointer(property_accessors());
VerifyPointer(prototype_template());
VerifyPointer(parent_template());
VerifyPointer(named_property_handler());
diff --git a/src/objects-inl.h b/src/objects-inl.h
index f629d9f..fc5ed24 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -917,17 +917,17 @@
}
-MaybeObject* Object::GetElement(uint32_t index) {
+MaybeObject* Object::GetElement(Isolate* isolate, uint32_t index) {
// GetElement can trigger a getter which can cause allocation.
// This was not always the case. This ASSERT is here to catch
// leftover incorrect uses.
ASSERT(AllowHeapAllocation::IsAllowed());
- return GetElementWithReceiver(this, index);
+ return GetElementWithReceiver(isolate, this, index);
}
-Object* Object::GetElementNoExceptionThrown(uint32_t index) {
- MaybeObject* maybe = GetElementWithReceiver(this, index);
+Object* Object::GetElementNoExceptionThrown(Isolate* isolate, uint32_t index) {
+ MaybeObject* maybe = GetElementWithReceiver(isolate, this, index);
ASSERT(!maybe->IsFailure());
Object* result = NULL; // Initialization to please compiler.
maybe->ToObject(&result);
@@ -4195,7 +4195,7 @@
TransitionArray* transitions;
MaybeObject* maybe_transitions;
if (!map->HasTransitionArray()) {
- maybe_transitions = TransitionArray::Allocate(0);
+ maybe_transitions = TransitionArray::Allocate(map->GetIsolate(), 0);
if (!maybe_transitions->To(&transitions)) return maybe_transitions;
transitions->set_back_pointer_storage(map->GetBackPointer());
} else if (!map->transitions()->IsFullTransitionArray()) {
@@ -4466,11 +4466,10 @@
ACCESSORS(TemplateInfo, tag, Object, kTagOffset)
ACCESSORS(TemplateInfo, property_list, Object, kPropertyListOffset)
+ACCESSORS(TemplateInfo, property_accessors, Object, kPropertyAccessorsOffset)
ACCESSORS(FunctionTemplateInfo, serial_number, Object, kSerialNumberOffset)
ACCESSORS(FunctionTemplateInfo, call_code, Object, kCallCodeOffset)
-ACCESSORS(FunctionTemplateInfo, property_accessors, Object,
- kPropertyAccessorsOffset)
ACCESSORS(FunctionTemplateInfo, prototype_template, Object,
kPrototypeTemplateOffset)
ACCESSORS(FunctionTemplateInfo, parent_template, Object, kParentTemplateOffset)
@@ -4840,7 +4839,7 @@
bool SharedFunctionInfo::is_compiled() {
return code() !=
- Isolate::Current()->builtins()->builtin(Builtins::kLazyCompile);
+ GetIsolate()->builtins()->builtin(Builtins::kLazyCompile);
}
@@ -5004,6 +5003,7 @@
context()->native_context()->AddOptimizedFunction(this);
}
if (was_optimized && !is_optimized) {
+ // TODO(titzer): linear in the number of optimized functions; fix!
context()->native_context()->RemoveOptimizedFunction(this);
}
}
@@ -5266,6 +5266,20 @@
}
+Object* Code::next_code_link() {
+ CHECK(kind() == OPTIMIZED_FUNCTION);
+ return Object::cast(READ_FIELD(this, kTypeFeedbackInfoOffset));
+}
+
+
+void Code::set_next_code_link(Object* value, WriteBarrierMode mode) {
+ CHECK(kind() == OPTIMIZED_FUNCTION);
+ WRITE_FIELD(this, kTypeFeedbackInfoOffset, value);
+ CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kTypeFeedbackInfoOffset,
+ value, mode);
+}
+
+
int Code::stub_info() {
ASSERT(kind() == COMPARE_IC || kind() == COMPARE_NIL_IC ||
kind() == BINARY_OP_IC || kind() == LOAD_IC);
@@ -5287,25 +5301,6 @@
}
-Object* Code::code_to_deoptimize_link() {
- // Optimized code should not have type feedback.
- ASSERT(kind() == OPTIMIZED_FUNCTION);
- return READ_FIELD(this, kTypeFeedbackInfoOffset);
-}
-
-
-void Code::set_code_to_deoptimize_link(Object* value) {
- ASSERT(kind() == OPTIMIZED_FUNCTION);
- WRITE_FIELD(this, kTypeFeedbackInfoOffset, value);
-}
-
-
-Object** Code::code_to_deoptimize_link_slot() {
- ASSERT(kind() == OPTIMIZED_FUNCTION);
- return HeapObject::RawField(this, kTypeFeedbackInfoOffset);
-}
-
-
ACCESSORS(Code, gc_metadata, Object, kGCMetadataOffset)
INT_ACCESSORS(Code, ic_age, kICAgeOffset)
diff --git a/src/objects-printer.cc b/src/objects-printer.cc
index 9ea060f..0b8fdfd 100644
--- a/src/objects-printer.cc
+++ b/src/objects-printer.cc
@@ -1070,6 +1070,8 @@
tag()->ShortPrint(out);
PrintF(out, "\n - property_list: ");
property_list()->ShortPrint(out);
+ PrintF(out, "\n - property_accessors: ");
+ property_accessors()->ShortPrint(out);
PrintF(out, "\n - constructor: ");
constructor()->ShortPrint(out);
PrintF(out, "\n - internal_field_count: ");
diff --git a/src/objects-visiting-inl.h b/src/objects-visiting-inl.h
index 9398d6d..e90c74c 100644
--- a/src/objects-visiting-inl.h
+++ b/src/objects-visiting-inl.h
@@ -304,7 +304,7 @@
&& (target->ic_state() == MEGAMORPHIC || target->ic_state() == GENERIC ||
target->ic_state() == POLYMORPHIC || heap->flush_monomorphic_ics() ||
Serializer::enabled() || target->ic_age() != heap->global_ic_age())) {
- IC::Clear(rinfo->pc());
+ IC::Clear(target->GetIsolate(), rinfo->pc());
target = Code::GetCodeFromTargetAddress(rinfo->target_address());
}
heap->mark_compact_collector()->RecordRelocSlot(rinfo, target);
diff --git a/src/objects.cc b/src/objects.cc
index 80ca046..9cb077b 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -83,23 +83,19 @@
}
-MaybeObject* Object::ToObject() {
+MaybeObject* Object::ToObject(Isolate* isolate) {
if (IsJSReceiver()) {
return this;
} else if (IsNumber()) {
- Isolate* isolate = Isolate::Current();
Context* native_context = isolate->context()->native_context();
return CreateJSValue(native_context->number_function(), this);
} else if (IsBoolean()) {
- Isolate* isolate = HeapObject::cast(this)->GetIsolate();
Context* native_context = isolate->context()->native_context();
return CreateJSValue(native_context->boolean_function(), this);
} else if (IsString()) {
- Isolate* isolate = HeapObject::cast(this)->GetIsolate();
Context* native_context = isolate->context()->native_context();
return CreateJSValue(native_context->string_function(), this);
} else if (IsSymbol()) {
- Isolate* isolate = HeapObject::cast(this)->GetIsolate();
Context* native_context = isolate->context()->native_context();
return CreateJSValue(native_context->symbol_function(), this);
}
@@ -135,7 +131,7 @@
} else if (IsBoolean()) {
holder = native_context->boolean_function()->instance_prototype();
} else {
- Isolate::Current()->PushStackTraceAndDie(
+ result->isolate()->PushStackTraceAndDie(
0xDEAD0000, this, JSReceiver::cast(this)->map(), 0xDEAD0001);
}
}
@@ -422,24 +418,22 @@
}
-Handle<Object> Object::GetProperty(Handle<Object> object, Handle<Name> name) {
+Handle<Object> Object::GetProperty(Handle<Object> object,
+ Handle<Name> name) {
// TODO(rossberg): The index test should not be here but in the GetProperty
// method (or somewhere else entirely). Needs more global clean-up.
uint32_t index;
+ Isolate* isolate = name->GetIsolate();
if (name->AsArrayIndex(&index))
- return GetElement(object, index);
- Isolate* isolate = object->IsHeapObject()
- ? Handle<HeapObject>::cast(object)->GetIsolate()
- : Isolate::Current();
+ return GetElement(isolate, object, index);
CALL_HEAP_FUNCTION(isolate, object->GetProperty(*name), Object);
}
-Handle<Object> Object::GetElement(Handle<Object> object, uint32_t index) {
- Isolate* isolate = object->IsHeapObject()
- ? Handle<HeapObject>::cast(object)->GetIsolate()
- : Isolate::Current();
- CALL_HEAP_FUNCTION(isolate, object->GetElement(index), Object);
+Handle<Object> Object::GetElement(Isolate* isolate,
+ Handle<Object> object,
+ uint32_t index) {
+ CALL_HEAP_FUNCTION(isolate, object->GetElement(isolate, index), Object);
}
@@ -801,9 +795,7 @@
LookupResult* result,
Handle<Name> key,
PropertyAttributes* attributes) {
- Isolate* isolate = object->IsHeapObject()
- ? Handle<HeapObject>::cast(object)->GetIsolate()
- : Isolate::Current();
+ Isolate* isolate = result->isolate();
CALL_HEAP_FUNCTION(
isolate,
object->GetProperty(*receiver, result, *key, attributes),
@@ -816,9 +808,7 @@
LookupResult* result,
Handle<Name> key,
PropertyAttributes* attributes) {
- Isolate* isolate = object->IsHeapObject()
- ? Handle<HeapObject>::cast(object)->GetIsolate()
- : Isolate::Current();
+ Isolate* isolate = result->isolate();
CALL_HEAP_FUNCTION_PASS_EXCEPTION(
isolate,
object->GetProperty(*receiver, result, *key, attributes));
@@ -910,10 +900,9 @@
}
-MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
- Isolate* isolate = IsSmi()
- ? Isolate::Current()
- : HeapObject::cast(this)->GetIsolate();
+MaybeObject* Object::GetElementWithReceiver(Isolate* isolate,
+ Object* receiver,
+ uint32_t index) {
Heap* heap = isolate->heap();
Object* holder = this;
@@ -3012,48 +3001,101 @@
}
-void Map::AppendCallbackDescriptors(Handle<Map> map,
- Handle<Object> descriptors) {
- Isolate* isolate = map->GetIsolate();
- Handle<DescriptorArray> array(map->instance_descriptors());
- NeanderArray callbacks(descriptors);
- int nof_callbacks = callbacks.length();
+template<class T>
+static int AppendUniqueCallbacks(NeanderArray* callbacks,
+ Handle<typename T::Array> array,
+ int valid_descriptors) {
+ int nof_callbacks = callbacks->length();
- ASSERT(array->NumberOfSlackDescriptors() >= nof_callbacks);
-
+ Isolate* isolate = array->GetIsolate();
// Ensure the keys are unique names before writing them into the
// instance descriptor. Since it may cause a GC, it has to be done before we
// temporarily put the heap in an invalid state while appending descriptors.
for (int i = 0; i < nof_callbacks; ++i) {
- Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks.get(i)));
- if (!entry->name()->IsUniqueName()) {
- Handle<String> key =
- isolate->factory()->InternalizedStringFromString(
- Handle<String>(String::cast(entry->name())));
- entry->set_name(*key);
- }
+ Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
+ if (entry->name()->IsUniqueName()) continue;
+ Handle<String> key =
+ isolate->factory()->InternalizedStringFromString(
+ Handle<String>(String::cast(entry->name())));
+ entry->set_name(*key);
}
- int nof = map->NumberOfOwnDescriptors();
-
// Fill in new callback descriptors. Process the callbacks from
// back to front so that the last callback with a given name takes
// precedence over previously added callbacks with that name.
for (int i = nof_callbacks - 1; i >= 0; i--) {
- AccessorInfo* entry = AccessorInfo::cast(callbacks.get(i));
+ AccessorInfo* entry = AccessorInfo::cast(callbacks->get(i));
Name* key = Name::cast(entry->name());
// Check if a descriptor with this name already exists before writing.
- if (array->Search(key, nof) == DescriptorArray::kNotFound) {
- CallbacksDescriptor desc(key, entry, entry->property_attributes());
- array->Append(&desc);
- nof += 1;
+ if (!T::Contains(key, entry, valid_descriptors, array)) {
+ T::Insert(key, entry, valid_descriptors, array);
+ valid_descriptors++;
}
}
+ return valid_descriptors;
+}
+
+struct DescriptorArrayAppender {
+ typedef DescriptorArray Array;
+ static bool Contains(Name* key,
+ AccessorInfo* entry,
+ int valid_descriptors,
+ Handle<DescriptorArray> array) {
+ return array->Search(key, valid_descriptors) != DescriptorArray::kNotFound;
+ }
+ static void Insert(Name* key,
+ AccessorInfo* entry,
+ int valid_descriptors,
+ Handle<DescriptorArray> array) {
+ CallbacksDescriptor desc(key, entry, entry->property_attributes());
+ array->Append(&desc);
+ }
+};
+
+
+struct FixedArrayAppender {
+ typedef FixedArray Array;
+ static bool Contains(Name* key,
+ AccessorInfo* entry,
+ int valid_descriptors,
+ Handle<FixedArray> array) {
+ for (int i = 0; i < valid_descriptors; i++) {
+ if (key == AccessorInfo::cast(array->get(i))->name()) return true;
+ }
+ return false;
+ }
+ static void Insert(Name* key,
+ AccessorInfo* entry,
+ int valid_descriptors,
+ Handle<FixedArray> array) {
+ array->set(valid_descriptors, entry);
+ }
+};
+
+
+void Map::AppendCallbackDescriptors(Handle<Map> map,
+ Handle<Object> descriptors) {
+ int nof = map->NumberOfOwnDescriptors();
+ Handle<DescriptorArray> array(map->instance_descriptors());
+ NeanderArray callbacks(descriptors);
+ ASSERT(array->NumberOfSlackDescriptors() >= callbacks.length());
+ nof = AppendUniqueCallbacks<DescriptorArrayAppender>(&callbacks, array, nof);
map->SetNumberOfOwnDescriptors(nof);
}
+int AccessorInfo::AppendUnique(Handle<Object> descriptors,
+ Handle<FixedArray> array,
+ int valid_descriptors) {
+ NeanderArray callbacks(descriptors);
+ ASSERT(array->length() >= callbacks.length() + valid_descriptors);
+ return AppendUniqueCallbacks<FixedArrayAppender>(&callbacks,
+ array,
+ valid_descriptors);
+}
+
+
static bool ContainsMap(MapHandleList* maps, Handle<Map> map) {
ASSERT(!map.is_null());
for (int i = 0; i < maps->length(); ++i) {
@@ -4067,7 +4109,8 @@
PropertyAttributes old_attributes = ABSENT;
bool is_observed = FLAG_harmony_observation && self->map()->is_observed();
if (is_observed && lookup.IsProperty()) {
- if (lookup.IsDataProperty()) old_value = Object::GetProperty(self, name);
+ if (lookup.IsDataProperty()) old_value =
+ Object::GetProperty(self, name);
old_attributes = lookup.GetAttributes();
}
@@ -5093,7 +5136,7 @@
if (should_enqueue_change_record) {
old_value = object->GetLocalElementAccessorPair(index) != NULL
? Handle<Object>::cast(factory->the_hole_value())
- : Object::GetElement(object, index);
+ : Object::GetElement(isolate, object, index);
}
}
@@ -6129,7 +6172,7 @@
if (is_element) {
preexists = object->HasLocalElement(index);
if (preexists && object->GetLocalElementAccessorPair(index) == NULL) {
- old_value = Object::GetElement(object, index);
+ old_value = Object::GetElement(isolate, object, index);
}
} else {
LookupResult lookup(isolate);
@@ -6541,7 +6584,7 @@
} else {
// Descriptor arrays grow by 50%.
MaybeObject* maybe_descriptors = DescriptorArray::Allocate(
- old_size, old_size < 4 ? 1 : old_size / 2);
+ GetIsolate(), old_size, old_size < 4 ? 1 : old_size / 2);
if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
DescriptorArray::WhitenessWitness witness(new_descriptors);
@@ -6791,7 +6834,8 @@
}
DescriptorArray* new_descriptors;
- MaybeObject* maybe_descriptors = DescriptorArray::Allocate(old_size, 1);
+ MaybeObject* maybe_descriptors =
+ DescriptorArray::Allocate(GetIsolate(), old_size, 1);
if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
DescriptorArray::WhitenessWitness witness(new_descriptors);
@@ -6838,7 +6882,7 @@
int size = enumeration_index;
DescriptorArray* descriptors;
- MaybeObject* maybe_descriptors = Allocate(size);
+ MaybeObject* maybe_descriptors = Allocate(GetIsolate(), size);
if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
DescriptorArray::WhitenessWitness witness(descriptors);
@@ -6885,7 +6929,8 @@
ASSERT_LT(insertion_index, new_size);
DescriptorArray* new_descriptors;
- MaybeObject* maybe_descriptors = DescriptorArray::Allocate(new_size);
+ MaybeObject* maybe_descriptors =
+ DescriptorArray::Allocate(GetIsolate(), new_size);
if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
DescriptorArray::WhitenessWitness witness(new_descriptors);
@@ -7675,8 +7720,10 @@
#endif
-MaybeObject* DescriptorArray::Allocate(int number_of_descriptors, int slack) {
- Heap* heap = Isolate::Current()->heap();
+MaybeObject* DescriptorArray::Allocate(Isolate* isolate,
+ int number_of_descriptors,
+ int slack) {
+ Heap* heap = isolate->heap();
// Do not use DescriptorArray::cast on incomplete object.
int size = number_of_descriptors + slack;
if (size == 0) return heap->empty_descriptor_array();
@@ -7744,7 +7791,8 @@
// Allocate a new descriptor array large enough to hold the required
// descriptors, with minimally the exact same size as this descriptor array.
MaybeObject* maybe_descriptors = DescriptorArray::Allocate(
- new_size, Max(new_size, other->number_of_descriptors()) - new_size);
+ GetIsolate(), new_size,
+ Max(new_size, other->number_of_descriptors()) - new_size);
if (!maybe_descriptors->To(&result)) return maybe_descriptors;
ASSERT(result->length() > length() ||
result->NumberOfSlackDescriptors() > 0 ||
@@ -7960,7 +8008,7 @@
bool String::LooksValid() {
- if (!Isolate::Current()->heap()->Contains(this)) return false;
+ if (!GetIsolate()->heap()->Contains(this)) return false;
return true;
}
@@ -8120,8 +8168,7 @@
}
-void Relocatable::PostGarbageCollectionProcessing() {
- Isolate* isolate = Isolate::Current();
+void Relocatable::PostGarbageCollectionProcessing(Isolate* isolate) {
Relocatable* current = isolate->relocatable_top();
while (current != NULL) {
current->PostGarbageCollection();
@@ -8132,7 +8179,7 @@
// Reserve space for statics needing saving and restoring.
int Relocatable::ArchiveSpacePerThread() {
- return sizeof(Isolate::Current()->relocatable_top());
+ return sizeof(Relocatable*); // NOLINT
}
@@ -8158,8 +8205,7 @@
}
-void Relocatable::Iterate(ObjectVisitor* v) {
- Isolate* isolate = Isolate::Current();
+void Relocatable::Iterate(Isolate* isolate, ObjectVisitor* v) {
Iterate(v, isolate->relocatable_top());
}
@@ -9273,7 +9319,7 @@
ASSERT(info->IsOptimizing() || !info->shared_info()->is_compiled());
ASSERT(!info->isolate()->has_pending_exception());
bool result = Compiler::CompileLazy(info);
- ASSERT(result != Isolate::Current()->has_pending_exception());
+ ASSERT(result != info->isolate()->has_pending_exception());
if (!result && flag == CLEAR_EXCEPTION) {
info->isolate()->clear_pending_exception();
}
@@ -9663,12 +9709,13 @@
}
-MaybeObject* Oddball::Initialize(const char* to_string,
+MaybeObject* Oddball::Initialize(Heap* heap,
+ const char* to_string,
Object* to_number,
byte kind) {
String* internalized_to_string;
{ MaybeObject* maybe_string =
- Isolate::Current()->heap()->InternalizeUtf8String(
+ heap->InternalizeUtf8String(
CStrVector(to_string));
if (!maybe_string->To(&internalized_to_string)) return maybe_string;
}
@@ -10305,7 +10352,7 @@
RelocInfo* info = it.rinfo();
Code* target(Code::GetCodeFromTargetAddress(info->target_address()));
if (target->is_inline_cache_stub()) {
- IC::Clear(info->pc());
+ IC::Clear(this->GetIsolate(), info->pc());
}
}
}
@@ -10329,6 +10376,18 @@
}
+BailoutId Code::TranslatePcOffsetToAstId(uint32_t pc_offset) {
+ DisallowHeapAllocation no_gc;
+ ASSERT(kind() == FUNCTION);
+ for (FullCodeGenerator::BackEdgeTableIterator it(this, &no_gc);
+ !it.Done();
+ it.Next()) {
+ if (it.pc_offset() == pc_offset) return it.ast_id();
+ }
+ return BailoutId::None();
+}
+
+
bool Code::allowed_in_shared_map_code_cache() {
return is_keyed_load_stub() || is_keyed_store_stub() ||
(is_compare_ic_stub() &&
@@ -10389,7 +10448,7 @@
void Code::GetCodeAgeAndParity(Code* code, Age* age,
MarkingParity* parity) {
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = code->GetIsolate();
Builtins* builtins = isolate->builtins();
Code* stub = NULL;
#define HANDLE_CODE_AGE(AGE) \
@@ -10789,7 +10848,8 @@
// If there is no back edge table, the "table start" will be at or after
// (due to alignment) the end of the instruction stream.
if (static_cast<int>(offset) < instruction_size()) {
- FullCodeGenerator::BackEdgeTableIterator back_edges(this);
+ DisallowHeapAllocation no_gc;
+ FullCodeGenerator::BackEdgeTableIterator back_edges(this, &no_gc);
PrintF(out, "Back edges (size = %u)\n", back_edges.table_length());
PrintF(out, "ast_id pc_offset loop_depth\n");
@@ -10965,7 +11025,7 @@
ASSERT(attributes != ABSENT);
if (attributes == DONT_DELETE) return false;
old_values->Add(object->GetLocalElementAccessorPair(index) == NULL
- ? Object::GetElement(object, index)
+ ? Object::GetElement(isolate, object, index)
: Handle<Object>::cast(isolate->factory()->the_hole_value()));
indices->Add(index);
return true;
@@ -11350,13 +11410,15 @@
int code_entries = starts.number_of_entries();
if (start == end) return;
- // Collect all the code to deoptimize.
- Zone zone(isolate);
- ZoneList<Code*> codes(end - start, &zone);
+ // Mark all the code that needs to be deoptimized.
+ bool marked = false;
for (int i = start; i < end; i++) {
if (is_code_at(i)) {
Code* code = code_at(i);
- if (!code->marked_for_deoptimization()) codes.Add(code, &zone);
+ if (!code->marked_for_deoptimization()) {
+ code->set_marked_for_deoptimization(true);
+ marked = true;
+ }
} else {
CompilationInfo* info = compilation_info_at(i);
info->AbortDueToDependencyChange();
@@ -11372,7 +11434,8 @@
clear_at(i);
}
set_number_of_entries(group, 0);
- Deoptimizer::DeoptimizeCodeList(isolate, &codes);
+
+ if (marked) Deoptimizer::DeoptimizeMarkedCode(isolate);
}
@@ -12205,7 +12268,7 @@
if (old_attributes != ABSENT) {
if (self->GetLocalElementAccessorPair(index) == NULL)
- old_value = Object::GetElement(self, index);
+ old_value = Object::GetElement(isolate, self, index);
} else if (self->IsJSArray()) {
// Store old array length in case adding an element grows the array.
old_length_handle = handle(Handle<JSArray>::cast(self)->length(), isolate);
@@ -12247,7 +12310,7 @@
} else if (old_value->IsTheHole()) {
EnqueueChangeRecord(self, "reconfigured", name, old_value);
} else {
- Handle<Object> new_value = Object::GetElement(self, index);
+ Handle<Object> new_value = Object::GetElement(isolate, self, index);
bool value_changed = !old_value->SameValue(*new_value);
if (old_attributes != new_attributes) {
if (!value_changed) old_value = isolate->factory()->the_hole_value();
@@ -12575,7 +12638,7 @@
Object* pt = holder_handle->GetPrototype();
if (pt == heap->null_value()) return heap->undefined_value();
- return pt->GetElementWithReceiver(*this_handle, index);
+ return pt->GetElementWithReceiver(isolate, *this_handle, index);
}
@@ -15220,7 +15283,7 @@
// Allocate the instance descriptor.
DescriptorArray* descriptors;
MaybeObject* maybe_descriptors =
- DescriptorArray::Allocate(instance_descriptor_length);
+ DescriptorArray::Allocate(GetIsolate(), instance_descriptor_length);
if (!maybe_descriptors->To(&descriptors)) {
return maybe_descriptors;
}
@@ -15513,7 +15576,7 @@
int code_position,
Handle<Object> break_point_object) {
Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position),
- Isolate::Current());
+ debug_info->GetIsolate());
if (break_point_info->IsUndefined()) return;
BreakPointInfo::ClearBreakPoint(
Handle<BreakPointInfo>::cast(break_point_info),
@@ -15526,7 +15589,7 @@
int source_position,
int statement_position,
Handle<Object> break_point_object) {
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = debug_info->GetIsolate();
Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position),
isolate);
if (!break_point_info->IsUndefined()) {
@@ -15640,7 +15703,7 @@
// Remove the specified break point object.
void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
Handle<Object> break_point_object) {
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = break_point_info->GetIsolate();
// If there are no break points just ignore.
if (break_point_info->break_point_objects()->IsUndefined()) return;
// If there is a single break point clear it if it is the same.
diff --git a/src/objects.h b/src/objects.h
index e4017ef..f001feb 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -1436,8 +1436,8 @@
inline bool HasSpecificClassOf(String* name);
- MUST_USE_RESULT MaybeObject* ToObject(); // ECMA-262 9.9.
- bool BooleanValue(); // ECMA-262 9.2.
+ MUST_USE_RESULT MaybeObject* ToObject(Isolate* isolate); // ECMA-262 9.9.
+ bool BooleanValue(); // ECMA-262 9.2.
// Convert to a JSObject if needed.
// native_context is used when creating wrapper object.
@@ -1459,7 +1459,8 @@
Name* key,
PropertyAttributes* attributes);
- static Handle<Object> GetProperty(Handle<Object> object, Handle<Name> key);
+ static Handle<Object> GetProperty(Handle<Object> object,
+ Handle<Name> key);
static Handle<Object> GetProperty(Handle<Object> object,
Handle<Object> receiver,
LookupResult* result,
@@ -1481,11 +1482,15 @@
MUST_USE_RESULT MaybeObject* GetPropertyWithDefinedGetter(Object* receiver,
JSReceiver* getter);
- static Handle<Object> GetElement(Handle<Object> object, uint32_t index);
- MUST_USE_RESULT inline MaybeObject* GetElement(uint32_t index);
+ static Handle<Object> GetElement(Isolate* isolate,
+ Handle<Object> object,
+ uint32_t index);
+ MUST_USE_RESULT inline MaybeObject* GetElement(Isolate* isolate,
+ uint32_t index);
// For use when we know that no exception can be thrown.
- inline Object* GetElementNoExceptionThrown(uint32_t index);
- MUST_USE_RESULT MaybeObject* GetElementWithReceiver(Object* receiver,
+ inline Object* GetElementNoExceptionThrown(Isolate* isolate, uint32_t index);
+ MUST_USE_RESULT MaybeObject* GetElementWithReceiver(Isolate* isolate,
+ Object* receiver,
uint32_t index);
// Return the object's prototype (might be Heap::null_value()).
@@ -3181,7 +3186,8 @@
// Allocates a DescriptorArray, but returns the singleton
// empty descriptor array object if number_of_descriptors is 0.
- MUST_USE_RESULT static MaybeObject* Allocate(int number_of_descriptors,
+ MUST_USE_RESULT static MaybeObject* Allocate(Isolate* isolate,
+ int number_of_descriptors,
int slack = 0);
// Casting.
@@ -4807,21 +4813,19 @@
// [deoptimization_data]: Array containing data for deopt.
DECL_ACCESSORS(deoptimization_data, FixedArray)
- // [type_feedback_info]: Struct containing type feedback information for
- // unoptimized code. Optimized code can temporarily store the head of
- // the list of code to be deoptimized during mark-compact GC.
- // STUBs can use this slot to store arbitrary information as a Smi.
- // Will contain either a TypeFeedbackInfo object, or JSFunction object,
- // or undefined, or a Smi.
+ // [type_feedback_info]: This field stores various things, depending on the
+ // kind of the code object.
+ // FUNCTION => type feedback information.
+ // STUB => various things, e.g. a SMI
+ // OPTIMIZED_FUNCTION => the next_code_link for optimized code list.
DECL_ACCESSORS(type_feedback_info, Object)
inline void InitializeTypeFeedbackInfoNoWriteBarrier(Object* value);
inline int stub_info();
inline void set_stub_info(int info);
- // Used during GC to code a list of code objects to deoptimize.
- inline Object* code_to_deoptimize_link();
- inline void set_code_to_deoptimize_link(Object* value);
- inline Object** code_to_deoptimize_link_slot();
+ // [next_code_link]: Link for lists of optimized or deoptimized code.
+ // Note that storage for this field is overlapped with typefeedback_info.
+ DECL_ACCESSORS(next_code_link, Object)
// [gc_metadata]: Field used to hold GC related metadata. The contents of this
// field does not have to be traced during garbage collection since
@@ -5101,6 +5105,8 @@
void ClearInlineCaches();
void ClearTypeFeedbackCells(Heap* heap);
+ BailoutId TranslatePcOffsetToAstId(uint32_t pc_offset);
+
#define DECLARE_CODE_AGE_ENUM(X) k##X##CodeAge,
enum Age {
kNoAge = 0,
@@ -5140,6 +5146,7 @@
kHandlerTableOffset + kPointerSize;
static const int kTypeFeedbackInfoOffset =
kDeoptimizationDataOffset + kPointerSize;
+ static const int kNextCodeLinkOffset = kTypeFeedbackInfoOffset; // Shared.
static const int kGCMetadataOffset = kTypeFeedbackInfoOffset + kPointerSize;
static const int kICAgeOffset =
kGCMetadataOffset + kPointerSize;
@@ -7013,8 +7020,10 @@
// Returns if this function has been compiled to native code yet.
inline bool is_compiled();
- // [next_function_link]: Field for linking functions. This list is treated as
- // a weak list by the GC.
+ // [next_function_link]: Links functions into various lists, e.g. the list
+ // of optimized functions hanging off the native_context. The CodeFlusher
+ // uses this link to chain together flushing candidates. Treated weakly
+ // by the garbage collector.
DECL_ACCESSORS(next_function_link, Object)
// Prints the name of the function using PrintF.
@@ -8719,13 +8728,14 @@
virtual void IterateInstance(ObjectVisitor* v) { }
virtual void PostGarbageCollection() { }
- static void PostGarbageCollectionProcessing();
+ static void PostGarbageCollectionProcessing(Isolate* isolate);
static int ArchiveSpacePerThread();
static char* ArchiveState(Isolate* isolate, char* to);
static char* RestoreState(Isolate* isolate, char* from);
- static void Iterate(ObjectVisitor* v);
+ static void Iterate(Isolate* isolate, ObjectVisitor* v);
static void Iterate(ObjectVisitor* v, Relocatable* top);
static char* Iterate(ObjectVisitor* v, char* t);
+
private:
Isolate* isolate_;
Relocatable* prev_;
@@ -8861,7 +8871,8 @@
DECLARE_VERIFIER(Oddball)
// Initialize the fields.
- MUST_USE_RESULT MaybeObject* Initialize(const char* to_string,
+ MUST_USE_RESULT MaybeObject* Initialize(Heap* heap,
+ const char* to_string,
Object* to_number,
byte kind);
@@ -9484,6 +9495,11 @@
// Dispatched behavior.
DECLARE_VERIFIER(AccessorInfo)
+ // Append all descriptors to the array that are not already there.
+ // Return number added.
+ static int AppendUnique(Handle<Object> descriptors,
+ Handle<FixedArray> array,
+ int valid_descriptors);
static const int kNameOffset = HeapObject::kHeaderSize;
static const int kFlagOffset = kNameOffset + kPointerSize;
@@ -9790,12 +9806,15 @@
public:
DECL_ACCESSORS(tag, Object)
DECL_ACCESSORS(property_list, Object)
+ DECL_ACCESSORS(property_accessors, Object)
DECLARE_VERIFIER(TemplateInfo)
- static const int kTagOffset = HeapObject::kHeaderSize;
+ static const int kTagOffset = HeapObject::kHeaderSize;
static const int kPropertyListOffset = kTagOffset + kPointerSize;
- static const int kHeaderSize = kPropertyListOffset + kPointerSize;
+ static const int kPropertyAccessorsOffset =
+ kPropertyListOffset + kPointerSize;
+ static const int kHeaderSize = kPropertyAccessorsOffset + kPointerSize;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(TemplateInfo);
@@ -9806,7 +9825,6 @@
public:
DECL_ACCESSORS(serial_number, Object)
DECL_ACCESSORS(call_code, Object)
- DECL_ACCESSORS(property_accessors, Object)
DECL_ACCESSORS(prototype_template, Object)
DECL_ACCESSORS(parent_template, Object)
DECL_ACCESSORS(named_property_handler, Object)
@@ -9838,9 +9856,8 @@
static const int kSerialNumberOffset = TemplateInfo::kHeaderSize;
static const int kCallCodeOffset = kSerialNumberOffset + kPointerSize;
- static const int kPropertyAccessorsOffset = kCallCodeOffset + kPointerSize;
static const int kPrototypeTemplateOffset =
- kPropertyAccessorsOffset + kPointerSize;
+ kCallCodeOffset + kPointerSize;
static const int kParentTemplateOffset =
kPrototypeTemplateOffset + kPointerSize;
static const int kNamedPropertyHandlerOffset =
diff --git a/src/optimizing-compiler-thread.cc b/src/optimizing-compiler-thread.cc
index 96847dc..b0e37fd 100644
--- a/src/optimizing-compiler-thread.cc
+++ b/src/optimizing-compiler-thread.cc
@@ -108,12 +108,18 @@
// The function may have already been optimized by OSR. Simply continue.
// Use a mutex to make sure that functions marked for install
// are always also queued.
- LockGuard<Mutex> mark_and_queue(&install_mutex_);
- { Heap::RelocationLock relocation_lock(isolate_->heap());
+ if (!optimizing_compiler->info()->osr_ast_id().IsNone()) {
+ ASSERT(FLAG_concurrent_osr);
+ LockGuard<Mutex> access_osr_lists(&osr_list_mutex_);
+ osr_candidates_.RemoveElement(optimizing_compiler);
+ ready_for_osr_.Add(optimizing_compiler);
+ } else {
+ LockGuard<Mutex> mark_and_queue(&install_mutex_);
+ Heap::RelocationLock relocation_lock(isolate_->heap());
AllowHandleDereference ahd;
optimizing_compiler->info()->closure()->MarkForInstallingRecompiledCode();
+ output_queue_.Enqueue(optimizing_compiler);
}
- output_queue_.Enqueue(optimizing_compiler);
}
@@ -145,6 +151,9 @@
}
delete info;
}
+
+ osr_candidates_.Clear();
+ RemoveStaleOSRCandidates(0);
}
@@ -179,6 +188,10 @@
PrintF(" ** Compiler thread did %.2f%% useful work\n", percentage);
}
+ if (FLAG_trace_osr && FLAG_concurrent_osr) {
+ PrintF("[COSR hit rate %d / %d]\n", osr_hits_, osr_attempts_);
+ }
+
Join();
}
@@ -194,6 +207,10 @@
}
Compiler::InstallOptimizedCode(compiler);
}
+
+ // Remove the oldest OSR candidates that are ready so that we
+ // only have limited number of them waiting.
+ if (FLAG_concurrent_osr) RemoveStaleOSRCandidates();
}
@@ -202,12 +219,62 @@
ASSERT(IsQueueAvailable());
ASSERT(!IsOptimizerThread());
Barrier_AtomicIncrement(&queue_length_, static_cast<Atomic32>(1));
- optimizing_compiler->info()->closure()->MarkInRecompileQueue();
+ if (optimizing_compiler->info()->osr_ast_id().IsNone()) {
+ optimizing_compiler->info()->closure()->MarkInRecompileQueue();
+ } else {
+ LockGuard<Mutex> access_osr_lists(&osr_list_mutex_);
+ osr_candidates_.Add(optimizing_compiler);
+ osr_attempts_++;
+ }
input_queue_.Enqueue(optimizing_compiler);
input_queue_semaphore_.Signal();
}
+OptimizingCompiler* OptimizingCompilerThread::FindReadyOSRCandidate(
+ Handle<JSFunction> function, uint32_t osr_pc_offset) {
+ ASSERT(!IsOptimizerThread());
+ LockGuard<Mutex> access_osr_lists(&osr_list_mutex_);
+ for (int i = 0; i < ready_for_osr_.length(); i++) {
+ if (ready_for_osr_[i]->info()->HasSameOsrEntry(function, osr_pc_offset)) {
+ osr_hits_++;
+ return ready_for_osr_.Remove(i);
+ }
+ }
+ return NULL;
+}
+
+
+bool OptimizingCompilerThread::IsQueuedForOSR(Handle<JSFunction> function,
+ uint32_t osr_pc_offset) {
+ ASSERT(!IsOptimizerThread());
+ LockGuard<Mutex> access_osr_lists(&osr_list_mutex_);
+ for (int i = 0; i < osr_candidates_.length(); i++) {
+ if (osr_candidates_[i]->info()->HasSameOsrEntry(function, osr_pc_offset)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+void OptimizingCompilerThread::RemoveStaleOSRCandidates(int limit) {
+ ASSERT(!IsOptimizerThread());
+ LockGuard<Mutex> access_osr_lists(&osr_list_mutex_);
+ while (ready_for_osr_.length() > limit) {
+ OptimizingCompiler* compiler = ready_for_osr_.Remove(0);
+ CompilationInfo* throw_away = compiler->info();
+ if (FLAG_trace_osr) {
+ PrintF("[COSR - Discarded ");
+ throw_away->closure()->PrintName();
+ PrintF(", AST id %d]\n",
+ throw_away->osr_ast_id().ToInt());
+ }
+ delete throw_away;
+ }
+}
+
+
#ifdef DEBUG
bool OptimizingCompilerThread::IsOptimizerThread() {
if (!FLAG_concurrent_recompilation) return false;
diff --git a/src/optimizing-compiler-thread.h b/src/optimizing-compiler-thread.h
index bb96c74..01cd2a0 100644
--- a/src/optimizing-compiler-thread.h
+++ b/src/optimizing-compiler-thread.h
@@ -30,6 +30,7 @@
#include "atomicops.h"
#include "flags.h"
+#include "list.h"
#include "platform.h"
#include "platform/mutex.h"
#include "platform/time.h"
@@ -51,7 +52,11 @@
#endif
isolate_(isolate),
stop_semaphore_(0),
- input_queue_semaphore_(0) {
+ input_queue_semaphore_(0),
+ osr_candidates_(2),
+ ready_for_osr_(2),
+ osr_hits_(0),
+ osr_attempts_(0) {
NoBarrier_Store(&stop_thread_, static_cast<AtomicWord>(CONTINUE));
NoBarrier_Store(&queue_length_, static_cast<AtomicWord>(0));
}
@@ -62,6 +67,13 @@
void Flush();
void QueueForOptimization(OptimizingCompiler* optimizing_compiler);
void InstallOptimizedFunctions();
+ OptimizingCompiler* FindReadyOSRCandidate(Handle<JSFunction> function,
+ uint32_t osr_pc_offset);
+ bool IsQueuedForOSR(Handle<JSFunction> function, uint32_t osr_pc_offset);
+
+ // Remove the oldest OSR candidates that are ready so that we
+ // only have |limit| left waiting.
+ void RemoveStaleOSRCandidates(int limit = kReadyForOSRLimit);
inline bool IsQueueAvailable() {
// We don't need a barrier since we have a data dependency right
@@ -86,7 +98,6 @@
void FlushInputQueue(bool restore_function_code);
void FlushOutputQueue(bool restore_function_code);
-
void CompileNext();
#ifdef DEBUG
@@ -97,13 +108,27 @@
Isolate* isolate_;
Semaphore stop_semaphore_;
Semaphore input_queue_semaphore_;
+
+ // Queue of incoming recompilation tasks (including OSR).
UnboundQueue<OptimizingCompiler*> input_queue_;
+ // Queue of recompilation tasks ready to be installed (excluding OSR).
UnboundQueue<OptimizingCompiler*> output_queue_;
+ // List of all OSR related recompilation tasks (both incoming and ready ones).
+ List<OptimizingCompiler*> osr_candidates_;
+ // List of recompilation tasks ready for OSR.
+ List<OptimizingCompiler*> ready_for_osr_;
+
Mutex install_mutex_;
volatile AtomicWord stop_thread_;
volatile Atomic32 queue_length_;
TimeDelta time_spent_compiling_;
TimeDelta time_spent_total_;
+
+ Mutex osr_list_mutex_;
+ int osr_hits_;
+ int osr_attempts_;
+
+ static const int kReadyForOSRLimit = 4;
};
} } // namespace v8::internal
diff --git a/src/parser.cc b/src/parser.cc
index e4a6bb2..257f80d 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -3744,8 +3744,9 @@
}
-Handle<FixedArray> CompileTimeValue::GetValue(Expression* expression) {
- Factory* factory = Isolate::Current()->factory();
+Handle<FixedArray> CompileTimeValue::GetValue(Isolate* isolate,
+ Expression* expression) {
+ Factory* factory = isolate->factory();
ASSERT(IsCompileTimeValue(expression));
Handle<FixedArray> result = factory->NewFixedArray(2, TENURED);
ObjectLiteral* object_literal = expression->AsObjectLiteral();
@@ -3784,7 +3785,7 @@
return expression->AsLiteral()->value();
}
if (CompileTimeValue::IsCompileTimeValue(expression)) {
- return CompileTimeValue::GetValue(expression);
+ return CompileTimeValue::GetValue(isolate(), expression);
}
return isolate()->factory()->uninitialized_value();
}
@@ -5023,7 +5024,7 @@
Handle<String>* error,
bool multiline,
Zone* zone)
- : isolate_(Isolate::Current()),
+ : isolate_(zone->isolate()),
zone_(zone),
error_(error),
captures_(NULL),
@@ -5895,9 +5896,9 @@
// Create a Scanner for the preparser to use as input, and preparse the source.
-ScriptDataImpl* PreParserApi::PreParse(Utf16CharacterStream* source) {
+ScriptDataImpl* PreParserApi::PreParse(Isolate* isolate,
+ Utf16CharacterStream* source) {
CompleteParserRecorder recorder;
- Isolate* isolate = Isolate::Current();
HistogramTimerScope timer(isolate->counters()->pre_parse());
Scanner scanner(isolate->unicode_cache());
intptr_t stack_limit = isolate->stack_guard()->real_climit();
diff --git a/src/parser.h b/src/parser.h
index 2f26b84..783626a 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -170,7 +170,8 @@
// This interface is here instead of in preparser.h because it instantiates a
// preparser recorder object that is suited to the parser's purposes. Also,
// the preparser doesn't know about ScriptDataImpl.
- static ScriptDataImpl* PreParse(Utf16CharacterStream* source);
+ static ScriptDataImpl* PreParse(Isolate* isolate,
+ Utf16CharacterStream* source);
};
@@ -894,7 +895,7 @@
static bool IsCompileTimeValue(Expression* expression);
// Get the value as a compile time value.
- static Handle<FixedArray> GetValue(Expression* expression);
+ static Handle<FixedArray> GetValue(Isolate* isolate, Expression* expression);
// Get the type of a compile time value returned by GetValue().
static LiteralType GetLiteralType(Handle<FixedArray> value);
diff --git a/src/platform-posix.cc b/src/platform-posix.cc
index aaf0ca7..504d140 100644
--- a/src/platform-posix.cc
+++ b/src/platform-posix.cc
@@ -739,202 +739,4 @@
}
-// ----------------------------------------------------------------------------
-// POSIX socket support.
-//
-
-class POSIXSocket : public Socket {
- public:
- explicit POSIXSocket() {
- // Create the socket.
- socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (IsValid()) {
- // Allow rapid reuse.
- static const int kOn = 1;
- int ret = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR,
- &kOn, sizeof(kOn));
- ASSERT(ret == 0);
- USE(ret);
- }
- }
- explicit POSIXSocket(int socket): socket_(socket) { }
- virtual ~POSIXSocket() { Shutdown(); }
-
- // Server initialization.
- bool Bind(const int port);
- bool Listen(int backlog) const;
- Socket* Accept() const;
-
- // Client initialization.
- bool Connect(const char* host, const char* port);
-
- // Shutdown socket for both read and write.
- bool Shutdown();
-
- // Data Transimission
- int Send(const char* data, int len) const;
- int Receive(char* data, int len) const;
-
- bool SetReuseAddress(bool reuse_address);
-
- bool IsValid() const { return socket_ != -1; }
-
- private:
- int socket_;
-};
-
-
-bool POSIXSocket::Bind(const int port) {
- if (!IsValid()) {
- return false;
- }
-
- sockaddr_in addr;
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- addr.sin_port = htons(port);
- int status = bind(socket_,
- BitCast<struct sockaddr *>(&addr),
- sizeof(addr));
- return status == 0;
-}
-
-
-bool POSIXSocket::Listen(int backlog) const {
- if (!IsValid()) {
- return false;
- }
-
- int status = listen(socket_, backlog);
- return status == 0;
-}
-
-
-Socket* POSIXSocket::Accept() const {
- if (!IsValid()) {
- return NULL;
- }
-
- int socket;
- do {
- socket = accept(socket_, NULL, NULL);
- } while (socket == -1 && errno == EINTR);
-
- if (socket == -1) {
- return NULL;
- } else {
- return new POSIXSocket(socket);
- }
-}
-
-
-bool POSIXSocket::Connect(const char* host, const char* port) {
- if (!IsValid()) {
- return false;
- }
-
- // Lookup host and port.
- struct addrinfo *result = NULL;
- struct addrinfo hints;
- memset(&hints, 0, sizeof(addrinfo));
- hints.ai_family = AF_INET;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_protocol = IPPROTO_TCP;
- int status = getaddrinfo(host, port, &hints, &result);
- if (status != 0) {
- return false;
- }
-
- // Connect.
- do {
- status = connect(socket_, result->ai_addr, result->ai_addrlen);
- } while (status == -1 && errno == EINTR);
- freeaddrinfo(result);
- return status == 0;
-}
-
-
-bool POSIXSocket::Shutdown() {
- if (IsValid()) {
- // Shutdown socket for both read and write.
- int status = shutdown(socket_, SHUT_RDWR);
- close(socket_);
- socket_ = -1;
- return status == 0;
- }
- return true;
-}
-
-
-int POSIXSocket::Send(const char* data, int len) const {
- if (len <= 0) return 0;
- int written = 0;
- while (written < len) {
- int status = send(socket_, data + written, len - written, 0);
- if (status == 0) {
- break;
- } else if (status > 0) {
- written += status;
- } else if (errno != EINTR) {
- return 0;
- }
- }
- return written;
-}
-
-
-int POSIXSocket::Receive(char* data, int len) const {
- if (len <= 0) return 0;
- int status;
- do {
- status = recv(socket_, data, len, 0);
- } while (status == -1 && errno == EINTR);
- return (status < 0) ? 0 : status;
-}
-
-
-bool POSIXSocket::SetReuseAddress(bool reuse_address) {
- int on = reuse_address ? 1 : 0;
- int status = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
- return status == 0;
-}
-
-
-bool Socket::SetUp() {
- // Nothing to do on POSIX.
- return true;
-}
-
-
-int Socket::LastError() {
- return errno;
-}
-
-
-uint16_t Socket::HToN(uint16_t value) {
- return htons(value);
-}
-
-
-uint16_t Socket::NToH(uint16_t value) {
- return ntohs(value);
-}
-
-
-uint32_t Socket::HToN(uint32_t value) {
- return htonl(value);
-}
-
-
-uint32_t Socket::NToH(uint32_t value) {
- return ntohl(value);
-}
-
-
-Socket* OS::CreateSocket() {
- return new POSIXSocket();
-}
-
-
} } // namespace v8::internal
diff --git a/src/platform-win32.cc b/src/platform-win32.cc
index 199ed2d..87387e7 100644
--- a/src/platform-win32.cc
+++ b/src/platform-win32.cc
@@ -1615,198 +1615,6 @@
}
-// ----------------------------------------------------------------------------
-// Win32 socket support.
-//
-
-class Win32Socket : public Socket {
- public:
- explicit Win32Socket() {
- // Create the socket.
- socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- }
- explicit Win32Socket(SOCKET socket): socket_(socket) { }
- virtual ~Win32Socket() { Shutdown(); }
-
- // Server initialization.
- bool Bind(const int port);
- bool Listen(int backlog) const;
- Socket* Accept() const;
-
- // Client initialization.
- bool Connect(const char* host, const char* port);
-
- // Shutdown socket for both read and write.
- bool Shutdown();
-
- // Data Transimission
- int Send(const char* data, int len) const;
- int Receive(char* data, int len) const;
-
- bool SetReuseAddress(bool reuse_address);
-
- bool IsValid() const { return socket_ != INVALID_SOCKET; }
-
- private:
- SOCKET socket_;
-};
-
-
-bool Win32Socket::Bind(const int port) {
- if (!IsValid()) {
- return false;
- }
-
- sockaddr_in addr;
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- addr.sin_port = htons(port);
- int status = bind(socket_,
- reinterpret_cast<struct sockaddr *>(&addr),
- sizeof(addr));
- return status == 0;
-}
-
-
-bool Win32Socket::Listen(int backlog) const {
- if (!IsValid()) {
- return false;
- }
-
- int status = listen(socket_, backlog);
- return status == 0;
-}
-
-
-Socket* Win32Socket::Accept() const {
- if (!IsValid()) {
- return NULL;
- }
-
- SOCKET socket = accept(socket_, NULL, NULL);
- if (socket == INVALID_SOCKET) {
- return NULL;
- } else {
- return new Win32Socket(socket);
- }
-}
-
-
-bool Win32Socket::Connect(const char* host, const char* port) {
- if (!IsValid()) {
- return false;
- }
-
- // Lookup host and port.
- struct addrinfo *result = NULL;
- struct addrinfo hints;
- memset(&hints, 0, sizeof(addrinfo));
- hints.ai_family = AF_INET;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_protocol = IPPROTO_TCP;
- int status = getaddrinfo(host, port, &hints, &result);
- if (status != 0) {
- return false;
- }
-
- // Connect.
- status = connect(socket_,
- result->ai_addr,
- static_cast<int>(result->ai_addrlen));
- freeaddrinfo(result);
- return status == 0;
-}
-
-
-bool Win32Socket::Shutdown() {
- if (IsValid()) {
- // Shutdown socket for both read and write.
- int status = shutdown(socket_, SD_BOTH);
- closesocket(socket_);
- socket_ = INVALID_SOCKET;
- return status == SOCKET_ERROR;
- }
- return true;
-}
-
-
-int Win32Socket::Send(const char* data, int len) const {
- if (len <= 0) return 0;
- int written = 0;
- while (written < len) {
- int status = send(socket_, data + written, len - written, 0);
- if (status == 0) {
- break;
- } else if (status > 0) {
- written += status;
- } else {
- return 0;
- }
- }
- return written;
-}
-
-
-int Win32Socket::Receive(char* data, int len) const {
- if (len <= 0) return 0;
- int status = recv(socket_, data, len, 0);
- return (status == SOCKET_ERROR) ? 0 : status;
-}
-
-
-bool Win32Socket::SetReuseAddress(bool reuse_address) {
- BOOL on = reuse_address ? true : false;
- int status = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR,
- reinterpret_cast<char*>(&on), sizeof(on));
- return status == SOCKET_ERROR;
-}
-
-
-bool Socket::SetUp() {
- // Initialize Winsock32
- int err;
- WSADATA winsock_data;
- WORD version_requested = MAKEWORD(1, 0);
- err = WSAStartup(version_requested, &winsock_data);
- if (err != 0) {
- PrintF("Unable to initialize Winsock, err = %d\n", Socket::LastError());
- }
-
- return err == 0;
-}
-
-
-int Socket::LastError() {
- return WSAGetLastError();
-}
-
-
-uint16_t Socket::HToN(uint16_t value) {
- return htons(value);
-}
-
-
-uint16_t Socket::NToH(uint16_t value) {
- return ntohs(value);
-}
-
-
-uint32_t Socket::HToN(uint32_t value) {
- return htonl(value);
-}
-
-
-uint32_t Socket::NToH(uint32_t value) {
- return ntohl(value);
-}
-
-
-Socket* OS::CreateSocket() {
- return new Win32Socket();
-}
-
-
void OS::SetUp() {
// Seed the random number generator.
// Convert the current time to a 64-bit integer first, before converting it
diff --git a/src/platform.h b/src/platform.h
index 8565775..18bf6b0 100644
--- a/src/platform.h
+++ b/src/platform.h
@@ -108,9 +108,6 @@
// on demand.
void lazily_initialize_fast_exp();
-// Forward declarations.
-class Socket;
-
// ----------------------------------------------------------------------------
// Fast TLS support
@@ -287,10 +284,6 @@
static int StackWalk(Vector<StackFrame> frames);
- // Factory method for creating platform dependent Socket.
- // Please use delete to reclaim the storage for the returned Socket.
- static Socket* CreateSocket();
-
class MemoryMappedFile {
public:
static MemoryMappedFile* open(const char* name);
@@ -619,47 +612,6 @@
DISALLOW_COPY_AND_ASSIGN(Thread);
};
-
-// ----------------------------------------------------------------------------
-// Socket
-//
-
-class Socket {
- public:
- virtual ~Socket() {}
-
- // Server initialization.
- virtual bool Bind(const int port) = 0;
- virtual bool Listen(int backlog) const = 0;
- virtual Socket* Accept() const = 0;
-
- // Client initialization.
- virtual bool Connect(const char* host, const char* port) = 0;
-
- // Shutdown socket for both read and write. This causes blocking Send and
- // Receive calls to exit. After Shutdown the Socket object cannot be used for
- // any communication.
- virtual bool Shutdown() = 0;
-
- // Data Transimission
- // Return 0 on failure.
- virtual int Send(const char* data, int len) const = 0;
- virtual int Receive(char* data, int len) const = 0;
-
- // Set the value of the SO_REUSEADDR socket option.
- virtual bool SetReuseAddress(bool reuse_address) = 0;
-
- virtual bool IsValid() const = 0;
-
- static bool SetUp();
- static int LastError();
- static uint16_t HToN(uint16_t value);
- static uint16_t NToH(uint16_t value);
- static uint32_t HToN(uint32_t value);
- static uint32_t NToH(uint32_t value);
-};
-
-
} } // namespace v8::internal
#endif // V8_PLATFORM_H_
diff --git a/src/platform/condition-variable.cc b/src/platform/condition-variable.cc
index 84df976..e2bf388 100644
--- a/src/platform/condition-variable.cc
+++ b/src/platform/condition-variable.cc
@@ -41,8 +41,8 @@
// TODO(bmeurer): The test for V8_LIBRT_NOT_AVAILABLE is a temporary
// hack to support cross-compiling Chrome for Android in AOSP. Remove
// this once AOSP is fixed.
-#if (V8_OS_FREEBSD || V8_OS_NETBSD || V8_OS_OPENBSD || V8_LIBC_GLIBC) && \
- !V8_LIBRT_NOT_AVAILABLE
+#if (V8_OS_FREEBSD || V8_OS_NETBSD || V8_OS_OPENBSD || \
+ (V8_OS_LINUX && V8_LIBC_GLIBC)) && !V8_LIBRT_NOT_AVAILABLE
// On Free/Net/OpenBSD and Linux with glibc we can change the time
// source for pthread_cond_timedwait() to use the monotonic clock.
pthread_condattr_t attr;
@@ -107,8 +107,8 @@
// TODO(bmeurer): The test for V8_LIBRT_NOT_AVAILABLE is a temporary
// hack to support cross-compiling Chrome for Android in AOSP. Remove
// this once AOSP is fixed.
-#if (V8_OS_FREEBSD || V8_OS_NETBSD || V8_OS_OPENBSD || V8_LIBC_GLIBC) && \
- !V8_LIBRT_NOT_AVAILABLE
+#if (V8_OS_FREEBSD || V8_OS_NETBSD || V8_OS_OPENBSD || \
+ (V8_OS_LINUX && V8_LIBC_GLIBC)) && !V8_LIBRT_NOT_AVAILABLE
// On Free/Net/OpenBSD and Linux with glibc we can change the time
// source for pthread_cond_timedwait() to use the monotonic clock.
result = clock_gettime(CLOCK_MONOTONIC, &ts);
diff --git a/src/platform/mutex.h b/src/platform/mutex.h
index c760c20..ff519b9 100644
--- a/src/platform/mutex.h
+++ b/src/platform/mutex.h
@@ -230,8 +230,7 @@
private:
Mutex* mutex_;
- LockGuard(const LockGuard<Mutex>& other) V8_DELETE;
- LockGuard<Mutex>& operator=(const LockGuard<Mutex>& other) V8_DELETE;
+ DISALLOW_COPY_AND_ASSIGN(LockGuard);
};
} } // namespace v8::internal
diff --git a/src/platform/socket.cc b/src/platform/socket.cc
new file mode 100644
index 0000000..2fce6f2
--- /dev/null
+++ b/src/platform/socket.cc
@@ -0,0 +1,224 @@
+// Copyright 2013 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:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "platform/socket.h"
+
+#if V8_OS_POSIX
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include <unistd.h>
+#endif
+
+#include <cerrno>
+
+#include "checks.h"
+#include "once.h"
+
+namespace v8 {
+namespace internal {
+
+#if V8_OS_WIN
+
+static V8_DECLARE_ONCE(initialize_winsock) = V8_ONCE_INIT;
+
+
+static void InitializeWinsock() {
+ WSADATA wsa_data;
+ int result = WSAStartup(MAKEWORD(1, 0), &wsa_data);
+ CHECK_EQ(0, result);
+}
+
+#endif // V8_OS_WIN
+
+
+Socket::Socket() {
+#if V8_OS_WIN
+ // Be sure to initialize the WinSock DLL first.
+ CallOnce(&initialize_winsock, &InitializeWinsock);
+#endif // V8_OS_WIN
+
+ // Create the native socket handle.
+ native_handle_ = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+}
+
+
+bool Socket::Bind(int port) {
+ ASSERT_GE(port, 0);
+ ASSERT_LT(port, 65536);
+ if (!IsValid()) return false;
+ struct sockaddr_in sin;
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ sin.sin_port = htons(static_cast<uint16_t>(port));
+ int result = ::bind(
+ native_handle_, reinterpret_cast<struct sockaddr*>(&sin), sizeof(sin));
+ return result == 0;
+}
+
+
+bool Socket::Listen(int backlog) {
+ if (!IsValid()) return false;
+ int result = ::listen(native_handle_, backlog);
+ return result == 0;
+}
+
+
+Socket* Socket::Accept() {
+ if (!IsValid()) return NULL;
+ while (true) {
+ NativeHandle native_handle = ::accept(native_handle_, NULL, NULL);
+ if (native_handle == kInvalidNativeHandle) {
+#if V8_OS_POSIX
+ if (errno == EINTR) continue; // Retry after signal.
+#endif
+ return NULL;
+ }
+ return new Socket(native_handle);
+ }
+}
+
+
+bool Socket::Connect(const char* host, const char* port) {
+ ASSERT_NE(NULL, host);
+ ASSERT_NE(NULL, port);
+ if (!IsValid()) return false;
+
+ // Lookup host and port.
+ struct addrinfo* info = NULL;
+ struct addrinfo hint;
+ memset(&hint, 0, sizeof(hint));
+ hint.ai_family = AF_INET;
+ hint.ai_socktype = SOCK_STREAM;
+ hint.ai_protocol = IPPROTO_TCP;
+ int result = ::getaddrinfo(host, port, &hint, &info);
+ if (result != 0) {
+ return false;
+ }
+
+ // Connect to the host on the given port.
+ for (struct addrinfo* ai = info; ai != NULL; ai = ai->ai_next) {
+ // Try to connect using this addr info.
+ while (true) {
+ result = ::connect(
+ native_handle_, ai->ai_addr, static_cast<int>(ai->ai_addrlen));
+ if (result == 0) {
+ freeaddrinfo(info);
+ return true;
+ }
+#if V8_OS_POSIX
+ if (errno == EINTR) continue; // Retry after signal.
+#endif
+ break;
+ }
+ }
+ freeaddrinfo(info);
+ return false;
+}
+
+
+bool Socket::Shutdown() {
+ if (!IsValid()) return false;
+ // Shutdown socket for both read and write.
+#if V8_OS_POSIX
+ int result = ::shutdown(native_handle_, SHUT_RDWR);
+ ::close(native_handle_);
+#elif V8_OS_WIN
+ int result = ::shutdown(native_handle_, SD_BOTH);
+ ::closesocket(native_handle_);
+#endif
+ native_handle_ = kInvalidNativeHandle;
+ return result == 0;
+}
+
+
+int Socket::Send(const char* buffer, int length) {
+ ASSERT(length <= 0 || buffer != NULL);
+ if (!IsValid()) return 0;
+ int offset = 0;
+ while (offset < length) {
+ int result = ::send(native_handle_, buffer + offset, length - offset, 0);
+ if (result == 0) {
+ break;
+ } else if (result > 0) {
+ ASSERT(result <= length - offset);
+ offset += result;
+ } else {
+#if V8_OS_POSIX
+ if (errno == EINTR) continue; // Retry after signal.
+#endif
+ return 0;
+ }
+ }
+ return offset;
+}
+
+
+int Socket::Receive(char* buffer, int length) {
+ if (!IsValid()) return 0;
+ if (length <= 0) return 0;
+ ASSERT_NE(NULL, buffer);
+ while (true) {
+ int result = ::recv(native_handle_, buffer, length, 0);
+ if (result < 0) {
+#if V8_OS_POSIX
+ if (errno == EINTR) continue; // Retry after signal.
+#endif
+ return 0;
+ }
+ return result;
+ }
+}
+
+
+bool Socket::SetReuseAddress(bool reuse_address) {
+ if (!IsValid()) return 0;
+ int v = reuse_address ? 1 : 0;
+ int result = ::setsockopt(native_handle_, SOL_SOCKET, SO_REUSEADDR,
+ reinterpret_cast<char*>(&v), sizeof(v));
+ return result == 0;
+}
+
+
+// static
+int Socket::GetLastError() {
+#if V8_OS_POSIX
+ return errno;
+#elif V8_OS_WIN
+ // Be sure to initialize the WinSock DLL first.
+ CallOnce(&initialize_winsock, &InitializeWinsock);
+
+ // Now we can safely perform WSA calls.
+ return ::WSAGetLastError();
+#endif
+}
+
+} } // namespace v8::internal
diff --git a/src/platform/socket.h b/src/platform/socket.h
new file mode 100644
index 0000000..6710692
--- /dev/null
+++ b/src/platform/socket.h
@@ -0,0 +1,101 @@
+// Copyright 2013 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:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_PLATFORM_SOCKET_H_
+#define V8_PLATFORM_SOCKET_H_
+
+#include "globals.h"
+#if V8_OS_WIN
+#include "win32-headers.h"
+#endif
+
+namespace v8 {
+namespace internal {
+
+// ----------------------------------------------------------------------------
+// Socket
+//
+
+class Socket V8_FINAL {
+ public:
+ Socket();
+ ~Socket() { Shutdown(); }
+
+ // Server initialization.
+ bool Bind(int port) V8_WARN_UNUSED_RESULT;
+ bool Listen(int backlog) V8_WARN_UNUSED_RESULT;
+ Socket* Accept() V8_WARN_UNUSED_RESULT;
+
+ // Client initialization.
+ bool Connect(const char* host, const char* port) V8_WARN_UNUSED_RESULT;
+
+ // Shutdown socket for both read and write. This causes blocking Send and
+ // Receive calls to exit. After |Shutdown()| the Socket object cannot be
+ // used for any communication.
+ bool Shutdown();
+
+ // Data Transimission
+ // Return 0 on failure.
+ int Send(const char* buffer, int length) V8_WARN_UNUSED_RESULT;
+ int Receive(char* buffer, int length) V8_WARN_UNUSED_RESULT;
+
+ // Set the value of the SO_REUSEADDR socket option.
+ bool SetReuseAddress(bool reuse_address);
+
+ V8_INLINE(bool IsValid()) const V8_WARN_UNUSED_RESULT {
+ return native_handle_ != kInvalidNativeHandle;
+ }
+
+ static int GetLastError() V8_WARN_UNUSED_RESULT;
+
+ // The implementation-defined native handle type.
+#if V8_OS_POSIX
+ typedef int NativeHandle;
+ static const NativeHandle kInvalidNativeHandle = -1;
+#elif V8_OS_WIN
+ typedef SOCKET NativeHandle;
+ static const NativeHandle kInvalidNativeHandle = INVALID_SOCKET;
+#endif
+
+ NativeHandle& native_handle() V8_WARN_UNUSED_RESULT {
+ return native_handle_;
+ }
+ const NativeHandle& native_handle() const V8_WARN_UNUSED_RESULT {
+ return native_handle_;
+ }
+
+ private:
+ explicit Socket(NativeHandle native_handle) : native_handle_(native_handle) {}
+
+ NativeHandle native_handle_;
+
+ DISALLOW_COPY_AND_ASSIGN(Socket);
+};
+
+} } // namespace v8::internal
+
+#endif // V8_PLATFORM_SOCKET_H_
diff --git a/src/runtime-profiler.cc b/src/runtime-profiler.cc
index 57c50dd..cfce1df 100644
--- a/src/runtime-profiler.cc
+++ b/src/runtime-profiler.cc
@@ -172,9 +172,9 @@
// any back edge in any unoptimized frame will trigger on-stack
// replacement for that frame.
if (FLAG_trace_osr) {
- PrintF("[patching back edges in ");
+ PrintF("[OSR - patching back edges in ");
function->PrintName();
- PrintF(" for on-stack replacement]\n");
+ PrintF("]\n");
}
Deoptimizer::PatchInterruptCode(isolate_, shared->code());
diff --git a/src/runtime.cc b/src/runtime.cc
index d183a6b..5c6bf39 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -4774,10 +4774,10 @@
}
if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
- return object->GetPrototype(isolate)->GetElement(index);
+ return object->GetPrototype(isolate)->GetElement(isolate, index);
}
- return object->GetElement(index);
+ return object->GetElement(isolate, index);
}
@@ -5904,7 +5904,7 @@
if (index < n) {
return frame->GetParameter(index);
} else {
- return isolate->initial_object_prototype()->GetElement(index);
+ return isolate->initial_object_prototype()->GetElement(isolate, index);
}
}
@@ -6679,7 +6679,7 @@
SealHandleScope shs(isolate);
ASSERT(args.length() == 1);
CONVERT_ARG_CHECKED(String, value, 0);
- return value->ToObject();
+ return value->ToObject(isolate);
}
@@ -7528,7 +7528,7 @@
result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
}
ASSERT(result ==
- StringCharacterStreamCompare(Isolate::Current()->runtime_state(), x, y));
+ StringCharacterStreamCompare(x->GetIsolate()->runtime_state(), x, y));
return result;
}
@@ -8343,7 +8343,9 @@
}
function->shared()->code()->set_profiler_ticks(0);
ASSERT(FLAG_concurrent_recompilation);
- Compiler::RecompileConcurrent(function);
+ if (!Compiler::RecompileConcurrent(function)) {
+ function->ReplaceCode(function->shared()->code());
+ }
return isolate->heap()->undefined_value();
}
@@ -8512,7 +8514,11 @@
unoptimized->kind() == Code::FUNCTION) {
CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
if (type->IsOneByteEqualTo(STATIC_ASCII_VECTOR("osr"))) {
- for (int i = 0; i <= Code::kMaxLoopNestingMarker; i++) {
+ // Start patching from the currently patched loop nesting level.
+ int current_level = unoptimized->allow_osr_at_loop_nesting_level();
+ ASSERT(Deoptimizer::VerifyInterruptCode(
+ isolate, unoptimized, current_level));
+ for (int i = current_level + 1; i <= Code::kMaxLoopNestingMarker; i++) {
unoptimized->set_allow_osr_at_loop_nesting_level(i);
isolate->runtime_profiler()->AttemptOnStackReplacement(*function);
}
@@ -8586,98 +8592,19 @@
// We're not prepared to handle a function with arguments object.
ASSERT(!function->shared()->uses_arguments());
- // We have hit a back edge in an unoptimized frame for a function that was
- // selected for on-stack replacement. Find the unoptimized code object.
- Handle<Code> unoptimized(function->shared()->code(), isolate);
- // Keep track of whether we've succeeded in optimizing.
- bool succeeded = unoptimized->optimizable();
- if (succeeded) {
- // If we are trying to do OSR when there are already optimized
- // activations of the function, it means (a) the function is directly or
- // indirectly recursive and (b) an optimized invocation has been
- // deoptimized so that we are currently in an unoptimized activation.
- // Check for optimized activations of this function.
- JavaScriptFrameIterator it(isolate);
- while (succeeded && !it.done()) {
- JavaScriptFrame* frame = it.frame();
- succeeded = !frame->is_optimized() || frame->function() != *function;
- it.Advance();
- }
- }
-
- BailoutId ast_id = BailoutId::None();
- if (succeeded) {
- // The top JS function is this one, the PC is somewhere in the
- // unoptimized code.
- JavaScriptFrameIterator it(isolate);
- JavaScriptFrame* frame = it.frame();
- ASSERT(frame->function() == *function);
- ASSERT(frame->LookupCode() == *unoptimized);
- ASSERT(unoptimized->contains(frame->pc()));
-
- // Use linear search of the unoptimized code's back edge table to find
- // the AST id matching the PC.
- uint32_t target_pc_offset =
- static_cast<uint32_t>(frame->pc() - unoptimized->instruction_start());
- uint32_t loop_depth = 0;
-
- for (FullCodeGenerator::BackEdgeTableIterator back_edges(*unoptimized);
- !back_edges.Done();
- back_edges.Next()) {
- if (back_edges.pc_offset() == target_pc_offset) {
- ast_id = back_edges.ast_id();
- loop_depth = back_edges.loop_depth();
- break;
- }
- }
- ASSERT(!ast_id.IsNone());
-
- if (FLAG_trace_osr) {
- PrintF("[replacing on-stack at AST id %d, loop depth %d in ",
- ast_id.ToInt(), loop_depth);
- function->PrintName();
- PrintF("]\n");
- }
-
- // Try to compile the optimized code. A true return value from
- // CompileOptimized means that compilation succeeded, not necessarily
- // that optimization succeeded.
- if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
- function->IsOptimized()) {
- DeoptimizationInputData* data = DeoptimizationInputData::cast(
- function->code()->deoptimization_data());
- if (data->OsrPcOffset()->value() >= 0) {
- if (FLAG_trace_osr) {
- PrintF("[on-stack replacement offset %d in optimized code]\n",
- data->OsrPcOffset()->value());
- }
- ASSERT(BailoutId(data->OsrAstId()->value()) == ast_id);
- } else {
- // We may never generate the desired OSR entry if we emit an
- // early deoptimize.
- succeeded = false;
- }
- } else {
- succeeded = false;
- }
- }
-
- // Revert to the original interrupt calls in the original unoptimized code.
- if (FLAG_trace_osr) {
- PrintF("[restoring original interrupt calls in ");
- function->PrintName();
- PrintF("]\n");
- }
- Deoptimizer::RevertInterruptCode(isolate, *unoptimized);
-
// If the optimization attempt succeeded, return the AST id tagged as a
// smi. This tells the builtin that we need to translate the unoptimized
// frame to an optimized one.
- if (succeeded) {
+ BailoutId ast_id =
+ (FLAG_concurrent_recompilation && FLAG_concurrent_osr)
+ ? Compiler::CompileForConcurrentOSR(function)
+ : Compiler::CompileForOnStackReplacement(function);
+ if (!ast_id.IsNone()) {
ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
return Smi::FromInt(ast_id.ToInt());
} else {
- if (function->IsMarkedForLazyRecompilation()) {
+ if (function->IsMarkedForLazyRecompilation() ||
+ function->IsMarkedForConcurrentRecompilation()) {
function->ReplaceCode(function->shared()->code());
}
return Smi::FromInt(-1);
@@ -8771,7 +8698,7 @@
}
for (int i = 0; i < argc; ++i) {
- argv[i] = Object::GetElement(arguments, offset + i);
+ argv[i] = Object::GetElement(isolate, arguments, offset + i);
}
bool threw;
@@ -8844,7 +8771,7 @@
extension_object = JSReceiver::cast(args[0]);
} else {
// Convert the object to a proper JavaScript object.
- MaybeObject* maybe_js_object = args[0]->ToObject();
+ MaybeObject* maybe_js_object = args[0]->ToObject(isolate);
if (!maybe_js_object->To(&extension_object)) {
if (Failure::cast(maybe_js_object)->IsInternalError()) {
HandleScope scope(isolate);
@@ -10158,7 +10085,7 @@
} else if (receiver->HasElement(j)) {
// Call GetElement on receiver, not its prototype, or getters won't
// have the correct receiver.
- element_value = Object::GetElement(receiver, j);
+ element_value = Object::GetElement(isolate, receiver, j);
RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
visitor->visit(j, element_value);
}
@@ -10183,7 +10110,8 @@
} else if (receiver->HasElement(j)) {
// Call GetElement on receiver, not its prototype, or getters won't
// have the correct receiver.
- Handle<Object> element_value = Object::GetElement(receiver, j);
+ Handle<Object> element_value =
+ Object::GetElement(isolate, receiver, j);
RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
visitor->visit(j, element_value);
}
@@ -10202,7 +10130,7 @@
while (j < n) {
HandleScope loop_scope(isolate);
uint32_t index = indices[j];
- Handle<Object> element = Object::GetElement(receiver, index);
+ Handle<Object> element = Object::GetElement(isolate, receiver, index);
RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
visitor->visit(index, element);
// Skip to next different index (i.e., omit duplicates).
@@ -13590,7 +13518,7 @@
Handle<Name> base =
isolate->factory()->NewStringFromAscii(CStrVector("base"));
for (unsigned int i = 0; i < length; ++i) {
- MaybeObject* maybe_string = input->GetElement(i);
+ MaybeObject* maybe_string = input->GetElement(isolate, i);
Object* locale_id;
if (!maybe_string->ToObject(&locale_id) || !locale_id->IsString()) {
return isolate->Throw(isolate->heap()->illegal_argument_string());
diff --git a/src/scopeinfo.cc b/src/scopeinfo.cc
index c9df1fb..3d09d3a 100644
--- a/src/scopeinfo.cc
+++ b/src/scopeinfo.cc
@@ -74,7 +74,7 @@
+ parameter_count + stack_local_count + 2 * context_local_count
+ (has_function_name ? 2 : 0);
- Factory* factory = Isolate::Current()->factory();
+ Factory* factory = zone->isolate()->factory();
Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length);
// Encode the flags.
diff --git a/src/scopes.cc b/src/scopes.cc
index e38e903..ce1741a 100644
--- a/src/scopes.cc
+++ b/src/scopes.cc
@@ -129,7 +129,7 @@
ScopeType scope_type,
Handle<ScopeInfo> scope_info,
Zone* zone)
- : isolate_(Isolate::Current()),
+ : isolate_(zone->isolate()),
inner_scopes_(4, zone),
variables_(zone),
internals_(4, zone),
@@ -152,7 +152,7 @@
Scope::Scope(Scope* inner_scope, Handle<String> catch_variable_name, Zone* zone)
- : isolate_(Isolate::Current()),
+ : isolate_(zone->isolate()),
inner_scopes_(1, zone),
variables_(zone),
internals_(0, zone),
@@ -1092,7 +1092,7 @@
// Assignment to const. Throw a syntax error.
MessageLocation location(
info->script(), proxy->position(), proxy->position());
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = info->isolate();
Factory* factory = isolate->factory();
Handle<JSArray> array = factory->NewJSArray(0);
Handle<Object> result =
@@ -1123,7 +1123,7 @@
// TODO(rossberg): generate more helpful error message.
MessageLocation location(
info->script(), proxy->position(), proxy->position());
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = info->isolate();
Factory* factory = isolate->factory();
Handle<JSArray> array = factory->NewJSArray(1);
USE(JSObject::SetElement(array, 0, var->name(), NONE, kStrictMode));
diff --git a/src/serialize.cc b/src/serialize.cc
index 746c926..6f84aed 100644
--- a/src/serialize.cc
+++ b/src/serialize.cc
@@ -596,9 +596,9 @@
}
-ExternalReferenceEncoder::ExternalReferenceEncoder()
+ExternalReferenceEncoder::ExternalReferenceEncoder(Isolate* isolate)
: encodings_(Match),
- isolate_(Isolate::Current()) {
+ isolate_(isolate) {
ExternalReferenceTable* external_references =
ExternalReferenceTable::instance(isolate_);
for (int i = 0; i < external_references->size(); ++i) {
@@ -638,9 +638,9 @@
}
-ExternalReferenceDecoder::ExternalReferenceDecoder()
+ExternalReferenceDecoder::ExternalReferenceDecoder(Isolate* isolate)
: encodings_(NewArray<Address*>(kTypeCodeCount)),
- isolate_(Isolate::Current()) {
+ isolate_(isolate) {
ExternalReferenceTable* external_references =
ExternalReferenceTable::instance(isolate_);
for (int type = kFirstTypeCode; type < kTypeCodeCount; ++type) {
@@ -780,13 +780,12 @@
CodeAddressMap* Serializer::code_address_map_ = NULL;
-void Serializer::Enable() {
+void Serializer::Enable(Isolate* isolate) {
if (!serialization_enabled_) {
ASSERT(!too_late_to_enable_now_);
}
if (serialization_enabled_) return;
serialization_enabled_ = true;
- i::Isolate* isolate = Isolate::Current();
isolate->InitializeLoggingAndCounters();
code_address_map_ = new CodeAddressMap(isolate);
}
@@ -810,8 +809,8 @@
}
-void Deserializer::Deserialize() {
- isolate_ = Isolate::Current();
+void Deserializer::Deserialize(Isolate* isolate) {
+ isolate_ = isolate;
ASSERT(isolate_ != NULL);
isolate_->heap()->ReserveSpace(reservations_, &high_water_[0]);
// No active threads.
@@ -819,7 +818,7 @@
// No active handles.
ASSERT(isolate_->handle_scope_implementer()->blocks()->is_empty());
ASSERT_EQ(NULL, external_reference_decoder_);
- external_reference_decoder_ = new ExternalReferenceDecoder();
+ external_reference_decoder_ = new ExternalReferenceDecoder(isolate);
isolate_->heap()->IterateStrongRoots(this, VISIT_ONLY_STRONG);
isolate_->heap()->RepairFreeListsAfterBoot();
isolate_->heap()->IterateWeakRoots(this, VISIT_ALL);
@@ -850,14 +849,14 @@
}
-void Deserializer::DeserializePartial(Object** root) {
- isolate_ = Isolate::Current();
+void Deserializer::DeserializePartial(Isolate* isolate, Object** root) {
+ isolate_ = isolate;
for (int i = NEW_SPACE; i < kNumberOfSpaces; i++) {
ASSERT(reservations_[i] != kUninitializedReservation);
}
isolate_->heap()->ReserveSpace(reservations_, &high_water_[0]);
if (external_reference_decoder_ == NULL) {
- external_reference_decoder_ = new ExternalReferenceDecoder();
+ external_reference_decoder_ = new ExternalReferenceDecoder(isolate);
}
// Keep track of the code space start and end pointers in case new
@@ -1277,12 +1276,12 @@
}
-Serializer::Serializer(SnapshotByteSink* sink)
- : sink_(sink),
+Serializer::Serializer(Isolate* isolate, SnapshotByteSink* sink)
+ : isolate_(isolate),
+ sink_(sink),
current_root_index_(0),
- external_reference_encoder_(new ExternalReferenceEncoder),
+ external_reference_encoder_(new ExternalReferenceEncoder(isolate)),
root_index_wave_front_(0) {
- isolate_ = Isolate::Current();
// The serializer is meant to be used only to generate initial heap images
// from a context in which there is only one isolate.
ASSERT(isolate_->IsDefaultIsolate());
@@ -1298,9 +1297,9 @@
void StartupSerializer::SerializeStrongReferences() {
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = this->isolate();
// No active threads.
- CHECK_EQ(NULL, Isolate::Current()->thread_manager()->FirstThreadStateInUse());
+ CHECK_EQ(NULL, isolate->thread_manager()->FirstThreadStateInUse());
// No active or weak handles.
CHECK(isolate->handle_scope_implementer()->blocks()->is_empty());
CHECK_EQ(0, isolate->global_handles()->NumberOfWeakHandles());
@@ -1319,7 +1318,7 @@
void Serializer::VisitPointers(Object** start, Object** end) {
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = this->isolate();;
for (Object** current = start; current < end; current++) {
if (start == isolate->heap()->roots_array_start()) {
@@ -1350,9 +1349,9 @@
// that correspond to the elements of this cache array. On deserialization we
// therefore need to visit the cache array. This fills it up with pointers to
// deserialized objects.
-void SerializerDeserializer::Iterate(ObjectVisitor* visitor) {
+void SerializerDeserializer::Iterate(Isolate* isolate,
+ ObjectVisitor* visitor) {
if (Serializer::enabled()) return;
- Isolate* isolate = Isolate::Current();
for (int i = 0; ; i++) {
if (isolate->serialize_partial_snapshot_cache_length() <= i) {
// Extend the array ready to get a value from the visitor when
@@ -1371,7 +1370,7 @@
int PartialSerializer::PartialSnapshotCacheIndex(HeapObject* heap_object) {
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = this->isolate();
for (int i = 0;
i < isolate->serialize_partial_snapshot_cache_length();
@@ -1394,7 +1393,7 @@
int Serializer::RootIndex(HeapObject* heap_object, HowToCode from) {
- Heap* heap = HEAP;
+ Heap* heap = isolate()->heap();
if (heap->InNewSpace(heap_object)) return kInvalidRootIndex;
for (int i = 0; i < root_index_wave_front_; i++) {
Object* root = heap->roots_array_start()[i];
@@ -1484,8 +1483,7 @@
// will contain some references needed to decode the partial snapshot. We
// add one entry with 'undefined' which is the sentinel that the deserializer
// uses to know it is done deserializing the array.
- Isolate* isolate = Isolate::Current();
- Object* undefined = isolate->heap()->undefined_value();
+ Object* undefined = isolate()->heap()->undefined_value();
VisitPointer(&undefined);
HEAP->IterateWeakRoots(this, VISIT_ALL);
Pad();
diff --git a/src/serialize.h b/src/serialize.h
index 563f0a0..0b07e1f 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -110,7 +110,7 @@
class ExternalReferenceEncoder {
public:
- ExternalReferenceEncoder();
+ explicit ExternalReferenceEncoder(Isolate* isolate);
uint32_t Encode(Address key) const;
@@ -134,7 +134,7 @@
class ExternalReferenceDecoder {
public:
- ExternalReferenceDecoder();
+ explicit ExternalReferenceDecoder(Isolate* isolate);
~ExternalReferenceDecoder();
Address Decode(uint32_t key) const {
@@ -208,7 +208,7 @@
// both.
class SerializerDeserializer: public ObjectVisitor {
public:
- static void Iterate(ObjectVisitor* visitor);
+ static void Iterate(Isolate* isolate, ObjectVisitor* visitor);
static int nop() { return kNop; }
@@ -325,10 +325,10 @@
virtual ~Deserializer();
// Deserialize the snapshot into an empty heap.
- void Deserialize();
+ void Deserialize(Isolate* isolate);
// Deserialize a single object and the objects reachable from it.
- void DeserializePartial(Object** root);
+ void DeserializePartial(Isolate* isolate, Object** root);
void set_reservation(int space_number, int reservation) {
ASSERT(space_number >= 0);
@@ -464,7 +464,7 @@
// There can be only one serializer per V8 process.
class Serializer : public SerializerDeserializer {
public:
- explicit Serializer(SnapshotByteSink* sink);
+ Serializer(Isolate* isolate, SnapshotByteSink* sink);
~Serializer();
void VisitPointers(Object** start, Object** end);
// You can call this after serialization to find out how much space was used
@@ -474,7 +474,8 @@
return fullness_[space];
}
- static void Enable();
+ Isolate* isolate() const { return isolate_; }
+ static void Enable(Isolate* isolate);
static void Disable();
// Call this when you have made use of the fact that there is no serialization
@@ -593,9 +594,10 @@
class PartialSerializer : public Serializer {
public:
- PartialSerializer(Serializer* startup_snapshot_serializer,
+ PartialSerializer(Isolate* isolate,
+ Serializer* startup_snapshot_serializer,
SnapshotByteSink* sink)
- : Serializer(sink),
+ : Serializer(isolate, sink),
startup_serializer_(startup_snapshot_serializer) {
set_root_index_wave_front(Heap::kStrongRootListLength);
}
@@ -629,12 +631,13 @@
class StartupSerializer : public Serializer {
public:
- explicit StartupSerializer(SnapshotByteSink* sink) : Serializer(sink) {
+ StartupSerializer(Isolate* isolate, SnapshotByteSink* sink)
+ : Serializer(isolate, sink) {
// Clear the cache of objects used by the partial snapshot. After the
// strong roots have been serialized we can create a partial snapshot
// which will repopulate the cache with objects needed by that partial
// snapshot.
- Isolate::Current()->set_serialize_partial_snapshot_cache_length(0);
+ isolate->set_serialize_partial_snapshot_cache_length(0);
}
// Serialize the current state of the heap. The order is:
// 1) Strong references.
diff --git a/src/snapshot-common.cc b/src/snapshot-common.cc
index 576269d..96034e3 100644
--- a/src/snapshot-common.cc
+++ b/src/snapshot-common.cc
@@ -116,7 +116,7 @@
}
-Handle<Context> Snapshot::NewContextFromSnapshot() {
+Handle<Context> Snapshot::NewContextFromSnapshot(Isolate* isolate) {
if (context_size_ == 0) {
return Handle<Context>();
}
@@ -132,7 +132,7 @@
deserializer.set_reservation(CELL_SPACE, context_cell_space_used_);
deserializer.set_reservation(PROPERTY_CELL_SPACE,
context_property_cell_space_used_);
- deserializer.DeserializePartial(&root);
+ deserializer.DeserializePartial(isolate, &root);
CHECK(root->IsContext());
return Handle<Context>(Context::cast(root));
}
diff --git a/src/snapshot.h b/src/snapshot.h
index 149306e..4041f29 100644
--- a/src/snapshot.h
+++ b/src/snapshot.h
@@ -43,7 +43,7 @@
static bool HaveASnapshotToStartFrom();
// Create a new context using the internal partial snapshot.
- static Handle<Context> NewContextFromSnapshot();
+ static Handle<Context> NewContextFromSnapshot(Isolate* isolate);
// Returns whether or not the snapshot is enabled.
static bool IsEnabled() { return size_ != 0; }
diff --git a/src/spaces.cc b/src/spaces.cc
index e62d381..d527c73 100644
--- a/src/spaces.cc
+++ b/src/spaces.cc
@@ -1777,8 +1777,7 @@
#ifdef DEBUG
// heap_histograms is shared, always clear it before using it.
-static void ClearHistograms() {
- Isolate* isolate = Isolate::Current();
+static void ClearHistograms(Isolate* isolate) {
// We reset the name each time, though it hasn't changed.
#define DEF_TYPE_NAME(name) isolate->heap_histograms()[name].set_name(#name);
INSTANCE_TYPE_LIST(DEF_TYPE_NAME)
@@ -1829,8 +1828,7 @@
}
-static void ReportHistogram(bool print_spill) {
- Isolate* isolate = Isolate::Current();
+static void ReportHistogram(Isolate* isolate, bool print_spill) {
PrintF("\n Object Histogram:\n");
for (int i = 0; i <= LAST_TYPE; i++) {
if (isolate->heap_histograms()[i].number() > 0) {
@@ -2685,8 +2683,7 @@
#ifdef DEBUG
-void PagedSpace::ReportCodeStatistics() {
- Isolate* isolate = Isolate::Current();
+void PagedSpace::ReportCodeStatistics(Isolate* isolate) {
CommentStatistic* comments_statistics =
isolate->paged_space_comments_statistics();
ReportCodeKindStatistics(isolate->code_kind_statistics());
@@ -2703,8 +2700,7 @@
}
-void PagedSpace::ResetCodeStatistics() {
- Isolate* isolate = Isolate::Current();
+void PagedSpace::ResetCodeStatistics(Isolate* isolate) {
CommentStatistic* comments_statistics =
isolate->paged_space_comments_statistics();
ClearCodeKindStatistics(isolate->code_kind_statistics());
@@ -2819,11 +2815,11 @@
Capacity(), Waste(), Available(), pct);
if (was_swept_conservatively_) return;
- ClearHistograms();
+ ClearHistograms(heap()->isolate());
HeapObjectIterator obj_it(this);
for (HeapObject* obj = obj_it.Next(); obj != NULL; obj = obj_it.Next())
CollectHistogramInfo(obj);
- ReportHistogram(true);
+ ReportHistogram(heap()->isolate(), true);
}
#endif
@@ -3160,7 +3156,7 @@
void LargeObjectSpace::ReportStatistics() {
PrintF(" size: %" V8_PTR_PREFIX "d\n", size_);
int num_objects = 0;
- ClearHistograms();
+ ClearHistograms(heap()->isolate());
LargeObjectIterator it(this);
for (HeapObject* obj = it.Next(); obj != NULL; obj = it.Next()) {
num_objects++;
@@ -3169,7 +3165,7 @@
PrintF(" number of objects %d, "
"size of objects %" V8_PTR_PREFIX "d\n", num_objects, objects_size_);
- if (num_objects > 0) ReportHistogram(false);
+ if (num_objects > 0) ReportHistogram(heap()->isolate(), false);
}
diff --git a/src/spaces.h b/src/spaces.h
index 7f8ab5e..92c135d 100644
--- a/src/spaces.h
+++ b/src/spaces.h
@@ -1753,8 +1753,8 @@
// Report code object related statistics
void CollectCodeStatistics();
- static void ReportCodeStatistics();
- static void ResetCodeStatistics();
+ static void ReportCodeStatistics(Isolate* isolate);
+ static void ResetCodeStatistics(Isolate* isolate);
#endif
bool was_swept_conservatively() { return was_swept_conservatively_; }
diff --git a/src/string-stream.cc b/src/string-stream.cc
index 9c4394e..f34f53d 100644
--- a/src/string-stream.cc
+++ b/src/string-stream.cc
@@ -194,7 +194,8 @@
return;
}
if (o->IsHeapObject()) {
- DebugObjectCache* debug_object_cache = Isolate::Current()->
+ HeapObject* ho = HeapObject::cast(o);
+ DebugObjectCache* debug_object_cache = ho->GetIsolate()->
string_stream_debug_object_cache();
for (int i = 0; i < debug_object_cache->length(); i++) {
if ((*debug_object_cache)[i] == o) {
@@ -289,14 +290,13 @@
}
-Handle<String> StringStream::ToString() {
- Factory* factory = Isolate::Current()->factory();
- return factory->NewStringFromUtf8(Vector<const char>(buffer_, length_));
+Handle<String> StringStream::ToString(Isolate* isolate) {
+ return isolate->factory()->NewStringFromUtf8(
+ Vector<const char>(buffer_, length_));
}
-void StringStream::ClearMentionedObjectCache() {
- Isolate* isolate = Isolate::Current();
+void StringStream::ClearMentionedObjectCache(Isolate* isolate) {
isolate->set_string_stream_current_security_token(NULL);
if (isolate->string_stream_debug_object_cache() == NULL) {
isolate->set_string_stream_debug_object_cache(
@@ -307,9 +307,8 @@
#ifdef DEBUG
-bool StringStream::IsMentionedObjectCacheClear() {
- return (
- Isolate::Current()->string_stream_debug_object_cache()->length() == 0);
+bool StringStream::IsMentionedObjectCacheClear(Isolate* isolate) {
+ return isolate->string_stream_debug_object_cache()->length() == 0;
}
#endif
@@ -422,9 +421,9 @@
}
-void StringStream::PrintMentionedObjectCache() {
+void StringStream::PrintMentionedObjectCache(Isolate* isolate) {
DebugObjectCache* debug_object_cache =
- Isolate::Current()->string_stream_debug_object_cache();
+ isolate->string_stream_debug_object_cache();
Add("==== Key ============================================\n\n");
for (int i = 0; i < debug_object_cache->length(); i++) {
HeapObject* printee = (*debug_object_cache)[i];
@@ -457,12 +456,12 @@
void StringStream::PrintSecurityTokenIfChanged(Object* f) {
- Isolate* isolate = Isolate::Current();
+ if (!f->IsHeapObject()) return;
+ HeapObject* obj = HeapObject::cast(f);
+ Isolate* isolate = obj->GetIsolate();
Heap* heap = isolate->heap();
- if (!f->IsHeapObject() || !heap->Contains(HeapObject::cast(f))) {
- return;
- }
- Map* map = HeapObject::cast(f)->map();
+ if (!heap->Contains(obj)) return;
+ Map* map = obj->map();
if (!map->IsHeapObject() ||
!heap->Contains(map) ||
!map->IsMap() ||
diff --git a/src/string-stream.h b/src/string-stream.h
index 2367994..255a2c3 100644
--- a/src/string-stream.h
+++ b/src/string-stream.h
@@ -148,7 +148,7 @@
void OutputToFile(FILE* out);
void OutputToStdOut() { OutputToFile(stdout); }
void Log();
- Handle<String> ToString();
+ Handle<String> ToString(Isolate* isolate);
SmartArrayPointer<const char> ToCString() const;
int length() const { return length_; }
@@ -169,10 +169,10 @@
}
// Mentioned object cache support.
- void PrintMentionedObjectCache();
- static void ClearMentionedObjectCache();
+ void PrintMentionedObjectCache(Isolate* isolate);
+ static void ClearMentionedObjectCache(Isolate* isolate);
#ifdef DEBUG
- static bool IsMentionedObjectCacheClear();
+ static bool IsMentionedObjectCacheClear(Isolate* isolate);
#endif
diff --git a/src/transitions.cc b/src/transitions.cc
index 086edcb..9d3f038 100644
--- a/src/transitions.cc
+++ b/src/transitions.cc
@@ -35,20 +35,20 @@
namespace internal {
-static MaybeObject* AllocateRaw(int length) {
- Heap* heap = Isolate::Current()->heap();
-
+static MaybeObject* AllocateRaw(Isolate* isolate, int length) {
// Use FixedArray to not use TransitionArray::cast on incomplete object.
FixedArray* array;
- MaybeObject* maybe_array = heap->AllocateFixedArray(length);
+ MaybeObject* maybe_array = isolate->heap()->AllocateFixedArray(length);
if (!maybe_array->To(&array)) return maybe_array;
return array;
}
-MaybeObject* TransitionArray::Allocate(int number_of_transitions) {
+MaybeObject* TransitionArray::Allocate(Isolate* isolate,
+ int number_of_transitions) {
FixedArray* array;
- MaybeObject* maybe_array = AllocateRaw(ToKeyIndex(number_of_transitions));
+ MaybeObject* maybe_array =
+ AllocateRaw(isolate, ToKeyIndex(number_of_transitions));
if (!maybe_array->To(&array)) return maybe_array;
array->set(kPrototypeTransitionsIndex, Smi::FromInt(0));
return array;
@@ -77,11 +77,11 @@
MaybeObject* maybe_result;
if (flag == SIMPLE_TRANSITION) {
- maybe_result = AllocateRaw(kSimpleTransitionSize);
+ maybe_result = AllocateRaw(target->GetIsolate(), kSimpleTransitionSize);
if (!maybe_result->To(&result)) return maybe_result;
result->set(kSimpleTransitionTarget, target);
} else {
- maybe_result = Allocate(1);
+ maybe_result = Allocate(target->GetIsolate(), 1);
if (!maybe_result->To(&result)) return maybe_result;
result->NoIncrementalWriteBarrierSet(0, key, target);
}
@@ -94,7 +94,7 @@
ASSERT(!IsFullTransitionArray());
int nof = number_of_transitions();
TransitionArray* result;
- MaybeObject* maybe_result = Allocate(nof);
+ MaybeObject* maybe_result = Allocate(GetIsolate(), nof);
if (!maybe_result->To(&result)) return maybe_result;
if (nof == 1) {
@@ -116,7 +116,7 @@
if (insertion_index == kNotFound) ++new_size;
MaybeObject* maybe_array;
- maybe_array = TransitionArray::Allocate(new_size);
+ maybe_array = TransitionArray::Allocate(GetIsolate(), new_size);
if (!maybe_array->To(&result)) return maybe_array;
if (HasPrototypeTransitions()) {
diff --git a/src/transitions.h b/src/transitions.h
index fde1279..b2e9839 100644
--- a/src/transitions.h
+++ b/src/transitions.h
@@ -119,7 +119,8 @@
inline int Search(Name* name);
// Allocates a TransitionArray.
- MUST_USE_RESULT static MaybeObject* Allocate(int number_of_transitions);
+ MUST_USE_RESULT static MaybeObject* Allocate(
+ Isolate* isolate, int number_of_transitions);
bool IsSimpleTransition() {
return length() == kSimpleTransitionSize &&
diff --git a/src/v8.cc b/src/v8.cc
index f2aa837..e47ff12 100644
--- a/src/v8.cc
+++ b/src/v8.cc
@@ -174,16 +174,6 @@
}
-bool V8::IdleNotification(int hint) {
- // Returning true tells the caller that there is no need to call
- // IdleNotification again.
- if (!FLAG_use_idle_notification) return true;
-
- // Tell the heap that it may want to adjust.
- return HEAP->IdleNotification(hint);
-}
-
-
void V8::AddCallCompletedCallback(CallCompletedCallback callback) {
if (call_completed_callbacks_ == NULL) { // Lazy init.
call_completed_callbacks_ = new List<CallCompletedCallback>();
diff --git a/src/v8.h b/src/v8.h
index 707482f..69f4df9 100644
--- a/src/v8.h
+++ b/src/v8.h
@@ -105,9 +105,6 @@
static Object* FillHeapNumberWithRandom(Object* heap_number,
Context* context);
- // Idle notification directly from the API.
- static bool IdleNotification(int hint);
-
static void AddCallCompletedCallback(CallCompletedCallback callback);
static void RemoveCallCompletedCallback(CallCompletedCallback callback);
static void FireCallCompletedCallback(Isolate* isolate);
diff --git a/src/v8threads.cc b/src/v8threads.cc
index c1f20b1..33b620d 100644
--- a/src/v8threads.cc
+++ b/src/v8threads.cc
@@ -144,12 +144,13 @@
void Locker::StartPreemption(int every_n_ms) {
- v8::internal::ContextSwitcher::StartPreemption(every_n_ms);
+ v8::internal::ContextSwitcher::StartPreemption(
+ i::Isolate::Current(), every_n_ms);
}
void Locker::StopPreemption() {
- v8::internal::ContextSwitcher::StopPreemption();
+ v8::internal::ContextSwitcher::StopPreemption(i::Isolate::Current());
}
@@ -437,8 +438,7 @@
// Set the scheduling interval of V8 threads. This function starts the
// ContextSwitcher thread if needed.
-void ContextSwitcher::StartPreemption(int every_n_ms) {
- Isolate* isolate = Isolate::Current();
+void ContextSwitcher::StartPreemption(Isolate* isolate, int every_n_ms) {
ASSERT(Locker::IsLocked(reinterpret_cast<v8::Isolate*>(isolate)));
if (isolate->context_switcher() == NULL) {
// If the ContextSwitcher thread is not running at the moment start it now.
@@ -454,8 +454,7 @@
// Disable preemption of V8 threads. If multiple threads want to use V8 they
// must cooperatively schedule amongst them from this point on.
-void ContextSwitcher::StopPreemption() {
- Isolate* isolate = Isolate::Current();
+void ContextSwitcher::StopPreemption(Isolate* isolate) {
ASSERT(Locker::IsLocked(reinterpret_cast<v8::Isolate*>(isolate)));
if (isolate->context_switcher() != NULL) {
// The ContextSwitcher thread is running. We need to stop it and release
diff --git a/src/v8threads.h b/src/v8threads.h
index b8ed817..1edacfc 100644
--- a/src/v8threads.h
+++ b/src/v8threads.h
@@ -146,10 +146,10 @@
class ContextSwitcher: public Thread {
public:
// Set the preemption interval for the ContextSwitcher thread.
- static void StartPreemption(int every_n_ms);
+ static void StartPreemption(Isolate* isolate, int every_n_ms);
// Stop sending preemption requests to threads.
- static void StopPreemption();
+ static void StopPreemption(Isolate* isolate);
// Preempted thread needs to call back to the ContextSwitcher to acknowledge
// the handling of a preemption request.
diff --git a/src/version.cc b/src/version.cc
index 5bc3a06..dbc114c 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,7 +34,7 @@
// system so their names cannot be changed without changing the scripts.
#define MAJOR_VERSION 3
#define MINOR_VERSION 21
-#define BUILD_NUMBER 9
+#define BUILD_NUMBER 10
#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
diff --git a/src/x64/disasm-x64.cc b/src/x64/disasm-x64.cc
index acf2dc1..9984a46 100644
--- a/src/x64/disasm-x64.cc
+++ b/src/x64/disasm-x64.cc
@@ -1320,6 +1320,8 @@
return "addsd";
case 0x59: // F2 prefix.
return "mulsd";
+ case 0x5A: // F2 prefix.
+ return "cvtsd2ss";
case 0x5C: // F2 prefix.
return "subsd";
case 0x5E: // F2 prefix.