Revision: 2682 Author: [email protected] Date: Thu Aug 13 05:44:13 2009 Log: Push version 1.3.4 to trunk.
Added a readline() command to the d8 shell. Fixed bug in json parsing. Added idle notification to the API and reduced memory on idle notifications. Review URL: http://codereview.chromium.org/164475 http://code.google.com/p/v8/source/detail?r=2682 Modified: /trunk/ChangeLog /trunk/include/v8.h /trunk/src/api.cc /trunk/src/compiler.cc /trunk/src/compiler.h /trunk/src/d8.cc /trunk/src/d8.h /trunk/src/flag-definitions.h /trunk/src/heap.cc /trunk/src/heap.h /trunk/src/messages.js /trunk/src/runtime.cc /trunk/src/spaces.cc /trunk/src/spaces.h /trunk/src/uri.js /trunk/src/v8.cc /trunk/src/v8.h /trunk/src/version.cc /trunk/src/x64/codegen-x64.cc /trunk/src/x64/disasm-x64.cc /trunk/test/mjsunit/json.js ======================================= --- /trunk/ChangeLog Wed Aug 12 07:20:51 2009 +++ /trunk/ChangeLog Thu Aug 13 05:44:13 2009 @@ -1,3 +1,13 @@ +2009-08-13: Version 1.3.4 + + Added a readline() command to the d8 shell. + + Fixed bug in json parsing. + + Added idle notification to the API and reduced memory on idle + notifications. + + 2009-08-12: Version 1.3.3 Fix issue 417: incorrect %t placeholder expansion. ======================================= --- /trunk/include/v8.h Wed Aug 12 07:20:51 2009 +++ /trunk/include/v8.h Thu Aug 13 05:44:13 2009 @@ -2201,6 +2201,14 @@ */ static bool Dispose(); + + /** + * Optional notification that the embedder is idle. + * V8 uses the notification to reduce memory footprint. + * \param is_high_priority tells whether the embedder is high priority. + */ + static void IdleNotification(bool is_high_priority); + private: V8(); ======================================= --- /trunk/src/api.cc Wed Aug 12 07:20:51 2009 +++ /trunk/src/api.cc Thu Aug 13 05:44:13 2009 @@ -2558,6 +2558,10 @@ } +void v8::V8::IdleNotification(bool is_high_priority) { + i::V8::IdleNotification(is_high_priority); +} + const char* v8::V8::GetVersion() { static v8::internal::EmbeddedVector<char, 128> buffer; v8::internal::Version::GetString(buffer); @@ -2589,12 +2593,8 @@ i::Handle<i::Context> env; { ENTER_V8; -#if defined(ANDROID) - // On mobile devices, full GC is expensive. -#else // Give the heap a chance to cleanup if we've disposed contexts. i::Heap::CollectAllGarbageIfContextDisposed(); -#endif v8::Handle<ObjectTemplate> proxy_template = global_template; i::Handle<i::FunctionTemplateInfo> proxy_constructor; i::Handle<i::FunctionTemplateInfo> global_constructor; ======================================= --- /trunk/src/compiler.cc Wed Aug 5 01:38:10 2009 +++ /trunk/src/compiler.cc Thu Aug 13 05:44:13 2009 @@ -102,7 +102,7 @@ static bool IsValidJSON(FunctionLiteral* lit) { - if (!lit->body()->length() == 1) + if (lit->body()->length() != 1) return false; Statement* stmt = lit->body()->at(0); if (stmt->AsExpressionStatement() == NULL) @@ -114,7 +114,7 @@ static Handle<JSFunction> MakeFunction(bool is_global, bool is_eval, - bool is_json, + Compiler::ValidationState validate, Handle<Script> script, Handle<Context> context, v8::Extension* extension, @@ -129,6 +129,7 @@ script->set_context_data((*i::Top::global_context())->data()); #ifdef ENABLE_DEBUGGER_SUPPORT + bool is_json = (validate == Compiler::VALIDATE_JSON); if (is_eval || is_json) { script->set_compilation_type( is_json ? Smi::FromInt(Script::COMPILATION_TYPE_JSON) : @@ -162,7 +163,7 @@ // When parsing JSON we do an ordinary parse and then afterwards // check the AST to ensure it was well-formed. If not we give a // syntax error. - if (is_json && !IsValidJSON(lit)) { + if (validate == Compiler::VALIDATE_JSON && !IsValidJSON(lit)) { HandleScope scope; Handle<JSArray> args = Factory::NewJSArray(1); Handle<Object> source(script->source()); @@ -282,7 +283,7 @@ // Compile the function and add it to the cache. result = MakeFunction(true, false, - false, + DONT_VALIDATE_JSON, script, Handle<Context>::null(), extension, @@ -305,7 +306,11 @@ Handle<JSFunction> Compiler::CompileEval(Handle<String> source, Handle<Context> context, bool is_global, - bool is_json) { + ValidationState validate) { + // Note that if validation is required then no path through this + // function is allowed to return a value without validating that + // the input is legal json. + int source_length = source->length(); Counters::total_eval_size.Increment(source_length); Counters::total_compile_size.Increment(source_length); @@ -314,20 +319,26 @@ VMState state(COMPILER); // Do a lookup in the compilation cache; if the entry is not there, - // invoke the compiler and add the result to the cache. - Handle<JSFunction> result = - CompilationCache::LookupEval(source, context, is_global); + // invoke the compiler and add the result to the cache. If we're + // evaluating json we bypass the cache since we can't be sure a + // potential value in the cache has been validated. + Handle<JSFunction> result; + if (validate == DONT_VALIDATE_JSON) + result = CompilationCache::LookupEval(source, context, is_global); + if (result.is_null()) { // Create a script object describing the script to be compiled. Handle<Script> script = Factory::NewScript(source); result = MakeFunction(is_global, true, - is_json, + validate, script, context, NULL, NULL); - if (!result.is_null()) { + if (!result.is_null() && validate != VALIDATE_JSON) { + // For json it's unlikely that we'll ever see exactly the same + // string again so we don't use the compilation cache. CompilationCache::PutEval(source, context, is_global, result); } } ======================================= --- /trunk/src/compiler.h Mon May 25 22:44:31 2009 +++ /trunk/src/compiler.h Thu Aug 13 05:44:13 2009 @@ -48,6 +48,8 @@ class Compiler : public AllStatic { public: + enum ValidationState { VALIDATE_JSON, DONT_VALIDATE_JSON }; + // All routines return a JSFunction. // If an error occurs an exception is raised and // the return handle contains NULL. @@ -63,7 +65,7 @@ static Handle<JSFunction> CompileEval(Handle<String> source, Handle<Context> context, bool is_global, - bool is_json); + ValidationState validation); // Compile from function info (used for lazy compilation). Returns // true on success and false if the compilation resulted in a stack ======================================= --- /trunk/src/d8.cc Wed Aug 12 07:20:51 2009 +++ /trunk/src/d8.cc Thu Aug 13 05:44:13 2009 @@ -167,9 +167,6 @@ Handle<Value> Shell::Read(const Arguments& args) { - if (args.Length() != 1) { - return ThrowException(String::New("Bad parameters")); - } String::Utf8Value file(args[0]); if (*file == NULL) { return ThrowException(String::New("Error loading file")); @@ -180,6 +177,19 @@ } return source; } + + +Handle<Value> Shell::ReadLine(const Arguments& args) { + char line_buf[256]; + if (fgets(line_buf, sizeof(line_buf), stdin) == NULL) { + return ThrowException(String::New("Error reading line")); + } + int len = strlen(line_buf); + if (line_buf[len - 1] == '\n') { + --len; + } + return String::New(line_buf, len); +} Handle<Value> Shell::Load(const Arguments& args) { @@ -404,6 +414,8 @@ global_template->Set(String::New("print"), FunctionTemplate::New(Print)); global_template->Set(String::New("write"), FunctionTemplate::New(Write)); global_template->Set(String::New("read"), FunctionTemplate::New(Read)); + global_template->Set(String::New("readline"), + FunctionTemplate::New(ReadLine)); global_template->Set(String::New("load"), FunctionTemplate::New(Load)); global_template->Set(String::New("quit"), FunctionTemplate::New(Quit)); global_template->Set(String::New("version"), FunctionTemplate::New(Version)); @@ -596,6 +608,8 @@ FunctionTemplate::New(Shell::Write)); global_template->Set(String::New("read"), FunctionTemplate::New(Shell::Read)); + global_template->Set(String::New("readline"), + FunctionTemplate::New(Shell::ReadLine)); global_template->Set(String::New("load"), FunctionTemplate::New(Shell::Load)); global_template->Set(String::New("yield"), ======================================= --- /trunk/src/d8.h Wed Aug 12 07:20:51 2009 +++ /trunk/src/d8.h Thu Aug 13 05:44:13 2009 @@ -143,6 +143,7 @@ static Handle<Value> Quit(const Arguments& args); static Handle<Value> Version(const Arguments& args); static Handle<Value> Read(const Arguments& args); + static Handle<Value> ReadLine(const Arguments& args); static Handle<Value> Load(const Arguments& args); // The OS object on the global object contains methods for performing // operating system calls: ======================================= --- /trunk/src/flag-definitions.h Wed Aug 5 01:38:10 2009 +++ /trunk/src/flag-definitions.h Thu Aug 13 05:44:13 2009 @@ -161,6 +161,9 @@ DEFINE_bool(collect_maps, true, "garbage collect maps from which no objects can be reached") +// v8.cc +DEFINE_bool(use_idle_notification, true, + "Use idle notification to reduce memory footprint.") // ic.cc DEFINE_bool(use_ic, true, "use inline caching") ======================================= --- /trunk/src/heap.cc Wed Aug 12 07:20:51 2009 +++ /trunk/src/heap.cc Thu Aug 13 05:44:13 2009 @@ -423,6 +423,20 @@ Heap::symbol_table()->IterateElements(&verifier); #endif // DEBUG } + + +void Heap::EnsureFromSpaceIsCommitted() { + if (new_space_.CommitFromSpaceIfNeeded()) return; + + // Committing memory to from space failed. + // Try shrinking and try again. + Shrink(); + if (new_space_.CommitFromSpaceIfNeeded()) return; + + // Committing memory to from space failed again. + // Memory is exhausted and we will die. + V8::FatalProcessOutOfMemory("Committing semi space failed."); +} void Heap::PerformGarbageCollection(AllocationSpace space, @@ -433,7 +447,7 @@ ASSERT(!allocation_allowed_); global_gc_prologue_callback_(); } - + EnsureFromSpaceIsCommitted(); if (collector == MARK_COMPACTOR) { MarkCompact(tracer); ======================================= --- /trunk/src/heap.h Wed Aug 5 01:38:10 2009 +++ /trunk/src/heap.h Thu Aug 13 05:44:13 2009 @@ -279,6 +279,9 @@ static Address* NewSpaceAllocationLimitAddress() { return new_space_.allocation_limit_address(); } + + // Uncommit unused semi space. + static bool UncommitFromSpace() { return new_space_.UncommitFromSpace(); } #ifdef ENABLE_HEAP_PROTECTION // Protect/unprotect the heap by marking all spaces read-only/writable. @@ -794,6 +797,9 @@ // Rebuild remembered set in old and map spaces. static void RebuildRSets(); + // Commits from space if it is uncommitted. + static void EnsureFromSpaceIsCommitted(); + // // Support for the API. // ======================================= --- /trunk/src/messages.js Thu Jul 30 07:48:31 2009 +++ /trunk/src/messages.js Thu Aug 13 05:44:13 2009 @@ -28,88 +28,36 @@ // ------------------------------------------------------------------- -const kVowelSounds = {a: true, e: true, i: true, o: true, u: true, y: true}; -const kCapitalVowelSounds = {a: true, e: true, i: true, o: true, u: true, - h: true, f: true, l: true, m: true, n: true, r: true, s: true, x: true, - y: true}; +// Lazily initialized. +var kVowelSounds = 0; +var kCapitalVowelSounds = 0; + function GetInstanceName(cons) { if (cons.length == 0) { return ""; } var first = %StringToLowerCase(StringCharAt.call(cons, 0)); - var mapping = kVowelSounds; + if (kVowelSounds === 0) { + kVowelSounds = {a: true, e: true, i: true, o: true, u: true, y: true}; + kCapitalVowelSounds = {a: true, e: true, i: true, o: true, u: true, h: true, + f: true, l: true, m: true, n: true, r: true, s: true, x: true, y: true}; + } + var vowel_mapping = kVowelSounds; if (cons.length > 1 && (StringCharAt.call(cons, 0) != first)) { // First char is upper case var second = %StringToLowerCase(StringCharAt.call(cons, 1)); // Second char is upper case - if (StringCharAt.call(cons, 1) != second) - mapping = kCapitalVowelSounds; - } - var s = mapping[first] ? "an " : "a "; + if (StringCharAt.call(cons, 1) != second) { + vowel_mapping = kCapitalVowelSounds; + } + } + var s = vowel_mapping[first] ? "an " : "a "; return s + cons; } -const kMessages = { - // Error - cyclic_proto: "Cyclic __proto__ value", - // TypeError - unexpected_token: "Unexpected token %0", - unexpected_token_number: "Unexpected number", - unexpected_token_string: "Unexpected string", - unexpected_token_identifier: "Unexpected identifier", - unexpected_eos: "Unexpected end of input", - malformed_regexp: "Invalid regular expression: /%0/: %1", - unterminated_regexp: "Invalid regular expression: missing /", - regexp_flags: "Cannot supply flags when constructing one RegExp from another", - invalid_lhs_in_assignment: "Invalid left-hand side in assignment", - invalid_lhs_in_for_in: "Invalid left-hand side in for-in", - invalid_lhs_in_postfix_op: "Invalid left-hand side expression in postfix operation", - invalid_lhs_in_prefix_op: "Invalid left-hand side expression in prefix operation", - multiple_defaults_in_switch: "More than one default clause in switch statement", - newline_after_throw: "Illegal newline after throw", - redeclaration: "%0 '%1' has already been declared", - no_catch_or_finally: "Missing catch or finally after try", - unknown_label: "Undefined label '%0'", - uncaught_exception: "Uncaught %0", - stack_trace: "Stack Trace:\n%0", - called_non_callable: "%0 is not a function", - undefined_method: "Object %1 has no method '%0'", - property_not_function: "Property '%0' of object %1 is not a function", - cannot_convert_to_primitive: "Cannot convert object to primitive value", - not_constructor: "%0 is not a constructor", - not_defined: "%0 is not defined", - non_object_property_load: "Cannot read property '%0' of %1", - non_object_property_store: "Cannot set property '%0' of %1", - non_object_property_call: "Cannot call method '%0' of %1", - with_expression: "%0 has no properties", - illegal_invocation: "Illegal invocation", - no_setter_in_callback: "Cannot set property %0 of %1 which has only a getter", - apply_non_function: "Function.prototype.apply was called on %0, which is a %1 and not a function", - apply_wrong_args: "Function.prototype.apply: Arguments list has wrong type", - invalid_in_operator_use: "Cannot use 'in' operator to search for '%0' in %1", - instanceof_function_expected: "Expecting a function in instanceof check, but got %0", - instanceof_nonobject_proto: "Function has non-object prototype '%0' in instanceof check", - null_to_object: "Cannot convert null to object", - reduce_no_initial: "Reduce of empty array with no initial value", - // RangeError - invalid_array_length: "Invalid array length", - stack_overflow: "Maximum call stack size exceeded", - apply_overflow: "Function.prototype.apply cannot support %0 arguments", - // SyntaxError - unable_to_parse: "Parse error", - duplicate_regexp_flag: "Duplicate RegExp flag %0", - invalid_regexp: "Invalid RegExp pattern /%0/", - illegal_break: "Illegal break statement", - illegal_continue: "Illegal continue statement", - illegal_return: "Illegal return statement", - error_loading_debugger: "Error loading debugger %0", - no_input_to_regexp: "No input to %0", - result_not_primitive: "Result of %0 must be a primitive, was %1", - invalid_json: "String '%0' is not valid JSON", - circular_structure: "Converting circular structure to JSON" -}; +var kMessages = 0; function FormatString(format, args) { @@ -161,6 +109,67 @@ // Helper functions; called from the runtime system. function FormatMessage(message) { + if (kMessages === 0) { + kMessages = { + // Error + cyclic_proto: "Cyclic __proto__ value", + // TypeError + unexpected_token: "Unexpected token %0", + unexpected_token_number: "Unexpected number", + unexpected_token_string: "Unexpected string", + unexpected_token_identifier: "Unexpected identifier", + unexpected_eos: "Unexpected end of input", + malformed_regexp: "Invalid regular expression: /%0/: %1", + unterminated_regexp: "Invalid regular expression: missing /", + regexp_flags: "Cannot supply flags when constructing one RegExp from another", + invalid_lhs_in_assignment: "Invalid left-hand side in assignment", + invalid_lhs_in_for_in: "Invalid left-hand side in for-in", + invalid_lhs_in_postfix_op: "Invalid left-hand side expression in postfix operation", + invalid_lhs_in_prefix_op: "Invalid left-hand side expression in prefix operation", + multiple_defaults_in_switch: "More than one default clause in switch statement", + newline_after_throw: "Illegal newline after throw", + redeclaration: "%0 '%1' has already been declared", + no_catch_or_finally: "Missing catch or finally after try", + unknown_label: "Undefined label '%0'", + uncaught_exception: "Uncaught %0", + stack_trace: "Stack Trace:\n%0", + called_non_callable: "%0 is not a function", + undefined_method: "Object %1 has no method '%0'", + property_not_function: "Property '%0' of object %1 is not a function", + cannot_convert_to_primitive: "Cannot convert object to primitive value", + not_constructor: "%0 is not a constructor", + not_defined: "%0 is not defined", + non_object_property_load: "Cannot read property '%0' of %1", + non_object_property_store: "Cannot set property '%0' of %1", + non_object_property_call: "Cannot call method '%0' of %1", + with_expression: "%0 has no properties", + illegal_invocation: "Illegal invocation", + no_setter_in_callback: "Cannot set property %0 of %1 which has only a getter", + apply_non_function: "Function.prototype.apply was called on %0, which is a %1 and not a function", + apply_wrong_args: "Function.prototype.apply: Arguments list has wrong type", + invalid_in_operator_use: "Cannot use 'in' operator to search for '%0' in %1", + instanceof_function_expected: "Expecting a function in instanceof check, but got %0", + instanceof_nonobject_proto: "Function has non-object prototype '%0' in instanceof check", + null_to_object: "Cannot convert null to object", + reduce_no_initial: "Reduce of empty array with no initial value", + // RangeError + invalid_array_length: "Invalid array length", + stack_overflow: "Maximum call stack size exceeded", + apply_overflow: "Function.prototype.apply cannot support %0 arguments", + // SyntaxError + unable_to_parse: "Parse error", + duplicate_regexp_flag: "Duplicate RegExp flag %0", + invalid_regexp: "Invalid RegExp pattern /%0/", + illegal_break: "Illegal break statement", + illegal_continue: "Illegal continue statement", + illegal_return: "Illegal return statement", + error_loading_debugger: "Error loading debugger %0", + no_input_to_regexp: "No input to %0", + result_not_primitive: "Result of %0 must be a primitive, was %1", + invalid_json: "String '%0' is not valid JSON", + circular_structure: "Converting circular structure to JSON" + }; + } var format = kMessages[message.type]; if (!format) return "<unknown message " + message.type + ">"; return FormatString(format, message.args); ======================================= --- /trunk/src/runtime.cc Wed Aug 5 01:38:10 2009 +++ /trunk/src/runtime.cc Thu Aug 13 05:44:13 2009 @@ -4973,10 +4973,12 @@ // Compile source string in the global context. Handle<Context> context(Top::context()->global_context()); + Compiler::ValidationState validate = (is_json->IsTrue()) + ? Compiler::VALIDATE_JSON : Compiler::DONT_VALIDATE_JSON; Handle<JSFunction> boilerplate = Compiler::CompileEval(source, context, true, - is_json->IsTrue()); + validate); if (boilerplate.is_null()) return Failure::Exception(); Handle<JSFunction> fun = Factory::NewFunctionFromBoilerplate(boilerplate, context); @@ -5000,8 +5002,11 @@ bool is_global = context->IsGlobalContext(); // Compile source string in the current context. - Handle<JSFunction> boilerplate = - Compiler::CompileEval(source, context, is_global, false); + Handle<JSFunction> boilerplate = Compiler::CompileEval( + source, + context, + is_global, + Compiler::DONT_VALIDATE_JSON); if (boilerplate.is_null()) return Failure::Exception(); Handle<JSFunction> fun = Factory::NewFunctionFromBoilerplate(boilerplate, context); @@ -7043,7 +7048,7 @@ Compiler::CompileEval(function_source, context, context->IsGlobalContext(), - false); + Compiler::DONT_VALIDATE_JSON); if (boilerplate.is_null()) return Failure::Exception(); Handle<JSFunction> compiled_function = Factory::NewFunctionFromBoilerplate(boilerplate, context); @@ -7111,7 +7116,7 @@ Handle<JSFunction>(Compiler::CompileEval(source, context, true, - false)); + Compiler::DONT_VALIDATE_JSON)); if (boilerplate.is_null()) return Failure::Exception(); Handle<JSFunction> compiled_function = Handle<JSFunction>(Factory::NewFunctionFromBoilerplate(boilerplate, ======================================= --- /trunk/src/spaces.cc Wed Aug 12 07:20:51 2009 +++ /trunk/src/spaces.cc Thu Aug 13 05:44:13 2009 @@ -340,6 +340,17 @@ return true; } +bool MemoryAllocator::UncommitBlock(Address start, size_t size) { + ASSERT(start != NULL); + ASSERT(size > 0); + ASSERT(initial_chunk_ != NULL); + ASSERT(InInitialChunk(start)); + ASSERT(InInitialChunk(start + size - 1)); + + if (!initial_chunk_->Uncommit(start, size)) return false; + Counters::memory_allocated.Decrement(size); + return true; +} Page* MemoryAllocator::InitializePagesInChunk(int chunk_id, int pages_in_chunk, PagedSpace* owner) { @@ -1039,6 +1050,26 @@ #endif +bool SemiSpace::Commit() { + ASSERT(!is_committed()); + if (!MemoryAllocator::CommitBlock(start_, capacity_, executable())) { + return false; + } + committed_ = true; + return true; +} + + +bool SemiSpace::Uncommit() { + ASSERT(is_committed()); + if (!MemoryAllocator::UncommitBlock(start_, capacity_)) { + return false; + } + committed_ = false; + return true; +} + + // ----------------------------------------------------------------------------- // SemiSpace implementation @@ -1053,18 +1084,15 @@ // addresses. capacity_ = initial_capacity; maximum_capacity_ = maximum_capacity; - - if (!MemoryAllocator::CommitBlock(start, capacity_, executable())) { - return false; - } + committed_ = false; start_ = start; address_mask_ = ~(maximum_capacity - 1); object_mask_ = address_mask_ | kHeapObjectTag; object_expected_ = reinterpret_cast<uintptr_t>(start) | kHeapObjectTag; - age_mark_ = start_; - return true; + + return Commit(); } @@ -1076,7 +1104,7 @@ bool SemiSpace::Grow() { // Commit 50% extra space but only up to maximum capacity. - int extra = capacity_/2; + int extra = RoundUp(capacity_ / 2, OS::AllocateAlignment()); if (capacity_ + extra > maximum_capacity_) { extra = maximum_capacity_ - capacity_; } ======================================= --- /trunk/src/spaces.h Wed Aug 12 07:20:51 2009 +++ /trunk/src/spaces.h Thu Aug 13 05:44:13 2009 @@ -367,6 +367,13 @@ // and false otherwise. static bool CommitBlock(Address start, size_t size, Executability executable); + + // Uncommit a contiguous block of memory [start..(start+size)[. + // start is not NULL, the size is greater than zero, and the + // block is contained in the initial chunk. Returns true if it succeeded + // and false otherwise. + static bool UncommitBlock(Address start, size_t size); + // Attempts to allocate the requested (non-zero) number of pages from the // OS. Fewer pages might be allocated than requested. If it fails to // allocate memory for the OS or cannot allocate a single page, this @@ -1034,6 +1041,10 @@ UNREACHABLE(); return 0; } + + bool is_committed() { return committed_; } + bool Commit(); + bool Uncommit(); #ifdef DEBUG virtual void Print(); @@ -1058,6 +1069,8 @@ uintptr_t object_mask_; uintptr_t object_expected_; + bool committed_; + public: TRACK_MEMORY("SemiSpace") }; @@ -1249,6 +1262,17 @@ void RecordAllocation(HeapObject* obj); void RecordPromotion(HeapObject* obj); #endif + + // Return whether the operation succeded. + bool CommitFromSpaceIfNeeded() { + if (from_space_.is_committed()) return true; + return from_space_.Commit(); + } + + bool UncommitFromSpace() { + if (!from_space_.is_committed()) return true; + return from_space_.Uncommit(); + } private: // The current and maximum capacities of a semispace. ======================================= --- /trunk/src/uri.js Thu Mar 12 00:19:55 2009 +++ /trunk/src/uri.js Thu Aug 13 05:44:13 2009 @@ -39,6 +39,10 @@ function URIEncodeOctets(octets, result, index) { + if (hexCharCodeArray === 0) { + hexCharCodeArray = [48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 65, 66, 67, 68, 69, 70]; + } index = URIAddEncodedOctetToBuffer(octets[0], result, index); if (octets[1]) index = URIAddEncodedOctetToBuffer(octets[1], result, index); if (octets[2]) index = URIAddEncodedOctetToBuffer(octets[2], result, index); @@ -316,11 +320,9 @@ } -const hexCharArray = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", - "A", "B", "C", "D", "E", "F"]; - -const hexCharCodeArray = [48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 65, 66, 67, 68, 69, 70]; +// Lazily initialized. +var hexCharArray = 0; +var hexCharCodeArray = 0; function HexValueOf(c) { @@ -341,6 +343,10 @@ // 64 -> 0040, 62234 -> F31A. function CharCodeToHex4Str(cc) { var r = ""; + if (hexCharArray === 0) { + hexCharArray = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", + "A", "B", "C", "D", "E", "F"]; + } for (var i = 0; i < 4; ++i) { var c = hexCharArray[cc & 0x0F]; r = c + r; ======================================= --- /trunk/src/v8.cc Tue Jun 16 02:43:10 2009 +++ /trunk/src/v8.cc Thu Aug 13 05:44:13 2009 @@ -155,6 +155,15 @@ lo = 18273 * (lo & 0xFFFF) + (lo >> 16); return (hi << 16) + (lo & 0xFFFF); } + +void V8::IdleNotification(bool is_high_priority) { + if (!FLAG_use_idle_notification) return; + // Ignore high priority instances of V8. + if (is_high_priority) return; + + // Uncommit unused memory in new space. + Heap::UncommitFromSpace(); +} Smi* V8::RandomPositiveSmi() { ======================================= --- /trunk/src/v8.h Mon Jun 29 01:26:34 2009 +++ /trunk/src/v8.h Thu Aug 13 05:44:13 2009 @@ -99,6 +99,9 @@ static uint32_t Random(); static Smi* RandomPositiveSmi(); + // Idle notification directly from the API. + static void IdleNotification(bool is_high_priority); + private: // True if engine is currently running static bool is_running_; ======================================= --- /trunk/src/version.cc Wed Aug 12 07:20:51 2009 +++ /trunk/src/version.cc Thu Aug 13 05:44:13 2009 @@ -34,7 +34,7 @@ // cannot be changed without changing the SCons build script. #define MAJOR_VERSION 1 #define MINOR_VERSION 3 -#define BUILD_NUMBER 3 +#define BUILD_NUMBER 4 #define PATCH_LEVEL 0 #define CANDIDATE_VERSION false ======================================= --- /trunk/src/x64/codegen-x64.cc Wed Aug 12 07:20:51 2009 +++ /trunk/src/x64/codegen-x64.cc Thu Aug 13 05:44:13 2009 @@ -5258,6 +5258,58 @@ } break; + case Token::SHL: + if (reversed) { + Result constant_operand(value); + LikelySmiBinaryOperation(op, &constant_operand, operand, + overwrite_mode); + } else { + // Only the least significant 5 bits of the shift value are used. + // In the slow case, this masking is done inside the runtime call. + int shift_value = int_value & 0x1f; + operand->ToRegister(); + if (shift_value == 0) { + // Spill operand so it can be overwritten in the slow case. + frame_->Spill(operand->reg()); + DeferredInlineSmiOperation* deferred = + new DeferredInlineSmiOperation(op, + operand->reg(), + operand->reg(), + smi_value, + overwrite_mode); + __ testl(operand->reg(), Immediate(kSmiTagMask)); + deferred->Branch(not_zero); + deferred->BindExit(); + frame_->Push(operand); + } else { + // Use a fresh temporary for nonzero shift values. + Result answer = allocator()->Allocate(); + ASSERT(answer.is_valid()); + DeferredInlineSmiOperation* deferred = + new DeferredInlineSmiOperation(op, + answer.reg(), + operand->reg(), + smi_value, + overwrite_mode); + __ testl(operand->reg(), Immediate(kSmiTagMask)); + deferred->Branch(not_zero); + __ movl(answer.reg(), operand->reg()); + ASSERT(kSmiTag == 0); // adjust code if not the case + // We do no shifts, only the Smi conversion, if shift_value is 1. + if (shift_value > 1) { + __ shll(answer.reg(), Immediate(shift_value - 1)); + } + // Convert int result to Smi, checking that it is in int range. + ASSERT(kSmiTagSize == 1); // adjust code if not the case + __ addl(answer.reg(), answer.reg()); + deferred->Branch(overflow); + deferred->BindExit(); + operand->Unuse(); + frame_->Push(&answer); + } + } + break; + case Token::BIT_OR: case Token::BIT_XOR: case Token::BIT_AND: { @@ -6013,6 +6065,8 @@ __ testl(key.reg(), Immediate(static_cast<uint32_t>(kSmiTagMask | 0x80000000U))); deferred->Branch(not_zero); + // Ensure that the smi is zero-extended. This is not guaranteed. + __ movl(key.reg(), key.reg()); // Check that the receiver is not a smi. __ testl(receiver.reg(), Immediate(kSmiTagMask)); @@ -7172,14 +7226,14 @@ __ jmp(&done); __ bind(&load_smi_1); - __ sar(kScratchRegister, Immediate(kSmiTagSize)); + __ sarl(kScratchRegister, Immediate(kSmiTagSize)); __ push(kScratchRegister); __ fild_s(Operand(rsp, 0)); __ pop(kScratchRegister); __ jmp(&done_load_1); __ bind(&load_smi_2); - __ sar(kScratchRegister, Immediate(kSmiTagSize)); + __ sarl(kScratchRegister, Immediate(kSmiTagSize)); __ push(kScratchRegister); __ fild_s(Operand(rsp, 0)); __ pop(kScratchRegister); @@ -7534,7 +7588,7 @@ __ j(negative, &non_smi_result); } // Tag smi result and return. - ASSERT(kSmiTagSize == times_2); // adjust code if not the case + ASSERT(kSmiTagSize == 1); // adjust code if not the case __ lea(rax, Operand(rax, rax, times_1, kSmiTag)); __ ret(2 * kPointerSize); ======================================= --- /trunk/src/x64/disasm-x64.cc Wed Aug 5 01:38:10 2009 +++ /trunk/src/x64/disasm-x64.cc Thu Aug 13 05:44:13 2009 @@ -105,7 +105,6 @@ static ByteMnemonic zero_operands_instr[] = { { 0xC3, UNSET_OP_ORDER, "ret" }, { 0xC9, UNSET_OP_ORDER, "leave" }, - { 0x90, UNSET_OP_ORDER, "nop" }, { 0xF4, UNSET_OP_ORDER, "hlt" }, { 0xCC, UNSET_OP_ORDER, "int3" }, { 0x60, UNSET_OP_ORDER, "pushad" }, @@ -1425,7 +1424,7 @@ default: UNREACHABLE(); } - AppendToBuffer("test%c rax,0x%"V8_PTR_PREFIX"ux", + AppendToBuffer("test%c rax,0x%"V8_PTR_PREFIX"x", operand_size_code(), value); break; ======================================= --- /trunk/test/mjsunit/json.js Mon Apr 27 02:26:21 2009 +++ /trunk/test/mjsunit/json.js Thu Aug 13 05:44:13 2009 @@ -195,3 +195,13 @@ assertEquals(undefined, JSON.stringify(undefined)); assertEquals(undefined, JSON.stringify(function () { })); + +function checkIllegal(str) { + assertThrows(function () { JSON.parse(str); }, SyntaxError); +} + +checkIllegal('1); throw "foo"; (1'); + +var x = 0; +eval("(1); x++; (1)"); +checkIllegal('1); x++; (1'); --~--~---------~--~----~------------~-------~--~----~ v8-dev mailing list [email protected] http://groups.google.com/group/v8-dev -~----------~----~----~----~------~----~------~--~---
