From 92f5a5d3caf01f382f90c235e9057590a5e76870 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Thu, 27 Oct 2011 00:48:23 -0700 Subject: [PATCH] Upgrade V8 to 3.7.1 --- deps/v8/ChangeLog | 45 + deps/v8/build/common.gypi | 1 + deps/v8/preparser/preparser-process.cc | 35 +- deps/v8/src/SConscript | 2 +- deps/v8/src/accessors.cc | 11 +- deps/v8/src/api.cc | 57 +- deps/v8/src/arm/assembler-arm-inl.h | 15 +- deps/v8/src/arm/assembler-arm.h | 6 +- deps/v8/src/arm/builtins-arm.cc | 78 +- deps/v8/src/arm/code-stubs-arm.cc | 98 +- deps/v8/src/arm/code-stubs-arm.h | 12 +- deps/v8/src/arm/codegen-arm.cc | 249 +++ deps/v8/src/arm/codegen-arm.h | 1 - deps/v8/src/arm/deoptimizer-arm.cc | 22 +- deps/v8/src/arm/full-codegen-arm.cc | 169 ++- deps/v8/src/arm/ic-arm.cc | 104 +- deps/v8/src/arm/lithium-arm.cc | 36 +- deps/v8/src/arm/lithium-arm.h | 32 +- deps/v8/src/arm/lithium-codegen-arm.cc | 191 ++- deps/v8/src/arm/lithium-codegen-arm.h | 14 +- deps/v8/src/arm/macro-assembler-arm.cc | 36 +- deps/v8/src/arm/macro-assembler-arm.h | 61 +- deps/v8/src/arm/regexp-macro-assembler-arm.cc | 5 + deps/v8/src/arm/simulator-arm.cc | 4 +- deps/v8/src/arm/stub-cache-arm.cc | 656 +++++--- deps/v8/src/array.js | 18 +- deps/v8/src/assembler.cc | 21 +- deps/v8/src/assembler.h | 15 +- deps/v8/src/ast-inl.h | 14 +- deps/v8/src/ast.cc | 7 +- deps/v8/src/ast.h | 19 +- deps/v8/src/bootstrapper.cc | 144 +- deps/v8/src/builtins.cc | 8 + deps/v8/src/builtins.h | 5 +- deps/v8/src/checks.h | 11 +- deps/v8/src/code-stubs.cc | 25 + deps/v8/src/code-stubs.h | 45 +- deps/v8/src/codegen.h | 15 + deps/v8/src/{weakmap.js => collection.js} | 89 +- deps/v8/src/compiler.cc | 46 +- deps/v8/src/compiler.h | 54 +- deps/v8/src/contexts.cc | 29 +- deps/v8/src/contexts.h | 53 +- deps/v8/src/d8.cc | 3 +- deps/v8/src/debug.cc | 242 ++- deps/v8/src/debug.h | 7 +- deps/v8/src/deoptimizer.cc | 9 +- deps/v8/src/deoptimizer.h | 3 +- deps/v8/src/factory.cc | 53 +- deps/v8/src/factory.h | 7 +- deps/v8/src/flag-definitions.h | 8 +- deps/v8/src/frames.cc | 63 + deps/v8/src/frames.h | 2 + deps/v8/src/full-codegen.cc | 16 +- deps/v8/src/full-codegen.h | 6 +- deps/v8/src/globals.h | 3 + deps/v8/src/handles.cc | 114 +- deps/v8/src/handles.h | 46 +- deps/v8/src/heap-inl.h | 5 +- deps/v8/src/heap.cc | 135 +- deps/v8/src/heap.h | 40 +- deps/v8/src/hydrogen-instructions.cc | 79 +- deps/v8/src/hydrogen-instructions.h | 92 +- deps/v8/src/hydrogen.cc | 286 ++-- deps/v8/src/hydrogen.h | 32 +- deps/v8/src/ia32/assembler-ia32-inl.h | 15 +- deps/v8/src/ia32/builtins-ia32.cc | 13 +- deps/v8/src/ia32/code-stubs-ia32.cc | 138 +- deps/v8/src/ia32/code-stubs-ia32.h | 11 +- deps/v8/src/ia32/codegen-ia32.cc | 258 ++++ deps/v8/src/ia32/deoptimizer-ia32.cc | 15 +- deps/v8/src/ia32/disasm-ia32.cc | 12 +- deps/v8/src/ia32/full-codegen-ia32.cc | 177 ++- deps/v8/src/ia32/ic-ia32.cc | 142 +- deps/v8/src/ia32/lithium-codegen-ia32.cc | 192 ++- deps/v8/src/ia32/lithium-codegen-ia32.h | 12 +- deps/v8/src/ia32/lithium-ia32.cc | 46 +- deps/v8/src/ia32/lithium-ia32.h | 32 +- deps/v8/src/ia32/macro-assembler-ia32.cc | 44 +- deps/v8/src/ia32/macro-assembler-ia32.h | 6 +- deps/v8/src/ia32/regexp-macro-assembler-ia32.cc | 5 + deps/v8/src/ia32/stub-cache-ia32.cc | 707 +++++---- deps/v8/src/ic.cc | 1087 ++++++------- deps/v8/src/ic.h | 190 +-- deps/v8/src/incremental-marking-inl.h | 3 - deps/v8/src/incremental-marking.cc | 26 +- deps/v8/src/incremental-marking.h | 11 + deps/v8/src/interpreter-irregexp.cc | 37 +- deps/v8/src/interpreter-irregexp.h | 12 +- deps/v8/src/isolate.cc | 14 + deps/v8/src/isolate.h | 11 +- deps/v8/src/jsregexp.cc | 18 +- deps/v8/src/list-inl.h | 5 +- deps/v8/src/list.h | 4 + deps/v8/src/liveobjectlist.cc | 6 +- deps/v8/src/macros.py | 5 + deps/v8/src/mark-compact-inl.h | 8 +- deps/v8/src/mark-compact.cc | 73 +- deps/v8/src/mark-compact.h | 56 +- deps/v8/src/messages.js | 44 +- deps/v8/src/mips/assembler-mips-inl.h | 15 +- deps/v8/src/mips/assembler-mips.h | 2 +- deps/v8/src/mips/builtins-mips.cc | 69 +- deps/v8/src/mips/code-stubs-mips.cc | 129 +- deps/v8/src/mips/code-stubs-mips.h | 12 +- deps/v8/src/mips/codegen-mips.cc | 257 ++++ deps/v8/src/mips/codegen-mips.h | 1 - deps/v8/src/mips/deoptimizer-mips.cc | 3 +- deps/v8/src/mips/full-codegen-mips.cc | 175 ++- deps/v8/src/mips/ic-mips.cc | 104 +- deps/v8/src/mips/macro-assembler-mips.cc | 32 +- deps/v8/src/mips/macro-assembler-mips.h | 3 +- deps/v8/src/mips/regexp-macro-assembler-mips.cc | 5 + deps/v8/src/mips/simulator-mips.cc | 4 +- deps/v8/src/mips/stub-cache-mips.cc | 501 ++++-- deps/v8/src/mirror-debugger.js | 2 +- deps/v8/src/mksnapshot.cc | 1 - deps/v8/src/objects-debug.cc | 28 + deps/v8/src/objects-inl.h | 426 +++--- deps/v8/src/objects-printer.cc | 48 - deps/v8/src/objects-visiting.cc | 10 + deps/v8/src/objects.cc | 788 ++++++++-- deps/v8/src/objects.h | 289 +++- deps/v8/src/parser.cc | 464 ++++-- deps/v8/src/parser.h | 23 +- deps/v8/src/platform-solaris.cc | 141 +- deps/v8/src/preparser-api.cc | 2 +- deps/v8/src/preparser.cc | 48 +- deps/v8/src/preparser.h | 51 +- deps/v8/src/profile-generator.cc | 19 +- deps/v8/src/property.cc | 9 + deps/v8/src/property.h | 22 +- deps/v8/src/proxy.js | 42 +- deps/v8/src/regexp.js | 15 - deps/v8/src/runtime.cc | 934 +++++++----- deps/v8/src/runtime.h | 38 +- deps/v8/src/runtime.js | 15 +- deps/v8/src/scanner.h | 11 + deps/v8/src/scopeinfo.cc | 81 +- deps/v8/src/scopeinfo.h | 15 +- deps/v8/src/scopes.cc | 371 ++--- deps/v8/src/scopes.h | 156 +- deps/v8/src/serialize.cc | 185 ++- deps/v8/src/serialize.h | 70 +- deps/v8/src/spaces-inl.h | 4 - deps/v8/src/spaces.cc | 39 +- deps/v8/src/spaces.h | 26 +- deps/v8/src/store-buffer-inl.h | 8 +- deps/v8/src/store-buffer.cc | 4 +- deps/v8/src/stub-cache.cc | 1604 +++++++++----------- deps/v8/src/stub-cache.h | 625 ++++---- deps/v8/src/token.h | 1 + deps/v8/src/type-info.cc | 101 +- deps/v8/src/type-info.h | 1 - deps/v8/src/utils.h | 23 +- deps/v8/src/v8.cc | 14 +- deps/v8/src/v8.h | 4 +- deps/v8/src/v8globals.h | 25 +- deps/v8/src/v8natives.js | 127 +- deps/v8/src/variables.cc | 1 + deps/v8/src/variables.h | 13 + deps/v8/src/version.cc | 2 +- deps/v8/src/x64/assembler-x64-inl.h | 16 +- deps/v8/src/x64/builtins-x64.cc | 75 +- deps/v8/src/x64/code-stubs-x64.cc | 106 +- deps/v8/src/x64/code-stubs-x64.h | 11 +- deps/v8/src/x64/codegen-x64.cc | 219 +++ deps/v8/src/x64/deoptimizer-x64.cc | 16 +- deps/v8/src/x64/full-codegen-x64.cc | 175 ++- deps/v8/src/x64/ic-x64.cc | 134 +- deps/v8/src/x64/lithium-codegen-x64.cc | 215 ++- deps/v8/src/x64/lithium-codegen-x64.h | 15 +- deps/v8/src/x64/lithium-x64.cc | 46 +- deps/v8/src/x64/lithium-x64.h | 32 +- deps/v8/src/x64/macro-assembler-x64.cc | 88 +- deps/v8/src/x64/macro-assembler-x64.h | 25 +- deps/v8/src/x64/regexp-macro-assembler-x64.cc | 5 + deps/v8/src/x64/stub-cache-x64.cc | 681 ++++++--- deps/v8/test/cctest/cctest.status | 3 - deps/v8/test/cctest/test-api.cc | 72 +- deps/v8/test/cctest/test-debug.cc | 11 +- deps/v8/test/cctest/test-dictionary.cc | 69 +- deps/v8/test/cctest/test-heap-profiler.cc | 22 + deps/v8/test/cctest/test-parsing.cc | 172 ++- deps/v8/test/cctest/test-serialize.cc | 3 +- deps/v8/test/mjsunit/apply.js | 7 + deps/v8/test/mjsunit/array-literal-transitions.js | 125 ++ deps/v8/test/mjsunit/compiler/compare.js | 4 +- .../compiler/regress-deopt-call-as-function.js | 62 + .../regress-inline-callfunctionstub.js} | 32 +- deps/v8/test/mjsunit/compiler/strict-recompile.js | 51 + deps/v8/test/mjsunit/debug-scopes.js | 46 +- deps/v8/test/mjsunit/debug-step-3.js | 95 ++ deps/v8/test/mjsunit/element-kind.js | 261 ---- deps/v8/test/mjsunit/elements-kind.js | 309 ++++ deps/v8/test/mjsunit/elements-transition.js | 107 ++ deps/v8/test/mjsunit/error-tostring.js | 85 ++ deps/v8/test/mjsunit/function-bind.js | 197 ++- deps/v8/test/mjsunit/harmony/block-conflicts.js | 5 + deps/v8/test/mjsunit/harmony/block-for.js | 142 ++ .../test/mjsunit/harmony/block-let-declaration.js | 57 +- .../v8/test/mjsunit/harmony/block-let-semantics.js | 28 +- deps/v8/test/mjsunit/harmony/block-scoping.js | 54 +- deps/v8/test/mjsunit/harmony/collections.js | 273 ++++ deps/v8/test/mjsunit/harmony/debug-blockscopes.js | 109 ++ deps/v8/test/mjsunit/harmony/proxies-for.js | 168 ++ deps/v8/test/mjsunit/harmony/proxies-function.js | 274 +++- deps/v8/test/mjsunit/harmony/proxies-hash.js | 80 +- deps/v8/test/mjsunit/harmony/proxies.js | 94 +- deps/v8/test/mjsunit/harmony/weakmaps.js | 167 -- deps/v8/test/mjsunit/mjsunit.status | 14 + deps/v8/test/mjsunit/object-define-properties.js | 16 + deps/v8/test/mjsunit/optimized-typeof.js | 47 + deps/v8/test/mjsunit/regexp-static.js | 17 +- deps/v8/test/mjsunit/regress/regress-100409.js | 55 + deps/v8/test/mjsunit/regress/regress-100702.js | 44 + deps/v8/test/mjsunit/regress/regress-1229.js | 4 +- deps/v8/test/mjsunit/regress/regress-1521.js | 3 +- deps/v8/test/mjsunit/stack-traces-2.js | 87 ++ deps/v8/test/mjsunit/stack-traces.js | 58 + deps/v8/test/mjsunit/strict-mode.js | 6 + deps/v8/test/mjsunit/to_number_order.js | 4 +- deps/v8/test/mozilla/mozilla.status | 11 +- deps/v8/test/sputnik/sputnik.status | 18 +- deps/v8/test/test262/test262.status | 173 --- deps/v8/tools/gyp/v8.gyp | 2 +- 226 files changed, 14000 insertions(+), 7084 deletions(-) rename deps/v8/src/{weakmap.js => collection.js} (65%) create mode 100644 deps/v8/test/mjsunit/array-literal-transitions.js create mode 100644 deps/v8/test/mjsunit/compiler/regress-deopt-call-as-function.js rename deps/v8/test/mjsunit/{cyclic-error-to-string.js => compiler/regress-inline-callfunctionstub.js} (80%) create mode 100644 deps/v8/test/mjsunit/compiler/strict-recompile.js create mode 100644 deps/v8/test/mjsunit/debug-step-3.js delete mode 100644 deps/v8/test/mjsunit/element-kind.js create mode 100644 deps/v8/test/mjsunit/elements-kind.js create mode 100644 deps/v8/test/mjsunit/elements-transition.js create mode 100644 deps/v8/test/mjsunit/error-tostring.js create mode 100644 deps/v8/test/mjsunit/harmony/block-for.js create mode 100644 deps/v8/test/mjsunit/harmony/collections.js create mode 100644 deps/v8/test/mjsunit/harmony/proxies-for.js delete mode 100644 deps/v8/test/mjsunit/harmony/weakmaps.js create mode 100644 deps/v8/test/mjsunit/optimized-typeof.js create mode 100644 deps/v8/test/mjsunit/regress/regress-100409.js create mode 100644 deps/v8/test/mjsunit/regress/regress-100702.js create mode 100644 deps/v8/test/mjsunit/stack-traces-2.js diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog index a95f3cc..874fcba 100644 --- a/deps/v8/ChangeLog +++ b/deps/v8/ChangeLog @@ -1,3 +1,48 @@ +2011-10-26: Version 3.7.1 + + Achieved 33% speedup in debug-mode tests. + + Removed special casing of calls to RegExp test and exec methods with no + argument. Now matches new JSC behaviour. crbug.com/75740. + + Return the empty string on cyclic references in toString (ES5 + conformance). + + Fixed bug triggered by JSBeautifier. crbug.com/100409. + + Made Math.random state per-context instead of per-process (issue 864). + + Fixed stack traces to skip native functions. + + Make snapshots (new contexts) smaller and faster. + + Fixed handling of Function.apply for non-array arguments. + + Fixed evaluation order in defineProperties to match FireFox. + + Fixed handling of non-object receivers for array builtins, + crbug.com/100702. + + Multiple fixes to improve compliance with test262. + + Fixed compatibility with older Android releases. + + Fixed compilation with gcc-4.5.3. + + Improved performance of WriteUtf8, issue 1665. + + Made native syntax an early error in the preparser. + + Fixed issues 793 and 893 relating to Function.prototype.bind. + + Improved let, const, Set and Map support and other Harmony features + (behind the --harmony flag). + + Changed evaluation order for > and <= to match ES5 instead of ES3. + + Bug fixes and performance improvements on all platforms. + + 2011-10-13: Version 3.7.0 Fixed array handling for Object.defineOwnProperty (ES5 conformance). diff --git a/deps/v8/build/common.gypi b/deps/v8/build/common.gypi index a6579ed..230b1fd 100644 --- a/deps/v8/build/common.gypi +++ b/deps/v8/build/common.gypi @@ -270,6 +270,7 @@ }], ['OS=="win"', { 'msvs_configuration_attributes': { + 'OutputDirectory': '<(DEPTH)\\build\\$(ConfigurationName)', 'IntermediateDirectory': '$(OutDir)\\obj\\$(ProjectName)', 'CharacterSet': '1', }, diff --git a/deps/v8/preparser/preparser-process.cc b/deps/v8/preparser/preparser-process.cc index e67851c..b0aeb81 100644 --- a/deps/v8/preparser/preparser-process.cc +++ b/deps/v8/preparser/preparser-process.cc @@ -267,34 +267,22 @@ void CheckException(v8::PreParserData* data, ExceptionExpectation ParseExpectation(int argc, const char* argv[]) { + // Parse ["throws" [ [ []]]]. ExceptionExpectation expects; - - // Parse exception expectations from (the remainder of) the command line. int arg_index = 0; - // Skip any flags. - while (argc > arg_index && IsFlag(argv[arg_index])) arg_index++; + while (argc > arg_index && strncmp("throws", argv[arg_index], 7)) { + arg_index++; + } if (argc > arg_index) { - if (strncmp("throws", argv[arg_index], 7)) { - // First argument after filename, if present, must be the verbatim - // "throws", marking that the preparsing should fail with an exception. - fail(NULL, "ERROR: Extra arguments not prefixed by \"throws\".\n"); - } expects.throws = true; - do { - arg_index++; - } while (argc > arg_index && IsFlag(argv[arg_index])); - if (argc > arg_index) { - // Next argument is the exception type identifier. + arg_index++; + if (argc > arg_index && !IsFlag(argv[arg_index])) { expects.type = argv[arg_index]; - do { - arg_index++; - } while (argc > arg_index && IsFlag(argv[arg_index])); - if (argc > arg_index) { + arg_index++; + if (argc > arg_index && !IsFlag(argv[arg_index])) { expects.beg_pos = atoi(argv[arg_index]); // NOLINT - do { - arg_index++; - } while (argc > arg_index && IsFlag(argv[arg_index])); - if (argc > arg_index) { + arg_index++; + if (argc > arg_index && !IsFlag(argv[arg_index])) { expects.end_pos = atoi(argv[arg_index]); // NOLINT } } @@ -308,7 +296,8 @@ int main(int argc, const char* argv[]) { // Parse command line. // Format: preparser ( | -e "") // ["throws" [ [ []]]] - // Any flags (except an initial -s) are ignored. + // Any flags (except an initial -e) are ignored. + // Flags must not separate "throws" and its arguments. // Check for mandatory filename argument. int arg_index = 1; diff --git a/deps/v8/src/SConscript b/deps/v8/src/SConscript index f3ae807..be4a8f0 100755 --- a/deps/v8/src/SConscript +++ b/deps/v8/src/SConscript @@ -321,7 +321,7 @@ debug-debugger.js EXPERIMENTAL_LIBRARY_FILES = ''' proxy.js -weakmap.js +collection.js '''.split() diff --git a/deps/v8/src/accessors.cc b/deps/v8/src/accessors.cc index 951209d..02998f9 100644 --- a/deps/v8/src/accessors.cc +++ b/deps/v8/src/accessors.cc @@ -527,7 +527,9 @@ MaybeObject* Accessors::FunctionGetLength(Object* object, void*) { // correctly yet. Compile it now and return the right length. HandleScope scope; Handle handle(function); - if (!CompileLazy(handle, KEEP_EXCEPTION)) return Failure::Exception(); + if (!JSFunction::CompileLazy(handle, KEEP_EXCEPTION)) { + return Failure::Exception(); + } return Smi::FromInt(handle->shared()->length()); } else { return Smi::FromInt(function->shared()->length()); @@ -759,7 +761,12 @@ MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) { caller = potential_caller; potential_caller = it.next(); } - + // If caller is bound, return null. This is compatible with JSC, and + // allows us to make bound functions use the strict function map + // and its associated throwing caller and arguments. + if (caller->shared()->bound()) { + return isolate->heap()->null_value(); + } return CheckNonStrictCallerOrThrow(isolate, caller); } diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index a03b741..ac4f07f 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -2794,7 +2794,7 @@ Local v8::Object::Get(uint32_t index) { ENTER_V8(isolate); i::Handle self = Utils::OpenHandle(this); EXCEPTION_PREAMBLE(isolate); - i::Handle result = i::GetElement(self, index); + i::Handle result = i::Object::GetElement(self, index); has_pending_exception = result.is_null(); EXCEPTION_BAILOUT_CHECK(isolate, Local()); return Utils::ToLocal(result); @@ -2874,8 +2874,10 @@ Local v8::Object::GetPropertyNames() { ENTER_V8(isolate); i::HandleScope scope(isolate); i::Handle self = Utils::OpenHandle(this); + bool threw = false; i::Handle value = - i::GetKeysInFixedArrayFor(self, i::INCLUDE_PROTOS); + i::GetKeysInFixedArrayFor(self, i::INCLUDE_PROTOS, &threw); + if (threw) return Local(); // Because we use caching to speed up enumeration it is important // to never change the result of the basic enumeration function so // we clone the result. @@ -2893,8 +2895,10 @@ Local v8::Object::GetOwnPropertyNames() { ENTER_V8(isolate); i::HandleScope scope(isolate); i::Handle self = Utils::OpenHandle(this); + bool threw = false; i::Handle value = - i::GetKeysInFixedArrayFor(self, i::LOCAL_ONLY); + i::GetKeysInFixedArrayFor(self, i::LOCAL_ONLY, &threw); + if (threw) return Local(); // Because we use caching to speed up enumeration it is important // to never change the result of the basic enumeration function so // we clone the result. @@ -3093,7 +3097,10 @@ static Local GetPropertyByLookup(i::Isolate* isolate, // If the property being looked up is a callback, it can throw // an exception. EXCEPTION_PREAMBLE(isolate); - i::Handle result = i::GetProperty(receiver, name, lookup); + PropertyAttributes ignored; + i::Handle result = + i::Object::GetProperty(receiver, receiver, lookup, name, + &ignored); has_pending_exception = result.is_null(); EXCEPTION_BAILOUT_CHECK(isolate, Local()); @@ -3110,7 +3117,7 @@ Local v8::Object::GetRealNamedPropertyInPrototypeChain( ENTER_V8(isolate); i::Handle self_obj = Utils::OpenHandle(this); i::Handle key_obj = Utils::OpenHandle(*key); - i::LookupResult lookup; + i::LookupResult lookup(isolate); self_obj->LookupRealNamedPropertyInPrototypes(*key_obj, &lookup); return GetPropertyByLookup(isolate, self_obj, key_obj, &lookup); } @@ -3123,7 +3130,7 @@ Local v8::Object::GetRealNamedProperty(Handle key) { ENTER_V8(isolate); i::Handle self_obj = Utils::OpenHandle(this); i::Handle key_obj = Utils::OpenHandle(*key); - i::LookupResult lookup; + i::LookupResult lookup(isolate); self_obj->LookupRealNamedProperty(*key_obj, &lookup); return GetPropertyByLookup(isolate, self_obj, key_obj, &lookup); } @@ -3634,13 +3641,30 @@ int String::WriteUtf8(char* buffer, if (IsDeadCheck(isolate, "v8::String::WriteUtf8()")) return 0; LOG_API(isolate, "String::WriteUtf8"); ENTER_V8(isolate); - i::StringInputBuffer& write_input_buffer = *isolate->write_input_buffer(); i::Handle str = Utils::OpenHandle(this); + if (str->IsAsciiRepresentation()) { + int len; + if (capacity == -1) { + capacity = str->length() + 1; + len = str->length(); + } else { + len = i::Min(capacity, str->length()); + } + i::String::WriteToFlat(*str, buffer, 0, len); + if (nchars_ref != NULL) *nchars_ref = len; + if (!(options & NO_NULL_TERMINATION) && capacity > len) { + buffer[len] = '\0'; + return len + 1; + } + return len; + } + + i::StringInputBuffer& write_input_buffer = *isolate->write_input_buffer(); isolate->string_tracker()->RecordWrite(str); if (options & HINT_MANY_WRITES_EXPECTED) { // Flatten the string for efficiency. This applies whether we are // using StringInputBuffer or Get(i) to access the characters. - str->TryFlatten(); + FlattenString(str); } write_input_buffer.Reset(0, *str); int len = str->length(); @@ -3961,6 +3985,15 @@ HeapStatistics::HeapStatistics(): total_heap_size_(0), void v8::V8::GetHeapStatistics(HeapStatistics* heap_statistics) { + if (!i::Isolate::Current()->IsInitialized()) { + // Isolate is unitialized thus heap is not configured yet. + heap_statistics->set_total_heap_size(0); + heap_statistics->set_total_heap_size_executable(0); + heap_statistics->set_used_heap_size(0); + heap_statistics->set_heap_size_limit(0); + return; + } + i::Heap* heap = i::Isolate::Current()->heap(); heap_statistics->set_total_heap_size(heap->CommittedMemory()); heap_statistics->set_total_heap_size_executable( @@ -3973,14 +4006,15 @@ void v8::V8::GetHeapStatistics(HeapStatistics* heap_statistics) { bool v8::V8::IdleNotification() { // Returning true tells the caller that it need not // continue to call IdleNotification. - if (!i::Isolate::Current()->IsInitialized()) return true; + i::Isolate* isolate = i::Isolate::Current(); + if (isolate == NULL || !isolate->IsInitialized()) return true; return i::V8::IdleNotification(); } void v8::V8::LowMemoryNotification() { i::Isolate* isolate = i::Isolate::Current(); - if (!isolate->IsInitialized()) return; + if (isolate == NULL || !isolate->IsInitialized()) return; isolate->heap()->CollectAllAvailableGarbage(); } @@ -4075,8 +4109,9 @@ Persistent v8::Context::New( } // Leave V8. - if (env.is_null()) + if (env.is_null()) { return Persistent(); + } return Persistent(Utils::ToLocal(env)); } diff --git a/deps/v8/src/arm/assembler-arm-inl.h b/deps/v8/src/arm/assembler-arm-inl.h index 93cecf5..7f9f4ce 100644 --- a/deps/v8/src/arm/assembler-arm-inl.h +++ b/deps/v8/src/arm/assembler-arm-inl.h @@ -74,10 +74,10 @@ int RelocInfo::target_address_size() { } -void RelocInfo::set_target_address(Address target) { +void RelocInfo::set_target_address(Address target, WriteBarrierMode mode) { ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY); Assembler::set_target_address_at(pc_, target); - if (host() != NULL && IsCodeTarget(rmode_)) { + if (mode == UPDATE_WRITE_BARRIER && host() != NULL && IsCodeTarget(rmode_)) { Object* target_code = Code::GetCodeFromTargetAddress(target); host()->GetHeap()->incremental_marking()->RecordWriteIntoCode( host(), this, HeapObject::cast(target_code)); @@ -103,10 +103,12 @@ Object** RelocInfo::target_object_address() { } -void RelocInfo::set_target_object(Object* target) { +void RelocInfo::set_target_object(Object* target, WriteBarrierMode mode) { ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); Assembler::set_target_address_at(pc_, reinterpret_cast
(target)); - if (host() != NULL && target->IsHeapObject()) { + if (mode == UPDATE_WRITE_BARRIER && + host() != NULL && + target->IsHeapObject()) { host()->GetHeap()->incremental_marking()->RecordWrite( host(), &Memory::Object_at(pc_), HeapObject::cast(target)); } @@ -136,11 +138,12 @@ JSGlobalPropertyCell* RelocInfo::target_cell() { } -void RelocInfo::set_target_cell(JSGlobalPropertyCell* cell) { +void RelocInfo::set_target_cell(JSGlobalPropertyCell* cell, + WriteBarrierMode mode) { ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL); Address address = cell->address() + JSGlobalPropertyCell::kValueOffset; Memory::Address_at(pc_) = address; - if (host() != NULL) { + if (mode == UPDATE_WRITE_BARRIER && host() != NULL) { // TODO(1550) We are passing NULL as a slot because cell can never be on // evacuation candidate. host()->GetHeap()->incremental_marking()->RecordWrite( diff --git a/deps/v8/src/arm/assembler-arm.h b/deps/v8/src/arm/assembler-arm.h index d19b64d..247479d 100644 --- a/deps/v8/src/arm/assembler-arm.h +++ b/deps/v8/src/arm/assembler-arm.h @@ -304,9 +304,9 @@ const DwVfpRegister d14 = { 14 }; const DwVfpRegister d15 = { 15 }; // Aliases for double registers. -const DwVfpRegister kFirstCalleeSavedDoubleReg = d8; -const DwVfpRegister kLastCalleeSavedDoubleReg = d15; -const DwVfpRegister kDoubleRegZero = d14; +static const DwVfpRegister& kFirstCalleeSavedDoubleReg = d8; +static const DwVfpRegister& kLastCalleeSavedDoubleReg = d15; +static const DwVfpRegister& kDoubleRegZero = d14; // Coprocessor register diff --git a/deps/v8/src/arm/builtins-arm.cc b/deps/v8/src/arm/builtins-arm.cc index 32b7896..29bf190 100644 --- a/deps/v8/src/arm/builtins-arm.cc +++ b/deps/v8/src/arm/builtins-arm.cc @@ -86,12 +86,6 @@ static void GenerateLoadArrayFunction(MacroAssembler* masm, Register result) { } -// This constant has the same value as JSArray::kPreallocatedArrayElements and -// if JSArray::kPreallocatedArrayElements is changed handling of loop unfolding -// below should be reconsidered. -static const int kLoopUnfoldLimit = 4; - - // Allocate an empty JSArray. The allocated array is put into the result // register. An elements backing store is allocated with size initial_capacity // and filled with the hole values. @@ -101,9 +95,9 @@ static void AllocateEmptyJSArray(MacroAssembler* masm, Register scratch1, Register scratch2, Register scratch3, - int initial_capacity, Label* gc_required) { - ASSERT(initial_capacity > 0); + const int initial_capacity = JSArray::kPreallocatedArrayElements; + STATIC_ASSERT(initial_capacity >= 0); // Load the initial map from the array function. __ ldr(scratch1, FieldMemOperand(array_function, JSFunction::kPrototypeOrInitialMapOffset)); @@ -153,12 +147,24 @@ static void AllocateEmptyJSArray(MacroAssembler* masm, ASSERT_EQ(1 * kPointerSize, FixedArray::kLengthOffset); __ str(scratch3, MemOperand(scratch1, kPointerSize, PostIndex)); - // Fill the FixedArray with the hole value. + // Fill the FixedArray with the hole value. Inline the code if short. + if (initial_capacity == 0) return; ASSERT_EQ(2 * kPointerSize, FixedArray::kHeaderSize); - ASSERT(initial_capacity <= kLoopUnfoldLimit); __ LoadRoot(scratch3, Heap::kTheHoleValueRootIndex); - for (int i = 0; i < initial_capacity; i++) { + static const int kLoopUnfoldLimit = 4; + if (initial_capacity <= kLoopUnfoldLimit) { + for (int i = 0; i < initial_capacity; i++) { + __ str(scratch3, MemOperand(scratch1, kPointerSize, PostIndex)); + } + } else { + Label loop, entry; + __ add(scratch2, scratch1, Operand(initial_capacity * kPointerSize)); + __ b(&entry); + __ bind(&loop); __ str(scratch3, MemOperand(scratch1, kPointerSize, PostIndex)); + __ bind(&entry); + __ cmp(scratch1, scratch2); + __ b(lt, &loop); } } @@ -173,7 +179,7 @@ static void AllocateEmptyJSArray(MacroAssembler* masm, // register elements_array_storage is scratched. static void AllocateJSArray(MacroAssembler* masm, Register array_function, // Array function. - Register array_size, // As a smi. + Register array_size, // As a smi, cannot be 0. Register result, Register elements_array_storage, Register elements_array_end, @@ -181,32 +187,18 @@ static void AllocateJSArray(MacroAssembler* masm, Register scratch2, bool fill_with_hole, Label* gc_required) { - Label not_empty, allocated; - // Load the initial map from the array function. __ ldr(elements_array_storage, FieldMemOperand(array_function, JSFunction::kPrototypeOrInitialMapOffset)); - // Check whether an empty sized array is requested. - __ tst(array_size, array_size); - __ b(ne, ¬_empty); - - // If an empty array is requested allocate a small elements array anyway. This - // keeps the code below free of special casing for the empty array. - int size = JSArray::kSize + - FixedArray::SizeFor(JSArray::kPreallocatedArrayElements); - __ AllocateInNewSpace(size, - result, - elements_array_end, - scratch1, - gc_required, - TAG_OBJECT); - __ jmp(&allocated); + if (FLAG_debug_code) { // Assert that array size is not zero. + __ tst(array_size, array_size); + __ Assert(ne, "array size is unexpectedly 0"); + } // Allocate the JSArray object together with space for a FixedArray with the // requested number of elements. - __ bind(¬_empty); STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); __ mov(elements_array_end, Operand((JSArray::kSize + FixedArray::kHeaderSize) / kPointerSize)); @@ -226,7 +218,6 @@ static void AllocateJSArray(MacroAssembler* masm, // result: JSObject // elements_array_storage: initial map // array_size: size of array (smi) - __ bind(&allocated); __ str(elements_array_storage, FieldMemOperand(result, JSObject::kMapOffset)); __ LoadRoot(elements_array_storage, Heap::kEmptyFixedArrayRootIndex); __ str(elements_array_storage, @@ -256,14 +247,6 @@ static void AllocateJSArray(MacroAssembler* masm, ASSERT_EQ(0 * kPointerSize, FixedArray::kMapOffset); __ str(scratch1, MemOperand(elements_array_storage, kPointerSize, PostIndex)); STATIC_ASSERT(kSmiTag == 0); - __ tst(array_size, array_size); - // Length of the FixedArray is the number of pre-allocated elements if - // the actual JSArray has length 0 and the size of the JSArray for non-empty - // JSArrays. The length of a FixedArray is stored as a smi. - __ mov(array_size, - Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)), - LeaveCC, - eq); ASSERT_EQ(1 * kPointerSize, FixedArray::kLengthOffset); __ str(array_size, MemOperand(elements_array_storage, kPointerSize, PostIndex)); @@ -311,20 +294,20 @@ static void AllocateJSArray(MacroAssembler* masm, static void ArrayNativeCode(MacroAssembler* masm, Label* call_generic_code) { Counters* counters = masm->isolate()->counters(); - Label argc_one_or_more, argc_two_or_more; + Label argc_one_or_more, argc_two_or_more, not_empty_array, empty_array; // Check for array construction with zero arguments or one. __ cmp(r0, Operand(0, RelocInfo::NONE)); __ b(ne, &argc_one_or_more); // Handle construction of an empty array. + __ bind(&empty_array); AllocateEmptyJSArray(masm, r1, r2, r3, r4, r5, - JSArray::kPreallocatedArrayElements, call_generic_code); __ IncrementCounter(counters->array_function_native(), 1, r3, r4); // Setup return value, remove receiver from stack and return. @@ -339,6 +322,13 @@ static void ArrayNativeCode(MacroAssembler* masm, __ b(ne, &argc_two_or_more); STATIC_ASSERT(kSmiTag == 0); __ ldr(r2, MemOperand(sp)); // Get the argument from the stack. + __ tst(r2, r2); + __ b(ne, ¬_empty_array); + __ Drop(1); // Adjust stack. + __ mov(r0, Operand(0)); // Treat this as a call with argc of zero. + __ b(&empty_array); + + __ bind(¬_empty_array); __ and_(r3, r2, Operand(kIntptrSignBit | kSmiTagMask), SetCC); __ b(ne, call_generic_code); @@ -1027,9 +1017,9 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); // Set up the roots register. - ExternalReference roots_address = - ExternalReference::roots_address(masm->isolate()); - __ mov(r10, Operand(roots_address)); + ExternalReference roots_array_start = + ExternalReference::roots_array_start(masm->isolate()); + __ mov(r10, Operand(roots_array_start)); // Push the function and the receiver onto the stack. __ push(r1); diff --git a/deps/v8/src/arm/code-stubs-arm.cc b/deps/v8/src/arm/code-stubs-arm.cc index 44923a1..412ba00 100644 --- a/deps/v8/src/arm/code-stubs-arm.cc +++ b/deps/v8/src/arm/code-stubs-arm.cc @@ -263,7 +263,12 @@ void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { // [sp + (2 * kPointerSize)]: literals array. // All sizes here are multiples of kPointerSize. - int elements_size = (length_ > 0) ? FixedArray::SizeFor(length_) : 0; + int elements_size = 0; + if (length_ > 0) { + elements_size = mode_ == CLONE_DOUBLE_ELEMENTS + ? FixedDoubleArray::SizeFor(length_) + : FixedArray::SizeFor(length_); + } int size = JSArray::kSize + elements_size; // Load boilerplate object into r3 and check if we need to create a @@ -283,6 +288,9 @@ void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { if (mode_ == CLONE_ELEMENTS) { message = "Expected (writable) fixed array"; expected_map_index = Heap::kFixedArrayMapRootIndex; + } else if (mode_ == CLONE_DOUBLE_ELEMENTS) { + message = "Expected (writable) fixed double array"; + expected_map_index = Heap::kFixedDoubleArrayMapRootIndex; } else { ASSERT(mode_ == COPY_ON_WRITE_ELEMENTS); message = "Expected copy-on-write fixed array"; @@ -322,6 +330,7 @@ void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { __ str(r2, FieldMemOperand(r0, JSArray::kElementsOffset)); // Copy the elements array. + ASSERT((elements_size % kPointerSize) == 0); __ CopyFields(r2, r3, r1.bit(), elements_size / kPointerSize); } @@ -3913,7 +3922,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) { } // Get the prototype of the function. - __ TryGetFunctionPrototype(function, prototype, scratch, &slow); + __ TryGetFunctionPrototype(function, prototype, scratch, &slow, true); // Check that the function prototype is a JS object. __ JumpIfSmi(prototype, &slow); @@ -6668,7 +6677,82 @@ void DirectCEntryStub::GenerateCall(MacroAssembler* masm, } -MaybeObject* StringDictionaryLookupStub::GenerateNegativeLookup( +void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm, + Label* miss, + Label* done, + Register receiver, + Register properties, + Handle name, + Register scratch0) { + // If names of slots in range from 1 to kProbes - 1 for the hash value are + // not equal to the name and kProbes-th slot is not used (its name is the + // undefined value), it guarantees the hash table doesn't contain the + // property. It's true even if some slots represent deleted properties + // (their names are the null value). + for (int i = 0; i < kInlinedProbes; i++) { + // scratch0 points to properties hash. + // Compute the masked index: (hash + i + i * i) & mask. + Register index = scratch0; + // Capacity is smi 2^n. + __ ldr(index, FieldMemOperand(properties, kCapacityOffset)); + __ sub(index, index, Operand(1)); + __ and_(index, index, Operand( + Smi::FromInt(name->Hash() + StringDictionary::GetProbeOffset(i)))); + + // Scale the index by multiplying by the entry size. + ASSERT(StringDictionary::kEntrySize == 3); + __ add(index, index, Operand(index, LSL, 1)); // index *= 3. + + Register entity_name = scratch0; + // Having undefined at this place means the name is not contained. + ASSERT_EQ(kSmiTagSize, 1); + Register tmp = properties; + __ add(tmp, properties, Operand(index, LSL, 1)); + __ ldr(entity_name, FieldMemOperand(tmp, kElementsStartOffset)); + + ASSERT(!tmp.is(entity_name)); + __ LoadRoot(tmp, Heap::kUndefinedValueRootIndex); + __ cmp(entity_name, tmp); + __ b(eq, done); + + if (i != kInlinedProbes - 1) { + // Stop if found the property. + __ cmp(entity_name, Operand(Handle(name))); + __ b(eq, miss); + + // Check if the entry name is not a symbol. + __ ldr(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset)); + __ ldrb(entity_name, + FieldMemOperand(entity_name, Map::kInstanceTypeOffset)); + __ tst(entity_name, Operand(kIsSymbolMask)); + __ b(eq, miss); + + // Restore the properties. + __ ldr(properties, + FieldMemOperand(receiver, JSObject::kPropertiesOffset)); + } + } + + const int spill_mask = + (lr.bit() | r6.bit() | r5.bit() | r4.bit() | r3.bit() | + r2.bit() | r1.bit() | r0.bit()); + + __ stm(db_w, sp, spill_mask); + __ ldr(r0, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); + __ mov(r1, Operand(Handle(name))); + StringDictionaryLookupStub stub(NEGATIVE_LOOKUP); + __ CallStub(&stub); + __ tst(r0, Operand(r0)); + __ ldm(ia_w, sp, spill_mask); + + __ b(eq, done); + __ b(ne, miss); +} + + +// TODO(kmillikin): Eliminate this function when the stub cache is fully +// handlified. +MaybeObject* StringDictionaryLookupStub::TryGenerateNegativeLookup( MacroAssembler* masm, Label* miss, Label* done, @@ -6927,6 +7011,13 @@ struct AheadOfTimeWriteBarrierStubList kAheadOfTime[] = { { r3, r1, r2, EMIT_REMEMBERED_SET }, // KeyedStoreStubCompiler::GenerateStoreFastElement. { r4, r2, r3, EMIT_REMEMBERED_SET }, + // ElementsTransitionGenerator::GenerateSmiOnlyToObject + // and ElementsTransitionGenerator::GenerateSmiOnlyToDouble + // and ElementsTransitionGenerator::GenerateDoubleToObject + { r2, r3, r9, EMIT_REMEMBERED_SET }, + // ElementsTransitionGenerator::GenerateDoubleToObject + { r6, r2, r0, EMIT_REMEMBERED_SET }, + { r2, r6, r9, EMIT_REMEMBERED_SET }, // Null termination. { no_reg, no_reg, no_reg, EMIT_REMEMBERED_SET} }; @@ -7163,7 +7254,6 @@ void RecordWriteStub::CheckNeedsToInformIncrementalMarker( // Fall through when we need to inform the incremental marker. } - #undef __ } } // namespace v8::internal diff --git a/deps/v8/src/arm/code-stubs-arm.h b/deps/v8/src/arm/code-stubs-arm.h index 3ba75ba..647fc8d 100644 --- a/deps/v8/src/arm/code-stubs-arm.h +++ b/deps/v8/src/arm/code-stubs-arm.h @@ -799,7 +799,17 @@ class StringDictionaryLookupStub: public CodeStub { void Generate(MacroAssembler* masm); - MUST_USE_RESULT static MaybeObject* GenerateNegativeLookup( + static void GenerateNegativeLookup(MacroAssembler* masm, + Label* miss, + Label* done, + Register receiver, + Register properties, + Handle name, + Register scratch0); + + // TODO(kmillikin): Eliminate this function when the stub cache is fully + // handlified. + MUST_USE_RESULT static MaybeObject* TryGenerateNegativeLookup( MacroAssembler* masm, Label* miss, Label* done, diff --git a/deps/v8/src/arm/codegen-arm.cc b/deps/v8/src/arm/codegen-arm.cc index 3993ed0..508d830 100644 --- a/deps/v8/src/arm/codegen-arm.cc +++ b/deps/v8/src/arm/codegen-arm.cc @@ -30,10 +30,13 @@ #if defined(V8_TARGET_ARCH_ARM) #include "codegen.h" +#include "macro-assembler.h" namespace v8 { namespace internal { +#define __ ACCESS_MASM(masm) + // ------------------------------------------------------------------------- // Platform-specific RuntimeCallHelper functions. @@ -51,6 +54,252 @@ void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const { } +// ------------------------------------------------------------------------- +// Code generators + +void ElementsTransitionGenerator::GenerateSmiOnlyToObject( + MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- r0 : value + // -- r1 : key + // -- r2 : receiver + // -- lr : return address + // -- r3 : target map, scratch for subsequent call + // -- r4 : scratch (elements) + // ----------------------------------- + // Set transitioned map. + __ str(r3, FieldMemOperand(r2, HeapObject::kMapOffset)); + __ RecordWriteField(r2, + HeapObject::kMapOffset, + r3, + r9, + kLRHasNotBeenSaved, + kDontSaveFPRegs, + EMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); +} + + +void ElementsTransitionGenerator::GenerateSmiOnlyToDouble( + MacroAssembler* masm, Label* fail) { + // ----------- S t a t e ------------- + // -- r0 : value + // -- r1 : key + // -- r2 : receiver + // -- lr : return address + // -- r3 : target map, scratch for subsequent call + // -- r4 : scratch (elements) + // ----------------------------------- + Label loop, entry, convert_hole, gc_required; + bool vfp3_supported = CpuFeatures::IsSupported(VFP3); + __ push(lr); + + __ ldr(r4, FieldMemOperand(r2, JSObject::kElementsOffset)); + __ ldr(r5, FieldMemOperand(r4, FixedArray::kLengthOffset)); + // r4: source FixedArray + // r5: number of elements (smi-tagged) + + // Allocate new FixedDoubleArray. + __ mov(lr, Operand(FixedDoubleArray::kHeaderSize)); + __ add(lr, lr, Operand(r5, LSL, 2)); + __ AllocateInNewSpace(lr, r6, r7, r9, &gc_required, NO_ALLOCATION_FLAGS); + // r6: destination FixedDoubleArray, not tagged as heap object + __ LoadRoot(r9, Heap::kFixedDoubleArrayMapRootIndex); + __ str(r9, MemOperand(r6, HeapObject::kMapOffset)); + // Set destination FixedDoubleArray's length. + __ str(r5, MemOperand(r6, FixedDoubleArray::kLengthOffset)); + // Update receiver's map. + + __ str(r3, FieldMemOperand(r2, HeapObject::kMapOffset)); + __ RecordWriteField(r2, + HeapObject::kMapOffset, + r3, + r9, + kLRHasBeenSaved, + kDontSaveFPRegs, + EMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + // Replace receiver's backing store with newly created FixedDoubleArray. + __ add(r3, r6, Operand(kHeapObjectTag)); + __ str(r3, FieldMemOperand(r2, JSObject::kElementsOffset)); + __ RecordWriteField(r2, + JSObject::kElementsOffset, + r3, + r9, + kLRHasBeenSaved, + kDontSaveFPRegs, + EMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + + // Prepare for conversion loop. + __ add(r3, r4, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); + __ add(r7, r6, Operand(FixedDoubleArray::kHeaderSize)); + __ add(r6, r7, Operand(r5, LSL, 2)); + __ mov(r4, Operand(kHoleNanLower32)); + __ mov(r5, Operand(kHoleNanUpper32)); + // r3: begin of source FixedArray element fields, not tagged + // r4: kHoleNanLower32 + // r5: kHoleNanUpper32 + // r6: end of destination FixedDoubleArray, not tagged + // r7: begin of FixedDoubleArray element fields, not tagged + if (!vfp3_supported) __ Push(r1, r0); + + __ b(&entry); + + // Call into runtime if GC is required. + __ bind(&gc_required); + __ pop(lr); + __ b(fail); + + // Convert and copy elements. + __ bind(&loop); + __ ldr(r9, MemOperand(r3, 4, PostIndex)); + // r9: current element + __ JumpIfNotSmi(r9, &convert_hole); + + // Normal smi, convert to double and store. + __ SmiUntag(r9); + if (vfp3_supported) { + CpuFeatures::Scope scope(VFP3); + __ vmov(s0, r9); + __ vcvt_f64_s32(d0, s0); + __ vstr(d0, r7, 0); + __ add(r7, r7, Operand(8)); + } else { + FloatingPointHelper::ConvertIntToDouble(masm, + r9, + FloatingPointHelper::kCoreRegisters, + d0, + r0, + r1, + lr, + s0); + __ Strd(r0, r1, MemOperand(r7, 8, PostIndex)); + } + __ b(&entry); + + // Hole found, store the-hole NaN. + __ bind(&convert_hole); + __ Strd(r4, r5, MemOperand(r7, 8, PostIndex)); + + __ bind(&entry); + __ cmp(r7, r6); + __ b(lt, &loop); + + if (!vfp3_supported) __ Pop(r1, r0); + __ pop(lr); +} + + +void ElementsTransitionGenerator::GenerateDoubleToObject( + MacroAssembler* masm, Label* fail) { + // ----------- S t a t e ------------- + // -- r0 : value + // -- r1 : key + // -- r2 : receiver + // -- lr : return address + // -- r3 : target map, scratch for subsequent call + // -- r4 : scratch (elements) + // ----------------------------------- + Label entry, loop, convert_hole, gc_required; + + __ push(lr); + __ Push(r3, r2, r1, r0); + + __ ldr(r4, FieldMemOperand(r2, JSObject::kElementsOffset)); + __ ldr(r5, FieldMemOperand(r4, FixedArray::kLengthOffset)); + // r4: source FixedDoubleArray + // r5: number of elements (smi-tagged) + + // Allocate new FixedArray. + __ mov(r0, Operand(FixedDoubleArray::kHeaderSize)); + __ add(r0, r0, Operand(r5, LSL, 1)); + __ AllocateInNewSpace(r0, r6, r7, r9, &gc_required, NO_ALLOCATION_FLAGS); + // r6: destination FixedArray, not tagged as heap object + __ LoadRoot(r9, Heap::kFixedArrayMapRootIndex); + __ str(r9, MemOperand(r6, HeapObject::kMapOffset)); + // Set destination FixedDoubleArray's length. + __ str(r5, MemOperand(r6, FixedDoubleArray::kLengthOffset)); + + // Prepare for conversion loop. + __ add(r4, r4, Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag + 4)); + __ add(r3, r6, Operand(FixedArray::kHeaderSize)); + __ add(r6, r6, Operand(kHeapObjectTag)); + __ add(r5, r3, Operand(r5, LSL, 1)); + __ LoadRoot(r7, Heap::kTheHoleValueRootIndex); + __ LoadRoot(r9, Heap::kHeapNumberMapRootIndex); + // Using offsetted addresses in r4 to fully take advantage of post-indexing. + // r3: begin of destination FixedArray element fields, not tagged + // r4: begin of source FixedDoubleArray element fields, not tagged, +4 + // r5: end of destination FixedArray, not tagged + // r6: destination FixedArray + // r7: the-hole pointer + // r9: heap number map + __ b(&entry); + + // Call into runtime if GC is required. + __ bind(&gc_required); + __ Pop(r3, r2, r1, r0); + __ pop(lr); + __ b(fail); + + __ bind(&loop); + __ ldr(r1, MemOperand(r4, 8, PostIndex)); + // lr: current element's upper 32 bit + // r4: address of next element's upper 32 bit + __ cmp(r1, Operand(kHoleNanUpper32)); + __ b(eq, &convert_hole); + + // Non-hole double, copy value into a heap number. + __ AllocateHeapNumber(r2, r0, lr, r9, &gc_required); + // r2: new heap number + __ ldr(r0, MemOperand(r4, 12, NegOffset)); + __ Strd(r0, r1, FieldMemOperand(r2, HeapNumber::kValueOffset)); + __ mov(r0, r3); + __ str(r2, MemOperand(r3, 4, PostIndex)); + __ RecordWrite(r6, + r0, + r2, + kLRHasBeenSaved, + kDontSaveFPRegs, + EMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + __ b(&entry); + + // Replace the-hole NaN with the-hole pointer. + __ bind(&convert_hole); + __ str(r7, MemOperand(r3, 4, PostIndex)); + + __ bind(&entry); + __ cmp(r3, r5); + __ b(lt, &loop); + + __ Pop(r3, r2, r1, r0); + // Update receiver's map. + __ str(r3, FieldMemOperand(r2, HeapObject::kMapOffset)); + __ RecordWriteField(r2, + HeapObject::kMapOffset, + r3, + r9, + kLRHasBeenSaved, + kDontSaveFPRegs, + EMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + // Replace receiver's backing store with newly created and filled FixedArray. + __ str(r6, FieldMemOperand(r2, JSObject::kElementsOffset)); + __ RecordWriteField(r2, + JSObject::kElementsOffset, + r6, + r9, + kLRHasBeenSaved, + kDontSaveFPRegs, + EMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + __ pop(lr); +} + +#undef __ + } } // namespace v8::internal #endif // V8_TARGET_ARCH_ARM diff --git a/deps/v8/src/arm/codegen-arm.h b/deps/v8/src/arm/codegen-arm.h index 1c0d508..f54231c 100644 --- a/deps/v8/src/arm/codegen-arm.h +++ b/deps/v8/src/arm/codegen-arm.h @@ -29,7 +29,6 @@ #define V8_ARM_CODEGEN_ARM_H_ #include "ast.h" -#include "code-stubs-arm.h" #include "ic-inl.h" namespace v8 { diff --git a/deps/v8/src/arm/deoptimizer-arm.cc b/deps/v8/src/arm/deoptimizer-arm.cc index bb03d74..8505c7d 100644 --- a/deps/v8/src/arm/deoptimizer-arm.cc +++ b/deps/v8/src/arm/deoptimizer-arm.cc @@ -100,7 +100,6 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { } } - #ifdef DEBUG // Destroy the code which is not supposed to be run again. int instructions = @@ -178,16 +177,13 @@ void Deoptimizer::PatchStackCheckCodeAt(Code* unoptimized_code, Memory::uint32_at(stack_check_address_pointer) = reinterpret_cast(replacement_code->entry()); - RelocInfo rinfo(pc_after - 2 * kInstrSize, - RelocInfo::CODE_TARGET, - 0, - unoptimized_code); - unoptimized_code->GetHeap()->incremental_marking()->RecordWriteIntoCode( - unoptimized_code, &rinfo, replacement_code); + unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch( + unoptimized_code, pc_after - 2 * kInstrSize, replacement_code); } -void Deoptimizer::RevertStackCheckCodeAt(Address pc_after, +void Deoptimizer::RevertStackCheckCodeAt(Code* unoptimized_code, + Address pc_after, Code* check_code, Code* replacement_code) { const int kInstrSize = Assembler::kInstrSize; @@ -209,8 +205,8 @@ void Deoptimizer::RevertStackCheckCodeAt(Address pc_after, Memory::uint32_at(stack_check_address_pointer) = reinterpret_cast(check_code->entry()); - check_code->GetHeap()->incremental_marking()-> - RecordCodeTargetPatch(pc_after - 2 * kInstrSize, check_code); + check_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch( + unoptimized_code, pc_after - 2 * kInstrSize, check_code); } @@ -727,7 +723,6 @@ void Deoptimizer::EntryGenerator::Generate() { __ ldr(r3, MemOperand(r2, FrameDescription::frame_size_offset())); __ bind(&inner_push_loop); __ sub(r3, r3, Operand(sizeof(uint32_t))); - // __ add(r6, r2, Operand(r3, LSL, 1)); __ add(r6, r2, Operand(r3)); __ ldr(r7, MemOperand(r6, FrameDescription::frame_content_offset())); __ push(r7); @@ -761,8 +756,9 @@ void Deoptimizer::EntryGenerator::Generate() { __ pop(ip); // remove lr // Set up the roots register. - ExternalReference roots_address = ExternalReference::roots_address(isolate); - __ mov(r10, Operand(roots_address)); + ExternalReference roots_array_start = + ExternalReference::roots_array_start(isolate); + __ mov(r10, Operand(roots_array_start)); __ pop(ip); // remove pc __ pop(r7); // get continuation, leave pc on stack diff --git a/deps/v8/src/arm/full-codegen-arm.cc b/deps/v8/src/arm/full-codegen-arm.cc index 353ce5b..497a295 100644 --- a/deps/v8/src/arm/full-codegen-arm.cc +++ b/deps/v8/src/arm/full-codegen-arm.cc @@ -269,7 +269,10 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { // constant. if (scope()->is_function_scope() && scope()->function() != NULL) { int ignored = 0; - EmitDeclaration(scope()->function(), CONST, NULL, &ignored); + VariableProxy* proxy = scope()->function(); + ASSERT(proxy->var()->mode() == CONST || + proxy->var()->mode() == CONST_HARMONY); + EmitDeclaration(proxy, proxy->var()->mode(), NULL, &ignored); } VisitDeclarations(scope()->declarations()); } @@ -718,6 +721,8 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, // need to "declare" it at runtime to make sure it actually exists in the // local context. Variable* variable = proxy->var(); + bool binding_needs_init = + mode == CONST || mode == CONST_HARMONY || mode == LET; switch (variable->location()) { case Variable::UNALLOCATED: ++(*global_count); @@ -729,7 +734,7 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, Comment cmnt(masm_, "[ Declaration"); VisitForAccumulatorValue(function); __ str(result_register(), StackOperand(variable)); - } else if (mode == CONST || mode == LET) { + } else if (binding_needs_init) { Comment cmnt(masm_, "[ Declaration"); __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); __ str(ip, StackOperand(variable)); @@ -763,7 +768,7 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); PrepareForBailoutForId(proxy->id(), NO_REGISTERS); - } else if (mode == CONST || mode == LET) { + } else if (binding_needs_init) { Comment cmnt(masm_, "[ Declaration"); __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); __ str(ip, ContextOperand(cp, variable->index())); @@ -775,9 +780,13 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, case Variable::LOOKUP: { Comment cmnt(masm_, "[ Declaration"); __ mov(r2, Operand(variable->name())); - // Declaration nodes are always introduced in one of three modes. - ASSERT(mode == VAR || mode == CONST || mode == LET); - PropertyAttributes attr = (mode == CONST) ? READ_ONLY : NONE; + // Declaration nodes are always introduced in one of four modes. + ASSERT(mode == VAR || + mode == CONST || + mode == CONST_HARMONY || + mode == LET); + PropertyAttributes attr = (mode == CONST || mode == CONST_HARMONY) + ? READ_ONLY : NONE; __ mov(r1, Operand(Smi::FromInt(attr))); // Push initial value, if any. // Note: For variables we must not push an initial value (such as @@ -787,7 +796,7 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, __ Push(cp, r2, r1); // Push initial value for function declaration. VisitForStackValue(function); - } else if (mode == CONST || mode == LET) { + } else if (binding_needs_init) { __ LoadRoot(r0, Heap::kTheHoleValueRootIndex); __ Push(cp, r2, r1, r0); } else { @@ -929,11 +938,17 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ bind(&done_convert); __ push(r0); + // Check for proxies. + Label call_runtime; + STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); + __ CompareObjectType(r0, r1, r1, LAST_JS_PROXY_TYPE); + __ b(le, &call_runtime); + // Check cache validity in generated code. This is a fast case for // the JSObject::IsSimpleEnum cache validity checks. If we cannot // guarantee cache validity, call the runtime system to check cache // validity or get the property names in a fixed array. - Label next, call_runtime; + Label next; // Preload a couple of values used in the loop. Register empty_fixed_array_value = r6; __ LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex); @@ -1012,9 +1027,16 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ jmp(&loop); // We got a fixed array in register r0. Iterate through that. + Label non_proxy; __ bind(&fixed_array); - __ mov(r1, Operand(Smi::FromInt(0))); // Map (0) - force slow check. - __ Push(r1, r0); + __ mov(r1, Operand(Smi::FromInt(1))); // Smi indicates slow check + __ ldr(r2, MemOperand(sp, 0 * kPointerSize)); // Get enumerated object + STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); + __ CompareObjectType(r2, r3, r3, LAST_JS_PROXY_TYPE); + __ b(gt, &non_proxy); + __ mov(r1, Operand(Smi::FromInt(0))); // Zero indicates proxy + __ bind(&non_proxy); + __ Push(r1, r0); // Smi and array __ ldr(r1, FieldMemOperand(r0, FixedArray::kLengthOffset)); __ mov(r0, Operand(Smi::FromInt(0))); __ Push(r1, r0); // Fixed array length (as smi) and initial index. @@ -1031,18 +1053,23 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ add(r2, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); __ ldr(r3, MemOperand(r2, r0, LSL, kPointerSizeLog2 - kSmiTagSize)); - // Get the expected map from the stack or a zero map in the + // Get the expected map from the stack or a smi in the // permanent slow case into register r2. __ ldr(r2, MemOperand(sp, 3 * kPointerSize)); // Check if the expected map still matches that of the enumerable. - // If not, we have to filter the key. + // If not, we may have to filter the key. Label update_each; __ ldr(r1, MemOperand(sp, 4 * kPointerSize)); __ ldr(r4, FieldMemOperand(r1, HeapObject::kMapOffset)); __ cmp(r4, Operand(r2)); __ b(eq, &update_each); + // For proxies, no filtering is done. + // TODO(rossberg): What if only a prototype is a proxy? Not specified yet. + __ cmp(r2, Operand(Smi::FromInt(0))); + __ b(eq, &update_each); + // Convert the entry to a string or (smi) 0 if it isn't a property // any more. If the property has been removed while iterating, we // just skip it. @@ -1097,7 +1124,7 @@ void FullCodeGenerator::EmitNewClosure(Handle info, !pretenure && scope()->is_function_scope() && info->num_literals() == 0) { - FastNewClosureStub stub(info->strict_mode() ? kStrictMode : kNonStrictMode); + FastNewClosureStub stub(info->strict_mode_flag()); __ mov(r0, Operand(info)); __ push(r0); __ CallStub(&stub); @@ -1128,7 +1155,7 @@ void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var, Scope* s = scope(); while (s != NULL) { if (s->num_heap_slots() > 0) { - if (s->calls_eval()) { + if (s->calls_non_strict_eval()) { // Check that extension is NULL. __ ldr(temp, ContextOperand(current, Context::EXTENSION_INDEX)); __ tst(temp, temp); @@ -1141,7 +1168,7 @@ void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var, } // If no outer scope calls eval, we do not need to check more // context extensions. - if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break; + if (!s->outer_scope_calls_non_strict_eval() || s->is_eval_scope()) break; s = s->outer_scope(); } @@ -1185,7 +1212,7 @@ MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var, for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) { if (s->num_heap_slots() > 0) { - if (s->calls_eval()) { + if (s->calls_non_strict_eval()) { // Check that extension is NULL. __ ldr(temp, ContextOperand(context, Context::EXTENSION_INDEX)); __ tst(temp, temp); @@ -1224,11 +1251,12 @@ void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var, Variable* local = var->local_if_not_shadowed(); __ ldr(r0, ContextSlotOperandCheckExtensions(local, slow)); if (local->mode() == CONST || + local->mode() == CONST_HARMONY || local->mode() == LET) { __ CompareRoot(r0, Heap::kTheHoleValueRootIndex); if (local->mode() == CONST) { __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); - } else { // LET + } else { // LET || CONST_HARMONY __ b(ne, done); __ mov(r0, Operand(var->name())); __ push(r0); @@ -1266,13 +1294,15 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { Comment cmnt(masm_, var->IsContextSlot() ? "Context variable" : "Stack variable"); - if (var->mode() != LET && var->mode() != CONST) { + if (!var->binding_needs_init()) { context()->Plug(var); } else { // Let and const need a read barrier. GetVar(r0, var); __ CompareRoot(r0, Heap::kTheHoleValueRootIndex); - if (var->mode() == LET) { + if (var->mode() == LET || var->mode() == CONST_HARMONY) { + // Throw a reference error when using an uninitialized let/const + // binding in harmony mode. Label done; __ b(ne, &done); __ mov(r0, Operand(var->name())); @@ -1280,6 +1310,8 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { __ CallRuntime(Runtime::kThrowReferenceError, 1); __ bind(&done); } else { + // Uninitalized const bindings outside of harmony mode are unholed. + ASSERT(var->mode() == CONST); __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); } context()->Plug(r0); @@ -1467,13 +1499,19 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { ZoneList* subexprs = expr->values(); int length = subexprs->length(); + Handle constant_elements = expr->constant_elements(); + ASSERT_EQ(2, constant_elements->length()); + ElementsKind constant_elements_kind = + static_cast(Smi::cast(constant_elements->get(0))->value()); + Handle constant_elements_values( + FixedArrayBase::cast(constant_elements->get(1))); __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset)); __ mov(r2, Operand(Smi::FromInt(expr->literal_index()))); - __ mov(r1, Operand(expr->constant_elements())); + __ mov(r1, Operand(constant_elements)); __ Push(r3, r2, r1); - if (expr->constant_elements()->map() == + if (constant_elements_values->map() == isolate()->heap()->fixed_cow_array_map()) { FastCloneShallowArrayStub stub( FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length); @@ -1485,8 +1523,14 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) { __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3); } else { - FastCloneShallowArrayStub stub( - FastCloneShallowArrayStub::CLONE_ELEMENTS, length); + ASSERT(constant_elements_kind == FAST_ELEMENTS || + constant_elements_kind == FAST_SMI_ONLY_ELEMENTS || + FLAG_smi_only_arrays); + FastCloneShallowArrayStub::Mode mode = + constant_elements_kind == FAST_DOUBLE_ELEMENTS + ? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS + : FastCloneShallowArrayStub::CLONE_ELEMENTS; + FastCloneShallowArrayStub stub(mode, length); __ CallStub(&stub); } @@ -1509,24 +1553,56 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { } VisitForAccumulatorValue(subexpr); - // Store the subexpression value in the array's elements. __ ldr(r6, MemOperand(sp)); // Copy of array literal. __ ldr(r1, FieldMemOperand(r6, JSObject::kElementsOffset)); + __ ldr(r2, FieldMemOperand(r6, JSObject::kMapOffset)); int offset = FixedArray::kHeaderSize + (i * kPointerSize); - __ str(result_register(), FieldMemOperand(r1, offset)); - Label no_map_change; - __ JumpIfSmi(result_register(), &no_map_change); - // Update the write barrier for the array store with r0 as the scratch - // register. + Label element_done; + Label double_elements; + Label smi_element; + Label slow_elements; + Label fast_elements; + __ CheckFastElements(r2, r3, &double_elements); + + // FAST_SMI_ONLY_ELEMENTS or FAST_ELEMENTS + __ JumpIfSmi(result_register(), &smi_element); + __ CheckFastSmiOnlyElements(r2, r3, &fast_elements); + + // Store into the array literal requires a elements transition. Call into + // the runtime. + __ bind(&slow_elements); + __ push(r6); // Copy of array literal. + __ mov(r1, Operand(Smi::FromInt(i))); + __ mov(r2, Operand(Smi::FromInt(NONE))); // PropertyAttributes + __ mov(r3, Operand(Smi::FromInt(strict_mode_flag()))); // Strict mode. + __ Push(r1, result_register(), r2, r3); + __ CallRuntime(Runtime::kSetProperty, 5); + __ b(&element_done); + + // Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS. + __ bind(&double_elements); + __ mov(r3, Operand(Smi::FromInt(i))); + __ StoreNumberToDoubleElements(result_register(), r3, r6, r1, r4, r5, r9, + r7, &slow_elements); + __ b(&element_done); + + // Array literal has ElementsKind of FAST_ELEMENTS and value is an object. + __ bind(&fast_elements); + __ str(result_register(), FieldMemOperand(r1, offset)); + // Update the write barrier for the array store. __ RecordWriteField( r1, offset, result_register(), r2, kLRHasBeenSaved, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); - __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset)); - __ CheckFastSmiOnlyElements(r3, r2, &no_map_change); - __ push(r6); // Copy of array literal. - __ CallRuntime(Runtime::kNonSmiElementStored, 1); - __ bind(&no_map_change); + __ b(&element_done); + + // Array literal has ElementsKind of FAST_SMI_ONLY_ELEMENTS or + // FAST_ELEMENTS, and value is Smi. + __ bind(&smi_element); + __ str(result_register(), FieldMemOperand(r1, offset)); + // Fall through + + __ bind(&element_done); PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); } @@ -1903,8 +1979,9 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, } } - } else if (var->mode() != CONST) { - // Assignment to var or initializing assignment to let. + } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) { + // Assignment to var or initializing assignment to let/const + // in harmony mode. if (var->IsStackAllocated() || var->IsContextSlot()) { MemOperand location = VarOperand(var, r1); if (FLAG_debug_code && op == Token::INIT_LET) { @@ -2784,7 +2861,8 @@ void FullCodeGenerator::EmitRandomHeapNumber(ZoneList* args) { // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)). if (CpuFeatures::IsSupported(VFP3)) { __ PrepareCallCFunction(1, r0); - __ mov(r0, Operand(ExternalReference::isolate_address())); + __ ldr(r0, ContextOperand(context_register(), Context::GLOBAL_INDEX)); + __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalContextOffset)); __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1); CpuFeatures::Scope scope(VFP3); @@ -2804,8 +2882,9 @@ void FullCodeGenerator::EmitRandomHeapNumber(ZoneList* args) { __ mov(r0, r4); } else { __ PrepareCallCFunction(2, r0); + __ ldr(r1, ContextOperand(context_register(), Context::GLOBAL_INDEX)); __ mov(r0, Operand(r4)); - __ mov(r1, Operand(ExternalReference::isolate_address())); + __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalContextOffset)); __ CallCFunction( ExternalReference::fill_heap_number_with_random_function(isolate()), 2); } @@ -4071,33 +4150,25 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { case Token::EQ_STRICT: case Token::EQ: cond = eq; - __ pop(r1); break; case Token::LT: cond = lt; - __ pop(r1); break; case Token::GT: - // Reverse left and right sides to obtain ECMA-262 conversion order. - cond = lt; - __ mov(r1, result_register()); - __ pop(r0); + cond = gt; break; case Token::LTE: - // Reverse left and right sides to obtain ECMA-262 conversion order. - cond = ge; - __ mov(r1, result_register()); - __ pop(r0); + cond = le; break; case Token::GTE: cond = ge; - __ pop(r1); break; case Token::IN: case Token::INSTANCEOF: default: UNREACHABLE(); } + __ pop(r1); bool inline_smi_code = ShouldInlineSmiCase(op); JumpPatchSite patch_site(masm_); diff --git a/deps/v8/src/arm/ic-arm.cc b/deps/v8/src/arm/ic-arm.cc index 6e0badc..18d4a9f 100644 --- a/deps/v8/src/arm/ic-arm.cc +++ b/deps/v8/src/arm/ic-arm.cc @@ -382,10 +382,10 @@ Object* CallIC_Miss(Arguments args); // The generated code does not accept smi keys. // The generated code falls through if both probes miss. -static void GenerateMonomorphicCacheProbe(MacroAssembler* masm, - int argc, - Code::Kind kind, - Code::ExtraICState extra_ic_state) { +void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm, + int argc, + Code::Kind kind, + Code::ExtraICState extra_state) { // ----------- S t a t e ------------- // -- r1 : receiver // -- r2 : name @@ -395,7 +395,7 @@ static void GenerateMonomorphicCacheProbe(MacroAssembler* masm, // Probe the stub cache. Code::Flags flags = Code::ComputeFlags(kind, MONOMORPHIC, - extra_ic_state, + extra_state, NORMAL, argc); Isolate::Current()->stub_cache()->GenerateProbe( @@ -464,7 +464,7 @@ static void GenerateFunctionTailCall(MacroAssembler* masm, } -static void GenerateCallNormal(MacroAssembler* masm, int argc) { +void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) { // ----------- S t a t e ------------- // -- r2 : name // -- lr : return address @@ -486,10 +486,10 @@ static void GenerateCallNormal(MacroAssembler* masm, int argc) { } -static void GenerateCallMiss(MacroAssembler* masm, - int argc, - IC::UtilityId id, - Code::ExtraICState extra_ic_state) { +void CallICBase::GenerateMiss(MacroAssembler* masm, + int argc, + IC::UtilityId id, + Code::ExtraICState extra_state) { // ----------- S t a t e ------------- // -- r2 : name // -- lr : return address @@ -541,7 +541,7 @@ static void GenerateCallMiss(MacroAssembler* masm, } // Invoke the function. - CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state) + CallKind call_kind = CallICBase::Contextual::decode(extra_state) ? CALL_AS_FUNCTION : CALL_AS_METHOD; ParameterCount actual(argc); @@ -553,18 +553,6 @@ static void GenerateCallMiss(MacroAssembler* masm, } -void CallIC::GenerateMiss(MacroAssembler* masm, - int argc, - Code::ExtraICState extra_ic_state) { - // ----------- S t a t e ------------- - // -- r2 : name - // -- lr : return address - // ----------------------------------- - - GenerateCallMiss(masm, argc, IC::kCallIC_Miss, extra_ic_state); -} - - void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc, Code::ExtraICState extra_ic_state) { @@ -580,27 +568,6 @@ void CallIC::GenerateMegamorphic(MacroAssembler* masm, } -void CallIC::GenerateNormal(MacroAssembler* masm, int argc) { - // ----------- S t a t e ------------- - // -- r2 : name - // -- lr : return address - // ----------------------------------- - - GenerateCallNormal(masm, argc); - GenerateMiss(masm, argc, Code::kNoExtraICState); -} - - -void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) { - // ----------- S t a t e ------------- - // -- r2 : name - // -- lr : return address - // ----------------------------------- - - GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss, Code::kNoExtraICState); -} - - void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) { // ----------- S t a t e ------------- // -- r2 : name @@ -718,7 +685,7 @@ void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) { __ JumpIfSmi(r2, &miss); __ IsObjectJSStringType(r2, r0, &miss); - GenerateCallNormal(masm, argc); + CallICBase::GenerateNormal(masm, argc); __ bind(&miss); GenerateMiss(masm, argc); } @@ -1244,6 +1211,47 @@ void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) { } +void KeyedStoreIC::GenerateTransitionElementsSmiToDouble(MacroAssembler* masm) { + // ---------- S t a t e -------------- + // -- r2 : receiver + // -- r3 : target map + // -- lr : return address + // ----------------------------------- + // Must return the modified receiver in r0. + if (!FLAG_trace_elements_transitions) { + Label fail; + ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &fail); + __ mov(r0, r2); + __ Ret(); + __ bind(&fail); + } + + __ push(r2); + __ TailCallRuntime(Runtime::kTransitionElementsSmiToDouble, 1, 1); +} + + +void KeyedStoreIC::GenerateTransitionElementsDoubleToObject( + MacroAssembler* masm) { + // ---------- S t a t e -------------- + // -- r2 : receiver + // -- r3 : target map + // -- lr : return address + // ----------------------------------- + // Must return the modified receiver in r0. + if (!FLAG_trace_elements_transitions) { + Label fail; + ElementsTransitionGenerator::GenerateDoubleToObject(masm, &fail); + __ mov(r0, r2); + __ Ret(); + __ bind(&fail); + } + + __ push(r2); + __ TailCallRuntime(Runtime::kTransitionElementsDoubleToObject, 1, 1); +} + + void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm, StrictModeFlag strict_mode) { // ---------- S t a t e -------------- @@ -1559,11 +1567,9 @@ Condition CompareIC::ComputeCondition(Token::Value op) { case Token::LT: return lt; case Token::GT: - // Reverse left and right operands to obtain ECMA-262 conversion order. - return lt; + return gt; case Token::LTE: - // Reverse left and right operands to obtain ECMA-262 conversion order. - return ge; + return le; case Token::GTE: return ge; default: diff --git a/deps/v8/src/arm/lithium-arm.cc b/deps/v8/src/arm/lithium-arm.cc index 8495939..5197842 100644 --- a/deps/v8/src/arm/lithium-arm.cc +++ b/deps/v8/src/arm/lithium-arm.cc @@ -391,6 +391,12 @@ void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) { } +void LTransitionElementsKind::PrintDataTo(StringStream* stream) { + object()->PrintTo(stream); + stream->Add(" %p -> %p", *original_map(), *transitioned_map()); +} + + LChunk::LChunk(CompilationInfo* info, HGraph* graph) : spill_slot_count_(0), info_(info), @@ -1404,12 +1410,10 @@ LInstruction* LChunkBuilder::DoPower(HPower* instr) { LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) { - Token::Value op = instr->token(); ASSERT(instr->left()->representation().IsTagged()); ASSERT(instr->right()->representation().IsTagged()); - bool reversed = (op == Token::GT || op == Token::LTE); - LOperand* left = UseFixed(instr->left(), reversed ? r0 : r1); - LOperand* right = UseFixed(instr->right(), reversed ? r1 : r0); + LOperand* left = UseFixed(instr->left(), r1); + LOperand* right = UseFixed(instr->right(), r0); LCmpT* result = new LCmpT(left, right); return MarkAsCall(DefineFixed(result, r0), instr); } @@ -1421,8 +1425,8 @@ LInstruction* LChunkBuilder::DoCompareIDAndBranch( if (r.IsInteger32()) { ASSERT(instr->left()->representation().IsInteger32()); ASSERT(instr->right()->representation().IsInteger32()); - LOperand* left = UseRegisterAtStart(instr->left()); - LOperand* right = UseRegisterAtStart(instr->right()); + LOperand* left = UseRegisterOrConstantAtStart(instr->left()); + LOperand* right = UseRegisterOrConstantAtStart(instr->right()); return new LCmpIDAndBranch(left, right); } else { ASSERT(r.IsDouble()); @@ -1970,6 +1974,26 @@ LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) { } +LInstruction* LChunkBuilder::DoTransitionElementsKind( + HTransitionElementsKind* instr) { + if (instr->original_map()->elements_kind() == FAST_SMI_ONLY_ELEMENTS && + instr->transitioned_map()->elements_kind() == FAST_ELEMENTS) { + LOperand* object = UseRegister(instr->object()); + LOperand* new_map_reg = TempRegister(); + LTransitionElementsKind* result = + new LTransitionElementsKind(object, new_map_reg, NULL); + return DefineSameAsFirst(result); + } else { + LOperand* object = UseFixed(instr->object(), r0); + LOperand* fixed_object_reg = FixedTemp(r2); + LOperand* new_map_reg = FixedTemp(r3); + LTransitionElementsKind* result = + new LTransitionElementsKind(object, new_map_reg, fixed_object_reg); + return MarkAsCall(DefineFixed(result, r0), instr); + } +} + + LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) { bool needs_write_barrier = instr->NeedsWriteBarrier(); diff --git a/deps/v8/src/arm/lithium-arm.h b/deps/v8/src/arm/lithium-arm.h index 73c7e45..5733bd0 100644 --- a/deps/v8/src/arm/lithium-arm.h +++ b/deps/v8/src/arm/lithium-arm.h @@ -162,6 +162,7 @@ class LCodeGen; V(ThisFunction) \ V(Throw) \ V(ToFastProperties) \ + V(TransitionElementsKind) \ V(Typeof) \ V(TypeofIsAndBranch) \ V(UnaryMathOperation) \ @@ -1260,7 +1261,6 @@ class LStoreContextSlot: public LTemplateInstruction<0, 2, 0> { LOperand* context() { return InputAt(0); } LOperand* value() { return InputAt(1); } int slot_index() { return hydrogen()->slot_index(); } - int needs_write_barrier() { return hydrogen()->NeedsWriteBarrier(); } virtual void PrintDataTo(StringStream* stream); }; @@ -1277,7 +1277,9 @@ class LPushArgument: public LTemplateInstruction<0, 1, 0> { class LThisFunction: public LTemplateInstruction<1, 0, 0> { + public: DECLARE_CONCRETE_INSTRUCTION(ThisFunction, "this-function") + DECLARE_HYDROGEN_ACCESSOR(ThisFunction) }; @@ -1561,7 +1563,6 @@ class LStoreNamedField: public LTemplateInstruction<0, 2, 0> { Handle name() const { return hydrogen()->name(); } bool is_in_object() { return hydrogen()->is_in_object(); } int offset() { return hydrogen()->offset(); } - bool needs_write_barrier() { return hydrogen()->NeedsWriteBarrier(); } Handle transition() const { return hydrogen()->transition(); } }; @@ -1581,7 +1582,8 @@ class LStoreNamedGeneric: public LTemplateInstruction<0, 2, 0> { LOperand* object() { return inputs_[0]; } LOperand* value() { return inputs_[1]; } Handle name() const { return hydrogen()->name(); } - bool strict_mode() { return hydrogen()->strict_mode(); } + StrictModeFlag strict_mode_flag() { return hydrogen()->strict_mode_flag(); } + bool strict_mode() { return strict_mode_flag() == kStrictMode; } }; @@ -1669,6 +1671,30 @@ class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 0> { }; +class LTransitionElementsKind: public LTemplateInstruction<1, 1, 2> { + public: + LTransitionElementsKind(LOperand* object, + LOperand* new_map_temp, + LOperand* temp_reg) { + inputs_[0] = object; + temps_[0] = new_map_temp; + temps_[1] = temp_reg; + } + + DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind, + "transition-elements-kind") + DECLARE_HYDROGEN_ACCESSOR(TransitionElementsKind) + + virtual void PrintDataTo(StringStream* stream); + + LOperand* object() { return inputs_[0]; } + LOperand* new_map_reg() { return temps_[0]; } + LOperand* temp_reg() { return temps_[1]; } + Handle original_map() { return hydrogen()->original_map(); } + Handle transitioned_map() { return hydrogen()->transitioned_map(); } +}; + + class LStringAdd: public LTemplateInstruction<1, 2, 0> { public: LStringAdd(LOperand* left, LOperand* right) { diff --git a/deps/v8/src/arm/lithium-codegen-arm.cc b/deps/v8/src/arm/lithium-codegen-arm.cc index 70ef884..4cf7df4 100644 --- a/deps/v8/src/arm/lithium-codegen-arm.cc +++ b/deps/v8/src/arm/lithium-codegen-arm.cc @@ -410,6 +410,12 @@ int LCodeGen::ToInteger32(LConstantOperand* op) const { } +double LCodeGen::ToDouble(LConstantOperand* op) const { + Handle value = chunk_->LookupLiteral(op); + return value->Number(); +} + + Operand LCodeGen::ToOperand(LOperand* op) { if (op->IsConstantOperand()) { LConstantOperand* const_op = LConstantOperand::cast(op); @@ -1705,30 +1711,44 @@ Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) { } -void LCodeGen::EmitCmpI(LOperand* left, LOperand* right) { - __ cmp(ToRegister(left), ToRegister(right)); -} - - void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { LOperand* left = instr->InputAt(0); LOperand* right = instr->InputAt(1); int false_block = chunk_->LookupDestination(instr->false_block_id()); int true_block = chunk_->LookupDestination(instr->true_block_id()); - - if (instr->is_double()) { - // Compare left and right as doubles and load the - // resulting flags into the normal status register. - __ VFPCompareAndSetFlags(ToDoubleRegister(left), ToDoubleRegister(right)); - // If a NaN is involved, i.e. the result is unordered (V set), - // jump to false block label. - __ b(vs, chunk_->GetAssemblyLabel(false_block)); + Condition cond = TokenToCondition(instr->op(), false); + + if (left->IsConstantOperand() && right->IsConstantOperand()) { + // We can statically evaluate the comparison. + double left_val = ToDouble(LConstantOperand::cast(left)); + double right_val = ToDouble(LConstantOperand::cast(right)); + int next_block = + EvalComparison(instr->op(), left_val, right_val) ? true_block + : false_block; + EmitGoto(next_block); } else { - EmitCmpI(left, right); + if (instr->is_double()) { + // Compare left and right operands as doubles and load the + // resulting flags into the normal status register. + __ VFPCompareAndSetFlags(ToDoubleRegister(left), ToDoubleRegister(right)); + // If a NaN is involved, i.e. the result is unordered (V set), + // jump to false block label. + __ b(vs, chunk_->GetAssemblyLabel(false_block)); + } else { + if (right->IsConstantOperand()) { + __ cmp(ToRegister(left), + Operand(ToInteger32(LConstantOperand::cast(right)))); + } else if (left->IsConstantOperand()) { + __ cmp(ToRegister(right), + Operand(ToInteger32(LConstantOperand::cast(left)))); + // We transposed the operands. Reverse the condition. + cond = ReverseCondition(cond); + } else { + __ cmp(ToRegister(left), ToRegister(right)); + } + } + EmitBranch(true_block, false_block, cond); } - - Condition cc = TokenToCondition(instr->op(), instr->is_double()); - EmitBranch(true_block, false_block, cc); } @@ -2176,9 +2196,6 @@ void LCodeGen::DoCmpT(LCmpT* instr) { __ cmp(r0, Operand(0)); // This instruction also signals no smi code inlined. Condition condition = ComputeCompareCondition(op); - if (op == Token::GT || op == Token::LTE) { - condition = ReverseCondition(condition); - } __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex, condition); @@ -2251,13 +2268,19 @@ void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) { __ str(value, FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset)); // Cells are always in the remembered set. - __ RecordWriteField(scratch, - JSGlobalPropertyCell::kValueOffset, - value, - scratch2, - kLRHasBeenSaved, - kSaveFPRegs, - OMIT_REMEMBERED_SET); + if (instr->hydrogen()->NeedsWriteBarrier()) { + HType type = instr->hydrogen()->value()->type(); + SmiCheck check_needed = + type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; + __ RecordWriteField(scratch, + JSGlobalPropertyCell::kValueOffset, + value, + scratch2, + kLRHasBeenSaved, + kSaveFPRegs, + OMIT_REMEMBERED_SET, + check_needed); + } } @@ -2285,13 +2308,18 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) { Register value = ToRegister(instr->value()); MemOperand target = ContextOperand(context, instr->slot_index()); __ str(value, target); - if (instr->needs_write_barrier()) { + if (instr->hydrogen()->NeedsWriteBarrier()) { + HType type = instr->hydrogen()->value()->type(); + SmiCheck check_needed = + type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; __ RecordWriteContextSlot(context, target.offset(), value, scratch0(), kLRHasBeenSaved, - kSaveFPRegs); + kSaveFPRegs, + EMIT_REMEMBERED_SET, + check_needed); } } @@ -2312,7 +2340,7 @@ void LCodeGen::EmitLoadFieldOrConstantFunction(Register result, Register object, Handle type, Handle name) { - LookupResult lookup; + LookupResult lookup(isolate()); type->LookupInDescriptors(NULL, *name, &lookup); ASSERT(lookup.IsProperty() && (lookup.type() == FIELD || lookup.type() == CONSTANT_FUNCTION)); @@ -2778,7 +2806,7 @@ void LCodeGen::DoPushArgument(LPushArgument* instr) { void LCodeGen::DoThisFunction(LThisFunction* instr) { Register result = ToRegister(instr->result()); - __ ldr(result, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); + LoadHeapObject(result, instr->hydrogen()->closure()); } @@ -3297,21 +3325,36 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { } // Do the store. + HType type = instr->hydrogen()->value()->type(); + SmiCheck check_needed = + type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; if (instr->is_in_object()) { __ str(value, FieldMemOperand(object, offset)); - if (instr->needs_write_barrier()) { + if (instr->hydrogen()->NeedsWriteBarrier()) { // Update the write barrier for the object for in-object properties. - __ RecordWriteField( - object, offset, value, scratch, kLRHasBeenSaved, kSaveFPRegs); + __ RecordWriteField(object, + offset, + value, + scratch, + kLRHasBeenSaved, + kSaveFPRegs, + EMIT_REMEMBERED_SET, + check_needed); } } else { __ ldr(scratch, FieldMemOperand(object, JSObject::kPropertiesOffset)); __ str(value, FieldMemOperand(scratch, offset)); - if (instr->needs_write_barrier()) { + if (instr->hydrogen()->NeedsWriteBarrier()) { // Update the write barrier for the properties array. // object is used as a scratch register. - __ RecordWriteField( - scratch, offset, value, object, kLRHasBeenSaved, kSaveFPRegs); + __ RecordWriteField(scratch, + offset, + value, + object, + kLRHasBeenSaved, + kSaveFPRegs, + EMIT_REMEMBERED_SET, + check_needed); } } } @@ -3362,9 +3405,18 @@ void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) { } if (instr->hydrogen()->NeedsWriteBarrier()) { + HType type = instr->hydrogen()->value()->type(); + SmiCheck check_needed = + type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; // Compute address of modified element and store it into key register. __ add(key, scratch, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); - __ RecordWrite(elements, key, value, kLRHasBeenSaved, kSaveFPRegs); + __ RecordWrite(elements, + key, + value, + kLRHasBeenSaved, + kSaveFPRegs, + EMIT_REMEMBERED_SET, + check_needed); } } @@ -3487,6 +3539,48 @@ void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { } +void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { + Register object_reg = ToRegister(instr->object()); + Register new_map_reg = ToRegister(instr->new_map_reg()); + Register scratch = scratch0(); + + Handle from_map = instr->original_map(); + Handle to_map = instr->transitioned_map(); + ElementsKind from_kind = from_map->elements_kind(); + ElementsKind to_kind = to_map->elements_kind(); + + Label not_applicable; + __ ldr(scratch, FieldMemOperand(object_reg, HeapObject::kMapOffset)); + __ cmp(scratch, Operand(from_map)); + __ b(ne, ¬_applicable); + __ mov(new_map_reg, Operand(to_map)); + if (from_kind == FAST_SMI_ONLY_ELEMENTS && to_kind == FAST_ELEMENTS) { + __ str(new_map_reg, FieldMemOperand(object_reg, HeapObject::kMapOffset)); + // Write barrier. + __ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg, + scratch, kLRHasBeenSaved, kDontSaveFPRegs); + } else if (from_kind == FAST_SMI_ONLY_ELEMENTS && + to_kind == FAST_DOUBLE_ELEMENTS) { + Register fixed_object_reg = ToRegister(instr->temp_reg()); + ASSERT(fixed_object_reg.is(r2)); + ASSERT(new_map_reg.is(r3)); + __ mov(fixed_object_reg, object_reg); + CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(), + RelocInfo::CODE_TARGET, instr); + } else if (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS) { + Register fixed_object_reg = ToRegister(instr->temp_reg()); + ASSERT(fixed_object_reg.is(r2)); + ASSERT(new_map_reg.is(r3)); + __ mov(fixed_object_reg, object_reg); + CallCode(isolate()->builtins()->TransitionElementsDoubleToObject(), + RelocInfo::CODE_TARGET, instr); + } else { + UNREACHABLE(); + } + __ bind(¬_applicable); +} + + void LCodeGen::DoStringAdd(LStringAdd* instr) { __ push(ToRegister(instr->left())); __ push(ToRegister(instr->right())); @@ -4203,10 +4297,15 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) { + Handle constant_elements = instr->hydrogen()->constant_elements(); + ASSERT_EQ(2, constant_elements->length()); + ElementsKind constant_elements_kind = + static_cast(Smi::cast(constant_elements->get(0))->value()); + __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset)); __ mov(r2, Operand(Smi::FromInt(instr->hydrogen()->literal_index()))); - __ mov(r1, Operand(instr->hydrogen()->constant_elements())); + __ mov(r1, Operand(constant_elements)); __ Push(r3, r2, r1); // Pick the right runtime function or stub to call. @@ -4223,7 +4322,9 @@ void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) { CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr); } else { FastCloneShallowArrayStub::Mode mode = - FastCloneShallowArrayStub::CLONE_ELEMENTS; + constant_elements_kind == FAST_DOUBLE_ELEMENTS + ? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS + : FastCloneShallowArrayStub::CLONE_ELEMENTS; FastCloneShallowArrayStub stub(mode, length); CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); } @@ -4315,8 +4416,7 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { Handle shared_info = instr->shared_info(); bool pretenure = instr->hydrogen()->pretenure(); if (!pretenure && shared_info->num_literals() == 0) { - FastNewClosureStub stub( - shared_info->strict_mode() ? kStrictMode : kNonStrictMode); + FastNewClosureStub stub(shared_info->strict_mode_flag()); __ mov(r1, Operand(shared_info)); __ push(r1); CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); @@ -4349,8 +4449,9 @@ void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { false_label, input, instr->type_literal()); - - EmitBranch(true_block, false_block, final_branch_condition); + if (final_branch_condition != kNoCondition) { + EmitBranch(true_block, false_block, final_branch_condition); + } } @@ -4420,9 +4521,7 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, final_branch_condition = eq; } else { - final_branch_condition = ne; __ b(false_label); - // A dead branch instruction will be generated after this point. } return final_branch_condition; diff --git a/deps/v8/src/arm/lithium-codegen-arm.h b/deps/v8/src/arm/lithium-codegen-arm.h index 711e459..b01e496 100644 --- a/deps/v8/src/arm/lithium-codegen-arm.h +++ b/deps/v8/src/arm/lithium-codegen-arm.h @@ -86,6 +86,7 @@ class LCodeGen BASE_EMBEDDED { SwVfpRegister flt_scratch, DoubleRegister dbl_scratch); int ToInteger32(LConstantOperand* op) const; + double ToDouble(LConstantOperand* op) const; Operand ToOperand(LOperand* op); MemOperand ToMemOperand(LOperand* op) const; // Returns a MemOperand pointing to the high word of a DoubleStackSlot. @@ -139,8 +140,8 @@ class LCodeGen BASE_EMBEDDED { bool is_done() const { return status_ == DONE; } bool is_aborted() const { return status_ == ABORTED; } - int strict_mode_flag() const { - return info()->is_strict_mode() ? kStrictMode : kNonStrictMode; + StrictModeFlag strict_mode_flag() const { + return info()->strict_mode_flag(); } LChunk* chunk() const { return chunk_; } @@ -206,7 +207,7 @@ class LCodeGen BASE_EMBEDDED { LInstruction* instr); // Generate a direct call to a known function. Expects the function - // to be in edi. + // to be in r1. void CallKnownFunction(Handle function, int arity, LInstruction* instr, @@ -263,7 +264,6 @@ class LCodeGen BASE_EMBEDDED { static Condition TokenToCondition(Token::Value op, bool is_unsigned); void EmitGoto(int block); void EmitBranch(int left_block, int right_block, Condition cc); - void EmitCmpI(LOperand* left, LOperand* right); void EmitNumberUntagD(Register input, DoubleRegister result, bool deoptimize_on_undefined, @@ -272,8 +272,10 @@ class LCodeGen BASE_EMBEDDED { // Emits optimized code for typeof x == "y". Modifies input register. // Returns the condition on which a final split to // true and false label should be made, to optimize fallthrough. - Condition EmitTypeofIs(Label* true_label, Label* false_label, - Register input, Handle type_name); + Condition EmitTypeofIs(Label* true_label, + Label* false_label, + Register input, + Handle type_name); // Emits optimized code for %_IsObject(x). Preserves input register. // Returns the condition on which a final split to diff --git a/deps/v8/src/arm/macro-assembler-arm.cc b/deps/v8/src/arm/macro-assembler-arm.cc index 918f9eb..cf4258c 100644 --- a/deps/v8/src/arm/macro-assembler-arm.cc +++ b/deps/v8/src/arm/macro-assembler-arm.cc @@ -1101,24 +1101,16 @@ void MacroAssembler::InvokeFunction(JSFunction* function, // You can't call a function without a valid frame. ASSERT(flag == JUMP_FUNCTION || has_frame()); - ASSERT(function->is_compiled()); - // Get the function and setup the context. mov(r1, Operand(Handle(function))); ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); - // Invoke the cached code. - Handle code(function->code()); ParameterCount expected(function->shared()->formal_parameter_count()); - if (V8::UseCrankshaft()) { - // TODO(kasperl): For now, we always call indirectly through the - // code field in the function to allow recompilation to take effect - // without changing any of the call sites. - ldr(r3, FieldMemOperand(r1, JSFunction::kCodeEntryOffset)); - InvokeCode(r3, expected, actual, flag, NullCallWrapper(), call_kind); - } else { - InvokeCode(code, expected, actual, RelocInfo::CODE_TARGET, flag, call_kind); - } + // We call indirectly through the code field in the function to + // allow recompilation to take effect without changing any of the + // call sites. + ldr(r3, FieldMemOperand(r1, JSFunction::kCodeEntryOffset)); + InvokeCode(r3, expected, actual, flag, NullCallWrapper(), call_kind); } @@ -1602,6 +1594,7 @@ void MacroAssembler::AllocateInNewSpace(Register object_size, ASSERT(!result.is(scratch1)); ASSERT(!result.is(scratch2)); ASSERT(!scratch1.is(scratch2)); + ASSERT(!object_size.is(ip)); ASSERT(!result.is(ip)); ASSERT(!scratch1.is(ip)); ASSERT(!scratch2.is(ip)); @@ -2030,7 +2023,8 @@ void MacroAssembler::DispatchMap(Register obj, void MacroAssembler::TryGetFunctionPrototype(Register function, Register result, Register scratch, - Label* miss) { + Label* miss, + bool miss_on_bound_function) { // Check that the receiver isn't a smi. JumpIfSmi(function, miss); @@ -2038,6 +2032,16 @@ void MacroAssembler::TryGetFunctionPrototype(Register function, CompareObjectType(function, result, scratch, JS_FUNCTION_TYPE); b(ne, miss); + if (miss_on_bound_function) { + ldr(scratch, + FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset)); + ldr(scratch, + FieldMemOperand(scratch, SharedFunctionInfo::kCompilerHintsOffset)); + tst(scratch, + Operand(Smi::FromInt(1 << SharedFunctionInfo::kBoundFunction))); + b(ne, miss); + } + // Make sure that the function has an instance prototype. Label non_instance; ldrb(scratch, FieldMemOperand(result, Map::kBitFieldOffset)); @@ -3147,8 +3151,10 @@ void MacroAssembler::CountLeadingZeros(Register zeros, // Answer. #ifdef CAN_USE_ARMV5_INSTRUCTIONS clz(zeros, source); // This instruction is only supported after ARM5. #else - mov(zeros, Operand(0, RelocInfo::NONE)); + // Order of the next two lines is important: zeros register + // can be the same as source register. Move(scratch, source); + mov(zeros, Operand(0, RelocInfo::NONE)); // Top 16. tst(scratch, Operand(0xffff0000)); add(zeros, zeros, Operand(16), LeaveCC, eq); diff --git a/deps/v8/src/arm/macro-assembler-arm.h b/deps/v8/src/arm/macro-assembler-arm.h index 8ee468a..90c4b37 100644 --- a/deps/v8/src/arm/macro-assembler-arm.h +++ b/deps/v8/src/arm/macro-assembler-arm.h @@ -320,8 +320,11 @@ class MacroAssembler: public Assembler { } // Push four registers. Pushes leftmost register first (to highest address). - void Push(Register src1, Register src2, - Register src3, Register src4, Condition cond = al) { + void Push(Register src1, + Register src2, + Register src3, + Register src4, + Condition cond = al) { ASSERT(!src1.is(src2)); ASSERT(!src2.is(src3)); ASSERT(!src1.is(src3)); @@ -360,6 +363,57 @@ class MacroAssembler: public Assembler { } } + // Pop three registers. Pops rightmost register first (from lower address). + void Pop(Register src1, Register src2, Register src3, Condition cond = al) { + ASSERT(!src1.is(src2)); + ASSERT(!src2.is(src3)); + ASSERT(!src1.is(src3)); + if (src1.code() > src2.code()) { + if (src2.code() > src3.code()) { + ldm(ia_w, sp, src1.bit() | src2.bit() | src3.bit(), cond); + } else { + ldr(src3, MemOperand(sp, 4, PostIndex), cond); + ldm(ia_w, sp, src1.bit() | src2.bit(), cond); + } + } else { + Pop(src2, src3, cond); + str(src1, MemOperand(sp, 4, PostIndex), cond); + } + } + + // Pop four registers. Pops rightmost register first (from lower address). + void Pop(Register src1, + Register src2, + Register src3, + Register src4, + Condition cond = al) { + ASSERT(!src1.is(src2)); + ASSERT(!src2.is(src3)); + ASSERT(!src1.is(src3)); + ASSERT(!src1.is(src4)); + ASSERT(!src2.is(src4)); + ASSERT(!src3.is(src4)); + if (src1.code() > src2.code()) { + if (src2.code() > src3.code()) { + if (src3.code() > src4.code()) { + ldm(ia_w, + sp, + src1.bit() | src2.bit() | src3.bit() | src4.bit(), + cond); + } else { + ldr(src4, MemOperand(sp, 4, PostIndex), cond); + ldm(ia_w, sp, src1.bit() | src2.bit() | src3.bit(), cond); + } + } else { + Pop(src3, src4, cond); + ldm(ia_w, sp, src1.bit() | src2.bit(), cond); + } + } else { + Pop(src2, src3, src4, cond); + ldr(src1, MemOperand(sp, 4, PostIndex), cond); + } + } + // Push and pop the registers that can hold pointers, as defined by the // RegList constant kSafepointSavedRegisters. void PushSafepointRegisters(); @@ -672,7 +726,8 @@ class MacroAssembler: public Assembler { void TryGetFunctionPrototype(Register function, Register result, Register scratch, - Label* miss); + Label* miss, + bool miss_on_bound_function = false); // Compare object type for heap object. heap_object contains a non-Smi // whose object type should be compared with the given type. This both diff --git a/deps/v8/src/arm/regexp-macro-assembler-arm.cc b/deps/v8/src/arm/regexp-macro-assembler-arm.cc index c876467..b212f9f 100644 --- a/deps/v8/src/arm/regexp-macro-assembler-arm.cc +++ b/deps/v8/src/arm/regexp-macro-assembler-arm.cc @@ -1111,6 +1111,11 @@ int RegExpMacroAssemblerARM::CheckStackGuardState(Address* return_address, frame_entry(re_frame, kInputString) = *subject; frame_entry(re_frame, kInputStart) = new_address; frame_entry(re_frame, kInputEnd) = new_address + byte_length; + } else if (frame_entry(re_frame, kInputString) != *subject) { + // Subject string might have been a ConsString that underwent + // short-circuiting during GC. That will not change start_address but + // will change pointer inside the subject handle. + frame_entry(re_frame, kInputString) = *subject; } return 0; diff --git a/deps/v8/src/arm/simulator-arm.cc b/deps/v8/src/arm/simulator-arm.cc index 5704202..542cc30 100644 --- a/deps/v8/src/arm/simulator-arm.cc +++ b/deps/v8/src/arm/simulator-arm.cc @@ -1268,9 +1268,9 @@ void Simulator::WriteDW(int32_t addr, int32_t value1, int32_t value2) { // Returns the limit of the stack area to enable checking for stack overflows. uintptr_t Simulator::StackLimit() const { - // Leave a safety margin of 256 bytes to prevent overrunning the stack when + // Leave a safety margin of 512 bytes to prevent overrunning the stack when // pushing values. - return reinterpret_cast(stack_) + 256; + return reinterpret_cast(stack_) + 512; } diff --git a/deps/v8/src/arm/stub-cache-arm.cc b/deps/v8/src/arm/stub-cache-arm.cc index 4558afe..f9a10c4 100644 --- a/deps/v8/src/arm/stub-cache-arm.cc +++ b/deps/v8/src/arm/stub-cache-arm.cc @@ -95,7 +95,63 @@ static void ProbeTable(Isolate* isolate, // must always call a backup property check that is complete. // This function is safe to call if the receiver has fast properties. // Name must be a symbol and receiver must be a heap object. -MUST_USE_RESULT static MaybeObject* GenerateDictionaryNegativeLookup( +static void GenerateDictionaryNegativeLookup(MacroAssembler* masm, + Label* miss_label, + Register receiver, + Handle name, + Register scratch0, + Register scratch1) { + ASSERT(name->IsSymbol()); + Counters* counters = masm->isolate()->counters(); + __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1); + __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); + + Label done; + + const int kInterceptorOrAccessCheckNeededMask = + (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); + + // Bail out if the receiver has a named interceptor or requires access checks. + Register map = scratch1; + __ ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset)); + __ ldrb(scratch0, FieldMemOperand(map, Map::kBitFieldOffset)); + __ tst(scratch0, Operand(kInterceptorOrAccessCheckNeededMask)); + __ b(ne, miss_label); + + // Check that receiver is a JSObject. + __ ldrb(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset)); + __ cmp(scratch0, Operand(FIRST_SPEC_OBJECT_TYPE)); + __ b(lt, miss_label); + + // Load properties array. + Register properties = scratch0; + __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); + // Check that the properties array is a dictionary. + __ ldr(map, FieldMemOperand(properties, HeapObject::kMapOffset)); + Register tmp = properties; + __ LoadRoot(tmp, Heap::kHashTableMapRootIndex); + __ cmp(map, tmp); + __ b(ne, miss_label); + + // Restore the temporarily used register. + __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); + + + StringDictionaryLookupStub::GenerateNegativeLookup(masm, + miss_label, + &done, + receiver, + properties, + name, + scratch1); + __ bind(&done); + __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); +} + + +// TODO(kmillikin): Eliminate this function when the stub cache is fully +// handlified. +MUST_USE_RESULT static MaybeObject* TryGenerateDictionaryNegativeLookup( MacroAssembler* masm, Label* miss_label, Register receiver, @@ -138,7 +194,7 @@ MUST_USE_RESULT static MaybeObject* GenerateDictionaryNegativeLookup( __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); - MaybeObject* result = StringDictionaryLookupStub::GenerateNegativeLookup( + MaybeObject* result = StringDictionaryLookupStub::TryGenerateNegativeLookup( masm, miss_label, &done, @@ -259,8 +315,10 @@ void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype( // are loaded directly otherwise the property is loaded from the properties // fixed array. void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm, - Register dst, Register src, - JSObject* holder, int index) { + Register dst, + Register src, + Handle holder, + int index) { // Adjust for the number of properties stored in the holder. index -= holder->map()->inobject_properties(); if (index < 0) { @@ -367,9 +425,9 @@ void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm, // may be clobbered. Upon branch to miss_label, the receiver and name // registers have their original values. void StubCompiler::GenerateStoreField(MacroAssembler* masm, - JSObject* object, + Handle object, int index, - Map* transition, + Handle transition, Register receiver_reg, Register name_reg, Register scratch, @@ -395,11 +453,11 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); // Perform map transition for the receiver if necessary. - if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) { + if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) { // The properties must be extended before we can store the value. // We jump to a runtime call that extends the properties array. __ push(receiver_reg); - __ mov(r2, Operand(Handle(transition))); + __ mov(r2, Operand(transition)); __ Push(r2, r0); __ TailCallExternalReference( ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), @@ -409,10 +467,10 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, return; } - if (transition != NULL) { + if (!transition.is_null()) { // Update the map of the object; no write barrier updating is // needed because the map is never in new space. - __ mov(ip, Operand(Handle(transition))); + __ mov(ip, Operand(transition)); __ str(ip, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); } @@ -467,20 +525,15 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) { ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC); - Code* code = NULL; - if (kind == Code::LOAD_IC) { - code = masm->isolate()->builtins()->builtin(Builtins::kLoadIC_Miss); - } else { - code = masm->isolate()->builtins()->builtin(Builtins::kKeyedLoadIC_Miss); - } - - Handle ic(code); - __ Jump(ic, RelocInfo::CODE_TARGET); + Handle code = (kind == Code::LOAD_IC) + ? masm->isolate()->builtins()->LoadIC_Miss() + : masm->isolate()->builtins()->KeyedLoadIC_Miss(); + __ Jump(code, RelocInfo::CODE_TARGET); } static void GenerateCallFunction(MacroAssembler* masm, - Object* object, + Handle object, const ParameterCount& arguments, Label* miss, Code::ExtraICState extra_ic_state) { @@ -868,7 +921,26 @@ class CallInterceptorCompiler BASE_EMBEDDED { // Generate code to check that a global property cell is empty. Create // the property cell at compilation time if no cell exists for the // property. -MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCell( +static void GenerateCheckPropertyCell(MacroAssembler* masm, + Handle global, + Handle name, + Register scratch, + Label* miss) { + Handle cell = + GlobalObject::EnsurePropertyCell(global, name); + ASSERT(cell->value()->IsTheHole()); + __ mov(scratch, Operand(cell)); + __ ldr(scratch, + FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset)); + __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); + __ cmp(scratch, ip); + __ b(ne, miss); +} + + +// TODO(kmillikin): Eliminate this function when the stub cache is fully +// handlified. +MUST_USE_RESULT static MaybeObject* TryGenerateCheckPropertyCell( MacroAssembler* masm, GlobalObject* global, String* name, @@ -889,9 +961,32 @@ MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCell( return cell; } + // Calls GenerateCheckPropertyCell for each global object in the prototype chain // from object to (but not including) holder. -MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCells( +static void GenerateCheckPropertyCells(MacroAssembler* masm, + Handle object, + Handle holder, + Handle name, + Register scratch, + Label* miss) { + Handle current = object; + while (!current.is_identical_to(holder)) { + if (current->IsGlobalObject()) { + GenerateCheckPropertyCell(masm, + Handle::cast(current), + name, + scratch, + miss); + } + current = Handle(JSObject::cast(current->GetPrototype())); + } +} + + +// TODO(kmillikin): Eliminate this function when the stub cache is fully +// handlified. +MUST_USE_RESULT static MaybeObject* TryGenerateCheckPropertyCells( MacroAssembler* masm, JSObject* object, JSObject* holder, @@ -902,7 +997,7 @@ MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCells( while (current != holder) { if (current->IsGlobalObject()) { // Returns a cell or a failure. - MaybeObject* result = GenerateCheckPropertyCell( + MaybeObject* result = TryGenerateCheckPropertyCell( masm, GlobalObject::cast(current), name, @@ -1027,6 +1122,112 @@ static void GenerateUInt2Double(MacroAssembler* masm, #define __ ACCESS_MASM(masm()) +Register StubCompiler::CheckPrototypes(Handle object, + Register object_reg, + Handle holder, + Register holder_reg, + Register scratch1, + Register scratch2, + Handle name, + int save_at_depth, + Label* miss) { + // Make sure there's no overlap between holder and object registers. + ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); + ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg) + && !scratch2.is(scratch1)); + + // Keep track of the current object in register reg. + Register reg = object_reg; + int depth = 0; + + if (save_at_depth == depth) { + __ str(reg, MemOperand(sp)); + } + + // Check the maps in the prototype chain. + // Traverse the prototype chain from the object and do map checks. + Handle current = object; + while (!current.is_identical_to(holder)) { + ++depth; + + // Only global objects and objects that do not require access + // checks are allowed in stubs. + ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded()); + + Handle prototype(JSObject::cast(current->GetPrototype())); + if (!current->HasFastProperties() && + !current->IsJSGlobalObject() && + !current->IsJSGlobalProxy()) { + if (!name->IsSymbol()) { + name = factory()->LookupSymbol(name); + } + ASSERT(current->property_dictionary()->FindEntry(*name) == + StringDictionary::kNotFound); + + GenerateDictionaryNegativeLookup(masm(), miss, reg, name, + scratch1, scratch2); + + __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); + reg = holder_reg; // From now on the object will be in holder_reg. + __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); + } else { + Handle current_map(current->map()); + __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); + __ cmp(scratch1, Operand(current_map)); + // Branch on the result of the map check. + __ b(ne, miss); + // Check access rights to the global object. This has to happen after + // the map check so that we know that the object is actually a global + // object. + if (current->IsJSGlobalProxy()) { + __ CheckAccessGlobalProxy(reg, scratch2, miss); + } + reg = holder_reg; // From now on the object will be in holder_reg. + + if (heap()->InNewSpace(*prototype)) { + // The prototype is in new space; we cannot store a reference to it + // in the code. Load it from the map. + __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); + } else { + // The prototype is in old space; load it directly. + __ mov(reg, Operand(prototype)); + } + } + + if (save_at_depth == depth) { + __ str(reg, MemOperand(sp)); + } + + // Go to the next object in the prototype chain. + current = prototype; + } + + // Log the check depth. + LOG(masm()->isolate(), IntEvent("check-maps-depth", depth + 1)); + + // Check the holder map. + __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); + __ cmp(scratch1, Operand(Handle(current->map()))); + __ b(ne, miss); + + // Perform security check for access to the global object. + ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded()); + if (holder->IsJSGlobalProxy()) { + __ CheckAccessGlobalProxy(reg, scratch1, miss); + } + + // If we've skipped any global objects, it's not enough to verify that + // their maps haven't changed. We also need to check that the property + // cell for the property is still empty. + GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss); + + // Return the register containing the holder. + return reg; +} + + +// TODO(kmillikin): Eliminate this function when the stub cache is fully +// handlified. Register StubCompiler::CheckPrototypes(JSObject* object, Register object_reg, JSObject* holder, @@ -1076,12 +1277,13 @@ Register StubCompiler::CheckPrototypes(JSObject* object, ASSERT(current->property_dictionary()->FindEntry(name) == StringDictionary::kNotFound); - MaybeObject* negative_lookup = GenerateDictionaryNegativeLookup(masm(), - miss, - reg, - name, - scratch1, - scratch2); + MaybeObject* negative_lookup = + TryGenerateDictionaryNegativeLookup(masm(), + miss, + reg, + name, + scratch1, + scratch2); if (negative_lookup->IsFailure()) { set_failure(Failure::cast(negative_lookup)); return reg; @@ -1150,17 +1352,17 @@ Register StubCompiler::CheckPrototypes(JSObject* object, ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded()); if (holder->IsJSGlobalProxy()) { __ CheckAccessGlobalProxy(reg, scratch1, miss); - }; + } // If we've skipped any global objects, it's not enough to verify // that their maps haven't changed. We also need to check that the // property cell for the property is still empty. - MaybeObject* result = GenerateCheckPropertyCells(masm(), - object, - holder, - name, - scratch1, - miss); + MaybeObject* result = TryGenerateCheckPropertyCells(masm(), + object, + holder, + name, + scratch1, + miss); if (result->IsFailure()) set_failure(Failure::cast(result)); // Return the register containing the holder. @@ -1168,45 +1370,44 @@ Register StubCompiler::CheckPrototypes(JSObject* object, } -void StubCompiler::GenerateLoadField(JSObject* object, - JSObject* holder, +void StubCompiler::GenerateLoadField(Handle object, + Handle holder, Register receiver, Register scratch1, Register scratch2, Register scratch3, int index, - String* name, + Handle name, Label* miss) { // Check that the receiver isn't a smi. __ JumpIfSmi(receiver, miss); // Check that the maps haven't changed. - Register reg = - CheckPrototypes(object, receiver, holder, scratch1, scratch2, scratch3, - name, miss); + Register reg = CheckPrototypes( + object, receiver, holder, scratch1, scratch2, scratch3, name, miss); GenerateFastPropertyLoad(masm(), r0, reg, holder, index); __ Ret(); } -void StubCompiler::GenerateLoadConstant(JSObject* object, - JSObject* holder, +void StubCompiler::GenerateLoadConstant(Handle object, + Handle holder, Register receiver, Register scratch1, Register scratch2, Register scratch3, - Object* value, - String* name, + Handle value, + Handle name, Label* miss) { // Check that the receiver isn't a smi. __ JumpIfSmi(receiver, miss); // Check that the maps haven't changed. - CheckPrototypes(object, receiver, holder, scratch1, scratch2, scratch3, name, - miss); + CheckPrototypes( + object, receiver, holder, scratch1, scratch2, scratch3, name, miss); // Return the constant value. - __ mov(r0, Operand(Handle(value))); + __ mov(r0, Operand(value)); __ Ret(); } @@ -1365,7 +1566,8 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object, // We found FIELD property in prototype chain of interceptor's holder. // Retrieve a field from field's holder. GenerateFastPropertyLoad(masm(), r0, holder_reg, - lookup->holder(), lookup->GetFieldIndex()); + Handle(lookup->holder()), + lookup->GetFieldIndex()); __ Ret(); } else { // We found CALLBACKS property in prototype chain of interceptor's @@ -1416,9 +1618,9 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object, } -void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) { +void CallStubCompiler::GenerateNameCheck(Handle name, Label* miss) { if (kind_ == Code::KEYED_CALL_IC) { - __ cmp(r2, Operand(Handle(name))); + __ cmp(r2, Operand(name)); __ b(ne, miss); } } @@ -1478,11 +1680,22 @@ void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell, } -MaybeObject* CallStubCompiler::GenerateMissBranch() { - MaybeObject* maybe_obj = +void CallStubCompiler::GenerateMissBranch() { + Handle code = isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(), kind_, - extra_ic_state_); + extra_state_); + __ Jump(code, RelocInfo::CODE_TARGET); +} + + +// TODO(kmillikin): Eliminate this function when the stub cache is fully +// handlified. +MaybeObject* CallStubCompiler::TryGenerateMissBranch() { + MaybeObject* maybe_obj = + isolate()->stub_cache()->TryComputeCallMiss(arguments().immediate(), + kind_, + extra_state_); Object* obj; if (!maybe_obj->ToObject(&obj)) return maybe_obj; __ Jump(Handle(Code::cast(obj)), RelocInfo::CODE_TARGET); @@ -1490,10 +1703,10 @@ MaybeObject* CallStubCompiler::GenerateMissBranch() { } -MaybeObject* CallStubCompiler::CompileCallField(JSObject* object, - JSObject* holder, +Handle CallStubCompiler::CompileCallField(Handle object, + Handle holder, int index, - String* name) { + Handle name) { // ----------- S t a t e ------------- // -- r2 : name // -- lr : return address @@ -1513,12 +1726,11 @@ MaybeObject* CallStubCompiler::CompileCallField(JSObject* object, Register reg = CheckPrototypes(object, r0, holder, r1, r3, r4, name, &miss); GenerateFastPropertyLoad(masm(), r1, reg, holder, index); - GenerateCallFunction(masm(), object, arguments(), &miss, extra_ic_state_); + GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_); // Handle call cache miss. __ bind(&miss); - MaybeObject* maybe_result = GenerateMissBranch(); - if (maybe_result->IsFailure()) return maybe_result; + GenerateMissBranch(); // Return the generated code. return GetCode(FIELD, name); @@ -1543,7 +1755,7 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object, Label miss; - GenerateNameCheck(name, &miss); + GenerateNameCheck(Handle(name), &miss); Register receiver = r1; @@ -1619,7 +1831,7 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object, __ bind(&with_write_barrier); __ ldr(r6, FieldMemOperand(receiver, HeapObject::kMapOffset)); - __ CheckFastSmiOnlyElements(r6, r6, &call_builtin); + __ CheckFastObjectElements(r6, r6, &call_builtin); // Save new length. __ str(r0, FieldMemOperand(receiver, JSArray::kLengthOffset)); @@ -1709,11 +1921,11 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object, // Handle call cache miss. __ bind(&miss); - MaybeObject* maybe_result = GenerateMissBranch(); + MaybeObject* maybe_result = TryGenerateMissBranch(); if (maybe_result->IsFailure()) return maybe_result; // Return the generated code. - return GetCode(function); + return TryGetCode(function); } @@ -1738,7 +1950,7 @@ MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object, Register receiver = r1; Register elements = r3; - GenerateNameCheck(name, &miss); + GenerateNameCheck(Handle(name), &miss); // Get the receiver from the stack const int argc = arguments().immediate(); @@ -1798,11 +2010,11 @@ MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object, // Handle call cache miss. __ bind(&miss); - MaybeObject* maybe_result = GenerateMissBranch(); + MaybeObject* maybe_result = TryGenerateMissBranch(); if (maybe_result->IsFailure()) return maybe_result; // Return the generated code. - return GetCode(function); + return TryGetCode(function); } @@ -1831,12 +2043,12 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall( Label* index_out_of_range_label = &index_out_of_range; if (kind_ == Code::CALL_IC && - (CallICBase::StringStubState::decode(extra_ic_state_) == + (CallICBase::StringStubState::decode(extra_state_) == DEFAULT_STRING_STUB)) { index_out_of_range_label = &miss; } - GenerateNameCheck(name, &name_miss); + GenerateNameCheck(Handle(name), &name_miss); // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype(masm(), @@ -1884,11 +2096,11 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall( // Restore function name in r2. __ Move(r2, Handle(name)); __ bind(&name_miss); - MaybeObject* maybe_result = GenerateMissBranch(); + MaybeObject* maybe_result = TryGenerateMissBranch(); if (maybe_result->IsFailure()) return maybe_result; // Return the generated code. - return GetCode(function); + return TryGetCode(function); } @@ -1917,12 +2129,12 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall( Label* index_out_of_range_label = &index_out_of_range; if (kind_ == Code::CALL_IC && - (CallICBase::StringStubState::decode(extra_ic_state_) == + (CallICBase::StringStubState::decode(extra_state_) == DEFAULT_STRING_STUB)) { index_out_of_range_label = &miss; } - GenerateNameCheck(name, &name_miss); + GenerateNameCheck(Handle(name), &name_miss); // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype(masm(), @@ -1972,11 +2184,11 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall( // Restore function name in r2. __ Move(r2, Handle(name)); __ bind(&name_miss); - MaybeObject* maybe_result = GenerateMissBranch(); + MaybeObject* maybe_result = TryGenerateMissBranch(); if (maybe_result->IsFailure()) return maybe_result; // Return the generated code. - return GetCode(function); + return TryGetCode(function); } @@ -2001,7 +2213,7 @@ MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall( if (!object->IsJSObject() || argc != 1) return heap()->undefined_value(); Label miss; - GenerateNameCheck(name, &miss); + GenerateNameCheck(Handle(name), &miss); if (cell == NULL) { __ ldr(r1, MemOperand(sp, 1 * kPointerSize)); @@ -2044,11 +2256,11 @@ MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall( __ bind(&miss); // r2: function name. - MaybeObject* maybe_result = GenerateMissBranch(); + MaybeObject* maybe_result = TryGenerateMissBranch(); if (maybe_result->IsFailure()) return maybe_result; // Return the generated code. - return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name); + return (cell == NULL) ? TryGetCode(function) : TryGetCode(NORMAL, name); } @@ -2078,7 +2290,7 @@ MaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object, if (!object->IsJSObject() || argc != 1) return heap()->undefined_value(); Label miss, slow; - GenerateNameCheck(name, &miss); + GenerateNameCheck(Handle(name), &miss); if (cell == NULL) { __ ldr(r1, MemOperand(sp, 1 * kPointerSize)); @@ -2192,11 +2404,11 @@ MaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object, __ bind(&miss); // r2: function name. - MaybeObject* maybe_result = GenerateMissBranch(); + MaybeObject* maybe_result = TryGenerateMissBranch(); if (maybe_result->IsFailure()) return maybe_result; // Return the generated code. - return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name); + return (cell == NULL) ? TryGetCode(function) : TryGetCode(NORMAL, name); } @@ -2220,7 +2432,7 @@ MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object, if (!object->IsJSObject() || argc != 1) return heap()->undefined_value(); Label miss; - GenerateNameCheck(name, &miss); + GenerateNameCheck(Handle(name), &miss); if (cell == NULL) { __ ldr(r1, MemOperand(sp, 1 * kPointerSize)); @@ -2293,11 +2505,11 @@ MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object, __ bind(&miss); // r2: function name. - MaybeObject* maybe_result = GenerateMissBranch(); + MaybeObject* maybe_result = TryGenerateMissBranch(); if (maybe_result->IsFailure()) return maybe_result; // Return the generated code. - return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name); + return (cell == NULL) ? TryGetCode(function) : TryGetCode(NORMAL, name); } @@ -2322,7 +2534,7 @@ MaybeObject* CallStubCompiler::CompileFastApiCall( Label miss, miss_before_stack_reserved; - GenerateNameCheck(name, &miss_before_stack_reserved); + GenerateNameCheck(Handle(name), &miss_before_stack_reserved); // Get the receiver from the stack. const int argc = arguments().immediate(); @@ -2347,11 +2559,11 @@ MaybeObject* CallStubCompiler::CompileFastApiCall( FreeSpaceForFastApiCall(masm()); __ bind(&miss_before_stack_reserved); - MaybeObject* maybe_result = GenerateMissBranch(); + MaybeObject* maybe_result = TryGenerateMissBranch(); if (maybe_result->IsFailure()) return maybe_result; // Return the generated code. - return GetCode(function); + return TryGetCode(function); } @@ -2375,7 +2587,7 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object, Label miss; - GenerateNameCheck(name, &miss); + GenerateNameCheck(Handle(name), &miss); // Get the receiver from the stack const int argc = arguments().immediate(); @@ -2474,18 +2686,18 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object, UNREACHABLE(); } - CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_) + CallKind call_kind = CallICBase::Contextual::decode(extra_state_) ? CALL_AS_FUNCTION : CALL_AS_METHOD; __ InvokeFunction(function, arguments(), JUMP_FUNCTION, call_kind); // Handle call cache miss. __ bind(&miss); - MaybeObject* maybe_result = GenerateMissBranch(); + MaybeObject* maybe_result = TryGenerateMissBranch(); if (maybe_result->IsFailure()) return maybe_result; // Return the generated code. - return GetCode(function); + return TryGetCode(function); } @@ -2499,18 +2711,18 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object, Label miss; - GenerateNameCheck(name, &miss); + GenerateNameCheck(Handle(name), &miss); // Get the number of arguments. const int argc = arguments().immediate(); - LookupResult lookup; + LookupResult lookup(isolate()); LookupPostInterceptor(holder, name, &lookup); // Get the receiver from the stack. __ ldr(r1, MemOperand(sp, argc * kPointerSize)); - CallInterceptorCompiler compiler(this, arguments(), r2, extra_ic_state_); + CallInterceptorCompiler compiler(this, arguments(), r2, extra_state_); MaybeObject* result = compiler.Compile(masm(), object, holder, @@ -2530,15 +2742,16 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object, // Restore receiver. __ ldr(r0, MemOperand(sp, argc * kPointerSize)); - GenerateCallFunction(masm(), object, arguments(), &miss, extra_ic_state_); + GenerateCallFunction(masm(), Handle(object), arguments(), &miss, + extra_state_); // Handle call cache miss. __ bind(&miss); - MaybeObject* maybe_result = GenerateMissBranch(); + MaybeObject* maybe_result = TryGenerateMissBranch(); if (maybe_result->IsFailure()) return maybe_result; // Return the generated code. - return GetCode(INTERCEPTOR, name); + return TryGetCode(INTERCEPTOR, name); } @@ -2563,7 +2776,7 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object, Label miss; - GenerateNameCheck(name, &miss); + GenerateNameCheck(Handle(name), &miss); // Get the number of arguments. const int argc = arguments().immediate(); @@ -2585,39 +2798,33 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object, // Jump to the cached code (tail call). Counters* counters = masm()->isolate()->counters(); __ IncrementCounter(counters->call_global_inline(), 1, r3, r4); - ASSERT(function->is_compiled()); Handle code(function->code()); ParameterCount expected(function->shared()->formal_parameter_count()); - CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_) + CallKind call_kind = CallICBase::Contextual::decode(extra_state_) ? CALL_AS_FUNCTION : CALL_AS_METHOD; - if (V8::UseCrankshaft()) { - // TODO(kasperl): For now, we always call indirectly through the - // code field in the function to allow recompilation to take effect - // without changing any of the call sites. - __ ldr(r3, FieldMemOperand(r1, JSFunction::kCodeEntryOffset)); - __ InvokeCode(r3, expected, arguments(), JUMP_FUNCTION, - NullCallWrapper(), call_kind); - } else { - __ InvokeCode(code, expected, arguments(), RelocInfo::CODE_TARGET, - JUMP_FUNCTION, call_kind); - } + // We call indirectly through the code field in the function to + // allow recompilation to take effect without changing any of the + // call sites. + __ ldr(r3, FieldMemOperand(r1, JSFunction::kCodeEntryOffset)); + __ InvokeCode(r3, expected, arguments(), JUMP_FUNCTION, + NullCallWrapper(), call_kind); // Handle call cache miss. __ bind(&miss); __ IncrementCounter(counters->call_global_inline_miss(), 1, r1, r3); - MaybeObject* maybe_result = GenerateMissBranch(); + MaybeObject* maybe_result = TryGenerateMissBranch(); if (maybe_result->IsFailure()) return maybe_result; // Return the generated code. - return GetCode(NORMAL, name); + return TryGetCode(NORMAL, name); } -MaybeObject* StoreStubCompiler::CompileStoreField(JSObject* object, +Handle StoreStubCompiler::CompileStoreField(Handle object, int index, - Map* transition, - String* name) { + Handle transition, + Handle name) { // ----------- S t a t e ------------- // -- r0 : value // -- r1 : receiver @@ -2626,24 +2833,20 @@ MaybeObject* StoreStubCompiler::CompileStoreField(JSObject* object, // ----------------------------------- Label miss; - GenerateStoreField(masm(), - object, - index, - transition, - r1, r2, r3, - &miss); + GenerateStoreField(masm(), object, index, transition, r1, r2, r3, &miss); __ bind(&miss); Handle ic = masm()->isolate()->builtins()->StoreIC_Miss(); __ Jump(ic, RelocInfo::CODE_TARGET); // Return the generated code. - return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name); + return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name); } -MaybeObject* StoreStubCompiler::CompileStoreCallback(JSObject* object, - AccessorInfo* callback, - String* name) { +Handle StoreStubCompiler::CompileStoreCallback( + Handle object, + Handle callback, + Handle name) { // ----------- S t a t e ------------- // -- r0 : value // -- r1 : receiver @@ -2670,7 +2873,7 @@ MaybeObject* StoreStubCompiler::CompileStoreCallback(JSObject* object, ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); __ push(r1); // receiver - __ mov(ip, Operand(Handle(callback))); // callback info + __ mov(ip, Operand(callback)); // callback info __ Push(ip, r2, r0); // Do tail-call to the runtime system. @@ -2689,8 +2892,9 @@ MaybeObject* StoreStubCompiler::CompileStoreCallback(JSObject* object, } -MaybeObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver, - String* name) { +Handle StoreStubCompiler::CompileStoreInterceptor( + Handle receiver, + Handle name) { // ----------- S t a t e ------------- // -- r0 : value // -- r1 : receiver @@ -2737,9 +2941,10 @@ MaybeObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver, } -MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object, - JSGlobalPropertyCell* cell, - String* name) { +Handle StoreStubCompiler::CompileStoreGlobal( + Handle object, + Handle cell, + Handle name) { // ----------- S t a t e ------------- // -- r0 : value // -- r1 : receiver @@ -2757,7 +2962,7 @@ MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object, // cell could have been deleted and reintroducing the global needs // to update the property details in the property dictionary of the // global object. We bail out to the runtime system to do that. - __ mov(r4, Operand(Handle(cell))); + __ mov(r4, Operand(cell)); __ LoadRoot(r5, Heap::kTheHoleValueRootIndex); __ ldr(r6, FieldMemOperand(r4, JSGlobalPropertyCell::kValueOffset)); __ cmp(r5, r6); @@ -2790,9 +2995,9 @@ MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object, } -MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name, - JSObject* object, - JSObject* last) { +Handle LoadStubCompiler::CompileLoadNonexistent(Handle name, + Handle object, + Handle last) { // ----------- S t a t e ------------- // -- r0 : receiver // -- lr : return address @@ -2808,15 +3013,8 @@ MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name, // If the last object in the prototype chain is a global object, // check that the global property cell is empty. if (last->IsGlobalObject()) { - MaybeObject* cell = GenerateCheckPropertyCell(masm(), - GlobalObject::cast(last), - name, - r1, - &miss); - if (cell->IsFailure()) { - miss.Unuse(); - return cell; - } + GenerateCheckPropertyCell( + masm(), Handle::cast(last), name, r1, &miss); } // Return undefined if maps of the full prototype chain are still the @@ -2828,14 +3026,14 @@ MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name, GenerateLoadMiss(masm(), Code::LOAD_IC); // Return the generated code. - return GetCode(NONEXISTENT, heap()->empty_string()); + return GetCode(NONEXISTENT, factory()->empty_string()); } -MaybeObject* LoadStubCompiler::CompileLoadField(JSObject* object, - JSObject* holder, +Handle LoadStubCompiler::CompileLoadField(Handle object, + Handle holder, int index, - String* name) { + Handle name) { // ----------- S t a t e ------------- // -- r0 : receiver // -- r2 : name @@ -2874,14 +3072,14 @@ MaybeObject* LoadStubCompiler::CompileLoadCallback(String* name, GenerateLoadMiss(masm(), Code::LOAD_IC); // Return the generated code. - return GetCode(CALLBACKS, name); + return TryGetCode(CALLBACKS, name); } -MaybeObject* LoadStubCompiler::CompileLoadConstant(JSObject* object, - JSObject* holder, - Object* value, - String* name) { +Handle LoadStubCompiler::CompileLoadConstant(Handle object, + Handle holder, + Handle value, + Handle name) { // ----------- S t a t e ------------- // -- r0 : receiver // -- r2 : name @@ -2908,7 +3106,7 @@ MaybeObject* LoadStubCompiler::CompileLoadInterceptor(JSObject* object, // ----------------------------------- Label miss; - LookupResult lookup; + LookupResult lookup(isolate()); LookupPostInterceptor(holder, name, &lookup); GenerateLoadInterceptor(object, holder, @@ -2924,15 +3122,16 @@ MaybeObject* LoadStubCompiler::CompileLoadInterceptor(JSObject* object, GenerateLoadMiss(masm(), Code::LOAD_IC); // Return the generated code. - return GetCode(INTERCEPTOR, name); + return TryGetCode(INTERCEPTOR, name); } -MaybeObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object, - GlobalObject* holder, - JSGlobalPropertyCell* cell, - String* name, - bool is_dont_delete) { +Handle LoadStubCompiler::CompileLoadGlobal( + Handle object, + Handle holder, + Handle cell, + Handle name, + bool is_dont_delete) { // ----------- S t a t e ------------- // -- r0 : receiver // -- r2 : name @@ -2943,7 +3142,7 @@ MaybeObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object, // If the object is the holder then we know that it's a global // object which can only happen for contextual calls. In this case, // the receiver cannot be a smi. - if (object != holder) { + if (!object.is_identical_to(holder)) { __ JumpIfSmi(r0, &miss); } @@ -2951,7 +3150,7 @@ MaybeObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object, CheckPrototypes(object, r0, holder, r3, r4, r1, name, &miss); // Get the value from the cell. - __ mov(r3, Operand(Handle(cell))); + __ mov(r3, Operand(cell)); __ ldr(r4, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset)); // Check for deleted property if property can actually be deleted. @@ -2975,9 +3174,9 @@ MaybeObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object, } -MaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name, - JSObject* receiver, - JSObject* holder, +Handle KeyedLoadStubCompiler::CompileLoadField(Handle name, + Handle receiver, + Handle holder, int index) { // ----------- S t a t e ------------- // -- lr : return address @@ -2987,7 +3186,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name, Label miss; // Check the key is the cached one. - __ cmp(r0, Operand(Handle(name))); + __ cmp(r0, Operand(name)); __ b(ne, &miss); GenerateLoadField(receiver, holder, r1, r2, r3, r4, index, name, &miss); @@ -3024,14 +3223,15 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback( __ bind(&miss); GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); - return GetCode(CALLBACKS, name); + return TryGetCode(CALLBACKS, name); } -MaybeObject* KeyedLoadStubCompiler::CompileLoadConstant(String* name, - JSObject* receiver, - JSObject* holder, - Object* value) { +Handle KeyedLoadStubCompiler::CompileLoadConstant( + Handle name, + Handle receiver, + Handle holder, + Handle value) { // ----------- S t a t e ------------- // -- lr : return address // -- r0 : key @@ -3040,7 +3240,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadConstant(String* name, Label miss; // Check the key is the cached one. - __ cmp(r0, Operand(Handle(name))); + __ cmp(r0, Operand(name)); __ b(ne, &miss); GenerateLoadConstant(receiver, holder, r1, r2, r3, r4, value, name, &miss); @@ -3066,7 +3266,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, __ cmp(r0, Operand(Handle(name))); __ b(ne, &miss); - LookupResult lookup; + LookupResult lookup(isolate()); LookupPostInterceptor(holder, name, &lookup); GenerateLoadInterceptor(receiver, holder, @@ -3081,11 +3281,12 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, __ bind(&miss); GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); - return GetCode(INTERCEPTOR, name); + return TryGetCode(INTERCEPTOR, name); } -MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) { +Handle KeyedLoadStubCompiler::CompileLoadArrayLength( + Handle name) { // ----------- S t a t e ------------- // -- lr : return address // -- r0 : key @@ -3094,7 +3295,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) { Label miss; // Check the key is the cached one. - __ cmp(r0, Operand(Handle(name))); + __ cmp(r0, Operand(name)); __ b(ne, &miss); GenerateLoadArrayLength(masm(), r1, r2, &miss); @@ -3105,7 +3306,8 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) { } -MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { +Handle KeyedLoadStubCompiler::CompileLoadStringLength( + Handle name) { // ----------- S t a t e ------------- // -- lr : return address // -- r0 : key @@ -3117,7 +3319,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { __ IncrementCounter(counters->keyed_load_string_length(), 1, r2, r3); // Check the key is the cached one. - __ cmp(r0, Operand(Handle(name))); + __ cmp(r0, Operand(name)); __ b(ne, &miss); GenerateLoadStringLength(masm(), r1, r2, r3, &miss, true); @@ -3130,7 +3332,8 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { } -MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) { +Handle KeyedLoadStubCompiler::CompileLoadFunctionPrototype( + Handle name) { // ----------- S t a t e ------------- // -- lr : return address // -- r0 : key @@ -3142,7 +3345,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) { __ IncrementCounter(counters->keyed_load_function_prototype(), 1, r2, r3); // Check the name hasn't changed. - __ cmp(r0, Operand(Handle(name))); + __ cmp(r0, Operand(name)); __ b(ne, &miss); GenerateLoadFunctionPrototype(masm(), r1, r2, r3, &miss); @@ -3154,33 +3357,29 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) { } -MaybeObject* KeyedLoadStubCompiler::CompileLoadElement(Map* receiver_map) { +Handle KeyedLoadStubCompiler::CompileLoadElement( + Handle receiver_map) { // ----------- S t a t e ------------- // -- lr : return address // -- r0 : key // -- r1 : receiver // ----------------------------------- - Code* stub; ElementsKind elements_kind = receiver_map->elements_kind(); - MaybeObject* maybe_stub = KeyedLoadElementStub(elements_kind).TryGetCode(); - if (!maybe_stub->To(&stub)) return maybe_stub; - __ DispatchMap(r1, - r2, - Handle(receiver_map), - Handle(stub), - DO_SMI_CHECK); + Handle stub = KeyedLoadElementStub(elements_kind).GetCode(); + + __ DispatchMap(r1, r2, receiver_map, stub, DO_SMI_CHECK); Handle ic = isolate()->builtins()->KeyedLoadIC_Miss(); __ Jump(ic, RelocInfo::CODE_TARGET); // Return the generated code. - return GetCode(NORMAL, NULL); + return GetCode(NORMAL, factory()->empty_string()); } -MaybeObject* KeyedLoadStubCompiler::CompileLoadPolymorphic( - MapList* receiver_maps, - CodeList* handler_ics) { +Handle KeyedLoadStubCompiler::CompileLoadPolymorphic( + MapHandleList* receiver_maps, + CodeHandleList* handler_ics) { // ----------- S t a t e ------------- // -- lr : return address // -- r0 : key @@ -3192,11 +3391,9 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadPolymorphic( int receiver_count = receiver_maps->length(); __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); for (int current = 0; current < receiver_count; ++current) { - Handle map(receiver_maps->at(current)); - Handle code(handler_ics->at(current)); - __ mov(ip, Operand(map)); + __ mov(ip, Operand(receiver_maps->at(current))); __ cmp(r2, ip); - __ Jump(code, RelocInfo::CODE_TARGET, eq); + __ Jump(handler_ics->at(current), RelocInfo::CODE_TARGET, eq); } __ bind(&miss); @@ -3204,14 +3401,14 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadPolymorphic( __ Jump(miss_ic, RelocInfo::CODE_TARGET, al); // Return the generated code. - return GetCode(NORMAL, NULL, MEGAMORPHIC); + return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC); } -MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object, +Handle KeyedStoreStubCompiler::CompileStoreField(Handle object, int index, - Map* transition, - String* name) { + Handle transition, + Handle name) { // ----------- S t a t e ------------- // -- r0 : value // -- r1 : name @@ -3224,17 +3421,12 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object, __ IncrementCounter(counters->keyed_store_field(), 1, r3, r4); // Check that the name has not changed. - __ cmp(r1, Operand(Handle(name))); + __ cmp(r1, Operand(name)); __ b(ne, &miss); // r3 is used as scratch register. r1 and r2 keep their values if a jump to // the miss label is generated. - GenerateStoreField(masm(), - object, - index, - transition, - r2, r1, r3, - &miss); + GenerateStoreField(masm(), object, index, transition, r2, r1, r3, &miss); __ bind(&miss); __ DecrementCounter(counters->keyed_store_field(), 1, r3, r4); @@ -3242,11 +3434,12 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object, __ Jump(ic, RelocInfo::CODE_TARGET); // Return the generated code. - return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name); + return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name); } -MaybeObject* KeyedStoreStubCompiler::CompileStoreElement(Map* receiver_map) { +Handle KeyedStoreStubCompiler::CompileStoreElement( + Handle receiver_map) { // ----------- S t a t e ------------- // -- r0 : value // -- r1 : key @@ -3254,30 +3447,25 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreElement(Map* receiver_map) { // -- lr : return address // -- r3 : scratch // ----------------------------------- - Code* stub; ElementsKind elements_kind = receiver_map->elements_kind(); bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; - MaybeObject* maybe_stub = - KeyedStoreElementStub(is_js_array, elements_kind).TryGetCode(); - if (!maybe_stub->To(&stub)) return maybe_stub; - __ DispatchMap(r2, - r3, - Handle(receiver_map), - Handle(stub), - DO_SMI_CHECK); + Handle stub = + KeyedStoreElementStub(is_js_array, elements_kind).GetCode(); + + __ DispatchMap(r2, r3, receiver_map, stub, DO_SMI_CHECK); Handle ic = isolate()->builtins()->KeyedStoreIC_Miss(); __ Jump(ic, RelocInfo::CODE_TARGET); // Return the generated code. - return GetCode(NORMAL, NULL); + return GetCode(NORMAL, factory()->empty_string()); } -MaybeObject* KeyedStoreStubCompiler::CompileStorePolymorphic( - MapList* receiver_maps, - CodeList* handler_stubs, - MapList* transitioned_maps) { +Handle KeyedStoreStubCompiler::CompileStorePolymorphic( + MapHandleList* receiver_maps, + CodeHandleList* handler_stubs, + MapHandleList* transitioned_maps) { // ----------- S t a t e ------------- // -- r0 : value // -- r1 : key @@ -3291,17 +3479,15 @@ MaybeObject* KeyedStoreStubCompiler::CompileStorePolymorphic( int receiver_count = receiver_maps->length(); __ ldr(r3, FieldMemOperand(r2, HeapObject::kMapOffset)); for (int i = 0; i < receiver_count; ++i) { - Handle map(receiver_maps->at(i)); - Handle code(handler_stubs->at(i)); - __ mov(ip, Operand(map)); + __ mov(ip, Operand(receiver_maps->at(i))); __ cmp(r3, ip); - if (transitioned_maps->at(i) == NULL) { - __ Jump(code, RelocInfo::CODE_TARGET, eq); + if (transitioned_maps->at(i).is_null()) { + __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq); } else { Label next_map; - __ b(eq, &next_map); - __ mov(r4, Operand(Handle(transitioned_maps->at(i)))); - __ Jump(code, RelocInfo::CODE_TARGET, al); + __ b(ne, &next_map); + __ mov(r3, Operand(transitioned_maps->at(i))); + __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, al); __ bind(&next_map); } } @@ -3311,7 +3497,7 @@ MaybeObject* KeyedStoreStubCompiler::CompileStorePolymorphic( __ Jump(miss_ic, RelocInfo::CODE_TARGET, al); // Return the generated code. - return GetCode(NORMAL, NULL, MEGAMORPHIC); + return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC); } diff --git a/deps/v8/src/array.js b/deps/v8/src/array.js index e1d7c20..214065c 100644 --- a/deps/v8/src/array.js +++ b/deps/v8/src/array.js @@ -1013,18 +1013,22 @@ function ArrayFilter(f, receiver) { } if (IS_NULL_OR_UNDEFINED(receiver)) { receiver = %GetDefaultReceiver(f) || receiver; + } else if (!IS_SPEC_OBJECT(receiver)) { + receiver = ToObject(receiver); } - var result = []; - var result_length = 0; + var result = new $Array(); + var accumulator = new InternalArray(); + var accumulator_length = 0; for (var i = 0; i < length; i++) { var current = array[i]; if (!IS_UNDEFINED(current) || i in array) { if (%_CallFunction(receiver, current, i, array, f)) { - result[result_length++] = current; + accumulator[accumulator_length++] = current; } } } + %MoveArrayContents(accumulator, result); return result; } @@ -1045,6 +1049,8 @@ function ArrayForEach(f, receiver) { } if (IS_NULL_OR_UNDEFINED(receiver)) { receiver = %GetDefaultReceiver(f) || receiver; + } else if (!IS_SPEC_OBJECT(receiver)) { + receiver = ToObject(receiver); } for (var i = 0; i < length; i++) { @@ -1074,6 +1080,8 @@ function ArraySome(f, receiver) { } if (IS_NULL_OR_UNDEFINED(receiver)) { receiver = %GetDefaultReceiver(f) || receiver; + } else if (!IS_SPEC_OBJECT(receiver)) { + receiver = ToObject(receiver); } for (var i = 0; i < length; i++) { @@ -1102,6 +1110,8 @@ function ArrayEvery(f, receiver) { } if (IS_NULL_OR_UNDEFINED(receiver)) { receiver = %GetDefaultReceiver(f) || receiver; + } else if (!IS_SPEC_OBJECT(receiver)) { + receiver = ToObject(receiver); } for (var i = 0; i < length; i++) { @@ -1129,6 +1139,8 @@ function ArrayMap(f, receiver) { } if (IS_NULL_OR_UNDEFINED(receiver)) { receiver = %GetDefaultReceiver(f) || receiver; + } else if (!IS_SPEC_OBJECT(receiver)) { + receiver = ToObject(receiver); } var result = new $Array(); diff --git a/deps/v8/src/assembler.cc b/deps/v8/src/assembler.cc index bda85e6..4dc2394 100644 --- a/deps/v8/src/assembler.cc +++ b/deps/v8/src/assembler.cc @@ -834,8 +834,8 @@ ExternalReference ExternalReference::keyed_lookup_cache_field_offsets( } -ExternalReference ExternalReference::roots_address(Isolate* isolate) { - return ExternalReference(isolate->heap()->roots_address()); +ExternalReference ExternalReference::roots_array_start(Isolate* isolate) { + return ExternalReference(isolate->heap()->roots_array_start()); } @@ -1137,6 +1137,23 @@ static int native_compare_doubles(double y, double x) { } +bool EvalComparison(Token::Value op, double op1, double op2) { + ASSERT(Token::IsCompareOp(op)); + switch (op) { + case Token::EQ: + case Token::EQ_STRICT: return (op1 == op2); + case Token::NE: return (op1 != op2); + case Token::LT: return (op1 < op2); + case Token::GT: return (op1 > op2); + case Token::LTE: return (op1 <= op2); + case Token::GTE: return (op1 >= op2); + default: + UNREACHABLE(); + return false; + } +} + + ExternalReference ExternalReference::double_fp_operation( Token::Value operation, Isolate* isolate) { typedef double BinaryFPOperation(double x, double y); diff --git a/deps/v8/src/assembler.h b/deps/v8/src/assembler.h index e5661c9..5b71363 100644 --- a/deps/v8/src/assembler.h +++ b/deps/v8/src/assembler.h @@ -279,14 +279,17 @@ class RelocInfo BASE_EMBEDDED { // this relocation applies to; // can only be called if IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY INLINE(Address target_address()); - INLINE(void set_target_address(Address target)); + INLINE(void set_target_address(Address target, + WriteBarrierMode mode = UPDATE_WRITE_BARRIER)); INLINE(Object* target_object()); INLINE(Handle target_object_handle(Assembler* origin)); INLINE(Object** target_object_address()); - INLINE(void set_target_object(Object* target)); + INLINE(void set_target_object(Object* target, + WriteBarrierMode mode = UPDATE_WRITE_BARRIER)); INLINE(JSGlobalPropertyCell* target_cell()); INLINE(Handle target_cell_handle()); - INLINE(void set_target_cell(JSGlobalPropertyCell* cell)); + INLINE(void set_target_cell(JSGlobalPropertyCell* cell, + WriteBarrierMode mode = UPDATE_WRITE_BARRIER)); // Read the address of the word containing the target_address in an @@ -593,8 +596,8 @@ class ExternalReference BASE_EMBEDDED { static ExternalReference keyed_lookup_cache_keys(Isolate* isolate); static ExternalReference keyed_lookup_cache_field_offsets(Isolate* isolate); - // Static variable Heap::roots_address() - static ExternalReference roots_address(Isolate* isolate); + // Static variable Heap::roots_array_start() + static ExternalReference roots_array_start(Isolate* isolate); // Static variable StackGuard::address_of_jslimit() static ExternalReference address_of_stack_limit(Isolate* isolate); @@ -847,6 +850,8 @@ static inline int NumberOfBitsSet(uint32_t x) { return num_bits_set; } +bool EvalComparison(Token::Value op, double op1, double op2); + // Computes pow(x, y) with the special cases in the spec for Math.pow. double power_double_int(double x, int y); double power_double_double(double x, double y); diff --git a/deps/v8/src/ast-inl.h b/deps/v8/src/ast-inl.h index 731ad2f..f8b460d 100644 --- a/deps/v8/src/ast-inl.h +++ b/deps/v8/src/ast-inl.h @@ -111,8 +111,18 @@ ForInStatement::ForInStatement(Isolate* isolate, ZoneStringList* labels) } -bool FunctionLiteral::strict_mode() const { - return scope()->is_strict_mode(); +int FunctionLiteral::start_position() const { + return scope()->start_position(); +} + + +int FunctionLiteral::end_position() const { + return scope()->end_position(); +} + + +StrictModeFlag FunctionLiteral::strict_mode_flag() const { + return scope()->strict_mode_flag(); } diff --git a/deps/v8/src/ast.cc b/deps/v8/src/ast.cc index d493814..9e34bc0 100644 --- a/deps/v8/src/ast.cc +++ b/deps/v8/src/ast.cc @@ -66,7 +66,6 @@ VariableProxy::VariableProxy(Isolate* isolate, Variable* var) name_(var->name()), var_(NULL), // Will be set by the call to BindTo. is_this_(var->is_this()), - inside_with_(false), is_trivial_(false), position_(RelocInfo::kNoPosition) { BindTo(var); @@ -76,13 +75,11 @@ VariableProxy::VariableProxy(Isolate* isolate, Variable* var) VariableProxy::VariableProxy(Isolate* isolate, Handle name, bool is_this, - bool inside_with, int position) : Expression(isolate), name_(name), var_(NULL), is_this_(is_this), - inside_with_(inside_with), is_trivial_(false), position_(position) { // Names must be canonicalized for fast equality checks. @@ -468,7 +465,7 @@ bool FunctionLiteral::IsInlineable() const { bool ThisFunction::IsInlineable() const { - return false; + return true; } @@ -723,7 +720,7 @@ bool Call::ComputeTarget(Handle type, Handle name) { holder_ = Handle::null(); } while (true) { - LookupResult lookup; + LookupResult lookup(type->GetIsolate()); type->LookupInDescriptors(NULL, *name, &lookup); // If the function wasn't found directly in the map, we start // looking upwards through the prototype chain. diff --git a/deps/v8/src/ast.h b/deps/v8/src/ast.h index 0efc483..3de00ef 100644 --- a/deps/v8/src/ast.h +++ b/deps/v8/src/ast.h @@ -405,7 +405,10 @@ class Declaration: public AstNode { mode_(mode), fun_(fun), scope_(scope) { - ASSERT(mode == VAR || mode == CONST || mode == LET); + ASSERT(mode == VAR || + mode == CONST || + mode == CONST_HARMONY || + mode == LET); // At the moment there are no "const functions"'s in JavaScript... ASSERT(fun == NULL || mode == VAR || mode == LET); } @@ -1128,7 +1131,6 @@ class VariableProxy: public Expression { Handle name() const { return name_; } Variable* var() const { return var_; } bool is_this() const { return is_this_; } - bool inside_with() const { return inside_with_; } int position() const { return position_; } void MarkAsTrivial() { is_trivial_ = true; } @@ -1140,14 +1142,12 @@ class VariableProxy: public Expression { Handle name_; Variable* var_; // resolved variable, or NULL bool is_this_; - bool inside_with_; bool is_trivial_; int position_; VariableProxy(Isolate* isolate, Handle name, bool is_this, - bool inside_with, int position = RelocInfo::kNoPosition); friend class Scope; @@ -1620,8 +1620,6 @@ class FunctionLiteral: public Expression { bool has_only_simple_this_property_assignments, Handle this_property_assignments, int num_parameters, - int start_position, - int end_position, Type type, bool has_duplicate_parameters) : Expression(isolate), @@ -1634,8 +1632,6 @@ class FunctionLiteral: public Expression { has_only_simple_this_property_assignments), this_property_assignments_(this_property_assignments), num_parameters_(num_parameters), - start_position_(start_position), - end_position_(end_position), function_token_position_(RelocInfo::kNoPosition), inferred_name_(HEAP->empty_string()), is_expression_(type != DECLARATION), @@ -1651,11 +1647,12 @@ class FunctionLiteral: public Expression { ZoneList* body() const { return body_; } void set_function_token_position(int pos) { function_token_position_ = pos; } int function_token_position() const { return function_token_position_; } - int start_position() const { return start_position_; } - int end_position() const { return end_position_; } + int start_position() const; + int end_position() const; bool is_expression() const { return is_expression_; } bool is_anonymous() const { return is_anonymous_; } - bool strict_mode() const; + bool strict_mode() const { return strict_mode_flag() == kStrictMode; } + StrictModeFlag strict_mode_flag() const; int materialized_literal_count() { return materialized_literal_count_; } int expected_property_count() { return expected_property_count_; } diff --git a/deps/v8/src/bootstrapper.cc b/deps/v8/src/bootstrapper.cc index dc722cb..6735ff4 100644 --- a/deps/v8/src/bootstrapper.cc +++ b/deps/v8/src/bootstrapper.cc @@ -38,6 +38,7 @@ #include "macro-assembler.h" #include "natives.h" #include "objects-visiting.h" +#include "platform.h" #include "snapshot.h" #include "extensions/externalize-string-extension.h" #include "extensions/gc-extension.h" @@ -362,6 +363,7 @@ static Handle InstallFunction(Handle target, if (is_ecma_native) { function->shared()->set_instance_class_name(*symbol); } + function->shared()->set_native(true); return function; } @@ -375,26 +377,28 @@ Handle Genesis::ComputeFunctionInstanceDescriptor( PropertyAttributes attributes = static_cast(DONT_ENUM | DONT_DELETE | READ_ONLY); + DescriptorArray::WhitenessWitness witness(*descriptors); + { // Add length. Handle foreign = factory()->NewForeign(&Accessors::FunctionLength); CallbacksDescriptor d(*factory()->length_symbol(), *foreign, attributes); - descriptors->Set(0, &d); + descriptors->Set(0, &d, witness); } { // Add name. Handle foreign = factory()->NewForeign(&Accessors::FunctionName); CallbacksDescriptor d(*factory()->name_symbol(), *foreign, attributes); - descriptors->Set(1, &d); + descriptors->Set(1, &d, witness); } { // Add arguments. Handle foreign = factory()->NewForeign(&Accessors::FunctionArguments); CallbacksDescriptor d(*factory()->arguments_symbol(), *foreign, attributes); - descriptors->Set(2, &d); + descriptors->Set(2, &d, witness); } { // Add caller. Handle foreign = factory()->NewForeign(&Accessors::FunctionCaller); CallbacksDescriptor d(*factory()->caller_symbol(), *foreign, attributes); - descriptors->Set(3, &d); + descriptors->Set(3, &d, witness); } if (prototypeMode != DONT_ADD_PROTOTYPE) { // Add prototype. @@ -404,9 +408,9 @@ Handle Genesis::ComputeFunctionInstanceDescriptor( Handle foreign = factory()->NewForeign(&Accessors::FunctionPrototype); CallbacksDescriptor d(*factory()->prototype_symbol(), *foreign, attributes); - descriptors->Set(4, &d); + descriptors->Set(4, &d, witness); } - descriptors->Sort(); + descriptors->Sort(witness); return descriptors; } @@ -522,41 +526,43 @@ Handle Genesis::ComputeStrictFunctionInstanceDescriptor( ? 4 : 5); PropertyAttributes attributes = static_cast( - DONT_ENUM | DONT_DELETE | READ_ONLY); + DONT_ENUM | DONT_DELETE); + + DescriptorArray::WhitenessWitness witness(*descriptors); { // length Handle foreign = factory()->NewForeign(&Accessors::FunctionLength); CallbacksDescriptor d(*factory()->length_symbol(), *foreign, attributes); - descriptors->Set(0, &d); + descriptors->Set(0, &d, witness); } { // name Handle foreign = factory()->NewForeign(&Accessors::FunctionName); CallbacksDescriptor d(*factory()->name_symbol(), *foreign, attributes); - descriptors->Set(1, &d); + descriptors->Set(1, &d, witness); } { // arguments CallbacksDescriptor d(*factory()->arguments_symbol(), *arguments, attributes); - descriptors->Set(2, &d); + descriptors->Set(2, &d, witness); } { // caller CallbacksDescriptor d(*factory()->caller_symbol(), *caller, attributes); - descriptors->Set(3, &d); + descriptors->Set(3, &d, witness); } // prototype if (prototypeMode != DONT_ADD_PROTOTYPE) { - if (prototypeMode == ADD_WRITEABLE_PROTOTYPE) { - attributes = static_cast(attributes & ~READ_ONLY); + if (prototypeMode != ADD_WRITEABLE_PROTOTYPE) { + attributes = static_cast(attributes | READ_ONLY); } Handle foreign = factory()->NewForeign(&Accessors::FunctionPrototype); CallbacksDescriptor d(*factory()->prototype_symbol(), *foreign, attributes); - descriptors->Set(4, &d); + descriptors->Set(4, &d, witness); } - descriptors->Sort(); + descriptors->Sort(witness); return descriptors; } @@ -941,6 +947,7 @@ void Genesis::InitializeGlobal(Handle inner_global, ASSERT_EQ(0, initial_map->inobject_properties()); Handle descriptors = factory->NewDescriptorArray(5); + DescriptorArray::WhitenessWitness witness(*descriptors); PropertyAttributes final = static_cast(DONT_ENUM | DONT_DELETE | READ_ONLY); int enum_index = 0; @@ -950,7 +957,7 @@ void Genesis::InitializeGlobal(Handle inner_global, JSRegExp::kSourceFieldIndex, final, enum_index++); - descriptors->Set(0, &field); + descriptors->Set(0, &field, witness); } { // ECMA-262, section 15.10.7.2. @@ -958,7 +965,7 @@ void Genesis::InitializeGlobal(Handle inner_global, JSRegExp::kGlobalFieldIndex, final, enum_index++); - descriptors->Set(1, &field); + descriptors->Set(1, &field, witness); } { // ECMA-262, section 15.10.7.3. @@ -966,7 +973,7 @@ void Genesis::InitializeGlobal(Handle inner_global, JSRegExp::kIgnoreCaseFieldIndex, final, enum_index++); - descriptors->Set(2, &field); + descriptors->Set(2, &field, witness); } { // ECMA-262, section 15.10.7.4. @@ -974,7 +981,7 @@ void Genesis::InitializeGlobal(Handle inner_global, JSRegExp::kMultilineFieldIndex, final, enum_index++); - descriptors->Set(3, &field); + descriptors->Set(3, &field, witness); } { // ECMA-262, section 15.10.7.5. @@ -984,10 +991,10 @@ void Genesis::InitializeGlobal(Handle inner_global, JSRegExp::kLastIndexFieldIndex, writable, enum_index++); - descriptors->Set(4, &field); + descriptors->Set(4, &field, witness); } descriptors->SetNextEnumerationIndex(enum_index); - descriptors->Sort(); + descriptors->Sort(witness); initial_map->set_inobject_properties(5); initial_map->set_pre_allocated_property_fields(5); @@ -1065,7 +1072,7 @@ void Genesis::InitializeGlobal(Handle inner_global, DONT_ENUM); #ifdef DEBUG - LookupResult lookup; + LookupResult lookup(isolate); result->LocalLookup(heap->callee_symbol(), &lookup); ASSERT(lookup.IsProperty() && (lookup.type() == FIELD)); ASSERT(lookup.GetFieldIndex() == Heap::kArgumentsCalleeIndex); @@ -1084,11 +1091,6 @@ void Genesis::InitializeGlobal(Handle inner_global, } { // --- aliased_arguments_boilerplate_ - Handle old_map(global_context()->arguments_boilerplate()->map()); - Handle new_map = factory->CopyMapDropTransitions(old_map); - new_map->set_pre_allocated_property_fields(2); - Handle result = factory->NewJSObjectFromMap(new_map); - new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS); // Set up a well-formed parameter map to make assertions happy. Handle elements = factory->NewFixedArray(2); elements->set_map(heap->non_strict_arguments_elements_map()); @@ -1097,12 +1099,16 @@ void Genesis::InitializeGlobal(Handle inner_global, elements->set(0, *array); array = factory->NewFixedArray(0); elements->set(1, *array); - Handle non_strict_arguments_elements_map = - factory->GetElementsTransitionMap(result, - NON_STRICT_ARGUMENTS_ELEMENTS); - result->set_map(*non_strict_arguments_elements_map); - ASSERT(result->HasNonStrictArgumentsElements()); + + Handle old_map(global_context()->arguments_boilerplate()->map()); + Handle new_map = factory->CopyMapDropTransitions(old_map); + new_map->set_pre_allocated_property_fields(2); + Handle result = factory->NewJSObjectFromMap(new_map); + // Set elements kind after allocating the object because + // NewJSObjectFromMap assumes a fast elements map. + new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS); result->set_elements(*elements); + ASSERT(result->HasNonStrictArgumentsElements()); global_context()->set_aliased_arguments_boilerplate(*result); } @@ -1125,19 +1131,20 @@ void Genesis::InitializeGlobal(Handle inner_global, // Create the descriptor array for the arguments object. Handle descriptors = factory->NewDescriptorArray(3); + DescriptorArray::WhitenessWitness witness(*descriptors); { // length FieldDescriptor d(*factory->length_symbol(), 0, DONT_ENUM); - descriptors->Set(0, &d); + descriptors->Set(0, &d, witness); } { // callee CallbacksDescriptor d(*factory->callee_symbol(), *callee, attributes); - descriptors->Set(1, &d); + descriptors->Set(1, &d, witness); } { // caller CallbacksDescriptor d(*factory->caller_symbol(), *caller, attributes); - descriptors->Set(2, &d); + descriptors->Set(2, &d, witness); } - descriptors->Sort(); + descriptors->Sort(witness); // Create the map. Allocate one in-object field for length. Handle map = factory->NewMap(JS_OBJECT_TYPE, @@ -1162,7 +1169,7 @@ void Genesis::InitializeGlobal(Handle inner_global, DONT_ENUM); #ifdef DEBUG - LookupResult lookup; + LookupResult lookup(isolate); result->LocalLookup(heap->length_symbol(), &lookup); ASSERT(lookup.IsProperty() && (lookup.type() == FIELD)); ASSERT(lookup.GetFieldIndex() == Heap::kArgumentsLengthIndex); @@ -1221,6 +1228,14 @@ void Genesis::InitializeGlobal(Handle inner_global, // Initialize the data slot. global_context()->set_data(heap->undefined_value()); + + { + // Initialize the random seed slot. + Handle zeroed_byte_array( + factory->NewByteArray(kRandomStateSize)); + global_context()->set_random_seed(*zeroed_byte_array); + memset(zeroed_byte_array->GetDataStartAddress(), 0, kRandomStateSize); + } } @@ -1228,12 +1243,26 @@ void Genesis::InitializeExperimentalGlobal() { Handle global = Handle(global_context()->global()); // TODO(mstarzinger): Move this into Genesis::InitializeGlobal once we no - // longer need to live behind a flag, so WeakMap gets added to the snapshot. - if (FLAG_harmony_weakmaps) { // -- W e a k M a p - Handle prototype = - factory()->NewJSObject(isolate()->object_function(), TENURED); - InstallFunction(global, "WeakMap", JS_WEAK_MAP_TYPE, JSWeakMap::kSize, - prototype, Builtins::kIllegal, true); + // longer need to live behind a flag, so functions get added to the snapshot. + if (FLAG_harmony_collections) { + { // -- S e t + Handle prototype = + factory()->NewJSObject(isolate()->object_function(), TENURED); + InstallFunction(global, "Set", JS_SET_TYPE, JSSet::kSize, + prototype, Builtins::kIllegal, true); + } + { // -- M a p + Handle prototype = + factory()->NewJSObject(isolate()->object_function(), TENURED); + InstallFunction(global, "Map", JS_MAP_TYPE, JSMap::kSize, + prototype, Builtins::kIllegal, true); + } + { // -- W e a k M a p + Handle prototype = + factory()->NewJSObject(isolate()->object_function(), TENURED); + InstallFunction(global, "WeakMap", JS_WEAK_MAP_TYPE, JSWeakMap::kSize, + prototype, Builtins::kIllegal, true); + } } } @@ -1362,6 +1391,7 @@ void Genesis::InstallExperimentalNativeFunctions() { INSTALL_NATIVE(JSFunction, "DerivedHasTrap", derived_has_trap); INSTALL_NATIVE(JSFunction, "DerivedGetTrap", derived_get_trap); INSTALL_NATIVE(JSFunction, "DerivedSetTrap", derived_set_trap); + INSTALL_NATIVE(JSFunction, "ProxyEnumerate", proxy_enumerate); } } @@ -1696,7 +1726,9 @@ bool Genesis::InstallNatives() { Handle reresult_descriptors = factory()->NewDescriptorArray(3); - reresult_descriptors->CopyFrom(0, *array_descriptors, 0); + DescriptorArray::WhitenessWitness witness(*reresult_descriptors); + + reresult_descriptors->CopyFrom(0, *array_descriptors, 0, witness); int enum_index = 0; { @@ -1704,7 +1736,7 @@ bool Genesis::InstallNatives() { JSRegExpResult::kIndexIndex, NONE, enum_index++); - reresult_descriptors->Set(1, &index_field); + reresult_descriptors->Set(1, &index_field, witness); } { @@ -1712,9 +1744,9 @@ bool Genesis::InstallNatives() { JSRegExpResult::kInputIndex, NONE, enum_index++); - reresult_descriptors->Set(2, &input_field); + reresult_descriptors->Set(2, &input_field, witness); } - reresult_descriptors->Sort(); + reresult_descriptors->Sort(witness); initial_map->set_inobject_properties(2); initial_map->set_pre_allocated_property_fields(2); @@ -1741,9 +1773,9 @@ bool Genesis::InstallExperimentalNatives() { "native proxy.js") == 0) { if (!CompileExperimentalBuiltin(isolate(), i)) return false; } - if (FLAG_harmony_weakmaps && + if (FLAG_harmony_collections && strcmp(ExperimentalNatives::GetScriptName(i).start(), - "native weakmap.js") == 0) { + "native collection.js") == 0) { if (!CompileExperimentalBuiltin(isolate(), i)) return false; } } @@ -1989,6 +2021,12 @@ bool Genesis::InstallExtension(v8::RegisteredExtension* current) { false); ASSERT(isolate->has_pending_exception() != result); if (!result) { + // We print out the name of the extension that fail to install. + // When an error is thrown during bootstrapping we automatically print + // the line number at which this happened to the console in the isolate + // error throwing functionality. + OS::PrintError("Error installing extension '%s'.\n", + current->extension()->name()); isolate->clear_pending_exception(); } current->set_state(v8::INSTALLED); @@ -2008,7 +2046,9 @@ bool Genesis::InstallJSBuiltins(Handle builtins) { builtins->set_javascript_builtin(id, *function); Handle shared = Handle(function->shared()); - if (!EnsureCompiled(shared, CLEAR_EXCEPTION)) return false; + if (!SharedFunctionInfo::EnsureCompiled(shared, CLEAR_EXCEPTION)) { + return false; + } // Set the code object on the function object. function->ReplaceCode(function->shared()->code()); builtins->set_javascript_builtin_code(id, shared->code()); @@ -2088,7 +2128,7 @@ void Genesis::TransferNamedProperties(Handle from, break; } case CALLBACKS: { - LookupResult result; + LookupResult result(isolate()); to->LocalLookup(descs->GetKey(i), &result); // If the property is already there we skip it if (result.IsProperty()) continue; @@ -2126,7 +2166,7 @@ void Genesis::TransferNamedProperties(Handle from, if (properties->IsKey(raw_key)) { ASSERT(raw_key->IsString()); // If the property is already there we skip it. - LookupResult result; + LookupResult result(isolate()); to->LocalLookup(String::cast(raw_key), &result); if (result.IsProperty()) continue; // Set the property. diff --git a/deps/v8/src/builtins.cc b/deps/v8/src/builtins.cc index d513200..e758b9a 100644 --- a/deps/v8/src/builtins.cc +++ b/deps/v8/src/builtins.cc @@ -1507,6 +1507,14 @@ static void Generate_KeyedStoreIC_NonStrictArguments(MacroAssembler* masm) { KeyedStoreIC::GenerateNonStrictArguments(masm); } +static void Generate_TransitionElementsSmiToDouble(MacroAssembler* masm) { + KeyedStoreIC::GenerateTransitionElementsSmiToDouble(masm); +} + +static void Generate_TransitionElementsDoubleToObject(MacroAssembler* masm) { + KeyedStoreIC::GenerateTransitionElementsDoubleToObject(masm); +} + #ifdef ENABLE_DEBUGGER_SUPPORT static void Generate_LoadIC_DebugBreak(MacroAssembler* masm) { Debug::GenerateLoadICDebugBreak(masm); diff --git a/deps/v8/src/builtins.h b/deps/v8/src/builtins.h index 31090d3..24059e7 100644 --- a/deps/v8/src/builtins.h +++ b/deps/v8/src/builtins.h @@ -167,6 +167,10 @@ enum BuiltinExtraArguments { kStrictMode) \ V(KeyedStoreIC_NonStrictArguments, KEYED_STORE_IC, MEGAMORPHIC, \ Code::kNoExtraICState) \ + V(TransitionElementsSmiToDouble, BUILTIN, UNINITIALIZED, \ + Code::kNoExtraICState) \ + V(TransitionElementsDoubleToObject, BUILTIN, UNINITIALIZED, \ + Code::kNoExtraICState) \ \ /* Uses KeyedLoadIC_Initialize; must be after in list. */ \ V(FunctionCall, BUILTIN, UNINITIALIZED, \ @@ -234,7 +238,6 @@ enum BuiltinExtraArguments { V(DELETE, 2) \ V(IN, 1) \ V(INSTANCE_OF, 1) \ - V(GET_KEYS, 0) \ V(FILTER_KEY, 1) \ V(CALL_NON_FUNCTION, 0) \ V(CALL_NON_FUNCTION_AS_CONSTRUCTOR, 0) \ diff --git a/deps/v8/src/checks.h b/deps/v8/src/checks.h index 2f359f6..832f778 100644 --- a/deps/v8/src/checks.h +++ b/deps/v8/src/checks.h @@ -63,7 +63,9 @@ static inline void CheckHelper(const char* file, // The CHECK macro checks that the given condition is true; if not, it // prints a message to stderr and aborts. -#define CHECK(condition) CheckHelper(__FILE__, __LINE__, #condition, condition) +#define CHECK(condition) do { \ + if (!(condition)) CheckHelper(__FILE__, __LINE__, #condition, false); \ + } while (0) // Helper function used by the CHECK_EQ function when given int @@ -257,11 +259,8 @@ template class StaticAssertionHelper { }; SEMI_STATIC_JOIN(__StaticAssertTypedef__, __LINE__) -namespace v8 { namespace internal { +extern bool FLAG_enable_slow_asserts; -bool EnableSlowAsserts(); - -} } // namespace v8::internal // The ASSERT macro is equivalent to CHECK except that it only // generates code in debug builds. @@ -273,7 +272,7 @@ bool EnableSlowAsserts(); #define ASSERT_GE(v1, v2) CHECK_GE(v1, v2) #define ASSERT_LT(v1, v2) CHECK_LT(v1, v2) #define ASSERT_LE(v1, v2) CHECK_LE(v1, v2) -#define SLOW_ASSERT(condition) if (EnableSlowAsserts()) CHECK(condition) +#define SLOW_ASSERT(condition) if (FLAG_enable_slow_asserts) CHECK(condition) #else #define ASSERT_RESULT(expr) (expr) #define ASSERT(condition) ((void) 0) diff --git a/deps/v8/src/code-stubs.cc b/deps/v8/src/code-stubs.cc index 4bc2603..b437436 100644 --- a/deps/v8/src/code-stubs.cc +++ b/deps/v8/src/code-stubs.cc @@ -415,4 +415,29 @@ bool ToBooleanStub::Types::CanBeUndetectable() const { } +void ElementsTransitionAndStoreStub::Generate(MacroAssembler* masm) { + Label fail; + if (!FLAG_trace_elements_transitions) { + if (to_ == FAST_ELEMENTS) { + if (from_ == FAST_SMI_ONLY_ELEMENTS) { + ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm); + } else if (from_ == FAST_DOUBLE_ELEMENTS) { + ElementsTransitionGenerator::GenerateDoubleToObject(masm, &fail); + } else { + UNREACHABLE(); + } + KeyedStoreStubCompiler::GenerateStoreFastElement(masm, + is_jsarray_, + FAST_ELEMENTS); + } else if (from_ == FAST_SMI_ONLY_ELEMENTS && to_ == FAST_DOUBLE_ELEMENTS) { + ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &fail); + KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(masm, is_jsarray_); + } else { + UNREACHABLE(); + } + } + masm->bind(&fail); + KeyedStoreIC::GenerateRuntimeSetProperty(masm, strict_mode_); +} + } } // namespace v8::internal diff --git a/deps/v8/src/code-stubs.h b/deps/v8/src/code-stubs.h index acfbd46..fc7000b 100644 --- a/deps/v8/src/code-stubs.h +++ b/deps/v8/src/code-stubs.h @@ -30,6 +30,7 @@ #include "allocation.h" #include "globals.h" +#include "codegen.h" namespace v8 { namespace internal { @@ -69,7 +70,8 @@ namespace internal { V(KeyedLoadElement) \ V(KeyedStoreElement) \ V(DebuggerStatement) \ - V(StringDictionaryLookup) + V(StringDictionaryLookup) \ + V(ElementsTransitionAndStore) // List of code stubs only used on ARM platforms. #ifdef V8_TARGET_ARCH_ARM @@ -362,6 +364,7 @@ class FastCloneShallowArrayStub : public CodeStub { enum Mode { CLONE_ELEMENTS, + CLONE_DOUBLE_ELEMENTS, COPY_ON_WRITE_ELEMENTS }; @@ -380,8 +383,8 @@ class FastCloneShallowArrayStub : public CodeStub { Major MajorKey() { return FastCloneShallowArray; } int MinorKey() { - ASSERT(mode_ == 0 || mode_ == 1); - return (length_ << 1) | mode_; + ASSERT(mode_ == 0 || mode_ == 1 || mode_ == 2); + return length_ * 3 + mode_; } }; @@ -1025,6 +1028,42 @@ class ToBooleanStub: public CodeStub { Types types_; }; + +class ElementsTransitionAndStoreStub : public CodeStub { + public: + ElementsTransitionAndStoreStub(ElementsKind from, + ElementsKind to, + bool is_jsarray, + StrictModeFlag strict_mode) + : from_(from), + to_(to), + is_jsarray_(is_jsarray), + strict_mode_(strict_mode) {} + + private: + class FromBits: public BitField {}; + class ToBits: public BitField {}; + class IsJSArrayBits: public BitField {}; + class StrictModeBits: public BitField {}; + + Major MajorKey() { return ElementsTransitionAndStore; } + int MinorKey() { + return FromBits::encode(from_) | + ToBits::encode(to_) | + IsJSArrayBits::encode(is_jsarray_) | + StrictModeBits::encode(strict_mode_); + } + + void Generate(MacroAssembler* masm); + + ElementsKind from_; + ElementsKind to_; + bool is_jsarray_; + StrictModeFlag strict_mode_; + + DISALLOW_COPY_AND_ASSIGN(ElementsTransitionAndStoreStub); +}; + } } // namespace v8::internal #endif // V8_CODE_STUBS_H_ diff --git a/deps/v8/src/codegen.h b/deps/v8/src/codegen.h index e551abf..5360d3e 100644 --- a/deps/v8/src/codegen.h +++ b/deps/v8/src/codegen.h @@ -81,4 +81,19 @@ enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF }; #error Unsupported target architecture. #endif +namespace v8 { +namespace internal { + +class ElementsTransitionGenerator : public AllStatic { + public: + static void GenerateSmiOnlyToObject(MacroAssembler* masm); + static void GenerateSmiOnlyToDouble(MacroAssembler* masm, Label* fail); + static void GenerateDoubleToObject(MacroAssembler* masm, Label* fail); + + private: + DISALLOW_COPY_AND_ASSIGN(ElementsTransitionGenerator); +}; + +} } // namespace v8::internal + #endif // V8_CODEGEN_H_ diff --git a/deps/v8/src/weakmap.js b/deps/v8/src/collection.js similarity index 65% rename from deps/v8/src/weakmap.js rename to deps/v8/src/collection.js index 5fb5151..4e45885 100644 --- a/deps/v8/src/weakmap.js +++ b/deps/v8/src/collection.js @@ -26,12 +26,69 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// This file relies on the fact that the following declaration has been made -// in runtime.js: -// const $Object = global.Object; +const $Set = global.Set; +const $Map = global.Map; const $WeakMap = global.WeakMap; -// ------------------------------------------------------------------- +//------------------------------------------------------------------- + +function SetConstructor() { + if (%_IsConstructCall()) { + %SetInitialize(this); + } else { + return new $Set(); + } +} + + +function SetAdd(key) { + return %SetAdd(this, key); +} + + +function SetHas(key) { + return %SetHas(this, key); +} + + +function SetDelete(key) { + return %SetDelete(this, key); +} + + +function MapConstructor() { + if (%_IsConstructCall()) { + %MapInitialize(this); + } else { + return new $Map(); + } +} + + +function MapGet(key) { + return %MapGet(this, key); +} + + +function MapSet(key, value) { + return %MapSet(this, key, value); +} + + +function MapHas(key) { + return !IS_UNDEFINED(%MapGet(this, key)); +} + + +function MapDelete(key) { + if (!IS_UNDEFINED(%MapGet(this, key))) { + %MapSet(this, key, void 0); + return true; + } else { + return false; + } +} + function WeakMapConstructor() { if (%_IsConstructCall()) { @@ -82,6 +139,30 @@ function WeakMapDelete(key) { (function () { %CheckIsBootstrapping(); + + // Set up the Set and Map constructor function. + %SetCode($Set, SetConstructor); + %SetCode($Map, MapConstructor); + + // Set up the constructor property on the Set and Map prototype object. + %SetProperty($Set.prototype, "constructor", $Set, DONT_ENUM); + %SetProperty($Map.prototype, "constructor", $Map, DONT_ENUM); + + // Set up the non-enumerable functions on the Set prototype object. + InstallFunctionsOnHiddenPrototype($Set.prototype, DONT_ENUM, $Array( + "add", SetAdd, + "has", SetHas, + "delete", SetDelete + )); + + // Set up the non-enumerable functions on the Map prototype object. + InstallFunctionsOnHiddenPrototype($Map.prototype, DONT_ENUM, $Array( + "get", MapGet, + "set", MapSet, + "has", MapHas, + "delete", MapDelete + )); + // Set up the WeakMap constructor function. %SetCode($WeakMap, WeakMapConstructor); diff --git a/deps/v8/src/compiler.cc b/deps/v8/src/compiler.cc index 4979a7f..88db467 100644 --- a/deps/v8/src/compiler.cc +++ b/deps/v8/src/compiler.cc @@ -59,7 +59,6 @@ CompilationInfo::CompilationInfo(Handle