| Index: src/api.cc
|
| ===================================================================
|
| --- src/api.cc (revision 3935)
|
| +++ src/api.cc (working copy)
|
| @@ -1107,7 +1107,8 @@
|
|
|
| Local<Script> Script::New(v8::Handle<String> source,
|
| v8::ScriptOrigin* origin,
|
| - v8::ScriptData* script_data) {
|
| + v8::ScriptData* pre_data,
|
| + v8::Handle<String> script_data) {
|
| ON_BAILOUT("v8::Script::New()", return Local<Script>());
|
| LOG_API("Script::New");
|
| ENTER_V8;
|
| @@ -1127,13 +1128,13 @@
|
| }
|
| }
|
| EXCEPTION_PREAMBLE();
|
| - i::ScriptDataImpl* pre_data = static_cast<i::ScriptDataImpl*>(script_data);
|
| + i::ScriptDataImpl* pre_data_impl = static_cast<i::ScriptDataImpl*>(pre_data);
|
| // We assert that the pre-data is sane, even though we can actually
|
| // handle it if it turns out not to be in release mode.
|
| - ASSERT(pre_data == NULL || pre_data->SanityCheck());
|
| + ASSERT(pre_data_impl == NULL || pre_data_impl->SanityCheck());
|
| // If the pre-data isn't sane we simply ignore it
|
| - if (pre_data != NULL && !pre_data->SanityCheck()) {
|
| - pre_data = NULL;
|
| + if (pre_data_impl != NULL && !pre_data_impl->SanityCheck()) {
|
| + pre_data_impl = NULL;
|
| }
|
| i::Handle<i::JSFunction> boilerplate =
|
| i::Compiler::Compile(str,
|
| @@ -1141,7 +1142,8 @@
|
| line_offset,
|
| column_offset,
|
| NULL,
|
| - pre_data,
|
| + pre_data_impl,
|
| + Utils::OpenHandle(*script_data),
|
| i::NOT_NATIVES_CODE);
|
| has_pending_exception = boilerplate.is_null();
|
| EXCEPTION_BAILOUT_CHECK(Local<Script>());
|
| @@ -1158,11 +1160,12 @@
|
|
|
| Local<Script> Script::Compile(v8::Handle<String> source,
|
| v8::ScriptOrigin* origin,
|
| - v8::ScriptData* script_data) {
|
| + v8::ScriptData* pre_data,
|
| + v8::Handle<String> script_data) {
|
| ON_BAILOUT("v8::Script::Compile()", return Local<Script>());
|
| LOG_API("Script::Compile");
|
| ENTER_V8;
|
| - Local<Script> generic = New(source, origin, script_data);
|
| + Local<Script> generic = New(source, origin, pre_data, script_data);
|
| if (generic.IsEmpty())
|
| return generic;
|
| i::Handle<i::JSFunction> boilerplate = Utils::OpenHandle(*generic);
|
| @@ -1174,9 +1177,10 @@
|
|
|
|
|
| Local<Script> Script::Compile(v8::Handle<String> source,
|
| - v8::Handle<Value> file_name) {
|
| + v8::Handle<Value> file_name,
|
| + v8::Handle<String> script_data) {
|
| ScriptOrigin origin(file_name);
|
| - return Compile(source, &origin);
|
| + return Compile(source, &origin, 0, script_data);
|
| }
|
|
|
|
|
| @@ -2035,6 +2039,19 @@
|
| }
|
|
|
|
|
| +bool v8::Object::SetPrototype(Handle<Value> value) {
|
| + ON_BAILOUT("v8::Object::SetPrototype()", return false);
|
| + ENTER_V8;
|
| + i::Handle<i::JSObject> self = Utils::OpenHandle(this);
|
| + i::Handle<i::Object> value_obj = Utils::OpenHandle(*value);
|
| + EXCEPTION_PREAMBLE();
|
| + i::Handle<i::Object> result = i::SetPrototype(self, value_obj);
|
| + has_pending_exception = result.is_null();
|
| + EXCEPTION_BAILOUT_CHECK(false);
|
| + return true;
|
| +}
|
| +
|
| +
|
| Local<Object> v8::Object::FindInstanceInPrototypeChain(
|
| v8::Handle<FunctionTemplate> tmpl) {
|
| ON_BAILOUT("v8::Object::FindInstanceInPrototypeChain()",
|
| @@ -2197,7 +2214,7 @@
|
| i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
|
| i::LookupResult lookup;
|
| self_obj->LookupRealNamedPropertyInPrototypes(*key_obj, &lookup);
|
| - if (lookup.IsValid()) {
|
| + if (lookup.IsProperty()) {
|
| PropertyAttributes attributes;
|
| i::Handle<i::Object> result(self_obj->GetProperty(*self_obj,
|
| &lookup,
|
| @@ -2216,7 +2233,7 @@
|
| i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
|
| i::LookupResult lookup;
|
| self_obj->LookupRealNamedProperty(*key_obj, &lookup);
|
| - if (lookup.IsValid()) {
|
| + if (lookup.IsProperty()) {
|
| PropertyAttributes attributes;
|
| i::Handle<i::Object> result(self_obj->GetProperty(*self_obj,
|
| &lookup,
|
| @@ -2448,6 +2465,99 @@
|
| }
|
|
|
|
|
| +ScriptOrigin Function::GetScriptOrigin() const {
|
| + i::Handle<i::JSFunction> func = Utils::OpenHandle(this);
|
| + if (func->shared()->script()->IsScript()) {
|
| + i::Handle<i::Script> script(i::Script::cast(func->shared()->script()));
|
| + v8::ScriptOrigin origin(
|
| + Utils::ToLocal(i::Handle<i::Object>(script->name())),
|
| + v8::Integer::New(script->line_offset()->value()),
|
| + v8::Integer::New(script->column_offset()->value()));
|
| + return origin;
|
| + }
|
| + return v8::ScriptOrigin(Handle<Value>());
|
| +}
|
| +
|
| +
|
| +const int Function::kLineOffsetNotFound = -1;
|
| +
|
| +
|
| +int Function::GetScriptLineNumber() const {
|
| + i::Handle<i::JSFunction> func = Utils::OpenHandle(this);
|
| + if (func->shared()->script()->IsScript()) {
|
| + i::Handle<i::Script> script(i::Script::cast(func->shared()->script()));
|
| + return i::GetScriptLineNumber(script, func->shared()->start_position());
|
| + }
|
| + return kLineOffsetNotFound;
|
| +}
|
| +
|
| +
|
| +namespace {
|
| +
|
| +// Tracks string usage to help make better decisions when
|
| +// externalizing strings.
|
| +//
|
| +// Implementation note: internally this class only tracks fresh
|
| +// strings and keeps a single use counter for them.
|
| +class StringTracker {
|
| + public:
|
| + // Records that the given string's characters were copied to some
|
| + // external buffer. If this happens often we should honor
|
| + // externalization requests for the string.
|
| + static void RecordWrite(i::Handle<i::String> string) {
|
| + i::Address address = reinterpret_cast<i::Address>(*string);
|
| + i::Address top = i::Heap::NewSpaceTop();
|
| + if (IsFreshString(address, top)) {
|
| + IncrementUseCount(top);
|
| + }
|
| + }
|
| +
|
| + // Estimates freshness and use frequency of the given string based
|
| + // on how close it is to the new space top and the recorded usage
|
| + // history.
|
| + static inline bool IsFreshUnusedString(i::Handle<i::String> string) {
|
| + i::Address address = reinterpret_cast<i::Address>(*string);
|
| + i::Address top = i::Heap::NewSpaceTop();
|
| + return IsFreshString(address, top) && IsUseCountLow(top);
|
| + }
|
| +
|
| + private:
|
| + static inline bool IsFreshString(i::Address string, i::Address top) {
|
| + return top - kFreshnessLimit <= string && string <= top;
|
| + }
|
| +
|
| + static inline bool IsUseCountLow(i::Address top) {
|
| + if (last_top_ != top) return true;
|
| + return use_count_ < kUseLimit;
|
| + }
|
| +
|
| + static inline void IncrementUseCount(i::Address top) {
|
| + if (last_top_ != top) {
|
| + use_count_ = 0;
|
| + last_top_ = top;
|
| + }
|
| + ++use_count_;
|
| + }
|
| +
|
| + // How close to the new space top a fresh string has to be.
|
| + static const int kFreshnessLimit = 1024;
|
| +
|
| + // The number of uses required to consider a string useful.
|
| + static const int kUseLimit = 32;
|
| +
|
| + // Single use counter shared by all fresh strings.
|
| + static int use_count_;
|
| +
|
| + // Last new space top when the use count above was valid.
|
| + static i::Address last_top_;
|
| +};
|
| +
|
| +int StringTracker::use_count_ = 0;
|
| +i::Address StringTracker::last_top_ = NULL;
|
| +
|
| +} // namespace
|
| +
|
| +
|
| int String::Length() const {
|
| if (IsDeadCheck("v8::String::Length()")) return 0;
|
| return Utils::OpenHandle(this)->length();
|
| @@ -2465,6 +2575,7 @@
|
| LOG_API("String::WriteUtf8");
|
| ENTER_V8;
|
| i::Handle<i::String> str = Utils::OpenHandle(this);
|
| + StringTracker::RecordWrite(str);
|
| write_input_buffer.Reset(0, *str);
|
| int len = str->length();
|
| // Encode the first K - 3 bytes directly into the buffer since we
|
| @@ -2508,6 +2619,7 @@
|
| ENTER_V8;
|
| ASSERT(start >= 0 && length >= -1);
|
| i::Handle<i::String> str = Utils::OpenHandle(this);
|
| + StringTracker::RecordWrite(str);
|
| // Flatten the string for efficiency. This applies whether we are
|
| // using StringInputBuffer or Get(i) to access the characters.
|
| str->TryFlattenIfNotFlat();
|
| @@ -2534,6 +2646,7 @@
|
| ENTER_V8;
|
| ASSERT(start >= 0 && length >= -1);
|
| i::Handle<i::String> str = Utils::OpenHandle(this);
|
| + StringTracker::RecordWrite(str);
|
| int end = length;
|
| if ( (length == -1) || (length > str->length() - start) )
|
| end = str->length() - start;
|
| @@ -3102,6 +3215,7 @@
|
| if (this->IsExternal()) return false; // Already an external string.
|
| ENTER_V8;
|
| i::Handle<i::String> obj = Utils::OpenHandle(this);
|
| + if (StringTracker::IsFreshUnusedString(obj)) return false;
|
| bool result = obj->MakeExternal(resource);
|
| if (result && !obj->IsSymbol()) {
|
| i::ExternalStringTable::AddString(*obj);
|
| @@ -3127,6 +3241,7 @@
|
| if (this->IsExternal()) return false; // Already an external string.
|
| ENTER_V8;
|
| i::Handle<i::String> obj = Utils::OpenHandle(this);
|
| + if (StringTracker::IsFreshUnusedString(obj)) return false;
|
| bool result = obj->MakeExternal(resource);
|
| if (result && !obj->IsSymbol()) {
|
| i::ExternalStringTable::AddString(*obj);
|
| @@ -3138,6 +3253,7 @@
|
| bool v8::String::CanMakeExternal() {
|
| if (IsDeadCheck("v8::String::CanMakeExternal()")) return false;
|
| i::Handle<i::String> obj = Utils::OpenHandle(this);
|
| + if (StringTracker::IsFreshUnusedString(obj)) return false;
|
| int size = obj->Size(); // Byte size of the original string.
|
| if (size < i::ExternalString::kSize)
|
| return false;
|
| @@ -3361,14 +3477,14 @@
|
|
|
| void V8::PauseProfiler() {
|
| #ifdef ENABLE_LOGGING_AND_PROFILING
|
| - i::Logger::PauseProfiler(PROFILER_MODULE_CPU);
|
| + PauseProfilerEx(PROFILER_MODULE_CPU);
|
| #endif
|
| }
|
|
|
|
|
| void V8::ResumeProfiler() {
|
| #ifdef ENABLE_LOGGING_AND_PROFILING
|
| - i::Logger::ResumeProfiler(PROFILER_MODULE_CPU);
|
| + ResumeProfilerEx(PROFILER_MODULE_CPU);
|
| #endif
|
| }
|
|
|
| @@ -3382,7 +3498,7 @@
|
| }
|
|
|
|
|
| -void V8::ResumeProfilerEx(int flags) {
|
| +void V8::ResumeProfilerEx(int flags, int tag) {
|
| #ifdef ENABLE_LOGGING_AND_PROFILING
|
| if (flags & PROFILER_MODULE_HEAP_SNAPSHOT) {
|
| // Snapshot mode: resume modules, perform GC, then pause only
|
| @@ -3392,19 +3508,19 @@
|
| // Reset snapshot flag and CPU module flags.
|
| flags &= ~(PROFILER_MODULE_HEAP_SNAPSHOT | PROFILER_MODULE_CPU);
|
| const int current_flags = i::Logger::GetActiveProfilerModules();
|
| - i::Logger::ResumeProfiler(flags);
|
| + i::Logger::ResumeProfiler(flags, tag);
|
| i::Heap::CollectAllGarbage(false);
|
| - i::Logger::PauseProfiler(~current_flags & flags);
|
| + i::Logger::PauseProfiler(~current_flags & flags, tag);
|
| } else {
|
| - i::Logger::ResumeProfiler(flags);
|
| + i::Logger::ResumeProfiler(flags, tag);
|
| }
|
| #endif
|
| }
|
|
|
|
|
| -void V8::PauseProfilerEx(int flags) {
|
| +void V8::PauseProfilerEx(int flags, int tag) {
|
| #ifdef ENABLE_LOGGING_AND_PROFILING
|
| - i::Logger::PauseProfiler(flags);
|
| + i::Logger::PauseProfiler(flags, tag);
|
| #endif
|
| }
|
|
|
|
|