diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog index 6d188b89d1..aeeea78ac1 100644 --- a/deps/v8/ChangeLog +++ b/deps/v8/ChangeLog @@ -1,3 +1,12 @@ +2011-08-22: Version 3.5.7 + + Make scanner handle invalid unicode escapes in identifiers correctly. + + Make regexp flag parsing stricter. + + Fix several memory leaks. + + 2011-08-17: Version 3.5.6 Fixed issue that could cause crashes when running with --heap-stats. diff --git a/deps/v8/build/common.gypi b/deps/v8/build/common.gypi index 5a3da526a8..c41b2b2b62 100644 --- a/deps/v8/build/common.gypi +++ b/deps/v8/build/common.gypi @@ -32,25 +32,30 @@ 'visibility%': 'hidden', 'msvs_multi_core_compile%': '1', 'variables': { - 'conditions': [ - [ 'OS=="linux" or OS=="freebsd" or OS=="openbsd"', { - # This handles the Linux platforms we generally deal with. Anything - # else gets passed through, which probably won't work very well; such - # hosts should pass an explicit target_arch to gyp. - 'host_arch%': - ' -#include #include -#ifdef COMPRESS_STARTUP_DATA_BZ2 -#include -#endif #include #include #include #include -// When building with V8 in a shared library we cannot use functions which -// is not explicitly a part of the public V8 API. This extensive use of -// #ifndef USING_V8_SHARED/#endif is a hack until we can resolve whether to -// still use the shell sample for testing or change to use the developer -// shell d8 TODO(1272). -#if !(defined(USING_V8_SHARED) || defined(V8_SHARED)) -#include "../src/v8.h" -#endif // USING_V8_SHARED - -#if !defined(_WIN32) && !defined(_WIN64) -#include // NOLINT +#ifdef COMPRESS_STARTUP_DATA_BZ2 +#error Using compressed startup data is not supported for this sample #endif -static void ExitShell(int exit_code) { - // Use _exit instead of exit to avoid races between isolate - // threads and static destructors. - fflush(stdout); - fflush(stderr); - _exit(exit_code); -} +/** + * This sample program shows how to implement a simple javascript shell + * based on V8. This includes initializing V8 with command line options, + * creating global functions, compiling and executing strings. + * + * For a more sophisticated shell, consider using the debug shell D8. + */ + v8::Persistent CreateShellContext(); void RunShell(v8::Handle context); +int RunMain(int argc, char* argv[]); bool ExecuteString(v8::Handle source, v8::Handle name, bool print_result, @@ -68,305 +57,28 @@ v8::Handle Read(const v8::Arguments& args); v8::Handle Load(const v8::Arguments& args); v8::Handle Quit(const v8::Arguments& args); v8::Handle Version(const v8::Arguments& args); -v8::Handle Int8Array(const v8::Arguments& args); -v8::Handle Uint8Array(const v8::Arguments& args); -v8::Handle Int16Array(const v8::Arguments& args); -v8::Handle Uint16Array(const v8::Arguments& args); -v8::Handle Int32Array(const v8::Arguments& args); -v8::Handle Uint32Array(const v8::Arguments& args); -v8::Handle Float32Array(const v8::Arguments& args); -v8::Handle Float64Array(const v8::Arguments& args); -v8::Handle PixelArray(const v8::Arguments& args); v8::Handle ReadFile(const char* name); void ReportException(v8::TryCatch* handler); -static bool last_run = true; - -class SourceGroup { - public: - SourceGroup() : -#if !(defined(USING_V8_SHARED) || defined(V8_SHARED)) - next_semaphore_(v8::internal::OS::CreateSemaphore(0)), - done_semaphore_(v8::internal::OS::CreateSemaphore(0)), - thread_(NULL), -#endif // USING_V8_SHARED - argv_(NULL), - begin_offset_(0), - end_offset_(0) { } - -#if !(defined(USING_V8_SHARED) || defined(V8_SHARED)) - ~SourceGroup() { - delete next_semaphore_; - delete done_semaphore_; - } -#endif // USING_V8_SHARED - - void Begin(char** argv, int offset) { - argv_ = const_cast(argv); - begin_offset_ = offset; - } - - void End(int offset) { end_offset_ = offset; } - - void Execute() { - for (int i = begin_offset_; i < end_offset_; ++i) { - const char* arg = argv_[i]; - if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) { - // Execute argument given to -e option directly. - v8::HandleScope handle_scope; - v8::Handle file_name = v8::String::New("unnamed"); - v8::Handle source = v8::String::New(argv_[i + 1]); - if (!ExecuteString(source, file_name, false, true)) { - ExitShell(1); - return; - } - ++i; - } else if (arg[0] == '-') { - // Ignore other options. They have been parsed already. - } else { - // Use all other arguments as names of files to load and run. - v8::HandleScope handle_scope; - v8::Handle file_name = v8::String::New(arg); - v8::Handle source = ReadFile(arg); - if (source.IsEmpty()) { - printf("Error reading '%s'\n", arg); - continue; - } - if (!ExecuteString(source, file_name, false, true)) { - ExitShell(1); - return; - } - } - } - } - -#if !(defined(USING_V8_SHARED) || defined(V8_SHARED)) - void StartExecuteInThread() { - if (thread_ == NULL) { - thread_ = new IsolateThread(this); - thread_->Start(); - } - next_semaphore_->Signal(); - } - - void WaitForThread() { - if (thread_ == NULL) return; - if (last_run) { - thread_->Join(); - thread_ = NULL; - } else { - done_semaphore_->Wait(); - } - } -#endif // USING_V8_SHARED - - private: -#if !(defined(USING_V8_SHARED) || defined(V8_SHARED)) - static v8::internal::Thread::Options GetThreadOptions() { - v8::internal::Thread::Options options; - options.name = "IsolateThread"; - // On some systems (OSX 10.6) the stack size default is 0.5Mb or less - // which is not enough to parse the big literal expressions used in tests. - // The stack size should be at least StackGuard::kLimitSize + some - // OS-specific padding for thread startup code. - options.stack_size = 2 << 20; // 2 Mb seems to be enough - return options; - } - - class IsolateThread : public v8::internal::Thread { - public: - explicit IsolateThread(SourceGroup* group) - : v8::internal::Thread(GetThreadOptions()), group_(group) {} - - virtual void Run() { - group_->ExecuteInThread(); - } - - private: - SourceGroup* group_; - }; - - void ExecuteInThread() { - v8::Isolate* isolate = v8::Isolate::New(); - do { - if (next_semaphore_ != NULL) next_semaphore_->Wait(); - { - v8::Isolate::Scope iscope(isolate); - v8::HandleScope scope; - v8::Persistent context = CreateShellContext(); - { - v8::Context::Scope cscope(context); - Execute(); - } - context.Dispose(); - } - if (done_semaphore_ != NULL) done_semaphore_->Signal(); - } while (!last_run); - isolate->Dispose(); - } - - v8::internal::Semaphore* next_semaphore_; - v8::internal::Semaphore* done_semaphore_; - v8::internal::Thread* thread_; -#endif // USING_V8_SHARED - - const char** argv_; - int begin_offset_; - int end_offset_; -}; - +static bool run_shell; -static SourceGroup* isolate_sources = NULL; - -#ifdef COMPRESS_STARTUP_DATA_BZ2 -class BZip2Decompressor : public v8::StartupDataDecompressor { - public: - virtual ~BZip2Decompressor() { } - - protected: - virtual int DecompressData(char* raw_data, - int* raw_data_size, - const char* compressed_data, - int compressed_data_size) { - ASSERT_EQ(v8::StartupData::kBZip2, - v8::V8::GetCompressedStartupDataAlgorithm()); - unsigned int decompressed_size = *raw_data_size; - int result = - BZ2_bzBuffToBuffDecompress(raw_data, - &decompressed_size, - const_cast(compressed_data), - compressed_data_size, - 0, 1); - if (result == BZ_OK) { - *raw_data_size = decompressed_size; - } - return result; - } -}; -#endif - - -int RunMain(int argc, char* argv[]) { +int main(int argc, char* argv[]) { v8::V8::SetFlagsFromCommandLine(&argc, argv, true); + run_shell = (argc == 1); v8::HandleScope handle_scope; v8::Persistent context = CreateShellContext(); - // Enter the newly created execution environment. - context->Enter(); if (context.IsEmpty()) { printf("Error creating context\n"); return 1; } - - bool run_shell = (argc == 1); - int num_isolates = 1; - for (int i = 1; i < argc; i++) { - if (strcmp(argv[i], "--isolate") == 0) { -#if !(defined(USING_V8_SHARED) || defined(V8_SHARED)) - ++num_isolates; -#else // USING_V8_SHARED - printf("Error: --isolate not supported when linked with shared " - "library\n"); - ExitShell(1); -#endif // USING_V8_SHARED - } - } - if (isolate_sources == NULL) { - isolate_sources = new SourceGroup[num_isolates]; - SourceGroup* current = isolate_sources; - current->Begin(argv, 1); - for (int i = 1; i < argc; i++) { - const char* str = argv[i]; - if (strcmp(str, "--isolate") == 0) { - current->End(i); - current++; - current->Begin(argv, i + 1); - } else if (strcmp(str, "--shell") == 0) { - run_shell = true; - } else if (strcmp(str, "-f") == 0) { - // Ignore any -f flags for compatibility with the other stand- - // alone JavaScript engines. - continue; - } else if (strncmp(str, "--", 2) == 0) { - printf("Warning: unknown flag %s.\nTry --help for options\n", str); - } - } - current->End(argc); - } -#if !(defined(USING_V8_SHARED) || defined(V8_SHARED)) - for (int i = 1; i < num_isolates; ++i) { - isolate_sources[i].StartExecuteInThread(); - } -#endif // USING_V8_SHARED - isolate_sources[0].Execute(); + context->Enter(); + int result = RunMain(argc, argv); if (run_shell) RunShell(context); -#if !(defined(USING_V8_SHARED) || defined(V8_SHARED)) - for (int i = 1; i < num_isolates; ++i) { - isolate_sources[i].WaitForThread(); - } -#endif // USING_V8_SHARED - if (last_run) { - delete[] isolate_sources; - isolate_sources = NULL; - } context->Exit(); context.Dispose(); - return 0; -} - - -int main(int argc, char* argv[]) { - // Figure out if we're requested to stress the optimization - // infrastructure by running tests multiple times and forcing - // optimization in the last run. - bool FLAG_stress_opt = false; - bool FLAG_stress_deopt = false; - for (int i = 0; i < argc; i++) { - if (strcmp(argv[i], "--stress-opt") == 0) { - FLAG_stress_opt = true; - argv[i] = NULL; - } else if (strcmp(argv[i], "--stress-deopt") == 0) { - FLAG_stress_deopt = true; - argv[i] = NULL; - } else if (strcmp(argv[i], "--noalways-opt") == 0) { - // No support for stressing if we can't use --always-opt. - FLAG_stress_opt = false; - FLAG_stress_deopt = false; - break; - } - } - -#ifdef COMPRESS_STARTUP_DATA_BZ2 - BZip2Decompressor startup_data_decompressor; - int bz2_result = startup_data_decompressor.Decompress(); - if (bz2_result != BZ_OK) { - fprintf(stderr, "bzip error code: %d\n", bz2_result); - exit(1); - } -#endif - - v8::V8::SetFlagsFromCommandLine(&argc, argv, true); - int result = 0; - if (FLAG_stress_opt || FLAG_stress_deopt) { - v8::Testing::SetStressRunType(FLAG_stress_opt - ? v8::Testing::kStressTypeOpt - : v8::Testing::kStressTypeDeopt); - int stress_runs = v8::Testing::GetStressRuns(); - for (int i = 0; i < stress_runs && result == 0; i++) { - printf("============ Stress %d/%d ============\n", - i + 1, stress_runs); - v8::Testing::PrepareStressRun(i); - last_run = (i == stress_runs - 1); - result = RunMain(argc, argv); - } - printf("======== Full Deoptimization =======\n"); - v8::Testing::DeoptimizeAll(); - } else { - result = RunMain(argc, argv); - } v8::V8::Dispose(); - return result; } @@ -393,26 +105,6 @@ v8::Persistent CreateShellContext() { // Bind the 'version' function global->Set(v8::String::New("version"), v8::FunctionTemplate::New(Version)); - // Bind the handlers for external arrays. - global->Set(v8::String::New("Int8Array"), - v8::FunctionTemplate::New(Int8Array)); - global->Set(v8::String::New("Uint8Array"), - v8::FunctionTemplate::New(Uint8Array)); - global->Set(v8::String::New("Int16Array"), - v8::FunctionTemplate::New(Int16Array)); - global->Set(v8::String::New("Uint16Array"), - v8::FunctionTemplate::New(Uint16Array)); - global->Set(v8::String::New("Int32Array"), - v8::FunctionTemplate::New(Int32Array)); - global->Set(v8::String::New("Uint32Array"), - v8::FunctionTemplate::New(Uint32Array)); - global->Set(v8::String::New("Float32Array"), - v8::FunctionTemplate::New(Float32Array)); - global->Set(v8::String::New("Float64Array"), - v8::FunctionTemplate::New(Float64Array)); - global->Set(v8::String::New("PixelArray"), - v8::FunctionTemplate::New(PixelArray)); - return v8::Context::New(NULL, global); } @@ -486,7 +178,9 @@ v8::Handle Quit(const v8::Arguments& args) { // If not arguments are given args[0] will yield undefined which // converts to the integer value 0. int exit_code = args[0]->Int32Value(); - ExitShell(exit_code); + fflush(stdout); + fflush(stderr); + exit(exit_code); return v8::Undefined(); } @@ -496,113 +190,6 @@ v8::Handle Version(const v8::Arguments& args) { } -void ExternalArrayWeakCallback(v8::Persistent object, void* data) { - free(data); - object.Dispose(); -} - - -v8::Handle CreateExternalArray(const v8::Arguments& args, - v8::ExternalArrayType type, - size_t element_size) { - assert(element_size == 1 || - element_size == 2 || - element_size == 4 || - element_size == 8); - if (args.Length() != 1) { - return v8::ThrowException( - v8::String::New("Array constructor needs one parameter.")); - } - static const int kMaxLength = 0x3fffffff; - size_t length = 0; - if (args[0]->IsUint32()) { - length = args[0]->Uint32Value(); - } else if (args[0]->IsNumber()) { - double raw_length = args[0]->NumberValue(); - if (raw_length < 0) { - return v8::ThrowException( - v8::String::New("Array length must not be negative.")); - } - if (raw_length > kMaxLength) { - return v8::ThrowException( - v8::String::New("Array length exceeds maximum length.")); - } - length = static_cast(raw_length); - } else { - return v8::ThrowException( - v8::String::New("Array length must be a number.")); - } - if (length > static_cast(kMaxLength)) { - return v8::ThrowException( - v8::String::New("Array length exceeds maximum length.")); - } - void* data = calloc(length, element_size); - if (data == NULL) { - return v8::ThrowException(v8::String::New("Memory allocation failed.")); - } - v8::Handle array = v8::Object::New(); - v8::Persistent persistent_array = - v8::Persistent::New(array); - persistent_array.MakeWeak(data, ExternalArrayWeakCallback); - persistent_array.MarkIndependent(); - array->SetIndexedPropertiesToExternalArrayData(data, type, length); - array->Set(v8::String::New("length"), v8::Int32::New(length), - v8::ReadOnly); - array->Set(v8::String::New("BYTES_PER_ELEMENT"), - v8::Int32::New(element_size)); - return array; -} - - -v8::Handle Int8Array(const v8::Arguments& args) { - return CreateExternalArray(args, v8::kExternalByteArray, sizeof(int8_t)); -} - - -v8::Handle Uint8Array(const v8::Arguments& args) { - return CreateExternalArray(args, v8::kExternalUnsignedByteArray, - sizeof(uint8_t)); -} - - -v8::Handle Int16Array(const v8::Arguments& args) { - return CreateExternalArray(args, v8::kExternalShortArray, sizeof(int16_t)); -} - - -v8::Handle Uint16Array(const v8::Arguments& args) { - return CreateExternalArray(args, v8::kExternalUnsignedShortArray, - sizeof(uint16_t)); -} - -v8::Handle Int32Array(const v8::Arguments& args) { - return CreateExternalArray(args, v8::kExternalIntArray, sizeof(int32_t)); -} - - -v8::Handle Uint32Array(const v8::Arguments& args) { - return CreateExternalArray(args, v8::kExternalUnsignedIntArray, - sizeof(uint32_t)); -} - - -v8::Handle Float32Array(const v8::Arguments& args) { - return CreateExternalArray(args, v8::kExternalFloatArray, - sizeof(float)); // NOLINT -} - - -v8::Handle Float64Array(const v8::Arguments& args) { - return CreateExternalArray(args, v8::kExternalDoubleArray, - sizeof(double)); // NOLINT -} - - -v8::Handle PixelArray(const v8::Arguments& args) { - return CreateExternalArray(args, v8::kExternalPixelArray, sizeof(uint8_t)); -} - - // Reads a file into a v8 string. v8::Handle ReadFile(const char* name) { FILE* file = fopen(name, "rb"); @@ -625,9 +212,41 @@ v8::Handle ReadFile(const char* name) { } +// Process remaining command line arguments and execute files +int RunMain(int argc, char* argv[]) { + for (int i = 1; i < argc; i++) { + const char* str = argv[i]; + if (strcmp(str, "--shell") == 0) { + run_shell = true; + } else if (strcmp(str, "-f") == 0) { + // Ignore any -f flags for compatibility with the other stand- + // alone JavaScript engines. + continue; + } else if (strncmp(str, "--", 2) == 0) { + printf("Warning: unknown flag %s.\nTry --help for options\n", str); + } else if (strcmp(str, "-e") == 0 && i + 1 < argc) { + // Execute argument given to -e option directly. + v8::Handle file_name = v8::String::New("unnamed"); + v8::Handle source = v8::String::New(argv[++i]); + if (!ExecuteString(source, file_name, false, true)) return 1; + } else { + // Use all other arguments as names of files to load and run. + v8::Handle file_name = v8::String::New(str); + v8::Handle source = ReadFile(str); + if (source.IsEmpty()) { + printf("Error reading '%s'\n", str); + continue; + } + if (!ExecuteString(source, file_name, false, true)) return 1; + } + } + return 0; +} + + // The read-eval-execute loop of the shell. void RunShell(v8::Handle context) { - printf("V8 version %s\n", v8::V8::GetVersion()); + printf("V8 version %s [sample shell]\n", v8::V8::GetVersion()); static const int kBufferSize = 256; // Enter the execution environment before evaluating any code. v8::Context::Scope context_scope(context); diff --git a/deps/v8/src/api.h b/deps/v8/src/api.h index ce39d630a1..07723cb32c 100644 --- a/deps/v8/src/api.h +++ b/deps/v8/src/api.h @@ -406,6 +406,10 @@ class HandleScopeImplementer { spare_(NULL), call_depth_(0) { } + ~HandleScopeImplementer() { + DeleteArray(spare_); + } + // Threading support for handle data. static int ArchiveSpacePerThread(); char* RestoreThread(char* from); diff --git a/deps/v8/src/arm/full-codegen-arm.cc b/deps/v8/src/arm/full-codegen-arm.cc index 3116ca455b..d8ce956ec9 100644 --- a/deps/v8/src/arm/full-codegen-arm.cc +++ b/deps/v8/src/arm/full-codegen-arm.cc @@ -878,7 +878,7 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { __ bind(&next_test); __ Drop(1); // Switch value is no longer needed. if (default_clause == NULL) { - __ b(nested_statement.break_target()); + __ b(nested_statement.break_label()); } else { __ b(default_clause->body_target()); } @@ -892,7 +892,7 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { VisitStatements(clause->statements()); } - __ bind(nested_statement.break_target()); + __ bind(nested_statement.break_label()); PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); } @@ -1023,7 +1023,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // Load the current count to r0, load the length to r1. __ Ldrd(r0, r1, MemOperand(sp, 0 * kPointerSize)); __ cmp(r0, r1); // Compare to the array length. - __ b(hs, loop_statement.break_target()); + __ b(hs, loop_statement.break_label()); // Get the current entry of the array into register r3. __ ldr(r2, MemOperand(sp, 2 * kPointerSize)); @@ -1049,7 +1049,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ push(r3); // Current entry. __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION); __ mov(r3, Operand(r0), SetCC); - __ b(eq, loop_statement.continue_target()); + __ b(eq, loop_statement.continue_label()); // Update the 'each' property or variable from the possibly filtered // entry in register r3. @@ -1065,7 +1065,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // Generate code for the going to the next element by incrementing // the index (smi) stored on top of the stack. - __ bind(loop_statement.continue_target()); + __ bind(loop_statement.continue_label()); __ pop(r0); __ add(r0, r0, Operand(Smi::FromInt(1))); __ push(r0); @@ -1074,7 +1074,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ b(&loop); // Remove the pointers stored on the stack. - __ bind(loop_statement.break_target()); + __ bind(loop_statement.break_label()); __ Drop(5); // Exit and decrement the loop depth. diff --git a/deps/v8/src/d8.js b/deps/v8/src/d8.js index 3523e54abd..a2b9585ce8 100644 --- a/deps/v8/src/d8.js +++ b/deps/v8/src/d8.js @@ -392,14 +392,14 @@ function DebugRequest(cmd_line) { this.frameCommandToJSONRequest_('' + (Debug.State.currentFrame + 1)); break; - + case 'down': case 'do': this.request_ = this.frameCommandToJSONRequest_('' + (Debug.State.currentFrame - 1)); break; - + case 'set': case 'print': case 'p': @@ -1072,7 +1072,7 @@ DebugRequest.prototype.changeBreakpointCommandToJSONRequest_ = arg2 = 'uncaught'; } excType = arg2; - + // Check for: // en[able] [all|unc[aught]] exc[eptions] // dis[able] [all|unc[aught]] exc[eptions] @@ -1131,7 +1131,7 @@ DebugRequest.prototype.changeBreakpointCommandToJSONRequest_ = request.arguments.ignoreCount = parseInt(otherArgs); break; default: - throw new Error('Invalid arguments.'); + throw new Error('Invalid arguments.'); } } else { throw new Error('Invalid arguments.'); @@ -1252,7 +1252,7 @@ DebugRequest.prototype.lolMakeListRequest = start_index = parseInt(args[i]); // The user input start index starts at 1: if (start_index <= 0) { - throw new Error('Invalid index ' + args[i] + '.'); + throw new Error('Invalid index ' + args[i] + '.'); } start_index -= 1; is_verbose = true; @@ -2021,7 +2021,7 @@ function DebugResponseDetails(response) { } else if (body.breakOnUncaughtExceptions) { result += '* breaking on UNCAUGHT exceptions is enabled\n'; } else { - result += '* all exception breakpoints are disabled\n'; + result += '* all exception breakpoints are disabled\n'; } details.text = result; break; diff --git a/deps/v8/src/debug-debugger.js b/deps/v8/src/debug-debugger.js index 36b624e574..d254ee5696 100644 --- a/deps/v8/src/debug-debugger.js +++ b/deps/v8/src/debug-debugger.js @@ -404,7 +404,7 @@ ScriptBreakPoint.prototype.matchesScript = function(script) { return this.script_name_ == script.nameOrSourceURL(); } else if (this.type_ == Debug.ScriptBreakPointType.ScriptRegExp) { return this.script_regexp_object_.test(script.nameOrSourceURL()); - } else { + } else { throw new Error("Unexpected breakpoint type " + this.type_); } } @@ -1579,7 +1579,7 @@ DebugCommandProcessor.prototype.setBreakPointRequest_ = response.failed('Missing argument "type" or "target"'); return; } - + // Either function or script break point. var break_point_number; if (type == 'function') { @@ -1623,10 +1623,10 @@ DebugCommandProcessor.prototype.setBreakPointRequest_ = break_point_number = Debug.setScriptBreakPointByName(target, line, column, condition, groupId); - } else if (type == 'scriptId') { + } else if (type == 'scriptId') { break_point_number = Debug.setScriptBreakPointById(target, line, column, condition, groupId); - } else if (type == 'scriptRegExp') { + } else if (type == 'scriptRegExp') { break_point_number = Debug.setScriptBreakPointByRegExp(target, line, column, condition, groupId); @@ -1797,7 +1797,7 @@ DebugCommandProcessor.prototype.listBreakpointsRequest_ = function(request, resp description.type = 'scriptRegExp'; description.script_regexp = break_point.script_regexp_object().source; } else { - throw new Error("Internal error: Unexpected breakpoint type: " + break_point.type()); + throw new Error("Internal error: Unexpected breakpoint type: " + break_point.type()); } array.push(description); } @@ -1838,7 +1838,7 @@ DebugCommandProcessor.prototype.setExceptionBreakRequest_ = enabled = !Debug.isBreakOnException(); } else if (type == 'uncaught') { enabled = !Debug.isBreakOnUncaughtException(); - } + } // Pull out and check the 'enabled' argument if present: if (!IS_UNDEFINED(request.arguments.enabled)) { @@ -2022,22 +2022,22 @@ DebugCommandProcessor.prototype.evaluateRequest_ = function(request, response) { if (!IS_UNDEFINED(frame) && global) { return response.failed('Arguments "frame" and "global" are exclusive'); } - + var additional_context_object; if (additional_context) { additional_context_object = {}; for (var i = 0; i < additional_context.length; i++) { var mapping = additional_context[i]; if (!IS_STRING(mapping.name) || !IS_NUMBER(mapping.handle)) { - return response.failed("Context element #" + i + + return response.failed("Context element #" + i + " must contain name:string and handle:number"); - } + } var context_value_mirror = LookupMirror(mapping.handle); if (!context_value_mirror) { return response.failed("Context object '" + mapping.name + "' #" + mapping.handle + "# not found"); } - additional_context_object[mapping.name] = context_value_mirror.value(); + additional_context_object[mapping.name] = context_value_mirror.value(); } } diff --git a/deps/v8/src/elements.cc b/deps/v8/src/elements.cc index 9927cd5ced..70d58b31ac 100644 --- a/deps/v8/src/elements.cc +++ b/deps/v8/src/elements.cc @@ -29,6 +29,7 @@ #include "objects.h" #include "elements.h" +#include "utils.h" namespace v8 { namespace internal { @@ -70,24 +71,34 @@ bool HasKey(FixedArray* array, Object* key) { // specialization of SomeElementsAccessor methods). template class ElementsAccessorBase : public ElementsAccessor { - public: + protected: ElementsAccessorBase() { } - virtual MaybeObject* GetWithReceiver(JSObject* obj, - Object* receiver, - uint32_t index) { - BackingStoreClass* backing_store = BackingStoreClass::cast(obj->elements()); - if (index < ElementsAccessorSubclass::GetLength(backing_store)) { - return backing_store->get(index); + virtual MaybeObject* Get(FixedArrayBase* backing_store, + uint32_t key, + JSObject* obj, + Object* receiver) { + return ElementsAccessorSubclass::Get( + BackingStoreClass::cast(backing_store), key, obj, receiver); + } + + static MaybeObject* Get(BackingStoreClass* backing_store, + uint32_t key, + JSObject* obj, + Object* receiver) { + if (key < ElementsAccessorSubclass::GetCapacity(backing_store)) { + return backing_store->get(key); } - return obj->GetHeap()->the_hole_value(); + return backing_store->GetHeap()->the_hole_value(); } virtual MaybeObject* Delete(JSObject* obj, - uint32_t index, + uint32_t key, JSReceiver::DeleteMode mode) = 0; virtual MaybeObject* AddElementsToFixedArray(FixedArrayBase* from, - FixedArray* to) { + FixedArray* to, + JSObject* holder, + Object* receiver) { int len0 = to->length(); #ifdef DEBUG if (FLAG_enable_slow_asserts) { @@ -97,7 +108,7 @@ class ElementsAccessorBase : public ElementsAccessor { } #endif BackingStoreClass* backing_store = BackingStoreClass::cast(from); - int len1 = ElementsAccessorSubclass::GetCapacity(backing_store); + uint32_t len1 = ElementsAccessorSubclass::GetCapacity(backing_store); // Optimize if 'other' is empty. // We cannot optimize if 'this' is empty, as other may have holes. @@ -105,12 +116,22 @@ class ElementsAccessorBase : public ElementsAccessor { // Compute how many elements are not in other. int extra = 0; - for (int y = 0; y < len1; y++) { - Object* value; - MaybeObject* maybe_value = - ElementsAccessorSubclass::GetElementAtCapacityIndex(backing_store, y); - if (!maybe_value->ToObject(&value)) return maybe_value; - if (!value->IsTheHole() && !HasKey(to, value)) extra++; + for (uint32_t y = 0; y < len1; y++) { + if (ElementsAccessorSubclass::HasElementAtIndex(backing_store, + y, + holder, + receiver)) { + uint32_t key = + ElementsAccessorSubclass::GetKeyForIndex(backing_store, y); + MaybeObject* maybe_value = + ElementsAccessorSubclass::Get(backing_store, key, holder, receiver); + Object* value; + if (!maybe_value->ToObject(&value)) return maybe_value; + ASSERT(!value->IsTheHole()); + if (!HasKey(to, value)) { + extra++; + } + } } if (extra == 0) return to; @@ -133,32 +154,67 @@ class ElementsAccessorBase : public ElementsAccessor { } // Fill in the extra values. int index = 0; - for (int y = 0; y < len1; y++) { - MaybeObject* maybe_value = - ElementsAccessorSubclass::GetElementAtCapacityIndex(backing_store, y); - Object* value; - if (!maybe_value->ToObject(&value)) return maybe_value; - if (!value->IsTheHole() && !HasKey(to, value)) { - result->set(len0 + index, value); - index++; + for (uint32_t y = 0; y < len1; y++) { + if (ElementsAccessorSubclass::HasElementAtIndex(backing_store, + y, + holder, + receiver)) { + uint32_t key = + ElementsAccessorSubclass::GetKeyForIndex(backing_store, y); + MaybeObject* maybe_value = + ElementsAccessorSubclass::Get(backing_store, key, holder, receiver); + Object* value; + if (!maybe_value->ToObject(&value)) return maybe_value; + if (!value->IsTheHole() && !HasKey(to, value)) { + result->set(len0 + index, value); + index++; + } } } ASSERT(extra == index); return result; } - static uint32_t GetLength(BackingStoreClass* backing_store) { + protected: + static uint32_t GetCapacity(BackingStoreClass* backing_store) { return backing_store->length(); } - static uint32_t GetCapacity(BackingStoreClass* backing_store) { - return GetLength(backing_store); + virtual uint32_t GetCapacity(FixedArrayBase* backing_store) { + return ElementsAccessorSubclass::GetCapacity( + BackingStoreClass::cast(backing_store)); } - static MaybeObject* GetElementAtCapacityIndex( - BackingStoreClass* backing_store, - int index) { - return backing_store->get(index); + static bool HasElementAtIndex(BackingStoreClass* backing_store, + uint32_t index, + JSObject* holder, + Object* receiver) { + uint32_t key = + ElementsAccessorSubclass::GetKeyForIndex(backing_store, index); + MaybeObject* element = ElementsAccessorSubclass::Get(backing_store, + key, + holder, + receiver); + return !element->IsTheHole(); + } + + virtual bool HasElementAtIndex(FixedArrayBase* backing_store, + uint32_t index, + JSObject* holder, + Object* receiver) { + return ElementsAccessorSubclass::HasElementAtIndex( + BackingStoreClass::cast(backing_store), index, holder, receiver); + } + + static uint32_t GetKeyForIndex(BackingStoreClass* backing_store, + uint32_t index) { + return index; + } + + virtual uint32_t GetKeyForIndex(FixedArrayBase* backing_store, + uint32_t index) { + return ElementsAccessorSubclass::GetKeyForIndex( + BackingStoreClass::cast(backing_store), index); } private: @@ -170,7 +226,7 @@ class FastElementsAccessor : public ElementsAccessorBase { public: static MaybeObject* DeleteCommon(JSObject* obj, - uint32_t index) { + uint32_t key) { ASSERT(obj->HasFastElements() || obj->HasFastArgumentsElements()); Heap* heap = obj->GetHeap(); FixedArray* backing_store = FixedArray::cast(obj->elements()); @@ -186,8 +242,8 @@ class FastElementsAccessor obj->IsJSArray() ? Smi::cast(JSArray::cast(obj)->length())->value() : backing_store->length()); - if (index < length) { - backing_store->set_the_hole(index); + if (key < length) { + backing_store->set_the_hole(key); // If an old space backing store is larger than a certain size and // has too few used values, normalize it. // To avoid doing the check on every delete we require at least @@ -196,8 +252,8 @@ class FastElementsAccessor const int kMinLengthForSparsenessCheck = 64; if (backing_store->length() >= kMinLengthForSparsenessCheck && !heap->InNewSpace(backing_store) && - ((index > 0 && backing_store->get(index - 1) == hole) || - (index + 1 < length && backing_store->get(index + 1) == hole))) { + ((key > 0 && backing_store->get(key - 1) == hole) || + (key + 1 < length && backing_store->get(key + 1) == hole))) { int num_used = 0; for (int i = 0; i < backing_store->length(); ++i) { if (backing_store->get(i) != hole) ++num_used; @@ -213,10 +269,11 @@ class FastElementsAccessor return heap->true_value(); } + protected: virtual MaybeObject* Delete(JSObject* obj, - uint32_t index, + uint32_t key, JSReceiver::DeleteMode mode) { - return DeleteCommon(obj, index); + return DeleteCommon(obj, key); } }; @@ -224,17 +281,28 @@ class FastElementsAccessor class FastDoubleElementsAccessor : public ElementsAccessorBase { + protected: + friend class ElementsAccessorBase; + virtual MaybeObject* Delete(JSObject* obj, - uint32_t index, + uint32_t key, JSReceiver::DeleteMode mode) { int length = obj->IsJSArray() ? Smi::cast(JSArray::cast(obj)->length())->value() : FixedDoubleArray::cast(obj->elements())->length(); - if (index < static_cast(length)) { - FixedDoubleArray::cast(obj->elements())->set_the_hole(index); + if (key < static_cast(length)) { + FixedDoubleArray::cast(obj->elements())->set_the_hole(key); } return obj->GetHeap()->true_value(); } + + static bool HasElementAtIndex(FixedDoubleArray* backing_store, + uint32_t index, + JSObject* holder, + Object* receiver) { + return !backing_store->is_the_hole(index); + } }; @@ -244,20 +312,23 @@ template { - public: - virtual MaybeObject* GetWithReceiver(JSObject* obj, - Object* receiver, - uint32_t index) { - ExternalArray* backing_store = ExternalArray::cast(obj->elements()); - if (index < ExternalElementsAccessorSubclass::GetLength(backing_store)) { - return backing_store->get(index); + protected: + friend class ElementsAccessorBase; + + static MaybeObject* Get(ExternalArray* backing_store, + uint32_t key, + JSObject* obj, + Object* receiver) { + if (key < ExternalElementsAccessorSubclass::GetCapacity(backing_store)) { + return backing_store->get(key); } else { - return obj->GetHeap()->undefined_value(); + return backing_store->GetHeap()->undefined_value(); } } virtual MaybeObject* Delete(JSObject* obj, - uint32_t index, + uint32_t key, JSReceiver::DeleteMode mode) { // External arrays always ignore deletes. return obj->GetHeap()->true_value(); @@ -323,30 +394,8 @@ class DictionaryElementsAccessor : public ElementsAccessorBase { public: - static MaybeObject* GetNumberDictionaryElement( - JSObject* obj, - Object* receiver, - NumberDictionary* backing_store, - uint32_t index) { - int entry = backing_store->FindEntry(index); - if (entry != NumberDictionary::kNotFound) { - Object* element = backing_store->ValueAt(entry); - PropertyDetails details = backing_store->DetailsAt(entry); - if (details.type() == CALLBACKS) { - return obj->GetElementWithCallback(receiver, - element, - index, - obj); - } else { - return element; - } - } - return obj->GetHeap()->the_hole_value(); - } - - static MaybeObject* DeleteCommon(JSObject* obj, - uint32_t index, + uint32_t key, JSReceiver::DeleteMode mode) { Isolate* isolate = obj->GetIsolate(); Heap* heap = isolate->heap(); @@ -357,11 +406,11 @@ class DictionaryElementsAccessor backing_store = FixedArray::cast(backing_store->get(1)); } NumberDictionary* dictionary = NumberDictionary::cast(backing_store); - int entry = dictionary->FindEntry(index); + int entry = dictionary->FindEntry(key); if (entry != NumberDictionary::kNotFound) { Object* result = dictionary->DeleteProperty(entry, mode); if (result == heap->true_value()) { - MaybeObject* maybe_elements = dictionary->Shrink(index); + MaybeObject* maybe_elements = dictionary->Shrink(key); FixedArray* new_elements = NULL; if (!maybe_elements->To(&new_elements)) { return maybe_elements; @@ -378,7 +427,7 @@ class DictionaryElementsAccessor // throws an exception. HandleScope scope(isolate); Handle holder(obj); - Handle name = isolate->factory()->NewNumberFromUint(index); + Handle name = isolate->factory()->NewNumberFromUint(key); Handle args[2] = { name, holder }; Handle error = isolate->factory()->NewTypeError("strict_delete_property", @@ -389,32 +438,40 @@ class DictionaryElementsAccessor return heap->true_value(); } + protected: + friend class ElementsAccessorBase; + virtual MaybeObject* Delete(JSObject* obj, - uint32_t index, + uint32_t key, JSReceiver::DeleteMode mode) { - return DeleteCommon(obj, index, mode); - } - - virtual MaybeObject* GetWithReceiver(JSObject* obj, - Object* receiver, - uint32_t index) { - return GetNumberDictionaryElement(obj, - receiver, - obj->element_dictionary(), - index); + return DeleteCommon(obj, key, mode); } - static uint32_t GetCapacity(NumberDictionary* dict) { - return dict->Capacity(); + static MaybeObject* Get(NumberDictionary* backing_store, + uint32_t key, + JSObject* obj, + Object* receiver) { + int entry = backing_store->FindEntry(key); + if (entry != NumberDictionary::kNotFound) { + Object* element = backing_store->ValueAt(entry); + PropertyDetails details = backing_store->DetailsAt(entry); + if (details.type() == CALLBACKS) { + return obj->GetElementWithCallback(receiver, + element, + key, + obj); + } else { + return element; + } + } + return obj->GetHeap()->the_hole_value(); } - static MaybeObject* GetElementAtCapacityIndex(NumberDictionary* dict, - int index) { - if (dict->IsKey(dict->KeyAt(index))) { - return dict->ValueAt(index); - } else { - return dict->GetHeap()->the_hole_value(); - } + static uint32_t GetKeyForIndex(NumberDictionary* dict, + uint32_t index) { + Object* key = dict->KeyAt(index); + return Smi::cast(key)->value(); } }; @@ -422,15 +479,16 @@ class DictionaryElementsAccessor class NonStrictArgumentsElementsAccessor : public ElementsAccessorBase { - public: - virtual MaybeObject* GetWithReceiver(JSObject* obj, - Object* receiver, - uint32_t index) { - FixedArray* parameter_map = FixedArray::cast(obj->elements()); - uint32_t length = parameter_map->length(); - Object* probe = - (index < length - 2) ? parameter_map->get(index + 2) : NULL; - if (probe != NULL && !probe->IsTheHole()) { + protected: + friend class ElementsAccessorBase; + + static MaybeObject* Get(FixedArray* parameter_map, + uint32_t key, + JSObject* obj, + Object* receiver) { + Object* probe = GetParameterMapArg(parameter_map, key); + if (!probe->IsTheHole()) { Context* context = Context::cast(parameter_map->get(0)); int context_index = Smi::cast(probe)->value(); ASSERT(!context->get(context_index)->IsTheHole()); @@ -438,56 +496,105 @@ class NonStrictArgumentsElementsAccessor } else { // Object is not mapped, defer to the arguments. FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); - if (arguments->IsDictionary()) { - return DictionaryElementsAccessor::GetNumberDictionaryElement( - obj, - receiver, - NumberDictionary::cast(arguments), - index); - } else if (index < static_cast(arguments->length())) { - return arguments->get(index); - } + return ElementsAccessor::ForArray(arguments)->Get(arguments, + key, + obj, + receiver); } - return obj->GetHeap()->the_hole_value(); } virtual MaybeObject* Delete(JSObject* obj, - uint32_t index, + uint32_t key + , JSReceiver::DeleteMode mode) { FixedArray* parameter_map = FixedArray::cast(obj->elements()); - uint32_t length = parameter_map->length(); - Object* probe = - index < (length - 2) ? parameter_map->get(index + 2) : NULL; - if (probe != NULL && !probe->IsTheHole()) { + Object* probe = GetParameterMapArg(parameter_map, key); + if (!probe->IsTheHole()) { // TODO(kmillikin): We could check if this was the last aliased // parameter, and revert to normal elements in that case. That // would enable GC of the context. - parameter_map->set_the_hole(index + 2); + parameter_map->set_the_hole(key + 2); } else { FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); if (arguments->IsDictionary()) { - return DictionaryElementsAccessor::DeleteCommon(obj, index, mode); + return DictionaryElementsAccessor::DeleteCommon(obj, key, mode); } else { - return FastElementsAccessor::DeleteCommon(obj, index); + return FastElementsAccessor::DeleteCommon(obj, key); } } return obj->GetHeap()->true_value(); } - static uint32_t GetCapacity(FixedArray* obj) { - // TODO(danno): Return max of parameter map length or backing store - // capacity. - return 0; + static uint32_t GetCapacity(FixedArray* parameter_map) { + FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1)); + return Max(static_cast(parameter_map->length() - 2), + ForArray(arguments)->GetCapacity(arguments)); } - static MaybeObject* GetElementAtCapacityIndex(FixedArray* obj, int index) { - // TODO(danno): Return either value from parameter map of backing - // store value at index. - return obj->GetHeap()->the_hole_value(); + static uint32_t GetKeyForIndex(FixedArray* dict, + uint32_t index) { + return index; + } + + static bool HasElementAtIndex(FixedArray* parameter_map, + uint32_t index, + JSObject* holder, + Object* receiver) { + Object* probe = GetParameterMapArg(parameter_map, index); + if (!probe->IsTheHole()) { + return true; + } else { + FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1)); + ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments); + return !accessor->Get(arguments, index, holder, receiver)->IsTheHole(); + } + } + + private: + static Object* GetParameterMapArg(FixedArray* parameter_map, + uint32_t key) { + uint32_t length = parameter_map->length(); + return key < (length - 2 ) + ? parameter_map->get(key + 2) + : parameter_map->GetHeap()->the_hole_value(); } }; +ElementsAccessor* ElementsAccessor::ForArray(FixedArrayBase* array) { + switch (array->map()->instance_type()) { + case FIXED_ARRAY_TYPE: + if (array->IsDictionary()) { + return elements_accessors_[JSObject::DICTIONARY_ELEMENTS]; + } else { + return elements_accessors_[JSObject::FAST_ELEMENTS]; + } + case EXTERNAL_BYTE_ARRAY_TYPE: + return elements_accessors_[JSObject::EXTERNAL_BYTE_ELEMENTS]; + case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE: + return elements_accessors_[JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS]; + case EXTERNAL_SHORT_ARRAY_TYPE: + return elements_accessors_[JSObject::EXTERNAL_SHORT_ELEMENTS]; + case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE: + return elements_accessors_[JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS]; + case EXTERNAL_INT_ARRAY_TYPE: + return elements_accessors_[JSObject::EXTERNAL_INT_ELEMENTS]; + case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE: + return elements_accessors_[JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS]; + case EXTERNAL_FLOAT_ARRAY_TYPE: + return elements_accessors_[JSObject::EXTERNAL_FLOAT_ELEMENTS]; + case EXTERNAL_DOUBLE_ARRAY_TYPE: + return elements_accessors_[JSObject::EXTERNAL_DOUBLE_ELEMENTS]; + case EXTERNAL_PIXEL_ARRAY_TYPE: + return elements_accessors_[JSObject::EXTERNAL_PIXEL_ELEMENTS]; + default: + UNREACHABLE(); + return NULL; + break; + } +} + + void ElementsAccessor::InitializeOncePerProcess() { static struct ConcreteElementsAccessors { FastElementsAccessor fast_elements_handler; diff --git a/deps/v8/src/elements.h b/deps/v8/src/elements.h index 74e4ad6659..3eae303ed1 100644 --- a/deps/v8/src/elements.h +++ b/deps/v8/src/elements.h @@ -39,16 +39,19 @@ class ElementsAccessor { public: ElementsAccessor() { } virtual ~ElementsAccessor() { } - virtual MaybeObject* GetWithReceiver(JSObject* obj, - Object* receiver, - uint32_t index) = 0; + virtual MaybeObject* Get(FixedArrayBase* backing_store, + uint32_t key, + JSObject* holder, + Object* receiver) = 0; - virtual MaybeObject* Delete(JSObject* obj, - uint32_t index, + virtual MaybeObject* Delete(JSObject* holder, + uint32_t key, JSReceiver::DeleteMode mode) = 0; virtual MaybeObject* AddElementsToFixedArray(FixedArrayBase* from, - FixedArray* to) = 0; + FixedArray* to, + JSObject* holder, + Object* receiver) = 0; // Returns a shared ElementsAccessor for the specified ElementsKind. static ElementsAccessor* ForKind(JSObject::ElementsKind elements_kind) { @@ -56,8 +59,31 @@ class ElementsAccessor { return elements_accessors_[elements_kind]; } + static ElementsAccessor* ForArray(FixedArrayBase* array); + static void InitializeOncePerProcess(); + protected: + friend class NonStrictArgumentsElementsAccessor; + + virtual uint32_t GetCapacity(FixedArrayBase* backing_store) = 0; + + virtual bool HasElementAtIndex(FixedArrayBase* backing_store, + uint32_t index, + JSObject* holder, + Object* receiver) = 0; + + // Element handlers distinguish between indexes and keys when the manipulate + // elements. Indexes refer to elements in terms of their location in the + // underlying storage's backing store representation, and are between 0 + // GetCapacity. Keys refer to elements in terms of the value that would be + // specific in JavaScript to access the element. In most implementations, keys + // are equivalent to indexes, and GetKeyForIndex returns the same value it is + // passed. In the NumberDictionary ElementsAccessor, GetKeyForIndex maps the + // index to a key using the KeyAt method on the NumberDictionary. + virtual uint32_t GetKeyForIndex(FixedArrayBase* backing_store, + uint32_t index) = 0; + private: static ElementsAccessor** elements_accessors_; diff --git a/deps/v8/src/full-codegen.cc b/deps/v8/src/full-codegen.cc index 732a8fe7d0..fc7b6899bc 100644 --- a/deps/v8/src/full-codegen.cc +++ b/deps/v8/src/full-codegen.cc @@ -862,7 +862,7 @@ void FullCodeGenerator::VisitBlock(Block* stmt) { PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); VisitStatements(stmt->statements()); scope_ = saved_scope; - __ bind(nested_statement.break_target()); + __ bind(nested_statement.break_label()); PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); } @@ -932,8 +932,7 @@ void FullCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) { context_register()); } - Iteration* loop = current->AsIteration(); - __ jmp(loop->continue_target()); + __ jmp(current->AsIteration()->continue_label()); } @@ -961,8 +960,7 @@ void FullCodeGenerator::VisitBreakStatement(BreakStatement* stmt) { context_register()); } - Breakable* target = current->AsBreakable(); - __ jmp(target->break_target()); + __ jmp(current->AsBreakable()->break_label()); } @@ -1030,12 +1028,12 @@ void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { // Record the position of the do while condition and make sure it is // possible to break on the condition. - __ bind(loop_statement.continue_target()); + __ bind(loop_statement.continue_label()); PrepareForBailoutForId(stmt->ContinueId(), NO_REGISTERS); SetExpressionPosition(stmt->cond(), stmt->condition_position()); VisitForControl(stmt->cond(), &stack_check, - loop_statement.break_target(), + loop_statement.break_label(), &stack_check); // Check stack before looping. @@ -1045,7 +1043,7 @@ void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { __ jmp(&body); PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); - __ bind(loop_statement.break_target()); + __ bind(loop_statement.break_label()); decrement_loop_depth(); } @@ -1066,7 +1064,7 @@ void FullCodeGenerator::VisitWhileStatement(WhileStatement* stmt) { // Emit the statement position here as this is where the while // statement code starts. - __ bind(loop_statement.continue_target()); + __ bind(loop_statement.continue_label()); SetStatementPosition(stmt); // Check stack before looping. @@ -1075,11 +1073,11 @@ void FullCodeGenerator::VisitWhileStatement(WhileStatement* stmt) { __ bind(&test); VisitForControl(stmt->cond(), &body, - loop_statement.break_target(), - loop_statement.break_target()); + loop_statement.break_label(), + loop_statement.break_label()); PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); - __ bind(loop_statement.break_target()); + __ bind(loop_statement.break_label()); decrement_loop_depth(); } @@ -1102,7 +1100,7 @@ void FullCodeGenerator::VisitForStatement(ForStatement* stmt) { Visit(stmt->body()); PrepareForBailoutForId(stmt->ContinueId(), NO_REGISTERS); - __ bind(loop_statement.continue_target()); + __ bind(loop_statement.continue_label()); SetStatementPosition(stmt); if (stmt->next() != NULL) { Visit(stmt->next()); @@ -1119,14 +1117,14 @@ void FullCodeGenerator::VisitForStatement(ForStatement* stmt) { if (stmt->cond() != NULL) { VisitForControl(stmt->cond(), &body, - loop_statement.break_target(), - loop_statement.break_target()); + loop_statement.break_label(), + loop_statement.break_label()); } else { __ jmp(&body); } PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); - __ bind(loop_statement.break_target()); + __ bind(loop_statement.break_label()); decrement_loop_depth(); } @@ -1144,7 +1142,7 @@ void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { // to introduce a new scope to bind the catch variable and to remove // that scope again afterwards. - Label try_handler_setup, catch_entry, done; + Label try_handler_setup, done; __ Call(&try_handler_setup); // Try handler code, exception in result register. @@ -1170,12 +1168,13 @@ void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { // Try block code. Sets up the exception handler chain. __ bind(&try_handler_setup); { - TryCatch try_block(this, &catch_entry); + const int delta = StackHandlerConstants::kSize / kPointerSize; + TryCatch try_block(this); __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER); - increment_stack_height(StackHandlerConstants::kSize / kPointerSize); + increment_stack_height(delta); Visit(stmt->try_block()); __ PopTryHandler(); - decrement_stack_height(StackHandlerConstants::kSize / kPointerSize); + decrement_stack_height(delta); } __ bind(&done); } @@ -1208,9 +1207,6 @@ void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { Label finally_entry; Label try_handler_setup; const int original_stack_height = stack_height(); - const int finally_block_stack_height = original_stack_height + 2; - const int try_block_stack_height = original_stack_height + 5; - STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); // Setup the try-handler chain. Use a call to // Jump to try-handler setup and try-block code. Use call to put try-handler @@ -1219,9 +1215,9 @@ void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { // Try handler code. Return address of call is pushed on handler stack. { // This code is only executed during stack-handler traversal when an - // exception is thrown. The execption is in the result register, which + // exception is thrown. The exception is in the result register, which // is retained by the finally block. - // Call the finally block and then rethrow the exception. + // Call the finally block and then rethrow the exception if it returns. __ Call(&finally_entry); __ push(result_register()); __ CallRuntime(Runtime::kReThrow, 1); @@ -1232,7 +1228,7 @@ void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { // Finally block implementation. Finally finally_block(this); EnterFinallyBlock(); - set_stack_height(finally_block_stack_height); + set_stack_height(original_stack_height + Finally::kElementCount); Visit(stmt->finally_block()); ExitFinallyBlock(); // Return to the calling code. } @@ -1240,9 +1236,10 @@ void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { __ bind(&try_handler_setup); { // Setup try handler (stack pointer registers). + const int delta = StackHandlerConstants::kSize / kPointerSize; TryFinally try_block(this, &finally_entry); __ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER); - set_stack_height(try_block_stack_height); + set_stack_height(original_stack_height + delta); Visit(stmt->try_block()); __ PopTryHandler(); set_stack_height(original_stack_height); diff --git a/deps/v8/src/full-codegen.h b/deps/v8/src/full-codegen.h index 2fc0553661..0ed26a149e 100644 --- a/deps/v8/src/full-codegen.h +++ b/deps/v8/src/full-codegen.h @@ -111,10 +111,7 @@ class FullCodeGenerator: public AstVisitor { private: class Breakable; class Iteration; - class TryCatch; - class TryFinally; - class Finally; - class ForIn; + class TestContext; class NestedStatement BASE_EMBEDDED { @@ -132,10 +129,6 @@ class FullCodeGenerator: public AstVisitor { virtual Breakable* AsBreakable() { return NULL; } virtual Iteration* AsIteration() { return NULL; } - virtual TryCatch* AsTryCatch() { return NULL; } - virtual TryFinally* AsTryFinally() { return NULL; } - virtual Finally* AsFinally() { return NULL; } - virtual ForIn* AsForIn() { return NULL; } virtual bool IsContinueTarget(Statement* target) { return false; } virtual bool IsBreakTarget(Statement* target) { return false; } @@ -158,110 +151,102 @@ class FullCodeGenerator: public AstVisitor { DISALLOW_COPY_AND_ASSIGN(NestedStatement); }; + // A breakable statement such as a block. class Breakable : public NestedStatement { public: - Breakable(FullCodeGenerator* codegen, - BreakableStatement* break_target) - : NestedStatement(codegen), - target_(break_target) {} + Breakable(FullCodeGenerator* codegen, BreakableStatement* statement) + : NestedStatement(codegen), statement_(statement) { + } virtual ~Breakable() {} + virtual Breakable* AsBreakable() { return this; } - virtual bool IsBreakTarget(Statement* statement) { - return target_ == statement; + virtual bool IsBreakTarget(Statement* target) { + return statement() == target; } - BreakableStatement* statement() { return target_; } - Label* break_target() { return &break_target_label_; } + + BreakableStatement* statement() { return statement_; } + Label* break_label() { return &break_label_; } + private: - BreakableStatement* target_; - Label break_target_label_; - DISALLOW_COPY_AND_ASSIGN(Breakable); + BreakableStatement* statement_; + Label break_label_; }; + // An iteration statement such as a while, for, or do loop. class Iteration : public Breakable { public: - Iteration(FullCodeGenerator* codegen, - IterationStatement* iteration_statement) - : Breakable(codegen, iteration_statement) {} + Iteration(FullCodeGenerator* codegen, IterationStatement* statement) + : Breakable(codegen, statement) { + } virtual ~Iteration() {} + virtual Iteration* AsIteration() { return this; } - virtual bool IsContinueTarget(Statement* statement) { - return this->statement() == statement; + virtual bool IsContinueTarget(Statement* target) { + return statement() == target; } - Label* continue_target() { return &continue_target_label_; } + + Label* continue_label() { return &continue_label_; } + private: - Label continue_target_label_; - DISALLOW_COPY_AND_ASSIGN(Iteration); + Label continue_label_; }; - // The environment inside the try block of a try/catch statement. + // The try block of a try/catch statement. class TryCatch : public NestedStatement { public: - explicit TryCatch(FullCodeGenerator* codegen, Label* catch_entry) - : NestedStatement(codegen), catch_entry_(catch_entry) { } + explicit TryCatch(FullCodeGenerator* codegen) : NestedStatement(codegen) { + } virtual ~TryCatch() {} - virtual TryCatch* AsTryCatch() { return this; } - Label* catch_entry() { return catch_entry_; } + virtual NestedStatement* Exit(int* stack_depth, int* context_length); - private: - Label* catch_entry_; - DISALLOW_COPY_AND_ASSIGN(TryCatch); }; - // The environment inside the try block of a try/finally statement. + // The try block of a try/finally statement. class TryFinally : public NestedStatement { public: - explicit TryFinally(FullCodeGenerator* codegen, Label* finally_entry) - : NestedStatement(codegen), finally_entry_(finally_entry) { } + TryFinally(FullCodeGenerator* codegen, Label* finally_entry) + : NestedStatement(codegen), finally_entry_(finally_entry) { + } virtual ~TryFinally() {} - virtual TryFinally* AsTryFinally() { return this; } - Label* finally_entry() { return finally_entry_; } + virtual NestedStatement* Exit(int* stack_depth, int* context_length); + private: Label* finally_entry_; - DISALLOW_COPY_AND_ASSIGN(TryFinally); }; - // A FinallyEnvironment represents being inside a finally block. - // Abnormal termination of the finally block needs to clean up - // the block's parameters from the stack. + // The finally block of a try/finally statement. class Finally : public NestedStatement { public: + static const int kElementCount = 2; + explicit Finally(FullCodeGenerator* codegen) : NestedStatement(codegen) { } virtual ~Finally() {} - virtual Finally* AsFinally() { return this; } + virtual NestedStatement* Exit(int* stack_depth, int* context_length) { - *stack_depth += kFinallyStackElementCount; + *stack_depth += kElementCount; return previous_; } - private: - // Number of extra stack slots occupied during a finally block. - static const int kFinallyStackElementCount = 2; - DISALLOW_COPY_AND_ASSIGN(Finally); }; - // A ForInEnvironment represents being inside a for-in loop. - // Abnormal termination of the for-in block needs to clean up - // the block's temporary storage from the stack. + // The body of a for/in loop. class ForIn : public Iteration { public: - ForIn(FullCodeGenerator* codegen, - ForInStatement* statement) - : Iteration(codegen, statement) { } + static const int kElementCount = 5; + + ForIn(FullCodeGenerator* codegen, ForInStatement* statement) + : Iteration(codegen, statement) { + } virtual ~ForIn() {} - virtual ForIn* AsForIn() { return this; } + virtual NestedStatement* Exit(int* stack_depth, int* context_length) { - *stack_depth += kForInStackElementCount; + *stack_depth += kElementCount; return previous_; } - private: - static const int kForInStackElementCount = 5; - DISALLOW_COPY_AND_ASSIGN(ForIn); }; - // A WithOrCatch represents being inside the body of a with or catch - // statement. Exiting the body needs to remove a link from the context - // chain. + // The body of a with or catch. class WithOrCatch : public NestedStatement { public: explicit WithOrCatch(FullCodeGenerator* codegen) diff --git a/deps/v8/src/ia32/full-codegen-ia32.cc b/deps/v8/src/ia32/full-codegen-ia32.cc index bb75b1e6ac..07fd725823 100644 --- a/deps/v8/src/ia32/full-codegen-ia32.cc +++ b/deps/v8/src/ia32/full-codegen-ia32.cc @@ -875,7 +875,7 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { __ bind(&next_test); __ Drop(1); // Switch value is no longer needed. if (default_clause == NULL) { - __ jmp(nested_statement.break_target()); + __ jmp(nested_statement.break_label()); } else { __ jmp(default_clause->body_target()); } @@ -890,7 +890,7 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { VisitStatements(clause->statements()); } - __ bind(nested_statement.break_target()); + __ bind(nested_statement.break_label()); PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); } @@ -1006,12 +1006,13 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ push(eax); // Fixed array length (as smi). __ push(Immediate(Smi::FromInt(0))); // Initial index. - increment_stack_height(4); + // 1 ~ The object has already been pushed. + increment_stack_height(ForIn::kElementCount - 1); // Generate code for doing the condition check. __ bind(&loop); __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index. __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length. - __ j(above_equal, loop_statement.break_target()); + __ j(above_equal, loop_statement.break_label()); // Get the current entry of the array into register ebx. __ mov(ebx, Operand(esp, 2 * kPointerSize)); @@ -1035,7 +1036,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ push(ebx); // Current entry. __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION); __ test(eax, Operand(eax)); - __ j(equal, loop_statement.continue_target()); + __ j(equal, loop_statement.continue_label()); __ mov(ebx, Operand(eax)); // Update the 'each' property or variable from the possibly filtered @@ -1052,17 +1053,17 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // Generate code for going to the next element by incrementing the // index (smi) stored on top of the stack. - __ bind(loop_statement.continue_target()); + __ bind(loop_statement.continue_label()); __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1))); EmitStackCheck(stmt); __ jmp(&loop); // Remove the pointers stored on the stack. - __ bind(loop_statement.break_target()); + __ bind(loop_statement.break_label()); __ add(Operand(esp), Immediate(5 * kPointerSize)); - decrement_stack_height(5); + decrement_stack_height(ForIn::kElementCount); // Exit and decrement the loop depth. __ bind(&exit); decrement_loop_depth(); diff --git a/deps/v8/src/ia32/macro-assembler-ia32.cc b/deps/v8/src/ia32/macro-assembler-ia32.cc index 04e6cde4ed..9df5cad915 100644 --- a/deps/v8/src/ia32/macro-assembler-ia32.cc +++ b/deps/v8/src/ia32/macro-assembler-ia32.cc @@ -69,8 +69,8 @@ void MacroAssembler::RecordWriteHelper(Register object, // Compute number of region covering addr. See Page::GetRegionNumberForAddress // method for more details. - and_(addr, Page::kPageAlignmentMask); shr(addr, Page::kRegionSizeLog2); + and_(addr, Page::kPageAlignmentMask >> Page::kRegionSizeLog2); // Set dirty mark for region. // Bit tests with a memory operand should be avoided on Intel processors, diff --git a/deps/v8/src/isolate.cc b/deps/v8/src/isolate.cc index eae812bcd9..09cbc8a1e6 100644 --- a/deps/v8/src/isolate.cc +++ b/deps/v8/src/isolate.cc @@ -1335,6 +1335,7 @@ void Isolate::ThreadDataTable::Remove(PerIsolateThreadData* data) { if (list_ == data) list_ = data->next_; if (data->next_ != NULL) data->next_->prev_ = data->prev_; if (data->prev_ != NULL) data->prev_->next_ = data->next_; + delete data; } @@ -1536,6 +1537,9 @@ Isolate::~Isolate() { // Has to be called while counters_ are still alive. zone_.DeleteKeptSegment(); + delete[] assembler_spare_buffer_; + assembler_spare_buffer_ = NULL; + delete unicode_cache_; unicode_cache_ = NULL; @@ -1569,6 +1573,8 @@ Isolate::~Isolate() { handle_scope_implementer_ = NULL; delete break_access_; break_access_ = NULL; + delete debugger_access_; + debugger_access_ = NULL; delete compilation_cache_; compilation_cache_ = NULL; diff --git a/deps/v8/src/json.js b/deps/v8/src/json.js index 6c984a157d..8fd410fa4d 100644 --- a/deps/v8/src/json.js +++ b/deps/v8/src/json.js @@ -237,7 +237,7 @@ function BasicSerializeArray(value, stack, builder) { } } stack.pop(); - builder.push("]"); + builder.push("]"); } diff --git a/deps/v8/src/messages.js b/deps/v8/src/messages.js index 58c9a53025..8ea31eaadb 100644 --- a/deps/v8/src/messages.js +++ b/deps/v8/src/messages.js @@ -1,4 +1,4 @@ -// Copyright 2006-2008 the V8 project authors. All rights reserved. +// Copyright 2011 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: @@ -57,7 +57,7 @@ function FormatString(format, message) { for (var i = 0; i < format.length; i++) { var str = format[i]; for (arg_num = 0; arg_num < kReplacementMarkers.length; arg_num++) { - if (format[i] !== kReplacementMarkers[arg_num]) continue; + if (str !== kReplacementMarkers[arg_num]) continue; try { str = ToDetailString(args[arg_num]); } catch (e) { @@ -100,7 +100,8 @@ function ToStringCheckErrorObject(obj) { function ToDetailString(obj) { - if (obj != null && IS_OBJECT(obj) && obj.toString === $Object.prototype.toString) { + if (obj != null && IS_OBJECT(obj) && + obj.toString === $Object.prototype.toString) { var constructor = obj.constructor; if (!constructor) return ToStringCheckErrorObject(obj); var constructorName = constructor.name; @@ -207,7 +208,7 @@ function FormatMessage(message) { stack_overflow: ["Maximum call stack size exceeded"], // SyntaxError unable_to_parse: ["Parse error"], - duplicate_regexp_flag: ["Duplicate RegExp flag ", "%0"], + invalid_regexp_flags: ["Invalid flags supplied to RegExp constructor '", "%0", "'"], invalid_regexp: ["Invalid RegExp pattern /", "%0", "/"], illegal_break: ["Illegal break statement"], illegal_continue: ["Illegal continue statement"], @@ -560,6 +561,7 @@ function SourceLocation(script, position, line, column, start, end) { this.end = end; } +SourceLocation.prototype.__proto__ = null; const kLineLengthLimit = 78; @@ -649,6 +651,7 @@ function SourceSlice(script, from_line, to_line, from_position, to_position) { this.to_position = to_position; } +SourceSlice.prototype.__proto__ = null; /** * Get the source text for a SourceSlice @@ -716,23 +719,28 @@ function CallSite(receiver, fun, pos) { this.pos = pos; } +CallSite.prototype.__proto__ = null; + CallSite.prototype.getThis = function () { return this.receiver; }; CallSite.prototype.getTypeName = function () { var constructor = this.receiver.constructor; - if (!constructor) + if (!constructor) { return %_CallFunction(this.receiver, ObjectToString); + } var constructorName = constructor.name; - if (!constructorName) + if (!constructorName) { return %_CallFunction(this.receiver, ObjectToString); + } return constructorName; }; CallSite.prototype.isToplevel = function () { - if (this.receiver == null) + if (this.receiver == null) { return true; + } return IS_GLOBAL(this.receiver); }; @@ -765,8 +773,9 @@ CallSite.prototype.getFunctionName = function () { } // Maybe this is an evaluation? var script = %FunctionGetScript(this.fun); - if (script && script.compilation_type == COMPILATION_TYPE_EVAL) + if (script && script.compilation_type == COMPILATION_TYPE_EVAL) { return "eval"; + } return null; }; @@ -788,13 +797,15 @@ CallSite.prototype.getMethodName = function () { this.receiver.__lookupSetter__(prop) === this.fun || (!this.receiver.__lookupGetter__(prop) && this.receiver[prop] === this.fun)) { // If we find more than one match bail out to avoid confusion. - if (name) + if (name) { return null; + } name = prop; } } - if (name) + if (name) { return name; + } return null; }; @@ -804,8 +815,9 @@ CallSite.prototype.getFileName = function () { }; CallSite.prototype.getLineNumber = function () { - if (this.pos == -1) + if (this.pos == -1) { return null; + } var script = %FunctionGetScript(this.fun); var location = null; if (script) { @@ -815,8 +827,9 @@ CallSite.prototype.getLineNumber = function () { }; CallSite.prototype.getColumnNumber = function () { - if (this.pos == -1) + if (this.pos == -1) { return null; + } var script = %FunctionGetScript(this.fun); var location = null; if (script) { @@ -836,15 +849,17 @@ CallSite.prototype.getPosition = function () { CallSite.prototype.isConstructor = function () { var constructor = this.receiver ? this.receiver.constructor : null; - if (!constructor) + if (!constructor) { return false; + } return this.fun === constructor; }; function FormatEvalOrigin(script) { var sourceURL = script.nameOrSourceURL(); - if (sourceURL) + if (sourceURL) { return sourceURL; + } var eval_origin = "eval at "; if (script.eval_from_function_name) { @@ -1042,8 +1057,9 @@ function DefineError(f) { function captureStackTrace(obj, cons_opt) { var stackTraceLimit = $Error.stackTraceLimit; if (!stackTraceLimit || !IS_NUMBER(stackTraceLimit)) return; - if (stackTraceLimit < 0 || stackTraceLimit > 10000) + if (stackTraceLimit < 0 || stackTraceLimit > 10000) { stackTraceLimit = 10000; + } var raw_stack = %CollectStackTrace(cons_opt ? cons_opt : captureStackTrace, stackTraceLimit); @@ -1117,8 +1133,10 @@ function errorToString() { } catch(e) { // If this error message was encountered already return the empty // string for it instead of recursively formatting it. - if (isCyclicErrorMarker(e)) return ''; - else throw e; + if (isCyclicErrorMarker(e)) { + return ''; + } + throw e; } } diff --git a/deps/v8/src/mips/full-codegen-mips.cc b/deps/v8/src/mips/full-codegen-mips.cc index d8909c9ddd..e1a23b4ed2 100644 --- a/deps/v8/src/mips/full-codegen-mips.cc +++ b/deps/v8/src/mips/full-codegen-mips.cc @@ -747,9 +747,9 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable, __ li(a2, Operand(variable->name())); // Declaration nodes are always introduced in one of two modes. ASSERT(mode == Variable::VAR || - mode == Variable::CONST); - PropertyAttributes attr = - (mode == Variable::VAR) ? NONE : READ_ONLY; + mode == Variable::CONST || + mode == Variable::LET); + PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE; __ li(a1, Operand(Smi::FromInt(attr))); // Push initial value, if any. // Note: For variables we must not push an initial value (such as @@ -886,7 +886,7 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { __ bind(&next_test); __ Drop(1); // Switch value is no longer needed. if (default_clause == NULL) { - __ Branch(nested_statement.break_target()); + __ Branch(nested_statement.break_label()); } else { __ Branch(default_clause->body_target()); } @@ -900,7 +900,7 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { VisitStatements(clause->statements()); } - __ bind(nested_statement.break_target()); + __ bind(nested_statement.break_label()); PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); } @@ -1026,7 +1026,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // Load the current count to a0, load the length to a1. __ lw(a0, MemOperand(sp, 0 * kPointerSize)); __ lw(a1, MemOperand(sp, 1 * kPointerSize)); - __ Branch(loop_statement.break_target(), hs, a0, Operand(a1)); + __ Branch(loop_statement.break_label(), hs, a0, Operand(a1)); // Get the current entry of the array into register a3. __ lw(a2, MemOperand(sp, 2 * kPointerSize)); @@ -1053,7 +1053,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ push(a3); // Current entry. __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION); __ mov(a3, result_register()); - __ Branch(loop_statement.continue_target(), eq, a3, Operand(zero_reg)); + __ Branch(loop_statement.continue_label(), eq, a3, Operand(zero_reg)); // Update the 'each' property or variable from the possibly filtered // entry in register a3. @@ -1069,7 +1069,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // Generate code for the going to the next element by incrementing // the index (smi) stored on top of the stack. - __ bind(loop_statement.continue_target()); + __ bind(loop_statement.continue_label()); __ pop(a0); __ Addu(a0, a0, Operand(Smi::FromInt(1))); __ push(a0); @@ -1078,7 +1078,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ Branch(&loop); // Remove the pointers stored on the stack. - __ bind(loop_statement.break_target()); + __ bind(loop_statement.break_label()); __ Drop(5); // Exit and decrement the loop depth. diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc index 337dd65db0..1b29071324 100644 --- a/deps/v8/src/objects.cc +++ b/deps/v8/src/objects.cc @@ -656,10 +656,11 @@ MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) { } if (js_object->elements() != heap->empty_fixed_array()) { - MaybeObject* result = js_object->GetElementsAccessor()->GetWithReceiver( + MaybeObject* result = js_object->GetElementsAccessor()->Get( + js_object->elements(), + index, js_object, - receiver, - index); + receiver); if (result != heap->the_hole_value()) return result; } } @@ -4466,20 +4467,6 @@ void CodeCacheHashTable::RemoveByIndex(int index) { } -static bool HasKey(FixedArray* array, Object* key) { - int len0 = array->length(); - for (int i = 0; i < len0; i++) { - Object* element = array->get(i); - if (element->IsSmi() && key->IsSmi() && (element == key)) return true; - if (element->IsString() && - key->IsString() && String::cast(element)->Equals(String::cast(key))) { - return true; - } - } - return false; -} - - MaybeObject* PolymorphicCodeCache::Update(MapList* maps, Code::Flags flags, Code* code) { @@ -4641,7 +4628,7 @@ MaybeObject* PolymorphicCodeCacheHashTable::Put(MapList* maps, MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) { ElementsAccessor* accessor = array->GetElementsAccessor(); MaybeObject* maybe_result = - accessor->AddElementsToFixedArray(array->elements(), this); + accessor->AddElementsToFixedArray(array->elements(), this, array, array); FixedArray* result; if (!maybe_result->To(&result)) return maybe_result; #ifdef DEBUG @@ -4657,55 +4644,19 @@ MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) { MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) { - int len0 = length(); + ElementsAccessor* accessor = ElementsAccessor::ForArray(other); + MaybeObject* maybe_result = + accessor->AddElementsToFixedArray(other, this, NULL, NULL); + FixedArray* result; + if (!maybe_result->To(&result)) return maybe_result; #ifdef DEBUG if (FLAG_enable_slow_asserts) { - for (int i = 0; i < len0; i++) { - ASSERT(get(i)->IsString() || get(i)->IsNumber()); + for (int i = 0; i < result->length(); i++) { + Object* current = result->get(i); + ASSERT(current->IsNumber() || current->IsString()); } } #endif - int len1 = other->length(); - // Optimize if 'other' is empty. - // We cannot optimize if 'this' is empty, as other may have holes - // or non keys. - if (len1 == 0) return this; - - // Compute how many elements are not in this. - int extra = 0; - for (int y = 0; y < len1; y++) { - Object* value = other->get(y); - if (!value->IsTheHole() && !HasKey(this, value)) extra++; - } - - if (extra == 0) return this; - - // Allocate the result - Object* obj; - { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(len0 + extra); - if (!maybe_obj->ToObject(&obj)) return maybe_obj; - } - // Fill in the content - AssertNoAllocation no_gc; - FixedArray* result = FixedArray::cast(obj); - WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc); - for (int i = 0; i < len0; i++) { - Object* e = get(i); - ASSERT(e->IsString() || e->IsNumber()); - result->set(i, e, mode); - } - // Fill in the extra keys. - int index = 0; - for (int y = 0; y < len1; y++) { - Object* value = other->get(y); - if (!value->IsTheHole() && !HasKey(this, value)) { - Object* e = other->get(y); - ASSERT(e->IsString() || e->IsNumber()); - result->set(len0 + index, e, mode); - index++; - } - } - ASSERT(extra == index); return result; } @@ -8718,9 +8669,10 @@ MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver, Heap* heap = holder_handle->GetHeap(); ElementsAccessor* handler = holder_handle->GetElementsAccessor(); - MaybeObject* raw_result = handler->GetWithReceiver(*holder_handle, - *this_handle, - index); + MaybeObject* raw_result = handler->Get(holder_handle->elements(), + index, + *holder_handle, + *this_handle); if (raw_result != heap->the_hole_value()) return raw_result; RETURN_IF_SCHEDULED_EXCEPTION(isolate); diff --git a/deps/v8/src/regexp.js b/deps/v8/src/regexp.js index 7b851a3574..a7f42d59c2 100644 --- a/deps/v8/src/regexp.js +++ b/deps/v8/src/regexp.js @@ -50,24 +50,29 @@ function DoConstructRegExp(object, pattern, flags) { var global = false; var ignoreCase = false; var multiline = false; - for (var i = 0; i < flags.length; i++) { var c = %_CallFunction(flags, i, StringCharAt); switch (c) { case 'g': - // Allow duplicate flags to be consistent with JSC and others. + if (global) { + throw MakeSyntaxError("invalid_regexp_flags", [flags]); + } global = true; break; case 'i': + if (ignoreCase) { + throw MakeSyntaxError("invalid_regexp_flags", [flags]); + } ignoreCase = true; break; case 'm': + if (multiline) { + throw MakeSyntaxError("invalid_regexp_flags", [flags]); + } multiline = true; break; default: - // Ignore flags that have no meaning to be consistent with - // JSC. - break; + throw MakeSyntaxError("invalid_regexp_flags", [flags]); } } diff --git a/deps/v8/src/scanner-base.cc b/deps/v8/src/scanner-base.cc index 2ecbfd2a95..62eee1a548 100644 --- a/deps/v8/src/scanner-base.cc +++ b/deps/v8/src/scanner-base.cc @@ -41,12 +41,12 @@ Scanner::Scanner(UnicodeCache* unicode_cache) : unicode_cache_(unicode_cache) { } -uc32 Scanner::ScanHexEscape(uc32 c, int length) { - ASSERT(length <= 4); // prevent overflow +uc32 Scanner::ScanHexNumber(int expected_length) { + ASSERT(expected_length <= 4); // prevent overflow - uc32 digits[4]; + uc32 digits[4] = { 0, 0, 0, 0 }; uc32 x = 0; - for (int i = 0; i < length; i++) { + for (int i = 0; i < expected_length; i++) { digits[i] = c0_; int d = HexValue(c0_); if (d < 0) { @@ -54,12 +54,11 @@ uc32 Scanner::ScanHexEscape(uc32 c, int length) { // should be illegal, but other JS VMs just return the // non-escaped version of the original character. - // Push back digits read, except the last one (in c0_). + // Push back digits that we have advanced past. for (int j = i-1; j >= 0; j--) { PushBack(digits[j]); } - // Notice: No handling of error - treat it as "\u"->"u". - return c; + return -1; } x = x * 16 + d; Advance(); @@ -640,9 +639,17 @@ void JavaScriptScanner::ScanEscape() { case 'n' : c = '\n'; break; case 'r' : c = '\r'; break; case 't' : c = '\t'; break; - case 'u' : c = ScanHexEscape(c, 4); break; + case 'u' : { + c = ScanHexNumber(4); + if (c < 0) c = 'u'; + break; + } case 'v' : c = '\v'; break; - case 'x' : c = ScanHexEscape(c, 2); break; + case 'x' : { + c = ScanHexNumber(2); + if (c < 0) c = 'x'; + break; + } case '0' : // fall through case '1' : // fall through case '2' : // fall through @@ -802,13 +809,11 @@ Token::Value JavaScriptScanner::ScanNumber(bool seen_period) { uc32 JavaScriptScanner::ScanIdentifierUnicodeEscape() { Advance(); - if (c0_ != 'u') return unibrow::Utf8::kBadChar; + if (c0_ != 'u') return -1; Advance(); - uc32 c = ScanHexEscape('u', 4); - // We do not allow a unicode escape sequence to start another - // unicode escape sequence. - if (c == '\\') return unibrow::Utf8::kBadChar; - return c; + uc32 result = ScanHexNumber(4); + if (result < 0) PushBack('u'); + return result; } @@ -926,7 +931,11 @@ Token::Value JavaScriptScanner::ScanIdentifierOrKeyword() { if (c0_ == '\\') { uc32 c = ScanIdentifierUnicodeEscape(); // Only allow legal identifier start characters. - if (!unicode_cache_->IsIdentifierStart(c)) return Token::ILLEGAL; + if (c < 0 || + c == '\\' || // No recursive escapes. + !unicode_cache_->IsIdentifierStart(c)) { + return Token::ILLEGAL; + } AddLiteralChar(c); return ScanIdentifierSuffix(&literal); } @@ -966,7 +975,11 @@ Token::Value JavaScriptScanner::ScanIdentifierSuffix(LiteralScope* literal) { if (c0_ == '\\') { uc32 c = ScanIdentifierUnicodeEscape(); // Only allow legal identifier part characters. - if (!unicode_cache_->IsIdentifierPart(c)) return Token::ILLEGAL; + if (c < 0 || + c == '\\' || + !unicode_cache_->IsIdentifierPart(c)) { + return Token::ILLEGAL; + } AddLiteralChar(c); } else { AddLiteralChar(c0_); @@ -992,8 +1005,9 @@ bool JavaScriptScanner::ScanRegExpPattern(bool seen_equal) { // the scanner should pass uninterpreted bodies to the RegExp // constructor. LiteralScope literal(this); - if (seen_equal) + if (seen_equal) { AddLiteralChar('='); + } while (c0_ != '/' || in_character_class) { if (unicode_cache_->IsLineTerminator(c0_) || c0_ < 0) return false; @@ -1025,20 +1039,47 @@ bool JavaScriptScanner::ScanRegExpPattern(bool seen_equal) { } +bool JavaScriptScanner::ScanLiteralUnicodeEscape() { + ASSERT(c0_ == '\\'); + uc32 chars_read[6] = {'\\', 'u', 0, 0, 0, 0}; + Advance(); + int i = 1; + if (c0_ == 'u') { + i++; + while (i < 6) { + Advance(); + if (!IsHexDigit(c0_)) break; + chars_read[i] = c0_; + i++; + } + } + if (i < 6) { + // Incomplete escape. Undo all advances and return false. + while (i > 0) { + i--; + PushBack(chars_read[i]); + } + return false; + } + // Complete escape. Add all chars to current literal buffer. + for (int i = 0; i < 6; i++) { + AddLiteralChar(chars_read[i]); + } + return true; +} + + bool JavaScriptScanner::ScanRegExpFlags() { // Scan regular expression flags. LiteralScope literal(this); while (unicode_cache_->IsIdentifierPart(c0_)) { - if (c0_ == '\\') { - uc32 c = ScanIdentifierUnicodeEscape(); - if (c != static_cast(unibrow::Utf8::kBadChar)) { - // We allow any escaped character, unlike the restriction on - // IdentifierPart when it is used to build an IdentifierName. - AddLiteralChar(c); - continue; + if (c0_ != '\\') { + AddLiteralCharAdvance(); + } else { + if (!ScanLiteralUnicodeEscape()) { + break; } } - AddLiteralCharAdvance(); } literal.Complete(); diff --git a/deps/v8/src/scanner-base.h b/deps/v8/src/scanner-base.h index 3e1772a3d2..a7062a34af 100644 --- a/deps/v8/src/scanner-base.h +++ b/deps/v8/src/scanner-base.h @@ -419,7 +419,7 @@ class Scanner { } } - uc32 ScanHexEscape(uc32 c, int length); + uc32 ScanHexNumber(int expected_length); // Return the current source position. int source_pos() { @@ -537,6 +537,10 @@ class JavaScriptScanner : public Scanner { // Decodes a unicode escape-sequence which is part of an identifier. // If the escape sequence cannot be decoded the result is kBadChar. uc32 ScanIdentifierUnicodeEscape(); + // Recognizes a uniocde escape-sequence and adds its characters, + // uninterpreted, to the current literal. Used for parsing RegExp + // flags. + bool ScanLiteralUnicodeEscape(); // Start position of the octal literal last scanned. Location octal_pos_; diff --git a/deps/v8/src/spaces.h b/deps/v8/src/spaces.h index d8ed27e490..a0f4ba155d 100644 --- a/deps/v8/src/spaces.h +++ b/deps/v8/src/spaces.h @@ -409,6 +409,7 @@ class Space : public Malloced { class CodeRange { public: explicit CodeRange(Isolate* isolate); + ~CodeRange() { TearDown(); } // Reserves a range of virtual memory, but does not commit any of it. // Can only be called once, at heap initialization time. diff --git a/deps/v8/src/string.js b/deps/v8/src/string.js index 2a5c95e450..e0f20c2f69 100644 --- a/deps/v8/src/string.js +++ b/deps/v8/src/string.js @@ -170,7 +170,7 @@ function StringLocaleCompare(other) { ["String.prototype.localeCompare"]); } if (%_ArgumentsLength() === 0) return 0; - return %StringLocaleCompare(TO_STRING_INLINE(this), + return %StringLocaleCompare(TO_STRING_INLINE(this), TO_STRING_INLINE(other)); } @@ -914,6 +914,8 @@ function ReplaceResultBuilder(str) { this.special_string = str; } +ReplaceResultBuilder.prototype.__proto__ = null; + ReplaceResultBuilder.prototype.add = function(str) { str = TO_STRING_INLINE(str); diff --git a/deps/v8/src/v8natives.js b/deps/v8/src/v8natives.js index 88525f6b44..c16d73e82e 100644 --- a/deps/v8/src/v8natives.js +++ b/deps/v8/src/v8natives.js @@ -462,6 +462,7 @@ function PropertyDescriptor() { } PropertyDescriptor.prototype.__proto__ = null; + PropertyDescriptor.prototype.toString = function() { return "[object PropertyDescriptor]"; }; @@ -1015,24 +1016,27 @@ function ObjectDefineProperty(obj, p, attributes) { } +function GetOwnEnumerablePropertyNames(properties) { + var names = new InternalArray(); + for (var key in properties) { + if (%HasLocalProperty(properties, key)) { + names.push(key); + } + } + return names; +} + + // ES5 section 15.2.3.7. function ObjectDefineProperties(obj, properties) { if (!IS_SPEC_OBJECT(obj)) throw MakeTypeError("obj_ctor_property_non_object", ["defineProperties"]); var props = ToObject(properties); - var key_values = []; - for (var key in props) { - if (%HasLocalProperty(props, key)) { - key_values.push(key); - var value = props[key]; - var desc = ToPropertyDescriptor(value); - key_values.push(desc); - } - } - for (var i = 0; i < key_values.length; i += 2) { - var key = key_values[i]; - var desc = key_values[i + 1]; - DefineOwnProperty(obj, key, desc, true); + var names = GetOwnEnumerablePropertyNames(props); + for (var i = 0; i < names.length; i++) { + var name = names[i]; + var desc = ToPropertyDescriptor(props[name]); + DefineOwnProperty(obj, name, desc, true); } return obj; } diff --git a/deps/v8/src/v8threads.cc b/deps/v8/src/v8threads.cc index 52f82e2911..3881d66fb0 100644 --- a/deps/v8/src/v8threads.cc +++ b/deps/v8/src/v8threads.cc @@ -305,7 +305,9 @@ ThreadManager::ThreadManager() ThreadManager::~ThreadManager() { - // TODO(isolates): Destroy mutexes. + delete mutex_; + delete free_anchor_; + delete in_use_anchor_; } diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc index c39af566f9..e3cecdf99d 100644 --- a/deps/v8/src/version.cc +++ b/deps/v8/src/version.cc @@ -34,7 +34,7 @@ // cannot be changed without changing the SCons build script. #define MAJOR_VERSION 3 #define MINOR_VERSION 5 -#define BUILD_NUMBER 6 +#define BUILD_NUMBER 7 #define PATCH_LEVEL 0 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) diff --git a/deps/v8/src/x64/full-codegen-x64.cc b/deps/v8/src/x64/full-codegen-x64.cc index d0c71be12f..5567df2fa6 100644 --- a/deps/v8/src/x64/full-codegen-x64.cc +++ b/deps/v8/src/x64/full-codegen-x64.cc @@ -842,7 +842,7 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { __ bind(&next_test); __ Drop(1); // Switch value is no longer needed. if (default_clause == NULL) { - __ jmp(nested_statement.break_target()); + __ jmp(nested_statement.break_label()); } else { __ jmp(default_clause->body_target()); } @@ -856,7 +856,7 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { VisitStatements(clause->statements()); } - __ bind(nested_statement.break_target()); + __ bind(nested_statement.break_label()); PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); } @@ -982,7 +982,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ bind(&loop); __ movq(rax, Operand(rsp, 0 * kPointerSize)); // Get the current index. __ cmpq(rax, Operand(rsp, 1 * kPointerSize)); // Compare to the array length. - __ j(above_equal, loop_statement.break_target()); + __ j(above_equal, loop_statement.break_label()); // Get the current entry of the array into register rbx. __ movq(rbx, Operand(rsp, 2 * kPointerSize)); @@ -1010,7 +1010,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ push(rbx); // Current entry. __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION); __ Cmp(rax, Smi::FromInt(0)); - __ j(equal, loop_statement.continue_target()); + __ j(equal, loop_statement.continue_label()); __ movq(rbx, rax); // Update the 'each' property or variable from the possibly filtered @@ -1027,14 +1027,14 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // Generate code for going to the next element by incrementing the // index (smi) stored on top of the stack. - __ bind(loop_statement.continue_target()); + __ bind(loop_statement.continue_label()); __ SmiAddConstant(Operand(rsp, 0 * kPointerSize), Smi::FromInt(1)); EmitStackCheck(stmt); __ jmp(&loop); // Remove the pointers stored on the stack. - __ bind(loop_statement.break_target()); + __ bind(loop_statement.break_label()); __ addq(rsp, Immediate(5 * kPointerSize)); // Exit and decrement the loop depth. diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index d5e17b89a7..3ed6b523f0 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -3617,6 +3617,52 @@ THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) { } +Handle NonStrictArgsIndexedPropertyEnumerator( + const AccessorInfo& info) { + // Force the list of returned keys to be stored in a Arguments object. + Local