summaryrefslogtreecommitdiff
path: root/deps/v8
diff options
context:
space:
mode:
authorRyan Dahl <ry@tinyclouds.org>2011-10-27 00:48:23 -0700
committerRyan Dahl <ry@tinyclouds.org>2011-10-27 00:48:23 -0700
commit92f5a5d3caf01f382f90c235e9057590a5e76870 (patch)
treeedf52631145345943dc82e1b783de81ba89208af /deps/v8
parent528c28587f11b64616ffa22b5cf3f53bea831792 (diff)
downloadnode-new-92f5a5d3caf01f382f90c235e9057590a5e76870.tar.gz
Upgrade V8 to 3.7.1
Diffstat (limited to 'deps/v8')
-rw-r--r--deps/v8/ChangeLog45
-rw-r--r--deps/v8/build/common.gypi1
-rw-r--r--deps/v8/preparser/preparser-process.cc35
-rwxr-xr-xdeps/v8/src/SConscript2
-rw-r--r--deps/v8/src/accessors.cc11
-rw-r--r--deps/v8/src/api.cc57
-rw-r--r--deps/v8/src/arm/assembler-arm-inl.h15
-rw-r--r--deps/v8/src/arm/assembler-arm.h6
-rw-r--r--deps/v8/src/arm/builtins-arm.cc78
-rw-r--r--deps/v8/src/arm/code-stubs-arm.cc98
-rw-r--r--deps/v8/src/arm/code-stubs-arm.h12
-rw-r--r--deps/v8/src/arm/codegen-arm.cc249
-rw-r--r--deps/v8/src/arm/codegen-arm.h1
-rw-r--r--deps/v8/src/arm/deoptimizer-arm.cc22
-rw-r--r--deps/v8/src/arm/full-codegen-arm.cc169
-rw-r--r--deps/v8/src/arm/ic-arm.cc104
-rw-r--r--deps/v8/src/arm/lithium-arm.cc36
-rw-r--r--deps/v8/src/arm/lithium-arm.h32
-rw-r--r--deps/v8/src/arm/lithium-codegen-arm.cc191
-rw-r--r--deps/v8/src/arm/lithium-codegen-arm.h14
-rw-r--r--deps/v8/src/arm/macro-assembler-arm.cc36
-rw-r--r--deps/v8/src/arm/macro-assembler-arm.h61
-rw-r--r--deps/v8/src/arm/regexp-macro-assembler-arm.cc5
-rw-r--r--deps/v8/src/arm/simulator-arm.cc4
-rw-r--r--deps/v8/src/arm/stub-cache-arm.cc656
-rw-r--r--deps/v8/src/array.js18
-rw-r--r--deps/v8/src/assembler.cc21
-rw-r--r--deps/v8/src/assembler.h15
-rw-r--r--deps/v8/src/ast-inl.h14
-rw-r--r--deps/v8/src/ast.cc7
-rw-r--r--deps/v8/src/ast.h19
-rw-r--r--deps/v8/src/bootstrapper.cc144
-rw-r--r--deps/v8/src/builtins.cc8
-rw-r--r--deps/v8/src/builtins.h5
-rw-r--r--deps/v8/src/checks.h11
-rw-r--r--deps/v8/src/code-stubs.cc25
-rw-r--r--deps/v8/src/code-stubs.h45
-rw-r--r--deps/v8/src/codegen.h15
-rw-r--r--deps/v8/src/collection.js (renamed from deps/v8/src/weakmap.js)89
-rw-r--r--deps/v8/src/compiler.cc46
-rw-r--r--deps/v8/src/compiler.h54
-rw-r--r--deps/v8/src/contexts.cc29
-rw-r--r--deps/v8/src/contexts.h53
-rw-r--r--deps/v8/src/d8.cc3
-rw-r--r--deps/v8/src/debug.cc242
-rw-r--r--deps/v8/src/debug.h7
-rw-r--r--deps/v8/src/deoptimizer.cc9
-rw-r--r--deps/v8/src/deoptimizer.h3
-rw-r--r--deps/v8/src/factory.cc53
-rw-r--r--deps/v8/src/factory.h7
-rw-r--r--deps/v8/src/flag-definitions.h8
-rw-r--r--deps/v8/src/frames.cc63
-rw-r--r--deps/v8/src/frames.h2
-rw-r--r--deps/v8/src/full-codegen.cc16
-rw-r--r--deps/v8/src/full-codegen.h6
-rw-r--r--deps/v8/src/globals.h3
-rw-r--r--deps/v8/src/handles.cc114
-rw-r--r--deps/v8/src/handles.h46
-rw-r--r--deps/v8/src/heap-inl.h5
-rw-r--r--deps/v8/src/heap.cc135
-rw-r--r--deps/v8/src/heap.h40
-rw-r--r--deps/v8/src/hydrogen-instructions.cc79
-rw-r--r--deps/v8/src/hydrogen-instructions.h92
-rw-r--r--deps/v8/src/hydrogen.cc286
-rw-r--r--deps/v8/src/hydrogen.h32
-rw-r--r--deps/v8/src/ia32/assembler-ia32-inl.h15
-rw-r--r--deps/v8/src/ia32/builtins-ia32.cc13
-rw-r--r--deps/v8/src/ia32/code-stubs-ia32.cc138
-rw-r--r--deps/v8/src/ia32/code-stubs-ia32.h11
-rw-r--r--deps/v8/src/ia32/codegen-ia32.cc258
-rw-r--r--deps/v8/src/ia32/deoptimizer-ia32.cc15
-rw-r--r--deps/v8/src/ia32/disasm-ia32.cc12
-rw-r--r--deps/v8/src/ia32/full-codegen-ia32.cc177
-rw-r--r--deps/v8/src/ia32/ic-ia32.cc142
-rw-r--r--deps/v8/src/ia32/lithium-codegen-ia32.cc192
-rw-r--r--deps/v8/src/ia32/lithium-codegen-ia32.h12
-rw-r--r--deps/v8/src/ia32/lithium-ia32.cc46
-rw-r--r--deps/v8/src/ia32/lithium-ia32.h32
-rw-r--r--deps/v8/src/ia32/macro-assembler-ia32.cc44
-rw-r--r--deps/v8/src/ia32/macro-assembler-ia32.h6
-rw-r--r--deps/v8/src/ia32/regexp-macro-assembler-ia32.cc5
-rw-r--r--deps/v8/src/ia32/stub-cache-ia32.cc707
-rw-r--r--deps/v8/src/ic.cc1087
-rw-r--r--deps/v8/src/ic.h190
-rw-r--r--deps/v8/src/incremental-marking-inl.h3
-rw-r--r--deps/v8/src/incremental-marking.cc26
-rw-r--r--deps/v8/src/incremental-marking.h11
-rw-r--r--deps/v8/src/interpreter-irregexp.cc37
-rw-r--r--deps/v8/src/interpreter-irregexp.h12
-rw-r--r--deps/v8/src/isolate.cc14
-rw-r--r--deps/v8/src/isolate.h11
-rw-r--r--deps/v8/src/jsregexp.cc18
-rw-r--r--deps/v8/src/list-inl.h5
-rw-r--r--deps/v8/src/list.h4
-rw-r--r--deps/v8/src/liveobjectlist.cc6
-rw-r--r--deps/v8/src/macros.py5
-rw-r--r--deps/v8/src/mark-compact-inl.h8
-rw-r--r--deps/v8/src/mark-compact.cc73
-rw-r--r--deps/v8/src/mark-compact.h56
-rw-r--r--deps/v8/src/messages.js44
-rw-r--r--deps/v8/src/mips/assembler-mips-inl.h15
-rw-r--r--deps/v8/src/mips/assembler-mips.h2
-rw-r--r--deps/v8/src/mips/builtins-mips.cc69
-rw-r--r--deps/v8/src/mips/code-stubs-mips.cc129
-rw-r--r--deps/v8/src/mips/code-stubs-mips.h12
-rw-r--r--deps/v8/src/mips/codegen-mips.cc257
-rw-r--r--deps/v8/src/mips/codegen-mips.h1
-rw-r--r--deps/v8/src/mips/deoptimizer-mips.cc3
-rw-r--r--deps/v8/src/mips/full-codegen-mips.cc175
-rw-r--r--deps/v8/src/mips/ic-mips.cc104
-rw-r--r--deps/v8/src/mips/macro-assembler-mips.cc32
-rw-r--r--deps/v8/src/mips/macro-assembler-mips.h3
-rw-r--r--deps/v8/src/mips/regexp-macro-assembler-mips.cc5
-rw-r--r--deps/v8/src/mips/simulator-mips.cc4
-rw-r--r--deps/v8/src/mips/stub-cache-mips.cc501
-rw-r--r--deps/v8/src/mirror-debugger.js2
-rw-r--r--deps/v8/src/mksnapshot.cc1
-rw-r--r--deps/v8/src/objects-debug.cc28
-rw-r--r--deps/v8/src/objects-inl.h426
-rw-r--r--deps/v8/src/objects-printer.cc48
-rw-r--r--deps/v8/src/objects-visiting.cc10
-rw-r--r--deps/v8/src/objects.cc788
-rw-r--r--deps/v8/src/objects.h289
-rw-r--r--deps/v8/src/parser.cc464
-rw-r--r--deps/v8/src/parser.h23
-rw-r--r--deps/v8/src/platform-solaris.cc141
-rw-r--r--deps/v8/src/preparser-api.cc2
-rw-r--r--deps/v8/src/preparser.cc48
-rw-r--r--deps/v8/src/preparser.h51
-rw-r--r--deps/v8/src/profile-generator.cc19
-rw-r--r--deps/v8/src/property.cc9
-rw-r--r--deps/v8/src/property.h22
-rw-r--r--deps/v8/src/proxy.js42
-rw-r--r--deps/v8/src/regexp.js15
-rw-r--r--deps/v8/src/runtime.cc934
-rw-r--r--deps/v8/src/runtime.h38
-rw-r--r--deps/v8/src/runtime.js15
-rw-r--r--deps/v8/src/scanner.h11
-rw-r--r--deps/v8/src/scopeinfo.cc81
-rw-r--r--deps/v8/src/scopeinfo.h15
-rw-r--r--deps/v8/src/scopes.cc371
-rw-r--r--deps/v8/src/scopes.h156
-rw-r--r--deps/v8/src/serialize.cc185
-rw-r--r--deps/v8/src/serialize.h70
-rw-r--r--deps/v8/src/spaces-inl.h4
-rw-r--r--deps/v8/src/spaces.cc39
-rw-r--r--deps/v8/src/spaces.h26
-rw-r--r--deps/v8/src/store-buffer-inl.h8
-rw-r--r--deps/v8/src/store-buffer.cc4
-rw-r--r--deps/v8/src/stub-cache.cc1604
-rw-r--r--deps/v8/src/stub-cache.h625
-rw-r--r--deps/v8/src/token.h1
-rw-r--r--deps/v8/src/type-info.cc101
-rw-r--r--deps/v8/src/type-info.h1
-rw-r--r--deps/v8/src/utils.h23
-rw-r--r--deps/v8/src/v8.cc14
-rw-r--r--deps/v8/src/v8.h4
-rw-r--r--deps/v8/src/v8globals.h25
-rw-r--r--deps/v8/src/v8natives.js127
-rw-r--r--deps/v8/src/variables.cc1
-rw-r--r--deps/v8/src/variables.h13
-rw-r--r--deps/v8/src/version.cc2
-rw-r--r--deps/v8/src/x64/assembler-x64-inl.h16
-rw-r--r--deps/v8/src/x64/builtins-x64.cc75
-rw-r--r--deps/v8/src/x64/code-stubs-x64.cc106
-rw-r--r--deps/v8/src/x64/code-stubs-x64.h11
-rw-r--r--deps/v8/src/x64/codegen-x64.cc219
-rw-r--r--deps/v8/src/x64/deoptimizer-x64.cc16
-rw-r--r--deps/v8/src/x64/full-codegen-x64.cc175
-rw-r--r--deps/v8/src/x64/ic-x64.cc134
-rw-r--r--deps/v8/src/x64/lithium-codegen-x64.cc215
-rw-r--r--deps/v8/src/x64/lithium-codegen-x64.h15
-rw-r--r--deps/v8/src/x64/lithium-x64.cc46
-rw-r--r--deps/v8/src/x64/lithium-x64.h32
-rw-r--r--deps/v8/src/x64/macro-assembler-x64.cc88
-rw-r--r--deps/v8/src/x64/macro-assembler-x64.h25
-rw-r--r--deps/v8/src/x64/regexp-macro-assembler-x64.cc5
-rw-r--r--deps/v8/src/x64/stub-cache-x64.cc681
-rw-r--r--deps/v8/test/cctest/cctest.status3
-rw-r--r--deps/v8/test/cctest/test-api.cc72
-rw-r--r--deps/v8/test/cctest/test-debug.cc11
-rw-r--r--deps/v8/test/cctest/test-dictionary.cc69
-rw-r--r--deps/v8/test/cctest/test-heap-profiler.cc22
-rwxr-xr-xdeps/v8/test/cctest/test-parsing.cc172
-rw-r--r--deps/v8/test/cctest/test-serialize.cc3
-rw-r--r--deps/v8/test/mjsunit/apply.js7
-rw-r--r--deps/v8/test/mjsunit/array-literal-transitions.js125
-rw-r--r--deps/v8/test/mjsunit/compiler/compare.js4
-rw-r--r--deps/v8/test/mjsunit/compiler/regress-deopt-call-as-function.js62
-rw-r--r--deps/v8/test/mjsunit/compiler/regress-inline-callfunctionstub.js (renamed from deps/v8/test/mjsunit/cyclic-error-to-string.js)32
-rw-r--r--deps/v8/test/mjsunit/compiler/strict-recompile.js51
-rw-r--r--deps/v8/test/mjsunit/debug-scopes.js46
-rw-r--r--deps/v8/test/mjsunit/debug-step-3.js95
-rw-r--r--deps/v8/test/mjsunit/element-kind.js261
-rw-r--r--deps/v8/test/mjsunit/elements-kind.js309
-rw-r--r--deps/v8/test/mjsunit/elements-transition.js107
-rw-r--r--deps/v8/test/mjsunit/error-tostring.js85
-rw-r--r--deps/v8/test/mjsunit/function-bind.js197
-rw-r--r--deps/v8/test/mjsunit/harmony/block-conflicts.js5
-rw-r--r--deps/v8/test/mjsunit/harmony/block-for.js142
-rw-r--r--deps/v8/test/mjsunit/harmony/block-let-declaration.js57
-rw-r--r--deps/v8/test/mjsunit/harmony/block-let-semantics.js28
-rw-r--r--deps/v8/test/mjsunit/harmony/block-scoping.js54
-rw-r--r--deps/v8/test/mjsunit/harmony/collections.js273
-rw-r--r--deps/v8/test/mjsunit/harmony/debug-blockscopes.js109
-rw-r--r--deps/v8/test/mjsunit/harmony/proxies-for.js168
-rw-r--r--deps/v8/test/mjsunit/harmony/proxies-function.js274
-rw-r--r--deps/v8/test/mjsunit/harmony/proxies-hash.js80
-rw-r--r--deps/v8/test/mjsunit/harmony/proxies.js94
-rw-r--r--deps/v8/test/mjsunit/harmony/weakmaps.js167
-rw-r--r--deps/v8/test/mjsunit/mjsunit.status14
-rw-r--r--deps/v8/test/mjsunit/object-define-properties.js16
-rw-r--r--deps/v8/test/mjsunit/optimized-typeof.js47
-rw-r--r--deps/v8/test/mjsunit/regexp-static.js17
-rw-r--r--deps/v8/test/mjsunit/regress/regress-100409.js55
-rw-r--r--deps/v8/test/mjsunit/regress/regress-100702.js44
-rw-r--r--deps/v8/test/mjsunit/regress/regress-1229.js4
-rw-r--r--deps/v8/test/mjsunit/regress/regress-1521.js3
-rw-r--r--deps/v8/test/mjsunit/stack-traces-2.js87
-rw-r--r--deps/v8/test/mjsunit/stack-traces.js58
-rw-r--r--deps/v8/test/mjsunit/strict-mode.js6
-rw-r--r--deps/v8/test/mjsunit/to_number_order.js4
-rw-r--r--deps/v8/test/mozilla/mozilla.status11
-rw-r--r--deps/v8/test/sputnik/sputnik.status18
-rw-r--r--deps/v8/test/test262/test262.status173
-rw-r--r--deps/v8/tools/gyp/v8.gyp2
226 files changed, 14000 insertions, 7084 deletions
diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog
index a95f3cc34a..874fcba925 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 a6579ed9e1..230b1fd7a8 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 e67851cbd4..b0aeb81e2a 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" [<exn-type> [<start> [<end>]]]].
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 (<scriptfile> | -e "<source>")
// ["throws" [<exn-type> [<start> [<end>]]]]
- // 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 f3ae8078ba..be4a8f01fb 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 951209d964..02998f9b8e 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<JSFunction> 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 a03b7411c3..ac4f07fd5e 100644
--- a/deps/v8/src/api.cc
+++ b/deps/v8/src/api.cc
@@ -2794,7 +2794,7 @@ Local<Value> v8::Object::Get(uint32_t index) {
ENTER_V8(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
EXCEPTION_PREAMBLE(isolate);
- i::Handle<i::Object> result = i::GetElement(self, index);
+ i::Handle<i::Object> result = i::Object::GetElement(self, index);
has_pending_exception = result.is_null();
EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>());
return Utils::ToLocal(result);
@@ -2874,8 +2874,10 @@ Local<Array> v8::Object::GetPropertyNames() {
ENTER_V8(isolate);
i::HandleScope scope(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+ bool threw = false;
i::Handle<i::FixedArray> value =
- i::GetKeysInFixedArrayFor(self, i::INCLUDE_PROTOS);
+ i::GetKeysInFixedArrayFor(self, i::INCLUDE_PROTOS, &threw);
+ if (threw) return Local<v8::Array>();
// 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<Array> v8::Object::GetOwnPropertyNames() {
ENTER_V8(isolate);
i::HandleScope scope(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+ bool threw = false;
i::Handle<i::FixedArray> value =
- i::GetKeysInFixedArrayFor(self, i::LOCAL_ONLY);
+ i::GetKeysInFixedArrayFor(self, i::LOCAL_ONLY, &threw);
+ if (threw) return Local<v8::Array>();
// 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<Value> GetPropertyByLookup(i::Isolate* isolate,
// If the property being looked up is a callback, it can throw
// an exception.
EXCEPTION_PREAMBLE(isolate);
- i::Handle<i::Object> result = i::GetProperty(receiver, name, lookup);
+ PropertyAttributes ignored;
+ i::Handle<i::Object> result =
+ i::Object::GetProperty(receiver, receiver, lookup, name,
+ &ignored);
has_pending_exception = result.is_null();
EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>());
@@ -3110,7 +3117,7 @@ Local<Value> v8::Object::GetRealNamedPropertyInPrototypeChain(
ENTER_V8(isolate);
i::Handle<i::JSObject> self_obj = Utils::OpenHandle(this);
i::Handle<i::String> 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<Value> v8::Object::GetRealNamedProperty(Handle<String> key) {
ENTER_V8(isolate);
i::Handle<i::JSObject> self_obj = Utils::OpenHandle(this);
i::Handle<i::String> 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<i::String> 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<Context> v8::Context::New(
}
// Leave V8.
- if (env.is_null())
+ if (env.is_null()) {
return Persistent<Context>();
+ }
return Persistent<Context>(Utils::ToLocal(env));
}
diff --git a/deps/v8/src/arm/assembler-arm-inl.h b/deps/v8/src/arm/assembler-arm-inl.h
index 93cecf52b6..7f9f4cebe2 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<Address>(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 d19b64da54..247479d730 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 32b7896a52..29bf19028c 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, &not_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(&not_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, &not_empty_array);
+ __ Drop(1); // Adjust stack.
+ __ mov(r0, Operand(0)); // Treat this as a call with argc of zero.
+ __ b(&empty_array);
+
+ __ bind(&not_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 44923a1843..412ba00fc8 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<String> 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<String>(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<String>(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 3ba75bab13..647fc8d154 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<String> 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 3993ed02be..508d830bdf 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 1c0d508d2d..f54231c929 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 bb03d740d1..8505c7dfc1 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<uint32_t>(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<uint32_t>(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 353ce5b106..497a295464 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<SharedFunctionInfo> 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<Expression*>* subexprs = expr->values();
int length = subexprs->length();
+ Handle<FixedArray> constant_elements = expr->constant_elements();
+ ASSERT_EQ(2, constant_elements->length());
+ ElementsKind constant_elements_kind =
+ static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
+ Handle<FixedArrayBase> 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<Expression*>* 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<Expression*>* 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 6e0badca1d..18d4a9fa8b 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 84959397b6..51978421d8 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 73c7e459c3..5733bd08da 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<Object> 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<Map> 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<Object> 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<Map> original_map() { return hydrogen()->original_map(); }
+ Handle<Map> 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 70ef884816..4cf7df4c78 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<Object> 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<Map> type,
Handle<String> 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<Map> from_map = instr->original_map();
+ Handle<Map> 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, &not_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(&not_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<FixedArray> constant_elements = instr->hydrogen()->constant_elements();
+ ASSERT_EQ(2, constant_elements->length());
+ ElementsKind constant_elements_kind =
+ static_cast<ElementsKind>(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<SharedFunctionInfo> 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 711e4595e7..b01e4967d7 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<JSFunction> 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<String> type_name);
+ Condition EmitTypeofIs(Label* true_label,
+ Label* false_label,
+ Register input,
+ Handle<String> 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 918f9ebe06..cf4258c83a 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<JSFunction>(function)));
ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
- // Invoke the cached code.
- Handle<Code> 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 8ee468a917..90c4b37549 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 c876467938..b212f9f6e6 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<const String*>(re_frame, kInputString) = *subject;
frame_entry<const byte*>(re_frame, kInputStart) = new_address;
frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length;
+ } else if (frame_entry<const String*>(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<const String*>(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 5704202622..542cc302d3 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<uintptr_t>(stack_) + 256;
+ return reinterpret_cast<uintptr_t>(stack_) + 512;
}
diff --git a/deps/v8/src/arm/stub-cache-arm.cc b/deps/v8/src/arm/stub-cache-arm.cc
index 4558afe68a..f9a10c4f25 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<String> 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<JSObject> 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<JSObject> object,
int index,
- Map* transition,
+ Handle<Map> 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<Map>(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<Map>(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<Code> ic(code);
- __ Jump(ic, RelocInfo::CODE_TARGET);
+ Handle<Code> 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> 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<GlobalObject> global,
+ Handle<String> name,
+ Register scratch,
+ Label* miss) {
+ Handle<JSGlobalPropertyCell> 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<JSObject> object,
+ Handle<JSObject> holder,
+ Handle<String> name,
+ Register scratch,
+ Label* miss) {
+ Handle<JSObject> current = object;
+ while (!current.is_identical_to(holder)) {
+ if (current->IsGlobalObject()) {
+ GenerateCheckPropertyCell(masm,
+ Handle<GlobalObject>::cast(current),
+ name,
+ scratch,
+ miss);
+ }
+ current = Handle<JSObject>(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<JSObject> object,
+ Register object_reg,
+ Handle<JSObject> holder,
+ Register holder_reg,
+ Register scratch1,
+ Register scratch2,
+ Handle<String> 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<JSObject> 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<JSObject> 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<Map> 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<Map>(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<JSObject> object,
+ Handle<JSObject> holder,
Register receiver,
Register scratch1,
Register scratch2,
Register scratch3,
int index,
- String* name,
+ Handle<String> 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<JSObject> object,
+ Handle<JSObject> holder,
Register receiver,
Register scratch1,
Register scratch2,
Register scratch3,
- Object* value,
- String* name,
+ Handle<Object> value,
+ Handle<String> 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<Object>(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<JSObject>(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<String> name, Label* miss) {
if (kind_ == Code::KEYED_CALL_IC) {
- __ cmp(r2, Operand(Handle<String>(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> 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>(Code::cast(obj)), RelocInfo::CODE_TARGET);
@@ -1490,10 +1703,10 @@ MaybeObject* CallStubCompiler::GenerateMissBranch() {
}
-MaybeObject* CallStubCompiler::CompileCallField(JSObject* object,
- JSObject* holder,
+Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
+ Handle<JSObject> holder,
int index,
- String* name) {
+ Handle<String> 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<String>(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<String>(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<String>(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<String>(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<String>(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<String>(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<String>(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<String>(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<String>(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<String>(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<String>(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<String>(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>(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<String>(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> 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<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
int index,
- Map* transition,
- String* name) {
+ Handle<Map> transition,
+ Handle<String> 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<Code> 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<Code> StoreStubCompiler::CompileStoreCallback(
+ Handle<JSObject> object,
+ Handle<AccessorInfo> callback,
+ Handle<String> 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<AccessorInfo>(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<Code> StoreStubCompiler::CompileStoreInterceptor(
+ Handle<JSObject> receiver,
+ Handle<String> 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<Code> StoreStubCompiler::CompileStoreGlobal(
+ Handle<GlobalObject> object,
+ Handle<JSGlobalPropertyCell> cell,
+ Handle<String> 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<JSGlobalPropertyCell>(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<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
+ Handle<JSObject> object,
+ Handle<JSObject> 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<GlobalObject>::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<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
+ Handle<JSObject> holder,
int index,
- String* name) {
+ Handle<String> 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<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object,
+ Handle<JSObject> holder,
+ Handle<Object> value,
+ Handle<String> 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<Code> LoadStubCompiler::CompileLoadGlobal(
+ Handle<JSObject> object,
+ Handle<GlobalObject> holder,
+ Handle<JSGlobalPropertyCell> cell,
+ Handle<String> 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<JSGlobalPropertyCell>(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<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> 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<String>(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<Code> KeyedLoadStubCompiler::CompileLoadConstant(
+ Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> holder,
+ Handle<Object> 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<String>(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<String>(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<Code> KeyedLoadStubCompiler::CompileLoadArrayLength(
+ Handle<String> 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<String>(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<Code> KeyedLoadStubCompiler::CompileLoadStringLength(
+ Handle<String> 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<String>(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<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype(
+ Handle<String> 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<String>(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<Code> KeyedLoadStubCompiler::CompileLoadElement(
+ Handle<Map> 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<Map>(receiver_map),
- Handle<Code>(stub),
- DO_SMI_CHECK);
+ Handle<Code> stub = KeyedLoadElementStub(elements_kind).GetCode();
+
+ __ DispatchMap(r1, r2, receiver_map, stub, DO_SMI_CHECK);
Handle<Code> 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<Code> 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> map(receiver_maps->at(current));
- Handle<Code> 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<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
int index,
- Map* transition,
- String* name) {
+ Handle<Map> transition,
+ Handle<String> 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<String>(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<Code> KeyedStoreStubCompiler::CompileStoreElement(
+ Handle<Map> 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<Map>(receiver_map),
- Handle<Code>(stub),
- DO_SMI_CHECK);
+ Handle<Code> stub =
+ KeyedStoreElementStub(is_js_array, elements_kind).GetCode();
+
+ __ DispatchMap(r2, r3, receiver_map, stub, DO_SMI_CHECK);
Handle<Code> 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<Code> 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> map(receiver_maps->at(i));
- Handle<Code> 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<Map>(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 e1d7c2064e..214065c7bf 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 bda85e69de..4dc2394b06 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 e5661c9f12..5b71363759 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<Object> 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<JSGlobalPropertyCell> 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 731ad2ff3f..f8b460d324 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 d493814544..9e34bc0e81 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<String> 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<Map> type, Handle<String> name) {
holder_ = Handle<JSObject>::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 0efc4835c4..3de00ef5d3 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<String> 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<String> name_;
Variable* var_; // resolved variable, or NULL
bool is_this_;
- bool inside_with_;
bool is_trivial_;
int position_;
VariableProxy(Isolate* isolate,
Handle<String> 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<FixedArray> 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<Statement*>* 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 dc722cb749..6735ff4549 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<JSFunction> InstallFunction(Handle<JSObject> target,
if (is_ecma_native) {
function->shared()->set_instance_class_name(*symbol);
}
+ function->shared()->set_native(true);
return function;
}
@@ -375,26 +377,28 @@ Handle<DescriptorArray> Genesis::ComputeFunctionInstanceDescriptor(
PropertyAttributes attributes =
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
+ DescriptorArray::WhitenessWitness witness(*descriptors);
+
{ // Add length.
Handle<Foreign> 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> 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> 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> 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<DescriptorArray> Genesis::ComputeFunctionInstanceDescriptor(
Handle<Foreign> 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<DescriptorArray> Genesis::ComputeStrictFunctionInstanceDescriptor(
? 4
: 5);
PropertyAttributes attributes = static_cast<PropertyAttributes>(
- DONT_ENUM | DONT_DELETE | READ_ONLY);
+ DONT_ENUM | DONT_DELETE);
+
+ DescriptorArray::WhitenessWitness witness(*descriptors);
{ // length
Handle<Foreign> foreign = factory()->NewForeign(&Accessors::FunctionLength);
CallbacksDescriptor d(*factory()->length_symbol(), *foreign, attributes);
- descriptors->Set(0, &d);
+ descriptors->Set(0, &d, witness);
}
{ // name
Handle<Foreign> 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<PropertyAttributes>(attributes & ~READ_ONLY);
+ if (prototypeMode != ADD_WRITEABLE_PROTOTYPE) {
+ attributes = static_cast<PropertyAttributes>(attributes | READ_ONLY);
}
Handle<Foreign> 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<GlobalObject> inner_global,
ASSERT_EQ(0, initial_map->inobject_properties());
Handle<DescriptorArray> descriptors = factory->NewDescriptorArray(5);
+ DescriptorArray::WhitenessWitness witness(*descriptors);
PropertyAttributes final =
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
int enum_index = 0;
@@ -950,7 +957,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> 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<GlobalObject> 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<GlobalObject> 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<GlobalObject> 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<GlobalObject> 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<GlobalObject> 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<GlobalObject> inner_global,
}
{ // --- aliased_arguments_boilerplate_
- Handle<Map> old_map(global_context()->arguments_boilerplate()->map());
- Handle<Map> new_map = factory->CopyMapDropTransitions(old_map);
- new_map->set_pre_allocated_property_fields(2);
- Handle<JSObject> 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<FixedArray> elements = factory->NewFixedArray(2);
elements->set_map(heap->non_strict_arguments_elements_map());
@@ -1097,12 +1099,16 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
elements->set(0, *array);
array = factory->NewFixedArray(0);
elements->set(1, *array);
- Handle<Map> non_strict_arguments_elements_map =
- factory->GetElementsTransitionMap(result,
- NON_STRICT_ARGUMENTS_ELEMENTS);
- result->set_map(*non_strict_arguments_elements_map);
- ASSERT(result->HasNonStrictArgumentsElements());
+
+ Handle<Map> old_map(global_context()->arguments_boilerplate()->map());
+ Handle<Map> new_map = factory->CopyMapDropTransitions(old_map);
+ new_map->set_pre_allocated_property_fields(2);
+ Handle<JSObject> 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<GlobalObject> inner_global,
// Create the descriptor array for the arguments object.
Handle<DescriptorArray> 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> map = factory->NewMap(JS_OBJECT_TYPE,
@@ -1162,7 +1169,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> 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<GlobalObject> inner_global,
// Initialize the data slot.
global_context()->set_data(heap->undefined_value());
+
+ {
+ // Initialize the random seed slot.
+ Handle<ByteArray> 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<JSObject> global = Handle<JSObject>(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<JSObject> 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<JSObject> prototype =
+ factory()->NewJSObject(isolate()->object_function(), TENURED);
+ InstallFunction(global, "Set", JS_SET_TYPE, JSSet::kSize,
+ prototype, Builtins::kIllegal, true);
+ }
+ { // -- M a p
+ Handle<JSObject> 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<JSObject> 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<DescriptorArray> 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<JSBuiltinsObject> builtins) {
builtins->set_javascript_builtin(id, *function);
Handle<SharedFunctionInfo> shared
= Handle<SharedFunctionInfo>(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<JSObject> 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<JSObject> 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 d513200f0b..e758b9a415 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 31090d3a08..24059e7728 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 2f359f6cd8..832f778b25 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 <int> 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 4bc2603c53..b4374360c6 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 acfbd469f0..fc7000bb03 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<ElementsKind, 0, 8> {};
+ class ToBits: public BitField<ElementsKind, 8, 8> {};
+ class IsJSArrayBits: public BitField<bool, 16, 8> {};
+ class StrictModeBits: public BitField<StrictModeFlag, 24, 8> {};
+
+ 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 e551abfb11..5360d3ef3c 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
index 5fb5151071..4e45885b96 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 4979a7f866..88db467c35 100644
--- a/deps/v8/src/compiler.cc
+++ b/deps/v8/src/compiler.cc
@@ -59,7 +59,6 @@ CompilationInfo::CompilationInfo(Handle<Script> script)
script_(script),
extension_(NULL),
pre_parse_data_(NULL),
- supports_deoptimization_(false),
osr_ast_id_(AstNode::kNoNumber) {
Initialize(NONOPT);
}
@@ -74,7 +73,6 @@ CompilationInfo::CompilationInfo(Handle<SharedFunctionInfo> shared_info)
script_(Handle<Script>(Script::cast(shared_info->script()))),
extension_(NULL),
pre_parse_data_(NULL),
- supports_deoptimization_(false),
osr_ast_id_(AstNode::kNoNumber) {
Initialize(BASE);
}
@@ -90,7 +88,6 @@ CompilationInfo::CompilationInfo(Handle<JSFunction> closure)
script_(Handle<Script>(Script::cast(shared_info_->script()))),
extension_(NULL),
pre_parse_data_(NULL),
- supports_deoptimization_(false),
osr_ast_id_(AstNode::kNoNumber) {
Initialize(BASE);
}
@@ -309,9 +306,9 @@ static bool MakeCrankshaftCode(CompilationInfo* info) {
static bool GenerateCode(CompilationInfo* info) {
- return V8::UseCrankshaft() ?
- MakeCrankshaftCode(info) :
- FullCodeGenerator::MakeCode(info);
+ return info->IsCompilingForDebugging() || !V8::UseCrankshaft() ?
+ FullCodeGenerator::MakeCode(info) :
+ MakeCrankshaftCode(info);
}
@@ -480,20 +477,22 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
// that would be compiled lazily anyway, so we skip the preparse step
// in that case too.
ScriptDataImpl* pre_data = input_pre_data;
- bool harmony_scoping = natives != NATIVES_CODE && FLAG_harmony_scoping;
+ int flags = kNoParsingFlags;
+ if ((natives == NATIVES_CODE) || FLAG_allow_natives_syntax) {
+ flags |= kAllowNativesSyntax;
+ }
+ if (natives != NATIVES_CODE && FLAG_harmony_scoping) {
+ flags |= kHarmonyScoping;
+ }
if (pre_data == NULL
&& source_length >= FLAG_min_preparse_length) {
if (source->IsExternalTwoByteString()) {
ExternalTwoByteStringUC16CharacterStream stream(
Handle<ExternalTwoByteString>::cast(source), 0, source->length());
- pre_data = ParserApi::PartialPreParse(&stream,
- extension,
- harmony_scoping);
+ pre_data = ParserApi::PartialPreParse(&stream, extension, flags);
} else {
GenericStringUC16CharacterStream stream(source, 0, source->length());
- pre_data = ParserApi::PartialPreParse(&stream,
- extension,
- harmony_scoping);
+ pre_data = ParserApi::PartialPreParse(&stream, extension, flags);
}
}
@@ -516,9 +515,6 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
info.MarkAsGlobal();
info.SetExtension(extension);
info.SetPreParseData(pre_data);
- if (natives == NATIVES_CODE) {
- info.MarkAsAllowingNativesSyntax();
- }
result = MakeFunctionInfo(&info);
if (extension == NULL && !result.is_null()) {
compilation_cache->PutScript(source, result);
@@ -562,7 +558,7 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
CompilationInfo info(script);
info.MarkAsEval();
if (is_global) info.MarkAsGlobal();
- if (strict_mode == kStrictMode) info.MarkAsStrictMode();
+ info.SetStrictModeFlag(strict_mode);
info.SetCallingContext(context);
result = MakeFunctionInfo(&info);
if (!result.is_null()) {
@@ -570,6 +566,7 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
// If caller is strict mode, the result must be strict as well,
// but not the other way around. Consider:
// eval("'use strict'; ...");
+ // TODO(keuchel): adapt this for extended mode.
ASSERT(strict_mode == kNonStrictMode || result->strict_mode());
compilation_cache->PutEval(source, context, is_global, result);
}
@@ -601,10 +598,13 @@ bool Compiler::CompileLazy(CompilationInfo* info) {
HistogramTimerScope timer(isolate->counters()->compile_lazy());
// After parsing we know function's strict mode. Remember it.
- if (info->function()->strict_mode()) {
- shared->set_strict_mode(true);
- info->MarkAsStrictMode();
- }
+ StrictModeFlag strict_mode = info->function()->strict_mode_flag();
+ ASSERT(info->strict_mode_flag() == kNonStrictMode ||
+ info->strict_mode_flag() == strict_mode);
+ ASSERT(shared->strict_mode_flag() == kNonStrictMode ||
+ shared->strict_mode_flag() == strict_mode);
+ info->SetStrictModeFlag(strict_mode);
+ shared->set_strict_mode_flag(strict_mode);
// Compile the code.
if (!MakeCode(info)) {
@@ -684,7 +684,7 @@ Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal,
CompilationInfo info(script);
info.SetFunction(literal);
info.SetScope(literal->scope());
- if (literal->scope()->is_strict_mode()) info.MarkAsStrictMode();
+ info.SetStrictModeFlag(literal->scope()->strict_mode_flag());
LiveEditFunctionTracker live_edit_tracker(info.isolate(), literal);
// Determine if the function can be lazily compiled. This is necessary to
@@ -750,7 +750,7 @@ void Compiler::SetFunctionInfo(Handle<SharedFunctionInfo> function_info,
lit->has_only_simple_this_property_assignments(),
*lit->this_property_assignments());
function_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
- function_info->set_strict_mode(lit->strict_mode());
+ function_info->set_strict_mode_flag(lit->strict_mode_flag());
function_info->set_uses_arguments(lit->scope()->arguments() != NULL);
function_info->set_has_duplicate_parameters(lit->has_duplicate_parameters());
}
diff --git a/deps/v8/src/compiler.h b/deps/v8/src/compiler.h
index 09aa23dec9..bedf5eebb9 100644
--- a/deps/v8/src/compiler.h
+++ b/deps/v8/src/compiler.h
@@ -52,7 +52,10 @@ class CompilationInfo BASE_EMBEDDED {
bool is_lazy() const { return IsLazy::decode(flags_); }
bool is_eval() const { return IsEval::decode(flags_); }
bool is_global() const { return IsGlobal::decode(flags_); }
- bool is_strict_mode() const { return IsStrictMode::decode(flags_); }
+ bool is_strict_mode() const { return strict_mode_flag() == kStrictMode; }
+ StrictModeFlag strict_mode_flag() const {
+ return StrictModeFlagField::decode(flags_);
+ }
bool is_in_loop() const { return IsInLoop::decode(flags_); }
FunctionLiteral* function() const { return function_; }
Scope* scope() const { return scope_; }
@@ -73,22 +76,15 @@ class CompilationInfo BASE_EMBEDDED {
ASSERT(!is_lazy());
flags_ |= IsGlobal::encode(true);
}
- void MarkAsStrictMode() {
- flags_ |= IsStrictMode::encode(true);
- }
- StrictModeFlag StrictMode() {
- return is_strict_mode() ? kStrictMode : kNonStrictMode;
+ void SetStrictModeFlag(StrictModeFlag strict_mode_flag) {
+ ASSERT(StrictModeFlagField::decode(flags_) == kNonStrictMode ||
+ StrictModeFlagField::decode(flags_) == strict_mode_flag);
+ flags_ = StrictModeFlagField::update(flags_, strict_mode_flag);
}
void MarkAsInLoop() {
ASSERT(is_lazy());
flags_ |= IsInLoop::encode(true);
}
- void MarkAsAllowingNativesSyntax() {
- flags_ |= IsNativesSyntaxAllowed::encode(true);
- }
- bool allows_natives_syntax() const {
- return IsNativesSyntaxAllowed::decode(flags_);
- }
void MarkAsNative() {
flags_ |= IsNative::encode(true);
}
@@ -120,6 +116,19 @@ class CompilationInfo BASE_EMBEDDED {
ASSERT(IsOptimizing());
osr_ast_id_ = osr_ast_id;
}
+ void MarkCompilingForDebugging(Handle<Code> current_code) {
+ ASSERT(mode_ != OPTIMIZE);
+ ASSERT(current_code->kind() == Code::FUNCTION);
+ flags_ |= IsCompilingForDebugging::encode(true);
+ if (current_code->is_compiled_optimizable()) {
+ EnableDeoptimizationSupport();
+ } else {
+ mode_ = CompilationInfo::NONOPT;
+ }
+ }
+ bool IsCompilingForDebugging() {
+ return IsCompilingForDebugging::decode(flags_);
+ }
bool has_global_object() const {
return !closure().is_null() && (closure()->context()->global() != NULL);
@@ -139,10 +148,12 @@ class CompilationInfo BASE_EMBEDDED {
void DisableOptimization();
// Deoptimization support.
- bool HasDeoptimizationSupport() const { return supports_deoptimization_; }
+ bool HasDeoptimizationSupport() const {
+ return SupportsDeoptimization::decode(flags_);
+ }
void EnableDeoptimizationSupport() {
ASSERT(IsOptimizable());
- supports_deoptimization_ = true;
+ flags_ |= SupportsDeoptimization::encode(true);
}
// Determine whether or not we can adaptively optimize.
@@ -177,8 +188,9 @@ class CompilationInfo BASE_EMBEDDED {
if (script_->type()->value() == Script::TYPE_NATIVE) {
MarkAsNative();
}
- if (!shared_info_.is_null() && shared_info_->strict_mode()) {
- MarkAsStrictMode();
+ if (!shared_info_.is_null()) {
+ ASSERT(strict_mode_flag() == kNonStrictMode);
+ SetStrictModeFlag(shared_info_->strict_mode_flag());
}
}
@@ -198,11 +210,14 @@ class CompilationInfo BASE_EMBEDDED {
// Flags that can be set for lazy compilation.
class IsInLoop: public BitField<bool, 3, 1> {};
// Strict mode - used in eager compilation.
- class IsStrictMode: public BitField<bool, 4, 1> {};
- // Native syntax (%-stuff) allowed?
- class IsNativesSyntaxAllowed: public BitField<bool, 5, 1> {};
+ class StrictModeFlagField: public BitField<StrictModeFlag, 4, 1> {};
// Is this a function from our natives.
class IsNative: public BitField<bool, 6, 1> {};
+ // Is this code being compiled with support for deoptimization..
+ class SupportsDeoptimization: public BitField<bool, 7, 1> {};
+ // If compiling for debugging produce just full code matching the
+ // initial mode setting.
+ class IsCompilingForDebugging: public BitField<bool, 8, 1> {};
unsigned flags_;
@@ -231,7 +246,6 @@ class CompilationInfo BASE_EMBEDDED {
// Compilation mode flag and whether deoptimization is allowed.
Mode mode_;
- bool supports_deoptimization_;
int osr_ast_id_;
DISALLOW_COPY_AND_ASSIGN(CompilationInfo);
diff --git a/deps/v8/src/contexts.cc b/deps/v8/src/contexts.cc
index 0cda430492..b25ffac931 100644
--- a/deps/v8/src/contexts.cc
+++ b/deps/v8/src/contexts.cc
@@ -174,6 +174,10 @@ Handle<Object> Context::Lookup(Handle<String> name,
*attributes = READ_ONLY;
*binding_flags = IMMUTABLE_CHECK_INITIALIZED;
break;
+ case CONST_HARMONY:
+ *attributes = READ_ONLY;
+ *binding_flags = IMMUTABLE_CHECK_INITIALIZED_HARMONY;
+ break;
case DYNAMIC:
case DYNAMIC_GLOBAL:
case DYNAMIC_LOCAL:
@@ -187,7 +191,8 @@ Handle<Object> Context::Lookup(Handle<String> name,
// Check the slot corresponding to the intermediate context holding
// only the function name variable.
if (follow_context_chain && context->IsFunctionContext()) {
- int function_index = scope_info->FunctionContextSlotIndex(*name);
+ VariableMode mode;
+ int function_index = scope_info->FunctionContextSlotIndex(*name, &mode);
if (function_index >= 0) {
if (FLAG_trace_contexts) {
PrintF("=> found intermediate function in context slot %d\n",
@@ -195,7 +200,9 @@ Handle<Object> Context::Lookup(Handle<String> name,
}
*index = function_index;
*attributes = READ_ONLY;
- *binding_flags = IMMUTABLE_IS_INITIALIZED;
+ ASSERT(mode == CONST || mode == CONST_HARMONY);
+ *binding_flags = (mode == CONST)
+ ? IMMUTABLE_IS_INITIALIZED : IMMUTABLE_IS_INITIALIZED_HARMONY;
return context;
}
}
@@ -255,7 +262,7 @@ bool Context::GlobalIfNotShadowedByEval(Handle<String> name) {
if (param_index >= 0) return false;
// Check context only holding the function name variable.
- index = scope_info->FunctionContextSlotIndex(*name);
+ index = scope_info->FunctionContextSlotIndex(*name, NULL);
if (index >= 0) return false;
context = context->previous();
}
@@ -266,8 +273,7 @@ bool Context::GlobalIfNotShadowedByEval(Handle<String> name) {
}
-void Context::ComputeEvalScopeInfo(bool* outer_scope_calls_eval,
- bool* outer_scope_calls_non_strict_eval) {
+void Context::ComputeEvalScopeInfo(bool* outer_scope_calls_non_strict_eval) {
// Skip up the context chain checking all the function contexts to see
// whether they call eval.
Context* context = this;
@@ -275,14 +281,11 @@ void Context::ComputeEvalScopeInfo(bool* outer_scope_calls_eval,
if (context->IsFunctionContext()) {
Handle<SerializedScopeInfo> scope_info(
context->closure()->shared()->scope_info());
- if (scope_info->CallsEval()) {
- *outer_scope_calls_eval = true;
- if (!scope_info->IsStrictMode()) {
- // No need to go further since the answers will not change from
- // here.
- *outer_scope_calls_non_strict_eval = true;
- return;
- }
+ if (scope_info->CallsEval() && !scope_info->IsStrictMode()) {
+ // No need to go further since the answers will not change from
+ // here.
+ *outer_scope_calls_non_strict_eval = true;
+ return;
}
}
context = context->previous();
diff --git a/deps/v8/src/contexts.h b/deps/v8/src/contexts.h
index b80475f0f7..7021ff8fbf 100644
--- a/deps/v8/src/contexts.h
+++ b/deps/v8/src/contexts.h
@@ -46,24 +46,43 @@ enum ContextLookupFlags {
// ES5 10.2 defines lexical environments with mutable and immutable bindings.
// Immutable bindings have two states, initialized and uninitialized, and
-// their state is changed by the InitializeImmutableBinding method.
+// their state is changed by the InitializeImmutableBinding method. The
+// BindingFlags enum represents information if a binding has definitely been
+// initialized. A mutable binding does not need to be checked and thus has
+// the BindingFlag MUTABLE_IS_INITIALIZED.
+//
+// There are two possibilities for immutable bindings
+// * 'const' declared variables. They are initialized when evaluating the
+// corresponding declaration statement. They need to be checked for being
+// initialized and thus get the flag IMMUTABLE_CHECK_INITIALIZED.
+// * The function name of a named function literal. The binding is immediately
+// initialized when entering the function and thus does not need to be
+// checked. it gets the BindingFlag IMMUTABLE_IS_INITIALIZED.
+// Accessing an uninitialized binding produces the undefined value.
//
// The harmony proposal for block scoped bindings also introduces the
-// uninitialized state for mutable bindings. A 'let' declared variable
-// is a mutable binding that is created uninitalized upon activation of its
-// lexical environment and it is initialized when evaluating its declaration
-// statement. Var declared variables are mutable bindings that are
-// immediately initialized upon creation. The BindingFlags enum represents
-// information if a binding has definitely been initialized. 'const' declared
-// variables are created as uninitialized immutable bindings.
-
-// In harmony mode accessing an uninitialized binding produces a reference
-// error.
+// uninitialized state for mutable bindings.
+// * A 'let' declared variable. They are initialized when evaluating the
+// corresponding declaration statement. They need to be checked for being
+// initialized and thus get the flag MUTABLE_CHECK_INITIALIZED.
+// * A 'var' declared variable. It is initialized immediately upon creation
+// and thus doesn't need to be checked. It gets the flag
+// MUTABLE_IS_INITIALIZED.
+// * Catch bound variables, function parameters and variables introduced by
+// function declarations are initialized immediately and do not need to be
+// checked. Thus they get the flag MUTABLE_IS_INITIALIZED.
+// Immutable bindings in harmony mode get the _HARMONY flag variants. Accessing
+// an uninitialized binding produces a reference error.
+//
+// In V8 uninitialized bindings are set to the hole value upon creation and set
+// to a different value upon initialization.
enum BindingFlags {
MUTABLE_IS_INITIALIZED,
MUTABLE_CHECK_INITIALIZED,
IMMUTABLE_IS_INITIALIZED,
IMMUTABLE_CHECK_INITIALIZED,
+ IMMUTABLE_IS_INITIALIZED_HARMONY,
+ IMMUTABLE_CHECK_INITIALIZED_HARMONY,
MISSING_BINDING
};
@@ -138,7 +157,9 @@ enum BindingFlags {
to_complete_property_descriptor) \
V(DERIVED_HAS_TRAP_INDEX, JSFunction, derived_has_trap) \
V(DERIVED_GET_TRAP_INDEX, JSFunction, derived_get_trap) \
- V(DERIVED_SET_TRAP_INDEX, JSFunction, derived_set_trap)
+ V(DERIVED_SET_TRAP_INDEX, JSFunction, derived_set_trap) \
+ V(PROXY_ENUMERATE, JSFunction, proxy_enumerate) \
+ V(RANDOM_SEED_INDEX, ByteArray, random_seed)
// JSFunctions are pairs (context, function code), sometimes also called
// closures. A Context object is used to represent function contexts and
@@ -194,7 +215,8 @@ class Context: public FixedArray {
PREVIOUS_INDEX,
// The extension slot is used for either the global object (in global
// contexts), eval extension object (function contexts), subject of with
- // (with contexts), or the variable name (catch contexts).
+ // (with contexts), or the variable name (catch contexts), the serialized
+ // scope info (block contexts).
EXTENSION_INDEX,
GLOBAL_INDEX,
MIN_CONTEXT_SLOTS,
@@ -258,6 +280,8 @@ class Context: public FixedArray {
DERIVED_HAS_TRAP_INDEX,
DERIVED_GET_TRAP_INDEX,
DERIVED_SET_TRAP_INDEX,
+ PROXY_ENUMERATE,
+ RANDOM_SEED_INDEX,
// Properties from here are treated as weak references by the full GC.
// Scavenge treats them as strong references.
@@ -385,8 +409,7 @@ class Context: public FixedArray {
// Determine if any function scope in the context call eval and if
// any of those calls are in non-strict mode.
- void ComputeEvalScopeInfo(bool* outer_scope_calls_eval,
- bool* outer_scope_calls_non_strict_eval);
+ void ComputeEvalScopeInfo(bool* outer_scope_calls_non_strict_eval);
// Code generation support.
static int SlotOffset(int index) {
diff --git a/deps/v8/src/d8.cc b/deps/v8/src/d8.cc
index a516576faf..64ada2c245 100644
--- a/deps/v8/src/d8.cc
+++ b/deps/v8/src/d8.cc
@@ -178,7 +178,8 @@ bool Shell::ExecuteString(Handle<String> source,
// If all went well and the result wasn't undefined then print
// the returned value.
v8::String::Utf8Value str(result);
- fwrite(*str, sizeof(**str), str.length(), stdout);
+ size_t count = fwrite(*str, sizeof(**str), str.length(), stdout);
+ (void) count; // Silence GCC-4.5.x "unused result" warning.
printf("\n");
}
return true;
diff --git a/deps/v8/src/debug.cc b/deps/v8/src/debug.cc
index 3d79485b57..dc9f2974f7 100644
--- a/deps/v8/src/debug.cc
+++ b/deps/v8/src/debug.cc
@@ -87,19 +87,13 @@ static void PrintLn(v8::Local<v8::Value> value) {
static Handle<Code> ComputeCallDebugBreak(int argc, Code::Kind kind) {
Isolate* isolate = Isolate::Current();
- CALL_HEAP_FUNCTION(
- isolate,
- isolate->stub_cache()->ComputeCallDebugBreak(argc, kind),
- Code);
+ return isolate->stub_cache()->ComputeCallDebugBreak(argc, kind);
}
static Handle<Code> ComputeCallDebugPrepareStepIn(int argc, Code::Kind kind) {
Isolate* isolate = Isolate::Current();
- CALL_HEAP_FUNCTION(
- isolate,
- isolate->stub_cache()->ComputeCallDebugPrepareStepIn(argc, kind),
- Code);
+ return isolate->stub_cache()->ComputeCallDebugPrepareStepIn(argc, kind);
}
@@ -1727,50 +1721,203 @@ void Debug::ClearStepNext() {
}
+// Helper function to compile full code for debugging. This code will
+// have debug break slots and deoptimization
+// information. Deoptimization information is required in case that an
+// optimized version of this function is still activated on the
+// stack. It will also make sure that the full code is compiled with
+// the same flags as the previous version - that is flags which can
+// change the code generated. The current method of mapping from
+// already compiled full code without debug break slots to full code
+// with debug break slots depends on the generated code is otherwise
+// exactly the same.
+static bool CompileFullCodeForDebugging(Handle<SharedFunctionInfo> shared,
+ Handle<Code> current_code) {
+ ASSERT(!current_code->has_debug_break_slots());
+
+ CompilationInfo info(shared);
+ info.MarkCompilingForDebugging(current_code);
+ ASSERT(!info.shared_info()->is_compiled());
+ ASSERT(!info.isolate()->has_pending_exception());
+
+ // Use compile lazy which will end up compiling the full code in the
+ // configuration configured above.
+ bool result = Compiler::CompileLazy(&info);
+ ASSERT(result != Isolate::Current()->has_pending_exception());
+ info.isolate()->clear_pending_exception();
+#if DEBUG
+ if (result) {
+ Handle<Code> new_code(shared->code());
+ ASSERT(new_code->has_debug_break_slots());
+ ASSERT(current_code->is_compiled_optimizable() ==
+ new_code->is_compiled_optimizable());
+ ASSERT(current_code->instruction_size() <= new_code->instruction_size());
+ }
+#endif
+ return result;
+}
+
+
void Debug::PrepareForBreakPoints() {
// If preparing for the first break point make sure to deoptimize all
// functions as debugging does not work with optimized code.
if (!has_break_points_) {
Deoptimizer::DeoptimizeAll();
- // We are going to iterate heap to find all functions without
- // debug break slots.
- isolate_->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
-
- AssertNoAllocation no_allocation;
- Builtins* builtins = isolate_->builtins();
- Code* lazy_compile = builtins->builtin(Builtins::kLazyCompile);
-
- // Find all non-optimized code functions with activation frames on
- // the stack.
- List<JSFunction*> active_functions(100);
- for (JavaScriptFrameIterator it(isolate_); !it.done(); it.Advance()) {
- JavaScriptFrame* frame = it.frame();
- if (frame->function()->IsJSFunction()) {
- JSFunction* function = JSFunction::cast(frame->function());
- if (function->code()->kind() == Code::FUNCTION)
- active_functions.Add(function);
+ Handle<Code> lazy_compile =
+ Handle<Code>(isolate_->builtins()->builtin(Builtins::kLazyCompile));
+
+ // Keep the list of activated functions in a handlified list as it
+ // is used both in GC and non-GC code.
+ List<Handle<JSFunction> > active_functions(100);
+
+ {
+ // We are going to iterate heap to find all functions without
+ // debug break slots.
+ isolate_->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
+
+ // Ensure no GC in this scope as we are comparing raw pointer
+ // values and performing a heap iteration.
+ AssertNoAllocation no_allocation;
+
+ // Find all non-optimized code functions with activation frames on
+ // the stack.
+ for (JavaScriptFrameIterator it(isolate_); !it.done(); it.Advance()) {
+ JavaScriptFrame* frame = it.frame();
+ if (frame->function()->IsJSFunction()) {
+ JSFunction* function = JSFunction::cast(frame->function());
+ if (function->code()->kind() == Code::FUNCTION &&
+ !function->code()->has_debug_break_slots())
+ active_functions.Add(Handle<JSFunction>(function));
+ }
+ }
+ // Sort the functions on the object pointer value to prepare for
+ // the binary search below.
+ active_functions.Sort(HandleObjectPointerCompare<JSFunction>);
+
+ // Scan the heap for all non-optimized functions which has no
+ // debug break slots.
+ HeapIterator iterator;
+ HeapObject* obj = NULL;
+ while (((obj = iterator.next()) != NULL)) {
+ if (obj->IsJSFunction()) {
+ JSFunction* function = JSFunction::cast(obj);
+ if (function->shared()->allows_lazy_compilation() &&
+ function->shared()->script()->IsScript() &&
+ function->code()->kind() == Code::FUNCTION &&
+ !function->code()->has_debug_break_slots()) {
+ bool has_activation =
+ SortedListBSearch<Handle<JSFunction> >(
+ active_functions,
+ Handle<JSFunction>(function),
+ HandleObjectPointerCompare<JSFunction>) != -1;
+ if (!has_activation) {
+ function->set_code(*lazy_compile);
+ function->shared()->set_code(*lazy_compile);
+ }
+ }
+ }
}
}
- active_functions.Sort();
-
- // Scan the heap for all non-optimized functions which has no
- // debug break slots.
- HeapIterator iterator;
- HeapObject* obj = NULL;
- while (((obj = iterator.next()) != NULL)) {
- if (obj->IsJSFunction()) {
- JSFunction* function = JSFunction::cast(obj);
- if (function->shared()->allows_lazy_compilation() &&
- function->shared()->script()->IsScript() &&
- function->code()->kind() == Code::FUNCTION &&
- !function->code()->has_debug_break_slots()) {
- bool has_activation =
- SortedListBSearch<JSFunction*>(active_functions, function) != -1;
- if (!has_activation) {
- function->set_code(lazy_compile);
- function->shared()->set_code(lazy_compile);
+
+ // Now the non-GC scope is left, and the sorting of the functions
+ // in active_function is not ensured any more. The code below does
+ // not rely on it.
+
+ // Now recompile all functions with activation frames and and
+ // patch the return address to run in the new compiled code.
+ for (int i = 0; i < active_functions.length(); i++) {
+ Handle<JSFunction> function = active_functions[i];
+ Handle<SharedFunctionInfo> shared(function->shared());
+ // If recompilation is not possible just skip it.
+ if (shared->is_toplevel() ||
+ !shared->allows_lazy_compilation() ||
+ shared->code()->kind() == Code::BUILTIN) {
+ continue;
+ }
+
+ // Make sure that the shared full code is compiled with debug
+ // break slots.
+ Handle<Code> current_code(function->code());
+ if (shared->code()->has_debug_break_slots()) {
+ // if the code is already recompiled to have break slots skip
+ // recompilation.
+ ASSERT(!function->code()->has_debug_break_slots());
+ } else {
+ // Try to compile the full code with debug break slots. If it
+ // fails just keep the current code.
+ ASSERT(shared->code() == *current_code);
+ ZoneScope zone_scope(isolate_, DELETE_ON_EXIT);
+ shared->set_code(*lazy_compile);
+ bool prev_force_debugger_active =
+ isolate_->debugger()->force_debugger_active();
+ isolate_->debugger()->set_force_debugger_active(true);
+ CompileFullCodeForDebugging(shared, current_code);
+ isolate_->debugger()->set_force_debugger_active(
+ prev_force_debugger_active);
+ if (!shared->is_compiled()) {
+ shared->set_code(*current_code);
+ continue;
+ }
+ }
+ Handle<Code> new_code(shared->code());
+
+ // Find the function and patch return address.
+ for (JavaScriptFrameIterator it(isolate_); !it.done(); it.Advance()) {
+ JavaScriptFrame* frame = it.frame();
+ // If the current frame is for this function in its
+ // non-optimized form rewrite the return address to continue
+ // in the newly compiled full code with debug break slots.
+ if (frame->function()->IsJSFunction() &&
+ frame->function() == *function &&
+ frame->LookupCode()->kind() == Code::FUNCTION) {
+ intptr_t delta = frame->pc() - current_code->instruction_start();
+ int debug_break_slot_count = 0;
+ int mask = RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT);
+ for (RelocIterator it(*new_code, mask); !it.done(); it.next()) {
+ // Check if the pc in the new code with debug break
+ // slots is before this slot.
+ RelocInfo* info = it.rinfo();
+ int debug_break_slot_bytes =
+ debug_break_slot_count * Assembler::kDebugBreakSlotLength;
+ intptr_t new_delta =
+ info->pc() -
+ new_code->instruction_start() -
+ debug_break_slot_bytes;
+ if (new_delta > delta) {
+ break;
+ }
+
+ // Passed a debug break slot in the full code with debug
+ // break slots.
+ debug_break_slot_count++;
+ }
+ int debug_break_slot_bytes =
+ debug_break_slot_count * Assembler::kDebugBreakSlotLength;
+ if (FLAG_trace_deopt) {
+ PrintF("Replacing code %08" V8PRIxPTR " - %08" V8PRIxPTR " (%d) "
+ "with %08" V8PRIxPTR " - %08" V8PRIxPTR " (%d) "
+ "for debugging, "
+ "changing pc from %08" V8PRIxPTR " to %08" V8PRIxPTR "\n",
+ reinterpret_cast<intptr_t>(
+ current_code->instruction_start()),
+ reinterpret_cast<intptr_t>(
+ current_code->instruction_start()) +
+ current_code->instruction_size(),
+ current_code->instruction_size(),
+ reinterpret_cast<intptr_t>(new_code->instruction_start()),
+ reinterpret_cast<intptr_t>(new_code->instruction_start()) +
+ new_code->instruction_size(),
+ new_code->instruction_size(),
+ reinterpret_cast<intptr_t>(frame->pc()),
+ reinterpret_cast<intptr_t>(new_code->instruction_start()) +
+ delta + debug_break_slot_bytes);
}
+
+ // Patch the return address to return into the code with
+ // debug break slots.
+ frame->set_pc(
+ new_code->instruction_start() + delta + debug_break_slot_bytes);
}
}
}
@@ -1787,7 +1934,9 @@ bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) {
}
// Ensure shared in compiled. Return false if this failed.
- if (!EnsureCompiled(shared, CLEAR_EXCEPTION)) return false;
+ if (!SharedFunctionInfo::EnsureCompiled(shared, CLEAR_EXCEPTION)) {
+ return false;
+ }
// Create the debug info object.
Handle<DebugInfo> debug_info = FACTORY->NewDebugInfo(shared);
@@ -2077,6 +2226,7 @@ Debugger::Debugger(Isolate* isolate)
compiling_natives_(false),
is_loading_debugger_(false),
never_unload_debugger_(false),
+ force_debugger_active_(false),
message_handler_(NULL),
debugger_unload_pending_(false),
host_dispatch_handler_(NULL),
@@ -2844,7 +2994,9 @@ void Debugger::EnqueueDebugCommand(v8::Debug::ClientData* client_data) {
bool Debugger::IsDebuggerActive() {
ScopedLock with(debugger_access_);
- return message_handler_ != NULL || !event_listener_.is_null();
+ return message_handler_ != NULL ||
+ !event_listener_.is_null() ||
+ force_debugger_active_;
}
diff --git a/deps/v8/src/debug.h b/deps/v8/src/debug.h
index f01ef393f8..3c37186176 100644
--- a/deps/v8/src/debug.h
+++ b/deps/v8/src/debug.h
@@ -810,11 +810,15 @@ class Debugger {
}
void set_compiling_natives(bool compiling_natives) {
- Debugger::compiling_natives_ = compiling_natives;
+ compiling_natives_ = compiling_natives;
}
bool compiling_natives() const { return compiling_natives_; }
void set_loading_debugger(bool v) { is_loading_debugger_ = v; }
bool is_loading_debugger() const { return is_loading_debugger_; }
+ void set_force_debugger_active(bool force_debugger_active) {
+ force_debugger_active_ = force_debugger_active;
+ }
+ bool force_debugger_active() const { return force_debugger_active_; }
bool IsDebuggerActive();
@@ -840,6 +844,7 @@ class Debugger {
bool compiling_natives_; // Are we compiling natives?
bool is_loading_debugger_; // Are we loading the debugger?
bool never_unload_debugger_; // Can we unload the debugger?
+ bool force_debugger_active_; // Activate debugger without event listeners.
v8::Debug::MessageHandler2 message_handler_;
bool debugger_unload_pending_; // Was message handler cleared?
v8::Debug::HostDispatchHandler host_dispatch_handler_;
diff --git a/deps/v8/src/deoptimizer.cc b/deps/v8/src/deoptimizer.cc
index b0522757eb..a83493db48 100644
--- a/deps/v8/src/deoptimizer.cc
+++ b/deps/v8/src/deoptimizer.cc
@@ -882,10 +882,12 @@ bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator,
unsigned output_offset =
output->GetOffsetFromSlotIndex(this, output_index);
if (FLAG_trace_osr) {
- PrintF(" [sp + %d] <- 0x%08" V8PRIxPTR " ; [sp + %d]\n",
+ PrintF(" [sp + %d] <- 0x%08" V8PRIxPTR " ; [sp + %d] ",
output_offset,
input_value,
*input_offset);
+ reinterpret_cast<Object*>(input_value)->ShortPrint();
+ PrintF("\n");
}
output->SetFrameSlot(output_offset, input_value);
break;
@@ -1007,7 +1009,10 @@ void Deoptimizer::RevertStackCheckCode(Code* unoptimized_code,
for (uint32_t i = 0; i < table_length; ++i) {
uint32_t pc_offset = Memory::uint32_at(stack_check_cursor + kIntSize);
Address pc_after = unoptimized_code->instruction_start() + pc_offset;
- RevertStackCheckCodeAt(pc_after, check_code, replacement_code);
+ RevertStackCheckCodeAt(unoptimized_code,
+ pc_after,
+ check_code,
+ replacement_code);
stack_check_cursor += 2 * kIntSize;
}
}
diff --git a/deps/v8/src/deoptimizer.h b/deps/v8/src/deoptimizer.h
index 3cf70466c0..33580a1b9c 100644
--- a/deps/v8/src/deoptimizer.h
+++ b/deps/v8/src/deoptimizer.h
@@ -186,7 +186,8 @@ class Deoptimizer : public Malloced {
// Change all patched stack guard checks in the unoptimized code
// back to a normal stack guard check.
- static void RevertStackCheckCodeAt(Address pc_after,
+ static void RevertStackCheckCodeAt(Code* unoptimized_code,
+ Address pc_after,
Code* check_code,
Code* replacement_code);
diff --git a/deps/v8/src/factory.cc b/deps/v8/src/factory.cc
index 143b342083..15f640e7e5 100644
--- a/deps/v8/src/factory.cc
+++ b/deps/v8/src/factory.cc
@@ -59,13 +59,13 @@ Handle<FixedArray> Factory::NewFixedArrayWithHoles(int size,
}
-Handle<FixedArray> Factory::NewFixedDoubleArray(int size,
- PretenureFlag pretenure) {
+Handle<FixedDoubleArray> Factory::NewFixedDoubleArray(int size,
+ PretenureFlag pretenure) {
ASSERT(0 <= size);
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateUninitializedFixedDoubleArray(size, pretenure),
- FixedArray);
+ FixedDoubleArray);
}
@@ -85,6 +85,14 @@ Handle<NumberDictionary> Factory::NewNumberDictionary(int at_least_space_for) {
}
+Handle<ObjectHashSet> Factory::NewObjectHashSet(int at_least_space_for) {
+ ASSERT(0 <= at_least_space_for);
+ CALL_HEAP_FUNCTION(isolate(),
+ ObjectHashSet::Allocate(at_least_space_for),
+ ObjectHashSet);
+}
+
+
Handle<ObjectHashTable> Factory::NewObjectHashTable(int at_least_space_for) {
ASSERT(0 <= at_least_space_for);
CALL_HEAP_FUNCTION(isolate(),
@@ -471,6 +479,12 @@ Handle<FixedArray> Factory::CopyFixedArray(Handle<FixedArray> array) {
}
+Handle<FixedDoubleArray> Factory::CopyFixedDoubleArray(
+ Handle<FixedDoubleArray> array) {
+ CALL_HEAP_FUNCTION(isolate(), array->Copy(), FixedDoubleArray);
+}
+
+
Handle<JSFunction> Factory::BaseNewFunctionFromSharedFunctionInfo(
Handle<SharedFunctionInfo> function_info,
Handle<Map> function_map,
@@ -497,16 +511,20 @@ Handle<JSFunction> Factory::NewFunctionFromSharedFunctionInfo(
pretenure);
result->set_context(*context);
- int number_of_literals = function_info->num_literals();
- Handle<FixedArray> literals = NewFixedArray(number_of_literals, pretenure);
- if (number_of_literals > 0) {
- // Store the object, regexp and array functions in the literals
- // array prefix. These functions will be used when creating
- // object, regexp and array literals in this function.
- literals->set(JSFunction::kLiteralGlobalContextIndex,
- context->global_context());
+ if (!function_info->bound()) {
+ int number_of_literals = function_info->num_literals();
+ Handle<FixedArray> literals = NewFixedArray(number_of_literals, pretenure);
+ if (number_of_literals > 0) {
+ // Store the object, regexp and array functions in the literals
+ // array prefix. These functions will be used when creating
+ // object, regexp and array literals in this function.
+ literals->set(JSFunction::kLiteralGlobalContextIndex,
+ context->global_context());
+ }
+ result->set_literals(*literals);
+ } else {
+ result->set_function_bindings(isolate()->heap()->empty_fixed_array());
}
- result->set_literals(*literals);
result->set_next_function_link(isolate()->heap()->undefined_value());
if (V8::UseCrankshaft() &&
@@ -821,10 +839,13 @@ Handle<DescriptorArray> Factory::CopyAppendCallbackDescriptors(
// Number of descriptors added to the result so far.
int descriptor_count = 0;
+ // Ensure that marking will not progress and change color of objects.
+ DescriptorArray::WhitenessWitness witness(*result);
+
// Copy the descriptors from the array.
for (int i = 0; i < array->number_of_descriptors(); i++) {
if (array->GetType(i) != NULL_DESCRIPTOR) {
- result->CopyFrom(descriptor_count++, *array, i);
+ result->CopyFrom(descriptor_count++, *array, i, witness);
}
}
@@ -844,7 +865,7 @@ Handle<DescriptorArray> Factory::CopyAppendCallbackDescriptors(
if (result->LinearSearch(*key, descriptor_count) ==
DescriptorArray::kNotFound) {
CallbacksDescriptor desc(*key, *entry, entry->property_attributes());
- result->Set(descriptor_count, &desc);
+ result->Set(descriptor_count, &desc, witness);
descriptor_count++;
} else {
duplicates++;
@@ -858,13 +879,13 @@ Handle<DescriptorArray> Factory::CopyAppendCallbackDescriptors(
Handle<DescriptorArray> new_result =
NewDescriptorArray(number_of_descriptors);
for (int i = 0; i < number_of_descriptors; i++) {
- new_result->CopyFrom(i, *result, i);
+ new_result->CopyFrom(i, *result, i, witness);
}
result = new_result;
}
// Sort the result before returning.
- result->Sort();
+ result->Sort(witness);
return result;
}
diff --git a/deps/v8/src/factory.h b/deps/v8/src/factory.h
index a3615f2a0a..2073ce3926 100644
--- a/deps/v8/src/factory.h
+++ b/deps/v8/src/factory.h
@@ -50,7 +50,7 @@ class Factory {
PretenureFlag pretenure = NOT_TENURED);
// Allocate a new uninitialized fixed double array.
- Handle<FixedArray> NewFixedDoubleArray(
+ Handle<FixedDoubleArray> NewFixedDoubleArray(
int size,
PretenureFlag pretenure = NOT_TENURED);
@@ -58,6 +58,8 @@ class Factory {
Handle<StringDictionary> NewStringDictionary(int at_least_space_for);
+ Handle<ObjectHashSet> NewObjectHashSet(int at_least_space_for);
+
Handle<ObjectHashTable> NewObjectHashTable(int at_least_space_for);
Handle<DescriptorArray> NewDescriptorArray(int number_of_descriptors);
@@ -222,6 +224,9 @@ class Factory {
Handle<FixedArray> CopyFixedArray(Handle<FixedArray> array);
+ Handle<FixedDoubleArray> CopyFixedDoubleArray(
+ Handle<FixedDoubleArray> array);
+
// Numbers (eg, literals) are pretenured by the parser.
Handle<Object> NewNumber(double value,
PretenureFlag pretenure = NOT_TENURED);
diff --git a/deps/v8/src/flag-definitions.h b/deps/v8/src/flag-definitions.h
index 58fab14e1c..ee6ef01a69 100644
--- a/deps/v8/src/flag-definitions.h
+++ b/deps/v8/src/flag-definitions.h
@@ -100,7 +100,8 @@ private:
DEFINE_bool(harmony_typeof, false, "enable harmony semantics for typeof")
DEFINE_bool(harmony_scoping, false, "enable harmony block scoping")
DEFINE_bool(harmony_proxies, false, "enable harmony proxies")
-DEFINE_bool(harmony_weakmaps, false, "enable harmony weak maps")
+DEFINE_bool(harmony_collections, false,
+ "enable harmony collections (sets, maps, and weak maps)")
DEFINE_bool(harmony, false, "enable all harmony features")
// Flags for experimental implementation features.
@@ -186,6 +187,8 @@ DEFINE_bool(expose_gc, false, "expose gc extension")
DEFINE_bool(expose_externalize_string, false,
"expose externalize string extension")
DEFINE_int(stack_trace_limit, 10, "number of stack frames to capture")
+DEFINE_bool(builtins_in_stack_traces, false,
+ "show built-in functions in stack traces")
DEFINE_bool(disable_native_files, false, "disable builtin natives files")
// builtins-ia32.cc
@@ -527,6 +530,9 @@ DEFINE_bool(ll_prof, false, "Enable low-level linux profiler.")
#define FLAG FLAG_READONLY
#endif
+// elements.cc
+DEFINE_bool(trace_elements_transitions, false, "trace elements transitions")
+
// code-stubs.cc
DEFINE_bool(print_code_stubs, false, "print code stubs")
diff --git a/deps/v8/src/frames.cc b/deps/v8/src/frames.cc
index 412a59cc7d..7c4c573e12 100644
--- a/deps/v8/src/frames.cc
+++ b/deps/v8/src/frames.cc
@@ -711,6 +711,69 @@ void JavaScriptFrame::Summarize(List<FrameSummary>* functions) {
}
+void JavaScriptFrame::PrintTop(FILE* file,
+ bool print_args,
+ bool print_line_number) {
+ // constructor calls
+ HandleScope scope;
+ AssertNoAllocation no_allocation;
+ JavaScriptFrameIterator it;
+ while (!it.done()) {
+ if (it.frame()->is_java_script()) {
+ JavaScriptFrame* frame = it.frame();
+ if (frame->IsConstructor()) PrintF(file, "new ");
+ // function name
+ Object* fun = frame->function();
+ if (fun->IsJSFunction()) {
+ SharedFunctionInfo* shared = JSFunction::cast(fun)->shared();
+ shared->DebugName()->ShortPrint(file);
+ if (print_line_number) {
+ Address pc = frame->pc();
+ Code* code = Code::cast(
+ v8::internal::Isolate::Current()->heap()->FindCodeObject(pc));
+ int source_pos = code->SourcePosition(pc);
+ Object* maybe_script = shared->script();
+ if (maybe_script->IsScript()) {
+ Handle<Script> script(Script::cast(maybe_script));
+ int line = GetScriptLineNumberSafe(script, source_pos) + 1;
+ Object* script_name_raw = script->name();
+ if (script_name_raw->IsString()) {
+ String* script_name = String::cast(script->name());
+ SmartArrayPointer<char> c_script_name =
+ script_name->ToCString(DISALLOW_NULLS,
+ ROBUST_STRING_TRAVERSAL);
+ PrintF(file, " at %s:%d", *c_script_name, line);
+ } else {
+ PrintF(file, "at <unknown>:%d", line);
+ }
+ } else {
+ PrintF(file, " at <unknown>:<unknown>");
+ }
+ }
+ } else {
+ fun->ShortPrint(file);
+ }
+
+ if (print_args) {
+ // function arguments
+ // (we are intentionally only printing the actually
+ // supplied parameters, not all parameters required)
+ PrintF(file, "(this=");
+ frame->receiver()->ShortPrint(file);
+ const int length = frame->ComputeParametersCount();
+ for (int i = 0; i < length; i++) {
+ PrintF(file, ", ");
+ frame->GetParameter(i)->ShortPrint(file);
+ }
+ PrintF(file, ")");
+ }
+ break;
+ }
+ it.Advance();
+ }
+}
+
+
void FrameSummary::Print() {
PrintF("receiver: ");
receiver_->ShortPrint();
diff --git a/deps/v8/src/frames.h b/deps/v8/src/frames.h
index ca19b053aa..778b803168 100644
--- a/deps/v8/src/frames.h
+++ b/deps/v8/src/frames.h
@@ -512,6 +512,8 @@ class JavaScriptFrame: public StandardFrame {
return static_cast<JavaScriptFrame*>(frame);
}
+ static void PrintTop(FILE* file, bool print_args, bool print_line_number);
+
protected:
inline explicit JavaScriptFrame(StackFrameIterator* iterator);
diff --git a/deps/v8/src/full-codegen.cc b/deps/v8/src/full-codegen.cc
index 083675d133..27c509f776 100644
--- a/deps/v8/src/full-codegen.cc
+++ b/deps/v8/src/full-codegen.cc
@@ -289,11 +289,12 @@ bool FullCodeGenerator::MakeCode(CompilationInfo* info) {
#ifdef ENABLE_DEBUGGER_SUPPORT
code->set_has_debug_break_slots(
info->isolate()->debugger()->IsDebuggerActive());
+ code->set_compiled_optimizable(info->IsOptimizable());
#endif // ENABLE_DEBUGGER_SUPPORT
code->set_allow_osr_at_loop_nesting_level(0);
code->set_stack_check_table_offset(table_offset);
CodeGenerator::PrintCode(code, info);
- info->SetCode(code); // may be an empty handle.
+ info->SetCode(code); // May be an empty handle.
#ifdef ENABLE_GDB_JIT_INTERFACE
if (FLAG_gdbjit && !code.is_null()) {
GDBJITLineInfo* lineinfo =
@@ -520,8 +521,8 @@ void FullCodeGenerator::VisitDeclarations(
if (var->IsUnallocated()) {
array->set(j++, *(var->name()));
if (decl->fun() == NULL) {
- if (var->mode() == CONST) {
- // In case this is const property use the hole.
+ if (var->binding_needs_init()) {
+ // In case this binding needs initialization use the hole.
array->set_the_hole(j++);
} else {
array->set_undefined(j++);
@@ -546,11 +547,10 @@ void FullCodeGenerator::VisitDeclarations(
int FullCodeGenerator::DeclareGlobalsFlags() {
- int flags = 0;
- if (is_eval()) flags |= kDeclareGlobalsEvalFlag;
- if (is_strict_mode()) flags |= kDeclareGlobalsStrictModeFlag;
- if (is_native()) flags |= kDeclareGlobalsNativeFlag;
- return flags;
+ ASSERT(DeclareGlobalsStrictModeFlag::is_valid(strict_mode_flag()));
+ return DeclareGlobalsEvalFlag::encode(is_eval()) |
+ DeclareGlobalsStrictModeFlag::encode(strict_mode_flag()) |
+ DeclareGlobalsNativeFlag::encode(is_native());
}
diff --git a/deps/v8/src/full-codegen.h b/deps/v8/src/full-codegen.h
index 081192a541..9132502680 100644
--- a/deps/v8/src/full-codegen.h
+++ b/deps/v8/src/full-codegen.h
@@ -577,9 +577,11 @@ class FullCodeGenerator: public AstVisitor {
Handle<Script> script() { return info_->script(); }
bool is_eval() { return info_->is_eval(); }
bool is_native() { return info_->is_native(); }
- bool is_strict_mode() { return function()->strict_mode(); }
+ bool is_strict_mode() {
+ return strict_mode_flag() == kStrictMode;
+ }
StrictModeFlag strict_mode_flag() {
- return is_strict_mode() ? kStrictMode : kNonStrictMode;
+ return function()->strict_mode_flag();
}
FunctionLiteral* function() { return info_->function(); }
Scope* scope() { return scope_; }
diff --git a/deps/v8/src/globals.h b/deps/v8/src/globals.h
index d0c78d6e22..cbe7abdf66 100644
--- a/deps/v8/src/globals.h
+++ b/deps/v8/src/globals.h
@@ -230,6 +230,9 @@ const int kPointerSize = sizeof(void*); // NOLINT
const int kDoubleSizeLog2 = 3;
+// Size of the state of a the random number generator.
+const int kRandomStateSize = 2 * kIntSize;
+
#if V8_HOST_ARCH_64_BIT
const int kPointerSizeLog2 = 3;
const intptr_t kIntptrSignBit = V8_INT64_C(0x8000000000000000);
diff --git a/deps/v8/src/handles.cc b/deps/v8/src/handles.cc
index 57f5d1b66f..62851f3416 100644
--- a/deps/v8/src/handles.cc
+++ b/deps/v8/src/handles.cc
@@ -376,24 +376,6 @@ Handle<Object> GetProperty(Handle<Object> obj,
}
-Handle<Object> GetProperty(Handle<JSReceiver> obj,
- Handle<String> name,
- LookupResult* result) {
- PropertyAttributes attributes;
- Isolate* isolate = Isolate::Current();
- CALL_HEAP_FUNCTION(isolate,
- obj->GetProperty(*obj, result, *name, &attributes),
- Object);
-}
-
-
-Handle<Object> GetElement(Handle<Object> obj,
- uint32_t index) {
- Isolate* isolate = Isolate::Current();
- CALL_HEAP_FUNCTION(isolate, Runtime::GetElement(obj, index), Object);
-}
-
-
Handle<Object> GetPropertyWithInterceptor(Handle<JSObject> receiver,
Handle<JSObject> holder,
Handle<String> name,
@@ -504,6 +486,14 @@ Handle<Object> SetOwnElement(Handle<JSObject> object,
}
+Handle<Object> TransitionElementsKind(Handle<JSObject> object,
+ ElementsKind to_kind) {
+ CALL_HEAP_FUNCTION(object->GetIsolate(),
+ object->TransitionElementsKind(to_kind),
+ Object);
+}
+
+
Handle<JSObject> Copy(Handle<JSObject> obj) {
Isolate* isolate = obj->GetIsolate();
CALL_HEAP_FUNCTION(isolate,
@@ -701,7 +691,7 @@ void CustomArguments::IterateInstance(ObjectVisitor* v) {
// Compute the property keys from the interceptor.
-v8::Handle<v8::Array> GetKeysForNamedInterceptor(Handle<JSObject> receiver,
+v8::Handle<v8::Array> GetKeysForNamedInterceptor(Handle<JSReceiver> receiver,
Handle<JSObject> object) {
Isolate* isolate = receiver->GetIsolate();
Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor());
@@ -723,7 +713,7 @@ v8::Handle<v8::Array> GetKeysForNamedInterceptor(Handle<JSObject> receiver,
// Compute the element keys from the interceptor.
-v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSObject> receiver,
+v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSReceiver> receiver,
Handle<JSObject> object) {
Isolate* isolate = receiver->GetIsolate();
Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
@@ -754,8 +744,9 @@ static bool ContainsOnlyValidKeys(Handle<FixedArray> array) {
}
-Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object,
- KeyCollectionType type) {
+Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSReceiver> object,
+ KeyCollectionType type,
+ bool* threw) {
USE(ContainsOnlyValidKeys);
Isolate* isolate = object->GetIsolate();
Handle<FixedArray> content = isolate->factory()->empty_fixed_array();
@@ -770,6 +761,16 @@ Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object,
for (Handle<Object> p = object;
*p != isolate->heap()->null_value();
p = Handle<Object>(p->GetPrototype(), isolate)) {
+ if (p->IsJSProxy()) {
+ Handle<JSProxy> proxy(JSProxy::cast(*p), isolate);
+ Handle<Object> args[] = { proxy };
+ Handle<Object> names = Execution::Call(
+ isolate->proxy_enumerate(), object, ARRAY_SIZE(args), args, threw);
+ if (*threw) return content;
+ content = AddKeysFromJSArray(content, Handle<JSArray>::cast(names));
+ break;
+ }
+
Handle<JSObject> current(JSObject::cast(*p), isolate);
// Check access rights if required.
@@ -836,11 +837,11 @@ Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object,
}
-Handle<JSArray> GetKeysFor(Handle<JSObject> object) {
+Handle<JSArray> GetKeysFor(Handle<JSReceiver> object, bool* threw) {
Isolate* isolate = object->GetIsolate();
isolate->counters()->for_in()->Increment();
- Handle<FixedArray> elements = GetKeysInFixedArrayFor(object,
- INCLUDE_PROTOS);
+ Handle<FixedArray> elements =
+ GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, threw);
return isolate->factory()->NewJSArrayWithElements(elements);
}
@@ -890,62 +891,29 @@ Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
}
-Handle<ObjectHashTable> PutIntoObjectHashTable(Handle<ObjectHashTable> table,
- Handle<JSReceiver> key,
- Handle<Object> value) {
+Handle<ObjectHashSet> ObjectHashSetAdd(Handle<ObjectHashSet> table,
+ Handle<Object> key) {
CALL_HEAP_FUNCTION(table->GetIsolate(),
- table->Put(*key, *value),
- ObjectHashTable);
-}
-
-
-bool EnsureCompiled(Handle<SharedFunctionInfo> shared,
- ClearExceptionFlag flag) {
- return shared->is_compiled() || CompileLazyShared(shared, flag);
+ table->Add(*key),
+ ObjectHashSet);
}
-static bool CompileLazyHelper(CompilationInfo* info,
- ClearExceptionFlag flag) {
- // Compile the source information to a code object.
- ASSERT(info->IsOptimizing() || !info->shared_info()->is_compiled());
- ASSERT(!info->isolate()->has_pending_exception());
- bool result = Compiler::CompileLazy(info);
- ASSERT(result != Isolate::Current()->has_pending_exception());
- if (!result && flag == CLEAR_EXCEPTION) {
- info->isolate()->clear_pending_exception();
- }
- return result;
-}
-
-
-bool CompileLazyShared(Handle<SharedFunctionInfo> shared,
- ClearExceptionFlag flag) {
- CompilationInfo info(shared);
- return CompileLazyHelper(&info, flag);
+Handle<ObjectHashSet> ObjectHashSetRemove(Handle<ObjectHashSet> table,
+ Handle<Object> key) {
+ CALL_HEAP_FUNCTION(table->GetIsolate(),
+ table->Remove(*key),
+ ObjectHashSet);
}
-bool CompileLazy(Handle<JSFunction> function, ClearExceptionFlag flag) {
- bool result = true;
- if (function->shared()->is_compiled()) {
- function->ReplaceCode(function->shared()->code());
- function->shared()->set_code_age(0);
- } else {
- CompilationInfo info(function);
- result = CompileLazyHelper(&info, flag);
- ASSERT(!result || function->is_compiled());
- }
- return result;
+Handle<ObjectHashTable> PutIntoObjectHashTable(Handle<ObjectHashTable> table,
+ Handle<Object> key,
+ Handle<Object> value) {
+ CALL_HEAP_FUNCTION(table->GetIsolate(),
+ table->Put(*key, *value),
+ ObjectHashTable);
}
-bool CompileOptimized(Handle<JSFunction> function,
- int osr_ast_id,
- ClearExceptionFlag flag) {
- CompilationInfo info(function);
- info.SetOptimizing(osr_ast_id);
- return CompileLazyHelper(&info, flag);
-}
-
} } // namespace v8::internal
diff --git a/deps/v8/src/handles.h b/deps/v8/src/handles.h
index d5521f89c1..06e47fca9f 100644
--- a/deps/v8/src/handles.h
+++ b/deps/v8/src/handles.h
@@ -240,20 +240,15 @@ Handle<Object> SetOwnElement(Handle<JSObject> object,
Handle<Object> value,
StrictModeFlag strict_mode);
+Handle<Object> TransitionElementsKind(Handle<JSObject> object,
+ ElementsKind to_kind);
+
Handle<Object> GetProperty(Handle<JSReceiver> obj,
const char* name);
Handle<Object> GetProperty(Handle<Object> obj,
Handle<Object> key);
-Handle<Object> GetProperty(Handle<JSReceiver> obj,
- Handle<String> name,
- LookupResult* result);
-
-
-Handle<Object> GetElement(Handle<Object> obj,
- uint32_t index);
-
Handle<Object> GetPropertyWithInterceptor(Handle<JSObject> receiver,
Handle<JSObject> holder,
Handle<String> name,
@@ -300,18 +295,19 @@ int GetScriptLineNumberSafe(Handle<Script> script, int code_position);
// Computes the enumerable keys from interceptors. Used for debug mirrors and
// by GetKeysInFixedArrayFor below.
-v8::Handle<v8::Array> GetKeysForNamedInterceptor(Handle<JSObject> receiver,
+v8::Handle<v8::Array> GetKeysForNamedInterceptor(Handle<JSReceiver> receiver,
Handle<JSObject> object);
-v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSObject> receiver,
+v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSReceiver> receiver,
Handle<JSObject> object);
enum KeyCollectionType { LOCAL_ONLY, INCLUDE_PROTOS };
// Computes the enumerable keys for a JSObject. Used for implementing
// "for (n in object) { }".
-Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object,
- KeyCollectionType type);
-Handle<JSArray> GetKeysFor(Handle<JSObject> object);
+Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSReceiver> object,
+ KeyCollectionType type,
+ bool* threw);
+Handle<JSArray> GetKeysFor(Handle<JSReceiver> object, bool* threw);
Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
bool cache_result);
@@ -346,25 +342,15 @@ Handle<Object> SetPrototype(Handle<JSFunction> function,
Handle<Object> PreventExtensions(Handle<JSObject> object);
-Handle<ObjectHashTable> PutIntoObjectHashTable(Handle<ObjectHashTable> table,
- Handle<JSReceiver> key,
- Handle<Object> value);
-
-// Does lazy compilation of the given function. Returns true on success and
-// false if the compilation resulted in a stack overflow.
-enum ClearExceptionFlag { KEEP_EXCEPTION, CLEAR_EXCEPTION };
-
-bool EnsureCompiled(Handle<SharedFunctionInfo> shared,
- ClearExceptionFlag flag);
+Handle<ObjectHashSet> ObjectHashSetAdd(Handle<ObjectHashSet> table,
+ Handle<Object> key);
-bool CompileLazyShared(Handle<SharedFunctionInfo> shared,
- ClearExceptionFlag flag);
+Handle<ObjectHashSet> ObjectHashSetRemove(Handle<ObjectHashSet> table,
+ Handle<Object> key);
-bool CompileLazy(Handle<JSFunction> function, ClearExceptionFlag flag);
-
-bool CompileOptimized(Handle<JSFunction> function,
- int osr_ast_id,
- ClearExceptionFlag flag);
+Handle<ObjectHashTable> PutIntoObjectHashTable(Handle<ObjectHashTable> table,
+ Handle<Object> key,
+ Handle<Object> value);
class NoHandleAllocation BASE_EMBEDDED {
public:
diff --git a/deps/v8/src/heap-inl.h b/deps/v8/src/heap-inl.h
index 4bd893e8ee..aaf2927f7f 100644
--- a/deps/v8/src/heap-inl.h
+++ b/deps/v8/src/heap-inl.h
@@ -359,7 +359,6 @@ AllocationSpace Heap::TargetSpaceId(InstanceType type) {
void Heap::CopyBlock(Address dst, Address src, int byte_size) {
- ASSERT(IsAligned(byte_size, kPointerSize));
CopyWords(reinterpret_cast<Object**>(dst),
reinterpret_cast<Object**>(src),
byte_size / kPointerSize);
@@ -591,7 +590,9 @@ void ExternalStringTable::AddOldString(String* string) {
void ExternalStringTable::ShrinkNewStrings(int position) {
new_space_strings_.Rewind(position);
- Verify();
+ if (FLAG_verify_heap) {
+ Verify();
+ }
}
diff --git a/deps/v8/src/heap.cc b/deps/v8/src/heap.cc
index c6efd62050..bbb9d3e26d 100644
--- a/deps/v8/src/heap.cc
+++ b/deps/v8/src/heap.cc
@@ -693,7 +693,9 @@ bool Heap::PerformGarbageCollection(GarbageCollector collector,
PROFILE(isolate_, CodeMovingGCEvent());
}
- VerifySymbolTable();
+ if (FLAG_verify_heap) {
+ VerifySymbolTable();
+ }
if (collector == MARK_COMPACTOR && global_gc_prologue_callback_) {
ASSERT(!allocation_allowed_);
GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
@@ -789,7 +791,9 @@ bool Heap::PerformGarbageCollection(GarbageCollector collector,
GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
global_gc_epilogue_callback_();
}
- VerifySymbolTable();
+ if (FLAG_verify_heap) {
+ VerifySymbolTable();
+ }
return next_gc_likely_to_collect_more;
}
@@ -983,7 +987,7 @@ void StoreBufferRebuilder::Callback(MemoryChunk* page, StoreBufferEvent event) {
void Heap::Scavenge() {
#ifdef DEBUG
- if (FLAG_enable_slow_asserts) VerifyNonPointerSpacePointers();
+ if (FLAG_verify_heap) VerifyNonPointerSpacePointers();
#endif
gc_state_ = SCAVENGE;
@@ -1112,7 +1116,9 @@ String* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap,
void Heap::UpdateNewSpaceReferencesInExternalStringTable(
ExternalStringTableUpdaterCallback updater_func) {
- external_string_table_.Verify();
+ if (FLAG_verify_heap) {
+ external_string_table_.Verify();
+ }
if (external_string_table_.new_space_strings_.is_empty()) return;
@@ -1443,9 +1449,9 @@ class ScavengingVisitor : public StaticVisitorBase {
HeapObject** slot,
HeapObject* object,
int object_size) {
- ASSERT((size_restriction != SMALL) ||
- (object_size <= Page::kMaxHeapObjectSize));
- ASSERT(object->Size() == object_size);
+ SLOW_ASSERT((size_restriction != SMALL) ||
+ (object_size <= Page::kMaxHeapObjectSize));
+ SLOW_ASSERT(object->Size() == object_size);
Heap* heap = map->GetHeap();
if (heap->ShouldBePromoted(object->address(), object_size)) {
@@ -1678,9 +1684,9 @@ void Heap::SelectScavengingVisitorsTable() {
void Heap::ScavengeObjectSlow(HeapObject** p, HeapObject* object) {
- ASSERT(HEAP->InFromSpace(object));
+ SLOW_ASSERT(HEAP->InFromSpace(object));
MapWord first_word = object->map_word();
- ASSERT(!first_word.IsForwardingAddress());
+ SLOW_ASSERT(!first_word.IsForwardingAddress());
Map* map = first_word.ToMap();
map->GetHeap()->DoScavengeObject(map, p, object);
}
@@ -2910,7 +2916,9 @@ MaybeObject* Heap::AllocateSubString(String* buffer,
ASSERT(buffer->IsFlat());
#if DEBUG
- buffer->StringVerify();
+ if (FLAG_verify_heap) {
+ buffer->StringVerify();
+ }
#endif
Object* result;
@@ -3156,7 +3164,9 @@ MaybeObject* Heap::CreateCode(const CodeDesc& desc,
code->CopyFrom(desc);
#ifdef DEBUG
- code->Verify();
+ if (FLAG_verify_heap) {
+ code->Verify();
+ }
#endif
return code;
}
@@ -3236,7 +3246,9 @@ MaybeObject* Heap::CopyCode(Code* code, Vector<byte> reloc_info) {
new_code->Relocate(new_addr - old_addr);
#ifdef DEBUG
- code->Verify();
+ if (FLAG_verify_heap) {
+ code->Verify();
+ }
#endif
return new_code;
}
@@ -3269,7 +3281,7 @@ void Heap::InitializeFunction(JSFunction* function,
function->set_code(shared->code());
function->set_prototype_or_initial_map(prototype);
function->set_context(undefined_value());
- function->set_literals(empty_fixed_array());
+ function->set_literals_or_bindings(empty_fixed_array());
function->set_next_function_link(undefined_value());
}
@@ -3434,22 +3446,22 @@ MaybeObject* Heap::AllocateInitialMap(JSFunction* fun) {
// Inline constructor can only handle inobject properties.
fun->shared()->ForbidInlineConstructor();
} else {
- Object* descriptors_obj;
+ DescriptorArray* descriptors;
{ MaybeObject* maybe_descriptors_obj = DescriptorArray::Allocate(count);
- if (!maybe_descriptors_obj->ToObject(&descriptors_obj)) {
+ if (!maybe_descriptors_obj->To<DescriptorArray>(&descriptors)) {
return maybe_descriptors_obj;
}
}
- DescriptorArray* descriptors = DescriptorArray::cast(descriptors_obj);
+ DescriptorArray::WhitenessWitness witness(descriptors);
for (int i = 0; i < count; i++) {
String* name = fun->shared()->GetThisPropertyAssignmentName(i);
ASSERT(name->IsSymbol());
FieldDescriptor field(name, i, NONE);
field.SetEnumerationIndex(i);
- descriptors->Set(i, &field);
+ descriptors->Set(i, &field, witness);
}
descriptors->SetNextEnumerationIndex(count);
- descriptors->SortUnchecked();
+ descriptors->SortUnchecked(witness);
// The descriptors may contain duplicates because the compiler does not
// guarantee the uniqueness of property names (it would have required
@@ -3688,13 +3700,15 @@ MaybeObject* Heap::AllocateGlobalObject(JSFunction* constructor) {
MaybeObject* Heap::CopyJSObject(JSObject* source) {
// Never used to copy functions. If functions need to be copied we
// have to be careful to clear the literals array.
- ASSERT(!source->IsJSFunction());
+ SLOW_ASSERT(!source->IsJSFunction());
// Make the clone.
Map* map = source->map();
int object_size = map->instance_size();
Object* clone;
+ WriteBarrierMode wb_mode = UPDATE_WRITE_BARRIER;
+
// If we're forced to always allocate, we use the general allocation
// functions which may leave us with an object in old space.
if (always_allocate()) {
@@ -3711,10 +3725,11 @@ MaybeObject* Heap::CopyJSObject(JSObject* source) {
JSObject::kHeaderSize,
(object_size - JSObject::kHeaderSize) / kPointerSize);
} else {
+ wb_mode = SKIP_WRITE_BARRIER;
{ MaybeObject* maybe_clone = new_space_.AllocateRaw(object_size);
if (!maybe_clone->ToObject(&clone)) return maybe_clone;
}
- ASSERT(InNewSpace(clone));
+ SLOW_ASSERT(InNewSpace(clone));
// Since we know the clone is allocated in new space, we can copy
// the contents without worrying about updating the write barrier.
CopyBlock(HeapObject::cast(clone)->address(),
@@ -3722,7 +3737,8 @@ MaybeObject* Heap::CopyJSObject(JSObject* source) {
object_size);
}
- ASSERT(JSObject::cast(clone)->GetElementsKind() == source->GetElementsKind());
+ SLOW_ASSERT(
+ JSObject::cast(clone)->GetElementsKind() == source->GetElementsKind());
FixedArrayBase* elements = FixedArrayBase::cast(source->elements());
FixedArray* properties = FixedArray::cast(source->properties());
// Update elements if necessary.
@@ -3738,7 +3754,7 @@ MaybeObject* Heap::CopyJSObject(JSObject* source) {
}
if (!maybe_elem->ToObject(&elem)) return maybe_elem;
}
- JSObject::cast(clone)->set_elements(FixedArrayBase::cast(elem));
+ JSObject::cast(clone)->set_elements(FixedArrayBase::cast(elem), wb_mode);
}
// Update properties if necessary.
if (properties->length() > 0) {
@@ -3746,7 +3762,7 @@ MaybeObject* Heap::CopyJSObject(JSObject* source) {
{ MaybeObject* maybe_prop = CopyFixedArray(properties);
if (!maybe_prop->ToObject(&prop)) return maybe_prop;
}
- JSObject::cast(clone)->set_properties(FixedArray::cast(prop));
+ JSObject::cast(clone)->set_properties(FixedArray::cast(prop), wb_mode);
}
// Return the new clone.
return clone;
@@ -4802,12 +4818,12 @@ void Heap::IterateAndMarkPointersToFromSpace(Address start,
HeapObject::cast(object));
Object* new_object = *slot;
if (InNewSpace(new_object)) {
- ASSERT(Heap::InToSpace(new_object));
- ASSERT(new_object->IsHeapObject());
+ SLOW_ASSERT(Heap::InToSpace(new_object));
+ SLOW_ASSERT(new_object->IsHeapObject());
store_buffer_.EnterDirectlyIntoStoreBuffer(
reinterpret_cast<Address>(slot));
}
- ASSERT(!MarkCompactCollector::IsOnEvacuationCandidate(new_object));
+ SLOW_ASSERT(!MarkCompactCollector::IsOnEvacuationCandidate(new_object));
} else if (record_slots &&
MarkCompactCollector::IsOnEvacuationCandidate(object)) {
mark_compact_collector()->RecordSlot(slot, slot, object);
@@ -5361,6 +5377,7 @@ class HeapDebugUtils {
bool Heap::Setup(bool create_heap_objects) {
#ifdef DEBUG
+ allocation_timeout_ = FLAG_gc_interval;
debug_utils_ = new HeapDebugUtils(this);
#endif
@@ -5446,7 +5463,7 @@ bool Heap::Setup(bool create_heap_objects) {
// The large object code space may contain code or data. We set the memory
// to be non-executable here for safety, but this means we need to enable it
// explicitly when allocating large code objects.
- lo_space_ = new LargeObjectSpace(this, LO_SPACE);
+ lo_space_ = new LargeObjectSpace(this, max_old_generation_size_, LO_SPACE);
if (lo_space_ == NULL) return false;
if (!lo_space_->Setup()) return false;
if (create_heap_objects) {
@@ -5762,56 +5779,51 @@ class HeapObjectsFilter {
class UnreachableObjectsFilter : public HeapObjectsFilter {
public:
UnreachableObjectsFilter() {
- MarkUnreachableObjects();
+ MarkReachableObjects();
+ }
+
+ ~UnreachableObjectsFilter() {
+ Isolate::Current()->heap()->mark_compact_collector()->ClearMarkbits();
}
bool SkipObject(HeapObject* object) {
- if (IntrusiveMarking::IsMarked(object)) {
- IntrusiveMarking::ClearMark(object);
- return true;
- } else {
- return false;
- }
+ MarkBit mark_bit = Marking::MarkBitFrom(object);
+ return !mark_bit.Get();
}
private:
- class UnmarkingVisitor : public ObjectVisitor {
+ class MarkingVisitor : public ObjectVisitor {
public:
- UnmarkingVisitor() : list_(10) {}
+ MarkingVisitor() : marking_stack_(10) {}
void VisitPointers(Object** start, Object** end) {
for (Object** p = start; p < end; p++) {
if (!(*p)->IsHeapObject()) continue;
HeapObject* obj = HeapObject::cast(*p);
- if (IntrusiveMarking::IsMarked(obj)) {
- IntrusiveMarking::ClearMark(obj);
- list_.Add(obj);
+ MarkBit mark_bit = Marking::MarkBitFrom(obj);
+ if (!mark_bit.Get()) {
+ mark_bit.Set();
+ marking_stack_.Add(obj);
}
}
}
- bool can_process() { return !list_.is_empty(); }
-
- void ProcessNext() {
- HeapObject* obj = list_.RemoveLast();
- obj->Iterate(this);
+ void TransitiveClosure() {
+ while (!marking_stack_.is_empty()) {
+ HeapObject* obj = marking_stack_.RemoveLast();
+ obj->Iterate(this);
+ }
}
private:
- List<HeapObject*> list_;
+ List<HeapObject*> marking_stack_;
};
- void MarkUnreachableObjects() {
- HeapIterator iterator;
- for (HeapObject* obj = iterator.next();
- obj != NULL;
- obj = iterator.next()) {
- IntrusiveMarking::SetMark(obj);
- }
- UnmarkingVisitor visitor;
- HEAP->IterateRoots(&visitor, VISIT_ALL);
- while (visitor.can_process())
- visitor.ProcessNext();
+ void MarkReachableObjects() {
+ Heap* heap = Isolate::Current()->heap();
+ MarkingVisitor visitor;
+ heap->IterateRoots(&visitor, VISIT_ALL);
+ visitor.TransitiveClosure();
}
AssertNoAllocation no_alloc;
@@ -5839,13 +5851,8 @@ HeapIterator::~HeapIterator() {
void HeapIterator::Init() {
// Start the iteration.
- space_iterator_ = filtering_ == kNoFiltering ? new SpaceIterator :
- new SpaceIterator(Isolate::Current()->heap()->
- GcSafeSizeOfOldObjectFunction());
+ space_iterator_ = new SpaceIterator;
switch (filtering_) {
- case kFilterFreeListNodes:
- // TODO(gc): Not handled.
- break;
case kFilterUnreachable:
filter_ = new UnreachableObjectsFilter;
break;
@@ -6350,7 +6357,9 @@ void ExternalStringTable::CleanUp() {
old_space_strings_[last++] = old_space_strings_[i];
}
old_space_strings_.Rewind(last);
- Verify();
+ if (FLAG_verify_heap) {
+ Verify();
+ }
}
diff --git a/deps/v8/src/heap.h b/deps/v8/src/heap.h
index 6fb2d18c24..7c0b0ea8d6 100644
--- a/deps/v8/src/heap.h
+++ b/deps/v8/src/heap.h
@@ -64,18 +64,31 @@ inline Heap* _inline_get_heap_();
V(Oddball, null_value, NullValue) \
V(Oddball, true_value, TrueValue) \
V(Oddball, false_value, FalseValue) \
- V(Oddball, arguments_marker, ArgumentsMarker) \
- V(Oddball, frame_alignment_marker, FrameAlignmentMarker) \
+ V(Map, global_property_cell_map, GlobalPropertyCellMap) \
+ V(Map, shared_function_info_map, SharedFunctionInfoMap) \
+ V(Map, meta_map, MetaMap) \
+ V(Map, ascii_symbol_map, AsciiSymbolMap) \
+ V(Map, ascii_string_map, AsciiStringMap) \
V(Map, heap_number_map, HeapNumberMap) \
V(Map, global_context_map, GlobalContextMap) \
V(Map, fixed_array_map, FixedArrayMap) \
+ V(Map, code_map, CodeMap) \
V(Map, serialized_scope_info_map, SerializedScopeInfoMap) \
V(Map, fixed_cow_array_map, FixedCOWArrayMap) \
V(Map, fixed_double_array_map, FixedDoubleArrayMap) \
V(Object, no_interceptor_result_sentinel, NoInterceptorResultSentinel) \
- V(Map, meta_map, MetaMap) \
V(Map, hash_table_map, HashTableMap) \
+ V(FixedArray, empty_fixed_array, EmptyFixedArray) \
+ V(ByteArray, empty_byte_array, EmptyByteArray) \
+ V(FixedDoubleArray, empty_fixed_double_array, EmptyFixedDoubleArray) \
+ V(String, empty_string, EmptyString) \
+ V(DescriptorArray, empty_descriptor_array, EmptyDescriptorArray) \
V(Smi, stack_limit, StackLimit) \
+ V(Oddball, frame_alignment_marker, FrameAlignmentMarker) \
+ V(Oddball, arguments_marker, ArgumentsMarker) \
+ /* The first 32 roots above this line should be boring from a GC point of */ \
+ /* view. This means they are never in new space and never on a page that */ \
+ /* is being compacted. */ \
V(FixedArray, number_string_cache, NumberStringCache) \
V(Object, instanceof_cache_function, InstanceofCacheFunction) \
V(Object, instanceof_cache_map, InstanceofCacheMap) \
@@ -83,19 +96,12 @@ inline Heap* _inline_get_heap_();
V(FixedArray, single_character_string_cache, SingleCharacterStringCache) \
V(FixedArray, string_split_cache, StringSplitCache) \
V(Object, termination_exception, TerminationException) \
- V(FixedArray, empty_fixed_array, EmptyFixedArray) \
- V(ByteArray, empty_byte_array, EmptyByteArray) \
- V(FixedDoubleArray, empty_fixed_double_array, EmptyFixedDoubleArray) \
- V(String, empty_string, EmptyString) \
- V(DescriptorArray, empty_descriptor_array, EmptyDescriptorArray) \
V(Map, string_map, StringMap) \
- V(Map, ascii_string_map, AsciiStringMap) \
V(Map, symbol_map, SymbolMap) \
V(Map, cons_string_map, ConsStringMap) \
V(Map, cons_ascii_string_map, ConsAsciiStringMap) \
V(Map, sliced_string_map, SlicedStringMap) \
V(Map, sliced_ascii_string_map, SlicedAsciiStringMap) \
- V(Map, ascii_symbol_map, AsciiSymbolMap) \
V(Map, cons_symbol_map, ConsSymbolMap) \
V(Map, cons_ascii_symbol_map, ConsAsciiSymbolMap) \
V(Map, external_symbol_map, ExternalSymbolMap) \
@@ -120,10 +126,7 @@ inline Heap* _inline_get_heap_();
V(Map, catch_context_map, CatchContextMap) \
V(Map, with_context_map, WithContextMap) \
V(Map, block_context_map, BlockContextMap) \
- V(Map, code_map, CodeMap) \
V(Map, oddball_map, OddballMap) \
- V(Map, global_property_cell_map, GlobalPropertyCellMap) \
- V(Map, shared_function_info_map, SharedFunctionInfoMap) \
V(Map, message_object_map, JSMessageObjectMap) \
V(Map, foreign_map, ForeignMap) \
V(HeapNumber, nan_value, NanValue) \
@@ -1097,7 +1100,7 @@ class Heap {
inline void SetLastScriptId(Object* last_script_id);
// Generated code can embed this address to get access to the roots.
- Object** roots_address() { return roots_; }
+ Object** roots_array_start() { return roots_; }
Address* store_buffer_top_address() {
return reinterpret_cast<Address*>(&roots_[kStoreBufferTopRootIndex]);
@@ -1419,6 +1422,9 @@ class Heap {
// around a GC).
inline void CompletelyClearInstanceofCache();
+ // The roots that have an index less than this are always in old space.
+ static const int kOldSpaceRoots = 0x20;
+
private:
Heap();
@@ -1474,7 +1480,10 @@ class Heap {
int unflattened_strings_length_;
#define ROOT_ACCESSOR(type, name, camel_name) \
- inline void set_##name(type* value) { \
+ inline void set_##name(type* value) { \
+ /* The deserializer makes use of the fact that these common roots are */ \
+ /* never in new space and never on a page that is being compacted. */ \
+ ASSERT(k##camel_name##RootIndex >= kOldSpaceRoots || !InNewSpace(value)); \
roots_[k##camel_name##RootIndex] = value; \
}
ROOT_LIST(ROOT_ACCESSOR)
@@ -1954,7 +1963,6 @@ class HeapIterator BASE_EMBEDDED {
public:
enum HeapObjectsFiltering {
kNoFiltering,
- kFilterFreeListNodes,
kFilterUnreachable
};
diff --git a/deps/v8/src/hydrogen-instructions.cc b/deps/v8/src/hydrogen-instructions.cc
index fd0c3bb0d8..6f46509cac 100644
--- a/deps/v8/src/hydrogen-instructions.cc
+++ b/deps/v8/src/hydrogen-instructions.cc
@@ -587,11 +587,10 @@ void HInstruction::Verify() {
HBasicBlock* other_block = other_operand->block();
if (cur_block == other_block) {
if (!other_operand->IsPhi()) {
- HInstruction* cur = cur_block->first();
+ HInstruction* cur = this->previous();
while (cur != NULL) {
- ASSERT(cur != this); // We should reach other_operand before!
if (cur == other_operand) break;
- cur = cur->next();
+ cur = cur->previous();
}
// Must reach other operand in the same block!
ASSERT(cur == other_operand);
@@ -783,12 +782,21 @@ void HHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
void HTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
value()->PrintNameTo(stream);
- stream->Add(" == ");
- stream->Add(type_literal_->GetFlatContent().ToAsciiVector());
+ stream->Add(" == %o", *type_literal_);
HControlInstruction::PrintDataTo(stream);
}
+HValue* HConstant::Canonicalize() {
+ return HasNoUses() && !IsBlockEntry() ? NULL : this;
+}
+
+
+HValue* HTypeof::Canonicalize() {
+ return HasNoUses() && !IsBlockEntry() ? NULL : this;
+}
+
+
void HTypeof::PrintDataTo(StringStream* stream) {
value()->PrintNameTo(stream);
}
@@ -1138,15 +1146,16 @@ void HPhi::AddIndirectUsesTo(int* dest) {
void HSimulate::PrintDataTo(StringStream* stream) {
- stream->Add("id=%d ", ast_id());
- if (pop_count_ > 0) stream->Add("pop %d", pop_count_);
+ stream->Add("id=%d", ast_id());
+ if (pop_count_ > 0) stream->Add(" pop %d", pop_count_);
if (values_.length() > 0) {
if (pop_count_ > 0) stream->Add(" /");
for (int i = 0; i < values_.length(); ++i) {
- if (!HasAssignedIndexAt(i)) {
- stream->Add(" push ");
- } else {
+ if (i > 0) stream->Add(",");
+ if (HasAssignedIndexAt(i)) {
stream->Add(" var[%d] = ", GetAssignedIndexAt(i));
+ } else {
+ stream->Add(" push ");
}
values_[i]->PrintNameTo(stream);
}
@@ -1227,7 +1236,10 @@ void HConstant::PrintDataTo(StringStream* stream) {
bool HArrayLiteral::IsCopyOnWrite() const {
- return constant_elements()->map() == HEAP->fixed_cow_array_map();
+ Handle<FixedArray> constant_elements = this->constant_elements();
+ FixedArrayBase* constant_elements_values =
+ FixedArrayBase::cast(constant_elements->get(1));
+ return constant_elements_values->map() == HEAP->fixed_cow_array_map();
}
@@ -1392,7 +1404,7 @@ HLoadNamedFieldPolymorphic::HLoadNamedFieldPolymorphic(HValue* context,
i < types->length() && types_.length() < kMaxLoadPolymorphism;
++i) {
Handle<Map> map = types->at(i);
- LookupResult lookup;
+ LookupResult lookup(map->GetIsolate());
map->LookupInDescriptors(NULL, *name, &lookup);
if (lookup.IsProperty()) {
switch (lookup.type()) {
@@ -1445,14 +1457,14 @@ bool HLoadNamedFieldPolymorphic::DataEquals(HValue* value) {
void HLoadNamedFieldPolymorphic::PrintDataTo(StringStream* stream) {
object()->PrintNameTo(stream);
- stream->Add(" .");
+ stream->Add(".");
stream->Add(*String::cast(*name())->ToCString());
}
void HLoadNamedGeneric::PrintDataTo(StringStream* stream) {
object()->PrintNameTo(stream);
- stream->Add(" .");
+ stream->Add(".");
stream->Add(*String::cast(*name())->ToCString());
}
@@ -1549,10 +1561,10 @@ void HStoreNamedGeneric::PrintDataTo(StringStream* stream) {
void HStoreNamedField::PrintDataTo(StringStream* stream) {
object()->PrintNameTo(stream);
stream->Add(".");
- ASSERT(name()->IsString());
stream->Add(*String::cast(*name())->ToCString());
stream->Add(" = ");
value()->PrintNameTo(stream);
+ stream->Add(" @%d%s", offset(), is_in_object() ? "[in-object]" : "");
if (!transition().is_null()) {
stream->Add(" (transition map %p)", *transition());
}
@@ -1633,6 +1645,12 @@ void HStoreKeyedSpecializedArrayElement::PrintDataTo(
}
+void HTransitionElementsKind::PrintDataTo(StringStream* stream) {
+ object()->PrintNameTo(stream);
+ stream->Add(" %p -> %p", *original_map(), *transitioned_map());
+}
+
+
void HLoadGlobalCell::PrintDataTo(StringStream* stream) {
stream->Add("[%p]", *cell());
if (!details_.IsDontDelete()) stream->Add(" (deleteable)");
@@ -1746,6 +1764,12 @@ HType HInstanceOfKnownGlobal::CalculateInferredType() {
}
+HType HChange::CalculateInferredType() {
+ if (from().IsDouble() && to().IsTagged()) return HType::HeapNumber();
+ return type();
+}
+
+
HType HBitwiseBinaryOperation::CalculateInferredType() {
return HType::TaggedNumber();
}
@@ -1801,6 +1825,31 @@ HType HSar::CalculateInferredType() {
}
+HType HStringCharFromCode::CalculateInferredType() {
+ return HType::String();
+}
+
+
+HType HArrayLiteral::CalculateInferredType() {
+ return HType::JSArray();
+}
+
+
+HType HObjectLiteral::CalculateInferredType() {
+ return HType::JSObject();
+}
+
+
+HType HRegExpLiteral::CalculateInferredType() {
+ return HType::JSObject();
+}
+
+
+HType HFunctionLiteral::CalculateInferredType() {
+ return HType::JSObject();
+}
+
+
HValue* HUnaryMathOperation::EnsureAndPropagateNotMinusZero(
BitVector* visited) {
visited->Add(id());
diff --git a/deps/v8/src/hydrogen-instructions.h b/deps/v8/src/hydrogen-instructions.h
index 6b43f53da7..65fc4df4bd 100644
--- a/deps/v8/src/hydrogen-instructions.h
+++ b/deps/v8/src/hydrogen-instructions.h
@@ -171,6 +171,7 @@ class LChunkBuilder;
V(Throw) \
V(ToFastProperties) \
V(ToInt32) \
+ V(TransitionElementsKind) \
V(Typeof) \
V(TypeofIsAndBranch) \
V(UnaryMathOperation) \
@@ -397,6 +398,11 @@ class HType {
return type_ == kUninitialized;
}
+ bool IsHeapObject() {
+ ASSERT(type_ != kUninitialized);
+ return IsHeapNumber() || IsString() || IsNonPrimitive();
+ }
+
static HType TypeFromValue(Handle<Object> value);
const char* ToString();
@@ -1101,12 +1107,14 @@ class HChange: public HUnaryOperation {
ASSERT(!value->representation().IsNone() && !to.IsNone());
ASSERT(!value->representation().Equals(to));
set_representation(to);
+ set_type(HType::TaggedNumber());
SetFlag(kUseGVN);
if (deoptimize_on_undefined) SetFlag(kDeoptimizeOnUndefined);
if (is_truncating) SetFlag(kTruncatingToInt32);
}
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
+ virtual HType CalculateInferredType();
Representation from() { return value()->representation(); }
Representation to() { return representation(); }
@@ -1340,7 +1348,7 @@ class HPushArgument: public HUnaryOperation {
class HThisFunction: public HTemplateInstruction<0> {
public:
- HThisFunction() {
+ explicit HThisFunction(Handle<JSFunction> closure) : closure_(closure) {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
}
@@ -1349,10 +1357,18 @@ class HThisFunction: public HTemplateInstruction<0> {
return Representation::None();
}
+ Handle<JSFunction> closure() const { return closure_; }
+
DECLARE_CONCRETE_INSTRUCTION(ThisFunction)
protected:
- virtual bool DataEquals(HValue* other) { return true; }
+ virtual bool DataEquals(HValue* other) {
+ HThisFunction* b = HThisFunction::cast(other);
+ return *closure() == *b->closure();
+ }
+
+ private:
+ Handle<JSFunction> closure_;
};
@@ -2280,6 +2296,7 @@ class HConstant: public HTemplateInstruction<0> {
}
virtual bool EmitAtUses() { return !representation().IsDouble(); }
+ virtual HValue* Canonicalize();
virtual void PrintDataTo(StringStream* stream);
virtual HType CalculateInferredType();
bool IsInteger() const { return handle_->IsSmi(); }
@@ -3260,6 +3277,13 @@ class HLoadGlobalGeneric: public HTemplateInstruction<2> {
};
+static inline bool StoringValueNeedsWriteBarrier(HValue* value) {
+ return !value->type().IsBoolean()
+ && !value->type().IsSmi()
+ && !(value->IsConstant() && HConstant::cast(value)->ImmortalImmovable());
+}
+
+
class HStoreGlobalCell: public HUnaryOperation {
public:
HStoreGlobalCell(HValue* value,
@@ -3275,6 +3299,9 @@ class HStoreGlobalCell: public HUnaryOperation {
bool RequiresHoleCheck() {
return !details_.IsDontDelete() || details_.IsReadOnly();
}
+ bool NeedsWriteBarrier() {
+ return StoringValueNeedsWriteBarrier(value());
+ }
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
@@ -3355,13 +3382,6 @@ class HLoadContextSlot: public HUnaryOperation {
};
-static inline bool StoringValueNeedsWriteBarrier(HValue* value) {
- return !value->type().IsBoolean()
- && !value->type().IsSmi()
- && !(value->IsConstant() && HConstant::cast(value)->ImmortalImmovable());
-}
-
-
class HStoreContextSlot: public HTemplateInstruction<2> {
public:
HStoreContextSlot(HValue* context, int slot_index, HValue* value)
@@ -3700,9 +3720,9 @@ class HStoreNamedGeneric: public HTemplateInstruction<3> {
HValue* object,
Handle<String> name,
HValue* value,
- bool strict_mode)
+ StrictModeFlag strict_mode_flag)
: name_(name),
- strict_mode_(strict_mode) {
+ strict_mode_flag_(strict_mode_flag) {
SetOperandAt(0, object);
SetOperandAt(1, value);
SetOperandAt(2, context);
@@ -3713,7 +3733,7 @@ class HStoreNamedGeneric: public HTemplateInstruction<3> {
HValue* value() { return OperandAt(1); }
HValue* context() { return OperandAt(2); }
Handle<String> name() { return name_; }
- bool strict_mode() { return strict_mode_; }
+ StrictModeFlag strict_mode_flag() { return strict_mode_flag_; }
virtual void PrintDataTo(StringStream* stream);
@@ -3725,7 +3745,7 @@ class HStoreNamedGeneric: public HTemplateInstruction<3> {
private:
Handle<String> name_;
- bool strict_mode_;
+ StrictModeFlag strict_mode_flag_;
};
@@ -3886,6 +3906,44 @@ class HStoreKeyedGeneric: public HTemplateInstruction<4> {
};
+class HTransitionElementsKind: public HTemplateInstruction<1> {
+ public:
+ HTransitionElementsKind(HValue* object,
+ Handle<Map> original_map,
+ Handle<Map> transitioned_map)
+ : original_map_(original_map),
+ transitioned_map_(transitioned_map) {
+ SetOperandAt(0, object);
+ SetFlag(kUseGVN);
+ SetFlag(kDependsOnMaps);
+ set_representation(Representation::Tagged());
+ }
+
+ virtual Representation RequiredInputRepresentation(int index) {
+ return Representation::Tagged();
+ }
+
+ HValue* object() { return OperandAt(0); }
+ Handle<Map> original_map() { return original_map_; }
+ Handle<Map> transitioned_map() { return transitioned_map_; }
+
+ virtual void PrintDataTo(StringStream* stream);
+
+ DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind)
+
+ protected:
+ virtual bool DataEquals(HValue* other) {
+ HTransitionElementsKind* instr = HTransitionElementsKind::cast(other);
+ return original_map_.is_identical_to(instr->original_map()) &&
+ transitioned_map_.is_identical_to(instr->transitioned_map());
+ }
+
+ private:
+ Handle<Map> original_map_;
+ Handle<Map> transitioned_map_;
+};
+
+
class HStringAdd: public HBinaryOperation {
public:
HStringAdd(HValue* context, HValue* left, HValue* right)
@@ -3948,7 +4006,7 @@ class HStringCharFromCode: public HTemplateInstruction<2> {
HStringCharFromCode(HValue* context, HValue* char_code) {
SetOperandAt(0, context);
SetOperandAt(1, char_code);
- set_representation(Representation::Tagged());
+ set_representation(Representation::Tagged());
SetFlag(kUseGVN);
}
@@ -3957,6 +4015,7 @@ class HStringCharFromCode: public HTemplateInstruction<2> {
? Representation::Tagged()
: Representation::Integer32();
}
+ virtual HType CalculateInferredType();
HValue* context() { return OperandAt(0); }
HValue* value() { return OperandAt(1); }
@@ -4034,6 +4093,7 @@ class HArrayLiteral: public HMaterializedLiteral<1> {
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
}
+ virtual HType CalculateInferredType();
DECLARE_CONCRETE_INSTRUCTION(ArrayLiteral)
@@ -4068,6 +4128,7 @@ class HObjectLiteral: public HMaterializedLiteral<1> {
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
}
+ virtual HType CalculateInferredType();
DECLARE_CONCRETE_INSTRUCTION(ObjectLiteral)
@@ -4097,6 +4158,7 @@ class HRegExpLiteral: public HMaterializedLiteral<1> {
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
}
+ virtual HType CalculateInferredType();
DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral)
@@ -4121,6 +4183,7 @@ class HFunctionLiteral: public HTemplateInstruction<1> {
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
}
+ virtual HType CalculateInferredType();
DECLARE_CONCRETE_INSTRUCTION(FunctionLiteral)
@@ -4144,6 +4207,7 @@ class HTypeof: public HTemplateInstruction<2> {
HValue* context() { return OperandAt(0); }
HValue* value() { return OperandAt(1); }
+ virtual HValue* Canonicalize();
virtual void PrintDataTo(StringStream* stream);
virtual Representation RequiredInputRepresentation(int index) {
diff --git a/deps/v8/src/hydrogen.cc b/deps/v8/src/hydrogen.cc
index 2d471cc294..1460db8aef 100644
--- a/deps/v8/src/hydrogen.cc
+++ b/deps/v8/src/hydrogen.cc
@@ -164,10 +164,11 @@ void HBasicBlock::Finish(HControlInstruction* end) {
}
-void HBasicBlock::Goto(HBasicBlock* block) {
+void HBasicBlock::Goto(HBasicBlock* block, bool drop_extra) {
if (block->IsInlineReturnTarget()) {
AddInstruction(new(zone()) HLeaveInlined);
last_environment_ = last_environment()->outer();
+ if (drop_extra) last_environment_->Drop(1);
}
AddSimulate(AstNode::kNoNumber);
HGoto* instr = new(zone()) HGoto(block);
@@ -175,11 +176,14 @@ void HBasicBlock::Goto(HBasicBlock* block) {
}
-void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) {
+void HBasicBlock::AddLeaveInlined(HValue* return_value,
+ HBasicBlock* target,
+ bool drop_extra) {
ASSERT(target->IsInlineReturnTarget());
ASSERT(return_value != NULL);
AddInstruction(new(zone()) HLeaveInlined);
last_environment_ = last_environment()->outer();
+ if (drop_extra) last_environment_->Drop(1);
last_environment()->Push(return_value);
AddSimulate(AstNode::kNoNumber);
HGoto* instr = new(zone()) HGoto(target);
@@ -541,7 +545,7 @@ HConstant* HGraph::GetConstantHole() {
HGraphBuilder::HGraphBuilder(CompilationInfo* info,
TypeFeedbackOracle* oracle)
: function_state_(NULL),
- initial_function_state_(this, info, oracle),
+ initial_function_state_(this, info, oracle, false),
ast_context_(NULL),
break_scope_(NULL),
graph_(NULL),
@@ -1499,6 +1503,9 @@ int HGlobalValueNumberer::CollectSideEffectsOnPathsToDominatedBlock(
block->block_id() < dominated->block_id() &&
visited_on_paths_.Add(block->block_id())) {
side_effects |= block_side_effects_[block->block_id()];
+ if (block->IsLoopHeader()) {
+ side_effects |= loop_side_effects_[block->block_id()];
+ }
side_effects |= CollectSideEffectsOnPathsToDominatedBlock(
dominator, block);
}
@@ -2005,11 +2012,13 @@ void HGraph::ComputeMinusZeroChecks() {
// a (possibly inlined) function.
FunctionState::FunctionState(HGraphBuilder* owner,
CompilationInfo* info,
- TypeFeedbackOracle* oracle)
+ TypeFeedbackOracle* oracle,
+ bool drop_extra)
: owner_(owner),
compilation_info_(info),
oracle_(oracle),
call_context_(NULL),
+ drop_extra_(drop_extra),
function_return_(NULL),
test_context_(NULL),
outer_(owner->function_state()) {
@@ -2168,8 +2177,8 @@ void TestContext::ReturnControl(HControlInstruction* instr, int ast_id) {
instr->SetSuccessorAt(0, empty_true);
instr->SetSuccessorAt(1, empty_false);
owner()->current_block()->Finish(instr);
- empty_true->Goto(if_true());
- empty_false->Goto(if_false());
+ empty_true->Goto(if_true(), owner()->function_state()->drop_extra());
+ empty_false->Goto(if_false(), owner()->function_state()->drop_extra());
owner()->set_current_block(NULL);
}
@@ -2190,8 +2199,8 @@ void TestContext::BuildBranch(HValue* value) {
HBranch* test = new(zone()) HBranch(value, empty_true, empty_false, expected);
builder->current_block()->Finish(test);
- empty_true->Goto(if_true());
- empty_false->Goto(if_false());
+ empty_true->Goto(if_true(), owner()->function_state()->drop_extra());
+ empty_false->Goto(if_false(), owner()->function_state()->drop_extra());
builder->set_current_block(NULL);
}
@@ -2652,12 +2661,14 @@ void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
test->if_false());
} else if (context->IsEffect()) {
CHECK_ALIVE(VisitForEffect(stmt->expression()));
- current_block()->Goto(function_return());
+ current_block()->Goto(function_return(), function_state()->drop_extra());
} else {
ASSERT(context->IsValue());
CHECK_ALIVE(VisitForValue(stmt->expression()));
HValue* return_value = environment()->Pop();
- current_block()->AddLeaveInlined(return_value, function_return());
+ current_block()->AddLeaveInlined(return_value,
+ function_return(),
+ function_state()->drop_extra());
}
set_current_block(NULL);
}
@@ -3156,7 +3167,7 @@ void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
return ast_context()->ReturnInstruction(instr, expr->id());
}
- LookupResult lookup;
+ LookupResult lookup(isolate());
GlobalPropertyAccess type =
LookupGlobalProperty(variable, &lookup, false);
@@ -3276,7 +3287,7 @@ void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
literal,
name,
value,
- function_strict_mode());
+ function_strict_mode_flag());
AddInstruction(store);
AddSimulate(key->id());
} else {
@@ -3337,11 +3348,8 @@ void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
HValue* value = Pop();
if (!Smi::IsValid(i)) return Bailout("Non-smi key in array literal");
- // Load the elements array before the first store.
- if (elements == NULL) {
- elements = new(zone()) HLoadElements(literal);
- AddInstruction(elements);
- }
+ elements = new(zone()) HLoadElements(literal);
+ AddInstruction(elements);
HValue* key = AddInstruction(
new(zone()) HConstant(Handle<Object>(Smi::FromInt(i)),
@@ -3365,10 +3373,10 @@ void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
set_current_block(check_smi_only_elements);
HCompareConstantEqAndBranch* smi_elements_check =
new(zone()) HCompareConstantEqAndBranch(elements_kind,
- FAST_SMI_ONLY_ELEMENTS,
+ FAST_ELEMENTS,
Token::EQ_STRICT);
- smi_elements_check->SetSuccessorAt(0, store_generic);
- smi_elements_check->SetSuccessorAt(1, store_fast_edgesplit2);
+ smi_elements_check->SetSuccessorAt(0, store_fast_edgesplit2);
+ smi_elements_check->SetSuccessorAt(1, store_generic);
current_block()->Finish(smi_elements_check);
store_fast_edgesplit2->Finish(new(zone()) HGoto(store_fast));
@@ -3457,7 +3465,7 @@ HInstruction* HGraphBuilder::BuildStoreNamedGeneric(HValue* object,
object,
name,
value,
- function_strict_mode());
+ function_strict_mode_flag());
}
@@ -3471,7 +3479,7 @@ HInstruction* HGraphBuilder::BuildStoreNamed(HValue* object,
Handle<String> name = Handle<String>::cast(key->handle());
ASSERT(!name.is_null());
- LookupResult lookup;
+ LookupResult lookup(isolate());
SmallMapList* types = expr->GetReceiverTypes();
bool is_monomorphic = expr->IsMonomorphic() &&
ComputeStoredField(types->first(), name, &lookup);
@@ -3495,7 +3503,7 @@ void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr,
HBasicBlock* join = NULL;
for (int i = 0; i < types->length() && count < kMaxStorePolymorphism; ++i) {
Handle<Map> map = types->at(i);
- LookupResult lookup;
+ LookupResult lookup(isolate());
if (ComputeStoredField(map, name, &lookup)) {
if (count == 0) {
AddInstruction(new(zone()) HCheckNonSmi(object)); // Only needed once.
@@ -3578,7 +3586,7 @@ void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
ASSERT(!name.is_null());
SmallMapList* types = expr->GetReceiverTypes();
- LookupResult lookup;
+ LookupResult lookup(isolate());
if (expr->IsMonomorphic()) {
instr = BuildStoreNamed(object, value, expr);
@@ -3623,7 +3631,7 @@ void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var,
HValue* value,
int position,
int ast_id) {
- LookupResult lookup;
+ LookupResult lookup(isolate());
GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, true);
if (type == kUseCell) {
Handle<GlobalObject> global(info()->global_object());
@@ -3642,7 +3650,7 @@ void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var,
global_object,
var->name(),
value,
- function_strict_mode());
+ function_strict_mode_flag());
instr->set_position(position);
AddInstruction(instr);
ASSERT(instr->HasSideEffects());
@@ -3938,7 +3946,7 @@ HInstruction* HGraphBuilder::BuildLoadNamed(HValue* obj,
Property* expr,
Handle<Map> map,
Handle<String> name) {
- LookupResult lookup;
+ LookupResult lookup(isolate());
map->LookupInDescriptors(NULL, *name, &lookup);
if (lookup.IsProperty() && lookup.type() == FIELD) {
return BuildLoadNamedField(obj,
@@ -4037,11 +4045,8 @@ HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements,
HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object,
HValue* key,
HValue* val,
- Expression* expr,
+ Handle<Map> map,
bool is_store) {
- ASSERT(expr->IsMonomorphic());
- Handle<Map> map = expr->GetMonomorphicReceiverType();
- AddInstruction(new(zone()) HCheckNonSmi(object));
HInstruction* mapcheck = AddInstruction(new(zone()) HCheckMap(object, map));
bool fast_smi_only_elements = map->has_fast_smi_only_elements();
bool fast_elements = map->has_fast_elements();
@@ -4091,7 +4096,6 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
bool* has_side_effects) {
*has_side_effects = false;
AddInstruction(new(zone()) HCheckNonSmi(object));
- AddInstruction(HCheckInstanceType::NewIsSpecObject(object));
SmallMapList* maps = prop->GetReceiverTypes();
bool todo_external_array = false;
@@ -4101,15 +4105,55 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
type_todo[i] = false;
}
+ // Elements_kind transition support.
+ MapHandleList transition_target(maps->length());
+ // Collect possible transition targets.
+ MapHandleList possible_transitioned_maps(maps->length());
for (int i = 0; i < maps->length(); ++i) {
- ASSERT(maps->at(i)->IsMap());
- type_todo[maps->at(i)->elements_kind()] = true;
- if (maps->at(i)->elements_kind()
- >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND) {
- todo_external_array = true;
+ Handle<Map> map = maps->at(i);
+ ElementsKind elements_kind = map->elements_kind();
+ if (elements_kind == FAST_DOUBLE_ELEMENTS ||
+ elements_kind == FAST_ELEMENTS) {
+ possible_transitioned_maps.Add(map);
}
}
+ // Get transition target for each map (NULL == no transition).
+ for (int i = 0; i < maps->length(); ++i) {
+ Handle<Map> map = maps->at(i);
+ Handle<Map> transitioned_map =
+ map->FindTransitionedMap(&possible_transitioned_maps);
+ transition_target.Add(transitioned_map);
+ }
+ int num_untransitionable_maps = 0;
+ Handle<Map> untransitionable_map;
+ for (int i = 0; i < maps->length(); ++i) {
+ Handle<Map> map = maps->at(i);
+ ASSERT(map->IsMap());
+ if (!transition_target.at(i).is_null()) {
+ object = AddInstruction(new(zone()) HTransitionElementsKind(
+ object, map, transition_target.at(i)));
+ } else {
+ type_todo[map->elements_kind()] = true;
+ if (map->elements_kind() >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND) {
+ todo_external_array = true;
+ }
+ num_untransitionable_maps++;
+ untransitionable_map = map;
+ }
+ }
+
+ // If only one map is left after transitioning, handle this case
+ // monomorphically.
+ if (num_untransitionable_maps == 1) {
+ HInstruction* instr = AddInstruction(BuildMonomorphicElementAccess(
+ object, key, val, untransitionable_map, is_store));
+ *has_side_effects |= instr->HasSideEffects();
+ instr->set_position(position);
+ return is_store ? NULL : instr;
+ }
+
+ AddInstruction(HCheckInstanceType::NewIsSpecObject(object));
HBasicBlock* join = graph()->CreateBasicBlock();
HInstruction* elements_kind_instr =
@@ -4241,7 +4285,9 @@ HValue* HGraphBuilder::HandleKeyedElementAccess(HValue* obj,
ASSERT(!expr->IsPropertyName());
HInstruction* instr = NULL;
if (expr->IsMonomorphic()) {
- instr = BuildMonomorphicElementAccess(obj, key, val, expr, is_store);
+ Handle<Map> map = expr->GetMonomorphicReceiverType();
+ AddInstruction(new(zone()) HCheckNonSmi(obj));
+ instr = BuildMonomorphicElementAccess(obj, key, val, map, is_store);
} else if (expr->GetReceiverTypes() != NULL &&
!expr->GetReceiverTypes()->is_empty()) {
return HandlePolymorphicElementAccess(
@@ -4269,7 +4315,7 @@ HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object,
object,
key,
value,
- function_strict_mode());
+ function_strict_mode_flag());
}
bool HGraphBuilder::TryArgumentsAccess(Property* expr) {
@@ -4511,7 +4557,7 @@ void HGraphBuilder::TraceInline(Handle<JSFunction> target,
}
-bool HGraphBuilder::TryInline(Call* expr) {
+bool HGraphBuilder::TryInline(Call* expr, bool drop_extra) {
if (!FLAG_use_inlining) return false;
// The function call we are inlining is a method call if the call
@@ -4539,9 +4585,9 @@ bool HGraphBuilder::TryInline(Call* expr) {
return false;
}
- CompilationInfo* outer_info = info();
#if !defined(V8_TARGET_ARCH_IA32)
// Target must be able to use caller's context.
+ CompilationInfo* outer_info = info();
if (target->context() != outer_info->closure()->context() ||
outer_info->scope()->contains_with() ||
outer_info->scope()->num_heap_slots() > 0) {
@@ -4555,9 +4601,7 @@ bool HGraphBuilder::TryInline(Call* expr) {
HEnvironment* env = environment();
int current_level = 1;
while (env->outer() != NULL) {
- if (current_level == (FLAG_limit_inlining
- ? Compiler::kMaxInliningLevels
- : 2 * Compiler::kMaxInliningLevels)) {
+ if (current_level == Compiler::kMaxInliningLevels) {
TraceInline(target, caller, "inline depth limit reached");
return false;
}
@@ -4566,9 +4610,13 @@ bool HGraphBuilder::TryInline(Call* expr) {
}
// Don't inline recursive functions.
- if (*target_shared == outer_info->closure()->shared()) {
- TraceInline(target, caller, "target is recursive");
- return false;
+ for (FunctionState* state = function_state();
+ state != NULL;
+ state = state->outer()) {
+ if (state->compilation_info()->closure()->shared() == *target_shared) {
+ TraceInline(target, caller, "target is recursive");
+ return false;
+ }
}
// We don't want to add more than a certain number of nodes from inlining.
@@ -4665,7 +4713,10 @@ bool HGraphBuilder::TryInline(Call* expr) {
Handle<Code>(target_shared->code()),
Handle<Context>(target->context()->global_context()),
isolate());
- FunctionState target_state(this, &target_info, &target_oracle);
+ // The function state is new-allocated because we need to delete it
+ // in two different places.
+ FunctionState* target_state =
+ new FunctionState(this, &target_info, &target_oracle, drop_extra);
HConstant* undefined = graph()->GetConstantUndefined();
HEnvironment* inner_env =
@@ -4699,6 +4750,7 @@ bool HGraphBuilder::TryInline(Call* expr) {
TraceInline(target, caller, "inline graph construction failed");
target_shared->DisableOptimization(*target);
inline_bailout_ = true;
+ delete target_state;
return true;
}
@@ -4714,9 +4766,11 @@ bool HGraphBuilder::TryInline(Call* expr) {
ASSERT(function_return() != NULL);
ASSERT(call_context()->IsEffect() || call_context()->IsValue());
if (call_context()->IsEffect()) {
- current_block()->Goto(function_return());
+ current_block()->Goto(function_return(), drop_extra);
} else {
- current_block()->AddLeaveInlined(undefined, function_return());
+ current_block()->AddLeaveInlined(undefined,
+ function_return(),
+ drop_extra);
}
} else {
// The graph builder assumes control can reach both branches of a
@@ -4724,13 +4778,14 @@ bool HGraphBuilder::TryInline(Call* expr) {
// simply jumping to the false target.
//
// TODO(3168478): refactor to avoid this.
+ ASSERT(call_context()->IsTest());
HBasicBlock* empty_true = graph()->CreateBasicBlock();
HBasicBlock* empty_false = graph()->CreateBasicBlock();
HBranch* test = new(zone()) HBranch(undefined, empty_true, empty_false);
current_block()->Finish(test);
- empty_true->Goto(inlined_test_context()->if_true());
- empty_false->Goto(inlined_test_context()->if_false());
+ empty_true->Goto(inlined_test_context()->if_true(), drop_extra);
+ empty_false->Goto(inlined_test_context()->if_false(), drop_extra);
}
}
@@ -4742,19 +4797,21 @@ bool HGraphBuilder::TryInline(Call* expr) {
// Pop the return test context from the expression context stack.
ASSERT(ast_context() == inlined_test_context());
ClearInlinedTestContext();
+ delete target_state;
// Forward to the real test context.
if (if_true->HasPredecessor()) {
if_true->SetJoinId(expr->id());
HBasicBlock* true_target = TestContext::cast(ast_context())->if_true();
- if_true->Goto(true_target);
+ if_true->Goto(true_target, function_state()->drop_extra());
}
if (if_false->HasPredecessor()) {
if_false->SetJoinId(expr->id());
HBasicBlock* false_target = TestContext::cast(ast_context())->if_false();
- if_false->Goto(false_target);
+ if_false->Goto(false_target, function_state()->drop_extra());
}
set_current_block(NULL);
+ return true;
} else if (function_return()->HasPredecessor()) {
function_return()->SetJoinId(expr->id());
@@ -4762,7 +4819,7 @@ bool HGraphBuilder::TryInline(Call* expr) {
} else {
set_current_block(NULL);
}
-
+ delete target_state;
return true;
}
@@ -5014,7 +5071,7 @@ void HGraphBuilder::VisitCall(Call* expr) {
// If there is a global property cell for the name at compile time and
// access check is not enabled we assume that the function will not change
// and generate optimized code for calling the function.
- LookupResult lookup;
+ LookupResult lookup(isolate());
GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, false);
if (type == kUseCell &&
!info()->global_object()->IsAccessCheckNeeded()) {
@@ -5069,32 +5126,17 @@ void HGraphBuilder::VisitCall(Call* expr) {
PushAndAdd(receiver);
CHECK_ALIVE(VisitExpressions(expr->arguments()));
AddInstruction(new(zone()) HCheckFunction(function, expr->target()));
- if (TryInline(expr)) {
- // The function is lingering in the deoptimization environment.
- // Handle it by case analysis on the AST context.
- if (ast_context()->IsEffect()) {
- Drop(1);
- } else if (ast_context()->IsValue()) {
- HValue* result = Pop();
- Drop(1);
- Push(result);
- } else if (ast_context()->IsTest()) {
- TestContext* context = TestContext::cast(ast_context());
- if (context->if_true()->HasPredecessor()) {
- context->if_true()->last_environment()->Drop(1);
- }
- if (context->if_false()->HasPredecessor()) {
- context->if_true()->last_environment()->Drop(1);
- }
- } else {
- UNREACHABLE();
- }
+ if (TryInline(expr, true)) { // Drop function from environment.
return;
} else {
call = PreProcessCall(new(zone()) HInvokeFunction(context,
function,
argument_count));
+ call->set_position(expr->position());
+ AddInstruction(call);
+ AddSimulate(expr->id());
Drop(1); // The function.
+ return ast_context()->ReturnValue(call);
}
} else {
@@ -5304,7 +5346,6 @@ void HGraphBuilder::VisitBitNot(UnaryOperation* expr) {
void HGraphBuilder::VisitNot(UnaryOperation* expr) {
- // TODO(svenpanne) Perhaps a switch/virtual function is nicer here.
if (ast_context()->IsTest()) {
TestContext* context = TestContext::cast(ast_context());
VisitForControl(expr->expression(),
@@ -5791,38 +5832,68 @@ Representation HGraphBuilder::ToRepresentation(TypeInfo info) {
void HGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* expr,
- Expression* sub_expr,
+ HTypeof* typeof_expr,
Handle<String> check) {
- CHECK_ALIVE(VisitForTypeOf(sub_expr));
- HValue* value = Pop();
+ // Note: The HTypeof itself is removed during canonicalization, if possible.
+ HValue* value = typeof_expr->value();
HTypeofIsAndBranch* instr = new(zone()) HTypeofIsAndBranch(value, check);
instr->set_position(expr->position());
return ast_context()->ReturnControl(instr, expr->id());
}
-bool HGraphBuilder::TryLiteralCompare(CompareOperation* expr) {
- Expression *sub_expr;
- Handle<String> check;
- if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) {
- HandleLiteralCompareTypeof(expr, sub_expr, check);
+static bool MatchLiteralCompareNil(HValue* left,
+ Token::Value op,
+ HValue* right,
+ Handle<Object> nil,
+ HValue** expr) {
+ if (left->IsConstant() &&
+ HConstant::cast(left)->handle().is_identical_to(nil) &&
+ Token::IsEqualityOp(op)) {
+ *expr = right;
return true;
}
+ return false;
+}
- if (expr->IsLiteralCompareUndefined(&sub_expr)) {
- HandleLiteralCompareNil(expr, sub_expr, kUndefinedValue);
- return true;
- }
- if (expr->IsLiteralCompareNull(&sub_expr)) {
- HandleLiteralCompareNil(expr, sub_expr, kNullValue);
+static bool MatchLiteralCompareTypeof(HValue* left,
+ Token::Value op,
+ HValue* right,
+ HTypeof** typeof_expr,
+ Handle<String>* check) {
+ if (left->IsTypeof() &&
+ Token::IsEqualityOp(op) &&
+ right->IsConstant() &&
+ HConstant::cast(right)->HasStringValue()) {
+ *typeof_expr = HTypeof::cast(left);
+ *check = Handle<String>::cast(HConstant::cast(right)->handle());
return true;
}
-
return false;
}
+static bool IsLiteralCompareTypeof(HValue* left,
+ Token::Value op,
+ HValue* right,
+ HTypeof** typeof_expr,
+ Handle<String>* check) {
+ return MatchLiteralCompareTypeof(left, op, right, typeof_expr, check) ||
+ MatchLiteralCompareTypeof(right, op, left, typeof_expr, check);
+}
+
+
+static bool IsLiteralCompareNil(HValue* left,
+ Token::Value op,
+ HValue* right,
+ Handle<Object> nil,
+ HValue** expr) {
+ return MatchLiteralCompareNil(left, op, right, nil, expr) ||
+ MatchLiteralCompareNil(right, op, left, nil, expr);
+}
+
+
void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
@@ -5840,11 +5911,9 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
return ast_context()->ReturnControl(instr, expr->id());
}
- // Check for special cases that compare against literals.
- if (TryLiteralCompare(expr)) return;
-
TypeInfo type_info = oracle()->CompareType(expr);
// Check if this expression was ever executed according to type feedback.
+ // Note that for the special typeof/null/undefined cases we get unknown here.
if (type_info.IsUninitialized()) {
AddInstruction(new(zone()) HSoftDeoptimize);
current_block()->MarkAsDeoptimizing();
@@ -5859,6 +5928,20 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
HValue* left = Pop();
Token::Value op = expr->op();
+ HTypeof* typeof_expr = NULL;
+ Handle<String> check;
+ if (IsLiteralCompareTypeof(left, op, right, &typeof_expr, &check)) {
+ return HandleLiteralCompareTypeof(expr, typeof_expr, check);
+ }
+ HValue* sub_expr = NULL;
+ Factory* f = graph()->isolate()->factory();
+ if (IsLiteralCompareNil(left, op, right, f->undefined_value(), &sub_expr)) {
+ return HandleLiteralCompareNil(expr, sub_expr, kUndefinedValue);
+ }
+ if (IsLiteralCompareNil(left, op, right, f->null_value(), &sub_expr)) {
+ return HandleLiteralCompareNil(expr, sub_expr, kNullValue);
+ }
+
if (op == Token::INSTANCEOF) {
// Check to see if the rhs of the instanceof is a global function not
// residing in new space. If it is we assume that the function will stay the
@@ -5871,7 +5954,7 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
!info()->global_object()->IsAccessCheckNeeded()) {
Handle<String> name = proxy->name();
Handle<GlobalObject> global(info()->global_object());
- LookupResult lookup;
+ LookupResult lookup(isolate());
global->Lookup(*name, &lookup);
if (lookup.IsProperty() &&
lookup.type() == NORMAL &&
@@ -5947,13 +6030,11 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
void HGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr,
- Expression* sub_expr,
+ HValue* value,
NilValue nil) {
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
- CHECK_ALIVE(VisitForValue(sub_expr));
- HValue* value = Pop();
EqualityKind kind =
expr->op() == Token::EQ_STRICT ? kStrictEquality : kNonStrictEquality;
HIsNilAndBranch* instr = new(zone()) HIsNilAndBranch(value, kind, nil);
@@ -5966,7 +6047,8 @@ void HGraphBuilder::VisitThisFunction(ThisFunction* expr) {
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
- HThisFunction* self = new(zone()) HThisFunction;
+ HThisFunction* self = new(zone()) HThisFunction(
+ function_state()->compilation_info()->closure());
return ast_context()->ReturnInstruction(self, expr->id());
}
@@ -5979,7 +6061,9 @@ void HGraphBuilder::VisitDeclaration(Declaration* decl) {
void HGraphBuilder::HandleDeclaration(VariableProxy* proxy,
VariableMode mode,
FunctionLiteral* function) {
- if (mode == LET) return Bailout("unsupported let declaration");
+ if (mode == LET || mode == CONST_HARMONY) {
+ return Bailout("unsupported harmony declaration");
+ }
Variable* var = proxy->var();
switch (var->location()) {
case Variable::UNALLOCATED:
diff --git a/deps/v8/src/hydrogen.h b/deps/v8/src/hydrogen.h
index b66042c2cb..2d08dc8e79 100644
--- a/deps/v8/src/hydrogen.h
+++ b/deps/v8/src/hydrogen.h
@@ -121,7 +121,7 @@ class HBasicBlock: public ZoneObject {
void Finish(HControlInstruction* last);
void FinishExit(HControlInstruction* instruction);
- void Goto(HBasicBlock* block);
+ void Goto(HBasicBlock* block, bool drop_extra = false);
int PredecessorIndexOf(HBasicBlock* predecessor) const;
void AddSimulate(int ast_id) { AddInstruction(CreateSimulate(ast_id)); }
@@ -133,7 +133,9 @@ class HBasicBlock: public ZoneObject {
// Add the inlined function exit sequence, adding an HLeaveInlined
// instruction and updating the bailout environment.
- void AddLeaveInlined(HValue* return_value, HBasicBlock* target);
+ void AddLeaveInlined(HValue* return_value,
+ HBasicBlock* target,
+ bool drop_extra = false);
// If a target block is tagged as an inline function return, all
// predecessors should contain the inlined exit sequence:
@@ -603,16 +605,18 @@ class TestContext: public AstContext {
};
-class FunctionState BASE_EMBEDDED {
+class FunctionState {
public:
FunctionState(HGraphBuilder* owner,
CompilationInfo* info,
- TypeFeedbackOracle* oracle);
+ TypeFeedbackOracle* oracle,
+ bool drop_extra);
~FunctionState();
CompilationInfo* compilation_info() { return compilation_info_; }
TypeFeedbackOracle* oracle() { return oracle_; }
AstContext* call_context() { return call_context_; }
+ bool drop_extra() { return drop_extra_; }
HBasicBlock* function_return() { return function_return_; }
TestContext* test_context() { return test_context_; }
void ClearInlinedTestContext() {
@@ -632,6 +636,10 @@ class FunctionState BASE_EMBEDDED {
// inlined. NULL when not inlining.
AstContext* call_context_;
+ // Indicate if we have to drop an extra value from the environment on
+ // return from inlined functions.
+ bool drop_extra_;
+
// When inlining in an effect of value context, this is the return block.
// It is NULL otherwise. When inlining in a test context, there are a
// pair of return blocks in the context. When not inlining, there is no
@@ -728,6 +736,8 @@ class HGraphBuilder: public AstVisitor {
TypeFeedbackOracle* oracle() const { return function_state()->oracle(); }
+ FunctionState* function_state() const { return function_state_; }
+
private:
// Type of a member function that generates inline code for a native function.
typedef void (HGraphBuilder::*InlineFunctionGenerator)(CallRuntime* call);
@@ -746,7 +756,6 @@ class HGraphBuilder: public AstVisitor {
static const int kMaxSourceSize = 600;
// Simple accessors.
- FunctionState* function_state() const { return function_state_; }
void set_function_state(FunctionState* state) { function_state_ = state; }
AstContext* ast_context() const { return ast_context_; }
@@ -769,8 +778,8 @@ class HGraphBuilder: public AstVisitor {
void ClearInlinedTestContext() {
function_state()->ClearInlinedTestContext();
}
- bool function_strict_mode() {
- return function_state()->compilation_info()->is_strict_mode();
+ StrictModeFlag function_strict_mode_flag() {
+ return function_state()->compilation_info()->strict_mode_flag();
}
// Generators for inline runtime functions.
@@ -883,7 +892,7 @@ class HGraphBuilder: public AstVisitor {
// Try to optimize fun.apply(receiver, arguments) pattern.
bool TryCallApply(Call* expr);
- bool TryInline(Call* expr);
+ bool TryInline(Call* expr, bool drop_extra = false);
bool TryInlineBuiltinFunction(Call* expr,
HValue* receiver,
Handle<Map> receiver_map,
@@ -912,12 +921,11 @@ class HGraphBuilder: public AstVisitor {
HValue* receiver,
SmallMapList* types,
Handle<String> name);
- bool TryLiteralCompare(CompareOperation* expr);
void HandleLiteralCompareTypeof(CompareOperation* expr,
- Expression* sub_expr,
+ HTypeof* typeof_expr,
Handle<String> check);
void HandleLiteralCompareNil(CompareOperation* expr,
- Expression* sub_expr,
+ HValue* value,
NilValue nil);
HStringCharCodeAt* BuildStringCharCodeAt(HValue* context,
@@ -951,7 +959,7 @@ class HGraphBuilder: public AstVisitor {
HInstruction* BuildMonomorphicElementAccess(HValue* object,
HValue* key,
HValue* val,
- Expression* expr,
+ Handle<Map> map,
bool is_store);
HValue* HandlePolymorphicElementAccess(HValue* object,
HValue* key,
diff --git a/deps/v8/src/ia32/assembler-ia32-inl.h b/deps/v8/src/ia32/assembler-ia32-inl.h
index 446aa3e2de..2e9fcb6c54 100644
--- a/deps/v8/src/ia32/assembler-ia32-inl.h
+++ b/deps/v8/src/ia32/assembler-ia32-inl.h
@@ -88,10 +88,10 @@ int RelocInfo::target_address_size() {
}
-void RelocInfo::set_target_address(Address target) {
+void RelocInfo::set_target_address(Address target, WriteBarrierMode mode) {
Assembler::set_target_address_at(pc_, target);
ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
- 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));
@@ -117,11 +117,13 @@ 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);
Memory::Object_at(pc_) = target;
CPU::FlushICache(pc_, sizeof(Address));
- 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));
}
@@ -151,12 +153,13 @@ 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;
CPU::FlushICache(pc_, sizeof(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/ia32/builtins-ia32.cc b/deps/v8/src/ia32/builtins-ia32.cc
index 53ade3a6c9..70e342d3d7 100644
--- a/deps/v8/src/ia32/builtins-ia32.cc
+++ b/deps/v8/src/ia32/builtins-ia32.cc
@@ -915,10 +915,6 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
}
-// Number of empty elements to allocate for an empty array.
-static const int kPreallocatedArrayElements = 4;
-
-
// Allocate an empty JSArray. The allocated array is put into the result
// register. If the parameter initial_capacity is larger than zero an elements
// backing store is allocated with this size and filled with the hole values.
@@ -929,10 +925,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.
__ mov(scratch1, FieldOperand(array_function,
JSFunction::kPrototypeOrInitialMapOffset));
@@ -990,7 +985,6 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
// Fill the FixedArray with the hole value. Inline the code if short.
// Reconsider loop unfolding if kPreallocatedArrayElements gets changed.
static const int kLoopUnfoldLimit = 4;
- STATIC_ASSERT(kPreallocatedArrayElements <= kLoopUnfoldLimit);
if (initial_capacity <= kLoopUnfoldLimit) {
// Use a scratch register here to have only one reloc info when unfolding
// the loop.
@@ -1153,7 +1147,6 @@ static void ArrayNativeCode(MacroAssembler* masm,
ebx,
ecx,
edi,
- kPreallocatedArrayElements,
&prepare_generic_code_call);
__ IncrementCounter(masm->isolate()->counters()->array_function_native(), 1);
__ pop(ebx);
@@ -1182,7 +1175,7 @@ static void ArrayNativeCode(MacroAssembler* masm,
__ mov(eax, Operand(esp, i * kPointerSize));
__ mov(Operand(esp, (i + 1) * kPointerSize), eax);
}
- __ add(esp, Immediate(2 * kPointerSize)); // Drop two stack slots.
+ __ Drop(2); // Drop two stack slots.
__ push(Immediate(0)); // Treat this as a call with argc of zero.
__ jmp(&empty_array);
diff --git a/deps/v8/src/ia32/code-stubs-ia32.cc b/deps/v8/src/ia32/code-stubs-ia32.cc
index 1e886e202b..d7d1d9c3cc 100644
--- a/deps/v8/src/ia32/code-stubs-ia32.cc
+++ b/deps/v8/src/ia32/code-stubs-ia32.cc
@@ -34,6 +34,7 @@
#include "isolate.h"
#include "jsregexp.h"
#include "regexp-macro-assembler.h"
+#include "stub-cache.h"
namespace v8 {
namespace internal {
@@ -238,7 +239,12 @@ void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
// [esp + (3 * 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 ecx and check if we need to create a
@@ -261,6 +267,9 @@ void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
if (mode_ == CLONE_ELEMENTS) {
message = "Expected (writable) fixed array";
expected_map = factory->fixed_array_map();
+ } else if (mode_ == CLONE_DOUBLE_ELEMENTS) {
+ message = "Expected (writable) fixed double array";
+ expected_map = factory->fixed_double_array_map();
} else {
ASSERT(mode_ == COPY_ON_WRITE_ELEMENTS);
message = "Expected copy-on-write fixed array";
@@ -293,9 +302,24 @@ void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
__ mov(FieldOperand(eax, JSArray::kElementsOffset), edx);
// Copy the elements array.
- for (int i = 0; i < elements_size; i += kPointerSize) {
- __ mov(ebx, FieldOperand(ecx, i));
- __ mov(FieldOperand(edx, i), ebx);
+ if (mode_ == CLONE_ELEMENTS) {
+ for (int i = 0; i < elements_size; i += kPointerSize) {
+ __ mov(ebx, FieldOperand(ecx, i));
+ __ mov(FieldOperand(edx, i), ebx);
+ }
+ } else {
+ ASSERT(mode_ == CLONE_DOUBLE_ELEMENTS);
+ int i;
+ for (i = 0; i < FixedDoubleArray::kHeaderSize; i += kPointerSize) {
+ __ mov(ebx, FieldOperand(ecx, i));
+ __ mov(FieldOperand(edx, i), ebx);
+ }
+ while (i < elements_size) {
+ __ fld_d(FieldOperand(ecx, i));
+ __ fstp_d(FieldOperand(edx, i));
+ i += kDoubleSize;
+ }
+ ASSERT(i == elements_size);
}
}
@@ -3858,11 +3882,11 @@ void NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm,
Register scratch = scratch2;
// Load the number string cache.
- ExternalReference roots_address =
- ExternalReference::roots_address(masm->isolate());
+ ExternalReference roots_array_start =
+ ExternalReference::roots_array_start(masm->isolate());
__ mov(scratch, Immediate(Heap::kNumberStringCacheRootIndex));
__ mov(number_string_cache,
- Operand::StaticArray(scratch, times_pointer_size, roots_address));
+ Operand::StaticArray(scratch, times_pointer_size, roots_array_start));
// Make the hash mask from the length of the number string cache. It
// contains two elements (number and string) for each cache entry.
__ mov(mask, FieldOperand(number_string_cache, FixedArray::kLengthOffset));
@@ -4830,8 +4854,8 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
static const int8_t kCmpEdiImmediateByte2 = BitCast<int8_t, uint8_t>(0xff);
static const int8_t kMovEaxImmediateByte = BitCast<int8_t, uint8_t>(0xb8);
- ExternalReference roots_address =
- ExternalReference::roots_address(masm->isolate());
+ ExternalReference roots_array_start =
+ ExternalReference::roots_array_start(masm->isolate());
ASSERT_EQ(object.code(), InstanceofStub::left().code());
ASSERT_EQ(function.code(), InstanceofStub::right().code());
@@ -4853,22 +4877,23 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
// Look up the function and the map in the instanceof cache.
Label miss;
__ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex));
- __ cmp(function,
- Operand::StaticArray(scratch, times_pointer_size, roots_address));
+ __ cmp(function, Operand::StaticArray(scratch,
+ times_pointer_size,
+ roots_array_start));
__ j(not_equal, &miss, Label::kNear);
__ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex));
__ cmp(map, Operand::StaticArray(
- scratch, times_pointer_size, roots_address));
+ scratch, times_pointer_size, roots_array_start));
__ j(not_equal, &miss, Label::kNear);
__ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex));
__ mov(eax, Operand::StaticArray(
- scratch, times_pointer_size, roots_address));
+ scratch, times_pointer_size, roots_array_start));
__ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
__ bind(&miss);
}
// 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);
@@ -4878,9 +4903,10 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
// map and function. The cached answer will be set when it is known below.
if (!HasCallSiteInlineCheck()) {
__ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex));
- __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address), map);
+ __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_array_start),
+ map);
__ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex));
- __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address),
+ __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_array_start),
function);
} else {
// The constants for the code patching are based on no push instructions
@@ -4917,7 +4943,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
__ Set(eax, Immediate(0));
__ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex));
__ mov(Operand::StaticArray(scratch,
- times_pointer_size, roots_address), eax);
+ times_pointer_size, roots_array_start), eax);
} else {
// Get return address and delta to inlined map check.
__ mov(eax, factory->true_value());
@@ -4939,7 +4965,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
__ Set(eax, Immediate(Smi::FromInt(1)));
__ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex));
__ mov(Operand::StaticArray(
- scratch, times_pointer_size, roots_address), eax);
+ scratch, times_pointer_size, roots_array_start), eax);
} else {
// Get return address and delta to inlined map check.
__ mov(eax, factory->false_value());
@@ -5728,11 +5754,11 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
// Load the symbol table.
Register symbol_table = c2;
- ExternalReference roots_address =
- ExternalReference::roots_address(masm->isolate());
+ ExternalReference roots_array_start =
+ ExternalReference::roots_array_start(masm->isolate());
__ mov(scratch, Immediate(Heap::kSymbolTableRootIndex));
__ mov(symbol_table,
- Operand::StaticArray(scratch, times_pointer_size, roots_address));
+ Operand::StaticArray(scratch, times_pointer_size, roots_array_start));
// Calculate capacity mask from the symbol table capacity.
Register mask = scratch2;
@@ -6515,7 +6541,67 @@ void ICCompareStub::GenerateMiss(MacroAssembler* masm) {
// 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.
-MaybeObject* StringDictionaryLookupStub::GenerateNegativeLookup(
+void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
+ Label* miss,
+ Label* done,
+ Register properties,
+ Handle<String> name,
+ Register r0) {
+ ASSERT(name->IsSymbol());
+
+ // 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++) {
+ // Compute the masked index: (hash + i + i * i) & mask.
+ Register index = r0;
+ // Capacity is smi 2^n.
+ __ mov(index, FieldOperand(properties, kCapacityOffset));
+ __ dec(index);
+ __ and_(index,
+ Immediate(Smi::FromInt(name->Hash() +
+ StringDictionary::GetProbeOffset(i))));
+
+ // Scale the index by multiplying by the entry size.
+ ASSERT(StringDictionary::kEntrySize == 3);
+ __ lea(index, Operand(index, index, times_2, 0)); // index *= 3.
+ Register entity_name = r0;
+ // Having undefined at this place means the name is not contained.
+ ASSERT_EQ(kSmiTagSize, 1);
+ __ mov(entity_name, Operand(properties, index, times_half_pointer_size,
+ kElementsStartOffset - kHeapObjectTag));
+ __ cmp(entity_name, masm->isolate()->factory()->undefined_value());
+ __ j(equal, done);
+
+ // Stop if found the property.
+ __ cmp(entity_name, Handle<String>(name));
+ __ j(equal, miss);
+
+ // Check if the entry name is not a symbol.
+ __ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset));
+ __ test_b(FieldOperand(entity_name, Map::kInstanceTypeOffset),
+ kIsSymbolMask);
+ __ j(zero, miss);
+ }
+
+ StringDictionaryLookupStub stub(properties,
+ r0,
+ r0,
+ StringDictionaryLookupStub::NEGATIVE_LOOKUP);
+ __ push(Immediate(Handle<Object>(name)));
+ __ push(Immediate(name->Hash()));
+ __ CallStub(&stub);
+ __ test(r0, r0);
+ __ j(not_zero, miss);
+ __ jmp(done);
+}
+
+
+// TODO(kmillikin): Eliminate this function when the stub cache is fully
+// handlified.
+MaybeObject* StringDictionaryLookupStub::TryGenerateNegativeLookup(
MacroAssembler* masm,
Label* miss,
Label* done,
@@ -6749,6 +6835,13 @@ struct AheadOfTimeWriteBarrierStubList kAheadOfTime[] = {
{ ebx, edx, ecx, EMIT_REMEMBERED_SET},
// KeyedStoreStubCompiler::GenerateStoreFastElement.
{ edi, edx, ecx, EMIT_REMEMBERED_SET},
+ // ElementsTransitionGenerator::GenerateSmiOnlyToObject
+ // and ElementsTransitionGenerator::GenerateSmiOnlyToDouble
+ // and ElementsTransitionGenerator::GenerateDoubleToObject
+ { edx, ebx, edi, EMIT_REMEMBERED_SET},
+ // ElementsTransitionGenerator::GenerateDoubleToObject
+ { eax, edx, esi, EMIT_REMEMBERED_SET},
+ { edx, eax, edi, EMIT_REMEMBERED_SET},
// Null termination.
{ no_reg, no_reg, no_reg, EMIT_REMEMBERED_SET}
};
@@ -6991,7 +7084,6 @@ void RecordWriteStub::CheckNeedsToInformIncrementalMarker(
// Fall through when we need to inform the incremental marker.
}
-
#undef __
} } // namespace v8::internal
diff --git a/deps/v8/src/ia32/code-stubs-ia32.h b/deps/v8/src/ia32/code-stubs-ia32.h
index 2a7d316f47..8775344a5f 100644
--- a/deps/v8/src/ia32/code-stubs-ia32.h
+++ b/deps/v8/src/ia32/code-stubs-ia32.h
@@ -421,7 +421,16 @@ class StringDictionaryLookupStub: public CodeStub {
void Generate(MacroAssembler* masm);
- MUST_USE_RESULT static MaybeObject* GenerateNegativeLookup(
+ static void GenerateNegativeLookup(MacroAssembler* masm,
+ Label* miss,
+ Label* done,
+ Register properties,
+ Handle<String> name,
+ Register r0);
+
+ // 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/ia32/codegen-ia32.cc b/deps/v8/src/ia32/codegen-ia32.cc
index f901b6f888..7dc302bf6f 100644
--- a/deps/v8/src/ia32/codegen-ia32.cc
+++ b/deps/v8/src/ia32/codegen-ia32.cc
@@ -30,6 +30,7 @@
#if defined(V8_TARGET_ARCH_IA32)
#include "codegen.h"
+#include "macro-assembler.h"
namespace v8 {
namespace internal {
@@ -265,6 +266,263 @@ OS::MemCopyFunction CreateMemCopyFunction() {
#undef __
+// -------------------------------------------------------------------------
+// Code generators
+
+#define __ ACCESS_MASM(masm)
+
+void ElementsTransitionGenerator::GenerateSmiOnlyToObject(
+ MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- eax : value
+ // -- ebx : target map
+ // -- ecx : key
+ // -- edx : receiver
+ // -- esp[0] : return address
+ // -----------------------------------
+ // Set transitioned map.
+ __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
+ __ RecordWriteField(edx,
+ HeapObject::kMapOffset,
+ ebx,
+ edi,
+ kDontSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+}
+
+
+void ElementsTransitionGenerator::GenerateSmiOnlyToDouble(
+ MacroAssembler* masm, Label* fail) {
+ // ----------- S t a t e -------------
+ // -- eax : value
+ // -- ebx : target map
+ // -- ecx : key
+ // -- edx : receiver
+ // -- esp[0] : return address
+ // -----------------------------------
+ Label loop, entry, convert_hole, gc_required;
+ __ push(eax);
+ __ push(ebx);
+
+ __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
+ __ mov(edi, FieldOperand(edi, FixedArray::kLengthOffset));
+
+ // Allocate new FixedDoubleArray.
+ // edx: receiver
+ // edi: length of source FixedArray (smi-tagged)
+ __ lea(esi, Operand(edi, times_4, FixedDoubleArray::kHeaderSize));
+ __ AllocateInNewSpace(esi, eax, ebx, no_reg, &gc_required, TAG_OBJECT);
+
+ // eax: destination FixedDoubleArray
+ // edi: number of elements
+ // edx: receiver
+ __ mov(FieldOperand(eax, HeapObject::kMapOffset),
+ Immediate(masm->isolate()->factory()->fixed_double_array_map()));
+ __ mov(FieldOperand(eax, FixedDoubleArray::kLengthOffset), edi);
+ __ mov(esi, FieldOperand(edx, JSObject::kElementsOffset));
+ // Replace receiver's backing store with newly created FixedDoubleArray.
+ __ mov(FieldOperand(edx, JSObject::kElementsOffset), eax);
+ __ mov(ebx, eax);
+ __ RecordWriteField(edx,
+ JSObject::kElementsOffset,
+ ebx,
+ edi,
+ kDontSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+
+ __ mov(edi, FieldOperand(esi, FixedArray::kLengthOffset));
+
+ // Prepare for conversion loop.
+ ExternalReference canonical_the_hole_nan_reference =
+ ExternalReference::address_of_the_hole_nan();
+ XMMRegister the_hole_nan = xmm1;
+ if (CpuFeatures::IsSupported(SSE2)) {
+ CpuFeatures::Scope use_sse2(SSE2);
+ __ movdbl(the_hole_nan,
+ Operand::StaticVariable(canonical_the_hole_nan_reference));
+ }
+ __ jmp(&entry);
+
+ // Call into runtime if GC is required.
+ __ bind(&gc_required);
+ // Restore registers before jumping into runtime.
+ __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+ __ pop(ebx);
+ __ pop(eax);
+ __ jmp(fail);
+
+ // Convert and copy elements
+ // esi: source FixedArray
+ // edi: number of elements to convert/copy
+ __ bind(&loop);
+ __ sub(edi, Immediate(Smi::FromInt(1)));
+ __ mov(ebx, FieldOperand(esi, edi, times_2, FixedArray::kHeaderSize));
+ // ebx: current element from source
+ // edi: index of current element
+ __ JumpIfNotSmi(ebx, &convert_hole);
+
+ // Normal smi, convert it to double and store.
+ __ SmiUntag(ebx);
+ if (CpuFeatures::IsSupported(SSE2)) {
+ CpuFeatures::Scope fscope(SSE2);
+ __ cvtsi2sd(xmm0, ebx);
+ __ movdbl(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize),
+ xmm0);
+ } else {
+ __ push(ebx);
+ __ fild_s(Operand(esp, 0));
+ __ pop(ebx);
+ __ fstp_d(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize));
+ }
+ __ jmp(&entry);
+
+ // Found hole, store hole_nan_as_double instead.
+ __ bind(&convert_hole);
+ if (CpuFeatures::IsSupported(SSE2)) {
+ CpuFeatures::Scope use_sse2(SSE2);
+ __ movdbl(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize),
+ the_hole_nan);
+ } else {
+ __ fld_d(Operand::StaticVariable(canonical_the_hole_nan_reference));
+ __ fstp_d(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize));
+ }
+
+ __ bind(&entry);
+ __ test(edi, edi);
+ __ j(not_zero, &loop);
+
+ __ pop(ebx);
+ __ pop(eax);
+ // eax: value
+ // ebx: target map
+ // Set transitioned map.
+ __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
+ __ RecordWriteField(edx,
+ HeapObject::kMapOffset,
+ ebx,
+ edi,
+ kDontSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+ // Restore esi.
+ __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+}
+
+
+void ElementsTransitionGenerator::GenerateDoubleToObject(
+ MacroAssembler* masm, Label* fail) {
+ // ----------- S t a t e -------------
+ // -- eax : value
+ // -- ebx : target map
+ // -- ecx : key
+ // -- edx : receiver
+ // -- esp[0] : return address
+ // -----------------------------------
+ Label loop, entry, convert_hole, gc_required;
+ __ push(eax);
+ __ push(edx);
+ __ push(ebx);
+
+ __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
+ __ mov(ebx, FieldOperand(edi, FixedDoubleArray::kLengthOffset));
+
+ // Allocate new FixedArray.
+ // ebx: length of source FixedDoubleArray (smi-tagged)
+ __ lea(edi, Operand(ebx, times_2, FixedArray::kHeaderSize));
+ __ AllocateInNewSpace(edi, eax, esi, no_reg, &gc_required, TAG_OBJECT);
+
+ // eax: destination FixedArray
+ // ebx: number of elements
+ __ mov(FieldOperand(eax, HeapObject::kMapOffset),
+ Immediate(masm->isolate()->factory()->fixed_array_map()));
+ __ mov(FieldOperand(eax, FixedArray::kLengthOffset), ebx);
+ __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
+
+ __ jmp(&entry);
+
+ // Call into runtime if GC is required.
+ __ bind(&gc_required);
+ __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+ __ pop(ebx);
+ __ pop(edx);
+ __ pop(eax);
+ __ jmp(fail);
+
+ // Box doubles into heap numbers.
+ // edi: source FixedDoubleArray
+ // eax: destination FixedArray
+ __ bind(&loop);
+ __ sub(ebx, Immediate(Smi::FromInt(1)));
+ // ebx: index of current element (smi-tagged)
+ uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
+ __ cmp(FieldOperand(edi, ebx, times_4, offset), Immediate(kHoleNanUpper32));
+ __ j(equal, &convert_hole);
+
+ // Non-hole double, copy value into a heap number.
+ __ AllocateHeapNumber(edx, esi, no_reg, &gc_required);
+ // edx: new heap number
+ if (CpuFeatures::IsSupported(SSE2)) {
+ CpuFeatures::Scope fscope(SSE2);
+ __ movdbl(xmm0,
+ FieldOperand(edi, ebx, times_4, FixedDoubleArray::kHeaderSize));
+ __ movdbl(FieldOperand(edx, HeapNumber::kValueOffset), xmm0);
+ } else {
+ __ mov(esi, FieldOperand(edi, ebx, times_4, FixedDoubleArray::kHeaderSize));
+ __ mov(FieldOperand(edx, HeapNumber::kValueOffset), esi);
+ __ mov(esi, FieldOperand(edi, ebx, times_4, offset));
+ __ mov(FieldOperand(edx, HeapNumber::kValueOffset + kPointerSize), esi);
+ }
+ __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize), edx);
+ __ mov(esi, ebx);
+ __ RecordWriteArray(eax,
+ edx,
+ esi,
+ kDontSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+ __ jmp(&entry, Label::kNear);
+
+ // Replace the-hole NaN with the-hole pointer.
+ __ bind(&convert_hole);
+ __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize),
+ masm->isolate()->factory()->the_hole_value());
+
+ __ bind(&entry);
+ __ test(ebx, ebx);
+ __ j(not_zero, &loop);
+
+ __ pop(ebx);
+ __ pop(edx);
+ // ebx: target map
+ // edx: receiver
+ // Set transitioned map.
+ __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
+ __ RecordWriteField(edx,
+ HeapObject::kMapOffset,
+ ebx,
+ edi,
+ kDontSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+ // Replace receiver's backing store with newly created and filled FixedArray.
+ __ mov(FieldOperand(edx, JSObject::kElementsOffset), eax);
+ __ RecordWriteField(edx,
+ JSObject::kElementsOffset,
+ eax,
+ edi,
+ kDontSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+
+ // Restore registers.
+ __ pop(eax);
+ __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+}
+
+#undef __
+
} } // namespace v8::internal
#endif // V8_TARGET_ARCH_IA32
diff --git a/deps/v8/src/ia32/deoptimizer-ia32.cc b/deps/v8/src/ia32/deoptimizer-ia32.cc
index 02cc4ebd3b..db6c16b2df 100644
--- a/deps/v8/src/ia32/deoptimizer-ia32.cc
+++ b/deps/v8/src/ia32/deoptimizer-ia32.cc
@@ -258,16 +258,13 @@ void Deoptimizer::PatchStackCheckCodeAt(Code* unoptimized_code,
Assembler::set_target_address_at(call_target_address,
replacement_code->entry());
- RelocInfo rinfo(call_target_address,
- 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, call_target_address, replacement_code);
}
-void Deoptimizer::RevertStackCheckCodeAt(Address pc_after,
+void Deoptimizer::RevertStackCheckCodeAt(Code* unoptimized_code,
+ Address pc_after,
Code* check_code,
Code* replacement_code) {
Address call_target_address = pc_after - kIntSize;
@@ -283,8 +280,8 @@ void Deoptimizer::RevertStackCheckCodeAt(Address pc_after,
Assembler::set_target_address_at(call_target_address,
check_code->entry());
- check_code->GetHeap()->incremental_marking()->
- RecordCodeTargetPatch(call_target_address, check_code);
+ check_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
+ unoptimized_code, call_target_address, check_code);
}
diff --git a/deps/v8/src/ia32/disasm-ia32.cc b/deps/v8/src/ia32/disasm-ia32.cc
index 04edc5f427..da22390119 100644
--- a/deps/v8/src/ia32/disasm-ia32.cc
+++ b/deps/v8/src/ia32/disasm-ia32.cc
@@ -179,6 +179,10 @@ class InstructionTable {
public:
InstructionTable();
const InstructionDesc& Get(byte x) const { return instructions_[x]; }
+ static InstructionTable* get_instance() {
+ static InstructionTable table;
+ return &table;
+ }
private:
InstructionDesc instructions_[256];
@@ -259,15 +263,13 @@ void InstructionTable::AddJumpConditionalShort() {
}
-static InstructionTable instruction_table;
-
-
// The IA32 disassembler implementation.
class DisassemblerIA32 {
public:
DisassemblerIA32(const NameConverter& converter,
bool abort_on_unimplemented = true)
: converter_(converter),
+ instruction_table_(InstructionTable::get_instance()),
tmp_buffer_pos_(0),
abort_on_unimplemented_(abort_on_unimplemented) {
tmp_buffer_[0] = '\0';
@@ -281,11 +283,11 @@ class DisassemblerIA32 {
private:
const NameConverter& converter_;
+ InstructionTable* instruction_table_;
v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
unsigned int tmp_buffer_pos_;
bool abort_on_unimplemented_;
-
enum {
eax = 0,
ecx = 1,
@@ -884,7 +886,7 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
}
bool processed = true; // Will be set to false if the current instruction
// is not in 'instructions' table.
- const InstructionDesc& idesc = instruction_table.Get(*data);
+ const InstructionDesc& idesc = instruction_table_->Get(*data);
switch (idesc.type) {
case ZERO_OPERANDS_INSTR:
AppendToBuffer(idesc.mnem);
diff --git a/deps/v8/src/ia32/full-codegen-ia32.cc b/deps/v8/src/ia32/full-codegen-ia32.cc
index 33d5cabad7..de5dc06eb3 100644
--- a/deps/v8/src/ia32/full-codegen-ia32.cc
+++ b/deps/v8/src/ia32/full-codegen-ia32.cc
@@ -266,7 +266,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());
}
@@ -711,6 +714,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);
@@ -722,7 +727,7 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
Comment cmnt(masm_, "[ Declaration");
VisitForAccumulatorValue(function);
__ mov(StackOperand(variable), result_register());
- } else if (mode == CONST || mode == LET) {
+ } else if (binding_needs_init) {
Comment cmnt(masm_, "[ Declaration");
__ mov(StackOperand(variable),
Immediate(isolate()->factory()->the_hole_value()));
@@ -754,7 +759,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");
__ mov(ContextOperand(esi, variable->index()),
Immediate(isolate()->factory()->the_hole_value()));
@@ -767,9 +772,13 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
Comment cmnt(masm_, "[ Declaration");
__ push(esi);
__ push(Immediate(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;
__ push(Immediate(Smi::FromInt(attr)));
// Push initial value, if any.
// Note: For variables we must not push an initial value (such as
@@ -778,7 +787,7 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
increment_stack_height(3);
if (function != NULL) {
VisitForStackValue(function);
- } else if (mode == CONST || mode == LET) {
+ } else if (binding_needs_init) {
__ push(Immediate(isolate()->factory()->the_hole_value()));
increment_stack_height();
} else {
@@ -920,11 +929,17 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
__ push(eax);
increment_stack_height();
+ // Check for proxies.
+ Label call_runtime;
+ STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
+ __ CmpObjectType(eax, LAST_JS_PROXY_TYPE, ecx);
+ __ j(below_equal, &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;
__ mov(ecx, eax);
__ bind(&next);
@@ -995,9 +1010,17 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
__ jmp(&loop);
// We got a fixed array in register eax. Iterate through that.
+ Label non_proxy;
__ bind(&fixed_array);
- __ push(Immediate(Smi::FromInt(0))); // Map (0) - force slow check.
- __ push(eax);
+ __ mov(ebx, Immediate(Smi::FromInt(1))); // Smi indicates slow check
+ __ mov(ecx, Operand(esp, 0 * kPointerSize)); // Get enumerated object
+ STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
+ __ CmpObjectType(ecx, LAST_JS_PROXY_TYPE, ecx);
+ __ j(above, &non_proxy);
+ __ mov(ebx, Immediate(Smi::FromInt(0))); // Zero indicates proxy
+ __ bind(&non_proxy);
+ __ push(ebx); // Smi
+ __ push(eax); // Array
__ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset));
__ push(eax); // Fixed array length (as smi).
__ push(Immediate(Smi::FromInt(0))); // Initial index.
@@ -1014,17 +1037,23 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
__ mov(ebx, Operand(esp, 2 * kPointerSize));
__ mov(ebx, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize));
- // 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 edx.
__ mov(edx, Operand(esp, 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;
__ mov(ecx, Operand(esp, 4 * kPointerSize));
__ cmp(edx, FieldOperand(ecx, HeapObject::kMapOffset));
__ j(equal, &update_each, Label::kNear);
+ // For proxies, no filtering is done.
+ // TODO(rossberg): What if only a prototype is a proxy? Not specified yet.
+ ASSERT(Smi::FromInt(0) == 0);
+ __ test(edx, edx);
+ __ j(zero, &update_each);
+
// Convert the entry to a string or null if it isn't a property
// anymore. If the property has been removed while iterating, we
// just skip it.
@@ -1079,7 +1108,7 @@ void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
!pretenure &&
scope()->is_function_scope() &&
info->num_literals() == 0) {
- FastNewClosureStub stub(info->strict_mode() ? kStrictMode : kNonStrictMode);
+ FastNewClosureStub stub(info->strict_mode_flag());
__ push(Immediate(info));
__ CallStub(&stub);
} else {
@@ -1109,7 +1138,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.
__ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
Immediate(0));
@@ -1123,7 +1152,7 @@ void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var,
// If no outer scope calls eval, we do not need to check more
// context extensions. If we have reached an eval scope, we check
// all extensions from this point.
- 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();
}
@@ -1168,7 +1197,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.
__ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
Immediate(0));
@@ -1206,12 +1235,13 @@ void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var,
Variable* local = var->local_if_not_shadowed();
__ mov(eax, ContextSlotOperandCheckExtensions(local, slow));
if (local->mode() == CONST ||
+ local->mode() == CONST_HARMONY ||
local->mode() == LET) {
__ cmp(eax, isolate()->factory()->the_hole_value());
__ j(not_equal, done);
if (local->mode() == CONST) {
__ mov(eax, isolate()->factory()->undefined_value());
- } else { // LET
+ } else { // LET || CONST_HARMONY
__ push(Immediate(var->name()));
__ CallRuntime(Runtime::kThrowReferenceError, 1);
}
@@ -1247,7 +1277,7 @@ 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.
@@ -1255,10 +1285,14 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
GetVar(eax, var);
__ cmp(eax, isolate()->factory()->the_hole_value());
__ j(not_equal, &done, Label::kNear);
- 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.
__ push(Immediate(var->name()));
__ CallRuntime(Runtime::kThrowReferenceError, 1);
- } else { // CONST
+ } else {
+ // Uninitalized const bindings outside of harmony mode are unholed.
+ ASSERT(var->mode() == CONST);
__ mov(eax, isolate()->factory()->undefined_value());
}
__ bind(&done);
@@ -1448,12 +1482,18 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
ZoneList<Expression*>* subexprs = expr->values();
int length = subexprs->length();
+ Handle<FixedArray> constant_elements = expr->constant_elements();
+ ASSERT_EQ(2, constant_elements->length());
+ ElementsKind constant_elements_kind =
+ static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
+ Handle<FixedArrayBase> constant_elements_values(
+ FixedArrayBase::cast(constant_elements->get(1)));
__ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
__ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
__ push(Immediate(Smi::FromInt(expr->literal_index())));
- __ push(Immediate(expr->constant_elements()));
- if (expr->constant_elements()->map() ==
+ __ push(Immediate(constant_elements));
+ if (constant_elements_values->map() ==
isolate()->heap()->fixed_cow_array_map()) {
ASSERT(expr->depth() == 1);
FastCloneShallowArrayStub stub(
@@ -1465,8 +1505,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);
}
@@ -1492,22 +1538,61 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
// Store the subexpression value in the array's elements.
__ mov(ebx, Operand(esp, 0)); // Copy of array literal.
+ __ mov(edi, FieldOperand(ebx, JSObject::kMapOffset));
__ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
int offset = FixedArray::kHeaderSize + (i * kPointerSize);
- __ mov(FieldOperand(ebx, offset), result_register());
- Label no_map_change;
- __ JumpIfSmi(result_register(), &no_map_change);
+ Label element_done;
+ Label double_elements;
+ Label smi_element;
+ Label slow_elements;
+ Label fast_elements;
+ __ CheckFastElements(edi, &double_elements);
+
+ // FAST_SMI_ONLY_ELEMENTS or FAST_ELEMENTS
+ __ JumpIfSmi(result_register(), &smi_element);
+ __ CheckFastSmiOnlyElements(edi, &fast_elements, Label::kNear);
+
+ // Store into the array literal requires a elements transition. Call into
+ // the runtime.
+ __ bind(&slow_elements);
+ __ push(Operand(esp, 0)); // Copy of array literal.
+ __ push(Immediate(Smi::FromInt(i)));
+ __ push(result_register());
+ __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes
+ __ push(Immediate(Smi::FromInt(strict_mode_flag()))); // Strict mode.
+ __ CallRuntime(Runtime::kSetProperty, 5);
+ __ jmp(&element_done);
+
+ // Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS.
+ __ bind(&double_elements);
+ __ mov(ecx, Immediate(Smi::FromInt(i)));
+ __ StoreNumberToDoubleElements(result_register(),
+ ebx,
+ ecx,
+ edx,
+ xmm0,
+ &slow_elements,
+ false);
+ __ jmp(&element_done);
+
+ // Array literal has ElementsKind of FAST_ELEMENTS and value is an object.
+ __ bind(&fast_elements);
+ __ mov(FieldOperand(ebx, offset), result_register());
// Update the write barrier for the array store.
__ RecordWriteField(ebx, offset, result_register(), ecx,
kDontSaveFPRegs,
EMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
- __ mov(edi, FieldOperand(ebx, JSObject::kMapOffset));
- __ CheckFastSmiOnlyElements(edi, &no_map_change, Label::kNear);
- __ push(Operand(esp, 0));
- __ CallRuntime(Runtime::kNonSmiElementStored, 1);
- __ bind(&no_map_change);
+ __ jmp(&element_done);
+
+ // Array literal has ElementsKind of FAST_SMI_ONLY_ELEMENTS or
+ // FAST_ELEMENTS, and value is Smi.
+ __ bind(&smi_element);
+ __ mov(FieldOperand(ebx, offset), result_register());
+ // Fall through
+
+ __ bind(&element_done);
PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
}
@@ -1890,8 +1975,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, ecx);
if (FLAG_debug_code && op == Token::INIT_LET) {
@@ -2104,7 +2190,7 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) {
flags = static_cast<CallFunctionFlags>(flags | RECORD_CALL_TARGET);
}
CallFunctionStub stub(arg_count, flags);
- __ CallStub(&stub);
+ __ CallStub(&stub, expr->id());
if (record_call_target) {
// There is a one element cache in the instruction stream.
#ifdef DEBUG
@@ -2781,9 +2867,10 @@ void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) {
__ bind(&heapnumber_allocated);
__ PrepareCallCFunction(1, ebx);
- __ mov(Operand(esp, 0), Immediate(ExternalReference::isolate_address()));
- __ CallCFunction(ExternalReference::random_uint32_function(isolate()),
- 1);
+ __ mov(eax, ContextOperand(context_register(), Context::GLOBAL_INDEX));
+ __ mov(eax, FieldOperand(eax, GlobalObject::kGlobalContextOffset));
+ __ mov(Operand(esp, 0), eax);
+ __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
// Convert 32 random bits in eax to 0.(32 random bits) in a double
// by computing:
@@ -4147,33 +4234,25 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
case Token::EQ_STRICT:
case Token::EQ:
cc = equal;
- __ pop(edx);
break;
case Token::LT:
cc = less;
- __ pop(edx);
break;
case Token::GT:
- // Reverse left and right sizes to obtain ECMA-262 conversion order.
- cc = less;
- __ mov(edx, result_register());
- __ pop(eax);
+ cc = greater;
break;
case Token::LTE:
- // Reverse left and right sizes to obtain ECMA-262 conversion order.
- cc = greater_equal;
- __ mov(edx, result_register());
- __ pop(eax);
+ cc = less_equal;
break;
case Token::GTE:
cc = greater_equal;
- __ pop(edx);
break;
case Token::IN:
case Token::INSTANCEOF:
default:
UNREACHABLE();
}
+ __ pop(edx);
decrement_stack_height();
bool inline_smi_code = ShouldInlineSmiCase(op);
diff --git a/deps/v8/src/ia32/ic-ia32.cc b/deps/v8/src/ia32/ic-ia32.cc
index 8a98b179d3..1168932057 100644
--- a/deps/v8/src/ia32/ic-ia32.cc
+++ b/deps/v8/src/ia32/ic-ia32.cc
@@ -860,10 +860,10 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
// 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 -------------
// -- ecx : name
// -- edx : receiver
@@ -873,11 +873,11 @@ 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(masm, flags, edx, ecx, ebx,
- eax);
+ Isolate* isolate = masm->isolate();
+ isolate->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx, eax);
// If the stub cache probing failed, the receiver might be a value.
// For value objects, we use the map of the prototype objects for
@@ -903,9 +903,9 @@ static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
// Check for boolean.
__ bind(&non_string);
- __ cmp(edx, FACTORY->true_value());
+ __ cmp(edx, isolate->factory()->true_value());
__ j(equal, &boolean);
- __ cmp(edx, FACTORY->false_value());
+ __ cmp(edx, isolate->factory()->false_value());
__ j(not_equal, &miss);
__ bind(&boolean);
StubCompiler::GenerateLoadGlobalFunctionPrototype(
@@ -913,8 +913,7 @@ static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
// Probe the stub cache for the value object.
__ bind(&probe);
- Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx,
- no_reg);
+ isolate->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx, no_reg);
__ bind(&miss);
}
@@ -944,8 +943,9 @@ static void GenerateFunctionTailCall(MacroAssembler* masm,
NullCallWrapper(), CALL_AS_METHOD);
}
+
// The generated code falls through if the call should be handled by runtime.
-static void GenerateCallNormal(MacroAssembler* masm, int argc) {
+void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) {
// ----------- S t a t e -------------
// -- ecx : name
// -- esp[0] : return address
@@ -969,10 +969,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 -------------
// -- ecx : name
// -- esp[0] : return address
@@ -1029,7 +1029,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);
@@ -1043,7 +1043,7 @@ static void GenerateCallMiss(MacroAssembler* masm,
void CallIC::GenerateMegamorphic(MacroAssembler* masm,
int argc,
- Code::ExtraICState extra_ic_state) {
+ Code::ExtraICState extra_state) {
// ----------- S t a t e -------------
// -- ecx : name
// -- esp[0] : return address
@@ -1054,38 +1054,10 @@ void CallIC::GenerateMegamorphic(MacroAssembler* masm,
// Get the receiver of the function from the stack; 1 ~ return address.
__ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
- GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC, extra_ic_state);
-
- GenerateMiss(masm, argc, extra_ic_state);
-}
-
-
-void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
- // ----------- S t a t e -------------
- // -- ecx : name
- // -- esp[0] : return address
- // -- esp[(argc - n) * 4] : arg[n] (zero-based)
- // -- ...
- // -- esp[(argc + 1) * 4] : receiver
- // -----------------------------------
+ CallICBase::GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC,
+ extra_state);
- GenerateCallNormal(masm, argc);
- GenerateMiss(masm, argc, Code::kNoExtraICState);
-}
-
-
-void CallIC::GenerateMiss(MacroAssembler* masm,
- int argc,
- Code::ExtraICState extra_ic_state) {
- // ----------- S t a t e -------------
- // -- ecx : name
- // -- esp[0] : return address
- // -- esp[(argc - n) * 4] : arg[n] (zero-based)
- // -- ...
- // -- esp[(argc + 1) * 4] : receiver
- // -----------------------------------
-
- GenerateCallMiss(masm, argc, IC::kCallIC_Miss, extra_ic_state);
+ GenerateMiss(masm, argc, extra_state);
}
@@ -1187,10 +1159,8 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
__ bind(&lookup_monomorphic_cache);
__ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1);
- GenerateMonomorphicCacheProbe(masm,
- argc,
- Code::KEYED_CALL_IC,
- Code::kNoExtraICState);
+ CallICBase::GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC,
+ Code::kNoExtraICState);
// Fall through on miss.
__ bind(&slow_call);
@@ -1253,25 +1223,12 @@ void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
__ JumpIfSmi(ecx, &miss);
Condition cond = masm->IsObjectStringType(ecx, eax, eax);
__ j(NegateCondition(cond), &miss);
- GenerateCallNormal(masm, argc);
+ CallICBase::GenerateNormal(masm, argc);
__ bind(&miss);
GenerateMiss(masm, argc);
}
-void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) {
- // ----------- S t a t e -------------
- // -- ecx : name
- // -- esp[0] : return address
- // -- esp[(argc - n) * 4] : arg[n] (zero-based)
- // -- ...
- // -- esp[(argc + 1) * 4] : receiver
- // -----------------------------------
-
- GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss, Code::kNoExtraICState);
-}
-
-
void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : receiver
@@ -1580,6 +1537,51 @@ void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
}
+void KeyedStoreIC::GenerateTransitionElementsSmiToDouble(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- ebx : target map
+ // -- edx : receiver
+ // -- esp[0] : return address
+ // -----------------------------------
+ // Must return the modified receiver in eax.
+ if (!FLAG_trace_elements_transitions) {
+ Label fail;
+ ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &fail);
+ __ mov(eax, edx);
+ __ Ret();
+ __ bind(&fail);
+ }
+
+ __ pop(ebx);
+ __ push(edx);
+ __ push(ebx); // return address
+ __ TailCallRuntime(Runtime::kTransitionElementsSmiToDouble, 1, 1);
+}
+
+
+void KeyedStoreIC::GenerateTransitionElementsDoubleToObject(
+ MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- ebx : target map
+ // -- edx : receiver
+ // -- esp[0] : return address
+ // -----------------------------------
+ // Must return the modified receiver in eax.
+ if (!FLAG_trace_elements_transitions) {
+ Label fail;
+ ElementsTransitionGenerator::GenerateDoubleToObject(masm, &fail);
+ __ mov(eax, edx);
+ __ Ret();
+ __ bind(&fail);
+ }
+
+ __ pop(ebx);
+ __ push(edx);
+ __ push(ebx); // return address
+ __ TailCallRuntime(Runtime::kTransitionElementsDoubleToObject, 1, 1);
+}
+
+
#undef __
@@ -1591,11 +1593,9 @@ Condition CompareIC::ComputeCondition(Token::Value op) {
case Token::LT:
return less;
case Token::GT:
- // Reverse left and right operands to obtain ECMA-262 conversion order.
- return less;
+ return greater;
case Token::LTE:
- // Reverse left and right operands to obtain ECMA-262 conversion order.
- return greater_equal;
+ return less_equal;
case Token::GTE:
return greater_equal;
default:
diff --git a/deps/v8/src/ia32/lithium-codegen-ia32.cc b/deps/v8/src/ia32/lithium-codegen-ia32.cc
index 9e1fd34af3..d4cbbcec8f 100644
--- a/deps/v8/src/ia32/lithium-codegen-ia32.cc
+++ b/deps/v8/src/ia32/lithium-codegen-ia32.cc
@@ -355,6 +355,12 @@ int LCodeGen::ToInteger32(LConstantOperand* op) const {
}
+double LCodeGen::ToDouble(LConstantOperand* op) const {
+ Handle<Object> value = chunk_->LookupLiteral(op);
+ return value->Number();
+}
+
+
Immediate LCodeGen::ToImmediate(LOperand* op) {
LConstantOperand* const_op = LConstantOperand::cast(op);
Handle<Object> literal = chunk_->LookupLiteral(const_op);
@@ -1574,32 +1580,40 @@ Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
}
-void LCodeGen::EmitCmpI(LOperand* left, LOperand* right) {
- if (right->IsConstantOperand()) {
- __ cmp(ToOperand(left), ToImmediate(right));
- } else {
- __ cmp(ToRegister(left), ToOperand(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());
+ Condition cc = TokenToCondition(instr->op(), instr->is_double());
- if (instr->is_double()) {
- // Don't base result on EFLAGS when a NaN is involved. Instead
- // jump to the false block.
- __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
- __ j(parity_even, chunk_->GetAssemblyLabel(false_block));
+ 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()) {
+ // Don't base result on EFLAGS when a NaN is involved. Instead
+ // jump to the false block.
+ __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
+ __ j(parity_even, chunk_->GetAssemblyLabel(false_block));
+ } else {
+ if (right->IsConstantOperand()) {
+ __ cmp(ToRegister(left), ToImmediate(right));
+ } else if (left->IsConstantOperand()) {
+ __ cmp(ToOperand(right), ToImmediate(left));
+ // We transposed the operands. Reverse the condition.
+ cc = ReverseCondition(cc);
+ } else {
+ __ cmp(ToRegister(left), ToOperand(right));
+ }
+ }
+ EmitBranch(true_block, false_block, cc);
}
-
- Condition cc = TokenToCondition(instr->op(), instr->is_double());
- EmitBranch(true_block, false_block, cc);
}
@@ -2029,9 +2043,6 @@ void LCodeGen::DoCmpT(LCmpT* instr) {
CallCode(ic, RelocInfo::CODE_TARGET, instr);
Condition condition = ComputeCompareCondition(op);
- if (op == Token::GT || op == Token::LTE) {
- condition = ReverseCondition(condition);
- }
Label true_value, done;
__ test(eax, Operand(eax));
__ j(condition, &true_value, Label::kNear);
@@ -2116,12 +2127,18 @@ void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
__ mov(FieldOperand(object, offset), value);
// Cells are always in the remembered set.
- __ RecordWriteField(object,
- offset,
- value,
- address,
- 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(object,
+ offset,
+ value,
+ address,
+ kSaveFPRegs,
+ OMIT_REMEMBERED_SET,
+ check_needed);
+ }
}
@@ -2149,10 +2166,19 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
Register context = ToRegister(instr->context());
Register value = ToRegister(instr->value());
__ mov(ContextOperand(context, instr->slot_index()), value);
- 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;
Register temp = ToRegister(instr->TempAt(0));
int offset = Context::SlotOffset(instr->slot_index());
- __ RecordWriteContextSlot(context, offset, value, temp, kSaveFPRegs);
+ __ RecordWriteContextSlot(context,
+ offset,
+ value,
+ temp,
+ kSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ check_needed);
}
}
@@ -2173,7 +2199,7 @@ void LCodeGen::EmitLoadFieldOrConstantFunction(Register result,
Register object,
Handle<Map> type,
Handle<String> name) {
- LookupResult lookup;
+ LookupResult lookup(isolate());
type->LookupInDescriptors(NULL, *name, &lookup);
ASSERT(lookup.IsProperty() &&
(lookup.type() == FIELD || lookup.type() == CONSTANT_FUNCTION));
@@ -2614,7 +2640,7 @@ void LCodeGen::DoPushArgument(LPushArgument* instr) {
void LCodeGen::DoThisFunction(LThisFunction* instr) {
Register result = ToRegister(instr->result());
- __ mov(result, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
+ LoadHeapObject(result, instr->hydrogen()->closure());
}
@@ -3146,21 +3172,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()) {
__ mov(FieldOperand(object, offset), value);
- if (instr->needs_write_barrier()) {
+ if (instr->hydrogen()->NeedsWriteBarrier()) {
Register temp = ToRegister(instr->TempAt(0));
// Update the write barrier for the object for in-object properties.
- __ RecordWriteField(object, offset, value, temp, kSaveFPRegs);
+ __ RecordWriteField(object,
+ offset,
+ value,
+ temp,
+ kSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ check_needed);
}
} else {
Register temp = ToRegister(instr->TempAt(0));
__ mov(temp, FieldOperand(object, JSObject::kPropertiesOffset));
__ mov(FieldOperand(temp, offset), value);
- 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(temp, offset, value, object, kSaveFPRegs);
+ __ RecordWriteField(temp,
+ offset,
+ value,
+ object,
+ kSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ check_needed);
}
}
}
@@ -3259,13 +3300,21 @@ 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.
__ lea(key,
FieldOperand(elements,
key,
times_pointer_size,
FixedArray::kHeaderSize));
- __ RecordWrite(elements, key, value, kSaveFPRegs);
+ __ RecordWrite(elements,
+ key,
+ value,
+ kSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ check_needed);
}
}
@@ -3303,6 +3352,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());
+
+ Handle<Map> from_map = instr->original_map();
+ Handle<Map> to_map = instr->transitioned_map();
+ ElementsKind from_kind = from_map->elements_kind();
+ ElementsKind to_kind = to_map->elements_kind();
+
+ Label not_applicable;
+ __ cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map);
+ __ j(not_equal, &not_applicable);
+ __ mov(new_map_reg, to_map);
+ if (from_kind == FAST_SMI_ONLY_ELEMENTS && to_kind == FAST_ELEMENTS) {
+ Register object_reg = ToRegister(instr->object());
+ __ mov(FieldOperand(object_reg, HeapObject::kMapOffset), new_map_reg);
+ // Write barrier.
+ ASSERT_NE(instr->temp_reg(), NULL);
+ __ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg,
+ ToRegister(instr->temp_reg()), 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(edx));
+ ASSERT(new_map_reg.is(ebx));
+ __ 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(edx));
+ ASSERT(new_map_reg.is(ebx));
+ __ mov(fixed_object_reg, object_reg);
+ CallCode(isolate()->builtins()->TransitionElementsDoubleToObject(),
+ RelocInfo::CODE_TARGET, instr);
+ } else {
+ UNREACHABLE();
+ }
+ __ bind(&not_applicable);
+}
+
+
void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
class DeferredStringCharCodeAt: public LDeferredCode {
public:
@@ -4095,11 +4186,17 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
ASSERT(ToRegister(instr->context()).is(esi));
+
+ Handle<FixedArray> constant_elements = instr->hydrogen()->constant_elements();
+ ASSERT_EQ(2, constant_elements->length());
+ ElementsKind constant_elements_kind =
+ static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
+
// Setup the parameters to the stub/runtime call.
__ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
__ push(FieldOperand(eax, JSFunction::kLiteralsOffset));
__ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
- __ push(Immediate(instr->hydrogen()->constant_elements()));
+ __ push(Immediate(constant_elements));
// Pick the right runtime function or stub to call.
int length = instr->hydrogen()->length();
@@ -4115,7 +4212,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);
}
@@ -4214,8 +4313,7 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
Handle<SharedFunctionInfo> 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());
__ push(Immediate(shared_info));
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
} else {
@@ -4247,12 +4345,11 @@ void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
Label* true_label = chunk_->GetAssemblyLabel(true_block);
Label* false_label = chunk_->GetAssemblyLabel(false_block);
- Condition final_branch_condition = EmitTypeofIs(true_label,
- false_label,
- input,
- instr->type_literal());
-
- EmitBranch(true_block, false_block, final_branch_condition);
+ Condition final_branch_condition =
+ EmitTypeofIs(true_label, false_label, input, instr->type_literal());
+ if (final_branch_condition != no_condition) {
+ EmitBranch(true_block, false_block, final_branch_condition);
+ }
}
@@ -4319,11 +4416,8 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
final_branch_condition = zero;
} else {
- final_branch_condition = not_equal;
__ jmp(false_label);
- // A dead branch instruction will be generated after this point.
}
-
return final_branch_condition;
}
diff --git a/deps/v8/src/ia32/lithium-codegen-ia32.h b/deps/v8/src/ia32/lithium-codegen-ia32.h
index 6037c0868a..412e418f21 100644
--- a/deps/v8/src/ia32/lithium-codegen-ia32.h
+++ b/deps/v8/src/ia32/lithium-codegen-ia32.h
@@ -131,8 +131,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();
}
bool dynamic_frame_alignment() const { return dynamic_frame_alignment_; }
void set_dynamic_frame_alignment(bool value) {
@@ -227,6 +227,7 @@ class LCodeGen BASE_EMBEDDED {
Register ToRegister(int index) const;
XMMRegister ToDoubleRegister(int index) const;
int ToInteger32(LConstantOperand* op) const;
+ double ToDouble(LConstantOperand* op) const;
Operand BuildFastArrayOperand(LOperand* elements_pointer,
LOperand* key,
ElementsKind elements_kind,
@@ -261,7 +262,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,
XMMRegister result,
bool deoptimize_on_undefined,
@@ -270,8 +270,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<String> type_name);
+ Condition EmitTypeofIs(Label* true_label,
+ Label* false_label,
+ Register input,
+ Handle<String> 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/ia32/lithium-ia32.cc b/deps/v8/src/ia32/lithium-ia32.cc
index 856106c799..626f899bfb 100644
--- a/deps/v8/src/ia32/lithium-ia32.cc
+++ b/deps/v8/src/ia32/lithium-ia32.cc
@@ -452,6 +452,12 @@ void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
}
+void LTransitionElementsKind::PrintDataTo(StringStream* stream) {
+ object()->PrintTo(stream);
+ stream->Add(" %p -> %p", *original_map(), *transitioned_map());
+}
+
+
void LChunk::AddInstruction(LInstruction* instr, HBasicBlock* block) {
LInstructionGap* gap = new LInstructionGap(block);
int index = -1;
@@ -1434,13 +1440,11 @@ 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* context = UseFixed(instr->context(), esi);
- LOperand* left = UseFixed(instr->left(), reversed ? eax : edx);
- LOperand* right = UseFixed(instr->right(), reversed ? edx : eax);
+ LOperand* left = UseFixed(instr->left(), edx);
+ LOperand* right = UseFixed(instr->right(), eax);
LCmpT* result = new LCmpT(context, left, right);
return MarkAsCall(DefineFixed(result, eax), instr);
}
@@ -1452,15 +1456,22 @@ LInstruction* LChunkBuilder::DoCompareIDAndBranch(
if (r.IsInteger32()) {
ASSERT(instr->left()->representation().IsInteger32());
ASSERT(instr->right()->representation().IsInteger32());
- LOperand* left = UseRegisterAtStart(instr->left());
+ LOperand* left = UseRegisterOrConstantAtStart(instr->left());
LOperand* right = UseOrConstantAtStart(instr->right());
return new LCmpIDAndBranch(left, right);
} else {
ASSERT(r.IsDouble());
ASSERT(instr->left()->representation().IsDouble());
ASSERT(instr->right()->representation().IsDouble());
- LOperand* left = UseRegisterAtStart(instr->left());
- LOperand* right = UseRegisterAtStart(instr->right());
+ LOperand* left;
+ LOperand* right;
+ if (instr->left()->IsConstant() && instr->right()->IsConstant()) {
+ left = UseRegisterOrConstantAtStart(instr->left());
+ right = UseRegisterOrConstantAtStart(instr->right());
+ } else {
+ left = UseRegisterAtStart(instr->left());
+ right = UseRegisterAtStart(instr->right());
+ }
return new LCmpIDAndBranch(left, right);
}
}
@@ -2033,6 +2044,27 @@ 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();
+ LOperand* temp_reg = TempRegister();
+ LTransitionElementsKind* result =
+ new LTransitionElementsKind(object, new_map_reg, temp_reg);
+ return DefineSameAsFirst(result);
+ } else {
+ LOperand* object = UseFixed(instr->object(), eax);
+ LOperand* fixed_object_reg = FixedTemp(edx);
+ LOperand* new_map_reg = FixedTemp(ebx);
+ LTransitionElementsKind* result =
+ new LTransitionElementsKind(object, new_map_reg, fixed_object_reg);
+ return MarkAsCall(DefineFixed(result, eax), instr);
+ }
+}
+
+
LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
bool needs_write_barrier = instr->NeedsWriteBarrier();
diff --git a/deps/v8/src/ia32/lithium-ia32.h b/deps/v8/src/ia32/lithium-ia32.h
index 3a06ac358b..5f23afab00 100644
--- a/deps/v8/src/ia32/lithium-ia32.h
+++ b/deps/v8/src/ia32/lithium-ia32.h
@@ -156,6 +156,7 @@ class LCodeGen;
V(ThisFunction) \
V(Throw) \
V(ToFastProperties) \
+ V(TransitionElementsKind) \
V(Typeof) \
V(TypeofIsAndBranch) \
V(UnaryMathOperation) \
@@ -1295,7 +1296,6 @@ class LStoreContextSlot: public LTemplateInstruction<0, 2, 1> {
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);
};
@@ -1312,7 +1312,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)
};
@@ -1617,7 +1619,6 @@ class LStoreNamedField: public LTemplateInstruction<0, 2, 1> {
Handle<Object> 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<Map> transition() const { return hydrogen()->transition(); }
};
@@ -1639,7 +1640,8 @@ class LStoreNamedGeneric: public LTemplateInstruction<0, 3, 0> {
LOperand* object() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
Handle<Object> 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; }
};
@@ -1733,6 +1735,30 @@ class LStoreKeyedGeneric: public LTemplateInstruction<0, 4, 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<Map> original_map() { return hydrogen()->original_map(); }
+ Handle<Map> transitioned_map() { return hydrogen()->transitioned_map(); }
+};
+
+
class LStringAdd: public LTemplateInstruction<1, 3, 0> {
public:
LStringAdd(LOperand* context, LOperand* left, LOperand* right) {
diff --git a/deps/v8/src/ia32/macro-assembler-ia32.cc b/deps/v8/src/ia32/macro-assembler-ia32.cc
index 3aaa22acc9..dd1ace91a7 100644
--- a/deps/v8/src/ia32/macro-assembler-ia32.cc
+++ b/deps/v8/src/ia32/macro-assembler-ia32.cc
@@ -352,7 +352,7 @@ void MacroAssembler::SafePush(const Immediate& x) {
void MacroAssembler::CompareRoot(Register with, Heap::RootListIndex index) {
// see ROOT_ACCESSOR macro in factory.h
- Handle<Object> value(&isolate()->heap()->roots_address()[index]);
+ Handle<Object> value(&isolate()->heap()->roots_array_start()[index]);
cmp(with, value);
}
@@ -1492,6 +1492,19 @@ void MacroAssembler::InitializeFieldsWithFiller(Register start_offset,
}
+void MacroAssembler::BooleanBitTest(Register object,
+ int field_offset,
+ int bit_index) {
+ bit_index += kSmiTagSize + kSmiShiftSize;
+ ASSERT(IsPowerOf2(kBitsPerByte));
+ int byte_index = bit_index / kBitsPerByte;
+ int byte_bit_index = bit_index & (kBitsPerByte - 1);
+ test_b(FieldOperand(object, field_offset + byte_index),
+ static_cast<byte>(1 << byte_bit_index));
+}
+
+
+
void MacroAssembler::NegativeZeroTest(Register result,
Register op,
Label* then_label) {
@@ -1522,7 +1535,8 @@ void MacroAssembler::NegativeZeroTest(Register result,
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);
@@ -1530,6 +1544,15 @@ void MacroAssembler::TryGetFunctionPrototype(Register function,
CmpObjectType(function, JS_FUNCTION_TYPE, result);
j(not_equal, miss);
+ if (miss_on_bound_function) {
+ // If a bound function, go to miss label.
+ mov(scratch,
+ FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
+ BooleanBitTest(scratch, SharedFunctionInfo::kCompilerHintsOffset,
+ SharedFunctionInfo::kBoundFunction);
+ j(not_zero, miss);
+ }
+
// Make sure that the function has an instance prototype.
Label non_instance;
movzx_b(scratch, FieldOperand(result, Map::kBitFieldOffset));
@@ -2064,23 +2087,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(edi, Immediate(Handle<JSFunction>(function)));
mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
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.
- InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset),
- expected, actual, flag, call_wrapper, call_kind);
- } else {
- Handle<Code> code(function->code());
- InvokeCode(code, expected, actual, RelocInfo::CODE_TARGET,
- flag, call_wrapper, 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.
+ InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset),
+ expected, actual, flag, call_wrapper, call_kind);
}
diff --git a/deps/v8/src/ia32/macro-assembler-ia32.h b/deps/v8/src/ia32/macro-assembler-ia32.h
index a1b42c280c..8528c555ad 100644
--- a/deps/v8/src/ia32/macro-assembler-ia32.h
+++ b/deps/v8/src/ia32/macro-assembler-ia32.h
@@ -594,6 +594,9 @@ class MacroAssembler: public Assembler {
// ---------------------------------------------------------------------------
// Support functions.
+ // Check a boolean-bit of a Smi field.
+ void BooleanBitTest(Register object, int field_offset, int bit_index);
+
// Check if result is zero and op is negative.
void NegativeZeroTest(Register result, Register op, Label* then_label);
@@ -610,7 +613,8 @@ class MacroAssembler: public Assembler {
void TryGetFunctionPrototype(Register function,
Register result,
Register scratch,
- Label* miss);
+ Label* miss,
+ bool miss_on_bound_function = false);
// Generates code for reporting that an illegal operation has
// occurred.
diff --git a/deps/v8/src/ia32/regexp-macro-assembler-ia32.cc b/deps/v8/src/ia32/regexp-macro-assembler-ia32.cc
index 8b0b9ab911..dbf01abff0 100644
--- a/deps/v8/src/ia32/regexp-macro-assembler-ia32.cc
+++ b/deps/v8/src/ia32/regexp-macro-assembler-ia32.cc
@@ -1141,6 +1141,11 @@ int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address,
frame_entry<const String*>(re_frame, kInputString) = *subject;
frame_entry<const byte*>(re_frame, kInputStart) = new_address;
frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length;
+ } else if (frame_entry<const String*>(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<const String*>(re_frame, kInputString) = *subject;
}
return 0;
diff --git a/deps/v8/src/ia32/stub-cache-ia32.cc b/deps/v8/src/ia32/stub-cache-ia32.cc
index 07cb14d025..af53acd170 100644
--- a/deps/v8/src/ia32/stub-cache-ia32.cc
+++ b/deps/v8/src/ia32/stub-cache-ia32.cc
@@ -107,12 +107,60 @@ 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.
-static MaybeObject* GenerateDictionaryNegativeLookup(MacroAssembler* masm,
- Label* miss_label,
- Register receiver,
- String* name,
- Register r0,
- Register r1) {
+static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
+ Label* miss_label,
+ Register receiver,
+ Handle<String> name,
+ Register r0,
+ Register r1) {
+ ASSERT(name->IsSymbol());
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->negative_lookups(), 1);
+ __ IncrementCounter(counters->negative_lookups_miss(), 1);
+
+ __ mov(r0, FieldOperand(receiver, HeapObject::kMapOffset));
+
+ const int kInterceptorOrAccessCheckNeededMask =
+ (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
+
+ // Bail out if the receiver has a named interceptor or requires access checks.
+ __ test_b(FieldOperand(r0, Map::kBitFieldOffset),
+ kInterceptorOrAccessCheckNeededMask);
+ __ j(not_zero, miss_label);
+
+ // Check that receiver is a JSObject.
+ __ CmpInstanceType(r0, FIRST_SPEC_OBJECT_TYPE);
+ __ j(below, miss_label);
+
+ // Load properties array.
+ Register properties = r0;
+ __ mov(properties, FieldOperand(receiver, JSObject::kPropertiesOffset));
+
+ // Check that the properties array is a dictionary.
+ __ cmp(FieldOperand(properties, HeapObject::kMapOffset),
+ Immediate(masm->isolate()->factory()->hash_table_map()));
+ __ j(not_equal, miss_label);
+
+ Label done;
+ StringDictionaryLookupStub::GenerateNegativeLookup(masm,
+ miss_label,
+ &done,
+ properties,
+ name,
+ r1);
+ __ bind(&done);
+ __ DecrementCounter(counters->negative_lookups_miss(), 1);
+}
+
+
+// TODO(kmillikin): Eliminate this function when the stub cache is fully
+// handlified.
+static MaybeObject* TryGenerateDictionaryNegativeLookup(MacroAssembler* masm,
+ Label* miss_label,
+ Register receiver,
+ String* name,
+ Register r0,
+ Register r1) {
ASSERT(name->IsSymbol());
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->negative_lookups(), 1);
@@ -143,12 +191,12 @@ static MaybeObject* GenerateDictionaryNegativeLookup(MacroAssembler* masm,
Label done;
MaybeObject* result =
- StringDictionaryLookupStub::GenerateNegativeLookup(masm,
- miss_label,
- &done,
- properties,
- name,
- r1);
+ StringDictionaryLookupStub::TryGenerateNegativeLookup(masm,
+ miss_label,
+ &done,
+ properties,
+ name,
+ r1);
if (result->IsFailure()) return result;
__ bind(&done);
@@ -165,25 +213,23 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
Register scratch,
Register extra,
Register extra2) {
- Isolate* isolate = Isolate::Current();
Label miss;
- USE(extra2); // The register extra2 is not used on the ia32 platform.
- // Make sure that code is valid. The shifting code relies on the
- // entry size being 8.
+ // Assert that code is valid. The shifting code relies on the entry size
+ // being 8.
ASSERT(sizeof(Entry) == 8);
- // Make sure the flags does not name a specific type.
+ // Assert the flags do not name a specific type.
ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
- // Make sure that there are no register conflicts.
+ // Assert that there are no register conflicts.
ASSERT(!scratch.is(receiver));
ASSERT(!scratch.is(name));
ASSERT(!extra.is(receiver));
ASSERT(!extra.is(name));
ASSERT(!extra.is(scratch));
- // Check scratch and extra registers are valid, and extra2 is unused.
+ // Assert scratch and extra registers are valid, and extra2 is unused.
ASSERT(!scratch.is(no_reg));
ASSERT(extra2.is(no_reg));
@@ -197,7 +243,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
__ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
// Probe the primary table.
- ProbeTable(isolate, masm, flags, kPrimary, name, scratch, extra);
+ ProbeTable(isolate(), masm, flags, kPrimary, name, scratch, extra);
// Primary miss: Compute hash for secondary probe.
__ mov(scratch, FieldOperand(name, String::kHashFieldOffset));
@@ -209,7 +255,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
__ and_(scratch, (kSecondaryTableSize - 1) << kHeapObjectTagSize);
// Probe the secondary table.
- ProbeTable(isolate, masm, flags, kSecondary, name, scratch, extra);
+ ProbeTable(isolate(), masm, flags, kSecondary, name, scratch, extra);
// Cache miss: Fall-through and let caller handle the miss by
// entering the runtime system.
@@ -327,8 +373,10 @@ void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
// 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<JSObject> holder,
+ int index) {
// Adjust for the number of properties stored in the holder.
index -= holder->map()->inobject_properties();
if (index < 0) {
@@ -486,11 +534,11 @@ class CallInterceptorCompiler BASE_EMBEDDED {
CallInterceptorCompiler(StubCompiler* stub_compiler,
const ParameterCount& arguments,
Register name,
- Code::ExtraICState extra_ic_state)
+ Code::ExtraICState extra_state)
: stub_compiler_(stub_compiler),
arguments_(arguments),
name_(name),
- extra_ic_state_(extra_ic_state) {}
+ extra_state_(extra_state) {}
MaybeObject* Compile(MacroAssembler* masm,
JSObject* object,
@@ -614,7 +662,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
GenerateFastApiCall(masm, optimization, arguments_.immediate());
if (result->IsFailure()) return result;
} else {
- CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
+ CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
? CALL_AS_FUNCTION
: CALL_AS_METHOD;
__ InvokeFunction(optimization.constant_function(), arguments_,
@@ -700,21 +748,16 @@ class CallInterceptorCompiler BASE_EMBEDDED {
StubCompiler* stub_compiler_;
const ParameterCount& arguments_;
Register name_;
- Code::ExtraICState extra_ic_state_;
+ Code::ExtraICState extra_state_;
};
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<Code> ic(code);
- __ jmp(ic, RelocInfo::CODE_TARGET);
+ Handle<Code> code = (kind == Code::LOAD_IC)
+ ? masm->isolate()->builtins()->LoadIC_Miss()
+ : masm->isolate()->builtins()->KeyedLoadIC_Miss();
+ __ jmp(code, RelocInfo::CODE_TARGET);
}
@@ -729,9 +772,9 @@ void StubCompiler::GenerateKeyedLoadMissForceGeneric(MacroAssembler* masm) {
// Both name_reg and receiver_reg are preserved on jumps to miss_label,
// but may be destroyed if store is successful.
void StubCompiler::GenerateStoreField(MacroAssembler* masm,
- JSObject* object,
+ Handle<JSObject> object,
int index,
- Map* transition,
+ Handle<Map> transition,
Register receiver_reg,
Register name_reg,
Register scratch,
@@ -754,12 +797,12 @@ 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.
__ pop(scratch); // Return address.
__ push(receiver_reg);
- __ push(Immediate(Handle<Map>(transition)));
+ __ push(Immediate(transition));
__ push(eax);
__ push(scratch);
__ TailCallExternalReference(
@@ -770,11 +813,11 @@ 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(FieldOperand(receiver_reg, HeapObject::kMapOffset),
- Immediate(Handle<Map>(transition)));
+ Immediate(transition));
}
// Adjust for the number of properties stored in the object. Even in the
@@ -820,7 +863,29 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
// 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<GlobalObject> global,
+ Handle<String> name,
+ Register scratch,
+ Label* miss) {
+ Handle<JSGlobalPropertyCell> cell =
+ GlobalObject::EnsurePropertyCell(global, name);
+ ASSERT(cell->value()->IsTheHole());
+ Handle<Oddball> the_hole = masm->isolate()->factory()->the_hole_value();
+ if (Serializer::enabled()) {
+ __ mov(scratch, Immediate(cell));
+ __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
+ Immediate(the_hole));
+ } else {
+ __ cmp(Operand::Cell(cell), Immediate(the_hole));
+ }
+ __ j(not_equal, 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,
@@ -847,7 +912,29 @@ MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCell(
// 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<JSObject> object,
+ Handle<JSObject> holder,
+ Handle<String> name,
+ Register scratch,
+ Label* miss) {
+ Handle<JSObject> current = object;
+ while (!current.is_identical_to(holder)) {
+ if (current->IsGlobalObject()) {
+ GenerateCheckPropertyCell(masm,
+ Handle<GlobalObject>::cast(current),
+ name,
+ scratch,
+ miss);
+ }
+ current = Handle<JSObject>(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,
@@ -858,7 +945,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,
@@ -877,6 +964,120 @@ MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCells(
#define __ ACCESS_MASM(masm())
+Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
+ Register object_reg,
+ Handle<JSObject> holder,
+ Register holder_reg,
+ Register scratch1,
+ Register scratch2,
+ Handle<String> 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;
+ Handle<JSObject> current = object;
+ int depth = 0;
+
+ if (save_at_depth == depth) {
+ __ mov(Operand(esp, kPointerSize), reg);
+ }
+
+ // Traverse the prototype chain and check the maps in the prototype chain for
+ // fast and global objects or do negative lookup for normal objects.
+ 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<JSObject> 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);
+
+ __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
+ reg = holder_reg; // From now on the object will be in holder_reg.
+ __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
+ } else {
+ bool in_new_space = heap()->InNewSpace(*prototype);
+ Handle<Map> current_map(current->map());
+ if (in_new_space) {
+ // Save the map in scratch1 for later.
+ __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
+ __ cmp(scratch1, Immediate(current_map));
+ } else {
+ __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
+ Immediate(current_map));
+ }
+ // Branch on the result of the map check.
+ __ j(not_equal, 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 (in_new_space) {
+ // The prototype is in new space; we cannot store a reference to it
+ // in the code. Load it from the map.
+ __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
+ } else {
+ // The prototype is in old space; load it directly.
+ __ mov(reg, prototype);
+ }
+ }
+
+ if (save_at_depth == depth) {
+ __ mov(Operand(esp, kPointerSize), reg);
+ }
+
+ // Go to the next object in the prototype chain.
+ current = prototype;
+ }
+ ASSERT(current.is_identical_to(holder));
+
+ // Log the check depth.
+ LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
+
+ // Check the holder map.
+ __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
+ Immediate(Handle<Map>(holder->map())));
+ __ j(not_equal, 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,
@@ -926,12 +1127,9 @@ 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;
@@ -998,17 +1196,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.
@@ -1016,22 +1214,21 @@ Register StubCompiler::CheckPrototypes(JSObject* object,
}
-void StubCompiler::GenerateLoadField(JSObject* object,
- JSObject* holder,
+void StubCompiler::GenerateLoadField(Handle<JSObject> object,
+ Handle<JSObject> holder,
Register receiver,
Register scratch1,
Register scratch2,
Register scratch3,
int index,
- String* name,
+ Handle<String> name,
Label* miss) {
// Check that the receiver isn't a smi.
__ JumpIfSmi(receiver, miss);
// Check the prototype chain.
- Register reg =
- CheckPrototypes(object, receiver, holder,
- scratch1, scratch2, scratch3, name, miss);
+ Register reg = CheckPrototypes(
+ object, receiver, holder, scratch1, scratch2, scratch3, name, miss);
// Get the value from the properties.
GenerateFastPropertyLoad(masm(), eax, reg, holder, index);
@@ -1106,24 +1303,24 @@ MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object,
}
-void StubCompiler::GenerateLoadConstant(JSObject* object,
- JSObject* holder,
+void StubCompiler::GenerateLoadConstant(Handle<JSObject> object,
+ Handle<JSObject> holder,
Register receiver,
Register scratch1,
Register scratch2,
Register scratch3,
- Object* value,
- String* name,
+ Handle<Object> value,
+ Handle<String> 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(eax, Handle<Object>(value));
+ __ mov(eax, value);
__ ret(0);
}
@@ -1223,7 +1420,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(), eax, holder_reg,
- lookup->holder(), lookup->GetFieldIndex());
+ Handle<JSObject>(lookup->holder()),
+ lookup->GetFieldIndex());
__ ret(0);
} else {
// We found CALLBACKS property in prototype chain of interceptor's
@@ -1270,9 +1468,9 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object,
}
-void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) {
+void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
if (kind_ == Code::KEYED_CALL_IC) {
- __ cmp(ecx, Immediate(Handle<String>(name)));
+ __ cmp(ecx, Immediate(name));
__ j(not_equal, miss);
}
}
@@ -1335,11 +1533,22 @@ void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
}
-MaybeObject* CallStubCompiler::GenerateMissBranch() {
- MaybeObject* maybe_obj =
+void CallStubCompiler::GenerateMissBranch() {
+ Handle<Code> code =
isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
kind_,
- extra_ic_state_);
+ extra_state_);
+ __ jmp(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;
__ jmp(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET);
@@ -1347,11 +1556,10 @@ MaybeObject* CallStubCompiler::GenerateMissBranch() {
}
-MUST_USE_RESULT MaybeObject* CallStubCompiler::CompileCallField(
- JSObject* object,
- JSObject* holder,
- int index,
- String* name) {
+Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
+ Handle<JSObject> holder,
+ int index,
+ Handle<String> name) {
// ----------- S t a t e -------------
// -- ecx : name
// -- esp[0] : return address
@@ -1389,7 +1597,7 @@ MUST_USE_RESULT MaybeObject* CallStubCompiler::CompileCallField(
}
// 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;
__ InvokeFunction(edi, arguments(), JUMP_FUNCTION,
@@ -1397,8 +1605,7 @@ MUST_USE_RESULT MaybeObject* CallStubCompiler::CompileCallField(
// 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);
@@ -1425,7 +1632,7 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
Label miss;
- GenerateNameCheck(name, &miss);
+ GenerateNameCheck(Handle<String>(name), &miss);
// Get the receiver from the stack.
const int argc = arguments().immediate();
@@ -1513,8 +1720,8 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
// the new element is non-Smi. For now, delegate to the builtin.
Label no_fast_elements_check;
__ JumpIfSmi(edi, &no_fast_elements_check);
- __ mov(esi, FieldOperand(edx, HeapObject::kMapOffset));
- __ CheckFastObjectElements(esi, &call_builtin, Label::kFar);
+ __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
+ __ CheckFastObjectElements(ecx, &call_builtin, Label::kFar);
__ bind(&no_fast_elements_check);
// We could be lucky and the elements array could be at the top of
@@ -1582,11 +1789,11 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
}
__ 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);
}
@@ -1610,7 +1817,7 @@ MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object,
Label miss, return_undefined, call_builtin;
- GenerateNameCheck(name, &miss);
+ GenerateNameCheck(Handle<String>(name), &miss);
// Get the receiver from the stack.
const int argc = arguments().immediate();
@@ -1665,11 +1872,11 @@ MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object,
1);
__ 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);
}
@@ -1700,12 +1907,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<String>(name), &name_miss);
// Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype(masm(),
@@ -1751,11 +1958,11 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
// Restore function name in ecx.
__ Set(ecx, Immediate(Handle<String>(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);
}
@@ -1786,12 +1993,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<String>(name), &name_miss);
// Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype(masm(),
@@ -1839,11 +2046,11 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall(
// Restore function name in ecx.
__ Set(ecx, Immediate(Handle<String>(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);
}
@@ -1870,7 +2077,7 @@ MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall(
}
Label miss;
- GenerateNameCheck(name, &miss);
+ GenerateNameCheck(Handle<String>(name), &miss);
if (cell == NULL) {
__ mov(edx, Operand(esp, 2 * kPointerSize));
@@ -1908,7 +2115,7 @@ MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall(
// Tail call the full function. We do not have to patch the receiver
// because the function makes no use of it.
__ bind(&slow);
- 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,
@@ -1916,11 +2123,11 @@ MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall(
__ bind(&miss);
// ecx: 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);
}
@@ -1952,7 +2159,7 @@ MaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object,
}
Label miss;
- GenerateNameCheck(name, &miss);
+ GenerateNameCheck(Handle<String>(name), &miss);
if (cell == NULL) {
__ mov(edx, Operand(esp, 2 * kPointerSize));
@@ -2045,11 +2252,11 @@ MaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object,
__ bind(&miss);
// ecx: 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);
}
@@ -2075,7 +2282,7 @@ MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object,
}
Label miss;
- GenerateNameCheck(name, &miss);
+ GenerateNameCheck(Handle<String>(name), &miss);
if (cell == NULL) {
__ mov(edx, Operand(esp, 2 * kPointerSize));
@@ -2149,11 +2356,11 @@ MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object,
__ bind(&miss);
// ecx: 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);
}
@@ -2176,7 +2383,7 @@ MaybeObject* CallStubCompiler::CompileFastApiCall(
Label miss, miss_before_stack_reserved;
- GenerateNameCheck(name, &miss_before_stack_reserved);
+ GenerateNameCheck(Handle<String>(name), &miss_before_stack_reserved);
// Get the receiver from the stack.
const int argc = arguments().immediate();
@@ -2210,11 +2417,11 @@ MaybeObject* CallStubCompiler::CompileFastApiCall(
__ add(esp, Immediate(kFastApiCallArguments * kPointerSize));
__ 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);
}
@@ -2243,7 +2450,7 @@ MaybeObject* CallStubCompiler::CompileCallConstant(
Label miss;
- GenerateNameCheck(name, &miss);
+ GenerateNameCheck(Handle<String>(name), &miss);
// Get the receiver from the stack.
const int argc = arguments().immediate();
@@ -2339,7 +2546,7 @@ MaybeObject* CallStubCompiler::CompileCallConstant(
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,
@@ -2347,11 +2554,11 @@ MaybeObject* CallStubCompiler::CompileCallConstant(
// 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);
}
@@ -2367,18 +2574,18 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
// -----------------------------------
Label miss;
- GenerateNameCheck(name, &miss);
+ GenerateNameCheck(Handle<String>(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.
__ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
- CallInterceptorCompiler compiler(this, arguments(), ecx, extra_ic_state_);
+ CallInterceptorCompiler compiler(this, arguments(), ecx, extra_state_);
MaybeObject* result = compiler.Compile(masm(),
object,
holder,
@@ -2408,7 +2615,7 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
// Invoke the function.
__ mov(edi, eax);
- CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
+ CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
? CALL_AS_FUNCTION
: CALL_AS_METHOD;
__ InvokeFunction(edi, arguments(), JUMP_FUNCTION,
@@ -2416,11 +2623,11 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
// Handle load 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);
}
@@ -2449,7 +2656,7 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(
Label miss;
- GenerateNameCheck(name, &miss);
+ GenerateNameCheck(Handle<String>(name), &miss);
// Get the number of arguments.
const int argc = arguments().immediate();
@@ -2470,40 +2677,32 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(
// Jump to the cached code (tail call).
Counters* counters = isolate()->counters();
__ IncrementCounter(counters->call_global_inline(), 1);
- ASSERT(function->is_compiled());
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.
- __ InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset),
- expected, arguments(), JUMP_FUNCTION,
- NullCallWrapper(), call_kind);
- } else {
- Handle<Code> code(function->code());
- __ InvokeCode(code, expected, arguments(),
- RelocInfo::CODE_TARGET, JUMP_FUNCTION,
- NullCallWrapper(), 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.
+ __ InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset),
+ expected, arguments(), JUMP_FUNCTION,
+ NullCallWrapper(), call_kind);
// Handle call cache miss.
__ bind(&miss);
__ IncrementCounter(counters->call_global_inline_miss(), 1);
- 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<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
int index,
- Map* transition,
- String* name) {
+ Handle<Map> transition,
+ Handle<String> name) {
// ----------- S t a t e -------------
// -- eax : value
// -- ecx : name
@@ -2513,27 +2712,23 @@ MaybeObject* StoreStubCompiler::CompileStoreField(JSObject* object,
Label miss;
// Generate store field code. Trashes the name register.
- GenerateStoreField(masm(),
- object,
- index,
- transition,
- edx, ecx, ebx,
- &miss);
+ GenerateStoreField(masm(), object, index, transition, edx, ecx, ebx, &miss);
// Handle store cache miss.
__ bind(&miss);
- __ mov(ecx, Immediate(Handle<String>(name))); // restore name
+ __ mov(ecx, Immediate(name)); // restore name
Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
__ jmp(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<Code> StoreStubCompiler::CompileStoreCallback(
+ Handle<JSObject> object,
+ Handle<AccessorInfo> callback,
+ Handle<String> name) {
// ----------- S t a t e -------------
// -- eax : value
// -- ecx : name
@@ -2561,7 +2756,7 @@ MaybeObject* StoreStubCompiler::CompileStoreCallback(JSObject* object,
__ pop(ebx); // remove the return address
__ push(edx); // receiver
- __ push(Immediate(Handle<AccessorInfo>(callback))); // callback info
+ __ push(Immediate(callback)); // callback info
__ push(ecx); // name
__ push(eax); // value
__ push(ebx); // restore return address
@@ -2581,8 +2776,9 @@ MaybeObject* StoreStubCompiler::CompileStoreCallback(JSObject* object,
}
-MaybeObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
- String* name) {
+Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
+ Handle<JSObject> receiver,
+ Handle<String> name) {
// ----------- S t a t e -------------
// -- eax : value
// -- ecx : name
@@ -2630,9 +2826,10 @@ MaybeObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
}
-MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
- JSGlobalPropertyCell* cell,
- String* name) {
+Handle<Code> StoreStubCompiler::CompileStoreGlobal(
+ Handle<GlobalObject> object,
+ Handle<JSGlobalPropertyCell> cell,
+ Handle<String> name) {
// ----------- S t a t e -------------
// -- eax : value
// -- ecx : name
@@ -2647,7 +2844,7 @@ MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
__ j(not_equal, &miss);
// Compute the cell operand to use.
- __ mov(ebx, Immediate(Handle<JSGlobalPropertyCell>(cell)));
+ __ mov(ebx, Immediate(cell));
Operand cell_operand = FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset);
// Check that the value in the cell is not the hole. If it is, this
@@ -2691,10 +2888,10 @@ MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
}
-MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
+Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
int index,
- Map* transition,
- String* name) {
+ Handle<Map> transition,
+ Handle<String> name) {
// ----------- S t a t e -------------
// -- eax : value
// -- ecx : key
@@ -2707,16 +2904,11 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
__ IncrementCounter(counters->keyed_store_field(), 1);
// Check that the name has not changed.
- __ cmp(ecx, Immediate(Handle<String>(name)));
+ __ cmp(ecx, Immediate(name));
__ j(not_equal, &miss);
// Generate store field code. Trashes the name register.
- GenerateStoreField(masm(),
- object,
- index,
- transition,
- edx, ecx, ebx,
- &miss);
+ GenerateStoreField(masm(), object, index, transition, edx, ecx, ebx, &miss);
// Handle store cache miss.
__ bind(&miss);
@@ -2725,40 +2917,37 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
__ jmp(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<Code> KeyedStoreStubCompiler::CompileStoreElement(
+ Handle<Map> receiver_map) {
// ----------- S t a t e -------------
// -- eax : value
// -- ecx : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
- Code* stub;
ElementsKind elements_kind = receiver_map->elements_kind();
bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE;
- MaybeObject* maybe_stub =
- KeyedStoreElementStub(is_jsarray, elements_kind).TryGetCode();
- if (!maybe_stub->To(&stub)) return maybe_stub;
- __ DispatchMap(edx,
- Handle<Map>(receiver_map),
- Handle<Code>(stub),
- DO_SMI_CHECK);
+ Handle<Code> stub =
+ KeyedStoreElementStub(is_jsarray, elements_kind).GetCode();
+
+ __ DispatchMap(edx, receiver_map, stub, DO_SMI_CHECK);
Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
__ jmp(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<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
+ MapHandleList* receiver_maps,
+ CodeHandleList* handler_stubs,
+ MapHandleList* transitioned_maps) {
// ----------- S t a t e -------------
// -- eax : value
// -- ecx : key
@@ -2770,15 +2959,14 @@ MaybeObject* KeyedStoreStubCompiler::CompileStorePolymorphic(
__ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
// ebx: receiver->map().
for (int i = 0; i < receiver_maps->length(); ++i) {
- Handle<Map> map(receiver_maps->at(i));
- __ cmp(edi, map);
- if (transitioned_maps->at(i) == NULL) {
- __ j(equal, Handle<Code>(handler_stubs->at(i)));
+ __ cmp(edi, receiver_maps->at(i));
+ if (transitioned_maps->at(i).is_null()) {
+ __ j(equal, handler_stubs->at(i));
} else {
Label next_map;
__ j(not_equal, &next_map, Label::kNear);
- __ mov(ebx, Immediate(Handle<Map>(transitioned_maps->at(i))));
- __ jmp(Handle<Code>(handler_stubs->at(i)), RelocInfo::CODE_TARGET);
+ __ mov(ebx, Immediate(transitioned_maps->at(i)));
+ __ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET);
__ bind(&next_map);
}
}
@@ -2787,13 +2975,13 @@ MaybeObject* KeyedStoreStubCompiler::CompileStorePolymorphic(
__ jmp(miss_ic, RelocInfo::CODE_TARGET);
// Return the generated code.
- return GetCode(NORMAL, NULL, MEGAMORPHIC);
+ return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC);
}
-MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name,
- JSObject* object,
- JSObject* last) {
+Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
+ Handle<JSObject> object,
+ Handle<JSObject> last) {
// ----------- S t a t e -------------
// -- eax : receiver
// -- ecx : name
@@ -2814,15 +3002,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,
- edx,
- &miss);
- if (cell->IsFailure()) {
- miss.Unuse();
- return cell;
- }
+ GenerateCheckPropertyCell(
+ masm(), Handle<GlobalObject>::cast(last), name, edx, &miss);
}
// Return undefined if maps of the full prototype chain are still the
@@ -2834,14 +3015,14 @@ MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name,
GenerateLoadMiss(masm(), Code::LOAD_IC);
// Return the generated code.
- return GetCode(NONEXISTENT, isolate()->heap()->empty_string());
+ return GetCode(NONEXISTENT, factory()->empty_string());
}
-MaybeObject* LoadStubCompiler::CompileLoadField(JSObject* object,
- JSObject* holder,
+Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
+ Handle<JSObject> holder,
int index,
- String* name) {
+ Handle<String> name) {
// ----------- S t a t e -------------
// -- eax : receiver
// -- ecx : name
@@ -2880,14 +3061,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<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object,
+ Handle<JSObject> holder,
+ Handle<Object> value,
+ Handle<String> name) {
// ----------- S t a t e -------------
// -- eax : receiver
// -- ecx : name
@@ -2914,7 +3095,7 @@ MaybeObject* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
// -----------------------------------
Label miss;
- LookupResult lookup;
+ LookupResult lookup(isolate());
LookupPostInterceptor(holder, name, &lookup);
// TODO(368): Compile in the whole chain: all the interceptors in
@@ -2934,15 +3115,16 @@ MaybeObject* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
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<Code> LoadStubCompiler::CompileLoadGlobal(
+ Handle<JSObject> object,
+ Handle<GlobalObject> holder,
+ Handle<JSGlobalPropertyCell> cell,
+ Handle<String> name,
+ bool is_dont_delete) {
// ----------- S t a t e -------------
// -- eax : receiver
// -- ecx : name
@@ -2953,7 +3135,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 loads. In this case,
// the receiver cannot be a smi.
- if (object != holder) {
+ if (!object.is_identical_to(holder)) {
__ JumpIfSmi(eax, &miss);
}
@@ -2962,10 +3144,10 @@ MaybeObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
// Get the value from the cell.
if (Serializer::enabled()) {
- __ mov(ebx, Immediate(Handle<JSGlobalPropertyCell>(cell)));
+ __ mov(ebx, Immediate(cell));
__ mov(ebx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset));
} else {
- __ mov(ebx, Operand::Cell(Handle<JSGlobalPropertyCell>(cell)));
+ __ mov(ebx, Operand::Cell(cell));
}
// Check for deleted property if property can actually be deleted.
@@ -2991,9 +3173,9 @@ MaybeObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
}
-MaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name,
- JSObject* receiver,
- JSObject* holder,
+Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> holder,
int index) {
// ----------- S t a t e -------------
// -- eax : key
@@ -3006,7 +3188,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name,
__ IncrementCounter(counters->keyed_load_field(), 1);
// Check that the name has not changed.
- __ cmp(eax, Immediate(Handle<String>(name)));
+ __ cmp(eax, Immediate(name));
__ j(not_equal, &miss);
GenerateLoadField(receiver, holder, edx, ebx, ecx, edi, index, name, &miss);
@@ -3052,14 +3234,15 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback(
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
- return GetCode(CALLBACKS, name);
+ return TryGetCode(CALLBACKS, name);
}
-MaybeObject* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
- JSObject* receiver,
- JSObject* holder,
- Object* value) {
+Handle<Code> KeyedLoadStubCompiler::CompileLoadConstant(
+ Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> holder,
+ Handle<Object> value) {
// ----------- S t a t e -------------
// -- eax : key
// -- edx : receiver
@@ -3071,11 +3254,11 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
__ IncrementCounter(counters->keyed_load_constant_function(), 1);
// Check that the name has not changed.
- __ cmp(eax, Immediate(Handle<String>(name)));
+ __ cmp(eax, Immediate(name));
__ j(not_equal, &miss);
- GenerateLoadConstant(receiver, holder, edx, ebx, ecx, edi,
- value, name, &miss);
+ GenerateLoadConstant(
+ receiver, holder, edx, ebx, ecx, edi, value, name, &miss);
__ bind(&miss);
__ DecrementCounter(counters->keyed_load_constant_function(), 1);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
@@ -3102,7 +3285,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
__ cmp(eax, Immediate(Handle<String>(name)));
__ j(not_equal, &miss);
- LookupResult lookup;
+ LookupResult lookup(isolate());
LookupPostInterceptor(holder, name, &lookup);
GenerateLoadInterceptor(receiver,
holder,
@@ -3119,11 +3302,12 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
- return GetCode(INTERCEPTOR, name);
+ return TryGetCode(INTERCEPTOR, name);
}
-MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
+Handle<Code> KeyedLoadStubCompiler::CompileLoadArrayLength(
+ Handle<String> name) {
// ----------- S t a t e -------------
// -- eax : key
// -- edx : receiver
@@ -3135,7 +3319,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
__ IncrementCounter(counters->keyed_load_array_length(), 1);
// Check that the name has not changed.
- __ cmp(eax, Immediate(Handle<String>(name)));
+ __ cmp(eax, Immediate(name));
__ j(not_equal, &miss);
GenerateLoadArrayLength(masm(), edx, ecx, &miss);
@@ -3148,7 +3332,8 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
}
-MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
+Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength(
+ Handle<String> name) {
// ----------- S t a t e -------------
// -- eax : key
// -- edx : receiver
@@ -3160,7 +3345,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
__ IncrementCounter(counters->keyed_load_string_length(), 1);
// Check that the name has not changed.
- __ cmp(eax, Immediate(Handle<String>(name)));
+ __ cmp(eax, Immediate(name));
__ j(not_equal, &miss);
GenerateLoadStringLength(masm(), edx, ecx, ebx, &miss, true);
@@ -3173,7 +3358,8 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
}
-MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
+Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype(
+ Handle<String> name) {
// ----------- S t a t e -------------
// -- eax : key
// -- edx : receiver
@@ -3185,7 +3371,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
__ IncrementCounter(counters->keyed_load_function_prototype(), 1);
// Check that the name has not changed.
- __ cmp(eax, Immediate(Handle<String>(name)));
+ __ cmp(eax, Immediate(name));
__ j(not_equal, &miss);
GenerateLoadFunctionPrototype(masm(), edx, ecx, ebx, &miss);
@@ -3198,31 +3384,29 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
}
-MaybeObject* KeyedLoadStubCompiler::CompileLoadElement(Map* receiver_map) {
+Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
+ Handle<Map> receiver_map) {
// ----------- S t a t e -------------
// -- eax : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
- 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(edx,
- Handle<Map>(receiver_map),
- Handle<Code>(stub),
- DO_SMI_CHECK);
+ Handle<Code> stub = KeyedLoadElementStub(elements_kind).GetCode();
+
+ __ DispatchMap(edx, receiver_map, stub, DO_SMI_CHECK);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
- return GetCode(NORMAL, NULL);
+ return GetCode(NORMAL, factory()->empty_string());
}
-MaybeObject* KeyedLoadStubCompiler::CompileLoadPolymorphic(
- MapList* receiver_maps,
- CodeList* handler_ics) {
+Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
+ MapHandleList* receiver_maps,
+ CodeHandleList* handler_ics) {
// ----------- S t a t e -------------
// -- eax : key
// -- edx : receiver
@@ -3235,16 +3419,15 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadPolymorphic(
__ mov(map_reg, FieldOperand(edx, HeapObject::kMapOffset));
int receiver_count = receiver_maps->length();
for (int current = 0; current < receiver_count; ++current) {
- Handle<Map> map(receiver_maps->at(current));
- __ cmp(map_reg, map);
- __ j(equal, Handle<Code>(handler_ics->at(current)));
+ __ cmp(map_reg, receiver_maps->at(current));
+ __ j(equal, handler_ics->at(current));
}
__ bind(&miss);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
- return GetCode(NORMAL, NULL, MEGAMORPHIC);
+ return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC);
}
diff --git a/deps/v8/src/ic.cc b/deps/v8/src/ic.cc
index d5056a9ce8..fbe77b09d2 100644
--- a/deps/v8/src/ic.cc
+++ b/deps/v8/src/ic.cc
@@ -100,7 +100,11 @@ void IC::TraceIC(const char* type,
PrintF("]\n");
}
}
-#endif
+#endif // DEBUG
+
+
+#define TRACE_IC(type, name, old_state, new_target) \
+ ASSERT((TraceIC(type, name, old_state, new_target), true))
IC::IC(FrameDepth depth, Isolate* isolate) : isolate_(isolate) {
@@ -368,15 +372,13 @@ static bool HasInterceptorGetter(JSObject* object) {
}
-static void LookupForRead(Object* object,
- String* name,
+static void LookupForRead(Handle<Object> object,
+ Handle<String> name,
LookupResult* lookup) {
- AssertNoAllocation no_gc; // pointers must stay valid
-
// Skip all the objects with named interceptors, but
// without actual getter.
while (true) {
- object->Lookup(name, lookup);
+ object->Lookup(*name, lookup);
// Besides normal conditions (property not found or it's not
// an interceptor), bail out if lookup is not cacheable: we won't
// be able to IC it anyway and regular lookup should work fine.
@@ -386,18 +388,18 @@ static void LookupForRead(Object* object,
return;
}
- JSObject* holder = lookup->holder();
- if (HasInterceptorGetter(holder)) {
+ Handle<JSObject> holder(lookup->holder());
+ if (HasInterceptorGetter(*holder)) {
return;
}
- holder->LocalLookupRealNamedProperty(name, lookup);
+ holder->LocalLookupRealNamedProperty(*name, lookup);
if (lookup->IsProperty()) {
ASSERT(lookup->type() != INTERCEPTOR);
return;
}
- Object* proto = holder->GetPrototype();
+ Handle<Object> proto(holder->GetPrototype());
if (proto->IsNull()) {
lookup->NotFound();
return;
@@ -408,28 +410,29 @@ static void LookupForRead(Object* object,
}
-Object* CallICBase::TryCallAsFunction(Object* object) {
- HandleScope scope(isolate());
- Handle<Object> target(object, isolate());
- Handle<Object> delegate = Execution::GetFunctionDelegate(target);
+Handle<Object> CallICBase::TryCallAsFunction(Handle<Object> object) {
+ Handle<Object> delegate = Execution::GetFunctionDelegate(object);
- if (delegate->IsJSFunction()) {
+ if (delegate->IsJSFunction() && !object->IsJSFunctionProxy()) {
// Patch the receiver and use the delegate as the function to
- // invoke. This is used for invoking objects as if they were
- // functions.
- const int argc = this->target()->arguments_count();
+ // invoke. This is used for invoking objects as if they were functions.
+ const int argc = target()->arguments_count();
StackFrameLocator locator;
JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
int index = frame->ComputeExpressionsCount() - (argc + 1);
- frame->SetExpression(index, *target);
+ frame->SetExpression(index, *object);
}
- return *delegate;
+ return delegate;
}
void CallICBase::ReceiverToObjectIfRequired(Handle<Object> callee,
Handle<Object> object) {
+ while (callee->IsJSFunctionProxy()) {
+ callee = Handle<Object>(JSFunctionProxy::cast(*callee)->call_trap());
+ }
+
if (callee->IsJSFunction()) {
Handle<JSFunction> function = Handle<JSFunction>::cast(callee);
if (function->shared()->strict_mode() || function->IsBuiltin()) {
@@ -464,31 +467,27 @@ MaybeObject* CallICBase::LoadFunction(State state,
// the element if so.
uint32_t index;
if (name->AsArrayIndex(&index)) {
- Object* result;
- { MaybeObject* maybe_result = object->GetElement(index);
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
-
- if (result->IsJSFunction()) return result;
+ Handle<Object> result = Object::GetElement(object, index);
+ RETURN_IF_EMPTY_HANDLE(isolate(), result);
+ if (result->IsJSFunction()) return *result;
// Try to find a suitable function delegate for the object at hand.
result = TryCallAsFunction(result);
- if (result->IsJSFunction()) return result;
+ if (result->IsJSFunction()) return *result;
// Otherwise, it will fail in the lookup step.
}
// Lookup the property in the object.
- LookupResult lookup;
- LookupForRead(*object, *name, &lookup);
+ LookupResult lookup(isolate());
+ LookupForRead(object, name, &lookup);
if (!lookup.IsProperty()) {
// If the object does not have the requested property, check which
// exception we need to throw.
- if (IsContextual(object)) {
- return ReferenceError("not_defined", name);
- }
- return TypeError("undefined_method", object, name);
+ return IsContextual(object)
+ ? ReferenceError("not_defined", name)
+ : TypeError("undefined_method", object, name);
}
// Lookup is valid: Update inline cache and stub cache.
@@ -498,53 +497,42 @@ MaybeObject* CallICBase::LoadFunction(State state,
// Get the property.
PropertyAttributes attr;
- Object* result;
- { MaybeObject* maybe_result =
- object->GetProperty(*object, &lookup, *name, &attr);
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
+ Handle<Object> result =
+ Object::GetProperty(object, object, &lookup, name, &attr);
+ RETURN_IF_EMPTY_HANDLE(isolate(), result);
- if (lookup.type() == INTERCEPTOR) {
+ if (lookup.type() == INTERCEPTOR && attr == ABSENT) {
// If the object does not have the requested property, check which
// exception we need to throw.
- if (attr == ABSENT) {
- if (IsContextual(object)) {
- return ReferenceError("not_defined", name);
- }
- return TypeError("undefined_method", object, name);
- }
+ return IsContextual(object)
+ ? ReferenceError("not_defined", name)
+ : TypeError("undefined_method", object, name);
}
ASSERT(!result->IsTheHole());
- HandleScope scope(isolate());
- // Wrap result in a handle because ReceiverToObjectIfRequired may allocate
- // new object and cause GC.
- Handle<Object> result_handle(result);
// Make receiver an object if the callee requires it. Strict mode or builtin
// functions do not wrap the receiver, non-strict functions and objects
// called as functions do.
- ReceiverToObjectIfRequired(result_handle, object);
+ ReceiverToObjectIfRequired(result, object);
- if (result_handle->IsJSFunction()) {
+ if (result->IsJSFunction()) {
+ Handle<JSFunction> function = Handle<JSFunction>::cast(result);
#ifdef ENABLE_DEBUGGER_SUPPORT
// Handle stepping into a function if step into is active.
Debug* debug = isolate()->debug();
if (debug->StepInActive()) {
// Protect the result in a handle as the debugger can allocate and might
// cause GC.
- Handle<JSFunction> function(JSFunction::cast(*result_handle), isolate());
debug->HandleStepIn(function, object, fp(), false);
- return *function;
}
#endif
-
- return *result_handle;
+ return *function;
}
// Try to find a suitable function delegate for the object at hand.
- result_handle = Handle<Object>(TryCallAsFunction(*result_handle));
- if (result_handle->IsJSFunction()) return *result_handle;
+ result = TryCallAsFunction(result);
+ if (result->IsJSFunction()) return *result;
return TypeError("property_not_function", object, name);
}
@@ -594,89 +582,57 @@ bool CallICBase::TryUpdateExtraICState(LookupResult* lookup,
}
-MaybeObject* CallICBase::ComputeMonomorphicStub(
- LookupResult* lookup,
- State state,
- Code::ExtraICState extra_ic_state,
- Handle<Object> object,
- Handle<String> name) {
+Handle<Code> CallICBase::ComputeMonomorphicStub(LookupResult* lookup,
+ State state,
+ Code::ExtraICState extra_state,
+ Handle<Object> object,
+ Handle<String> name) {
int argc = target()->arguments_count();
- MaybeObject* maybe_code = NULL;
+ Handle<JSObject> holder(lookup->holder());
switch (lookup->type()) {
case FIELD: {
int index = lookup->GetFieldIndex();
- maybe_code = isolate()->stub_cache()->ComputeCallField(argc,
- kind_,
- extra_ic_state,
- *name,
- *object,
- lookup->holder(),
- index);
- break;
+ return isolate()->stub_cache()->ComputeCallField(
+ argc, kind_, extra_state, name, object, holder, index);
}
case CONSTANT_FUNCTION: {
// Get the constant function and compute the code stub for this
// call; used for rewriting to monomorphic state and making sure
// that the code stub is in the stub cache.
- JSFunction* function = lookup->GetConstantFunction();
- maybe_code =
- isolate()->stub_cache()->ComputeCallConstant(argc,
- kind_,
- extra_ic_state,
- *name,
- *object,
- lookup->holder(),
- function);
- break;
+ Handle<JSFunction> function(lookup->GetConstantFunction());
+ return isolate()->stub_cache()->ComputeCallConstant(
+ argc, kind_, extra_state, name, object, holder, function);
}
case NORMAL: {
- if (!object->IsJSObject()) return NULL;
+ // If we return a null handle, the IC will not be patched.
+ if (!object->IsJSObject()) return Handle<Code>::null();
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
- if (lookup->holder()->IsGlobalObject()) {
- GlobalObject* global = GlobalObject::cast(lookup->holder());
- JSGlobalPropertyCell* cell =
- JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
- if (!cell->value()->IsJSFunction()) return NULL;
- JSFunction* function = JSFunction::cast(cell->value());
- maybe_code = isolate()->stub_cache()->ComputeCallGlobal(argc,
- kind_,
- extra_ic_state,
- *name,
- *receiver,
- global,
- cell,
- function);
+ if (holder->IsGlobalObject()) {
+ Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder);
+ Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(lookup));
+ if (!cell->value()->IsJSFunction()) return Handle<Code>::null();
+ Handle<JSFunction> function(JSFunction::cast(cell->value()));
+ return isolate()->stub_cache()->ComputeCallGlobal(
+ argc, kind_, extra_state, name, receiver, global, cell, function);
} else {
// There is only one shared stub for calling normalized
// properties. It does not traverse the prototype chain, so the
// property must be found in the receiver for the stub to be
// applicable.
- if (lookup->holder() != *receiver) return NULL;
- maybe_code = isolate()->stub_cache()->ComputeCallNormal(argc,
- kind_,
- extra_ic_state,
- *name,
- *receiver);
+ if (!holder.is_identical_to(receiver)) return Handle<Code>::null();
+ return isolate()->stub_cache()->ComputeCallNormal(
+ argc, kind_, extra_state);
}
break;
}
- case INTERCEPTOR: {
- ASSERT(HasInterceptorGetter(lookup->holder()));
- maybe_code = isolate()->stub_cache()->ComputeCallInterceptor(
- argc,
- kind_,
- extra_ic_state,
- *name,
- *object,
- lookup->holder());
- break;
- }
+ case INTERCEPTOR:
+ ASSERT(HasInterceptorGetter(*holder));
+ return isolate()->stub_cache()->ComputeCallInterceptor(
+ argc, kind_, extra_state, name, object, holder);
default:
- maybe_code = NULL;
- break;
+ return Handle<Code>::null();
}
- return maybe_code;
}
@@ -698,75 +654,57 @@ void CallICBase::UpdateCaches(LookupResult* lookup,
// Compute the number of arguments.
int argc = target()->arguments_count();
- MaybeObject* maybe_code = NULL;
bool had_proto_failure = false;
+ Handle<Code> code;
if (state == UNINITIALIZED) {
// This is the first time we execute this inline cache.
// Set the target to the pre monomorphic stub to delay
// setting the monomorphic state.
- maybe_code =
- isolate()->stub_cache()->ComputeCallPreMonomorphic(argc,
- kind_,
- extra_ic_state);
+ code = isolate()->stub_cache()->ComputeCallPreMonomorphic(
+ argc, kind_, extra_ic_state);
} else if (state == MONOMORPHIC) {
if (kind_ == Code::CALL_IC &&
TryUpdateExtraICState(lookup, object, &extra_ic_state)) {
- maybe_code = ComputeMonomorphicStub(lookup,
- state,
- extra_ic_state,
- object,
- name);
+ code = ComputeMonomorphicStub(lookup, state, extra_ic_state,
+ object, name);
} else if (kind_ == Code::CALL_IC &&
TryRemoveInvalidPrototypeDependentStub(target(),
*object,
*name)) {
had_proto_failure = true;
- maybe_code = ComputeMonomorphicStub(lookup,
- state,
- extra_ic_state,
- object,
- name);
+ code = ComputeMonomorphicStub(lookup, state, extra_ic_state,
+ object, name);
} else {
- maybe_code =
- isolate()->stub_cache()->ComputeCallMegamorphic(argc,
- kind_,
- extra_ic_state);
+ code = isolate()->stub_cache()->ComputeCallMegamorphic(
+ argc, kind_, extra_ic_state);
}
} else {
- maybe_code = ComputeMonomorphicStub(lookup,
- state,
- extra_ic_state,
- object,
- name);
+ code = ComputeMonomorphicStub(lookup, state, extra_ic_state,
+ object, name);
}
- // If we're unable to compute the stub (not enough memory left), we
- // simply avoid updating the caches.
- Object* code;
- if (maybe_code == NULL || !maybe_code->ToObject(&code)) return;
+ // If there's no appropriate stub we simply avoid updating the caches.
+ if (code.is_null()) return;
// Patch the call site depending on the state of the cache.
if (state == UNINITIALIZED ||
state == PREMONOMORPHIC ||
state == MONOMORPHIC ||
state == MONOMORPHIC_PROTOTYPE_FAILURE) {
- set_target(Code::cast(code));
+ set_target(*code);
} else if (state == MEGAMORPHIC) {
// Cache code holding map should be consistent with
// GenerateMonomorphicCacheProbe. It is not the map which holds the stub.
- Map* map = JSObject::cast(object->IsJSObject() ? *object :
- object->GetPrototype())->map();
-
+ Handle<JSObject> cache_object = object->IsJSObject()
+ ? Handle<JSObject>::cast(object)
+ : Handle<JSObject>(JSObject::cast(object->GetPrototype()));
// Update the stub cache.
- isolate()->stub_cache()->Set(*name, map, Code::cast(code));
+ isolate()->stub_cache()->Set(*name, cache_object->map(), *code);
}
- USE(had_proto_failure);
-#ifdef DEBUG
if (had_proto_failure) state = MONOMORPHIC_PROTOTYPE_FAILURE;
- TraceIC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC",
- name, state, target());
-#endif
+ TRACE_IC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC",
+ name, state, target());
}
@@ -786,34 +724,22 @@ MaybeObject* KeyedCallIC::LoadFunction(State state,
if (FLAG_use_ic && state != MEGAMORPHIC && object->IsHeapObject()) {
int argc = target()->arguments_count();
- Heap* heap = Handle<HeapObject>::cast(object)->GetHeap();
- Map* map = heap->non_strict_arguments_elements_map();
+ Handle<Map> map =
+ isolate()->factory()->non_strict_arguments_elements_map();
if (object->IsJSObject() &&
- Handle<JSObject>::cast(object)->elements()->map() == map) {
- MaybeObject* maybe_code = isolate()->stub_cache()->ComputeCallArguments(
+ Handle<JSObject>::cast(object)->elements()->map() == *map) {
+ Handle<Code> code = isolate()->stub_cache()->ComputeCallArguments(
argc, Code::KEYED_CALL_IC);
- Object* code;
- if (maybe_code->ToObject(&code)) {
- set_target(Code::cast(code));
-#ifdef DEBUG
- TraceIC("KeyedCallIC", key, state, target());
-#endif
- }
- } else if (FLAG_use_ic && state != MEGAMORPHIC &&
- !object->IsAccessCheckNeeded()) {
- MaybeObject* maybe_code = isolate()->stub_cache()->ComputeCallMegamorphic(
+ set_target(*code);
+ TRACE_IC("KeyedCallIC", key, state, target());
+ } else if (!object->IsAccessCheckNeeded()) {
+ Handle<Code> code = isolate()->stub_cache()->ComputeCallMegamorphic(
argc, Code::KEYED_CALL_IC, Code::kNoExtraICState);
- Object* code;
- if (maybe_code->ToObject(&code)) {
- set_target(Code::cast(code));
-#ifdef DEBUG
- TraceIC("KeyedCallIC", key, state, target());
-#endif
- }
+ set_target(*code);
+ TRACE_IC("KeyedCallIC", key, state, target());
}
}
- HandleScope scope(isolate());
Handle<Object> result = GetProperty(object, key);
RETURN_IF_EMPTY_HANDLE(isolate(), result);
@@ -821,9 +747,9 @@ MaybeObject* KeyedCallIC::LoadFunction(State state,
// functions do not wrap the receiver, non-strict functions and objects
// called as functions do.
ReceiverToObjectIfRequired(result, object);
-
if (result->IsJSFunction()) return *result;
- result = Handle<Object>(TryCallAsFunction(*result));
+
+ result = TryCallAsFunction(result);
if (result->IsJSFunction()) return *result;
return TypeError("property_not_function", object, key);
@@ -846,53 +772,44 @@ MaybeObject* LoadIC::Load(State state,
// the underlying string value. See ECMA-262 15.5.5.1.
if ((object->IsString() || object->IsStringWrapper()) &&
name->Equals(isolate()->heap()->length_symbol())) {
- AssertNoAllocation no_allocation;
- Code* stub = NULL;
+ Handle<Code> stub;
if (state == UNINITIALIZED) {
stub = pre_monomorphic_stub();
} else if (state == PREMONOMORPHIC) {
- if (object->IsString()) {
- stub = isolate()->builtins()->builtin(
- Builtins::kLoadIC_StringLength);
- } else {
- stub = isolate()->builtins()->builtin(
- Builtins::kLoadIC_StringWrapperLength);
- }
+ stub = object->IsString()
+ ? isolate()->builtins()->LoadIC_StringLength()
+ : isolate()->builtins()->LoadIC_StringWrapperLength();
} else if (state == MONOMORPHIC && object->IsStringWrapper()) {
- stub = isolate()->builtins()->builtin(
- Builtins::kLoadIC_StringWrapperLength);
+ stub = isolate()->builtins()->LoadIC_StringWrapperLength();
} else if (state != MEGAMORPHIC) {
stub = megamorphic_stub();
}
- if (stub != NULL) {
- set_target(stub);
+ if (!stub.is_null()) {
+ set_target(*stub);
#ifdef DEBUG
if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n");
#endif
}
// Get the string if we have a string wrapper object.
- if (object->IsJSValue()) {
- return Smi::FromInt(
- String::cast(Handle<JSValue>::cast(object)->value())->length());
- }
- return Smi::FromInt(String::cast(*object)->length());
+ Handle<Object> string = object->IsJSValue()
+ ? Handle<Object>(Handle<JSValue>::cast(object)->value())
+ : object;
+ return Smi::FromInt(String::cast(*string)->length());
}
// Use specialized code for getting the length of arrays.
if (object->IsJSArray() &&
name->Equals(isolate()->heap()->length_symbol())) {
- AssertNoAllocation no_allocation;
- Code* stub = NULL;
+ Handle<Code> stub;
if (state == UNINITIALIZED) {
stub = pre_monomorphic_stub();
} else if (state == PREMONOMORPHIC) {
- stub = isolate()->builtins()->builtin(
- Builtins::kLoadIC_ArrayLength);
+ stub = isolate()->builtins()->LoadIC_ArrayLength();
} else if (state != MEGAMORPHIC) {
stub = megamorphic_stub();
}
- if (stub != NULL) {
- set_target(stub);
+ if (!stub.is_null()) {
+ set_target(*stub);
#ifdef DEBUG
if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n");
#endif
@@ -903,23 +820,20 @@ MaybeObject* LoadIC::Load(State state,
// Use specialized code for getting prototype of functions.
if (object->IsJSFunction() &&
name->Equals(isolate()->heap()->prototype_symbol()) &&
- JSFunction::cast(*object)->should_have_prototype()) {
- { AssertNoAllocation no_allocation;
- Code* stub = NULL;
- if (state == UNINITIALIZED) {
- stub = pre_monomorphic_stub();
- } else if (state == PREMONOMORPHIC) {
- stub = isolate()->builtins()->builtin(
- Builtins::kLoadIC_FunctionPrototype);
- } else if (state != MEGAMORPHIC) {
- stub = megamorphic_stub();
- }
- if (stub != NULL) {
- set_target(stub);
+ Handle<JSFunction>::cast(object)->should_have_prototype()) {
+ Handle<Code> stub;
+ if (state == UNINITIALIZED) {
+ stub = pre_monomorphic_stub();
+ } else if (state == PREMONOMORPHIC) {
+ stub = isolate()->builtins()->LoadIC_FunctionPrototype();
+ } else if (state != MEGAMORPHIC) {
+ stub = megamorphic_stub();
+ }
+ if (!stub.is_null()) {
+ set_target(*stub);
#ifdef DEBUG
- if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n");
+ if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n");
#endif
- }
}
return Accessors::FunctionGetPrototype(*object, 0);
}
@@ -931,8 +845,8 @@ MaybeObject* LoadIC::Load(State state,
if (name->AsArrayIndex(&index)) return object->GetElement(index);
// Named lookup in the object.
- LookupResult lookup;
- LookupForRead(*object, *name, &lookup);
+ LookupResult lookup(isolate());
+ LookupForRead(object, name, &lookup);
// If we did not find a property, check if we need to throw an exception.
if (!lookup.IsProperty()) {
@@ -951,17 +865,15 @@ MaybeObject* LoadIC::Load(State state,
if (lookup.IsProperty() &&
(lookup.type() == INTERCEPTOR || lookup.type() == HANDLER)) {
// Get the property.
- Object* result;
- { MaybeObject* maybe_result =
- object->GetProperty(*object, &lookup, *name, &attr);
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
+ Handle<Object> result =
+ Object::GetProperty(object, object, &lookup, name, &attr);
+ RETURN_IF_EMPTY_HANDLE(isolate(), result);
// If the property is not present, check if we need to throw an
// exception.
if (attr == ABSENT && IsContextual(object)) {
return ReferenceError("not_defined", name);
}
- return result;
+ return *result;
}
// Get the property.
@@ -984,128 +896,105 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return;
// Compute the code stub for this load.
- MaybeObject* maybe_code = NULL;
- Object* code;
+ Handle<Code> code;
if (state == UNINITIALIZED) {
// This is the first time we execute this inline cache.
// Set the target to the pre monomorphic stub to delay
// setting the monomorphic state.
- maybe_code = pre_monomorphic_stub();
+ code = pre_monomorphic_stub();
} else if (!lookup->IsProperty()) {
// Nonexistent property. The result is undefined.
- maybe_code = isolate()->stub_cache()->ComputeLoadNonexistent(*name,
- *receiver);
+ code = isolate()->stub_cache()->ComputeLoadNonexistent(name, receiver);
} else {
// Compute monomorphic stub.
+ Handle<JSObject> holder(lookup->holder());
switch (lookup->type()) {
- case FIELD: {
- maybe_code = isolate()->stub_cache()->ComputeLoadField(
- *name,
- *receiver,
- lookup->holder(),
- lookup->GetFieldIndex());
+ case FIELD:
+ code = isolate()->stub_cache()->ComputeLoadField(
+ name, receiver, holder, lookup->GetFieldIndex());
break;
- }
case CONSTANT_FUNCTION: {
- Object* constant = lookup->GetConstantFunction();
- maybe_code = isolate()->stub_cache()->ComputeLoadConstant(
- *name, *receiver, lookup->holder(), constant);
+ Handle<Object> constant(lookup->GetConstantFunction());
+ code = isolate()->stub_cache()->ComputeLoadConstant(
+ name, receiver, holder, constant);
break;
}
- case NORMAL: {
- if (lookup->holder()->IsGlobalObject()) {
- GlobalObject* global = GlobalObject::cast(lookup->holder());
- JSGlobalPropertyCell* cell =
- JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
- maybe_code = isolate()->stub_cache()->ComputeLoadGlobal(*name,
- *receiver,
- global,
- cell,
- lookup->IsDontDelete());
+ case NORMAL:
+ if (holder->IsGlobalObject()) {
+ Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder);
+ Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(lookup));
+ code = isolate()->stub_cache()->ComputeLoadGlobal(
+ name, receiver, global, cell, lookup->IsDontDelete());
} else {
// There is only one shared stub for loading normalized
// properties. It does not traverse the prototype chain, so the
// property must be found in the receiver for the stub to be
// applicable.
- if (lookup->holder() != *receiver) return;
- maybe_code = isolate()->stub_cache()->ComputeLoadNormal();
+ if (!holder.is_identical_to(receiver)) return;
+ code = isolate()->stub_cache()->ComputeLoadNormal();
}
break;
- }
case CALLBACKS: {
- if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
- AccessorInfo* callback =
- AccessorInfo::cast(lookup->GetCallbackObject());
+ Handle<Object> callback_object(lookup->GetCallbackObject());
+ if (!callback_object->IsAccessorInfo()) return;
+ Handle<AccessorInfo> callback =
+ Handle<AccessorInfo>::cast(callback_object);
if (v8::ToCData<Address>(callback->getter()) == 0) return;
- maybe_code = isolate()->stub_cache()->ComputeLoadCallback(
- *name, *receiver, lookup->holder(), callback);
+ code = isolate()->stub_cache()->ComputeLoadCallback(
+ name, receiver, holder, callback);
break;
}
- case INTERCEPTOR: {
- ASSERT(HasInterceptorGetter(lookup->holder()));
- maybe_code = isolate()->stub_cache()->ComputeLoadInterceptor(
- *name, *receiver, lookup->holder());
+ case INTERCEPTOR:
+ ASSERT(HasInterceptorGetter(*holder));
+ code = isolate()->stub_cache()->ComputeLoadInterceptor(
+ name, receiver, holder);
break;
- }
default:
return;
}
}
- // If we're unable to compute the stub (not enough memory left), we
- // simply avoid updating the caches.
- if (maybe_code == NULL || !maybe_code->ToObject(&code)) return;
-
// Patch the call site depending on the state of the cache.
- if (state == UNINITIALIZED || state == PREMONOMORPHIC ||
+ if (state == UNINITIALIZED ||
+ state == PREMONOMORPHIC ||
state == MONOMORPHIC_PROTOTYPE_FAILURE) {
- set_target(Code::cast(code));
+ set_target(*code);
} else if (state == MONOMORPHIC) {
- set_target(megamorphic_stub());
+ set_target(*megamorphic_stub());
} else if (state == MEGAMORPHIC) {
// Cache code holding map should be consistent with
// GenerateMonomorphicCacheProbe.
- Map* map = JSObject::cast(object->IsJSObject() ? *object :
- object->GetPrototype())->map();
-
- isolate()->stub_cache()->Set(*name, map, Code::cast(code));
+ isolate()->stub_cache()->Set(*name, receiver->map(), *code);
}
-#ifdef DEBUG
- TraceIC("LoadIC", name, state, target());
-#endif
+ TRACE_IC("LoadIC", name, state, target());
}
-MaybeObject* KeyedLoadIC::GetElementStubWithoutMapCheck(
+Handle<Code> KeyedLoadIC::GetElementStubWithoutMapCheck(
bool is_js_array,
ElementsKind elements_kind) {
- return KeyedLoadElementStub(elements_kind).TryGetCode();
+ return KeyedLoadElementStub(elements_kind).GetCode();
}
-MaybeObject* KeyedLoadIC::ComputePolymorphicStub(
- MapList* receiver_maps,
+Handle<Code> KeyedLoadIC::ComputePolymorphicStub(
+ MapHandleList* receiver_maps,
StrictModeFlag strict_mode) {
- CodeList handler_ics(receiver_maps->length());
+ CodeHandleList handler_ics(receiver_maps->length());
for (int i = 0; i < receiver_maps->length(); ++i) {
- Map* receiver_map(receiver_maps->at(i));
- MaybeObject* maybe_cached_stub = ComputeMonomorphicStubWithoutMapCheck(
+ Handle<Map> receiver_map = receiver_maps->at(i);
+ Handle<Code> cached_stub = ComputeMonomorphicStubWithoutMapCheck(
receiver_map, strict_mode);
- Code* cached_stub;
- if (!maybe_cached_stub->To(&cached_stub)) return maybe_cached_stub;
handler_ics.Add(cached_stub);
}
- Object* object;
- KeyedLoadStubCompiler compiler;
- MaybeObject* maybe_code = compiler.CompileLoadPolymorphic(receiver_maps,
- &handler_ics);
- if (!maybe_code->ToObject(&object)) return maybe_code;
+ KeyedLoadStubCompiler compiler(isolate());
+ Handle<Code> code = compiler.CompileLoadPolymorphic(
+ receiver_maps, &handler_ics);
isolate()->counters()->keyed_load_polymorphic_stubs()->Increment();
- PROFILE(isolate(), CodeCreateEvent(
- Logger::KEYED_LOAD_MEGAMORPHIC_IC_TAG,
- Code::cast(object), 0));
- return object;
+ PROFILE(isolate(),
+ CodeCreateEvent(Logger::KEYED_LOAD_MEGAMORPHIC_IC_TAG, *code, 0));
+ return code;
}
@@ -1115,9 +1004,8 @@ MaybeObject* KeyedLoadIC::Load(State state,
bool force_generic_stub) {
// Check for values that can be converted into a symbol.
// TODO(1295): Remove this code.
- HandleScope scope(isolate());
if (key->IsHeapNumber() &&
- isnan(HeapNumber::cast(*key)->value())) {
+ isnan(Handle<HeapNumber>::cast(key)->value())) {
key = isolate()->factory()->nan_symbol();
} else if (key->IsUndefined()) {
key = isolate()->factory()->undefined_symbol();
@@ -1139,16 +1027,11 @@ MaybeObject* KeyedLoadIC::Load(State state,
if (object->IsString() &&
name->Equals(isolate()->heap()->length_symbol())) {
Handle<String> string = Handle<String>::cast(object);
- Object* code = NULL;
- { MaybeObject* maybe_code =
- isolate()->stub_cache()->ComputeKeyedLoadStringLength(*name,
- *string);
- if (!maybe_code->ToObject(&code)) return maybe_code;
- }
- set_target(Code::cast(code));
-#ifdef DEBUG
- TraceIC("KeyedLoadIC", name, state, target());
-#endif // DEBUG
+ Handle<Code> code =
+ isolate()->stub_cache()->ComputeKeyedLoadStringLength(name, string);
+ ASSERT(!code.is_null());
+ set_target(*code);
+ TRACE_IC("KeyedLoadIC", name, state, target());
return Smi::FromInt(string->length());
}
@@ -1156,34 +1039,25 @@ MaybeObject* KeyedLoadIC::Load(State state,
if (object->IsJSArray() &&
name->Equals(isolate()->heap()->length_symbol())) {
Handle<JSArray> array = Handle<JSArray>::cast(object);
- Object* code;
- { MaybeObject* maybe_code =
- isolate()->stub_cache()->ComputeKeyedLoadArrayLength(*name,
- *array);
- if (!maybe_code->ToObject(&code)) return maybe_code;
- }
- set_target(Code::cast(code));
-#ifdef DEBUG
- TraceIC("KeyedLoadIC", name, state, target());
-#endif // DEBUG
- return JSArray::cast(*object)->length();
+ Handle<Code> code =
+ isolate()->stub_cache()->ComputeKeyedLoadArrayLength(name, array);
+ ASSERT(!code.is_null());
+ set_target(*code);
+ TRACE_IC("KeyedLoadIC", name, state, target());
+ return array->length();
}
// Use specialized code for getting prototype of functions.
if (object->IsJSFunction() &&
name->Equals(isolate()->heap()->prototype_symbol()) &&
- JSFunction::cast(*object)->should_have_prototype()) {
+ Handle<JSFunction>::cast(object)->should_have_prototype()) {
Handle<JSFunction> function = Handle<JSFunction>::cast(object);
- Object* code;
- { MaybeObject* maybe_code =
- isolate()->stub_cache()->ComputeKeyedLoadFunctionPrototype(
- *name, *function);
- if (!maybe_code->ToObject(&code)) return maybe_code;
- }
- set_target(Code::cast(code));
-#ifdef DEBUG
- TraceIC("KeyedLoadIC", name, state, target());
-#endif // DEBUG
+ Handle<Code> code =
+ isolate()->stub_cache()->ComputeKeyedLoadFunctionPrototype(
+ name, function);
+ ASSERT(!code.is_null());
+ set_target(*code);
+ TRACE_IC("KeyedLoadIC", name, state, target());
return Accessors::FunctionGetPrototype(*object, 0);
}
}
@@ -1192,15 +1066,14 @@ MaybeObject* KeyedLoadIC::Load(State state,
// the element or char if so.
uint32_t index = 0;
if (name->AsArrayIndex(&index)) {
- HandleScope scope(isolate());
// Rewrite to the generic keyed load stub.
- if (FLAG_use_ic) set_target(generic_stub());
+ if (FLAG_use_ic) set_target(*generic_stub());
return Runtime::GetElementOrCharAt(isolate(), object, index);
}
// Named lookup.
- LookupResult lookup;
- LookupForRead(*object, *name, &lookup);
+ LookupResult lookup(isolate());
+ LookupForRead(object, name, &lookup);
// If we did not find a property, check if we need to throw an exception.
if (!lookup.IsProperty() && IsContextual(object)) {
@@ -1214,17 +1087,15 @@ MaybeObject* KeyedLoadIC::Load(State state,
PropertyAttributes attr;
if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) {
// Get the property.
- Object* result;
- { MaybeObject* maybe_result =
- object->GetProperty(*object, &lookup, *name, &attr);
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
+ Handle<Object> result =
+ Object::GetProperty(object, object, &lookup, name, &attr);
+ RETURN_IF_EMPTY_HANDLE(isolate(), result);
// If the property is not present, check if we need to throw an
// exception.
if (attr == ABSENT && IsContextual(object)) {
return ReferenceError("not_defined", name);
}
- return result;
+ return *result;
}
return object->GetProperty(*object, &lookup, *name, &attr);
@@ -1235,44 +1106,38 @@ MaybeObject* KeyedLoadIC::Load(State state,
bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded();
if (use_ic) {
- Code* stub = generic_stub();
+ Handle<Code> stub = generic_stub();
if (!force_generic_stub) {
if (object->IsString() && key->IsNumber()) {
if (state == UNINITIALIZED) {
stub = string_stub();
}
} else if (object->IsJSObject()) {
- JSObject* receiver = JSObject::cast(*object);
- Heap* heap = Handle<JSObject>::cast(object)->GetHeap();
- Map* elements_map = Handle<JSObject>::cast(object)->elements()->map();
- if (elements_map == heap->non_strict_arguments_elements_map()) {
+ Handle<JSObject> receiver = Handle<JSObject>::cast(object);
+ if (receiver->elements()->map() ==
+ isolate()->heap()->non_strict_arguments_elements_map()) {
stub = non_strict_arguments_stub();
} else if (receiver->HasIndexedInterceptor()) {
stub = indexed_interceptor_stub();
- } else if (key->IsSmi() && (target() != non_strict_arguments_stub())) {
- MaybeObject* maybe_stub = ComputeStub(receiver,
- LOAD,
- kNonStrictMode,
- stub);
- stub = maybe_stub->IsFailure() ?
- NULL : Code::cast(maybe_stub->ToObjectUnchecked());
+ } else if (key->IsSmi() && (target() != *non_strict_arguments_stub())) {
+ stub = ComputeStub(receiver, LOAD, kNonStrictMode, stub);
}
}
}
- if (stub != NULL) set_target(stub);
+ if (!stub.is_null()) set_target(*stub);
}
-#ifdef DEBUG
- TraceIC("KeyedLoadIC", key, state, target());
-#endif // DEBUG
+ TRACE_IC("KeyedLoadIC", key, state, target());
// Get the property.
return Runtime::GetObjectProperty(isolate(), object, key);
}
-void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state,
- Handle<Object> object, Handle<String> name) {
+void KeyedLoadIC::UpdateCaches(LookupResult* lookup,
+ State state,
+ Handle<Object> object,
+ Handle<String> name) {
// Bail out if we didn't find a result.
if (!lookup->IsProperty() || !lookup->IsCacheable()) return;
@@ -1282,68 +1147,60 @@ void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state,
if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return;
// Compute the code stub for this load.
- MaybeObject* maybe_code = NULL;
- Object* code;
+ Handle<Code> code;
if (state == UNINITIALIZED) {
// This is the first time we execute this inline cache.
// Set the target to the pre monomorphic stub to delay
// setting the monomorphic state.
- maybe_code = pre_monomorphic_stub();
+ code = pre_monomorphic_stub();
} else {
// Compute a monomorphic stub.
+ Handle<JSObject> holder(lookup->holder());
switch (lookup->type()) {
- case FIELD: {
- maybe_code = isolate()->stub_cache()->ComputeKeyedLoadField(
- *name, *receiver, lookup->holder(), lookup->GetFieldIndex());
+ case FIELD:
+ code = isolate()->stub_cache()->ComputeKeyedLoadField(
+ name, receiver, holder, lookup->GetFieldIndex());
break;
- }
case CONSTANT_FUNCTION: {
- Object* constant = lookup->GetConstantFunction();
- maybe_code = isolate()->stub_cache()->ComputeKeyedLoadConstant(
- *name, *receiver, lookup->holder(), constant);
+ Handle<Object> constant(lookup->GetConstantFunction());
+ code = isolate()->stub_cache()->ComputeKeyedLoadConstant(
+ name, receiver, holder, constant);
break;
}
case CALLBACKS: {
- if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
- AccessorInfo* callback =
- AccessorInfo::cast(lookup->GetCallbackObject());
+ Handle<Object> callback_object(lookup->GetCallbackObject());
+ if (!callback_object->IsAccessorInfo()) return;
+ Handle<AccessorInfo> callback =
+ Handle<AccessorInfo>::cast(callback_object);
if (v8::ToCData<Address>(callback->getter()) == 0) return;
- maybe_code = isolate()->stub_cache()->ComputeKeyedLoadCallback(
- *name, *receiver, lookup->holder(), callback);
+ code = isolate()->stub_cache()->ComputeKeyedLoadCallback(
+ name, receiver, holder, callback);
break;
}
- case INTERCEPTOR: {
+ case INTERCEPTOR:
ASSERT(HasInterceptorGetter(lookup->holder()));
- maybe_code = isolate()->stub_cache()->ComputeKeyedLoadInterceptor(
- *name, *receiver, lookup->holder());
+ code = isolate()->stub_cache()->ComputeKeyedLoadInterceptor(
+ name, receiver, holder);
break;
- }
- default: {
+ default:
// Always rewrite to the generic case so that we do not
// repeatedly try to rewrite.
- maybe_code = generic_stub();
+ code = generic_stub();
break;
- }
}
}
- // If we're unable to compute the stub (not enough memory left), we
- // simply avoid updating the caches.
- if (maybe_code == NULL || !maybe_code->ToObject(&code)) return;
-
// Patch the call site depending on the state of the cache. Make
// sure to always rewrite from monomorphic to megamorphic.
ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE);
if (state == UNINITIALIZED || state == PREMONOMORPHIC) {
- set_target(Code::cast(code));
+ set_target(*code);
} else if (state == MONOMORPHIC) {
- set_target(megamorphic_stub());
+ set_target(*megamorphic_stub());
}
-#ifdef DEBUG
- TraceIC("KeyedLoadIC", name, state, target());
-#endif
+ TRACE_IC("KeyedLoadIC", name, state, target());
}
@@ -1359,17 +1216,17 @@ static bool StoreICableLookup(LookupResult* lookup) {
}
-static bool LookupForWrite(JSObject* receiver,
- String* name,
+static bool LookupForWrite(Handle<JSObject> receiver,
+ Handle<String> name,
LookupResult* lookup) {
- receiver->LocalLookup(name, lookup);
+ receiver->LocalLookup(*name, lookup);
if (!StoreICableLookup(lookup)) {
return false;
}
if (lookup->type() == INTERCEPTOR &&
receiver->GetNamedInterceptor()->setter()->IsUndefined()) {
- receiver->LocalLookupRealNamedProperty(name, lookup);
+ receiver->LocalLookupRealNamedProperty(*name, lookup);
return StoreICableLookup(lookup);
}
@@ -1401,6 +1258,7 @@ MaybeObject* StoreIC::Store(State state,
return TypeError("strict_read_only_property", object, name);
}
// Ignore other stores where the receiver is not a JSObject.
+ // TODO(1475): Must check prototype chains of object wrappers.
return *value;
}
@@ -1409,31 +1267,30 @@ MaybeObject* StoreIC::Store(State state,
// Check if the given name is an array index.
uint32_t index;
if (name->AsArrayIndex(&index)) {
- HandleScope scope(isolate());
Handle<Object> result = SetElement(receiver, index, value, strict_mode);
- if (result.is_null()) return Failure::Exception();
+ RETURN_IF_EMPTY_HANDLE(isolate(), result);
return *value;
}
// Use specialized code for setting the length of arrays.
if (receiver->IsJSArray()
&& name->Equals(isolate()->heap()->length_symbol())
- && JSArray::cast(*receiver)->AllowsSetElementsLength()) {
+ && Handle<JSArray>::cast(receiver)->AllowsSetElementsLength()) {
#ifdef DEBUG
if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n");
#endif
- Builtins::Name target = (strict_mode == kStrictMode)
- ? Builtins::kStoreIC_ArrayLength_Strict
- : Builtins::kStoreIC_ArrayLength;
- set_target(isolate()->builtins()->builtin(target));
+ Handle<Code> stub = (strict_mode == kStrictMode)
+ ? isolate()->builtins()->StoreIC_ArrayLength_Strict()
+ : isolate()->builtins()->StoreIC_ArrayLength();
+ set_target(*stub);
return receiver->SetProperty(*name, *value, NONE, strict_mode);
}
// Lookup the property locally in the receiver.
if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) {
- LookupResult lookup;
+ LookupResult lookup(isolate());
- if (LookupForWrite(*receiver, *name, &lookup)) {
+ if (LookupForWrite(receiver, name, &lookup)) {
// Generate a stub for this store.
UpdateCaches(&lookup, state, strict_mode, receiver, name, value);
} else {
@@ -1450,16 +1307,15 @@ MaybeObject* StoreIC::Store(State state,
}
if (receiver->IsJSGlobalProxy()) {
+ // TODO(ulan): find out why we patch this site even with --no-use-ic
// Generate a generic stub that goes to the runtime when we see a global
// proxy as receiver.
- Code* stub = (strict_mode == kStrictMode)
+ Handle<Code> stub = (strict_mode == kStrictMode)
? global_proxy_stub_strict()
: global_proxy_stub();
- if (target() != stub) {
- set_target(stub);
-#ifdef DEBUG
- TraceIC("StoreIC", name, state, target());
-#endif
+ if (target() != *stub) {
+ set_target(*stub);
+ TRACE_IC("StoreIC", name, state, target());
}
}
@@ -1487,89 +1343,82 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
// Compute the code stub for this store; used for rewriting to
// monomorphic state and making sure that the code stub is in the
// stub cache.
- MaybeObject* maybe_code = NULL;
- Object* code = NULL;
+ Handle<Code> code;
switch (type) {
- case FIELD: {
- maybe_code = isolate()->stub_cache()->ComputeStoreField(
- *name, *receiver, lookup->GetFieldIndex(), NULL, strict_mode);
+ case FIELD:
+ code = isolate()->stub_cache()->ComputeStoreField(name,
+ receiver,
+ lookup->GetFieldIndex(),
+ Handle<Map>::null(),
+ strict_mode);
break;
- }
case MAP_TRANSITION: {
if (lookup->GetAttributes() != NONE) return;
- HandleScope scope(isolate());
ASSERT(type == MAP_TRANSITION);
Handle<Map> transition(lookup->GetTransitionMap());
int index = transition->PropertyIndexFor(*name);
- maybe_code = isolate()->stub_cache()->ComputeStoreField(
- *name, *receiver, index, *transition, strict_mode);
+ code = isolate()->stub_cache()->ComputeStoreField(
+ name, receiver, index, transition, strict_mode);
break;
}
- case NORMAL: {
+ case NORMAL:
if (receiver->IsGlobalObject()) {
// The stub generated for the global object picks the value directly
// from the property cell. So the property must be directly on the
// global object.
Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver);
- JSGlobalPropertyCell* cell =
- JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
- maybe_code = isolate()->stub_cache()->ComputeStoreGlobal(
- *name, *global, cell, strict_mode);
+ Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(lookup));
+ code = isolate()->stub_cache()->ComputeStoreGlobal(
+ name, global, cell, strict_mode);
} else {
if (lookup->holder() != *receiver) return;
- maybe_code = isolate()->stub_cache()->ComputeStoreNormal(strict_mode);
+ code = isolate()->stub_cache()->ComputeStoreNormal(strict_mode);
}
break;
- }
case CALLBACKS: {
- if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
- AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
+ Handle<Object> callback_object(lookup->GetCallbackObject());
+ if (!callback_object->IsAccessorInfo()) return;
+ Handle<AccessorInfo> callback =
+ Handle<AccessorInfo>::cast(callback_object);
if (v8::ToCData<Address>(callback->setter()) == 0) return;
- maybe_code = isolate()->stub_cache()->ComputeStoreCallback(
- *name, *receiver, callback, strict_mode);
+ code = isolate()->stub_cache()->ComputeStoreCallback(
+ name, receiver, callback, strict_mode);
break;
}
- case INTERCEPTOR: {
+ case INTERCEPTOR:
ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined());
- maybe_code = isolate()->stub_cache()->ComputeStoreInterceptor(
- *name, *receiver, strict_mode);
+ code = isolate()->stub_cache()->ComputeStoreInterceptor(
+ name, receiver, strict_mode);
break;
- }
default:
return;
}
- // If we're unable to compute the stub (not enough memory left), we
- // simply avoid updating the caches.
- if (maybe_code == NULL || !maybe_code->ToObject(&code)) return;
-
// Patch the call site depending on the state of the cache.
if (state == UNINITIALIZED || state == MONOMORPHIC_PROTOTYPE_FAILURE) {
- set_target(Code::cast(code));
+ set_target(*code);
} else if (state == MONOMORPHIC) {
// Only move to megamorphic if the target changes.
- if (target() != Code::cast(code)) {
+ if (target() != *code) {
set_target((strict_mode == kStrictMode)
? megamorphic_stub_strict()
: megamorphic_stub());
}
} else if (state == MEGAMORPHIC) {
// Update the stub cache.
- isolate()->stub_cache()->Set(*name,
- receiver->map(),
- Code::cast(code));
+ isolate()->stub_cache()->Set(*name, receiver->map(), *code);
}
-#ifdef DEBUG
- TraceIC("StoreIC", name, state, target());
-#endif
+ TRACE_IC("StoreIC", name, state, target());
}
-static bool AddOneReceiverMapIfMissing(MapList* receiver_maps,
- Map* new_receiver_map) {
+static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
+ Handle<Map> new_receiver_map) {
+ ASSERT(!new_receiver_map.is_null());
for (int current = 0; current < receiver_maps->length(); ++current) {
- if (receiver_maps->at(current) == new_receiver_map) {
+ if (!receiver_maps->at(current).is_null() &&
+ receiver_maps->at(current).is_identical_to(new_receiver_map)) {
return false;
}
}
@@ -1578,45 +1427,40 @@ static bool AddOneReceiverMapIfMissing(MapList* receiver_maps,
}
-void KeyedIC::GetReceiverMapsForStub(Code* stub, MapList* result) {
+void KeyedIC::GetReceiverMapsForStub(Handle<Code> stub,
+ MapHandleList* result) {
ASSERT(stub->is_inline_cache_stub());
- if (stub == string_stub()) {
- return result->Add(isolate()->heap()->string_map());
+ if (!string_stub().is_null() && stub.is_identical_to(string_stub())) {
+ return result->Add(isolate()->factory()->string_map());
} else if (stub->is_keyed_load_stub() || stub->is_keyed_store_stub()) {
if (stub->ic_state() == MONOMORPHIC) {
- result->Add(Map::cast(stub->FindFirstMap()));
+ result->Add(Handle<Map>(stub->FindFirstMap()));
} else {
ASSERT(stub->ic_state() == MEGAMORPHIC);
AssertNoAllocation no_allocation;
int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
- for (RelocIterator it(stub, mask); !it.done(); it.next()) {
+ for (RelocIterator it(*stub, mask); !it.done(); it.next()) {
RelocInfo* info = it.rinfo();
- Object* object = info->target_object();
+ Handle<Object> object(info->target_object());
ASSERT(object->IsMap());
- result->Add(Map::cast(object));
+ AddOneReceiverMapIfMissing(result, Handle<Map>::cast(object));
}
}
}
}
-MaybeObject* KeyedIC::ComputeStub(JSObject* receiver,
+Handle<Code> KeyedIC::ComputeStub(Handle<JSObject> receiver,
StubKind stub_kind,
StrictModeFlag strict_mode,
- Code* generic_stub) {
+ Handle<Code> generic_stub) {
State ic_state = target()->ic_state();
if ((ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) &&
!IsTransitionStubKind(stub_kind)) {
- Code* monomorphic_stub;
- MaybeObject* maybe_stub = ComputeMonomorphicStub(receiver,
- stub_kind,
- strict_mode,
- generic_stub);
- if (!maybe_stub->To(&monomorphic_stub)) return maybe_stub;
-
- return monomorphic_stub;
+ return ComputeMonomorphicStub(
+ receiver, stub_kind, strict_mode, generic_stub);
}
- ASSERT(target() != generic_stub);
+ ASSERT(target() != *generic_stub);
// Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS
// via megamorphic stubs, since they don't have a map in their relocation info
@@ -1627,18 +1471,17 @@ MaybeObject* KeyedIC::ComputeStub(JSObject* receiver,
// Determine the list of receiver maps that this call site has seen,
// adding the map that was just encountered.
- MapList target_receiver_maps;
+ MapHandleList target_receiver_maps;
+ Handle<Map> receiver_map(receiver->map());
if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) {
- target_receiver_maps.Add(receiver->map());
+ target_receiver_maps.Add(receiver_map);
} else {
- GetReceiverMapsForStub(target(), &target_receiver_maps);
+ GetReceiverMapsForStub(Handle<Code>(target()), &target_receiver_maps);
}
bool map_added =
- AddOneReceiverMapIfMissing(&target_receiver_maps, receiver->map());
+ AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map);
if (IsTransitionStubKind(stub_kind)) {
- MaybeObject* maybe_map = ComputeTransitionedMap(receiver, stub_kind);
- Map* new_map = NULL;
- if (!maybe_map->To(&new_map)) return maybe_map;
+ Handle<Map> new_map = ComputeTransitionedMap(receiver, stub_kind);
map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps, new_map);
}
if (!map_added) {
@@ -1653,31 +1496,24 @@ MaybeObject* KeyedIC::ComputeStub(JSObject* receiver,
return generic_stub;
}
- PolymorphicCodeCache* cache = isolate()->heap()->polymorphic_code_cache();
- Code::Flags flags = Code::ComputeFlags(this->kind(),
- MEGAMORPHIC,
- strict_mode);
- Object* maybe_cached_stub = cache->Lookup(&target_receiver_maps, flags);
- // If there is a cached stub, use it.
- if (!maybe_cached_stub->IsUndefined()) {
- ASSERT(maybe_cached_stub->IsCode());
- return Code::cast(maybe_cached_stub);
- }
- MaybeObject* maybe_stub =
+ Handle<PolymorphicCodeCache> cache =
+ isolate()->factory()->polymorphic_code_cache();
+ Code::Flags flags = Code::ComputeFlags(kind(), MEGAMORPHIC, strict_mode);
+ Handle<Object> probe = cache->Lookup(&target_receiver_maps, flags);
+ if (probe->IsCode()) return Handle<Code>::cast(probe);
+
+ Handle<Code> stub =
ComputePolymorphicStub(&target_receiver_maps, strict_mode);
- Code* stub;
- if (!maybe_stub->To(&stub)) return maybe_stub;
- MaybeObject* maybe_update = cache->Update(&target_receiver_maps, flags, stub);
- if (maybe_update->IsFailure()) return maybe_update;
+ PolymorphicCodeCache::Update(cache, &target_receiver_maps, flags, stub);
return stub;
}
-MaybeObject* KeyedIC::ComputeMonomorphicStubWithoutMapCheck(
- Map* receiver_map,
+Handle<Code> KeyedIC::ComputeMonomorphicStubWithoutMapCheck(
+ Handle<Map> receiver_map,
StrictModeFlag strict_mode) {
if ((receiver_map->instance_type() & kNotStringTag) == 0) {
- ASSERT(string_stub() != NULL);
+ ASSERT(!string_stub().is_null());
return string_stub();
} else {
ASSERT(receiver_map->has_dictionary_elements() ||
@@ -1692,137 +1528,78 @@ MaybeObject* KeyedIC::ComputeMonomorphicStubWithoutMapCheck(
}
-MaybeObject* KeyedIC::ComputeMonomorphicStub(JSObject* receiver,
+Handle<Code> KeyedIC::ComputeMonomorphicStub(Handle<JSObject> receiver,
StubKind stub_kind,
StrictModeFlag strict_mode,
- Code* generic_stub) {
- Code* result = NULL;
+ Handle<Code> generic_stub) {
if (receiver->HasFastElements() ||
receiver->HasFastSmiOnlyElements() ||
receiver->HasExternalArrayElements() ||
receiver->HasFastDoubleElements() ||
receiver->HasDictionaryElements()) {
- MaybeObject* maybe_stub =
- isolate()->stub_cache()->ComputeKeyedLoadOrStoreElement(
- receiver, stub_kind, strict_mode);
- if (!maybe_stub->To(&result)) return maybe_stub;
+ return isolate()->stub_cache()->ComputeKeyedLoadOrStoreElement(
+ receiver, stub_kind, strict_mode);
} else {
- result = generic_stub;
+ return generic_stub;
}
- return result;
}
-MaybeObject* KeyedIC::ComputeTransitionedMap(JSObject* receiver,
- StubKind stub_kind) {
+Handle<Map> KeyedIC::ComputeTransitionedMap(Handle<JSObject> receiver,
+ StubKind stub_kind) {
switch (stub_kind) {
case KeyedIC::STORE_TRANSITION_SMI_TO_OBJECT:
case KeyedIC::STORE_TRANSITION_DOUBLE_TO_OBJECT:
- return receiver->GetElementsTransitionMap(FAST_ELEMENTS);
+ return JSObject::GetElementsTransitionMap(receiver, FAST_ELEMENTS);
+ break;
case KeyedIC::STORE_TRANSITION_SMI_TO_DOUBLE:
- return receiver->GetElementsTransitionMap(FAST_DOUBLE_ELEMENTS);
+ return JSObject::GetElementsTransitionMap(receiver, FAST_DOUBLE_ELEMENTS);
+ break;
default:
UNREACHABLE();
- return NULL;
+ return Handle<Map>::null();
}
}
-MaybeObject* KeyedStoreIC::GetElementStubWithoutMapCheck(
+Handle<Code> KeyedStoreIC::GetElementStubWithoutMapCheck(
bool is_js_array,
ElementsKind elements_kind) {
- return KeyedStoreElementStub(is_js_array, elements_kind).TryGetCode();
-}
-
-
-// If |map| is contained in |maps_list|, returns |map|; otherwise returns NULL.
-Map* GetMapIfPresent(Map* map, MapList* maps_list) {
- for (int i = 0; i < maps_list->length(); ++i) {
- if (maps_list->at(i) == map) return map;
- }
- return NULL;
-}
-
-
-// Returns the most generic transitioned map for |map| that's found in
-// |maps_list|, or NULL if no transitioned map for |map| is found at all.
-Map* GetTransitionedMap(Map* map, MapList* maps_list) {
- ElementsKind elements_kind = map->elements_kind();
- if (elements_kind == FAST_ELEMENTS) {
- return NULL;
- }
- if (elements_kind == FAST_DOUBLE_ELEMENTS) {
- bool dummy = true;
- Map* fast_map = map->LookupElementsTransitionMap(FAST_ELEMENTS, &dummy);
- if (fast_map == NULL) return NULL;
- return GetMapIfPresent(fast_map, maps_list);
- }
- if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
- bool dummy = true;
- Map* double_map = map->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS,
- &dummy);
- // In the current implementation, if the DOUBLE map doesn't exist, the
- // FAST map can't exist either.
- if (double_map == NULL) return NULL;
- Map* fast_map = map->LookupElementsTransitionMap(FAST_ELEMENTS, &dummy);
- if (fast_map == NULL) {
- return GetMapIfPresent(double_map, maps_list);
- }
- // Both double_map and fast_map are non-NULL. Return fast_map if it's in
- // maps_list, double_map otherwise.
- Map* fast_map_present = GetMapIfPresent(fast_map, maps_list);
- if (fast_map_present != NULL) return fast_map_present;
- return GetMapIfPresent(double_map, maps_list);
- }
- return NULL;
+ return KeyedStoreElementStub(is_js_array, elements_kind).GetCode();
}
-MaybeObject* KeyedStoreIC::ComputePolymorphicStub(
- MapList* receiver_maps,
- StrictModeFlag strict_mode) {
- // TODO(yangguo): <remove>
- Code* generic_stub = (strict_mode == kStrictMode)
- ? isolate()->builtins()->builtin(Builtins::kKeyedStoreIC_Generic_Strict)
- : isolate()->builtins()->builtin(Builtins::kKeyedStoreIC_Generic);
- // </remove>
-
+Handle<Code> KeyedStoreIC::ComputePolymorphicStub(MapHandleList* receiver_maps,
+ StrictModeFlag strict_mode) {
// Collect MONOMORPHIC stubs for all target_receiver_maps.
- CodeList handler_ics(receiver_maps->length());
- MapList transitioned_maps(receiver_maps->length());
+ CodeHandleList handler_ics(receiver_maps->length());
+ MapHandleList transitioned_maps(receiver_maps->length());
for (int i = 0; i < receiver_maps->length(); ++i) {
- Map* receiver_map(receiver_maps->at(i));
- MaybeObject* maybe_cached_stub = NULL;
- Map* transitioned_map = GetTransitionedMap(receiver_map, receiver_maps);
- if (transitioned_map != NULL) {
- // TODO(yangguo): Enable this code!
- // maybe_cached_stub = FastElementsConversionStub(
- // receiver_map->elements_kind(), // original elements_kind
- // transitioned_map->elements_kind(),
- // receiver_map->instance_type() == JS_ARRAY_TYPE, // is_js_array
- // strict_mode_).TryGetCode();
- // TODO(yangguo): <remove>
- maybe_cached_stub = generic_stub;
- // </remove>
+ Handle<Map> receiver_map(receiver_maps->at(i));
+ Handle<Code> cached_stub;
+ Handle<Map> transitioned_map =
+ receiver_map->FindTransitionedMap(receiver_maps);
+ if (!transitioned_map.is_null()) {
+ cached_stub = ElementsTransitionAndStoreStub(
+ receiver_map->elements_kind(), // original elements_kind
+ transitioned_map->elements_kind(),
+ receiver_map->instance_type() == JS_ARRAY_TYPE, // is_js_array
+ strict_mode).GetCode();
} else {
- maybe_cached_stub = ComputeMonomorphicStubWithoutMapCheck(
- receiver_map, strict_mode);
+ cached_stub = ComputeMonomorphicStubWithoutMapCheck(receiver_map,
+ strict_mode);
}
- Code* cached_stub;
- if (!maybe_cached_stub->To(&cached_stub)) return maybe_cached_stub;
+ ASSERT(!cached_stub.is_null());
handler_ics.Add(cached_stub);
transitioned_maps.Add(transitioned_map);
}
- Object* object;
- KeyedStoreStubCompiler compiler(strict_mode);
- MaybeObject* maybe_code = compiler.CompileStorePolymorphic(
+ KeyedStoreStubCompiler compiler(isolate(), strict_mode);
+ Handle<Code> code = compiler.CompileStorePolymorphic(
receiver_maps, &handler_ics, &transitioned_maps);
- if (!maybe_code->ToObject(&object)) return maybe_code;
isolate()->counters()->keyed_store_polymorphic_stubs()->Increment();
- PROFILE(isolate(), CodeCreateEvent(
- Logger::KEYED_STORE_MEGAMORPHIC_IC_TAG,
- Code::cast(object), 0));
- return object;
+ PROFILE(isolate(),
+ CodeCreateEvent(Logger::KEYED_STORE_MEGAMORPHIC_IC_TAG, *code, 0));
+ return code;
}
@@ -1835,6 +1612,12 @@ MaybeObject* KeyedStoreIC::Store(State state,
if (key->IsSymbol()) {
Handle<String> name = Handle<String>::cast(key);
+ // Handle proxies.
+ if (object->IsJSProxy()) {
+ return JSProxy::cast(*object)->SetProperty(
+ *name, *value, NONE, strict_mode);
+ }
+
// If the object is undefined or null it's illegal to try to set any
// properties on it; throw a TypeError in that case.
if (object->IsUndefined() || object->IsNull()) {
@@ -1848,14 +1631,13 @@ MaybeObject* KeyedStoreIC::Store(State state,
// Check if the given name is an array index.
uint32_t index;
if (name->AsArrayIndex(&index)) {
- HandleScope scope(isolate());
Handle<Object> result = SetElement(receiver, index, value, strict_mode);
- if (result.is_null()) return Failure::Exception();
+ RETURN_IF_EMPTY_HANDLE(isolate(), result);
return *value;
}
// Lookup the property locally in the receiver.
- LookupResult lookup;
+ LookupResult lookup(isolate());
receiver->LocalLookup(*name, &lookup);
// Update inline cache and stub cache.
@@ -1873,17 +1655,16 @@ MaybeObject* KeyedStoreIC::Store(State state,
ASSERT(!(use_ic && object->IsJSGlobalProxy()));
if (use_ic) {
- Code* stub = (strict_mode == kStrictMode)
+ Handle<Code> stub = (strict_mode == kStrictMode)
? generic_stub_strict()
: generic_stub();
if (object->IsJSObject()) {
- JSObject* receiver = JSObject::cast(*object);
- Heap* heap = Handle<JSObject>::cast(object)->GetHeap();
- Map* elements_map = Handle<JSObject>::cast(object)->elements()->map();
- if (elements_map == heap->non_strict_arguments_elements_map()) {
+ Handle<JSObject> receiver = Handle<JSObject>::cast(object);
+ if (receiver->elements()->map() ==
+ isolate()->heap()->non_strict_arguments_elements_map()) {
stub = non_strict_arguments_stub();
} else if (!force_generic) {
- if (key->IsSmi() && (target() != non_strict_arguments_stub())) {
+ if (key->IsSmi() && (target() != *non_strict_arguments_stub())) {
StubKind stub_kind = STORE_NO_TRANSITION;
if (receiver->GetElementsKind() == FAST_SMI_ONLY_ELEMENTS) {
if (value->IsHeapNumber()) {
@@ -1896,22 +1677,14 @@ MaybeObject* KeyedStoreIC::Store(State state,
stub_kind = STORE_TRANSITION_DOUBLE_TO_OBJECT;
}
}
- HandleScope scope(isolate());
- MaybeObject* maybe_stub = ComputeStub(receiver,
- stub_kind,
- strict_mode,
- stub);
- stub = maybe_stub->IsFailure() ?
- NULL : Code::cast(maybe_stub->ToObjectUnchecked());
+ stub = ComputeStub(receiver, stub_kind, strict_mode, stub);
}
}
}
- if (stub != NULL) set_target(stub);
+ if (!stub.is_null()) set_target(*stub);
}
-#ifdef DEBUG
- TraceIC("KeyedStoreIC", key, state, target());
-#endif
+ TRACE_IC("KeyedStoreIC", key, state, target());
// Set the property.
return Runtime::SetObjectProperty(
@@ -1943,75 +1716,60 @@ void KeyedStoreIC::UpdateCaches(LookupResult* lookup,
// Compute the code stub for this store; used for rewriting to
// monomorphic state and making sure that the code stub is in the
// stub cache.
- MaybeObject* maybe_code = NULL;
- Object* code = NULL;
+ Handle<Code> code;
switch (type) {
- case FIELD: {
- maybe_code = isolate()->stub_cache()->ComputeKeyedStoreField(
- *name, *receiver, lookup->GetFieldIndex(), NULL, strict_mode);
+ case FIELD:
+ code = isolate()->stub_cache()->ComputeKeyedStoreField(
+ name, receiver, lookup->GetFieldIndex(),
+ Handle<Map>::null(), strict_mode);
break;
- }
- case MAP_TRANSITION: {
+ case MAP_TRANSITION:
if (lookup->GetAttributes() == NONE) {
- HandleScope scope(isolate());
ASSERT(type == MAP_TRANSITION);
Handle<Map> transition(lookup->GetTransitionMap());
int index = transition->PropertyIndexFor(*name);
- maybe_code = isolate()->stub_cache()->ComputeKeyedStoreField(
- *name, *receiver, index, *transition, strict_mode);
+ code = isolate()->stub_cache()->ComputeKeyedStoreField(
+ name, receiver, index, transition, strict_mode);
break;
}
// fall through.
- }
- default: {
+ default:
// Always rewrite to the generic case so that we do not
// repeatedly try to rewrite.
- maybe_code = (strict_mode == kStrictMode)
+ code = (strict_mode == kStrictMode)
? generic_stub_strict()
: generic_stub();
break;
- }
}
- // If we're unable to compute the stub (not enough memory left), we
- // simply avoid updating the caches.
- if (maybe_code == NULL || !maybe_code->ToObject(&code)) return;
+ ASSERT(!code.is_null());
// Patch the call site depending on the state of the cache. Make
// sure to always rewrite from monomorphic to megamorphic.
ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE);
if (state == UNINITIALIZED || state == PREMONOMORPHIC) {
- set_target(Code::cast(code));
+ set_target(*code);
} else if (state == MONOMORPHIC) {
set_target((strict_mode == kStrictMode)
- ? megamorphic_stub_strict()
- : megamorphic_stub());
+ ? *megamorphic_stub_strict()
+ : *megamorphic_stub());
}
-#ifdef DEBUG
- TraceIC("KeyedStoreIC", name, state, target());
-#endif
+ TRACE_IC("KeyedStoreIC", name, state, target());
}
+#undef TRACE_IC
+
+
// ----------------------------------------------------------------------------
// Static IC stub generators.
//
-static JSFunction* CompileFunction(Isolate* isolate,
- JSFunction* function) {
- // Compile now with optimization.
- HandleScope scope(isolate);
- Handle<JSFunction> function_handle(function, isolate);
- CompileLazy(function_handle, CLEAR_EXCEPTION);
- return *function_handle;
-}
-
-
// Used from ic-<arch>.cc.
RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) {
- NoHandleAllocation na;
+ HandleScope scope(isolate);
ASSERT(args.length() == 2);
CallIC ic(isolate);
IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
@@ -2020,45 +1778,46 @@ RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) {
extra_ic_state,
args.at<Object>(0),
args.at<String>(1));
- Object* result;
- if (!maybe_result->ToObject(&result)) return maybe_result;
+ // Result could be a function or a failure.
+ JSFunction* raw_function = NULL;
+ if (!maybe_result->To(&raw_function)) return maybe_result;
// The first time the inline cache is updated may be the first time the
- // function it references gets called. If the function was lazily compiled
+ // function it references gets called. If the function is lazily compiled
// then the first call will trigger a compilation. We check for this case
// and we do the compilation immediately, instead of waiting for the stub
- // currently attached to the JSFunction object to trigger compilation. We
- // do this in the case where we know that the inline cache is inside a loop,
- // because then we know that we want to optimize the function.
- if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) {
- return result;
- }
- return CompileFunction(isolate, JSFunction::cast(result));
+ // currently attached to the JSFunction object to trigger compilation.
+ if (raw_function->is_compiled()) return raw_function;
+
+ Handle<JSFunction> function(raw_function);
+ JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
+ return *function;
}
// Used from ic-<arch>.cc.
RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_Miss) {
- NoHandleAllocation na;
+ HandleScope scope(isolate);
ASSERT(args.length() == 2);
KeyedCallIC ic(isolate);
IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
- Object* result;
- { MaybeObject* maybe_result =
+ MaybeObject* maybe_result =
ic.LoadFunction(state, args.at<Object>(0), args.at<Object>(1));
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
+ // Result could be a function or a failure.
+ JSFunction* raw_function = NULL;
+ if (!maybe_result->To(&raw_function)) return maybe_result;
- if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) {
- return result;
- }
- return CompileFunction(isolate, JSFunction::cast(result));
+ if (raw_function->is_compiled()) return raw_function;
+
+ Handle<JSFunction> function(raw_function);
+ JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
+ return *function;
}
// Used from ic-<arch>.cc.
RUNTIME_FUNCTION(MaybeObject*, LoadIC_Miss) {
- NoHandleAllocation na;
+ HandleScope scope(isolate);
ASSERT(args.length() == 2);
LoadIC ic(isolate);
IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
@@ -2068,7 +1827,7 @@ RUNTIME_FUNCTION(MaybeObject*, LoadIC_Miss) {
// Used from ic-<arch>.cc
RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_Miss) {
- NoHandleAllocation na;
+ HandleScope scope(isolate);
ASSERT(args.length() == 2);
KeyedLoadIC ic(isolate);
IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
@@ -2077,7 +1836,7 @@ RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_Miss) {
RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissForceGeneric) {
- NoHandleAllocation na;
+ HandleScope scope(isolate);
ASSERT(args.length() == 2);
KeyedLoadIC ic(isolate);
IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
@@ -2087,7 +1846,7 @@ RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissForceGeneric) {
// Used from ic-<arch>.cc.
RUNTIME_FUNCTION(MaybeObject*, StoreIC_Miss) {
- NoHandleAllocation na;
+ HandleScope scope;
ASSERT(args.length() == 3);
StoreIC ic(isolate);
IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
@@ -2156,7 +1915,7 @@ RUNTIME_FUNCTION(MaybeObject*, SharedStoreIC_ExtendStorage) {
// Used from ic-<arch>.cc.
RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Miss) {
- NoHandleAllocation na;
+ HandleScope scope(isolate);
ASSERT(args.length() == 3);
KeyedStoreIC ic(isolate);
IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
@@ -2190,7 +1949,7 @@ RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Slow) {
RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissForceGeneric) {
- NoHandleAllocation na;
+ HandleScope scope(isolate);
ASSERT(args.length() == 3);
KeyedStoreIC ic(isolate);
IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
diff --git a/deps/v8/src/ic.h b/deps/v8/src/ic.h
index ca8447eb81..81aa6b7c2f 100644
--- a/deps/v8/src/ic.h
+++ b/deps/v8/src/ic.h
@@ -198,47 +198,60 @@ class CallICBase: public IC {
class Contextual: public BitField<bool, 0, 1> {};
class StringStubState: public BitField<StringStubFeedback, 1, 1> {};
- protected:
- CallICBase(Code::Kind kind, Isolate* isolate)
- : IC(EXTRA_CALL_FRAME, isolate), kind_(kind) {}
-
- public:
+ // Returns a JSFunction or a Failure.
MUST_USE_RESULT MaybeObject* LoadFunction(State state,
Code::ExtraICState extra_ic_state,
Handle<Object> object,
Handle<String> name);
protected:
- Code::Kind kind_;
+ CallICBase(Code::Kind kind, Isolate* isolate)
+ : IC(EXTRA_CALL_FRAME, isolate), kind_(kind) {}
bool TryUpdateExtraICState(LookupResult* lookup,
Handle<Object> object,
Code::ExtraICState* extra_ic_state);
- MUST_USE_RESULT MaybeObject* ComputeMonomorphicStub(
- LookupResult* lookup,
- State state,
- Code::ExtraICState extra_ic_state,
- Handle<Object> object,
- Handle<String> name);
+ // Compute a monomorphic stub if possible, otherwise return a null handle.
+ Handle<Code> ComputeMonomorphicStub(LookupResult* lookup,
+ State state,
+ Code::ExtraICState extra_state,
+ Handle<Object> object,
+ Handle<String> name);
- // Update the inline cache and the global stub cache based on the
- // lookup result.
+ // Update the inline cache and the global stub cache based on the lookup
+ // result.
void UpdateCaches(LookupResult* lookup,
State state,
Code::ExtraICState extra_ic_state,
Handle<Object> object,
Handle<String> name);
- // Returns a JSFunction if the object can be called as a function,
- // and patches the stack to be ready for the call.
- // Otherwise, it returns the undefined value.
- Object* TryCallAsFunction(Object* object);
+ // Returns a JSFunction if the object can be called as a function, and
+ // patches the stack to be ready for the call. Otherwise, it returns the
+ // undefined value.
+ Handle<Object> TryCallAsFunction(Handle<Object> object);
void ReceiverToObjectIfRequired(Handle<Object> callee, Handle<Object> object);
static void Clear(Address address, Code* target);
+ // Platform-specific code generation functions used by both call and
+ // keyed call.
+ static void GenerateMiss(MacroAssembler* masm,
+ int argc,
+ IC::UtilityId id,
+ Code::ExtraICState extra_state);
+
+ static void GenerateNormal(MacroAssembler* masm, int argc);
+
+ static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
+ int argc,
+ Code::Kind kind,
+ Code::ExtraICState extra_state);
+
+ Code::Kind kind_;
+
friend class IC;
};
@@ -252,16 +265,24 @@ class CallIC: public CallICBase {
// Code generator routines.
static void GenerateInitialize(MacroAssembler* masm,
int argc,
- Code::ExtraICState extra_ic_state) {
- GenerateMiss(masm, argc, extra_ic_state);
+ Code::ExtraICState extra_state) {
+ GenerateMiss(masm, argc, extra_state);
}
+
static void GenerateMiss(MacroAssembler* masm,
int argc,
- Code::ExtraICState extra_ic_state);
+ Code::ExtraICState extra_state) {
+ CallICBase::GenerateMiss(masm, argc, IC::kCallIC_Miss, extra_state);
+ }
+
static void GenerateMegamorphic(MacroAssembler* masm,
int argc,
Code::ExtraICState extra_ic_state);
- static void GenerateNormal(MacroAssembler* masm, int argc);
+
+ static void GenerateNormal(MacroAssembler* masm, int argc) {
+ CallICBase::GenerateNormal(masm, argc);
+ GenerateMiss(masm, argc, Code::kNoExtraICState);
+ }
};
@@ -280,7 +301,12 @@ class KeyedCallIC: public CallICBase {
static void GenerateInitialize(MacroAssembler* masm, int argc) {
GenerateMiss(masm, argc);
}
- static void GenerateMiss(MacroAssembler* masm, int argc);
+
+ static void GenerateMiss(MacroAssembler* masm, int argc) {
+ CallICBase::GenerateMiss(masm, argc, IC::kKeyedCallIC_Miss,
+ Code::kNoExtraICState);
+ }
+
static void GenerateMegamorphic(MacroAssembler* masm, int argc);
static void GenerateNormal(MacroAssembler* masm, int argc);
static void GenerateNonStrictArguments(MacroAssembler* masm, int argc);
@@ -321,17 +347,15 @@ class LoadIC: public IC {
Handle<String> name);
// Stub accessors.
- Code* megamorphic_stub() {
- return isolate()->builtins()->builtin(
- Builtins::kLoadIC_Megamorphic);
+ Handle<Code> megamorphic_stub() {
+ return isolate()->builtins()->LoadIC_Megamorphic();
}
static Code* initialize_stub() {
return Isolate::Current()->builtins()->builtin(
Builtins::kLoadIC_Initialize);
}
- Code* pre_monomorphic_stub() {
- return isolate()->builtins()->builtin(
- Builtins::kLoadIC_PreMonomorphic);
+ Handle<Code> pre_monomorphic_stub() {
+ return isolate()->builtins()->LoadIC_PreMonomorphic();
}
static void Clear(Address address, Code* target);
@@ -352,38 +376,39 @@ class KeyedIC: public IC {
explicit KeyedIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) {}
virtual ~KeyedIC() {}
- virtual MaybeObject* GetElementStubWithoutMapCheck(
+ virtual Handle<Code> GetElementStubWithoutMapCheck(
bool is_js_array,
ElementsKind elements_kind) = 0;
protected:
- virtual Code* string_stub() {
- return NULL;
+ virtual Handle<Code> string_stub() {
+ return Handle<Code>::null();
}
virtual Code::Kind kind() const = 0;
- MaybeObject* ComputeStub(JSObject* receiver,
+ Handle<Code> ComputeStub(Handle<JSObject> receiver,
StubKind stub_kind,
StrictModeFlag strict_mode,
- Code* default_stub);
+ Handle<Code> default_stub);
- virtual MaybeObject* ComputePolymorphicStub(MapList* receiver_maps,
+ virtual Handle<Code> ComputePolymorphicStub(MapHandleList* receiver_maps,
StrictModeFlag strict_mode) = 0;
- MaybeObject* ComputeMonomorphicStubWithoutMapCheck(
- Map* receiver_map,
+ Handle<Code> ComputeMonomorphicStubWithoutMapCheck(
+ Handle<Map> receiver_map,
StrictModeFlag strict_mode);
private:
- void GetReceiverMapsForStub(Code* stub, MapList* result);
+ void GetReceiverMapsForStub(Handle<Code> stub, MapHandleList* result);
- MaybeObject* ComputeMonomorphicStub(JSObject* receiver,
+ Handle<Code> ComputeMonomorphicStub(Handle<JSObject> receiver,
StubKind stub_kind,
StrictModeFlag strict_mode,
- Code* default_stub);
+ Handle<Code> default_stub);
- MaybeObject* ComputeTransitionedMap(JSObject* receiver, StubKind stub_kind);
+ Handle<Map> ComputeTransitionedMap(Handle<JSObject> receiver,
+ StubKind stub_kind);
static bool IsTransitionStubKind(StubKind stub_kind) {
return stub_kind > STORE_NO_TRANSITION;
@@ -423,20 +448,18 @@ class KeyedLoadIC: public KeyedIC {
static const int kSlowCaseBitFieldMask =
(1 << Map::kIsAccessCheckNeeded) | (1 << Map::kHasIndexedInterceptor);
- virtual MaybeObject* GetElementStubWithoutMapCheck(
+ virtual Handle<Code> GetElementStubWithoutMapCheck(
bool is_js_array,
ElementsKind elements_kind);
protected:
virtual Code::Kind kind() const { return Code::KEYED_LOAD_IC; }
- virtual MaybeObject* ComputePolymorphicStub(
- MapList* receiver_maps,
- StrictModeFlag strict_mode);
+ virtual Handle<Code> ComputePolymorphicStub(MapHandleList* receiver_maps,
+ StrictModeFlag strict_mode);
- virtual Code* string_stub() {
- return isolate()->builtins()->builtin(
- Builtins::kKeyedLoadIC_String);
+ virtual Handle<Code> string_stub() {
+ return isolate()->builtins()->KeyedLoadIC_String();
}
private:
@@ -451,25 +474,20 @@ class KeyedLoadIC: public KeyedIC {
return Isolate::Current()->builtins()->builtin(
Builtins::kKeyedLoadIC_Initialize);
}
- Code* megamorphic_stub() {
- return isolate()->builtins()->builtin(
- Builtins::kKeyedLoadIC_Generic);
+ Handle<Code> megamorphic_stub() {
+ return isolate()->builtins()->KeyedLoadIC_Generic();
}
- Code* generic_stub() {
- return isolate()->builtins()->builtin(
- Builtins::kKeyedLoadIC_Generic);
+ Handle<Code> generic_stub() {
+ return isolate()->builtins()->KeyedLoadIC_Generic();
}
- Code* pre_monomorphic_stub() {
- return isolate()->builtins()->builtin(
- Builtins::kKeyedLoadIC_PreMonomorphic);
+ Handle<Code> pre_monomorphic_stub() {
+ return isolate()->builtins()->KeyedLoadIC_PreMonomorphic();
}
- Code* indexed_interceptor_stub() {
- return isolate()->builtins()->builtin(
- Builtins::kKeyedLoadIC_IndexedInterceptor);
+ Handle<Code> indexed_interceptor_stub() {
+ return isolate()->builtins()->KeyedLoadIC_IndexedInterceptor();
}
- Code* non_strict_arguments_stub() {
- return isolate()->builtins()->builtin(
- Builtins::kKeyedLoadIC_NonStrictArguments);
+ Handle<Code> non_strict_arguments_stub() {
+ return isolate()->builtins()->KeyedLoadIC_NonStrictArguments();
}
static void Clear(Address address, Code* target);
@@ -534,13 +552,11 @@ class StoreIC: public IC {
return Isolate::Current()->builtins()->builtin(
Builtins::kStoreIC_Initialize_Strict);
}
- Code* global_proxy_stub() {
- return isolate()->builtins()->builtin(
- Builtins::kStoreIC_GlobalProxy);
+ Handle<Code> global_proxy_stub() {
+ return isolate()->builtins()->StoreIC_GlobalProxy();
}
- Code* global_proxy_stub_strict() {
- return isolate()->builtins()->builtin(
- Builtins::kStoreIC_GlobalProxy_Strict);
+ Handle<Code> global_proxy_stub_strict() {
+ return isolate()->builtins()->StoreIC_GlobalProxy_Strict();
}
static void Clear(Address address, Code* target);
@@ -572,17 +588,18 @@ class KeyedStoreIC: public KeyedIC {
StrictModeFlag strict_mode);
static void GenerateGeneric(MacroAssembler* masm, StrictModeFlag strict_mode);
static void GenerateNonStrictArguments(MacroAssembler* masm);
+ static void GenerateTransitionElementsSmiToDouble(MacroAssembler* masm);
+ static void GenerateTransitionElementsDoubleToObject(MacroAssembler* masm);
- virtual MaybeObject* GetElementStubWithoutMapCheck(
+ virtual Handle<Code> GetElementStubWithoutMapCheck(
bool is_js_array,
ElementsKind elements_kind);
protected:
virtual Code::Kind kind() const { return Code::KEYED_STORE_IC; }
- virtual MaybeObject* ComputePolymorphicStub(
- MapList* receiver_maps,
- StrictModeFlag strict_mode);
+ virtual Handle<Code> ComputePolymorphicStub(MapHandleList* receiver_maps,
+ StrictModeFlag strict_mode);
private:
// Update the inline cache.
@@ -605,29 +622,24 @@ class KeyedStoreIC: public KeyedIC {
return Isolate::Current()->builtins()->builtin(
Builtins::kKeyedStoreIC_Initialize);
}
- Code* megamorphic_stub() {
- return isolate()->builtins()->builtin(
- Builtins::kKeyedStoreIC_Generic);
- }
static Code* initialize_stub_strict() {
return Isolate::Current()->builtins()->builtin(
Builtins::kKeyedStoreIC_Initialize_Strict);
}
- Code* megamorphic_stub_strict() {
- return isolate()->builtins()->builtin(
- Builtins::kKeyedStoreIC_Generic_Strict);
+ Handle<Code> megamorphic_stub() {
+ return isolate()->builtins()->KeyedStoreIC_Generic();
}
- Code* generic_stub() {
- return isolate()->builtins()->builtin(
- Builtins::kKeyedStoreIC_Generic);
+ Handle<Code> megamorphic_stub_strict() {
+ return isolate()->builtins()->KeyedStoreIC_Generic_Strict();
}
- Code* generic_stub_strict() {
- return isolate()->builtins()->builtin(
- Builtins::kKeyedStoreIC_Generic_Strict);
+ Handle<Code> generic_stub() {
+ return isolate()->builtins()->KeyedStoreIC_Generic();
}
- Code* non_strict_arguments_stub() {
- return isolate()->builtins()->builtin(
- Builtins::kKeyedStoreIC_NonStrictArguments);
+ Handle<Code> generic_stub_strict() {
+ return isolate()->builtins()->KeyedStoreIC_Generic_Strict();
+ }
+ Handle<Code> non_strict_arguments_stub() {
+ return isolate()->builtins()->KeyedStoreIC_NonStrictArguments();
}
static void Clear(Address address, Code* target);
diff --git a/deps/v8/src/incremental-marking-inl.h b/deps/v8/src/incremental-marking-inl.h
index 43fe0f5539..2a7fba756b 100644
--- a/deps/v8/src/incremental-marking-inl.h
+++ b/deps/v8/src/incremental-marking-inl.h
@@ -143,9 +143,6 @@ void IncrementalMarking::WhiteToGreyAndPush(HeapObject* obj, MarkBit mark_bit) {
void IncrementalMarking::WhiteToGrey(HeapObject* obj, MarkBit mark_bit) {
- ASSERT(Marking::MarkBitFrom(obj) == mark_bit);
- ASSERT(obj->Size() >= 2*kPointerSize);
- ASSERT(IsMarking());
Marking::WhiteToGrey(mark_bit);
}
diff --git a/deps/v8/src/incremental-marking.cc b/deps/v8/src/incremental-marking.cc
index 88ebd783ea..68b830a4df 100644
--- a/deps/v8/src/incremental-marking.cc
+++ b/deps/v8/src/incremental-marking.cc
@@ -50,7 +50,8 @@ IncrementalMarking::IncrementalMarking(Heap* heap)
steps_took_since_last_gc_(0),
should_hurry_(false),
allocation_marking_factor_(0),
- allocated_(0) {
+ allocated_(0),
+ no_marking_scope_depth_(0) {
}
@@ -87,6 +88,16 @@ void IncrementalMarking::RecordWriteForEvacuationFromCode(HeapObject* obj,
}
+void IncrementalMarking::RecordCodeTargetPatch(Code* host,
+ Address pc,
+ HeapObject* value) {
+ if (IsMarking()) {
+ RelocInfo rinfo(pc, RelocInfo::CODE_TARGET, 0, host);
+ RecordWriteIntoCode(host, &rinfo, value);
+ }
+}
+
+
void IncrementalMarking::RecordCodeTargetPatch(Address pc, HeapObject* value) {
if (IsMarking()) {
Code* host = heap_->isolate()->inner_pointer_to_code_cache()->
@@ -343,7 +354,8 @@ bool IncrementalMarking::WorthActivating() {
static const intptr_t kActivationThreshold = 0;
#endif
- return FLAG_incremental_marking &&
+ return !FLAG_expose_gc &&
+ FLAG_incremental_marking &&
!Serializer::enabled() &&
heap_->PromotedSpaceSize() > kActivationThreshold;
}
@@ -461,7 +473,9 @@ void IncrementalMarking::StartMarking(CompactionFlag flag) {
#ifdef DEBUG
// Marking bits are cleared by the sweeper.
- heap_->mark_compact_collector()->VerifyMarkbitsAreClean();
+ if (FLAG_verify_heap) {
+ heap_->mark_compact_collector()->VerifyMarkbitsAreClean();
+ }
#endif
heap_->CompletelyClearInstanceofCache();
@@ -692,6 +706,8 @@ void IncrementalMarking::Step(intptr_t allocated_bytes) {
if (allocated_ < kAllocatedThreshold) return;
+ if (state_ == MARKING && no_marking_scope_depth_ > 0) return;
+
intptr_t bytes_to_process = allocated_ * allocation_marking_factor_;
double start = 0;
@@ -739,8 +755,8 @@ void IncrementalMarking::Step(intptr_t allocated_bytes) {
}
MarkBit obj_mark_bit = Marking::MarkBitFrom(obj);
- ASSERT(Marking::IsGrey(obj_mark_bit) ||
- (obj->IsFiller() && Marking::IsWhite(obj_mark_bit)));
+ SLOW_ASSERT(Marking::IsGrey(obj_mark_bit) ||
+ (obj->IsFiller() && Marking::IsWhite(obj_mark_bit)));
Marking::MarkBlack(obj_mark_bit);
MemoryChunk::IncrementLiveBytes(obj->address(), size);
}
diff --git a/deps/v8/src/incremental-marking.h b/deps/v8/src/incremental-marking.h
index d1627bcba5..fa7337b78f 100644
--- a/deps/v8/src/incremental-marking.h
+++ b/deps/v8/src/incremental-marking.h
@@ -127,6 +127,7 @@ class IncrementalMarking {
inline void RecordWriteIntoCode(HeapObject* obj,
RelocInfo* rinfo,
Object* value);
+ void RecordCodeTargetPatch(Code* host, Address pc, HeapObject* value);
void RecordCodeTargetPatch(Address pc, HeapObject* value);
void RecordWriteOfCodeEntry(JSFunction* host, Object** slot, Code* value);
@@ -197,6 +198,14 @@ class IncrementalMarking {
}
}
+ void EnterNoMarkingScope() {
+ no_marking_scope_depth_++;
+ }
+
+ void LeaveNoMarkingScope() {
+ no_marking_scope_depth_--;
+ }
+
private:
void set_should_hurry(bool val) {
should_hurry_ = val;
@@ -248,6 +257,8 @@ class IncrementalMarking {
int allocation_marking_factor_;
intptr_t allocated_;
+ int no_marking_scope_depth_;
+
DISALLOW_IMPLICIT_CONSTRUCTORS(IncrementalMarking);
};
diff --git a/deps/v8/src/interpreter-irregexp.cc b/deps/v8/src/interpreter-irregexp.cc
index 796a447e2f..b337e88452 100644
--- a/deps/v8/src/interpreter-irregexp.cc
+++ b/deps/v8/src/interpreter-irregexp.cc
@@ -33,9 +33,9 @@
#include "utils.h"
#include "ast.h"
#include "bytecodes-irregexp.h"
+#include "jsregexp.h"
#include "interpreter-irregexp.h"
-
namespace v8 {
namespace internal {
@@ -187,12 +187,12 @@ class BacktrackStack {
template <typename Char>
-static bool RawMatch(Isolate* isolate,
- const byte* code_base,
- Vector<const Char> subject,
- int* registers,
- int current,
- uint32_t current_char) {
+static RegExpImpl::IrregexpResult RawMatch(Isolate* isolate,
+ const byte* code_base,
+ Vector<const Char> subject,
+ int* registers,
+ int current,
+ uint32_t current_char) {
const byte* pc = code_base;
// BacktrackStack ensures that the memory allocated for the backtracking stack
// is returned to the system or cached if there is no stack being cached at
@@ -211,24 +211,24 @@ static bool RawMatch(Isolate* isolate,
switch (insn & BYTECODE_MASK) {
BYTECODE(BREAK)
UNREACHABLE();
- return false;
+ return RegExpImpl::RE_FAILURE;
BYTECODE(PUSH_CP)
if (--backtrack_stack_space < 0) {
- return false; // No match on backtrack stack overflow.
+ return RegExpImpl::RE_EXCEPTION;
}
*backtrack_sp++ = current;
pc += BC_PUSH_CP_LENGTH;
break;
BYTECODE(PUSH_BT)
if (--backtrack_stack_space < 0) {
- return false; // No match on backtrack stack overflow.
+ return RegExpImpl::RE_EXCEPTION;
}
*backtrack_sp++ = Load32Aligned(pc + 4);
pc += BC_PUSH_BT_LENGTH;
break;
BYTECODE(PUSH_REGISTER)
if (--backtrack_stack_space < 0) {
- return false; // No match on backtrack stack overflow.
+ return RegExpImpl::RE_EXCEPTION;
}
*backtrack_sp++ = registers[insn >> BYTECODE_SHIFT];
pc += BC_PUSH_REGISTER_LENGTH;
@@ -278,9 +278,9 @@ static bool RawMatch(Isolate* isolate,
pc += BC_POP_REGISTER_LENGTH;
break;
BYTECODE(FAIL)
- return false;
+ return RegExpImpl::RE_FAILURE;
BYTECODE(SUCCEED)
- return true;
+ return RegExpImpl::RE_SUCCESS;
BYTECODE(ADVANCE_CP)
current += insn >> BYTECODE_SHIFT;
pc += BC_ADVANCE_CP_LENGTH;
@@ -625,11 +625,12 @@ static bool RawMatch(Isolate* isolate,
}
-bool IrregexpInterpreter::Match(Isolate* isolate,
- Handle<ByteArray> code_array,
- Handle<String> subject,
- int* registers,
- int start_position) {
+RegExpImpl::IrregexpResult IrregexpInterpreter::Match(
+ Isolate* isolate,
+ Handle<ByteArray> code_array,
+ Handle<String> subject,
+ int* registers,
+ int start_position) {
ASSERT(subject->IsFlat());
AssertNoAllocation a;
diff --git a/deps/v8/src/interpreter-irregexp.h b/deps/v8/src/interpreter-irregexp.h
index 076f0c5081..0f45d98207 100644
--- a/deps/v8/src/interpreter-irregexp.h
+++ b/deps/v8/src/interpreter-irregexp.h
@@ -1,4 +1,4 @@
-// Copyright 2008 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -36,11 +36,11 @@ namespace internal {
class IrregexpInterpreter {
public:
- static bool Match(Isolate* isolate,
- Handle<ByteArray> code,
- Handle<String> subject,
- int* captures,
- int start_position);
+ static RegExpImpl::IrregexpResult Match(Isolate* isolate,
+ Handle<ByteArray> code,
+ Handle<String> subject,
+ int* captures,
+ int start_position);
};
diff --git a/deps/v8/src/isolate.cc b/deps/v8/src/isolate.cc
index 492694e607..a073af9c37 100644
--- a/deps/v8/src/isolate.cc
+++ b/deps/v8/src/isolate.cc
@@ -98,6 +98,7 @@ void ThreadLocalTop::InitializeInternal() {
failed_access_check_callback_ = NULL;
save_context_ = NULL;
catcher_ = NULL;
+ top_lookup_result_ = NULL;
// These members are re-initialized later after deserialization
// is complete.
@@ -480,6 +481,9 @@ void Isolate::Iterate(ObjectVisitor* v, ThreadLocalTop* thread) {
for (StackFrameIterator it(this, thread); !it.done(); it.Advance()) {
it.frame()->Iterate(v);
}
+
+ // Iterate pointers in live lookup results.
+ thread->top_lookup_result_->Iterate(v);
}
@@ -1068,6 +1072,16 @@ void Isolate::DoThrow(MaybeObject* exception, MessageLocation* location) {
message_obj = MessageHandler::MakeMessageObject("uncaught_exception",
location, HandleVector<Object>(&exception_handle, 1), stack_trace,
stack_trace_object);
+ } else if (location != NULL && !location->script().is_null()) {
+ // We are bootstrapping and caught an error where the location is set
+ // and we have a script for the location.
+ // In this case we could have an extension (or an internal error
+ // somewhere) and we print out the line number at which the error occured
+ // to the console for easier debugging.
+ int line_number = GetScriptLineNumberSafe(location->script(),
+ location->start_pos());
+ OS::PrintError("Extension or internal compilation error at line %d.\n",
+ line_number);
}
}
diff --git a/deps/v8/src/isolate.h b/deps/v8/src/isolate.h
index 01ab04e60a..5453bf249a 100644
--- a/deps/v8/src/isolate.h
+++ b/deps/v8/src/isolate.h
@@ -255,6 +255,9 @@ class ThreadLocalTop BASE_EMBEDDED {
// Call back function to report unsafe JS accesses.
v8::FailedAccessCheckCallback failed_access_check_callback_;
+ // Head of the list of live LookupResults.
+ LookupResult* top_lookup_result_;
+
// Whether out of memory exceptions should be ignored.
bool ignore_out_of_memory_;
@@ -311,7 +314,6 @@ class HashMap;
V(int, bad_char_shift_table, kUC16AlphabetSize) \
V(int, good_suffix_shift_table, (kBMMaxShift + 1)) \
V(int, suffix_table, (kBMMaxShift + 1)) \
- V(uint32_t, random_seed, 2) \
V(uint32_t, private_random_seed, 2) \
ISOLATE_INIT_DEBUG_ARRAY_LIST(V)
@@ -995,6 +997,13 @@ class Isolate {
void SetData(void* data) { embedder_data_ = data; }
void* GetData() { return embedder_data_; }
+ LookupResult* top_lookup_result() {
+ return thread_local_top_.top_lookup_result_;
+ }
+ void SetTopLookupResult(LookupResult* top) {
+ thread_local_top_.top_lookup_result_ = top;
+ }
+
private:
Isolate();
diff --git a/deps/v8/src/jsregexp.cc b/deps/v8/src/jsregexp.cc
index c1a9e067c9..18ff2570e6 100644
--- a/deps/v8/src/jsregexp.cc
+++ b/deps/v8/src/jsregexp.cc
@@ -509,14 +509,16 @@ RegExpImpl::IrregexpResult RegExpImpl::IrregexpExecOnce(
}
Handle<ByteArray> byte_codes(IrregexpByteCode(*irregexp, is_ascii), isolate);
- if (IrregexpInterpreter::Match(isolate,
- byte_codes,
- subject,
- register_vector,
- index)) {
- return RE_SUCCESS;
- }
- return RE_FAILURE;
+ IrregexpResult result = IrregexpInterpreter::Match(isolate,
+ byte_codes,
+ subject,
+ register_vector,
+ index);
+ if (result == RE_EXCEPTION) {
+ ASSERT(!isolate->has_pending_exception());
+ isolate->StackOverflow();
+ }
+ return result;
#endif // V8_INTERPRETED_REGEXP
}
diff --git a/deps/v8/src/list-inl.h b/deps/v8/src/list-inl.h
index 80bccc9bc3..e2c358ceea 100644
--- a/deps/v8/src/list-inl.h
+++ b/deps/v8/src/list-inl.h
@@ -216,11 +216,11 @@ int SortedListBSearch(
int mid = (low + high) / 2;
T mid_elem = list[mid];
- if (mid_elem > elem) {
+ if (cmp(&mid_elem, &elem) > 0) {
high = mid - 1;
continue;
}
- if (mid_elem < elem) {
+ if (cmp(&mid_elem, &elem) < 0) {
low = mid + 1;
continue;
}
@@ -236,6 +236,7 @@ int SortedListBSearch(const List<T>& list, T elem) {
return SortedListBSearch<T>(list, elem, PointerValueCompare<T>);
}
+
} } // namespace v8::internal
#endif // V8_LIST_INL_H_
diff --git a/deps/v8/src/list.h b/deps/v8/src/list.h
index 055870904e..57504e075d 100644
--- a/deps/v8/src/list.h
+++ b/deps/v8/src/list.h
@@ -165,8 +165,11 @@ class List {
class Map;
class Code;
+template<typename T> class Handle;
typedef List<Map*> MapList;
typedef List<Code*> CodeList;
+typedef List<Handle<Map> > MapHandleList;
+typedef List<Handle<Code> > CodeHandleList;
// Perform binary search for an element in an already sorted
// list. Returns the index of the element of -1 if it was not found.
@@ -176,6 +179,7 @@ int SortedListBSearch(
template <typename T>
int SortedListBSearch(const List<T>& list, T elem);
+
} } // namespace v8::internal
diff --git a/deps/v8/src/liveobjectlist.cc b/deps/v8/src/liveobjectlist.cc
index d62c4d1763..408e2a3160 100644
--- a/deps/v8/src/liveobjectlist.cc
+++ b/deps/v8/src/liveobjectlist.cc
@@ -1085,7 +1085,7 @@ void LiveObjectList::SortAll() {
static int CountHeapObjects() {
int count = 0;
// Iterate over all the heap spaces and count the number of objects.
- HeapIterator iterator(HeapIterator::kFilterFreeListNodes);
+ HeapIterator iterator;
HeapObject* heap_obj = NULL;
while ((heap_obj = iterator.next()) != NULL) {
count++;
@@ -1122,7 +1122,7 @@ MaybeObject* LiveObjectList::Capture() {
// allocation, and we need allocate below.
{
// Iterate over all the heap spaces and add the objects.
- HeapIterator iterator(HeapIterator::kFilterFreeListNodes);
+ HeapIterator iterator;
HeapObject* heap_obj = NULL;
bool failed = false;
while (!failed && (heap_obj = iterator.next()) != NULL) {
@@ -2513,7 +2513,7 @@ void LiveObjectList::Verify(bool match_heap_exactly) {
OS::Print(" Start verify ...\n");
OS::Print(" Verifying ...");
Flush();
- HeapIterator iterator(HeapIterator::kFilterFreeListNodes);
+ HeapIterator iterator;
HeapObject* heap_obj = NULL;
while ((heap_obj = iterator.next()) != NULL) {
number_of_heap_objects++;
diff --git a/deps/v8/src/macros.py b/deps/v8/src/macros.py
index 7a493ca70f..a42e83c602 100644
--- a/deps/v8/src/macros.py
+++ b/deps/v8/src/macros.py
@@ -128,6 +128,11 @@ macro IS_SPEC_OBJECT(arg) = (%_IsSpecObject(arg));
# we cannot handle those anyway.
macro IS_SPEC_FUNCTION(arg) = (%_ClassOf(arg) === 'Function');
+# Indices in bound function info retrieved by %BoundFunctionGetBindings(...).
+const kBoundFunctionIndex = 0;
+const kBoundThisIndex = 1;
+const kBoundArgumentsStartIndex = 2;
+
# Inline macros. Use %IS_VAR to make sure arg is evaluated only once.
macro NUMBER_IS_NAN(arg) = (!%_IsSmi(%IS_VAR(arg)) && !(arg == arg));
macro NUMBER_IS_FINITE(arg) = (%_IsSmi(%IS_VAR(arg)) || ((arg == arg) && (arg != 1/0) && (arg != -1/0)));
diff --git a/deps/v8/src/mark-compact-inl.h b/deps/v8/src/mark-compact-inl.h
index 20f11a78a2..573715e286 100644
--- a/deps/v8/src/mark-compact-inl.h
+++ b/deps/v8/src/mark-compact-inl.h
@@ -38,7 +38,7 @@ namespace internal {
MarkBit Marking::MarkBitFrom(Address addr) {
- MemoryChunk *p = MemoryChunk::FromAddress(addr);
+ MemoryChunk* p = MemoryChunk::FromAddress(addr);
return p->markbits()->MarkBitFromIndex(p->AddressToMarkbitIndex(addr),
p->ContainsOnlyData());
}
@@ -54,9 +54,6 @@ void MarkCompactCollector::MarkObject(HeapObject* obj, MarkBit mark_bit) {
if (!mark_bit.Get()) {
mark_bit.Set();
MemoryChunk::IncrementLiveBytes(obj->address(), obj->Size());
-#ifdef DEBUG
- UpdateLiveObjectCount(obj);
-#endif
ProcessNewlyMarkedObject(obj);
}
}
@@ -67,9 +64,6 @@ void MarkCompactCollector::SetMark(HeapObject* obj, MarkBit mark_bit) {
ASSERT(Marking::MarkBitFrom(obj) == mark_bit);
mark_bit.Set();
MemoryChunk::IncrementLiveBytes(obj->address(), obj->Size());
-#ifdef DEBUG
- UpdateLiveObjectCount(obj);
-#endif
}
diff --git a/deps/v8/src/mark-compact.cc b/deps/v8/src/mark-compact.cc
index 9fa79ca746..b41b03367c 100644
--- a/deps/v8/src/mark-compact.cc
+++ b/deps/v8/src/mark-compact.cc
@@ -65,16 +65,6 @@ MarkCompactCollector::MarkCompactCollector() : // NOLINT
collect_maps_(FLAG_collect_maps),
tracer_(NULL),
migration_slots_buffer_(NULL),
-#ifdef DEBUG
- live_young_objects_size_(0),
- live_old_pointer_objects_size_(0),
- live_old_data_objects_size_(0),
- live_code_objects_size_(0),
- live_map_objects_size_(0),
- live_cell_objects_size_(0),
- live_lo_objects_size_(0),
- live_bytes_(0),
-#endif
heap_(NULL),
code_flusher_(NULL),
encountered_weak_maps_(NULL) { }
@@ -330,7 +320,7 @@ void MarkCompactCollector::VerifyMarkbitsAreClean() {
#endif
-static void ClearMarkbits(PagedSpace* space) {
+static void ClearMarkbitsInPagedSpace(PagedSpace* space) {
PageIterator it(space);
while (it.has_next()) {
@@ -339,7 +329,7 @@ static void ClearMarkbits(PagedSpace* space) {
}
-static void ClearMarkbits(NewSpace* space) {
+static void ClearMarkbitsInNewSpace(NewSpace* space) {
NewSpacePageIterator it(space->ToSpaceStart(), space->ToSpaceEnd());
while (it.has_next()) {
@@ -348,15 +338,15 @@ static void ClearMarkbits(NewSpace* space) {
}
-static void ClearMarkbits(Heap* heap) {
- ClearMarkbits(heap->code_space());
- ClearMarkbits(heap->map_space());
- ClearMarkbits(heap->old_pointer_space());
- ClearMarkbits(heap->old_data_space());
- ClearMarkbits(heap->cell_space());
- ClearMarkbits(heap->new_space());
+void MarkCompactCollector::ClearMarkbits() {
+ ClearMarkbitsInPagedSpace(heap_->code_space());
+ ClearMarkbitsInPagedSpace(heap_->map_space());
+ ClearMarkbitsInPagedSpace(heap_->old_pointer_space());
+ ClearMarkbitsInPagedSpace(heap_->old_data_space());
+ ClearMarkbitsInPagedSpace(heap_->cell_space());
+ ClearMarkbitsInNewSpace(heap_->new_space());
- LargeObjectIterator it(heap->lo_space());
+ LargeObjectIterator it(heap_->lo_space());
for (HeapObject* obj = it.Next(); obj != NULL; obj = it.Next()) {
MarkBit mark_bit = Marking::MarkBitFrom(obj);
mark_bit.Clear();
@@ -504,7 +494,7 @@ void MarkCompactCollector::Prepare(GCTracer* tracer) {
// Clear marking bits for precise sweeping to collect all garbage.
if (was_marked_incrementally_ && PreciseSweepingRequired()) {
heap()->incremental_marking()->Abort();
- ClearMarkbits(heap_);
+ ClearMarkbits();
AbortCompaction();
was_marked_incrementally_ = false;
}
@@ -523,21 +513,10 @@ void MarkCompactCollector::Prepare(GCTracer* tracer) {
}
#ifdef DEBUG
- if (!was_marked_incrementally_) {
+ if (!was_marked_incrementally_ && FLAG_verify_heap) {
VerifyMarkbitsAreClean();
}
#endif
-
-#ifdef DEBUG
- live_bytes_ = 0;
- live_young_objects_size_ = 0;
- live_old_pointer_objects_size_ = 0;
- live_old_data_objects_size_ = 0;
- live_code_objects_size_ = 0;
- live_map_objects_size_ = 0;
- live_cell_objects_size_ = 0;
- live_lo_objects_size_ = 0;
-#endif
}
@@ -2176,32 +2155,6 @@ void MarkCompactCollector::ProcessMapCaches() {
}
-#ifdef DEBUG
-void MarkCompactCollector::UpdateLiveObjectCount(HeapObject* obj) {
- live_bytes_ += obj->Size();
- if (heap()->new_space()->Contains(obj)) {
- live_young_objects_size_ += obj->Size();
- } else if (heap()->map_space()->Contains(obj)) {
- ASSERT(obj->IsMap());
- live_map_objects_size_ += obj->Size();
- } else if (heap()->cell_space()->Contains(obj)) {
- ASSERT(obj->IsJSGlobalPropertyCell());
- live_cell_objects_size_ += obj->Size();
- } else if (heap()->old_pointer_space()->Contains(obj)) {
- live_old_pointer_objects_size_ += obj->Size();
- } else if (heap()->old_data_space()->Contains(obj)) {
- live_old_data_objects_size_ += obj->Size();
- } else if (heap()->code_space()->Contains(obj)) {
- live_code_objects_size_ += obj->Size();
- } else if (heap()->lo_space()->Contains(obj)) {
- live_lo_objects_size_ += obj->Size();
- } else {
- UNREACHABLE();
- }
-}
-#endif // DEBUG
-
-
void MarkCompactCollector::ReattachInitialMaps() {
HeapObjectIterator map_iterator(heap()->map_space());
for (HeapObject* obj = map_iterator.Next();
@@ -3649,8 +3602,6 @@ void MarkCompactCollector::SweepSpaces() {
// of the previous ones.
SweepSpace(heap()->map_space(), PRECISE);
- ASSERT(live_map_objects_size_ <= heap()->map_space()->Size());
-
// Deallocate unmarked objects and clear marked bits for marked objects.
heap_->lo_space()->FreeUnmarkedObjects();
}
diff --git a/deps/v8/src/mark-compact.h b/deps/v8/src/mark-compact.h
index d54d822495..254f175b6c 100644
--- a/deps/v8/src/mark-compact.h
+++ b/deps/v8/src/mark-compact.h
@@ -61,68 +61,52 @@ class Marking {
// Impossible markbits: 01
static const char* kImpossibleBitPattern;
static inline bool IsImpossible(MarkBit mark_bit) {
- ASSERT(strcmp(kImpossibleBitPattern, "01") == 0);
return !mark_bit.Get() && mark_bit.Next().Get();
}
// Black markbits: 10 - this is required by the sweeper.
static const char* kBlackBitPattern;
static inline bool IsBlack(MarkBit mark_bit) {
- ASSERT(strcmp(kBlackBitPattern, "10") == 0);
- ASSERT(!IsImpossible(mark_bit));
return mark_bit.Get() && !mark_bit.Next().Get();
}
// White markbits: 00 - this is required by the mark bit clearer.
static const char* kWhiteBitPattern;
static inline bool IsWhite(MarkBit mark_bit) {
- ASSERT(strcmp(kWhiteBitPattern, "00") == 0);
- ASSERT(!IsImpossible(mark_bit));
return !mark_bit.Get();
}
// Grey markbits: 11
static const char* kGreyBitPattern;
static inline bool IsGrey(MarkBit mark_bit) {
- ASSERT(strcmp(kGreyBitPattern, "11") == 0);
- ASSERT(!IsImpossible(mark_bit));
return mark_bit.Get() && mark_bit.Next().Get();
}
static inline void MarkBlack(MarkBit mark_bit) {
mark_bit.Set();
mark_bit.Next().Clear();
- ASSERT(Marking::IsBlack(mark_bit));
}
static inline void BlackToGrey(MarkBit markbit) {
- ASSERT(IsBlack(markbit));
markbit.Next().Set();
- ASSERT(IsGrey(markbit));
}
static inline void WhiteToGrey(MarkBit markbit) {
- ASSERT(IsWhite(markbit));
markbit.Set();
markbit.Next().Set();
- ASSERT(IsGrey(markbit));
}
static inline void GreyToBlack(MarkBit markbit) {
- ASSERT(IsGrey(markbit));
markbit.Next().Clear();
- ASSERT(IsBlack(markbit));
}
static inline void BlackToGrey(HeapObject* obj) {
- ASSERT(obj->Size() >= 2 * kPointerSize);
BlackToGrey(MarkBitFrom(obj));
}
static inline void AnyToGrey(MarkBit markbit) {
markbit.Set();
markbit.Next().Set();
- ASSERT(IsGrey(markbit));
}
// Returns true if the the object whose mark is transferred is marked black.
@@ -173,8 +157,6 @@ class Marking {
to_mark_bit.Next().Set();
is_black = false; // Was actually gray.
}
- ASSERT(Color(from) == Color(to));
- ASSERT(is_black == (Color(to) == BLACK_OBJECT));
return is_black;
}
@@ -227,7 +209,6 @@ class MarkingDeque {
inline void PushGrey(HeapObject* object) {
ASSERT(object->IsHeapObject());
if (IsFull()) {
- ASSERT(Marking::IsGrey(Marking::MarkBitFrom(object)));
SetOverflowed();
} else {
array_[top_] = object;
@@ -246,7 +227,6 @@ class MarkingDeque {
inline void UnshiftGrey(HeapObject* object) {
ASSERT(object->IsHeapObject());
if (IsFull()) {
- ASSERT(Marking::IsGrey(Marking::MarkBitFrom(object)));
SetOverflowed();
} else {
bottom_ = ((bottom_ - 1) & mask_);
@@ -558,6 +538,8 @@ class MarkCompactCollector {
void InvalidateCode(Code* code);
+ void ClearMarkbits();
+
private:
MarkCompactCollector();
~MarkCompactCollector();
@@ -687,10 +669,6 @@ class MarkCompactCollector {
// heap object.
static bool IsUnmarkedHeapObject(Object** p);
-#ifdef DEBUG
- void UpdateLiveObjectCount(HeapObject* obj);
-#endif
-
// Map transitions from a live map to a dead map must be killed.
// We replace them with a null descriptor, with the same key.
void ClearNonLiveTransitions();
@@ -737,37 +715,7 @@ class MarkCompactCollector {
void SweepSpace(PagedSpace* space, SweeperType sweeper);
-
#ifdef DEBUG
- // -----------------------------------------------------------------------
- // Debugging variables, functions and classes
- // Counters used for debugging the marking phase of mark-compact or
- // mark-sweep collection.
-
- // Size of live objects in Heap::to_space_.
- int live_young_objects_size_;
-
- // Size of live objects in Heap::old_pointer_space_.
- int live_old_pointer_objects_size_;
-
- // Size of live objects in Heap::old_data_space_.
- int live_old_data_objects_size_;
-
- // Size of live objects in Heap::code_space_.
- int live_code_objects_size_;
-
- // Size of live objects in Heap::map_space_.
- int live_map_objects_size_;
-
- // Size of live objects in Heap::cell_space_.
- int live_cell_objects_size_;
-
- // Size of live objects in Heap::lo_space_.
- int live_lo_objects_size_;
-
- // Number of live bytes in this collection.
- int live_bytes_;
-
friend class MarkObjectVisitor;
static void VisitObject(HeapObject* obj);
diff --git a/deps/v8/src/messages.js b/deps/v8/src/messages.js
index a9993af229..e4607abd2a 100644
--- a/deps/v8/src/messages.js
+++ b/deps/v8/src/messages.js
@@ -83,7 +83,7 @@ function IsNativeErrorObject(obj) {
// objects between script tags in a browser setting.
function ToStringCheckErrorObject(obj) {
if (IsNativeErrorObject(obj)) {
- return %_CallFunction(obj, errorToString);
+ return %_CallFunction(obj, ErrorToString);
} else {
return ToString(obj);
}
@@ -185,14 +185,15 @@ function FormatMessage(message) {
"define_disallowed", ["Cannot define property:", "%0", ", object is not extensible."],
"non_extensible_proto", ["%0", " is not extensible"],
"handler_non_object", ["Proxy.", "%0", " called with non-object as handler"],
- "trap_function_expected", ["Proxy.", "%0", " called with non-function for ", "%1", " trap"],
+ "proto_non_object", ["Proxy.", "%0", " called with non-object as prototype"],
+ "trap_function_expected", ["Proxy.", "%0", " called with non-function for '", "%1", "' trap"],
"handler_trap_missing", ["Proxy handler ", "%0", " has no '", "%1", "' trap"],
"handler_trap_must_be_callable", ["Proxy handler ", "%0", " has non-callable '", "%1", "' trap"],
- "handler_returned_false", ["Proxy handler ", "%0", " returned false for '", "%1", "' trap"],
- "handler_returned_undefined", ["Proxy handler ", "%0", " returned undefined for '", "%1", "' trap"],
- "proxy_prop_not_configurable", ["Trap ", "%1", " of proxy handler ", "%0", " returned non-configurable descriptor for property ", "%2"],
- "proxy_non_object_prop_names", ["Trap ", "%1", " returned non-object ", "%0"],
- "proxy_repeated_prop_name", ["Trap ", "%1", " returned repeated property name ", "%2"],
+ "handler_returned_false", ["Proxy handler ", "%0", " returned false from '", "%1", "' trap"],
+ "handler_returned_undefined", ["Proxy handler ", "%0", " returned undefined from '", "%1", "' trap"],
+ "proxy_prop_not_configurable", ["Proxy handler ", "%0", " returned non-configurable descriptor for property '", "%2", "' from '", "%1", "' trap"],
+ "proxy_non_object_prop_names", ["Trap '", "%1", "' returned non-object ", "%0"],
+ "proxy_repeated_prop_name", ["Trap '", "%1", "' returned repeated property name '", "%2", "'"],
"invalid_weakmap_key", ["Invalid value used as weak map key"],
// RangeError
"invalid_array_length", ["Invalid array length"],
@@ -240,6 +241,7 @@ function FormatMessage(message) {
"strict_poison_pill", ["'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them"],
"strict_caller", ["Illegal access to a strict mode caller function."],
"unprotected_let", ["Illegal let declaration in unprotected statement context."],
+ "unprotected_const", ["Illegal const declaration in unprotected statement context."],
"cant_prevent_ext_external_array_elements", ["Cannot prevent extension of an object with external array elements"],
"redef_external_array_element", ["Cannot redefine a property of an object with external array elements"],
];
@@ -1126,6 +1128,7 @@ function SetUpError() {
return new f(m);
}
});
+ %SetNativeFlag(f);
}
DefineError(function Error() { });
@@ -1143,42 +1146,43 @@ $Error.captureStackTrace = captureStackTrace;
%SetProperty($Error.prototype, 'message', '', DONT_ENUM);
-// Global list of error objects visited during errorToString. This is
+// Global list of error objects visited during ErrorToString. This is
// used to detect cycles in error toString formatting.
const visited_errors = new InternalArray();
const cyclic_error_marker = new $Object();
-function errorToStringDetectCycle(error) {
+function ErrorToStringDetectCycle(error) {
if (!%PushIfAbsent(visited_errors, error)) throw cyclic_error_marker;
try {
var type = error.type;
+ var name = error.name
+ name = IS_UNDEFINED(name) ? "Error" : TO_STRING_INLINE(name);
+ var message = error.message;
var hasMessage = %_CallFunction(error, "message", ObjectHasOwnProperty);
if (type && !hasMessage) {
- var formatted = FormatMessage(%NewMessageObject(type, error.arguments));
- return error.name + ": " + formatted;
+ message = FormatMessage(%NewMessageObject(type, error.arguments));
}
- var message = hasMessage ? (": " + error.message) : "";
- return error.name + message;
+ message = IS_UNDEFINED(message) ? "" : TO_STRING_INLINE(message);
+ if (name === "") return message;
+ if (message === "") return name;
+ return name + ": " + message;
} finally {
visited_errors.length = visited_errors.length - 1;
}
}
-function errorToString() {
+function ErrorToString() {
if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
throw MakeTypeError("called_on_null_or_undefined",
["Error.prototype.toString"]);
}
- // This helper function is needed because access to properties on
- // the builtins object do not work inside of a catch clause.
- function isCyclicErrorMarker(o) { return o === cyclic_error_marker; }
try {
- return errorToStringDetectCycle(this);
+ return ErrorToStringDetectCycle(this);
} catch(e) {
// If this error message was encountered already return the empty
// string for it instead of recursively formatting it.
- if (isCyclicErrorMarker(e)) {
+ if (e === cyclic_error_marker) {
return '';
}
throw e;
@@ -1186,7 +1190,7 @@ function errorToString() {
}
-InstallFunctions($Error.prototype, DONT_ENUM, ['toString', errorToString]);
+InstallFunctions($Error.prototype, DONT_ENUM, ['toString', ErrorToString]);
// Boilerplate for exceptions for stack overflows. Used from
// Isolate::StackOverflow().
diff --git a/deps/v8/src/mips/assembler-mips-inl.h b/deps/v8/src/mips/assembler-mips-inl.h
index 553c511c34..2ba9760e2a 100644
--- a/deps/v8/src/mips/assembler-mips-inl.h
+++ b/deps/v8/src/mips/assembler-mips-inl.h
@@ -116,10 +116,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));
@@ -150,10 +150,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<Address>(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));
}
@@ -184,11 +186,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/mips/assembler-mips.h b/deps/v8/src/mips/assembler-mips.h
index 38e9537afb..b66ea0d9f9 100644
--- a/deps/v8/src/mips/assembler-mips.h
+++ b/deps/v8/src/mips/assembler-mips.h
@@ -302,7 +302,7 @@ const FPURegister f29 = { 29 };
const FPURegister f30 = { 30 };
const FPURegister f31 = { 31 };
-const FPURegister kDoubleRegZero = f28;
+static const FPURegister& kDoubleRegZero = f28;
// FPU (coprocessor 1) control registers.
// Currently only FCSR (#31) is implemented.
diff --git a/deps/v8/src/mips/builtins-mips.cc b/deps/v8/src/mips/builtins-mips.cc
index 5609d5ee4a..1687abe880 100644
--- a/deps/v8/src/mips/builtins-mips.cc
+++ b/deps/v8/src/mips/builtins-mips.cc
@@ -88,12 +88,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.
@@ -103,9 +97,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.
__ lw(scratch1, FieldMemOperand(array_function,
JSFunction::kPrototypeOrInitialMapOffset));
@@ -155,13 +149,24 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
__ sw(scratch3, MemOperand(scratch1));
__ Addu(scratch1, scratch1, kPointerSize);
- // 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++) {
+ __ sw(scratch3, MemOperand(scratch1, i * kPointerSize));
+ }
+ } else {
+ Label loop, entry;
+ __ Addu(scratch2, scratch1, Operand(initial_capacity * kPointerSize));
+ __ Branch(&entry);
+ __ bind(&loop);
__ sw(scratch3, MemOperand(scratch1));
__ Addu(scratch1, scratch1, kPointerSize);
+ __ bind(&entry);
+ __ Branch(&loop, lt, scratch1, Operand(scratch2));
}
}
@@ -177,7 +182,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,
@@ -185,31 +190,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.
__ lw(elements_array_storage,
FieldMemOperand(array_function,
JSFunction::kPrototypeOrInitialMapOffset));
- // Check whether an empty sized array is requested.
- __ Branch(&not_empty, ne, array_size, Operand(zero_reg));
-
- // 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);
- __ Branch(&allocated);
+ if (FLAG_debug_code) { // Assert that array size is not zero.
+ __ Assert(
+ ne, "array size is unexpectedly 0", array_size, Operand(zero_reg));
+ }
// Allocate the JSArray object together with space for a FixedArray with the
// requested number of elements.
- __ bind(&not_empty);
STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
__ li(elements_array_end,
(JSArray::kSize + FixedArray::kHeaderSize) / kPointerSize);
@@ -228,7 +220,6 @@ static void AllocateJSArray(MacroAssembler* masm,
// result: JSObject
// elements_array_storage: initial map
// array_size: size of array (smi)
- __ bind(&allocated);
__ sw(elements_array_storage, FieldMemOperand(result, JSObject::kMapOffset));
__ LoadRoot(elements_array_storage, Heap::kEmptyFixedArrayRootIndex);
__ sw(elements_array_storage,
@@ -262,8 +253,6 @@ static void AllocateJSArray(MacroAssembler* masm,
// 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.
STATIC_ASSERT(kSmiTag == 0);
- __ li(at, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
- __ movz(array_size, at, array_size);
ASSERT_EQ(1 * kPointerSize, FixedArray::kLengthOffset);
__ sw(array_size, MemOperand(elements_array_storage));
@@ -312,18 +301,18 @@ 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.
__ Branch(&argc_one_or_more, ne, a0, Operand(zero_reg));
// Handle construction of an empty array.
+ __ bind(&empty_array);
AllocateEmptyJSArray(masm,
a1,
a2,
a3,
t0,
t1,
- JSArray::kPreallocatedArrayElements,
call_generic_code);
__ IncrementCounter(counters->array_function_native(), 1, a3, t0);
// Setup return value, remove receiver from stack and return.
@@ -338,6 +327,12 @@ static void ArrayNativeCode(MacroAssembler* masm,
STATIC_ASSERT(kSmiTag == 0);
__ lw(a2, MemOperand(sp)); // Get the argument from the stack.
+ __ Branch(&not_empty_array, ne, a2, Operand(zero_reg));
+ __ Drop(1); // Adjust stack.
+ __ mov(a0, zero_reg); // Treat this as a call with argc of zero.
+ __ Branch(&empty_array);
+
+ __ bind(&not_empty_array);
__ And(a3, a2, Operand(kIntptrSignBit | kSmiTagMask));
__ Branch(call_generic_code, eq, a3, Operand(zero_reg));
@@ -1053,9 +1048,9 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
__ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
// Set up the roots register.
- ExternalReference roots_address =
- ExternalReference::roots_address(masm->isolate());
- __ li(s6, Operand(roots_address));
+ ExternalReference roots_array_start =
+ ExternalReference::roots_array_start(masm->isolate());
+ __ li(s6, Operand(roots_array_start));
// Push the function and the receiver onto the stack.
__ Push(a1, a2);
diff --git a/deps/v8/src/mips/code-stubs-mips.cc b/deps/v8/src/mips/code-stubs-mips.cc
index fe251b9e6f..85e929d39a 100644
--- a/deps/v8/src/mips/code-stubs-mips.cc
+++ b/deps/v8/src/mips/code-stubs-mips.cc
@@ -262,7 +262,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) {
__ sw(a2, FieldMemOperand(v0, JSArray::kElementsOffset));
// Copy the elements array.
+ ASSERT((elements_size % kPointerSize) == 0);
__ CopyFields(a2, a3, a1.bit(), elements_size / kPointerSize);
}
@@ -4071,7 +4080,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);
@@ -6889,7 +6898,7 @@ void DirectCEntryStub::Generate(MacroAssembler* masm) {
// The saved ra is after the reserved stack space for the 4 args.
__ lw(t9, MemOperand(sp, kCArgsSlotsSize));
- if (FLAG_debug_code && EnableSlowAsserts()) {
+ if (FLAG_debug_code && FLAG_enable_slow_asserts) {
// In case of an error the return address may point to a memory area
// filled with kZapValue by the GC.
// Dereference the address and check for this.
@@ -6939,7 +6948,82 @@ void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
}
-MaybeObject* StringDictionaryLookupStub::GenerateNegativeLookup(
+void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
+ Label* miss,
+ Label* done,
+ Register receiver,
+ Register properties,
+ Handle<String> 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.
+ __ lw(index, FieldMemOperand(properties, kCapacityOffset));
+ __ Subu(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);
+ __ sll(at, index, 1);
+ __ Addu(index, index, at);
+
+ Register entity_name = scratch0;
+ // Having undefined at this place means the name is not contained.
+ ASSERT_EQ(kSmiTagSize, 1);
+ Register tmp = properties;
+ __ sll(tmp, index, 1);
+ __ Addu(tmp, properties, tmp);
+ __ lw(entity_name, FieldMemOperand(tmp, kElementsStartOffset));
+
+ ASSERT(!tmp.is(entity_name));
+ __ LoadRoot(tmp, Heap::kUndefinedValueRootIndex);
+ __ Branch(done, eq, entity_name, Operand(tmp));
+
+ if (i != kInlinedProbes - 1) {
+ // Stop if found the property.
+ __ Branch(miss, eq, entity_name, Operand(Handle<String>(name)));
+
+ // Check if the entry name is not a symbol.
+ __ lw(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset));
+ __ lbu(entity_name,
+ FieldMemOperand(entity_name, Map::kInstanceTypeOffset));
+ __ And(tmp, entity_name, Operand(kIsSymbolMask));
+ __ Branch(miss, eq, tmp, Operand(zero_reg));
+
+ // Restore the properties.
+ __ lw(properties,
+ FieldMemOperand(receiver, JSObject::kPropertiesOffset));
+ }
+ }
+
+ const int spill_mask =
+ (ra.bit() | t2.bit() | t1.bit() | t0.bit() | a3.bit() |
+ a2.bit() | a1.bit() | a0.bit() | v0.bit());
+
+ __ MultiPush(spill_mask);
+ __ lw(a0, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
+ __ li(a1, Operand(Handle<String>(name)));
+ StringDictionaryLookupStub stub(NEGATIVE_LOOKUP);
+ __ CallStub(&stub);
+ __ mov(at, v0);
+ __ MultiPop(spill_mask);
+
+ __ Branch(done, eq, at, Operand(zero_reg));
+ __ Branch(miss, ne, at, Operand(zero_reg));
+}
+
+
+// TODO(kmillikin): Eliminate this function when the stub cache is fully
+// handlified.
+MaybeObject* StringDictionaryLookupStub::TryGenerateNegativeLookup(
MacroAssembler* masm,
Label* miss,
Label* done,
@@ -6965,8 +7049,7 @@ MaybeObject* StringDictionaryLookupStub::GenerateNegativeLookup(
// Scale the index by multiplying by the entry size.
ASSERT(StringDictionary::kEntrySize == 3);
// index *= 3.
- __ mov(at, index);
- __ sll(index, index, 1);
+ __ sll(at, index, 1);
__ Addu(index, index, at);
Register entity_name = scratch0;
@@ -7001,7 +7084,7 @@ MaybeObject* StringDictionaryLookupStub::GenerateNegativeLookup(
const int spill_mask =
(ra.bit() | t2.bit() | t1.bit() | t0.bit() | a3.bit() |
- a2.bit() | a1.bit() | a0.bit());
+ a2.bit() | a1.bit() | a0.bit() | v0.bit());
__ MultiPush(spill_mask);
__ lw(a0, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
@@ -7009,10 +7092,11 @@ MaybeObject* StringDictionaryLookupStub::GenerateNegativeLookup(
StringDictionaryLookupStub stub(NEGATIVE_LOOKUP);
MaybeObject* result = masm->TryCallStub(&stub);
if (result->IsFailure()) return result;
+ __ mov(at, v0);
__ MultiPop(spill_mask);
- __ Branch(done, eq, v0, Operand(zero_reg));
- __ Branch(miss, ne, v0, Operand(zero_reg));
+ __ Branch(done, eq, at, Operand(zero_reg));
+ __ Branch(miss, ne, at, Operand(zero_reg));
return result;
}
@@ -7058,8 +7142,7 @@ void StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
ASSERT(StringDictionary::kEntrySize == 3);
// scratch2 = scratch2 * 3.
- __ mov(at, scratch2);
- __ sll(scratch2, scratch2, 1);
+ __ sll(at, scratch2, 1);
__ Addu(scratch2, scratch2, at);
// Check if the key is identical to the name.
@@ -7071,19 +7154,26 @@ void StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
const int spill_mask =
(ra.bit() | t2.bit() | t1.bit() | t0.bit() |
- a3.bit() | a2.bit() | a1.bit() | a0.bit()) &
+ a3.bit() | a2.bit() | a1.bit() | a0.bit() | v0.bit()) &
~(scratch1.bit() | scratch2.bit());
__ MultiPush(spill_mask);
- __ Move(a0, elements);
- __ Move(a1, name);
+ if (name.is(a0)) {
+ ASSERT(!elements.is(a1));
+ __ Move(a1, name);
+ __ Move(a0, elements);
+ } else {
+ __ Move(a0, elements);
+ __ Move(a1, name);
+ }
StringDictionaryLookupStub stub(POSITIVE_LOOKUP);
__ CallStub(&stub);
__ mov(scratch2, a2);
+ __ mov(at, v0);
__ MultiPop(spill_mask);
- __ Branch(done, ne, v0, Operand(zero_reg));
- __ Branch(miss, eq, v0, Operand(zero_reg));
+ __ Branch(done, ne, at, Operand(zero_reg));
+ __ Branch(miss, eq, at, Operand(zero_reg));
}
@@ -7207,6 +7297,13 @@ struct AheadOfTimeWriteBarrierStubList kAheadOfTime[] = {
{ a3, a1, a2, EMIT_REMEMBERED_SET },
// KeyedStoreStubCompiler::GenerateStoreFastElement.
{ t0, a2, a3, EMIT_REMEMBERED_SET },
+ // ElementsTransitionGenerator::GenerateSmiOnlyToObject
+ // and ElementsTransitionGenerator::GenerateSmiOnlyToDouble
+ // and ElementsTransitionGenerator::GenerateDoubleToObject
+ { a2, a3, t5, EMIT_REMEMBERED_SET },
+ // ElementsTransitionGenerator::GenerateDoubleToObject
+ { t2, a2, a0, EMIT_REMEMBERED_SET },
+ { a2, t2, t5, EMIT_REMEMBERED_SET },
// Null termination.
{ no_reg, no_reg, no_reg, EMIT_REMEMBERED_SET}
};
diff --git a/deps/v8/src/mips/code-stubs-mips.h b/deps/v8/src/mips/code-stubs-mips.h
index ef6b88908e..beb20aab4f 100644
--- a/deps/v8/src/mips/code-stubs-mips.h
+++ b/deps/v8/src/mips/code-stubs-mips.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<String> 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/mips/codegen-mips.cc b/deps/v8/src/mips/codegen-mips.cc
index ff146dd4ed..e9fe2324ea 100644
--- a/deps/v8/src/mips/codegen-mips.cc
+++ b/deps/v8/src/mips/codegen-mips.cc
@@ -30,10 +30,13 @@
#if defined(V8_TARGET_ARCH_MIPS)
#include "codegen.h"
+#include "macro-assembler.h"
namespace v8 {
namespace internal {
+#define __ ACCESS_MASM(masm)
+
// -------------------------------------------------------------------------
// Platform-specific RuntimeCallHelper functions.
@@ -50,6 +53,260 @@ void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const {
masm->set_has_frame(false);
}
+// -------------------------------------------------------------------------
+// Code generators
+
+void ElementsTransitionGenerator::GenerateSmiOnlyToObject(
+ MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- a0 : value
+ // -- a1 : key
+ // -- a2 : receiver
+ // -- ra : return address
+ // -- a3 : target map, scratch for subsequent call
+ // -- t0 : scratch (elements)
+ // -----------------------------------
+ // Set transitioned map.
+ __ sw(a3, FieldMemOperand(a2, HeapObject::kMapOffset));
+ __ RecordWriteField(a2,
+ HeapObject::kMapOffset,
+ a3,
+ t5,
+ kRAHasNotBeenSaved,
+ kDontSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+}
+
+
+void ElementsTransitionGenerator::GenerateSmiOnlyToDouble(
+ MacroAssembler* masm, Label* fail) {
+ // ----------- S t a t e -------------
+ // -- a0 : value
+ // -- a1 : key
+ // -- a2 : receiver
+ // -- ra : return address
+ // -- a3 : target map, scratch for subsequent call
+ // -- t0 : scratch (elements)
+ // -----------------------------------
+ Label loop, entry, convert_hole, gc_required;
+ bool fpu_supported = CpuFeatures::IsSupported(FPU);
+ __ push(ra);
+
+ Register scratch = t6;
+
+ __ lw(t0, FieldMemOperand(a2, JSObject::kElementsOffset));
+ __ lw(t1, FieldMemOperand(t0, FixedArray::kLengthOffset));
+ // t0: source FixedArray
+ // t1: number of elements (smi-tagged)
+
+ // Allocate new FixedDoubleArray.
+ __ sll(scratch, t1, 2);
+ __ Addu(scratch, scratch, FixedDoubleArray::kHeaderSize);
+ __ AllocateInNewSpace(scratch, t2, t3, t5, &gc_required, NO_ALLOCATION_FLAGS);
+ // t2: destination FixedDoubleArray, not tagged as heap object
+ __ LoadRoot(t5, Heap::kFixedDoubleArrayMapRootIndex);
+ __ sw(t5, MemOperand(t2, HeapObject::kMapOffset));
+ // Set destination FixedDoubleArray's length.
+ __ sw(t1, MemOperand(t2, FixedDoubleArray::kLengthOffset));
+ // Update receiver's map.
+
+ __ sw(a3, FieldMemOperand(a2, HeapObject::kMapOffset));
+ __ RecordWriteField(a2,
+ HeapObject::kMapOffset,
+ a3,
+ t5,
+ kRAHasBeenSaved,
+ kDontSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+ // Replace receiver's backing store with newly created FixedDoubleArray.
+ __ Addu(a3, t2, Operand(kHeapObjectTag));
+ __ sw(a3, FieldMemOperand(a2, JSObject::kElementsOffset));
+ __ RecordWriteField(a2,
+ JSObject::kElementsOffset,
+ a3,
+ t5,
+ kRAHasBeenSaved,
+ kDontSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+
+
+ // Prepare for conversion loop.
+ __ Addu(a3, t0, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+ __ Addu(t3, t2, Operand(FixedDoubleArray::kHeaderSize));
+ __ sll(t2, t1, 2);
+ __ Addu(t2, t2, t3);
+ __ li(t0, Operand(kHoleNanLower32));
+ __ li(t1, Operand(kHoleNanUpper32));
+ // t0: kHoleNanLower32
+ // t1: kHoleNanUpper32
+ // t2: end of destination FixedDoubleArray, not tagged
+ // t3: begin of FixedDoubleArray element fields, not tagged
+
+ if (!fpu_supported) __ Push(a1, a0);
+
+ __ Branch(&entry);
+
+ // Call into runtime if GC is required.
+ __ bind(&gc_required);
+ __ pop(ra);
+ __ Branch(fail);
+
+ // Convert and copy elements.
+ __ bind(&loop);
+ __ lw(t5, MemOperand(a3));
+ __ Addu(a3, a3, kIntSize);
+ // t5: current element
+ __ JumpIfNotSmi(t5, &convert_hole);
+
+ // Normal smi, convert to double and store.
+ __ SmiUntag(t5);
+ if (fpu_supported) {
+ CpuFeatures::Scope scope(FPU);
+ __ mtc1(t5, f0);
+ __ cvt_d_w(f0, f0);
+ __ sdc1(f0, MemOperand(t3));
+ __ Addu(t3, t3, kDoubleSize);
+ } else {
+ FloatingPointHelper::ConvertIntToDouble(masm,
+ t5,
+ FloatingPointHelper::kCoreRegisters,
+ f0,
+ a0,
+ a1,
+ t7,
+ f0);
+ __ sw(a0, MemOperand(t3)); // mantissa
+ __ sw(a1, MemOperand(t3, kIntSize)); // exponent
+ __ Addu(t3, t3, kDoubleSize);
+ }
+ __ Branch(&entry);
+
+ // Hole found, store the-hole NaN.
+ __ bind(&convert_hole);
+ __ sw(t0, MemOperand(t3)); // mantissa
+ __ sw(t1, MemOperand(t3, kIntSize)); // exponent
+ __ Addu(t3, t3, kDoubleSize);
+
+ __ bind(&entry);
+ __ Branch(&loop, lt, t3, Operand(t2));
+
+ if (!fpu_supported) __ Pop(a1, a0);
+ __ pop(ra);
+}
+
+
+void ElementsTransitionGenerator::GenerateDoubleToObject(
+ MacroAssembler* masm, Label* fail) {
+ // ----------- S t a t e -------------
+ // -- a0 : value
+ // -- a1 : key
+ // -- a2 : receiver
+ // -- ra : return address
+ // -- a3 : target map, scratch for subsequent call
+ // -- t0 : scratch (elements)
+ // -----------------------------------
+ Label entry, loop, convert_hole, gc_required;
+ __ MultiPush(a0.bit() | a1.bit() | a2.bit() | a3.bit() | ra.bit());
+
+ __ lw(t0, FieldMemOperand(a2, JSObject::kElementsOffset));
+ __ lw(t1, FieldMemOperand(t0, FixedArray::kLengthOffset));
+ // t0: source FixedArray
+ // t1: number of elements (smi-tagged)
+
+ // Allocate new FixedArray.
+ __ sll(a0, t1, 1);
+ __ Addu(a0, a0, FixedDoubleArray::kHeaderSize);
+ __ AllocateInNewSpace(a0, t2, t3, t5, &gc_required, NO_ALLOCATION_FLAGS);
+ // t2: destination FixedArray, not tagged as heap object
+ __ LoadRoot(t5, Heap::kFixedArrayMapRootIndex);
+ __ sw(t5, MemOperand(t2, HeapObject::kMapOffset));
+ // Set destination FixedDoubleArray's length.
+ __ sw(t1, MemOperand(t2, FixedDoubleArray::kLengthOffset));
+
+ // Prepare for conversion loop.
+ __ Addu(t0, t0, Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag + 4));
+ __ Addu(a3, t2, Operand(FixedArray::kHeaderSize));
+ __ Addu(t2, t2, Operand(kHeapObjectTag));
+ __ sll(t1, t1, 1);
+ __ Addu(t1, a3, t1);
+ __ LoadRoot(t3, Heap::kTheHoleValueRootIndex);
+ __ LoadRoot(t5, Heap::kHeapNumberMapRootIndex);
+ // Using offsetted addresses.
+ // a3: begin of destination FixedArray element fields, not tagged
+ // t0: begin of source FixedDoubleArray element fields, not tagged, +4
+ // t1: end of destination FixedArray, not tagged
+ // t2: destination FixedArray
+ // t3: the-hole pointer
+ // t5: heap number map
+ __ Branch(&entry);
+
+ // Call into runtime if GC is required.
+ __ bind(&gc_required);
+ __ MultiPop(a0.bit() | a1.bit() | a2.bit() | a3.bit() | ra.bit());
+
+ __ Branch(fail);
+
+ __ bind(&loop);
+ __ lw(a1, MemOperand(t0));
+ __ Addu(t0, t0, kDoubleSize);
+ // a1: current element's upper 32 bit
+ // t0: address of next element's upper 32 bit
+ __ Branch(&convert_hole, eq, a1, Operand(kHoleNanUpper32));
+
+ // Non-hole double, copy value into a heap number.
+ __ AllocateHeapNumber(a2, a0, t6, t5, &gc_required);
+ // a2: new heap number
+ __ lw(a0, MemOperand(t0, -12));
+ __ sw(a0, FieldMemOperand(a2, HeapNumber::kMantissaOffset));
+ __ sw(a1, FieldMemOperand(a2, HeapNumber::kExponentOffset));
+ __ mov(a0, a3);
+ __ sw(a2, MemOperand(a3));
+ __ Addu(a3, a3, kIntSize);
+ __ RecordWrite(t2,
+ a0,
+ a2,
+ kRAHasBeenSaved,
+ kDontSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+ __ Branch(&entry);
+
+ // Replace the-hole NaN with the-hole pointer.
+ __ bind(&convert_hole);
+ __ sw(t3, MemOperand(a3));
+ __ Addu(a3, a3, kIntSize);
+
+ __ bind(&entry);
+ __ Branch(&loop, lt, a3, Operand(t1));
+
+ __ MultiPop(a2.bit() | a3.bit() | a0.bit() | a1.bit());
+ // Update receiver's map.
+ __ sw(a3, FieldMemOperand(a2, HeapObject::kMapOffset));
+ __ RecordWriteField(a2,
+ HeapObject::kMapOffset,
+ a3,
+ t5,
+ kRAHasBeenSaved,
+ kDontSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+ // Replace receiver's backing store with newly created and filled FixedArray.
+ __ sw(t2, FieldMemOperand(a2, JSObject::kElementsOffset));
+ __ RecordWriteField(a2,
+ JSObject::kElementsOffset,
+ t2,
+ t5,
+ kRAHasBeenSaved,
+ kDontSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+ __ pop(ra);
+}
+
+#undef __
} } // namespace v8::internal
diff --git a/deps/v8/src/mips/codegen-mips.h b/deps/v8/src/mips/codegen-mips.h
index b020d80575..4549509f30 100644
--- a/deps/v8/src/mips/codegen-mips.h
+++ b/deps/v8/src/mips/codegen-mips.h
@@ -31,7 +31,6 @@
#include "ast.h"
-#include "code-stubs-mips.h"
#include "ic-inl.h"
namespace v8 {
diff --git a/deps/v8/src/mips/deoptimizer-mips.cc b/deps/v8/src/mips/deoptimizer-mips.cc
index 280b8cb549..92d7edd836 100644
--- a/deps/v8/src/mips/deoptimizer-mips.cc
+++ b/deps/v8/src/mips/deoptimizer-mips.cc
@@ -61,7 +61,8 @@ void Deoptimizer::PatchStackCheckCodeAt(Code* unoptimized_code,
}
-void Deoptimizer::RevertStackCheckCodeAt(Address pc_after,
+void Deoptimizer::RevertStackCheckCodeAt(Code* unoptimized_code,
+ Address pc_after,
Code* check_code,
Code* replacement_code) {
UNIMPLEMENTED();
diff --git a/deps/v8/src/mips/full-codegen-mips.cc b/deps/v8/src/mips/full-codegen-mips.cc
index b3f0540872..2f989bc6f3 100644
--- a/deps/v8/src/mips/full-codegen-mips.cc
+++ b/deps/v8/src/mips/full-codegen-mips.cc
@@ -278,7 +278,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());
}
@@ -728,6 +731,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);
@@ -739,7 +744,7 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
Comment cmnt(masm_, "[ Declaration");
VisitForAccumulatorValue(function);
__ sw(result_register(), StackOperand(variable));
- } else if (mode == CONST || mode == LET) {
+ } else if (binding_needs_init) {
Comment cmnt(masm_, "[ Declaration");
__ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
__ sw(t0, StackOperand(variable));
@@ -775,7 +780,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(at, Heap::kTheHoleValueRootIndex);
__ sw(at, ContextOperand(cp, variable->index()));
@@ -787,9 +792,13 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
case Variable::LOOKUP: {
Comment cmnt(masm_, "[ Declaration");
__ li(a2, 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;
__ li(a1, Operand(Smi::FromInt(attr)));
// Push initial value, if any.
// Note: For variables we must not push an initial value (such as
@@ -799,7 +808,7 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
__ Push(cp, a2, a1);
// Push initial value for function declaration.
VisitForStackValue(function);
- } else if (mode == CONST || mode == LET) {
+ } else if (binding_needs_init) {
__ LoadRoot(a0, Heap::kTheHoleValueRootIndex);
__ Push(cp, a2, a1, a0);
} else {
@@ -942,11 +951,17 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
__ bind(&done_convert);
__ push(a0);
+ // Check for proxies.
+ Label call_runtime;
+ STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
+ __ GetObjectType(a0, a1, a1);
+ __ Branch(&call_runtime, le, a1, Operand(LAST_JS_PROXY_TYPE));
+
// 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 = t2;
__ LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
@@ -1020,9 +1035,16 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
__ jmp(&loop);
// We got a fixed array in register v0. Iterate through that.
+ Label non_proxy;
__ bind(&fixed_array);
- __ li(a1, Operand(Smi::FromInt(0))); // Map (0) - force slow check.
- __ Push(a1, v0);
+ __ li(a1, Operand(Smi::FromInt(1))); // Smi indicates slow check
+ __ lw(a2, MemOperand(sp, 0 * kPointerSize)); // Get enumerated object
+ STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
+ __ GetObjectType(a2, a3, a3);
+ __ Branch(&non_proxy, gt, a3, Operand(LAST_JS_PROXY_TYPE));
+ __ li(a1, Operand(Smi::FromInt(0))); // Zero indicates proxy
+ __ bind(&non_proxy);
+ __ Push(a1, v0); // Smi and array
__ lw(a1, FieldMemOperand(v0, FixedArray::kLengthOffset));
__ li(a0, Operand(Smi::FromInt(0)));
__ Push(a1, a0); // Fixed array length (as smi) and initial index.
@@ -1041,17 +1063,22 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
__ addu(t0, a2, t0); // Array base + scaled (smi) index.
__ lw(a3, MemOperand(t0)); // Current entry.
- // 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 a2.
__ lw(a2, 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;
__ lw(a1, MemOperand(sp, 4 * kPointerSize));
__ lw(t0, FieldMemOperand(a1, HeapObject::kMapOffset));
__ Branch(&update_each, eq, t0, Operand(a2));
+ // For proxies, no filtering is done.
+ // TODO(rossberg): What if only a prototype is a proxy? Not specified yet.
+ ASSERT_EQ(Smi::FromInt(0), 0);
+ __ Branch(&update_each, eq, a2, Operand(zero_reg));
+
// 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.
@@ -1106,7 +1133,7 @@ void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
!pretenure &&
scope()->is_function_scope() &&
info->num_literals() == 0) {
- FastNewClosureStub stub(info->strict_mode() ? kStrictMode : kNonStrictMode);
+ FastNewClosureStub stub(info->strict_mode_flag());
__ li(a0, Operand(info));
__ push(a0);
__ CallStub(&stub);
@@ -1137,7 +1164,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.
__ lw(temp, ContextOperand(current, Context::EXTENSION_INDEX));
__ Branch(slow, ne, temp, Operand(zero_reg));
@@ -1149,7 +1176,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();
}
@@ -1191,7 +1218,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.
__ lw(temp, ContextOperand(context, Context::EXTENSION_INDEX));
__ Branch(slow, ne, temp, Operand(zero_reg));
@@ -1228,13 +1255,14 @@ void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var,
Variable* local = var->local_if_not_shadowed();
__ lw(v0, ContextSlotOperandCheckExtensions(local, slow));
if (local->mode() == CONST ||
+ local->mode() == CONST_HARMONY ||
local->mode() == LET) {
__ LoadRoot(at, Heap::kTheHoleValueRootIndex);
__ subu(at, v0, at); // Sub as compare: at == 0 on eq.
if (local->mode() == CONST) {
__ LoadRoot(a0, Heap::kUndefinedValueRootIndex);
__ movz(v0, a0, at); // Conditional move: return Undefined if TheHole.
- } else { // LET
+ } else { // LET || CONST_HARMONY
__ Branch(done, ne, at, Operand(zero_reg));
__ li(a0, Operand(var->name()));
__ push(a0);
@@ -1272,14 +1300,16 @@ 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(v0, var);
__ LoadRoot(at, Heap::kTheHoleValueRootIndex);
__ subu(at, v0, at); // Sub as compare: at == 0 on eq.
- 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;
__ Branch(&done, ne, at, Operand(zero_reg));
__ li(a0, Operand(var->name()));
@@ -1287,6 +1317,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(a0, Heap::kUndefinedValueRootIndex);
__ movz(v0, a0, at); // Conditional move: Undefined if TheHole.
}
@@ -1476,13 +1508,21 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
ZoneList<Expression*>* subexprs = expr->values();
int length = subexprs->length();
+
+ Handle<FixedArray> constant_elements = expr->constant_elements();
+ ASSERT_EQ(2, constant_elements->length());
+ ElementsKind constant_elements_kind =
+ static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
+ Handle<FixedArrayBase> constant_elements_values(
+ FixedArrayBase::cast(constant_elements->get(1)));
+
__ mov(a0, result_register());
__ lw(a3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
__ lw(a3, FieldMemOperand(a3, JSFunction::kLiteralsOffset));
__ li(a2, Operand(Smi::FromInt(expr->literal_index())));
- __ li(a1, Operand(expr->constant_elements()));
+ __ li(a1, Operand(constant_elements));
__ Push(a3, a2, a1);
- if (expr->constant_elements()->map() ==
+ if (constant_elements_values->map() ==
isolate()->heap()->fixed_cow_array_map()) {
FastCloneShallowArrayStub stub(
FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length);
@@ -1494,8 +1534,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);
}
@@ -1518,24 +1564,57 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
}
VisitForAccumulatorValue(subexpr);
- // Store the subexpression value in the array's elements.
__ lw(t6, MemOperand(sp)); // Copy of array literal.
__ lw(a1, FieldMemOperand(t6, JSObject::kElementsOffset));
+ __ lw(a2, FieldMemOperand(t6, JSObject::kMapOffset));
int offset = FixedArray::kHeaderSize + (i * kPointerSize);
+
+ Label element_done;
+ Label double_elements;
+ Label smi_element;
+ Label slow_elements;
+ Label fast_elements;
+ __ CheckFastElements(a2, a3, &double_elements);
+
+ // FAST_SMI_ONLY_ELEMENTS or FAST_ELEMENTS
+ __ JumpIfSmi(result_register(), &smi_element);
+ __ CheckFastSmiOnlyElements(a2, a3, &fast_elements);
+
+ // Store into the array literal requires a elements transition. Call into
+ // the runtime.
+ __ bind(&slow_elements);
+ __ push(t6); // Copy of array literal.
+ __ li(a1, Operand(Smi::FromInt(i)));
+ __ li(a2, Operand(Smi::FromInt(NONE))); // PropertyAttributes
+ __ li(a3, Operand(Smi::FromInt(strict_mode_flag()))); // Strict mode.
+ __ Push(a1, result_register(), a2, a3);
+ __ CallRuntime(Runtime::kSetProperty, 5);
+ __ Branch(&element_done);
+
+ // Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS.
+ __ bind(&double_elements);
+ __ li(a3, Operand(Smi::FromInt(i)));
+ __ StoreNumberToDoubleElements(result_register(), a3, t6, a1, t0, t1, t5,
+ t3, &slow_elements);
+ __ Branch(&element_done);
+
+ // Array literal has ElementsKind of FAST_ELEMENTS and value is an object.
+ __ bind(&fast_elements);
__ sw(result_register(), FieldMemOperand(a1, offset));
+ // Update the write barrier for the array store.
- Label no_map_change;
- __ JumpIfSmi(result_register(), &no_map_change);
- // Update the write barrier for the array store with v0 as the scratch
- // register.
__ RecordWriteField(
a1, offset, result_register(), a2, kRAHasBeenSaved, kDontSaveFPRegs,
EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
- __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
- __ CheckFastSmiOnlyElements(a3, a2, &no_map_change);
- __ push(t6); // Copy of array literal.
- __ CallRuntime(Runtime::kNonSmiElementStored, 1);
- __ bind(&no_map_change);
+ __ Branch(&element_done);
+
+ // Array literal has ElementsKind of FAST_SMI_ONLY_ELEMENTS or
+ // FAST_ELEMENTS, and value is Smi.
+ __ bind(&smi_element);
+ __ sw(result_register(), FieldMemOperand(a1, offset));
+ // Fall through
+
+ __ bind(&element_done);
PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
}
@@ -1917,8 +1996,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, a1);
if (FLAG_debug_code && op == Token::INIT_LET) {
@@ -2803,10 +2883,10 @@ void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) {
// ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
if (CpuFeatures::IsSupported(FPU)) {
__ PrepareCallCFunction(1, a0);
- __ li(a0, Operand(ExternalReference::isolate_address()));
+ __ lw(a0, ContextOperand(cp, Context::GLOBAL_INDEX));
+ __ lw(a0, FieldMemOperand(a0, GlobalObject::kGlobalContextOffset));
__ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
-
CpuFeatures::Scope scope(FPU);
// 0x41300000 is the top half of 1.0 x 2^20 as a double.
__ li(a1, Operand(0x41300000));
@@ -2821,7 +2901,8 @@ void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) {
} else {
__ PrepareCallCFunction(2, a0);
__ mov(a0, s0);
- __ li(a1, Operand(ExternalReference::isolate_address()));
+ __ lw(a1, ContextOperand(cp, Context::GLOBAL_INDEX));
+ __ lw(a1, FieldMemOperand(a1, GlobalObject::kGlobalContextOffset));
__ CallCFunction(
ExternalReference::fill_heap_number_with_random_function(isolate()), 2);
}
@@ -4100,36 +4181,26 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
case Token::EQ_STRICT:
case Token::EQ:
cc = eq;
- __ mov(a0, result_register());
- __ pop(a1);
break;
case Token::LT:
cc = lt;
- __ mov(a0, result_register());
- __ pop(a1);
break;
case Token::GT:
- // Reverse left and right sides to obtain ECMA-262 conversion order.
- cc = lt;
- __ mov(a1, result_register());
- __ pop(a0);
+ cc = gt;
break;
case Token::LTE:
- // Reverse left and right sides to obtain ECMA-262 conversion order.
- cc = ge;
- __ mov(a1, result_register());
- __ pop(a0);
+ cc = le;
break;
case Token::GTE:
cc = ge;
- __ mov(a0, result_register());
- __ pop(a1);
break;
case Token::IN:
case Token::INSTANCEOF:
default:
UNREACHABLE();
}
+ __ mov(a0, result_register());
+ __ pop(a1);
bool inline_smi_code = ShouldInlineSmiCase(op);
JumpPatchSite patch_site(masm_);
diff --git a/deps/v8/src/mips/ic-mips.cc b/deps/v8/src/mips/ic-mips.cc
index fb33eb6651..ca6383cba7 100644
--- a/deps/v8/src/mips/ic-mips.cc
+++ b/deps/v8/src/mips/ic-mips.cc
@@ -384,10 +384,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 -------------
// -- a1 : receiver
// -- a2 : name
@@ -397,7 +397,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(
@@ -463,7 +463,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 -------------
// -- a2 : name
// -- ra : 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 -------------
// -- a2 : name
// -- ra : return address
@@ -540,7 +540,7 @@ static void GenerateCallMiss(MacroAssembler* masm,
__ bind(&invoke);
}
// 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);
@@ -552,18 +552,6 @@ static void GenerateCallMiss(MacroAssembler* masm,
}
-void CallIC::GenerateMiss(MacroAssembler* masm,
- int argc,
- Code::ExtraICState extra_ic_state) {
- // ----------- S t a t e -------------
- // -- a2 : name
- // -- ra : return address
- // -----------------------------------
-
- GenerateCallMiss(masm, argc, IC::kCallIC_Miss, extra_ic_state);
-}
-
-
void CallIC::GenerateMegamorphic(MacroAssembler* masm,
int argc,
Code::ExtraICState extra_ic_state) {
@@ -579,27 +567,6 @@ void CallIC::GenerateMegamorphic(MacroAssembler* masm,
}
-void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
- // ----------- S t a t e -------------
- // -- a2 : name
- // -- ra : return address
- // -----------------------------------
-
- GenerateCallNormal(masm, argc);
- GenerateMiss(masm, argc, Code::kNoExtraICState);
-}
-
-
-void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) {
- // ----------- S t a t e -------------
- // -- a2 : name
- // -- ra : return address
- // -----------------------------------
-
- GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss, Code::kNoExtraICState);
-}
-
-
void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
// ----------- S t a t e -------------
// -- a2 : name
@@ -716,7 +683,7 @@ void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
__ JumpIfSmi(a2, &miss);
__ IsObjectJSStringType(a2, a0, &miss);
- GenerateCallNormal(masm, argc);
+ CallICBase::GenerateNormal(masm, argc);
__ bind(&miss);
GenerateMiss(masm, argc);
}
@@ -1421,6 +1388,47 @@ void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
}
+void KeyedStoreIC::GenerateTransitionElementsSmiToDouble(MacroAssembler* masm) {
+ // ---------- S t a t e --------------
+ // -- a2 : receiver
+ // -- a3 : target map
+ // -- ra : return address
+ // -----------------------------------
+ // Must return the modified receiver in v0.
+ if (!FLAG_trace_elements_transitions) {
+ Label fail;
+ ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &fail);
+ __ Ret(USE_DELAY_SLOT);
+ __ mov(v0, a2);
+ __ bind(&fail);
+ }
+
+ __ push(a2);
+ __ TailCallRuntime(Runtime::kTransitionElementsSmiToDouble, 1, 1);
+}
+
+
+void KeyedStoreIC::GenerateTransitionElementsDoubleToObject(
+ MacroAssembler* masm) {
+ // ---------- S t a t e --------------
+ // -- a2 : receiver
+ // -- a3 : target map
+ // -- ra : return address
+ // -----------------------------------
+ // Must return the modified receiver in v0.
+ if (!FLAG_trace_elements_transitions) {
+ Label fail;
+ ElementsTransitionGenerator::GenerateDoubleToObject(masm, &fail);
+ __ Ret(USE_DELAY_SLOT);
+ __ mov(v0, a2);
+ __ bind(&fail);
+ }
+
+ __ push(a2);
+ __ TailCallRuntime(Runtime::kTransitionElementsDoubleToObject, 1, 1);
+}
+
+
void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
StrictModeFlag strict_mode) {
// ----------- S t a t e -------------
@@ -1560,11 +1568,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/mips/macro-assembler-mips.cc b/deps/v8/src/mips/macro-assembler-mips.cc
index 2964fbc86c..32dce660d8 100644
--- a/deps/v8/src/mips/macro-assembler-mips.cc
+++ b/deps/v8/src/mips/macro-assembler-mips.cc
@@ -2873,6 +2873,7 @@ void MacroAssembler::AllocateInNewSpace(Register object_size,
ASSERT(!result.is(scratch1));
ASSERT(!result.is(scratch2));
ASSERT(!scratch1.is(scratch2));
+ ASSERT(!object_size.is(t9));
ASSERT(!scratch1.is(t9) && !scratch2.is(t9) && !result.is(t9));
// Check relative positions of allocation top and limit addresses.
@@ -3616,24 +3617,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.
li(a1, Operand(Handle<JSFunction>(function)));
lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
- // Invoke the cached code.
- Handle<Code> 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.
- lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
- InvokeCode(a3, 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.
+ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
+ InvokeCode(a3, expected, actual, flag, NullCallWrapper(), call_kind);
}
@@ -3674,7 +3667,8 @@ void MacroAssembler::IsObjectJSStringType(Register object,
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);
@@ -3682,6 +3676,16 @@ void MacroAssembler::TryGetFunctionPrototype(Register function,
GetObjectType(function, result, scratch);
Branch(miss, ne, scratch, Operand(JS_FUNCTION_TYPE));
+ if (miss_on_bound_function) {
+ lw(scratch,
+ FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
+ lw(scratch,
+ FieldMemOperand(scratch, SharedFunctionInfo::kCompilerHintsOffset));
+ And(scratch, scratch,
+ Operand(Smi::FromInt(1 << SharedFunctionInfo::kBoundFunction)));
+ Branch(miss, ne, scratch, Operand(zero_reg));
+ }
+
// Make sure that the function has an instance prototype.
Label non_instance;
lbu(scratch, FieldMemOperand(result, Map::kBitFieldOffset));
diff --git a/deps/v8/src/mips/macro-assembler-mips.h b/deps/v8/src/mips/macro-assembler-mips.h
index 6f81a4bd6a..84c55f7e60 100644
--- a/deps/v8/src/mips/macro-assembler-mips.h
+++ b/deps/v8/src/mips/macro-assembler-mips.h
@@ -887,7 +887,8 @@ class MacroAssembler: public Assembler {
void TryGetFunctionPrototype(Register function,
Register result,
Register scratch,
- Label* miss);
+ Label* miss,
+ bool miss_on_bound_function = false);
void GetObjectType(Register function,
Register map,
diff --git a/deps/v8/src/mips/regexp-macro-assembler-mips.cc b/deps/v8/src/mips/regexp-macro-assembler-mips.cc
index 9db5c5bed2..cb210fed04 100644
--- a/deps/v8/src/mips/regexp-macro-assembler-mips.cc
+++ b/deps/v8/src/mips/regexp-macro-assembler-mips.cc
@@ -1112,6 +1112,11 @@ int RegExpMacroAssemblerMIPS::CheckStackGuardState(Address* return_address,
frame_entry<const String*>(re_frame, kInputString) = *subject;
frame_entry<const byte*>(re_frame, kInputStart) = new_address;
frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length;
+ } else if (frame_entry<const String*>(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<const String*>(re_frame, kInputString) = *subject;
}
return 0;
diff --git a/deps/v8/src/mips/simulator-mips.cc b/deps/v8/src/mips/simulator-mips.cc
index 17c18977c7..0ec3e283c6 100644
--- a/deps/v8/src/mips/simulator-mips.cc
+++ b/deps/v8/src/mips/simulator-mips.cc
@@ -1359,9 +1359,9 @@ void Simulator::WriteB(int32_t addr, int8_t value) {
// 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<uintptr_t>(stack_) + 256;
+ return reinterpret_cast<uintptr_t>(stack_) + 512;
}
diff --git a/deps/v8/src/mips/stub-cache-mips.cc b/deps/v8/src/mips/stub-cache-mips.cc
index 4bad0a2ccd..9f94b1d798 100644
--- a/deps/v8/src/mips/stub-cache-mips.cc
+++ b/deps/v8/src/mips/stub-cache-mips.cc
@@ -99,7 +99,61 @@ 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<String> 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;
+ __ lw(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+ __ lbu(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
+ __ And(scratch0, scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
+ __ Branch(miss_label, ne, scratch0, Operand(zero_reg));
+
+ // Check that receiver is a JSObject.
+ __ lbu(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
+ __ Branch(miss_label, lt, scratch0, Operand(FIRST_SPEC_OBJECT_TYPE));
+
+ // Load properties array.
+ Register properties = scratch0;
+ __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
+ // Check that the properties array is a dictionary.
+ __ lw(map, FieldMemOperand(properties, HeapObject::kMapOffset));
+ Register tmp = properties;
+ __ LoadRoot(tmp, Heap::kHashTableMapRootIndex);
+ __ Branch(miss_label, ne, map, Operand(tmp));
+
+ // Restore the temporarily used register.
+ __ lw(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,
@@ -140,7 +194,7 @@ MUST_USE_RESULT static MaybeObject* GenerateDictionaryNegativeLookup(
// Restore the temporarily used register.
__ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
- MaybeObject* result = StringDictionaryLookupStub::GenerateNegativeLookup(
+ MaybeObject* result = StringDictionaryLookupStub::TryGenerateNegativeLookup(
masm,
miss_label,
&done,
@@ -261,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<JSObject> holder,
+ int index) {
// Adjust for the number of properties stored in the holder.
index -= holder->map()->inobject_properties();
if (index < 0) {
@@ -469,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<Code> ic(code);
- __ Jump(ic, RelocInfo::CODE_TARGET);
+ Handle<Code> 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> object,
const ParameterCount& arguments,
Label* miss,
Code::ExtraICState extra_ic_state) {
@@ -878,7 +929,25 @@ 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<GlobalObject> global,
+ Handle<String> name,
+ Register scratch,
+ Label* miss) {
+ Handle<JSGlobalPropertyCell> cell =
+ GlobalObject::EnsurePropertyCell(global, name);
+ ASSERT(cell->value()->IsTheHole());
+ __ li(scratch, Operand(cell));
+ __ lw(scratch,
+ FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
+ __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
+ __ Branch(miss, ne, scratch, Operand(at));
+}
+
+
+// TODO(kmillikin): Eliminate this function when the stub cache is fully
+// handlified.
+MUST_USE_RESULT static MaybeObject* TryGenerateCheckPropertyCell(
MacroAssembler* masm,
GlobalObject* global,
String* name,
@@ -901,7 +970,29 @@ MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCell(
// 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<JSObject> object,
+ Handle<JSObject> holder,
+ Handle<String> name,
+ Register scratch,
+ Label* miss) {
+ Handle<JSObject> current = object;
+ while (!current.is_identical_to(holder)) {
+ if (current->IsGlobalObject()) {
+ GenerateCheckPropertyCell(masm,
+ Handle<GlobalObject>::cast(current),
+ name,
+ scratch,
+ miss);
+ }
+ current = Handle<JSObject>(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,
@@ -912,7 +1003,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,
@@ -1047,6 +1138,108 @@ static void GenerateUInt2Double(MacroAssembler* masm,
#define __ ACCESS_MASM(masm())
+Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
+ Register object_reg,
+ Handle<JSObject> holder,
+ Register holder_reg,
+ Register scratch1,
+ Register scratch2,
+ Handle<String> 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) {
+ __ sw(reg, MemOperand(sp));
+ }
+
+ // Check the maps in the prototype chain.
+ // Traverse the prototype chain from the object and do map checks.
+ Handle<JSObject> 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<JSObject> 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);
+
+ __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
+ reg = holder_reg; // From now on the object will be in holder_reg.
+ __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
+ } else {
+ Handle<Map> current_map(current->map());
+ __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
+ // Branch on the result of the map check.
+ __ Branch(miss, ne, scratch1, Operand(current_map));
+ // 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.
+ __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
+ } else {
+ // The prototype is in old space; load it directly.
+ __ li(reg, Operand(prototype));
+ }
+ }
+
+ if (save_at_depth == depth) {
+ __ sw(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.
+ __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
+ __ Branch(miss, ne, scratch1, Operand(Handle<Map>(current->map())));
+
+ // 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;
+}
+
+
Register StubCompiler::CheckPrototypes(JSObject* object,
Register object_reg,
JSObject* holder,
@@ -1096,12 +1289,14 @@ 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;
@@ -1166,18 +1361,18 @@ 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.
@@ -1185,36 +1380,35 @@ Register StubCompiler::CheckPrototypes(JSObject* object,
}
-void StubCompiler::GenerateLoadField(JSObject* object,
- JSObject* holder,
+void StubCompiler::GenerateLoadField(Handle<JSObject> object,
+ Handle<JSObject> holder,
Register receiver,
Register scratch1,
Register scratch2,
Register scratch3,
int index,
- String* name,
+ Handle<String> name,
Label* miss) {
// Check that the receiver isn't a smi.
__ And(scratch1, receiver, Operand(kSmiTagMask));
__ Branch(miss, eq, scratch1, Operand(zero_reg));
// 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(), v0, reg, holder, index);
__ Ret();
}
-void StubCompiler::GenerateLoadConstant(JSObject* object,
- JSObject* holder,
+void StubCompiler::GenerateLoadConstant(Handle<JSObject> object,
+ Handle<JSObject> holder,
Register receiver,
Register scratch1,
Register scratch2,
Register scratch3,
- Object* value,
- String* name,
+ Handle<Object> value,
+ Handle<String> name,
Label* miss) {
// Check that the receiver isn't a smi.
__ JumpIfSmi(receiver, miss, scratch1);
@@ -1225,7 +1419,7 @@ void StubCompiler::GenerateLoadConstant(JSObject* object,
scratch1, scratch2, scratch3, name, miss);
// Return the constant value.
- __ li(v0, Operand(Handle<Object>(value)));
+ __ li(v0, Operand(value));
__ Ret();
}
@@ -1390,7 +1584,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(), v0, holder_reg,
- lookup->holder(), lookup->GetFieldIndex());
+ Handle<JSObject>(lookup->holder()),
+ lookup->GetFieldIndex());
__ Ret();
} else {
// We found CALLBACKS property in prototype chain of interceptor's
@@ -1440,9 +1635,9 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object,
}
-void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) {
+void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
if (kind_ == Code::KEYED_CALL_IC) {
- __ Branch(miss, ne, a2, Operand(Handle<String>(name)));
+ __ Branch(miss, ne, a2, Operand(name));
}
}
@@ -1499,11 +1694,22 @@ void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
}
-MaybeObject* CallStubCompiler::GenerateMissBranch() {
- MaybeObject* maybe_obj =
+void CallStubCompiler::GenerateMissBranch() {
+ Handle<Code> 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>(Code::cast(obj)), RelocInfo::CODE_TARGET);
@@ -1511,10 +1717,10 @@ MaybeObject* CallStubCompiler::GenerateMissBranch() {
}
-MaybeObject* CallStubCompiler::CompileCallField(JSObject* object,
- JSObject* holder,
+Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
+ Handle<JSObject> holder,
int index,
- String* name) {
+ Handle<String> name) {
// ----------- S t a t e -------------
// -- a2 : name
// -- ra : return address
@@ -1534,12 +1740,11 @@ MaybeObject* CallStubCompiler::CompileCallField(JSObject* object,
Register reg = CheckPrototypes(object, a0, holder, a1, a3, t0, name, &miss);
GenerateFastPropertyLoad(masm(), a1, 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);
@@ -1564,7 +1769,7 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
Label miss;
- GenerateNameCheck(name, &miss);
+ GenerateNameCheck(Handle<String>(name), &miss);
Register receiver = a1;
@@ -1640,7 +1845,7 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
__ bind(&with_write_barrier);
__ lw(t2, FieldMemOperand(receiver, HeapObject::kMapOffset));
- __ CheckFastSmiOnlyElements(t2, t2, &call_builtin);
+ __ CheckFastObjectElements(t2, t2, &call_builtin);
// Save new length.
__ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
@@ -1730,11 +1935,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);
}
@@ -1759,7 +1964,7 @@ MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object,
Register receiver = a1;
Register elements = a3;
- GenerateNameCheck(name, &miss);
+ GenerateNameCheck(Handle<String>(name), &miss);
// Get the receiver from the stack.
const int argc = arguments().immediate();
@@ -1819,11 +2024,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);
}
@@ -1853,12 +2058,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<String>(name), &name_miss);
// Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype(masm(),
@@ -1906,11 +2111,11 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
// Restore function name in a2.
__ li(a2, Handle<String>(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);
}
@@ -1939,12 +2144,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<String>(name), &name_miss);
// Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype(masm(),
@@ -1994,11 +2199,11 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall(
// Restore function name in a2.
__ li(a2, Handle<String>(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);
}
@@ -2023,7 +2228,7 @@ MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall(
if (!object->IsJSObject() || argc != 1) return heap()->undefined_value();
Label miss;
- GenerateNameCheck(name, &miss);
+ GenerateNameCheck(Handle<String>(name), &miss);
if (cell == NULL) {
__ lw(a1, MemOperand(sp, 1 * kPointerSize));
@@ -2066,11 +2271,11 @@ MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall(
__ bind(&miss);
// a2: 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);
}
@@ -2098,7 +2303,7 @@ MaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object,
if (!object->IsJSObject() || argc != 1) return heap()->undefined_value();
Label miss, slow;
- GenerateNameCheck(name, &miss);
+ GenerateNameCheck(Handle<String>(name), &miss);
if (cell == NULL) {
__ lw(a1, MemOperand(sp, 1 * kPointerSize));
@@ -2200,11 +2405,11 @@ MaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object,
__ bind(&miss);
// a2: function name.
- MaybeObject* obj = GenerateMissBranch();
+ MaybeObject* obj = TryGenerateMissBranch();
if (obj->IsFailure()) return obj;
// Return the generated code.
- return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
+ return (cell == NULL) ? TryGetCode(function) : TryGetCode(NORMAL, name);
}
@@ -2228,7 +2433,7 @@ MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object,
if (!object->IsJSObject() || argc != 1) return heap()->undefined_value();
Label miss;
- GenerateNameCheck(name, &miss);
+ GenerateNameCheck(Handle<String>(name), &miss);
if (cell == NULL) {
__ lw(a1, MemOperand(sp, 1 * kPointerSize));
@@ -2302,11 +2507,11 @@ MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object,
__ bind(&miss);
// a2: 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);
}
@@ -2332,7 +2537,7 @@ MaybeObject* CallStubCompiler::CompileFastApiCall(
Label miss, miss_before_stack_reserved;
- GenerateNameCheck(name, &miss_before_stack_reserved);
+ GenerateNameCheck(Handle<String>(name), &miss_before_stack_reserved);
// Get the receiver from the stack.
const int argc = arguments().immediate();
@@ -2357,11 +2562,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);
}
@@ -2385,7 +2590,7 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
Label miss;
- GenerateNameCheck(name, &miss);
+ GenerateNameCheck(Handle<String>(name), &miss);
// Get the receiver from the stack.
const int argc = arguments().immediate();
@@ -2484,7 +2689,7 @@ 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);
@@ -2492,11 +2697,11 @@ MaybeObject* CallStubCompiler::CompileCallConstant(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);
}
@@ -2510,18 +2715,18 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
Label miss;
- GenerateNameCheck(name, &miss);
+ GenerateNameCheck(Handle<String>(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.
__ lw(a1, MemOperand(sp, argc * kPointerSize));
- CallInterceptorCompiler compiler(this, arguments(), a2, extra_ic_state_);
+ CallInterceptorCompiler compiler(this, arguments(), a2, extra_state_);
MaybeObject* result = compiler.Compile(masm(),
object,
holder,
@@ -2541,15 +2746,16 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
// Restore receiver.
__ lw(a0, MemOperand(sp, argc * kPointerSize));
- GenerateCallFunction(masm(), object, arguments(), &miss, extra_ic_state_);
+ GenerateCallFunction(masm(), Handle<Object>(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);
}
@@ -2574,7 +2780,7 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
Label miss;
- GenerateNameCheck(name, &miss);
+ GenerateNameCheck(Handle<String>(name), &miss);
// Get the number of arguments.
const int argc = arguments().immediate();
@@ -2595,32 +2801,26 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
// Jump to the cached code (tail call).
Counters* counters = masm()->isolate()->counters();
__ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
- ASSERT(function->is_compiled());
Handle<Code> 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.
- __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
- __ InvokeCode(a3, 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.
+ __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
+ __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
+ NullCallWrapper(), call_kind);
// Handle call cache miss.
__ bind(&miss);
__ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
- 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);
}
@@ -2799,9 +2999,9 @@ MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
}
-MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name,
- JSObject* object,
- JSObject* last) {
+Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
+ Handle<JSObject> object,
+ Handle<JSObject> last) {
// ----------- S t a t e -------------
// -- a0 : receiver
// -- ra : return address
@@ -2817,15 +3017,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,
- a1,
- &miss);
- if (cell->IsFailure()) {
- miss.Unuse();
- return cell;
- }
+ GenerateCheckPropertyCell(
+ masm(), Handle<GlobalObject>::cast(last), name, a1, &miss);
}
// Return undefined if maps of the full prototype chain is still the same.
@@ -2836,14 +3029,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<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
+ Handle<JSObject> holder,
int index,
- String* name) {
+ Handle<String> name) {
// ----------- S t a t e -------------
// -- a0 : receiver
// -- a2 : name
@@ -2884,14 +3077,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<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object,
+ Handle<JSObject> holder,
+ Handle<Object> value,
+ Handle<String> name) {
// ----------- S t a t e -------------
// -- a0 : receiver
// -- a2 : name
@@ -2919,7 +3112,7 @@ MaybeObject* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
// -----------------------------------
Label miss;
- LookupResult lookup;
+ LookupResult lookup(isolate());
LookupPostInterceptor(holder, name, &lookup);
GenerateLoadInterceptor(object,
holder,
@@ -2935,7 +3128,7 @@ MaybeObject* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
GenerateLoadMiss(masm(), Code::LOAD_IC);
// Return the generated code.
- return GetCode(INTERCEPTOR, name);
+ return TryGetCode(INTERCEPTOR, name);
}
@@ -2982,13 +3175,13 @@ MaybeObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
GenerateLoadMiss(masm(), Code::LOAD_IC);
// Return the generated code.
- return GetCode(NORMAL, name);
+ return TryGetCode(NORMAL, name);
}
-MaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name,
- JSObject* receiver,
- JSObject* holder,
+Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> holder,
int index) {
// ----------- S t a t e -------------
// -- ra : return address
@@ -2998,7 +3191,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name,
Label miss;
// Check the key is the cached one.
- __ Branch(&miss, ne, a0, Operand(Handle<String>(name)));
+ __ Branch(&miss, ne, a0, Operand(name));
GenerateLoadField(receiver, holder, a1, a2, a3, t0, index, name, &miss);
__ bind(&miss);
@@ -3033,14 +3226,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<Code> KeyedLoadStubCompiler::CompileLoadConstant(
+ Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> holder,
+ Handle<Object> value) {
// ----------- S t a t e -------------
// -- ra : return address
// -- a0 : key
@@ -3049,7 +3243,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
Label miss;
// Check the key is the cached one.
- __ Branch(&miss, ne, a0, Operand(Handle<String>(name)));
+ __ Branch(&miss, ne, a0, Operand(name));
GenerateLoadConstant(receiver, holder, a1, a2, a3, t0, value, name, &miss);
__ bind(&miss);
@@ -3073,7 +3267,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
// Check the key is the cached one.
__ Branch(&miss, ne, a0, Operand(Handle<String>(name)));
- LookupResult lookup;
+ LookupResult lookup(isolate());
LookupPostInterceptor(holder, name, &lookup);
GenerateLoadInterceptor(receiver,
holder,
@@ -3088,11 +3282,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<Code> KeyedLoadStubCompiler::CompileLoadArrayLength(
+ Handle<String> name) {
// ----------- S t a t e -------------
// -- ra : return address
// -- a0 : key
@@ -3101,7 +3296,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
Label miss;
// Check the key is the cached one.
- __ Branch(&miss, ne, a0, Operand(Handle<String>(name)));
+ __ Branch(&miss, ne, a0, Operand(name));
GenerateLoadArrayLength(masm(), a1, a2, &miss);
__ bind(&miss);
@@ -3111,7 +3306,8 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
}
-MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
+Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength(
+ Handle<String> name) {
// ----------- S t a t e -------------
// -- ra : return address
// -- a0 : key
@@ -3123,7 +3319,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
__ IncrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
// Check the key is the cached one.
- __ Branch(&miss, ne, a0, Operand(Handle<String>(name)));
+ __ Branch(&miss, ne, a0, Operand(name));
GenerateLoadStringLength(masm(), a1, a2, a3, &miss, true);
__ bind(&miss);
@@ -3135,7 +3331,8 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
}
-MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
+Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype(
+ Handle<String> name) {
// ----------- S t a t e -------------
// -- ra : return address
// -- a0 : key
@@ -3147,7 +3344,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
__ IncrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
// Check the name hasn't changed.
- __ Branch(&miss, ne, a0, Operand(Handle<String>(name)));
+ __ Branch(&miss, ne, a0, Operand(name));
GenerateLoadFunctionPrototype(masm(), a1, a2, a3, &miss);
__ bind(&miss);
@@ -3178,7 +3375,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadElement(Map* receiver_map) {
__ Jump(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
- return GetCode(NORMAL, NULL);
+ return TryGetCode(NORMAL, NULL);
}
@@ -3206,7 +3403,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadPolymorphic(
__ Jump(miss_ic, RelocInfo::CODE_TARGET);
// Return the generated code.
- return GetCode(NORMAL, NULL, MEGAMORPHIC);
+ return TryGetCode(NORMAL, NULL, MEGAMORPHIC);
}
@@ -3299,8 +3496,8 @@ MaybeObject* KeyedStoreStubCompiler::CompileStorePolymorphic(
__ Jump(code, RelocInfo::CODE_TARGET, eq, a3, Operand(map));
} else {
Label next_map;
- __ Branch(&next_map, eq, a3, Operand(map));
- __ li(t0, Operand(Handle<Map>(transitioned_maps->at(i))));
+ __ Branch(&next_map, ne, a3, Operand(map));
+ __ li(a3, Operand(Handle<Map>(transitioned_maps->at(i))));
__ Jump(code, RelocInfo::CODE_TARGET);
__ bind(&next_map);
}
diff --git a/deps/v8/src/mirror-debugger.js b/deps/v8/src/mirror-debugger.js
index e3f3c48bb5..999252d57f 100644
--- a/deps/v8/src/mirror-debugger.js
+++ b/deps/v8/src/mirror-debugger.js
@@ -1087,7 +1087,7 @@ ErrorMirror.prototype.toText = function() {
// Use the same text representation as in messages.js.
var text;
try {
- str = %_CallFunction(this.value_, builtins.errorToString);
+ str = %_CallFunction(this.value_, builtins.ErrorToString);
} catch (e) {
str = '#<Error>';
}
diff --git a/deps/v8/src/mksnapshot.cc b/deps/v8/src/mksnapshot.cc
index 7a3fd090d1..bc0c2fc5b4 100644
--- a/deps/v8/src/mksnapshot.cc
+++ b/deps/v8/src/mksnapshot.cc
@@ -312,7 +312,6 @@ int main(int argc, char** argv) {
}
// If we don't do this then we end up with a stray root pointing at the
// context even after we have disposed of the context.
- // TODO(gc): request full compaction?
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
i::Object* raw_context = *(v8::Utils::OpenHandle(*context));
context.Dispose();
diff --git a/deps/v8/src/objects-debug.cc b/deps/v8/src/objects-debug.cc
index 6d2cf5f72c..64bda9473f 100644
--- a/deps/v8/src/objects-debug.cc
+++ b/deps/v8/src/objects-debug.cc
@@ -156,6 +156,12 @@ void HeapObject::HeapObjectVerify() {
case JS_ARRAY_TYPE:
JSArray::cast(this)->JSArrayVerify();
break;
+ case JS_SET_TYPE:
+ JSSet::cast(this)->JSSetVerify();
+ break;
+ case JS_MAP_TYPE:
+ JSMap::cast(this)->JSMapVerify();
+ break;
case JS_WEAK_MAP_TYPE:
JSWeakMap::cast(this)->JSWeakMapVerify();
break;
@@ -263,6 +269,12 @@ void ExternalDoubleArray::ExternalDoubleArrayVerify() {
void JSObject::JSObjectVerify() {
VerifyHeapPointer(properties());
VerifyHeapPointer(elements());
+
+ if (GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS) {
+ ASSERT(this->elements()->IsFixedArray());
+ ASSERT(this->elements()->length() >= 2);
+ }
+
if (HasFastProperties()) {
CHECK_EQ(map()->unused_property_fields(),
(map()->inobject_properties() + properties()->length() -
@@ -494,6 +506,22 @@ void JSArray::JSArrayVerify() {
}
+void JSSet::JSSetVerify() {
+ CHECK(IsJSSet());
+ JSObjectVerify();
+ VerifyHeapPointer(table());
+ ASSERT(table()->IsHashTable() || table()->IsUndefined());
+}
+
+
+void JSMap::JSMapVerify() {
+ CHECK(IsJSMap());
+ JSObjectVerify();
+ VerifyHeapPointer(table());
+ ASSERT(table()->IsHashTable() || table()->IsUndefined());
+}
+
+
void JSWeakMap::JSWeakMapVerify() {
CHECK(IsJSWeakMap());
JSObjectVerify();
diff --git a/deps/v8/src/objects-inl.h b/deps/v8/src/objects-inl.h
index cebf9be074..dc3aa46669 100644
--- a/deps/v8/src/objects-inl.h
+++ b/deps/v8/src/objects-inl.h
@@ -67,6 +67,13 @@ PropertyDetails PropertyDetails::AsDeleted() {
}
+#define TYPE_CHECKER(type, instancetype) \
+ bool Object::Is##type() { \
+ return Object::IsHeapObject() && \
+ HeapObject::cast(this)->map()->instance_type() == instancetype; \
+ }
+
+
#define CAST_ACCESSOR(type) \
type* type::cast(Object* object) { \
ASSERT(object->Is##type()); \
@@ -112,6 +119,11 @@ PropertyDetails PropertyDetails::AsDeleted() {
}
+bool Object::IsFixedArrayBase() {
+ return IsFixedArray() || IsFixedDoubleArray();
+}
+
+
bool Object::IsInstanceOf(FunctionTemplateInfo* expected) {
// There is a constraint on the object; check.
if (!this->IsJSObject()) return false;
@@ -147,10 +159,7 @@ bool Object::NonFailureIsHeapObject() {
}
-bool Object::IsHeapNumber() {
- return Object::IsHeapObject()
- && HeapObject::cast(this)->map()->instance_type() == HEAP_NUMBER_TYPE;
-}
+TYPE_CHECKER(HeapNumber, HEAP_NUMBER_TYPE)
bool Object::IsString() {
@@ -403,16 +412,8 @@ bool Object::IsNumber() {
}
-bool Object::IsByteArray() {
- return Object::IsHeapObject()
- && HeapObject::cast(this)->map()->instance_type() == BYTE_ARRAY_TYPE;
-}
-
-
-bool Object::IsFreeSpace() {
- return Object::IsHeapObject()
- && HeapObject::cast(this)->map()->instance_type() == FREE_SPACE_TYPE;
-}
+TYPE_CHECKER(ByteArray, BYTE_ARRAY_TYPE)
+TYPE_CHECKER(FreeSpace, FREE_SPACE_TYPE)
bool Object::IsFiller() {
@@ -422,11 +423,7 @@ bool Object::IsFiller() {
}
-bool Object::IsExternalPixelArray() {
- return Object::IsHeapObject() &&
- HeapObject::cast(this)->map()->instance_type() ==
- EXTERNAL_PIXEL_ARRAY_TYPE;
-}
+TYPE_CHECKER(ExternalPixelArray, EXTERNAL_PIXEL_ARRAY_TYPE)
bool Object::IsExternalArray() {
@@ -439,60 +436,14 @@ bool Object::IsExternalArray() {
}
-bool Object::IsExternalByteArray() {
- return Object::IsHeapObject() &&
- HeapObject::cast(this)->map()->instance_type() ==
- EXTERNAL_BYTE_ARRAY_TYPE;
-}
-
-
-bool Object::IsExternalUnsignedByteArray() {
- return Object::IsHeapObject() &&
- HeapObject::cast(this)->map()->instance_type() ==
- EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE;
-}
-
-
-bool Object::IsExternalShortArray() {
- return Object::IsHeapObject() &&
- HeapObject::cast(this)->map()->instance_type() ==
- EXTERNAL_SHORT_ARRAY_TYPE;
-}
-
-
-bool Object::IsExternalUnsignedShortArray() {
- return Object::IsHeapObject() &&
- HeapObject::cast(this)->map()->instance_type() ==
- EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE;
-}
-
-
-bool Object::IsExternalIntArray() {
- return Object::IsHeapObject() &&
- HeapObject::cast(this)->map()->instance_type() ==
- EXTERNAL_INT_ARRAY_TYPE;
-}
-
-
-bool Object::IsExternalUnsignedIntArray() {
- return Object::IsHeapObject() &&
- HeapObject::cast(this)->map()->instance_type() ==
- EXTERNAL_UNSIGNED_INT_ARRAY_TYPE;
-}
-
-
-bool Object::IsExternalFloatArray() {
- return Object::IsHeapObject() &&
- HeapObject::cast(this)->map()->instance_type() ==
- EXTERNAL_FLOAT_ARRAY_TYPE;
-}
-
-
-bool Object::IsExternalDoubleArray() {
- return Object::IsHeapObject() &&
- HeapObject::cast(this)->map()->instance_type() ==
- EXTERNAL_DOUBLE_ARRAY_TYPE;
-}
+TYPE_CHECKER(ExternalByteArray, EXTERNAL_BYTE_ARRAY_TYPE)
+TYPE_CHECKER(ExternalUnsignedByteArray, EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE)
+TYPE_CHECKER(ExternalShortArray, EXTERNAL_SHORT_ARRAY_TYPE)
+TYPE_CHECKER(ExternalUnsignedShortArray, EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE)
+TYPE_CHECKER(ExternalIntArray, EXTERNAL_INT_ARRAY_TYPE)
+TYPE_CHECKER(ExternalUnsignedIntArray, EXTERNAL_UNSIGNED_INT_ARRAY_TYPE)
+TYPE_CHECKER(ExternalFloatArray, EXTERNAL_FLOAT_ARRAY_TYPE)
+TYPE_CHECKER(ExternalDoubleArray, EXTERNAL_DOUBLE_ARRAY_TYPE)
bool MaybeObject::IsFailure() {
@@ -549,42 +500,14 @@ bool Object::IsJSProxy() {
}
-bool Object::IsJSFunctionProxy() {
- return Object::IsHeapObject() &&
- HeapObject::cast(this)->map()->instance_type() == JS_FUNCTION_PROXY_TYPE;
-}
-
-
-bool Object::IsJSWeakMap() {
- return Object::IsJSObject() &&
- HeapObject::cast(this)->map()->instance_type() == JS_WEAK_MAP_TYPE;
-}
-
-
-bool Object::IsJSContextExtensionObject() {
- return IsHeapObject()
- && (HeapObject::cast(this)->map()->instance_type() ==
- JS_CONTEXT_EXTENSION_OBJECT_TYPE);
-}
-
-
-bool Object::IsMap() {
- return Object::IsHeapObject()
- && HeapObject::cast(this)->map()->instance_type() == MAP_TYPE;
-}
-
-
-bool Object::IsFixedArray() {
- return Object::IsHeapObject()
- && HeapObject::cast(this)->map()->instance_type() == FIXED_ARRAY_TYPE;
-}
-
-
-bool Object::IsFixedDoubleArray() {
- return Object::IsHeapObject()
- && HeapObject::cast(this)->map()->instance_type() ==
- FIXED_DOUBLE_ARRAY_TYPE;
-}
+TYPE_CHECKER(JSFunctionProxy, JS_FUNCTION_PROXY_TYPE)
+TYPE_CHECKER(JSSet, JS_SET_TYPE)
+TYPE_CHECKER(JSMap, JS_MAP_TYPE)
+TYPE_CHECKER(JSWeakMap, JS_WEAK_MAP_TYPE)
+TYPE_CHECKER(JSContextExtensionObject, JS_CONTEXT_EXTENSION_OBJECT_TYPE)
+TYPE_CHECKER(Map, MAP_TYPE)
+TYPE_CHECKER(FixedArray, FIXED_ARRAY_TYPE)
+TYPE_CHECKER(FixedDoubleArray, FIXED_DOUBLE_ARRAY_TYPE)
bool Object::IsDescriptorArray() {
@@ -647,10 +570,7 @@ bool Object::IsSerializedScopeInfo() {
}
-bool Object::IsJSFunction() {
- return Object::IsHeapObject()
- && HeapObject::cast(this)->map()->instance_type() == JS_FUNCTION_TYPE;
-}
+TYPE_CHECKER(JSFunction, JS_FUNCTION_TYPE)
template <> inline bool Is<JSFunction>(Object* obj) {
@@ -658,43 +578,12 @@ template <> inline bool Is<JSFunction>(Object* obj) {
}
-bool Object::IsCode() {
- return Object::IsHeapObject()
- && HeapObject::cast(this)->map()->instance_type() == CODE_TYPE;
-}
-
-
-bool Object::IsOddball() {
- return Object::IsHeapObject()
- && HeapObject::cast(this)->map()->instance_type() == ODDBALL_TYPE;
-}
-
-
-bool Object::IsJSGlobalPropertyCell() {
- return Object::IsHeapObject()
- && HeapObject::cast(this)->map()->instance_type()
- == JS_GLOBAL_PROPERTY_CELL_TYPE;
-}
-
-
-bool Object::IsSharedFunctionInfo() {
- return Object::IsHeapObject() &&
- (HeapObject::cast(this)->map()->instance_type() ==
- SHARED_FUNCTION_INFO_TYPE);
-}
-
-
-bool Object::IsJSValue() {
- return Object::IsHeapObject()
- && HeapObject::cast(this)->map()->instance_type() == JS_VALUE_TYPE;
-}
-
-
-bool Object::IsJSMessageObject() {
- return Object::IsHeapObject()
- && (HeapObject::cast(this)->map()->instance_type() ==
- JS_MESSAGE_OBJECT_TYPE);
-}
+TYPE_CHECKER(Code, CODE_TYPE)
+TYPE_CHECKER(Oddball, ODDBALL_TYPE)
+TYPE_CHECKER(JSGlobalPropertyCell, JS_GLOBAL_PROPERTY_CELL_TYPE)
+TYPE_CHECKER(SharedFunctionInfo, SHARED_FUNCTION_INFO_TYPE)
+TYPE_CHECKER(JSValue, JS_VALUE_TYPE)
+TYPE_CHECKER(JSMessageObject, JS_MESSAGE_OBJECT_TYPE)
bool Object::IsStringWrapper() {
@@ -702,10 +591,7 @@ bool Object::IsStringWrapper() {
}
-bool Object::IsForeign() {
- return Object::IsHeapObject()
- && HeapObject::cast(this)->map()->instance_type() == FOREIGN_TYPE;
-}
+TYPE_CHECKER(Foreign, FOREIGN_TYPE)
bool Object::IsBoolean() {
@@ -714,16 +600,8 @@ bool Object::IsBoolean() {
}
-bool Object::IsJSArray() {
- return Object::IsHeapObject()
- && HeapObject::cast(this)->map()->instance_type() == JS_ARRAY_TYPE;
-}
-
-
-bool Object::IsJSRegExp() {
- return Object::IsHeapObject()
- && HeapObject::cast(this)->map()->instance_type() == JS_REGEXP_TYPE;
-}
+TYPE_CHECKER(JSArray, JS_ARRAY_TYPE)
+TYPE_CHECKER(JSRegExp, JS_REGEXP_TYPE)
template <> inline bool Is<JSArray>(Object* obj) {
@@ -760,7 +638,10 @@ bool Object::IsJSFunctionResultCache() {
return false;
}
#ifdef DEBUG
- reinterpret_cast<JSFunctionResultCache*>(this)->JSFunctionResultCacheVerify();
+ if (FLAG_verify_heap) {
+ reinterpret_cast<JSFunctionResultCache*>(this)->
+ JSFunctionResultCacheVerify();
+ }
#endif
return true;
}
@@ -772,7 +653,9 @@ bool Object::IsNormalizedMapCache() {
return false;
}
#ifdef DEBUG
- reinterpret_cast<NormalizedMapCache*>(this)->NormalizedMapCacheVerify();
+ if (FLAG_verify_heap) {
+ reinterpret_cast<NormalizedMapCache*>(this)->NormalizedMapCacheVerify();
+ }
#endif
return true;
}
@@ -821,18 +704,8 @@ bool Object::IsGlobalObject() {
}
-bool Object::IsJSGlobalObject() {
- return IsHeapObject() &&
- (HeapObject::cast(this)->map()->instance_type() ==
- JS_GLOBAL_OBJECT_TYPE);
-}
-
-
-bool Object::IsJSBuiltinsObject() {
- return IsHeapObject() &&
- (HeapObject::cast(this)->map()->instance_type() ==
- JS_BUILTINS_OBJECT_TYPE);
-}
+TYPE_CHECKER(JSGlobalObject, JS_GLOBAL_OBJECT_TYPE)
+TYPE_CHECKER(JSBuiltinsObject, JS_BUILTINS_OBJECT_TYPE)
bool Object::IsUndetectableObject() {
@@ -1300,7 +1173,6 @@ ACCESSORS(JSObject, properties, FixedArray, kPropertiesOffset)
FixedArrayBase* JSObject::elements() {
Object* array = READ_FIELD(this, kElementsOffset);
- ASSERT(array->HasValidElements());
return static_cast<FixedArrayBase*>(array);
}
@@ -1740,7 +1612,11 @@ void FixedDoubleArray::Initialize(FixedDoubleArray* from) {
old_length * kDoubleSize);
} else {
for (int i = 0; i < old_length; ++i) {
- set(i, from->get_scalar(i));
+ if (from->is_the_hole(i)) {
+ set_the_hole(i);
+ } else {
+ set(i, from->get_scalar(i));
+ }
}
}
int offset = kHeaderSize + old_length * kDoubleSize;
@@ -1805,15 +1681,13 @@ void FixedArray::set(int index,
}
-void FixedArray::fast_set(FixedArray* array, int index, Object* value) {
+void FixedArray::NoWriteBarrierSet(FixedArray* array,
+ int index,
+ Object* value) {
ASSERT(array->map() != HEAP->raw_unchecked_fixed_cow_array_map());
ASSERT(index >= 0 && index < array->length());
ASSERT(!HEAP->InNewSpace(value));
WRITE_FIELD(array, kHeaderSize + index * kPointerSize, value);
- array->GetHeap()->incremental_marking()->RecordWrite(
- array,
- HeapObject::RawField(array, kHeaderSize + index * kPointerSize),
- value);
}
@@ -1901,10 +1775,12 @@ void DescriptorArray::set_bit_field3_storage(int value) {
}
-void DescriptorArray::fast_swap(FixedArray* array, int first, int second) {
+void DescriptorArray::NoWriteBarrierSwap(FixedArray* array,
+ int first,
+ int second) {
Object* tmp = array->get(first);
- fast_set(array, first, array->get(second));
- fast_set(array, second, tmp);
+ NoWriteBarrierSet(array, first, array->get(second));
+ NoWriteBarrierSet(array, second, tmp);
}
@@ -2012,7 +1888,9 @@ void DescriptorArray::Get(int descriptor_number, Descriptor* desc) {
}
-void DescriptorArray::Set(int descriptor_number, Descriptor* desc) {
+void DescriptorArray::Set(int descriptor_number,
+ Descriptor* desc,
+ const WhitenessWitness&) {
// Range check.
ASSERT(descriptor_number < number_of_descriptors());
@@ -2020,26 +1898,53 @@ void DescriptorArray::Set(int descriptor_number, Descriptor* desc) {
ASSERT(!HEAP->InNewSpace(desc->GetKey()));
ASSERT(!HEAP->InNewSpace(desc->GetValue()));
- fast_set(this, ToKeyIndex(descriptor_number), desc->GetKey());
+ NoWriteBarrierSet(this,
+ ToKeyIndex(descriptor_number),
+ desc->GetKey());
FixedArray* content_array = GetContentArray();
- fast_set(content_array, ToValueIndex(descriptor_number), desc->GetValue());
- fast_set(content_array, ToDetailsIndex(descriptor_number),
- desc->GetDetails().AsSmi());
+ NoWriteBarrierSet(content_array,
+ ToValueIndex(descriptor_number),
+ desc->GetValue());
+ NoWriteBarrierSet(content_array,
+ ToDetailsIndex(descriptor_number),
+ desc->GetDetails().AsSmi());
}
-void DescriptorArray::CopyFrom(int index, DescriptorArray* src, int src_index) {
+void DescriptorArray::CopyFrom(int index,
+ DescriptorArray* src,
+ int src_index,
+ const WhitenessWitness& witness) {
Descriptor desc;
src->Get(src_index, &desc);
- Set(index, &desc);
+ Set(index, &desc, witness);
}
-void DescriptorArray::Swap(int first, int second) {
- fast_swap(this, ToKeyIndex(first), ToKeyIndex(second));
+void DescriptorArray::NoWriteBarrierSwapDescriptors(int first, int second) {
+ NoWriteBarrierSwap(this, ToKeyIndex(first), ToKeyIndex(second));
FixedArray* content_array = GetContentArray();
- fast_swap(content_array, ToValueIndex(first), ToValueIndex(second));
- fast_swap(content_array, ToDetailsIndex(first), ToDetailsIndex(second));
+ NoWriteBarrierSwap(content_array,
+ ToValueIndex(first),
+ ToValueIndex(second));
+ NoWriteBarrierSwap(content_array,
+ ToDetailsIndex(first),
+ ToDetailsIndex(second));
+}
+
+
+DescriptorArray::WhitenessWitness::WhitenessWitness(DescriptorArray* array)
+ : marking_(array->GetHeap()->incremental_marking()) {
+ marking_->EnterNoMarkingScope();
+ if (array->number_of_descriptors() > 0) {
+ ASSERT(Marking::Color(array) == Marking::WHITE_OBJECT);
+ ASSERT(Marking::Color(array->GetContentArray()) == Marking::WHITE_OBJECT);
+ }
+}
+
+
+DescriptorArray::WhitenessWitness::~WhitenessWitness() {
+ marking_->LeaveNoMarkingScope();
}
@@ -2142,6 +2047,8 @@ CAST_ACCESSOR(JSArray)
CAST_ACCESSOR(JSRegExp)
CAST_ACCESSOR(JSProxy)
CAST_ACCESSOR(JSFunctionProxy)
+CAST_ACCESSOR(JSSet)
+CAST_ACCESSOR(JSMap)
CAST_ACCESSOR(JSWeakMap)
CAST_ACCESSOR(Foreign)
CAST_ACCESSOR(ByteArray)
@@ -2979,6 +2886,21 @@ void Code::set_has_debug_break_slots(bool value) {
}
+bool Code::is_compiled_optimizable() {
+ ASSERT(kind() == FUNCTION);
+ byte flags = READ_BYTE_FIELD(this, kFullCodeFlags);
+ return FullCodeFlagsIsCompiledOptimizable::decode(flags);
+}
+
+
+void Code::set_compiled_optimizable(bool value) {
+ ASSERT(kind() == FUNCTION);
+ byte flags = READ_BYTE_FIELD(this, kFullCodeFlags);
+ flags = FullCodeFlagsIsCompiledOptimizable::update(flags, value);
+ WRITE_BYTE_FIELD(this, kFullCodeFlags, flags);
+}
+
+
int Code::allow_osr_at_loop_nesting_level() {
ASSERT(kind() == FUNCTION);
return READ_BYTE_FIELD(this, kAllowOSRAtLoopNestingLevelOffset);
@@ -3304,7 +3226,7 @@ ACCESSORS(Map, prototype_transitions, FixedArray, kPrototypeTransitionsOffset)
ACCESSORS(Map, constructor, Object, kConstructorOffset)
ACCESSORS(JSFunction, shared, SharedFunctionInfo, kSharedFunctionInfoOffset)
-ACCESSORS(JSFunction, literals, FixedArray, kLiteralsOffset)
+ACCESSORS(JSFunction, literals_or_bindings, FixedArray, kLiteralsOffset)
ACCESSORS(JSFunction,
next_function_link,
Object,
@@ -3547,8 +3469,23 @@ void SharedFunctionInfo::set_optimization_disabled(bool disable) {
}
-BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, strict_mode,
- kStrictModeFunction)
+StrictModeFlag SharedFunctionInfo::strict_mode_flag() {
+ return BooleanBit::get(compiler_hints(), kStrictModeFunction)
+ ? kStrictMode : kNonStrictMode;
+}
+
+
+void SharedFunctionInfo::set_strict_mode_flag(StrictModeFlag strict_mode_flag) {
+ ASSERT(strict_mode_flag == kStrictMode ||
+ strict_mode_flag == kNonStrictMode);
+ bool value = strict_mode_flag == kStrictMode;
+ set_compiler_hints(
+ BooleanBit::set(compiler_hints(), kStrictModeFunction, value));
+}
+
+
+BOOL_GETTER(SharedFunctionInfo, compiler_hints, strict_mode,
+ kStrictModeFunction)
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, native, kNative)
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints,
name_should_print_as_anonymous,
@@ -3823,7 +3760,36 @@ bool JSFunction::is_compiled() {
}
+FixedArray* JSFunction::literals() {
+ ASSERT(!shared()->bound());
+ return literals_or_bindings();
+}
+
+
+void JSFunction::set_literals(FixedArray* literals) {
+ ASSERT(!shared()->bound());
+ set_literals_or_bindings(literals);
+}
+
+
+FixedArray* JSFunction::function_bindings() {
+ ASSERT(shared()->bound());
+ return literals_or_bindings();
+}
+
+
+void JSFunction::set_function_bindings(FixedArray* bindings) {
+ ASSERT(shared()->bound());
+ // Bound function literal may be initialized to the empty fixed array
+ // before the bindings are set.
+ ASSERT(bindings == GetHeap()->empty_fixed_array() ||
+ bindings->map() == GetHeap()->fixed_cow_array_map());
+ set_literals_or_bindings(bindings);
+}
+
+
int JSFunction::NumberOfLiterals() {
+ ASSERT(!shared()->bound());
return literals()->length();
}
@@ -3870,6 +3836,8 @@ void JSProxy::InitializeBody(int object_size, Object* value) {
}
+ACCESSORS(JSSet, table, Object, kTableOffset)
+ACCESSORS(JSMap, table, Object, kTableOffset)
ACCESSORS(JSWeakMap, table, Object, kTableOffset)
ACCESSORS(JSWeakMap, next, Object, kNextOffset)
@@ -4056,14 +4024,16 @@ ElementsKind JSObject::GetElementsKind() {
reinterpret_cast<FixedArrayBase*>(READ_FIELD(this, kElementsOffset));
Map* map = fixed_array->map();
ASSERT(((kind == FAST_ELEMENTS || kind == FAST_SMI_ONLY_ELEMENTS) &&
- (map == GetHeap()->fixed_array_map() ||
- map == GetHeap()->fixed_cow_array_map())) ||
- (kind == FAST_DOUBLE_ELEMENTS &&
- fixed_array->IsFixedDoubleArray()) ||
- (kind == DICTIONARY_ELEMENTS &&
- fixed_array->IsFixedArray() &&
- fixed_array->IsDictionary()) ||
- (kind > DICTIONARY_ELEMENTS));
+ (map == GetHeap()->fixed_array_map() ||
+ map == GetHeap()->fixed_cow_array_map())) ||
+ (kind == FAST_DOUBLE_ELEMENTS &&
+ fixed_array->IsFixedDoubleArray()) ||
+ (kind == DICTIONARY_ELEMENTS &&
+ fixed_array->IsFixedArray() &&
+ fixed_array->IsDictionary()) ||
+ (kind > DICTIONARY_ELEMENTS));
+ ASSERT((kind != NON_STRICT_ARGUMENTS_ELEMENTS) ||
+ (elements()->IsFixedArray() && elements()->length() >= 2));
#endif
return kind;
}
@@ -4407,7 +4377,7 @@ void Dictionary<Shape, Key>::SetEntry(int entry,
WriteBarrierMode mode = FixedArray::GetWriteBarrierMode(no_gc);
FixedArray::set(index, key, mode);
FixedArray::set(index+1, value, mode);
- FixedArray::fast_set(this, index+2, details.AsSmi());
+ FixedArray::set(index+2, details.AsSmi());
}
@@ -4456,27 +4426,31 @@ MaybeObject* StringDictionaryShape::AsObject(String* key) {
}
-bool ObjectHashTableShape::IsMatch(JSReceiver* key, Object* other) {
- return key == JSReceiver::cast(other);
+template <int entrysize>
+bool ObjectHashTableShape<entrysize>::IsMatch(Object* key, Object* other) {
+ return key->SameValue(other);
}
-uint32_t ObjectHashTableShape::Hash(JSReceiver* key) {
- MaybeObject* maybe_hash = key->GetIdentityHash(OMIT_CREATION);
- ASSERT(!maybe_hash->IsFailure());
- return Smi::cast(maybe_hash->ToObjectUnchecked())->value();
+template <int entrysize>
+uint32_t ObjectHashTableShape<entrysize>::Hash(Object* key) {
+ ASSERT(!key->IsUndefined() && !key->IsNull());
+ MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
+ return Smi::cast(maybe_hash->ToObjectChecked())->value();
}
-uint32_t ObjectHashTableShape::HashForObject(JSReceiver* key, Object* other) {
- MaybeObject* maybe_hash =
- JSReceiver::cast(other)->GetIdentityHash(OMIT_CREATION);
- ASSERT(!maybe_hash->IsFailure());
- return Smi::cast(maybe_hash->ToObjectUnchecked())->value();
+template <int entrysize>
+uint32_t ObjectHashTableShape<entrysize>::HashForObject(Object* key,
+ Object* other) {
+ ASSERT(!other->IsUndefined() && !other->IsNull());
+ MaybeObject* maybe_hash = other->GetHash(OMIT_CREATION);
+ return Smi::cast(maybe_hash->ToObjectChecked())->value();
}
-MaybeObject* ObjectHashTableShape::AsObject(JSReceiver* key) {
+template <int entrysize>
+MaybeObject* ObjectHashTableShape<entrysize>::AsObject(Object* key) {
return key;
}
@@ -4534,6 +4508,12 @@ MaybeObject* FixedArray::Copy() {
}
+MaybeObject* FixedDoubleArray::Copy() {
+ if (length() == 0) return this;
+ return GetHeap()->CopyFixedDoubleArray(this);
+}
+
+
Relocatable::Relocatable(Isolate* isolate) {
ASSERT(isolate == Isolate::Current());
isolate_ = isolate;
diff --git a/deps/v8/src/objects-printer.cc b/deps/v8/src/objects-printer.cc
index fc7573241a..b788504fa1 100644
--- a/deps/v8/src/objects-printer.cc
+++ b/deps/v8/src/objects-printer.cc
@@ -245,54 +245,6 @@ void ExternalDoubleArray::ExternalDoubleArrayPrint(FILE* out) {
}
-static void PrintElementsKind(FILE* out, ElementsKind kind) {
- switch (kind) {
- case FAST_SMI_ONLY_ELEMENTS:
- PrintF(out, "FAST_SMI_ONLY_ELEMENTS");
- break;
- case FAST_ELEMENTS:
- PrintF(out, "FAST_ELEMENTS");
- break;
- case FAST_DOUBLE_ELEMENTS:
- PrintF(out, "FAST_DOUBLE_ELEMENTS");
- break;
- case DICTIONARY_ELEMENTS:
- PrintF(out, "DICTIONARY_ELEMENTS");
- break;
- case NON_STRICT_ARGUMENTS_ELEMENTS:
- PrintF(out, "NON_STRICT_ARGUMENTS_ELEMENTS");
- break;
- case EXTERNAL_BYTE_ELEMENTS:
- PrintF(out, "EXTERNAL_BYTE_ELEMENTS");
- break;
- case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- PrintF(out, "EXTERNAL_UNSIGNED_BYTE_ELEMENTS");
- break;
- case EXTERNAL_SHORT_ELEMENTS:
- PrintF(out, "EXTERNAL_SHORT_ELEMENTS");
- break;
- case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- PrintF(out, "EXTERNAL_UNSIGNED_SHORT_ELEMENTS");
- break;
- case EXTERNAL_INT_ELEMENTS:
- PrintF(out, "EXTERNAL_INT_ELEMENTS");
- break;
- case EXTERNAL_UNSIGNED_INT_ELEMENTS:
- PrintF(out, "EXTERNAL_UNSIGNED_INT_ELEMENTS");
- break;
- case EXTERNAL_FLOAT_ELEMENTS:
- PrintF(out, "EXTERNAL_FLOAT_ELEMENTS");
- break;
- case EXTERNAL_DOUBLE_ELEMENTS:
- PrintF(out, "EXTERNAL_DOUBLE_ELEMENTS");
- break;
- case EXTERNAL_PIXEL_ELEMENTS:
- PrintF(out, "EXTERNAL_DOUBLE_ELEMENTS");
- break;
- }
-}
-
-
void JSObject::PrintProperties(FILE* out) {
if (HasFastProperties()) {
DescriptorArray* descs = map()->instance_descriptors();
diff --git a/deps/v8/src/objects-visiting.cc b/deps/v8/src/objects-visiting.cc
index 20a7b31701..a796283e2f 100644
--- a/deps/v8/src/objects-visiting.cc
+++ b/deps/v8/src/objects-visiting.cc
@@ -94,6 +94,16 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
case JS_GLOBAL_PROPERTY_CELL_TYPE:
return kVisitPropertyCell;
+ case JS_SET_TYPE:
+ return GetVisitorIdForSize(kVisitStruct,
+ kVisitStructGeneric,
+ JSSet::kSize);
+
+ case JS_MAP_TYPE:
+ return GetVisitorIdForSize(kVisitStruct,
+ kVisitStructGeneric,
+ JSMap::kSize);
+
case JS_WEAK_MAP_TYPE:
return kVisitJSWeakMap;
diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc
index 5612732303..9a87ac57d6 100644
--- a/deps/v8/src/objects.cc
+++ b/deps/v8/src/objects.cc
@@ -55,6 +55,54 @@
namespace v8 {
namespace internal {
+void PrintElementsKind(FILE* out, ElementsKind kind) {
+ switch (kind) {
+ case FAST_SMI_ONLY_ELEMENTS:
+ PrintF(out, "FAST_SMI_ONLY_ELEMENTS");
+ break;
+ case FAST_ELEMENTS:
+ PrintF(out, "FAST_ELEMENTS");
+ break;
+ case FAST_DOUBLE_ELEMENTS:
+ PrintF(out, "FAST_DOUBLE_ELEMENTS");
+ break;
+ case DICTIONARY_ELEMENTS:
+ PrintF(out, "DICTIONARY_ELEMENTS");
+ break;
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
+ PrintF(out, "NON_STRICT_ARGUMENTS_ELEMENTS");
+ break;
+ case EXTERNAL_BYTE_ELEMENTS:
+ PrintF(out, "EXTERNAL_BYTE_ELEMENTS");
+ break;
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ PrintF(out, "EXTERNAL_UNSIGNED_BYTE_ELEMENTS");
+ break;
+ case EXTERNAL_SHORT_ELEMENTS:
+ PrintF(out, "EXTERNAL_SHORT_ELEMENTS");
+ break;
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ PrintF(out, "EXTERNAL_UNSIGNED_SHORT_ELEMENTS");
+ break;
+ case EXTERNAL_INT_ELEMENTS:
+ PrintF(out, "EXTERNAL_INT_ELEMENTS");
+ break;
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ PrintF(out, "EXTERNAL_UNSIGNED_INT_ELEMENTS");
+ break;
+ case EXTERNAL_FLOAT_ELEMENTS:
+ PrintF(out, "EXTERNAL_FLOAT_ELEMENTS");
+ break;
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ PrintF(out, "EXTERNAL_DOUBLE_ELEMENTS");
+ break;
+ case EXTERNAL_PIXEL_ELEMENTS:
+ PrintF(out, "EXTERNAL_DOUBLE_ELEMENTS");
+ break;
+ }
+}
+
+
// Getters and setters are stored in a fixed array property. These are
// constants for their indices.
const int kGetterIndex = 0;
@@ -154,7 +202,7 @@ void Object::Lookup(String* name, LookupResult* result) {
MaybeObject* Object::GetPropertyWithReceiver(Object* receiver,
String* name,
PropertyAttributes* attributes) {
- LookupResult result;
+ LookupResult result(name->GetIsolate());
Lookup(name, &result);
MaybeObject* value = GetProperty(receiver, &result, name, attributes);
ASSERT(*attributes <= ABSENT);
@@ -234,6 +282,14 @@ MaybeObject* JSProxy::GetPropertyWithHandler(Object* receiver_raw,
}
+Handle<Object> Object::GetElement(Handle<Object> object, uint32_t index) {
+ Isolate* isolate = object->IsHeapObject()
+ ? Handle<HeapObject>::cast(object)->GetIsolate()
+ : Isolate::Current();
+ CALL_HEAP_FUNCTION(isolate, object->GetElement(index), Object);
+}
+
+
MaybeObject* JSProxy::GetElementWithHandler(Object* receiver,
uint32_t index) {
String* name;
@@ -310,7 +366,7 @@ MaybeObject* JSObject::GetPropertyWithFailedAccessCheck(
case FIELD:
case CONSTANT_FUNCTION: {
// Search ALL_CAN_READ accessors in prototype chain.
- LookupResult r;
+ LookupResult r(GetIsolate());
result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
if (r.IsProperty()) {
return GetPropertyWithFailedAccessCheck(receiver,
@@ -323,7 +379,7 @@ MaybeObject* JSObject::GetPropertyWithFailedAccessCheck(
case INTERCEPTOR: {
// If the object has an interceptor, try real named properties.
// No access check in GetPropertyAttributeWithInterceptor.
- LookupResult r;
+ LookupResult r(GetIsolate());
result->holder()->LookupRealNamedProperty(name, &r);
if (r.IsProperty()) {
return GetPropertyWithFailedAccessCheck(receiver,
@@ -370,7 +426,7 @@ PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
case CONSTANT_FUNCTION: {
if (!continue_search) break;
// Search ALL_CAN_READ accessors in prototype chain.
- LookupResult r;
+ LookupResult r(GetIsolate());
result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
if (r.IsProperty()) {
return GetPropertyAttributeWithFailedAccessCheck(receiver,
@@ -384,7 +440,7 @@ PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
case INTERCEPTOR: {
// If the object has an interceptor, try real named properties.
// No access check in GetPropertyAttributeWithInterceptor.
- LookupResult r;
+ LookupResult r(GetIsolate());
if (continue_search) {
result->holder()->LookupRealNamedProperty(name, &r);
} else {
@@ -404,7 +460,7 @@ PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
}
}
- GetHeap()->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
+ GetIsolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
return ABSENT;
}
@@ -528,6 +584,21 @@ bool JSObject::IsDirty() {
}
+Handle<Object> Object::GetProperty(Handle<Object> object,
+ Handle<Object> receiver,
+ LookupResult* result,
+ Handle<String> key,
+ PropertyAttributes* attributes) {
+ Isolate* isolate = object->IsHeapObject()
+ ? Handle<HeapObject>::cast(object)->GetIsolate()
+ : Isolate::Current();
+ CALL_HEAP_FUNCTION(
+ isolate,
+ object->GetProperty(*receiver, result, *key, attributes),
+ Object);
+}
+
+
MaybeObject* Object::GetProperty(Object* receiver,
LookupResult* result,
String* name,
@@ -700,6 +771,49 @@ Object* Object::GetPrototype() {
}
+MaybeObject* Object::GetHash(CreationFlag flag) {
+ // The object is either a number, a string, an odd-ball,
+ // a real JS object, or a Harmony proxy.
+ if (IsNumber()) {
+ uint32_t hash = ComputeLongHash(double_to_uint64(Number()));
+ return Smi::FromInt(hash & Smi::kMaxValue);
+ }
+ if (IsString()) {
+ uint32_t hash = String::cast(this)->Hash();
+ return Smi::FromInt(hash);
+ }
+ if (IsOddball()) {
+ uint32_t hash = Oddball::cast(this)->to_string()->Hash();
+ return Smi::FromInt(hash);
+ }
+ if (IsJSReceiver()) {
+ return JSReceiver::cast(this)->GetIdentityHash(flag);
+ }
+
+ UNREACHABLE();
+ return Smi::FromInt(0);
+}
+
+
+bool Object::SameValue(Object* other) {
+ if (other == this) return true;
+ if (!IsHeapObject() || !other->IsHeapObject()) return false;
+
+ // The object is either a number, a string, an odd-ball,
+ // a real JS object, or a Harmony proxy.
+ if (IsNumber() && other->IsNumber()) {
+ double this_value = Number();
+ double other_value = other->Number();
+ return (this_value == other_value) ||
+ (isnan(this_value) && isnan(other_value));
+ }
+ if (IsString() && other->IsString()) {
+ return String::cast(this)->Equals(String::cast(other));
+ }
+ return false;
+}
+
+
void Object::ShortPrint(FILE* out) {
HeapStringAllocator allocator;
StringStream accumulator(&allocator);
@@ -1074,6 +1188,27 @@ void JSObject::JSObjectShortPrint(StringStream* accumulator) {
}
+void JSObject::PrintElementsTransition(
+ FILE* file, ElementsKind from_kind, FixedArrayBase* from_elements,
+ ElementsKind to_kind, FixedArrayBase* to_elements) {
+ if (from_kind != to_kind) {
+ PrintF(file, "elements transition [");
+ PrintElementsKind(file, from_kind);
+ PrintF(file, " -> ");
+ PrintElementsKind(file, to_kind);
+ PrintF(file, "] in ");
+ JavaScriptFrame::PrintTop(file, false, true);
+ PrintF(file, " for ");
+ ShortPrint(file);
+ PrintF(file, " from ");
+ from_elements->ShortPrint(file);
+ PrintF(file, " to ");
+ to_elements->ShortPrint(file);
+ PrintF(file, "\n");
+ }
+}
+
+
void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
Heap* heap = GetHeap();
if (!heap->Contains(this)) {
@@ -1102,6 +1237,10 @@ void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
case FIXED_ARRAY_TYPE:
accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length());
break;
+ case FIXED_DOUBLE_ARRAY_TYPE:
+ accumulator->Add("<FixedDoubleArray[%u]>",
+ FixedDoubleArray::cast(this)->length());
+ break;
case BYTE_ARRAY_TYPE:
accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length());
break;
@@ -1247,6 +1386,8 @@ void HeapObject::IterateBody(InstanceType type, int object_size,
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
case JS_VALUE_TYPE:
case JS_ARRAY_TYPE:
+ case JS_SET_TYPE:
+ case JS_MAP_TYPE:
case JS_WEAK_MAP_TYPE:
case JS_REGEXP_TYPE:
case JS_GLOBAL_PROXY_TYPE:
@@ -1658,7 +1799,7 @@ MaybeObject* JSObject::SetPropertyPostInterceptor(
PropertyAttributes attributes,
StrictModeFlag strict_mode) {
// Check local property, ignore interceptor.
- LookupResult result;
+ LookupResult result(GetIsolate());
LocalLookupRealNamedProperty(name, &result);
if (result.IsFound()) {
// An existing property, a map transition or a null descriptor was
@@ -1840,7 +1981,7 @@ MaybeObject* JSReceiver::SetProperty(String* name,
Object* value,
PropertyAttributes attributes,
StrictModeFlag strict_mode) {
- LookupResult result;
+ LookupResult result(GetIsolate());
LocalLookup(name, &result);
return SetProperty(&result, name, value, attributes, strict_mode);
}
@@ -2006,9 +2147,9 @@ MaybeObject* JSObject::SetPropertyWithCallbackSetterInPrototypes(
PropertyAttributes attributes,
bool* found,
StrictModeFlag strict_mode) {
- LookupResult result;
- LookupCallbackSetterInPrototypes(name, &result);
Heap* heap = GetHeap();
+ LookupResult result(heap->isolate());
+ LookupCallbackSetterInPrototypes(name, &result);
if (result.IsFound()) {
*found = true;
if (result.type() == CALLBACKS) {
@@ -2020,7 +2161,7 @@ MaybeObject* JSObject::SetPropertyWithCallbackSetterInPrototypes(
} else if (result.type() == HANDLER) {
// We could not find a local property so let's check whether there is an
// accessor that wants to handle the property.
- LookupResult accessor_result;
+ LookupResult accessor_result(heap->isolate());
LookupCallbackSetterInPrototypes(name, &accessor_result);
if (accessor_result.IsFound()) {
if (accessor_result.type() == CALLBACKS) {
@@ -2085,6 +2226,51 @@ void Map::LookupInDescriptors(JSObject* holder,
}
+static bool ContainsMap(MapHandleList* maps, Handle<Map> map) {
+ ASSERT(!map.is_null());
+ for (int i = 0; i < maps->length(); ++i) {
+ if (!maps->at(i).is_null() && maps->at(i).is_identical_to(map)) return true;
+ }
+ return false;
+}
+
+
+template <class T>
+static Handle<T> MaybeNull(T* p) {
+ if (p == NULL) return Handle<T>::null();
+ return Handle<T>(p);
+}
+
+
+Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) {
+ ElementsKind elms_kind = elements_kind();
+ if (elms_kind == FAST_DOUBLE_ELEMENTS) {
+ bool dummy = true;
+ Handle<Map> fast_map =
+ MaybeNull(LookupElementsTransitionMap(FAST_ELEMENTS, &dummy));
+ if (!fast_map.is_null() && ContainsMap(candidates, fast_map)) {
+ return fast_map;
+ }
+ return Handle<Map>::null();
+ }
+ if (elms_kind == FAST_SMI_ONLY_ELEMENTS) {
+ bool dummy = true;
+ Handle<Map> double_map =
+ MaybeNull(LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, &dummy));
+ // In the current implementation, if the DOUBLE map doesn't exist, the
+ // FAST map can't exist either.
+ if (double_map.is_null()) return Handle<Map>::null();
+ Handle<Map> fast_map =
+ MaybeNull(double_map->LookupElementsTransitionMap(FAST_ELEMENTS,
+ &dummy));
+ if (!fast_map.is_null() && ContainsMap(candidates, fast_map)) {
+ return fast_map;
+ }
+ if (ContainsMap(candidates, double_map)) return double_map;
+ }
+ return Handle<Map>::null();
+}
+
static Map* GetElementsTransitionMapFromDescriptor(Object* descriptor_contents,
ElementsKind elements_kind) {
if (descriptor_contents->IsMap()) {
@@ -2268,6 +2454,15 @@ MaybeObject* Map::AddElementsTransition(ElementsKind elements_kind,
}
+Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
+ ElementsKind to_kind) {
+ Isolate* isolate = object->GetIsolate();
+ CALL_HEAP_FUNCTION(isolate,
+ object->GetElementsTransitionMap(to_kind),
+ Map);
+}
+
+
MaybeObject* JSObject::GetElementsTransitionMap(ElementsKind to_kind) {
Map* current_map = map();
ElementsKind from_kind = current_map->elements_kind();
@@ -2423,7 +2618,7 @@ MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(
case INTERCEPTOR: {
// Try lookup real named properties. Note that only property can be
// set is callbacks marked as ALL_CAN_WRITE on the prototype chain.
- LookupResult r;
+ LookupResult r(GetIsolate());
LookupRealNamedProperty(name, &r);
if (r.IsProperty()) {
return SetPropertyWithFailedAccessCheck(&r,
@@ -2441,10 +2636,10 @@ MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(
}
}
- Heap* heap = GetHeap();
- HandleScope scope(heap->isolate());
+ Isolate* isolate = GetIsolate();
+ HandleScope scope(isolate);
Handle<Object> value_handle(value);
- heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
+ isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
return *value_handle;
}
@@ -2507,6 +2702,7 @@ MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandlerIfDefiningSetter(
*found = true; // except where defined otherwise...
Isolate* isolate = GetHeap()->isolate();
Handle<JSProxy> proxy(this);
+ Handle<Object> handler(this->handler()); // Trap might morph proxy.
Handle<String> name(name_raw);
Handle<Object> value(value_raw);
Handle<Object> args[] = { name };
@@ -2530,7 +2726,9 @@ MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandlerIfDefiningSetter(
Handle<Object> configurable(v8::internal::GetProperty(desc, conf_name));
ASSERT(!isolate->has_pending_exception());
if (configurable->IsFalse()) {
- Handle<Object> args[] = { Handle<Object>(proxy->handler()), proxy, name };
+ Handle<String> trap =
+ isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
+ Handle<Object> args[] = { handler, trap, name };
Handle<Object> error = isolate->factory()->NewTypeError(
"proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
return isolate->Throw(*error);
@@ -2610,6 +2808,7 @@ MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler(
Isolate* isolate = GetIsolate();
HandleScope scope(isolate);
Handle<JSProxy> proxy(this);
+ Handle<Object> handler(this->handler()); // Trap might morph proxy.
Handle<JSReceiver> receiver(receiver_raw);
Handle<Object> name(name_raw);
@@ -2639,7 +2838,9 @@ MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler(
if (isolate->has_pending_exception()) return NONE;
if (configurable->IsFalse()) {
- Handle<Object> args[] = { Handle<Object>(proxy->handler()), proxy, name };
+ Handle<String> trap =
+ isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
+ Handle<Object> args[] = { handler, trap, name };
Handle<Object> error = isolate->factory()->NewTypeError(
"proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
isolate->Throw(*error);
@@ -2859,12 +3060,12 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
// Make sure that the top context does not change when doing callbacks or
// interceptor calls.
AssertNoContextChange ncc;
- LookupResult result;
+ Isolate* isolate = GetIsolate();
+ LookupResult result(isolate);
LocalLookup(name, &result);
// Check access rights if needed.
if (IsAccessCheckNeeded()) {
- Heap* heap = GetHeap();
- if (!heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
+ if (!isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
return SetPropertyWithFailedAccessCheck(&result,
name,
value,
@@ -2935,7 +3136,7 @@ PropertyAttributes JSObject::GetPropertyAttributePostInterceptor(
String* name,
bool continue_search) {
// Check local property, ignore interceptor.
- LookupResult result;
+ LookupResult result(GetIsolate());
LocalLookupRealNamedProperty(name, &result);
if (result.IsProperty()) return result.GetAttributes();
@@ -3011,7 +3212,7 @@ PropertyAttributes JSReceiver::GetPropertyAttributeWithReceiver(
? NONE : ABSENT;
}
// Named property.
- LookupResult result;
+ LookupResult result(GetIsolate());
Lookup(key, &result);
return GetPropertyAttribute(receiver, &result, key, true);
}
@@ -3060,7 +3261,7 @@ PropertyAttributes JSReceiver::GetLocalPropertyAttribute(String* name) {
return ABSENT;
}
// Named property.
- LookupResult result;
+ LookupResult result(GetIsolate());
LocalLookup(name, &result);
return GetPropertyAttribute(this, &result, name, false);
}
@@ -3075,7 +3276,9 @@ MaybeObject* NormalizedMapCache::Get(JSObject* obj,
if (result->IsMap() &&
Map::cast(result)->EquivalentToForNormalization(fast, mode)) {
#ifdef DEBUG
- Map::cast(result)->SharedMapVerify();
+ if (FLAG_verify_heap) {
+ Map::cast(result)->SharedMapVerify();
+ }
if (FLAG_enable_slow_asserts) {
// The cached map should match newly created normalized map bit-by-bit.
Object* fresh;
@@ -3111,6 +3314,15 @@ void NormalizedMapCache::Clear() {
}
+void JSObject::UpdateMapCodeCache(Handle<JSObject> object,
+ Handle<String> name,
+ Handle<Code> code) {
+ Isolate* isolate = object->GetIsolate();
+ CALL_HEAP_FUNCTION_VOID(isolate,
+ object->UpdateMapCodeCache(*name, *code));
+}
+
+
MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) {
if (map()->is_shared()) {
// Fast case maps are never marked as shared.
@@ -3356,7 +3568,7 @@ Smi* JSReceiver::GenerateIdentityHash() {
do {
// Generate a random 32-bit hash value but limit range to fit
// within a smi.
- hash_value = V8::Random(isolate) & Smi::kMaxValue;
+ hash_value = V8::RandomPrivate(isolate) & Smi::kMaxValue;
attempts++;
} while (hash_value == 0 && attempts < 30);
hash_value = hash_value != 0 ? hash_value : 1; // never return 0
@@ -3377,6 +3589,9 @@ MaybeObject* JSObject::GetIdentityHash(CreationFlag flag) {
Object* stored_value = GetHiddenProperty(GetHeap()->identity_hash_symbol());
if (stored_value->IsSmi()) return stored_value;
+ // Do not generate permanent identity hash code if not requested.
+ if (flag == OMIT_CREATION) return GetHeap()->undefined_value();
+
Smi* hash = GenerateIdentityHash();
MaybeObject* result = SetHiddenProperty(GetHeap()->identity_hash_symbol(),
hash);
@@ -3567,7 +3782,7 @@ MaybeObject* JSObject::SetHiddenPropertiesDictionary(
MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name,
DeleteMode mode) {
// Check local property, ignore interceptor.
- LookupResult result;
+ LookupResult result(GetIsolate());
LocalLookupRealNamedProperty(name, &result);
if (!result.IsProperty()) return GetHeap()->true_value();
@@ -3716,7 +3931,7 @@ MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) {
if (name->AsArrayIndex(&index)) {
return DeleteElement(index, mode);
} else {
- LookupResult result;
+ LookupResult result(isolate);
LocalLookup(name, &result);
if (!result.IsProperty()) return isolate->heap()->true_value();
// Ignore attributes if forcing a deletion.
@@ -3927,15 +4142,16 @@ MaybeObject* JSObject::PreventExtensions() {
// Tests for the fast common case for property enumeration:
-// - This object and all prototypes has an enum cache (which means that it has
-// no interceptors and needs no access checks).
+// - This object and all prototypes has an enum cache (which means that
+// it is no proxy, has no interceptors and needs no access checks).
// - This object has no elements.
// - No prototype has enumerable properties/elements.
-bool JSObject::IsSimpleEnum() {
+bool JSReceiver::IsSimpleEnum() {
Heap* heap = GetHeap();
for (Object* o = this;
o != heap->null_value();
o = JSObject::cast(o)->GetPrototype()) {
+ if (!o->IsJSObject()) return false;
JSObject* curr = JSObject::cast(o);
if (!curr->map()->instance_descriptors()->HasEnumCache()) return false;
ASSERT(!curr->HasNamedInterceptor());
@@ -4065,19 +4281,27 @@ void JSObject::LookupCallback(String* name, LookupResult* result) {
}
-// Search for a getter or setter in an elements dictionary. Returns either
-// undefined if the element is read-only, or the getter/setter pair (fixed
-// array) if there is an existing one, or the hole value if the element does
-// not exist or is a normal non-getter/setter data element.
-static Object* FindGetterSetterInDictionary(NumberDictionary* dictionary,
- uint32_t index,
- Heap* heap) {
+// Search for a getter or setter in an elements dictionary and update its
+// attributes. Returns either undefined if the element is read-only, or the
+// getter/setter pair (fixed array) if there is an existing one, or the hole
+// value if the element does not exist or is a normal non-getter/setter data
+// element.
+static Object* UpdateGetterSetterInDictionary(NumberDictionary* dictionary,
+ uint32_t index,
+ PropertyAttributes attributes,
+ Heap* heap) {
int entry = dictionary->FindEntry(index);
if (entry != NumberDictionary::kNotFound) {
Object* result = dictionary->ValueAt(entry);
PropertyDetails details = dictionary->DetailsAt(entry);
if (details.IsReadOnly()) return heap->undefined_value();
- if (details.type() == CALLBACKS && result->IsFixedArray()) return result;
+ if (details.type() == CALLBACKS && result->IsFixedArray()) {
+ if (details.attributes() != attributes) {
+ dictionary->DetailsAtPut(entry,
+ PropertyDetails(attributes, CALLBACKS, index));
+ }
+ return result;
+ }
}
return heap->the_hole_value();
}
@@ -4119,8 +4343,10 @@ MaybeObject* JSObject::DefineGetterSetter(String* name,
// elements.
return heap->undefined_value();
case DICTIONARY_ELEMENTS: {
- Object* probe =
- FindGetterSetterInDictionary(element_dictionary(), index, heap);
+ Object* probe = UpdateGetterSetterInDictionary(element_dictionary(),
+ index,
+ attributes,
+ heap);
if (!probe->IsTheHole()) return probe;
// Otherwise allow to override it.
break;
@@ -4137,7 +4363,10 @@ MaybeObject* JSObject::DefineGetterSetter(String* name,
FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
if (arguments->IsDictionary()) {
NumberDictionary* dictionary = NumberDictionary::cast(arguments);
- probe = FindGetterSetterInDictionary(dictionary, index, heap);
+ probe = UpdateGetterSetterInDictionary(dictionary,
+ index,
+ attributes,
+ heap);
if (!probe->IsTheHole()) return probe;
}
}
@@ -4146,7 +4375,7 @@ MaybeObject* JSObject::DefineGetterSetter(String* name,
}
} else {
// Lookup the name.
- LookupResult result;
+ LookupResult result(heap->isolate());
LocalLookup(name, &result);
if (result.IsProperty()) {
if (result.IsReadOnly()) return heap->undefined_value();
@@ -4176,8 +4405,8 @@ MaybeObject* JSObject::DefineGetterSetter(String* name,
bool JSObject::CanSetCallback(String* name) {
- ASSERT(!IsAccessCheckNeeded()
- || Isolate::Current()->MayNamedAccess(this, name, v8::ACCESS_SET));
+ ASSERT(!IsAccessCheckNeeded() ||
+ GetIsolate()->MayNamedAccess(this, name, v8::ACCESS_SET));
// Check if there is an API defined callback object which prohibits
// callback overwriting in this object or it's prototype chain.
@@ -4185,7 +4414,7 @@ bool JSObject::CanSetCallback(String* name) {
// certain accessors such as window.location should not be allowed
// to be overwritten because allowing overwriting could potentially
// cause security problems.
- LookupResult callback_result;
+ LookupResult callback_result(GetIsolate());
LookupCallback(name, &callback_result);
if (callback_result.IsProperty()) {
Object* obj = callback_result.GetCallbackObject();
@@ -4382,7 +4611,7 @@ MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
}
} else {
// Lookup the name.
- LookupResult result;
+ LookupResult result(isolate);
LocalLookup(name, &result);
// ES5 forbids turning a property into an accessor if it's not
// configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5).
@@ -4440,7 +4669,7 @@ Object* JSObject::LookupAccessor(String* name, bool is_getter) {
for (Object* obj = this;
obj != heap->null_value();
obj = JSObject::cast(obj)->GetPrototype()) {
- LookupResult result;
+ LookupResult result(heap->isolate());
JSObject::cast(obj)->LocalLookup(name, &result);
if (result.IsProperty()) {
if (result.IsReadOnly()) return heap->undefined_value();
@@ -4548,7 +4777,7 @@ MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode,
Map::cast(result)->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
#ifdef DEBUG
- if (Map::cast(result)->is_shared()) {
+ if (FLAG_verify_heap && Map::cast(result)->is_shared()) {
Map::cast(result)->SharedMapVerify();
}
#endif
@@ -4571,6 +4800,13 @@ MaybeObject* Map::CopyDropTransitions() {
return new_map;
}
+void Map::UpdateCodeCache(Handle<Map> map,
+ Handle<String> name,
+ Handle<Code> code) {
+ Isolate* isolate = map->GetIsolate();
+ CALL_HEAP_FUNCTION_VOID(isolate,
+ map->UpdateCodeCache(*name, *code));
+}
MaybeObject* Map::UpdateCodeCache(String* name, Code* code) {
// Allocate the code cache if not present.
@@ -4960,7 +5196,16 @@ void CodeCacheHashTable::RemoveByIndex(int index) {
}
-MaybeObject* PolymorphicCodeCache::Update(MapList* maps,
+void PolymorphicCodeCache::Update(Handle<PolymorphicCodeCache> cache,
+ MapHandleList* maps,
+ Code::Flags flags,
+ Handle<Code> code) {
+ Isolate* isolate = cache->GetIsolate();
+ CALL_HEAP_FUNCTION_VOID(isolate, cache->Update(maps, flags, *code));
+}
+
+
+MaybeObject* PolymorphicCodeCache::Update(MapHandleList* maps,
Code::Flags flags,
Code* code) {
// Initialize cache if necessary.
@@ -4988,13 +5233,14 @@ MaybeObject* PolymorphicCodeCache::Update(MapList* maps,
}
-Object* PolymorphicCodeCache::Lookup(MapList* maps, Code::Flags flags) {
+Handle<Object> PolymorphicCodeCache::Lookup(MapHandleList* maps,
+ Code::Flags flags) {
if (!cache()->IsUndefined()) {
PolymorphicCodeCacheHashTable* hash_table =
PolymorphicCodeCacheHashTable::cast(cache());
- return hash_table->Lookup(maps, flags);
+ return Handle<Object>(hash_table->Lookup(maps, flags));
} else {
- return GetHeap()->undefined_value();
+ return GetIsolate()->factory()->undefined_value();
}
}
@@ -5005,12 +5251,12 @@ Object* PolymorphicCodeCache::Lookup(MapList* maps, Code::Flags flags) {
class PolymorphicCodeCacheHashTableKey : public HashTableKey {
public:
// Callers must ensure that |maps| outlives the newly constructed object.
- PolymorphicCodeCacheHashTableKey(MapList* maps, int code_flags)
+ PolymorphicCodeCacheHashTableKey(MapHandleList* maps, int code_flags)
: maps_(maps),
code_flags_(code_flags) {}
bool IsMatch(Object* other) {
- MapList other_maps(kDefaultListAllocationSize);
+ MapHandleList other_maps(kDefaultListAllocationSize);
int other_flags;
FromObject(other, &other_flags, &other_maps);
if (code_flags_ != other_flags) return false;
@@ -5026,7 +5272,7 @@ class PolymorphicCodeCacheHashTableKey : public HashTableKey {
for (int i = 0; i < maps_->length(); ++i) {
bool match_found = false;
for (int j = 0; j < other_maps.length(); ++j) {
- if (maps_->at(i)->EquivalentTo(other_maps.at(j))) {
+ if (maps_->at(i)->EquivalentTo(*other_maps.at(j))) {
match_found = true;
break;
}
@@ -5036,7 +5282,7 @@ class PolymorphicCodeCacheHashTableKey : public HashTableKey {
return true;
}
- static uint32_t MapsHashHelper(MapList* maps, int code_flags) {
+ static uint32_t MapsHashHelper(MapHandleList* maps, int code_flags) {
uint32_t hash = code_flags;
for (int i = 0; i < maps->length(); ++i) {
hash ^= maps->at(i)->Hash();
@@ -5049,7 +5295,7 @@ class PolymorphicCodeCacheHashTableKey : public HashTableKey {
}
uint32_t HashForObject(Object* obj) {
- MapList other_maps(kDefaultListAllocationSize);
+ MapHandleList other_maps(kDefaultListAllocationSize);
int other_flags;
FromObject(obj, &other_flags, &other_maps);
return MapsHashHelper(&other_maps, other_flags);
@@ -5067,29 +5313,32 @@ class PolymorphicCodeCacheHashTableKey : public HashTableKey {
FixedArray* list = FixedArray::cast(obj);
list->set(0, Smi::FromInt(code_flags_));
for (int i = 0; i < maps_->length(); ++i) {
- list->set(i + 1, maps_->at(i));
+ list->set(i + 1, *maps_->at(i));
}
return list;
}
private:
- static MapList* FromObject(Object* obj, int* code_flags, MapList* maps) {
+ static MapHandleList* FromObject(Object* obj,
+ int* code_flags,
+ MapHandleList* maps) {
FixedArray* list = FixedArray::cast(obj);
maps->Rewind(0);
*code_flags = Smi::cast(list->get(0))->value();
for (int i = 1; i < list->length(); ++i) {
- maps->Add(Map::cast(list->get(i)));
+ maps->Add(Handle<Map>(Map::cast(list->get(i))));
}
return maps;
}
- MapList* maps_; // weak.
+ MapHandleList* maps_; // weak.
int code_flags_;
static const int kDefaultListAllocationSize = kMaxKeyedPolymorphism + 1;
};
-Object* PolymorphicCodeCacheHashTable::Lookup(MapList* maps, int code_flags) {
+Object* PolymorphicCodeCacheHashTable::Lookup(MapHandleList* maps,
+ int code_flags) {
PolymorphicCodeCacheHashTableKey key(maps, code_flags);
int entry = FindEntry(&key);
if (entry == kNotFound) return GetHeap()->undefined_value();
@@ -5097,7 +5346,7 @@ Object* PolymorphicCodeCacheHashTable::Lookup(MapList* maps, int code_flags) {
}
-MaybeObject* PolymorphicCodeCacheHashTable::Put(MapList* maps,
+MaybeObject* PolymorphicCodeCacheHashTable::Put(MapHandleList* maps,
int code_flags,
Code* code) {
PolymorphicCodeCacheHashTableKey key(maps, code_flags);
@@ -5232,9 +5481,9 @@ void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
if (IsEmpty()) return; // Do nothing for empty descriptor array.
FixedArray::cast(bridge_storage)->
set(kEnumCacheBridgeCacheIndex, new_cache);
- fast_set(FixedArray::cast(bridge_storage),
- kEnumCacheBridgeEnumIndex,
- get(kEnumerationIndexIndex));
+ NoWriteBarrierSet(FixedArray::cast(bridge_storage),
+ kEnumCacheBridgeEnumIndex,
+ get(kEnumerationIndexIndex));
set(kEnumerationIndexIndex, bridge_storage);
}
}
@@ -5295,10 +5544,16 @@ MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
++new_size;
}
}
+
+ DescriptorArray* new_descriptors;
{ MaybeObject* maybe_result = Allocate(new_size);
- if (!maybe_result->ToObject(&result)) return maybe_result;
+ if (!maybe_result->To<DescriptorArray>(&new_descriptors)) {
+ return maybe_result;
+ }
}
- DescriptorArray* new_descriptors = DescriptorArray::cast(result);
+
+ DescriptorArray::WhitenessWitness witness(new_descriptors);
+
// Set the enumeration index in the descriptors and set the enumeration index
// in the result.
int enumeration_index = NextEnumerationIndex();
@@ -5326,16 +5581,16 @@ MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
}
if (IsNullDescriptor(from_index)) continue;
if (remove_transitions && IsTransition(from_index)) continue;
- new_descriptors->CopyFrom(to_index++, this, from_index);
+ new_descriptors->CopyFrom(to_index++, this, from_index, witness);
}
- new_descriptors->Set(to_index++, descriptor);
+ new_descriptors->Set(to_index++, descriptor, witness);
if (replacing) from_index++;
for (; from_index < number_of_descriptors(); from_index++) {
if (IsNullDescriptor(from_index)) continue;
if (remove_transitions && IsTransition(from_index)) continue;
- new_descriptors->CopyFrom(to_index++, this, from_index);
+ new_descriptors->CopyFrom(to_index++, this, from_index, witness);
}
ASSERT(to_index == new_descriptors->number_of_descriptors());
@@ -5357,16 +5612,21 @@ MaybeObject* DescriptorArray::RemoveTransitions() {
}
// Allocate the new descriptor array.
- Object* result;
+ DescriptorArray* new_descriptors;
{ MaybeObject* maybe_result = Allocate(number_of_descriptors() - num_removed);
- if (!maybe_result->ToObject(&result)) return maybe_result;
+ if (!maybe_result->To<DescriptorArray>(&new_descriptors)) {
+ return maybe_result;
+ }
}
- DescriptorArray* new_descriptors = DescriptorArray::cast(result);
+
+ DescriptorArray::WhitenessWitness witness(new_descriptors);
// Copy the content.
int next_descriptor = 0;
for (int i = 0; i < number_of_descriptors(); i++) {
- if (IsProperty(i)) new_descriptors->CopyFrom(next_descriptor++, this, i);
+ if (IsProperty(i)) {
+ new_descriptors->CopyFrom(next_descriptor++, this, i, witness);
+ }
}
ASSERT(next_descriptor == new_descriptors->number_of_descriptors());
@@ -5374,7 +5634,7 @@ MaybeObject* DescriptorArray::RemoveTransitions() {
}
-void DescriptorArray::SortUnchecked() {
+void DescriptorArray::SortUnchecked(const WhitenessWitness& witness) {
// In-place heap sort.
int len = number_of_descriptors();
@@ -5395,7 +5655,7 @@ void DescriptorArray::SortUnchecked() {
}
}
if (child_hash <= parent_hash) break;
- Swap(parent_index, child_index);
+ NoWriteBarrierSwapDescriptors(parent_index, child_index);
// Now element at child_index could be < its children.
parent_index = child_index; // parent_hash remains correct.
}
@@ -5404,8 +5664,8 @@ void DescriptorArray::SortUnchecked() {
// Extract elements and create sorted array.
for (int i = len - 1; i > 0; --i) {
// Put max element at the back of the array.
- Swap(0, i);
- // Sift down the new top element.
+ NoWriteBarrierSwapDescriptors(0, i);
+ // Shift down the new top element.
int parent_index = 0;
const uint32_t parent_hash = GetKey(parent_index)->Hash();
const int max_parent_index = (i / 2) - 1;
@@ -5420,15 +5680,15 @@ void DescriptorArray::SortUnchecked() {
}
}
if (child_hash <= parent_hash) break;
- Swap(parent_index, child_index);
+ NoWriteBarrierSwapDescriptors(parent_index, child_index);
parent_index = child_index;
}
}
}
-void DescriptorArray::Sort() {
- SortUnchecked();
+void DescriptorArray::Sort(const WhitenessWitness& witness) {
+ SortUnchecked(witness);
SLOW_ASSERT(IsSortedNoDuplicates());
}
@@ -5513,24 +5773,6 @@ bool String::LooksValid() {
}
-int String::Utf8Length() {
- if (IsAsciiRepresentation()) return length();
- // Attempt to flatten before accessing the string. It probably
- // doesn't make Utf8Length faster, but it is very likely that
- // the string will be accessed later (for example by WriteUtf8)
- // so it's still a good idea.
- Heap* heap = GetHeap();
- TryFlatten();
- Access<StringInputBuffer> buffer(
- heap->isolate()->objects_string_input_buffer());
- buffer->Reset(0, this);
- int result = 0;
- while (buffer->has_more())
- result += unibrow::Utf8::Length(buffer->GetNext());
- return result;
-}
-
-
String::FlatContent String::GetFlatContent() {
int length = this->length();
StringShape shape(this);
@@ -5954,6 +6196,73 @@ const unibrow::byte* String::ReadBlock(String* input,
}
+// This method determines the type of string involved and then gets the UTF8
+// length of the string. It doesn't flatten the string and has log(n) recursion
+// for a string of length n.
+int String::Utf8Length(String* input, int from, int to) {
+ if (from == to) return 0;
+ int total = 0;
+ while (true) {
+ if (input->IsAsciiRepresentation()) return total + to - from;
+ switch (StringShape(input).representation_tag()) {
+ case kConsStringTag: {
+ ConsString* str = ConsString::cast(input);
+ String* first = str->first();
+ String* second = str->second();
+ int first_length = first->length();
+ if (first_length - from < to - first_length) {
+ if (first_length > from) {
+ // Left hand side is shorter.
+ total += Utf8Length(first, from, first_length);
+ input = second;
+ from = 0;
+ to -= first_length;
+ } else {
+ // We only need the right hand side.
+ input = second;
+ from -= first_length;
+ to -= first_length;
+ }
+ } else {
+ if (first_length <= to) {
+ // Right hand side is shorter.
+ total += Utf8Length(second, 0, to - first_length);
+ input = first;
+ to = first_length;
+ } else {
+ // We only need the left hand side.
+ input = first;
+ }
+ }
+ continue;
+ }
+ case kExternalStringTag:
+ case kSeqStringTag: {
+ Vector<const uc16> vector = input->GetFlatContent().ToUC16Vector();
+ const uc16* p = vector.start();
+ for (int i = from; i < to; i++) {
+ total += unibrow::Utf8::Length(p[i]);
+ }
+ return total;
+ }
+ case kSlicedStringTag: {
+ SlicedString* str = SlicedString::cast(input);
+ int offset = str->offset();
+ input = str->parent();
+ from += offset;
+ to += offset;
+ continue;
+ }
+ default:
+ break;
+ }
+ UNREACHABLE();
+ return 0;
+ }
+ return 0;
+}
+
+
void Relocatable::PostGarbageCollectionProcessing() {
Isolate* isolate = Isolate::Current();
Relocatable* current = isolate->relocatable_top();
@@ -6851,6 +7160,57 @@ void JSFunction::MarkForLazyRecompilation() {
}
+bool SharedFunctionInfo::EnsureCompiled(Handle<SharedFunctionInfo> shared,
+ ClearExceptionFlag flag) {
+ return shared->is_compiled() || CompileLazy(shared, flag);
+}
+
+
+static bool CompileLazyHelper(CompilationInfo* info,
+ ClearExceptionFlag flag) {
+ // Compile the source information to a code object.
+ ASSERT(info->IsOptimizing() || !info->shared_info()->is_compiled());
+ ASSERT(!info->isolate()->has_pending_exception());
+ bool result = Compiler::CompileLazy(info);
+ ASSERT(result != Isolate::Current()->has_pending_exception());
+ if (!result && flag == CLEAR_EXCEPTION) {
+ info->isolate()->clear_pending_exception();
+ }
+ return result;
+}
+
+
+bool SharedFunctionInfo::CompileLazy(Handle<SharedFunctionInfo> shared,
+ ClearExceptionFlag flag) {
+ CompilationInfo info(shared);
+ return CompileLazyHelper(&info, flag);
+}
+
+
+bool JSFunction::CompileLazy(Handle<JSFunction> function,
+ ClearExceptionFlag flag) {
+ bool result = true;
+ if (function->shared()->is_compiled()) {
+ function->ReplaceCode(function->shared()->code());
+ function->shared()->set_code_age(0);
+ } else {
+ CompilationInfo info(function);
+ result = CompileLazyHelper(&info, flag);
+ ASSERT(!result || function->is_compiled());
+ }
+ return result;
+}
+
+
+bool JSFunction::CompileOptimized(Handle<JSFunction> function,
+ int osr_ast_id,
+ ClearExceptionFlag flag) {
+ CompilationInfo info(function);
+ info.SetOptimizing(osr_ast_id);
+ return CompileLazyHelper(&info, flag);
+}
+
+
bool JSFunction::IsInlineable() {
if (IsBuiltin()) return false;
SharedFunctionInfo* shared_info = shared();
@@ -7033,7 +7393,7 @@ bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) {
obj = obj->GetPrototype()) {
JSObject* js_object = JSObject::cast(obj);
for (int i = 0; i < this_property_assignments_count(); i++) {
- LookupResult result;
+ LookupResult result(heap->isolate());
String* name = GetThisPropertyAssignmentName(i);
js_object->LocalLookupRealNamedProperty(name, &result);
if (result.IsProperty() && result.type() == CALLBACKS) {
@@ -7391,6 +7751,8 @@ void Code::Relocate(intptr_t delta) {
void Code::CopyFrom(const CodeDesc& desc) {
+ ASSERT(Marking::Color(this) == Marking::WHITE_OBJECT);
+
// copy code
memmove(instruction_start(), desc.buffer, desc.instr_size);
@@ -7410,16 +7772,17 @@ void Code::CopyFrom(const CodeDesc& desc) {
RelocInfo::Mode mode = it.rinfo()->rmode();
if (mode == RelocInfo::EMBEDDED_OBJECT) {
Handle<Object> p = it.rinfo()->target_object_handle(origin);
- it.rinfo()->set_target_object(*p);
+ it.rinfo()->set_target_object(*p, SKIP_WRITE_BARRIER);
} else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
Handle<JSGlobalPropertyCell> cell = it.rinfo()->target_cell_handle();
- it.rinfo()->set_target_cell(*cell);
+ it.rinfo()->set_target_cell(*cell, SKIP_WRITE_BARRIER);
} else if (RelocInfo::IsCodeTarget(mode)) {
// rewrite code handles in inline cache targets to direct
// pointers to the first instruction in the code object
Handle<Object> p = it.rinfo()->target_object_handle(origin);
Code* code = Code::cast(*p);
- it.rinfo()->set_target_address(code->instruction_start());
+ it.rinfo()->set_target_address(code->instruction_start(),
+ SKIP_WRITE_BARRIER);
} else {
it.rinfo()->apply(delta);
}
@@ -7847,13 +8210,15 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength(
new_map = Map::cast(object);
}
+ FixedArrayBase* old_elements_raw = elements();
ElementsKind elements_kind = GetElementsKind();
switch (elements_kind) {
case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS: {
AssertNoAllocation no_gc;
WriteBarrierMode mode(new_elements->GetWriteBarrierMode(no_gc));
- CopyFastElementsToFast(FixedArray::cast(elements()), new_elements, mode);
+ CopyFastElementsToFast(FixedArray::cast(old_elements_raw),
+ new_elements, mode);
set_map(new_map);
set_elements(new_elements);
break;
@@ -7861,7 +8226,7 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength(
case DICTIONARY_ELEMENTS: {
AssertNoAllocation no_gc;
WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
- CopySlowElementsToFast(NumberDictionary::cast(elements()),
+ CopySlowElementsToFast(NumberDictionary::cast(old_elements_raw),
new_elements,
mode);
set_map(new_map);
@@ -7873,7 +8238,7 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength(
WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
// The object's map and the parameter map are unchanged, the unaliased
// arguments are copied to the new backing store.
- FixedArray* parameter_map = FixedArray::cast(elements());
+ FixedArray* parameter_map = FixedArray::cast(old_elements_raw);
FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
if (arguments->IsDictionary()) {
CopySlowElementsToFast(NumberDictionary::cast(arguments),
@@ -7886,7 +8251,7 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength(
break;
}
case FAST_DOUBLE_ELEMENTS: {
- FixedDoubleArray* old_elements = FixedDoubleArray::cast(elements());
+ FixedDoubleArray* old_elements = FixedDoubleArray::cast(old_elements_raw);
uint32_t old_length = static_cast<uint32_t>(old_elements->length());
// Fill out the new array with this content and array holes.
for (uint32_t i = 0; i < old_length; i++) {
@@ -7924,6 +8289,11 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength(
break;
}
+ if (FLAG_trace_elements_transitions) {
+ PrintElementsTransition(stdout, elements_kind, old_elements_raw,
+ FAST_ELEMENTS, new_elements);
+ }
+
// Update the length if necessary.
if (IsJSArray()) {
JSArray::cast(this)->set_length(Smi::FromInt(length));
@@ -7953,19 +8323,21 @@ MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength(
}
Map* new_map = Map::cast(obj);
+ FixedArrayBase* old_elements = elements();
+ ElementsKind elements_kind(GetElementsKind());
AssertNoAllocation no_gc;
- switch (GetElementsKind()) {
+ switch (elements_kind) {
case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS: {
- elems->Initialize(FixedArray::cast(elements()));
+ elems->Initialize(FixedArray::cast(old_elements));
break;
}
case FAST_DOUBLE_ELEMENTS: {
- elems->Initialize(FixedDoubleArray::cast(elements()));
+ elems->Initialize(FixedDoubleArray::cast(old_elements));
break;
}
case DICTIONARY_ELEMENTS: {
- elems->Initialize(NumberDictionary::cast(elements()));
+ elems->Initialize(NumberDictionary::cast(old_elements));
break;
}
default:
@@ -7973,6 +8345,11 @@ MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength(
break;
}
+ if (FLAG_trace_elements_transitions) {
+ PrintElementsTransition(stdout, elements_kind, old_elements,
+ FAST_DOUBLE_ELEMENTS, elems);
+ }
+
ASSERT(new_map->has_fast_double_elements());
set_map(new_map);
ASSERT(elems->IsFixedDoubleArray());
@@ -7992,13 +8369,14 @@ MaybeObject* JSObject::SetSlowElements(Object* len) {
uint32_t new_length = static_cast<uint32_t>(len->Number());
- switch (GetElementsKind()) {
+ FixedArrayBase* old_elements = elements();
+ ElementsKind elements_kind = GetElementsKind();
+ switch (elements_kind) {
case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS:
case FAST_DOUBLE_ELEMENTS: {
// Make sure we never try to shrink dense arrays into sparse arrays.
- ASSERT(static_cast<uint32_t>(
- FixedArrayBase::cast(elements())->length()) <= new_length);
+ ASSERT(static_cast<uint32_t>(old_elements->length()) <= new_length);
MaybeObject* result = NormalizeElements();
if (result->IsFailure()) return result;
@@ -8030,6 +8408,12 @@ MaybeObject* JSObject::SetSlowElements(Object* len) {
UNREACHABLE();
break;
}
+
+ if (FLAG_trace_elements_transitions) {
+ PrintElementsTransition(stdout, elements_kind, old_elements,
+ DICTIONARY_ELEMENTS, elements());
+ }
+
return this;
}
@@ -8957,6 +9341,10 @@ MaybeObject* JSObject::SetFastElement(uint32_t index,
Map* new_map;
if (!maybe_new_map->To<Map>(&new_map)) return maybe_new_map;
set_map(new_map);
+ if (FLAG_trace_elements_transitions) {
+ PrintElementsTransition(stdout, FAST_SMI_ONLY_ELEMENTS, elements(),
+ FAST_ELEMENTS, elements());
+ }
}
// Increase backing store capacity if that's been decided previously.
if (new_capacity != capacity) {
@@ -9313,6 +9701,51 @@ MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
}
+MUST_USE_RESULT MaybeObject* JSObject::TransitionElementsKind(
+ ElementsKind to_kind) {
+ ElementsKind from_kind = map()->elements_kind();
+ FixedArrayBase* elms = FixedArrayBase::cast(elements());
+ uint32_t capacity = static_cast<uint32_t>(elms->length());
+ uint32_t length = capacity;
+ if (IsJSArray()) {
+ CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
+ }
+ if (from_kind == FAST_SMI_ONLY_ELEMENTS) {
+ if (to_kind == FAST_DOUBLE_ELEMENTS) {
+ MaybeObject* maybe_result =
+ SetFastDoubleElementsCapacityAndLength(capacity, length);
+ if (maybe_result->IsFailure()) return maybe_result;
+ return this;
+ } else if (to_kind == FAST_ELEMENTS) {
+ MaybeObject* maybe_new_map = GetElementsTransitionMap(FAST_ELEMENTS);
+ Map* new_map;
+ if (!maybe_new_map->To(&new_map)) return maybe_new_map;
+ set_map(new_map);
+ return this;
+ }
+ } else if (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS) {
+ MaybeObject* maybe_result = SetFastElementsCapacityAndLength(
+ capacity, length, kDontAllowSmiOnlyElements);
+ if (maybe_result->IsFailure()) return maybe_result;
+ return this;
+ }
+ // This method should never be called for any other case than the ones
+ // handled above.
+ UNREACHABLE();
+ return GetIsolate()->heap()->null_value();
+}
+
+
+// static
+bool Map::IsValidElementsTransition(ElementsKind from_kind,
+ ElementsKind to_kind) {
+ return
+ (from_kind == FAST_SMI_ONLY_ELEMENTS &&
+ (to_kind == FAST_DOUBLE_ELEMENTS || to_kind == FAST_ELEMENTS)) ||
+ (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS);
+}
+
+
MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index,
Object* value) {
uint32_t old_len = 0;
@@ -9579,7 +10012,7 @@ MaybeObject* JSObject::GetPropertyPostInterceptor(
String* name,
PropertyAttributes* attributes) {
// Check local property in holder, ignore interceptor.
- LookupResult result;
+ LookupResult result(GetIsolate());
LocalLookupRealNamedProperty(name, &result);
if (result.IsProperty()) {
return GetProperty(receiver, &result, name, attributes);
@@ -9597,7 +10030,7 @@ MaybeObject* JSObject::GetLocalPropertyPostInterceptor(
String* name,
PropertyAttributes* attributes) {
// Check local property in holder, ignore interceptor.
- LookupResult result;
+ LookupResult result(GetIsolate());
LocalLookupRealNamedProperty(name, &result);
if (result.IsProperty()) {
return GetProperty(receiver, &result, name, attributes);
@@ -9648,15 +10081,15 @@ MaybeObject* JSObject::GetPropertyWithInterceptor(
bool JSObject::HasRealNamedProperty(String* key) {
// Check access rights if needed.
+ Isolate* isolate = GetIsolate();
if (IsAccessCheckNeeded()) {
- Heap* heap = GetHeap();
- if (!heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
- heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
+ if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
+ isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
return false;
}
}
- LookupResult result;
+ LookupResult result(isolate);
LocalLookupRealNamedProperty(key, &result);
return result.IsProperty() && (result.type() != INTERCEPTOR);
}
@@ -9725,15 +10158,15 @@ bool JSObject::HasRealElementProperty(uint32_t index) {
bool JSObject::HasRealNamedCallbackProperty(String* key) {
// Check access rights if needed.
+ Isolate* isolate = GetIsolate();
if (IsAccessCheckNeeded()) {
- Heap* heap = GetHeap();
- if (!heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
- heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
+ if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
+ isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
return false;
}
}
- LookupResult result;
+ LookupResult result(isolate);
LocalLookupRealNamedProperty(key, &result);
return result.IsProperty() && (result.type() == CALLBACKS);
}
@@ -10598,7 +11031,9 @@ template class HashTable<CompilationCacheShape, HashTableKey*>;
template class HashTable<MapCacheShape, HashTableKey*>;
-template class HashTable<ObjectHashTableShape, JSReceiver*>;
+template class HashTable<ObjectHashTableShape<1>, Object*>;
+
+template class HashTable<ObjectHashTableShape<2>, Object*>;
template class Dictionary<StringDictionaryShape, String*>;
@@ -11089,6 +11524,16 @@ JSGlobalPropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
}
+Handle<JSGlobalPropertyCell> GlobalObject::EnsurePropertyCell(
+ Handle<GlobalObject> global,
+ Handle<String> name) {
+ Isolate* isolate = global->GetIsolate();
+ CALL_HEAP_FUNCTION(isolate,
+ global->EnsurePropertyCell(*name),
+ JSGlobalPropertyCell);
+}
+
+
MaybeObject* GlobalObject::EnsurePropertyCell(String* name) {
ASSERT(!HasFastProperties());
int entry = property_dictionary()->FindEntry(name);
@@ -11326,7 +11771,7 @@ MaybeObject* CompilationCacheTable::PutEval(String* src,
SharedFunctionInfo* value) {
StringSharedKey key(src,
context->closure()->shared(),
- value->strict_mode() ? kStrictMode : kNonStrictMode);
+ value->strict_mode_flag());
Object* obj;
{ MaybeObject* maybe_obj = EnsureCapacity(1, &key);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
@@ -11375,8 +11820,8 @@ void CompilationCacheTable::Remove(Object* value) {
int entry_index = EntryToIndex(entry);
int value_index = entry_index + 1;
if (get(value_index) == value) {
- fast_set(this, entry_index, null_value);
- fast_set(this, value_index, null_value);
+ NoWriteBarrierSet(this, entry_index, null_value);
+ NoWriteBarrierSet(this, value_index, null_value);
ElementRemoved();
}
}
@@ -11848,14 +12293,15 @@ MaybeObject* StringDictionary::TransformPropertiesToFastFor(
}
// Allocate the instance descriptor.
- Object* descriptors_unchecked;
- { MaybeObject* maybe_descriptors_unchecked =
+ DescriptorArray* descriptors;
+ { MaybeObject* maybe_descriptors =
DescriptorArray::Allocate(instance_descriptor_length);
- if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
- return maybe_descriptors_unchecked;
+ if (!maybe_descriptors->To<DescriptorArray>(&descriptors)) {
+ return maybe_descriptors;
}
}
- DescriptorArray* descriptors = DescriptorArray::cast(descriptors_unchecked);
+
+ DescriptorArray::WhitenessWitness witness(descriptors);
int inobject_props = obj->map()->inobject_properties();
int number_of_allocated_fields =
@@ -11893,7 +12339,7 @@ MaybeObject* StringDictionary::TransformPropertiesToFastFor(
JSFunction::cast(value),
details.attributes(),
details.index());
- descriptors->Set(next_descriptor++, &d);
+ descriptors->Set(next_descriptor++, &d, witness);
} else if (type == NORMAL) {
if (current_offset < inobject_props) {
obj->InObjectPropertyAtPut(current_offset,
@@ -11907,13 +12353,13 @@ MaybeObject* StringDictionary::TransformPropertiesToFastFor(
current_offset++,
details.attributes(),
details.index());
- descriptors->Set(next_descriptor++, &d);
+ descriptors->Set(next_descriptor++, &d, witness);
} else if (type == CALLBACKS) {
CallbacksDescriptor d(String::cast(key),
value,
details.attributes(),
details.index());
- descriptors->Set(next_descriptor++, &d);
+ descriptors->Set(next_descriptor++, &d, witness);
} else {
UNREACHABLE();
}
@@ -11921,7 +12367,7 @@ MaybeObject* StringDictionary::TransformPropertiesToFastFor(
}
ASSERT(current_offset == number_of_fields);
- descriptors->Sort();
+ descriptors->Sort(witness);
// Allocate new map.
Object* new_map;
{ MaybeObject* maybe_new_map = obj->map()->CopyDropDescriptors();
@@ -11944,20 +12390,74 @@ MaybeObject* StringDictionary::TransformPropertiesToFastFor(
}
-Object* ObjectHashTable::Lookup(JSReceiver* key) {
+bool ObjectHashSet::Contains(Object* key) {
+ // If the object does not have an identity hash, it was never used as a key.
+ { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
+ if (maybe_hash->ToObjectUnchecked()->IsUndefined()) return false;
+ }
+ return (FindEntry(key) != kNotFound);
+}
+
+
+MaybeObject* ObjectHashSet::Add(Object* key) {
+ // Make sure the key object has an identity hash code.
+ int hash;
+ { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION);
+ if (maybe_hash->IsFailure()) return maybe_hash;
+ hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
+ }
+ int entry = FindEntry(key);
+
+ // Check whether key is already present.
+ if (entry != kNotFound) return this;
+
+ // Check whether the hash set should be extended and add entry.
+ Object* obj;
+ { MaybeObject* maybe_obj = EnsureCapacity(1, key);
+ if (!maybe_obj->ToObject(&obj)) return maybe_obj;
+ }
+ ObjectHashSet* table = ObjectHashSet::cast(obj);
+ entry = table->FindInsertionEntry(hash);
+ table->set(EntryToIndex(entry), key);
+ table->ElementAdded();
+ return table;
+}
+
+
+MaybeObject* ObjectHashSet::Remove(Object* key) {
// If the object does not have an identity hash, it was never used as a key.
- MaybeObject* maybe_hash = key->GetIdentityHash(OMIT_CREATION);
- if (maybe_hash->IsFailure()) return GetHeap()->undefined_value();
+ { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
+ if (maybe_hash->ToObjectUnchecked()->IsUndefined()) return this;
+ }
+ int entry = FindEntry(key);
+
+ // Check whether key is actually present.
+ if (entry == kNotFound) return this;
+
+ // Remove entry and try to shrink this hash set.
+ set_null(EntryToIndex(entry));
+ ElementRemoved();
+ return Shrink(key);
+}
+
+
+Object* ObjectHashTable::Lookup(Object* key) {
+ // If the object does not have an identity hash, it was never used as a key.
+ { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
+ if (maybe_hash->ToObjectUnchecked()->IsUndefined()) {
+ return GetHeap()->undefined_value();
+ }
+ }
int entry = FindEntry(key);
if (entry == kNotFound) return GetHeap()->undefined_value();
return get(EntryToIndex(entry) + 1);
}
-MaybeObject* ObjectHashTable::Put(JSReceiver* key, Object* value) {
+MaybeObject* ObjectHashTable::Put(Object* key, Object* value) {
// Make sure the key object has an identity hash code.
int hash;
- { MaybeObject* maybe_hash = key->GetIdentityHash(ALLOW_CREATION);
+ { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION);
if (maybe_hash->IsFailure()) return maybe_hash;
hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
}
@@ -11987,7 +12487,7 @@ MaybeObject* ObjectHashTable::Put(JSReceiver* key, Object* value) {
}
-void ObjectHashTable::AddEntry(int entry, JSReceiver* key, Object* value) {
+void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) {
set(EntryToIndex(entry), key);
set(EntryToIndex(entry) + 1, value);
ElementAdded();
diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h
index b95fa574a0..f7d2180227 100644
--- a/deps/v8/src/objects.h
+++ b/deps/v8/src/objects.h
@@ -40,6 +40,7 @@
#endif
#include "v8checks.h"
+
//
// Most object types in the V8 JavaScript are described in this file.
//
@@ -52,6 +53,8 @@
// - JSReceiver (suitable for property access)
// - JSObject
// - JSArray
+// - JSSet
+// - JSMap
// - JSWeakMap
// - JSRegExp
// - JSFunction
@@ -173,6 +176,8 @@ enum ElementsKind {
static const int kElementsKindCount =
LAST_ELEMENTS_KIND - FIRST_ELEMENTS_KIND + 1;
+void PrintElementsKind(FILE* out, ElementsKind kind);
+
// PropertyDetails captures type and attributes for a property.
// They are used both in property dictionaries and instance descriptors.
class PropertyDetails BASE_EMBEDDED {
@@ -628,6 +633,8 @@ enum InstanceType {
JS_BUILTINS_OBJECT_TYPE,
JS_GLOBAL_PROXY_TYPE,
JS_ARRAY_TYPE,
+ JS_SET_TYPE,
+ JS_MAP_TYPE,
JS_WEAK_MAP_TYPE,
JS_REGEXP_TYPE,
@@ -820,6 +827,8 @@ class MaybeObject BASE_EMBEDDED {
V(JSArray) \
V(JSProxy) \
V(JSFunctionProxy) \
+ V(JSSet) \
+ V(JSMap) \
V(JSWeakMap) \
V(JSRegExp) \
V(HashTable) \
@@ -857,6 +866,8 @@ class Object : public MaybeObject {
HEAP_OBJECT_TYPE_LIST(IS_TYPE_FUNCTION_DECL)
#undef IS_TYPE_FUNCTION_DECL
+ inline bool IsFixedArrayBase();
+
// Returns true if this object is an instance of the specified
// function template.
inline bool IsInstanceOf(FunctionTemplateInfo* type);
@@ -912,13 +923,22 @@ class Object : public MaybeObject {
Object* receiver,
String* key,
PropertyAttributes* attributes);
+
+ static Handle<Object> GetProperty(Handle<Object> object,
+ Handle<Object> receiver,
+ LookupResult* result,
+ Handle<String> key,
+ PropertyAttributes* attributes);
+
MUST_USE_RESULT MaybeObject* GetProperty(Object* receiver,
LookupResult* result,
String* key,
PropertyAttributes* attributes);
+
MUST_USE_RESULT MaybeObject* GetPropertyWithDefinedGetter(Object* receiver,
JSReceiver* getter);
+ static Handle<Object> GetElement(Handle<Object> object, uint32_t index);
inline MaybeObject* GetElement(uint32_t index);
// For use when we know that no exception can be thrown.
inline Object* GetElementNoExceptionThrown(uint32_t index);
@@ -927,6 +947,16 @@ class Object : public MaybeObject {
// Return the object's prototype (might be Heap::null_value()).
Object* GetPrototype();
+ // Returns the permanent hash code associated with this object depending on
+ // the actual object type. Might return a failure in case no hash was
+ // created yet or GC was caused by creation.
+ MUST_USE_RESULT MaybeObject* GetHash(CreationFlag flag);
+
+ // Checks whether this object has the same value as the given one. This
+ // function is implemented according to ES5, section 9.12 and can be used
+ // to implement the Harmony "egal" function.
+ bool SameValue(Object* other);
+
// Tries to convert an object to an array index. Returns true and sets
// the output parameter if it succeeds.
inline bool ToArrayIndex(uint32_t* index);
@@ -1351,6 +1381,9 @@ class JSReceiver: public HeapObject {
StrictModeFlag strict_mode,
bool check_prototype);
+ // Tests for the fast common case for property enumeration.
+ bool IsSimpleEnum();
+
// Returns the class name ([[Class]] property in the specification).
String* class_name();
@@ -1376,7 +1409,7 @@ class JSReceiver: public HeapObject {
bool skip_hidden_prototypes);
// Retrieves a permanent object identity hash code. The undefined value might
- // be returned in case no has been created yet and OMIT_CREATION was used.
+ // be returned in case no hash was created yet and OMIT_CREATION was used.
inline MUST_USE_RESULT MaybeObject* GetIdentityHash(CreationFlag flag);
// Lookup a property. If found, the result is valid and has
@@ -1603,9 +1636,6 @@ class JSObject: public JSReceiver {
MUST_USE_RESULT MaybeObject* DeleteProperty(String* name, DeleteMode mode);
MUST_USE_RESULT MaybeObject* DeleteElement(uint32_t index, DeleteMode mode);
- // Tests for the fast common case for property enumeration.
- bool IsSimpleEnum();
-
inline void ValidateSmiOnlyElements();
// Makes sure that this object can contain non-smi Object as elements.
@@ -1786,9 +1816,13 @@ class JSObject: public JSReceiver {
// Returns a new map with all transitions dropped from the object's current
// map and the ElementsKind set.
+ static Handle<Map> GetElementsTransitionMap(Handle<JSObject> object,
+ ElementsKind to_kind);
MUST_USE_RESULT MaybeObject* GetElementsTransitionMap(
ElementsKind elements_kind);
+ MUST_USE_RESULT MaybeObject* TransitionElementsKind(ElementsKind to_kind);
+
// Converts a descriptor of any other type to a real field,
// backed by the properties array. Descriptors of visible
// types, such as CONSTANT_FUNCTION, keep their enumeration order.
@@ -1835,6 +1869,10 @@ class JSObject: public JSReceiver {
// dictionary. Returns the backing after conversion.
MUST_USE_RESULT MaybeObject* NormalizeElements();
+ static void UpdateMapCodeCache(Handle<JSObject> object,
+ Handle<String> name,
+ Handle<Code> code);
+
MUST_USE_RESULT MaybeObject* UpdateMapCodeCache(String* name, Code* code);
// Transform slow named properties to fast variants.
@@ -1896,6 +1934,10 @@ class JSObject: public JSReceiver {
void PrintElements(FILE* out);
#endif
+ void PrintElementsTransition(
+ FILE* file, ElementsKind from_kind, FixedArrayBase* from_elements,
+ ElementsKind to_kind, FixedArrayBase* to_elements);
+
#ifdef DEBUG
// Structure for collecting spill information about JSObjects.
class SpillInformation {
@@ -2162,7 +2204,9 @@ class FixedArray: public FixedArrayBase {
protected:
// Set operation on FixedArray without using write barriers. Can
// only be used for storing old space objects or smis.
- static inline void fast_set(FixedArray* array, int index, Object* value);
+ static inline void NoWriteBarrierSet(FixedArray* array,
+ int index,
+ Object* value);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(FixedArray);
@@ -2185,6 +2229,9 @@ class FixedDoubleArray: public FixedArrayBase {
// Checking for the hole.
inline bool is_the_hole(int index);
+ // Copy operations
+ MUST_USE_RESULT inline MaybeObject* Copy();
+
// Garbage collection support.
inline static int SizeFor(int length) {
return kHeaderSize + length * kDoubleSize;
@@ -2224,6 +2271,9 @@ class FixedDoubleArray: public FixedArrayBase {
};
+class IncrementalMarking;
+
+
// DescriptorArrays are fixed arrays used to hold instance descriptors.
// The format of the these objects is:
// TODO(1399): It should be possible to make room for bit_field3 in the map
@@ -2265,7 +2315,7 @@ class DescriptorArray: public FixedArray {
// Set next enumeration index and flush any enum cache.
void SetNextEnumerationIndex(int value) {
if (!IsEmpty()) {
- fast_set(this, kEnumerationIndexIndex, Smi::FromInt(value));
+ set(kEnumerationIndexIndex, Smi::FromInt(value));
}
}
bool HasEnumCache() {
@@ -2302,13 +2352,27 @@ class DescriptorArray: public FixedArray {
inline bool IsNullDescriptor(int descriptor_number);
inline bool IsDontEnum(int descriptor_number);
+ class WhitenessWitness {
+ public:
+ inline explicit WhitenessWitness(DescriptorArray* array);
+ inline ~WhitenessWitness();
+
+ private:
+ IncrementalMarking* marking_;
+ };
+
// Accessor for complete descriptor.
inline void Get(int descriptor_number, Descriptor* desc);
- inline void Set(int descriptor_number, Descriptor* desc);
+ inline void Set(int descriptor_number,
+ Descriptor* desc,
+ const WhitenessWitness&);
// Transfer complete descriptor from another descriptor array to
// this one.
- inline void CopyFrom(int index, DescriptorArray* src, int src_index);
+ inline void CopyFrom(int index,
+ DescriptorArray* src,
+ int src_index,
+ const WhitenessWitness&);
// Copy the descriptor array, insert a new descriptor and optionally
// remove map transitions. If the descriptor is already present, it is
@@ -2325,11 +2389,11 @@ class DescriptorArray: public FixedArray {
// Sort the instance descriptors by the hash codes of their keys.
// Does not check for duplicates.
- void SortUnchecked();
+ void SortUnchecked(const WhitenessWitness&);
// Sort the instance descriptors by the hash codes of their keys.
// Checks the result for duplicates.
- void Sort();
+ void Sort(const WhitenessWitness&);
// Search the instance descriptors for given name.
inline int Search(String* name);
@@ -2422,10 +2486,12 @@ class DescriptorArray: public FixedArray {
NULL_DESCRIPTOR;
}
// Swap operation on FixedArray without using write barriers.
- static inline void fast_swap(FixedArray* array, int first, int second);
+ static inline void NoWriteBarrierSwap(FixedArray* array,
+ int first,
+ int second);
// Swap descriptor first and second.
- inline void Swap(int first, int second);
+ inline void NoWriteBarrierSwapDescriptors(int first, int second);
FixedArray* GetContentArray() {
return FixedArray::cast(get(kContentArrayIndex));
@@ -2567,12 +2633,12 @@ class HashTable: public FixedArray {
// Update the number of elements in the hash table.
void SetNumberOfElements(int nof) {
- fast_set(this, kNumberOfElementsIndex, Smi::FromInt(nof));
+ set(kNumberOfElementsIndex, Smi::FromInt(nof));
}
// Update the number of deleted elements in the hash table.
void SetNumberOfDeletedElements(int nod) {
- fast_set(this, kNumberOfDeletedElementsIndex, Smi::FromInt(nod));
+ set(kNumberOfDeletedElementsIndex, Smi::FromInt(nod));
}
// Sets the capacity of the hash table.
@@ -2582,7 +2648,7 @@ class HashTable: public FixedArray {
// and non-zero.
ASSERT(capacity > 0);
ASSERT(capacity <= kMaxCapacity);
- fast_set(this, kCapacityIndex, Smi::FromInt(capacity));
+ set(kCapacityIndex, Smi::FromInt(capacity));
}
@@ -2790,7 +2856,7 @@ class Dictionary: public HashTable<Shape, Key> {
// Accessors for next enumeration index.
void SetNextEnumerationIndex(int index) {
- this->fast_set(this, kNextEnumerationIndexIndex, Smi::FromInt(index));
+ this->set(kNextEnumerationIndexIndex, Smi::FromInt(index));
}
int NextEnumerationIndex() {
@@ -2931,20 +2997,41 @@ class NumberDictionary: public Dictionary<NumberDictionaryShape, uint32_t> {
};
+template <int entrysize>
class ObjectHashTableShape {
public:
- static inline bool IsMatch(JSReceiver* key, Object* other);
- static inline uint32_t Hash(JSReceiver* key);
- static inline uint32_t HashForObject(JSReceiver* key, Object* object);
- MUST_USE_RESULT static inline MaybeObject* AsObject(JSReceiver* key);
+ static inline bool IsMatch(Object* key, Object* other);
+ static inline uint32_t Hash(Object* key);
+ static inline uint32_t HashForObject(Object* key, Object* object);
+ MUST_USE_RESULT static inline MaybeObject* AsObject(Object* key);
static const int kPrefixSize = 0;
- static const int kEntrySize = 2;
+ static const int kEntrySize = entrysize;
+};
+
+
+// ObjectHashSet holds keys that are arbitrary objects by using the identity
+// hash of the key for hashing purposes.
+class ObjectHashSet: public HashTable<ObjectHashTableShape<1>, Object*> {
+ public:
+ static inline ObjectHashSet* cast(Object* obj) {
+ ASSERT(obj->IsHashTable());
+ return reinterpret_cast<ObjectHashSet*>(obj);
+ }
+
+ // Looks up whether the given key is part of this hash set.
+ bool Contains(Object* key);
+
+ // Adds the given key to this hash set.
+ MUST_USE_RESULT MaybeObject* Add(Object* key);
+
+ // Removes the given key from this hash set.
+ MUST_USE_RESULT MaybeObject* Remove(Object* key);
};
-// ObjectHashTable maps keys that are JavaScript objects to object values by
+// ObjectHashTable maps keys that are arbitrary objects to object values by
// using the identity hash of the key for hashing purposes.
-class ObjectHashTable: public HashTable<ObjectHashTableShape, JSReceiver*> {
+class ObjectHashTable: public HashTable<ObjectHashTableShape<2>, Object*> {
public:
static inline ObjectHashTable* cast(Object* obj) {
ASSERT(obj->IsHashTable());
@@ -2953,16 +3040,16 @@ class ObjectHashTable: public HashTable<ObjectHashTableShape, JSReceiver*> {
// Looks up the value associated with the given key. The undefined value is
// returned in case the key is not present.
- Object* Lookup(JSReceiver* key);
+ Object* Lookup(Object* key);
// Adds (or overwrites) the value associated with the given key. Mapping a
// key to the undefined value causes removal of the whole entry.
- MUST_USE_RESULT MaybeObject* Put(JSReceiver* key, Object* value);
+ MUST_USE_RESULT MaybeObject* Put(Object* key, Object* value);
private:
friend class MarkCompactCollector;
- void AddEntry(int entry, JSReceiver* key, Object* value);
+ void AddEntry(int entry, Object* key, Object* value);
void RemoveEntry(int entry, Heap* heap);
inline void RemoveEntry(int entry);
@@ -3020,6 +3107,9 @@ class SerializedScopeInfo : public FixedArray {
return reinterpret_cast<SerializedScopeInfo*>(object);
}
+ // Return the type of this scope.
+ ScopeType Type();
+
// Does this scope call eval?
bool CallsEval();
@@ -3035,6 +3125,9 @@ class SerializedScopeInfo : public FixedArray {
// Return if this has context slots besides MIN_CONTEXT_SLOTS;
bool HasHeapAllocatedLocals();
+ // Return if contexts are allocated for this scope.
+ bool HasContext();
+
// Lookup support for serialized scope info. Returns the
// the stack slot index for a given slot name if the slot is
// present; otherwise returns a value < 0. The name must be a symbol
@@ -3057,7 +3150,7 @@ class SerializedScopeInfo : public FixedArray {
// function context slot index if the function name is present (named
// function expressions, only), otherwise returns a value < 0. The name
// must be a symbol (canonicalized).
- int FunctionContextSlotIndex(String* name);
+ int FunctionContextSlotIndex(String* name, VariableMode* mode);
static Handle<SerializedScopeInfo> Create(Scope* scope);
@@ -3746,6 +3839,11 @@ class Code: public HeapObject {
inline bool has_debug_break_slots();
inline void set_has_debug_break_slots(bool value);
+ // [compiled_with_optimizing]: For FUNCTION kind, tells if it has
+ // been compiled with IsOptimizing set to true.
+ inline bool is_compiled_optimizable();
+ inline void set_compiled_optimizable(bool value);
+
// [allow_osr_at_loop_nesting_level]: For FUNCTION kind, tells for
// how long the function has been marked for OSR and therefore which
// level of loop nesting we are willing to do on-stack replacement
@@ -3941,6 +4039,7 @@ class Code: public HeapObject {
class FullCodeFlagsHasDeoptimizationSupportField:
public BitField<bool, 0, 1> {}; // NOLINT
class FullCodeFlagsHasDebugBreakSlotsField: public BitField<bool, 1, 1> {};
+ class FullCodeFlagsIsCompiledOptimizable: public BitField<bool, 2, 1> {};
static const int kBinaryOpReturnTypeOffset = kBinaryOpTypeOffset + 1;
@@ -4122,6 +4221,9 @@ class Map: public HeapObject {
return elements_kind() == DICTIONARY_ELEMENTS;
}
+ static bool IsValidElementsTransition(ElementsKind from_kind,
+ ElementsKind to_kind);
+
// Tells whether the map is attached to SharedFunctionInfo
// (for inobject slack tracking).
inline void set_attached_to_shared_function_info(bool value);
@@ -4230,6 +4332,9 @@ class Map: public HeapObject {
inline void ClearCodeCache(Heap* heap);
// Update code cache.
+ static void UpdateCodeCache(Handle<Map> map,
+ Handle<String> name,
+ Handle<Code> code);
MUST_USE_RESULT MaybeObject* UpdateCodeCache(String* name, Code* code);
// Returns the found code or undefined if absent.
@@ -4288,6 +4393,13 @@ class Map: public HeapObject {
MaybeObject* AddElementsTransition(ElementsKind elements_kind,
Map* transitioned_map);
+ // Returns the transitioned map for this map with the most generic
+ // elements_kind that's found in |candidates|, or null handle if no match is
+ // found at all.
+ Handle<Map> FindTransitionedMap(MapHandleList* candidates);
+ Map* FindTransitionedMap(MapList* candidates);
+
+
// Dispatched behavior.
#ifdef OBJECT_PRINT
inline void MapPrint() {
@@ -4796,7 +4908,11 @@ class SharedFunctionInfo: public HeapObject {
DECL_BOOLEAN_ACCESSORS(optimization_disabled)
// Indicates whether the function is a strict mode function.
- DECL_BOOLEAN_ACCESSORS(strict_mode)
+ inline bool strict_mode();
+
+ // Indicates the mode of the function.
+ inline StrictModeFlag strict_mode_flag();
+ inline void set_strict_mode_flag(StrictModeFlag strict_mode_flag);
// False if the function definitely does not allocate an arguments object.
DECL_BOOLEAN_ACCESSORS(uses_arguments)
@@ -4888,6 +5004,13 @@ class SharedFunctionInfo: public HeapObject {
void SharedFunctionInfoVerify();
#endif
+ // Helpers to compile the shared code. Returns true on success, false on
+ // failure (e.g., stack overflow during compilation).
+ static bool EnsureCompiled(Handle<SharedFunctionInfo> shared,
+ ClearExceptionFlag flag);
+ static bool CompileLazy(Handle<SharedFunctionInfo> shared,
+ ClearExceptionFlag flag);
+
// Casting.
static inline SharedFunctionInfo* cast(Object* obj);
@@ -5038,7 +5161,7 @@ class SharedFunctionInfo: public HeapObject {
public:
// Constants for optimizing codegen for strict mode function and
// native tests.
- // Allows to use byte-widgh instructions.
+ // Allows to use byte-width instructions.
static const int kStrictModeBitWithinByte =
(kStrictModeFunction + kCompilerHintsSmiTagSize) % kBitsPerByte;
@@ -5109,6 +5232,14 @@ class JSFunction: public JSObject {
// recompiled the next time it is executed.
void MarkForLazyRecompilation();
+ // Helpers to compile this function. Returns true on success, false on
+ // failure (e.g., stack overflow during compilation).
+ static bool CompileLazy(Handle<JSFunction> function,
+ ClearExceptionFlag flag);
+ static bool CompileOptimized(Handle<JSFunction> function,
+ int osr_ast_id,
+ ClearExceptionFlag flag);
+
// Tells whether or not the function is already marked for lazy
// recompilation.
inline bool IsMarkedForLazyRecompilation();
@@ -5116,7 +5247,8 @@ class JSFunction: public JSObject {
// Check whether or not this function is inlineable.
bool IsInlineable();
- // [literals]: Fixed array holding the materialized literals.
+ // [literals_or_bindings]: Fixed array holding either
+ // the materialized literals or the bindings of a bound function.
//
// If the function contains object, regexp or array literals, the
// literals array prefix contains the object, regexp, and array
@@ -5125,7 +5257,17 @@ class JSFunction: public JSObject {
// or array functions. Performing a dynamic lookup, we might end up
// using the functions from a new context that we should not have
// access to.
- DECL_ACCESSORS(literals, FixedArray)
+ //
+ // On bound functions, the array is a (copy-on-write) fixed-array containing
+ // the function that was bound, bound this-value and any bound
+ // arguments. Bound functions never contain literals.
+ DECL_ACCESSORS(literals_or_bindings, FixedArray)
+
+ inline FixedArray* literals();
+ inline void set_literals(FixedArray* literals);
+
+ inline FixedArray* function_bindings();
+ inline void set_function_bindings(FixedArray* bindings);
// The initial map for an object created by this constructor.
inline Map* initial_map();
@@ -5213,6 +5355,11 @@ class JSFunction: public JSObject {
static const int kLiteralsPrefixSize = 1;
static const int kLiteralGlobalContextIndex = 0;
+ // Layout of the bound-function binding array.
+ static const int kBoundFunctionIndex = 0;
+ static const int kBoundThisIndex = 1;
+ static const int kBoundArgumentsStartIndex = 2;
+
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSFunction);
};
@@ -5285,6 +5432,11 @@ class GlobalObject: public JSObject {
}
// Ensure that the global object has a cell for the given property name.
+ static Handle<JSGlobalPropertyCell> EnsurePropertyCell(
+ Handle<GlobalObject> global,
+ Handle<String> name);
+ // TODO(kmillikin): This function can be eliminated once the stub cache is
+ // full handlified (and the static helper can be written directly).
MUST_USE_RESULT MaybeObject* EnsurePropertyCell(String* name);
// Casting.
@@ -5757,10 +5909,17 @@ class PolymorphicCodeCache: public Struct {
public:
DECL_ACCESSORS(cache, Object)
- MUST_USE_RESULT MaybeObject* Update(MapList* maps,
+ static void Update(Handle<PolymorphicCodeCache> cache,
+ MapHandleList* maps,
+ Code::Flags flags,
+ Handle<Code> code);
+
+ MUST_USE_RESULT MaybeObject* Update(MapHandleList* maps,
Code::Flags flags,
Code* code);
- Object* Lookup(MapList* maps, Code::Flags flags);
+
+ // Returns an undefined value if the entry is not found.
+ Handle<Object> Lookup(MapHandleList* maps, Code::Flags flags);
static inline PolymorphicCodeCache* cast(Object* obj);
@@ -5785,8 +5944,11 @@ class PolymorphicCodeCache: public Struct {
class PolymorphicCodeCacheHashTable
: public HashTable<CodeCacheHashTableShape, HashTableKey*> {
public:
- Object* Lookup(MapList* maps, int code_kind);
- MUST_USE_RESULT MaybeObject* Put(MapList* maps, int code_kind, Code* code);
+ Object* Lookup(MapHandleList* maps, int code_kind);
+
+ MUST_USE_RESULT MaybeObject* Put(MapHandleList* maps,
+ int code_kind,
+ Code* code);
static inline PolymorphicCodeCacheHashTable* cast(Object* obj);
@@ -6057,7 +6219,8 @@ class String: public HeapObject {
RobustnessFlag robustness_flag = FAST_STRING_TRAVERSAL,
int* length_output = 0);
- int Utf8Length();
+ inline int Utf8Length() { return Utf8Length(this, 0, length()); }
+ static int Utf8Length(String* input, int from, int to);
// Return a 16 bit Unicode representation of the string.
// The string should be nearly flat, otherwise the performance of
@@ -6917,6 +7080,60 @@ class JSFunctionProxy: public JSProxy {
};
+// The JSSet describes EcmaScript Harmony maps
+class JSSet: public JSObject {
+ public:
+ // [set]: the backing hash set containing keys.
+ DECL_ACCESSORS(table, Object)
+
+ // Casting.
+ static inline JSSet* cast(Object* obj);
+
+#ifdef OBJECT_PRINT
+ inline void JSSetPrint() {
+ JSSetPrint(stdout);
+ }
+ void JSSetPrint(FILE* out);
+#endif
+#ifdef DEBUG
+ void JSSetVerify();
+#endif
+
+ static const int kTableOffset = JSObject::kHeaderSize;
+ static const int kSize = kTableOffset + kPointerSize;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSSet);
+};
+
+
+// The JSMap describes EcmaScript Harmony maps
+class JSMap: public JSObject {
+ public:
+ // [table]: the backing hash table mapping keys to values.
+ DECL_ACCESSORS(table, Object)
+
+ // Casting.
+ static inline JSMap* cast(Object* obj);
+
+#ifdef OBJECT_PRINT
+ inline void JSMapPrint() {
+ JSMapPrint(stdout);
+ }
+ void JSMapPrint(FILE* out);
+#endif
+#ifdef DEBUG
+ void JSMapVerify();
+#endif
+
+ static const int kTableOffset = JSObject::kHeaderSize;
+ static const int kSize = kTableOffset + kPointerSize;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSMap);
+};
+
+
// The JSWeakMap describes EcmaScript Harmony weak maps
class JSWeakMap: public JSObject {
public:
diff --git a/deps/v8/src/parser.cc b/deps/v8/src/parser.cc
index fb94a1a60b..3c6c4ba1e2 100644
--- a/deps/v8/src/parser.cc
+++ b/deps/v8/src/parser.cc
@@ -407,9 +407,9 @@ unsigned* ScriptDataImpl::ReadAddress(int position) {
}
-Scope* Parser::NewScope(Scope* parent, Scope::Type type, bool inside_with) {
+Scope* Parser::NewScope(Scope* parent, ScopeType type) {
Scope* result = new(zone()) Scope(parent, type);
- result->Initialize(inside_with);
+ result->Initialize();
return result;
}
@@ -459,13 +459,31 @@ class TargetScope BASE_EMBEDDED {
// ----------------------------------------------------------------------------
-// LexicalScope is a support class to facilitate manipulation of the
-// Parser's scope stack. The constructor sets the parser's top scope
-// to the incoming scope, and the destructor resets it.
-//
-// Additionally, it stores transient information used during parsing.
-// These scopes are not kept around after parsing or referenced by syntax
-// trees so they can be stack-allocated and hence used by the pre-parser.
+// LexicalScope and SaveScope are stack allocated support classes to facilitate
+// anipulation of the Parser's scope stack. The constructor sets the parser's
+// top scope to the incoming scope, and the destructor resets it. Additionally,
+// LexicalScope stores transient information used during parsing.
+
+
+class SaveScope BASE_EMBEDDED {
+ public:
+ SaveScope(Parser* parser, Scope* scope)
+ : parser_(parser),
+ previous_top_scope_(parser->top_scope_) {
+ parser->top_scope_ = scope;
+ }
+
+ ~SaveScope() {
+ parser_->top_scope_ = previous_top_scope_;
+ }
+
+ private:
+ // Bookkeeping
+ Parser* parser_;
+ // Previous values
+ Scope* previous_top_scope_;
+};
+
class LexicalScope BASE_EMBEDDED {
public:
@@ -516,7 +534,6 @@ class LexicalScope BASE_EMBEDDED {
// Previous values
LexicalScope* lexical_scope_parent_;
Scope* previous_scope_;
- int previous_with_nesting_level_;
unsigned previous_ast_node_id_;
};
@@ -529,11 +546,9 @@ LexicalScope::LexicalScope(Parser* parser, Scope* scope, Isolate* isolate)
parser_(parser),
lexical_scope_parent_(parser->lexical_scope_),
previous_scope_(parser->top_scope_),
- previous_with_nesting_level_(parser->with_nesting_level_),
previous_ast_node_id_(isolate->ast_node_id()) {
parser->top_scope_ = scope;
parser->lexical_scope_ = this;
- parser->with_nesting_level_ = 0;
isolate->set_ast_node_id(AstNode::kDeclarationsId + 1);
}
@@ -541,7 +556,6 @@ LexicalScope::LexicalScope(Parser* parser, Scope* scope, Isolate* isolate)
LexicalScope::~LexicalScope() {
parser_->top_scope_ = previous_scope_;
parser_->lexical_scope_ = lexical_scope_parent_;
- parser_->with_nesting_level_ = previous_with_nesting_level_;
parser_->isolate()->set_ast_node_id(previous_ast_node_id_);
}
@@ -578,7 +592,6 @@ Parser::Parser(Handle<Script> script,
script_(script),
scanner_(isolate_->unicode_cache()),
top_scope_(NULL),
- with_nesting_level_(0),
lexical_scope_(NULL),
target_stack_(NULL),
allow_natives_syntax_(allow_natives_syntax),
@@ -623,6 +636,7 @@ FunctionLiteral* Parser::DoParseProgram(Handle<String> source,
bool in_global_context,
StrictModeFlag strict_mode,
ZoneScope* zone_scope) {
+ ASSERT(top_scope_ == NULL);
ASSERT(target_stack_ == NULL);
if (pre_data_ != NULL) pre_data_->Initialize();
@@ -630,18 +644,16 @@ FunctionLiteral* Parser::DoParseProgram(Handle<String> source,
mode_ = FLAG_lazy ? PARSE_LAZILY : PARSE_EAGERLY;
if (allow_natives_syntax_ || extension_ != NULL) mode_ = PARSE_EAGERLY;
- Scope::Type type =
- in_global_context
- ? Scope::GLOBAL_SCOPE
- : Scope::EVAL_SCOPE;
+ ScopeType type = in_global_context ? GLOBAL_SCOPE : EVAL_SCOPE;
Handle<String> no_name = isolate()->factory()->empty_symbol();
FunctionLiteral* result = NULL;
- { Scope* scope = NewScope(top_scope_, type, inside_with());
+ { Scope* scope = NewScope(top_scope_, type);
+ scope->set_start_position(0);
+ scope->set_end_position(source->length());
LexicalScope lexical_scope(this, scope, isolate());
- if (strict_mode == kStrictMode) {
- top_scope_->EnableStrictMode();
- }
+ ASSERT(top_scope_->strict_mode_flag() == kNonStrictMode);
+ top_scope_->SetStrictModeFlag(strict_mode);
ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16);
bool ok = true;
int beg_loc = scanner().location().beg_pos;
@@ -665,8 +677,6 @@ FunctionLiteral* Parser::DoParseProgram(Handle<String> source,
lexical_scope.only_simple_this_property_assignments(),
lexical_scope.this_property_assignments(),
0,
- 0,
- source->length(),
FunctionLiteral::ANONYMOUS_EXPRESSION,
false); // Does not have duplicate parameters.
} else if (stack_overflow_) {
@@ -714,6 +724,7 @@ FunctionLiteral* Parser::ParseLazy(CompilationInfo* info,
ZoneScope* zone_scope) {
Handle<SharedFunctionInfo> shared_info = info->shared_info();
scanner_.Initialize(source);
+ ASSERT(top_scope_ == NULL);
ASSERT(target_stack_ == NULL);
Handle<String> name(String::cast(shared_info->name()));
@@ -727,16 +738,15 @@ FunctionLiteral* Parser::ParseLazy(CompilationInfo* info,
{
// Parse the function literal.
- Scope* scope = NewScope(top_scope_, Scope::GLOBAL_SCOPE, inside_with());
+ Scope* scope = NewScope(top_scope_, GLOBAL_SCOPE);
if (!info->closure().is_null()) {
scope = Scope::DeserializeScopeChain(info, scope);
}
LexicalScope lexical_scope(this, scope, isolate());
-
- if (shared_info->strict_mode()) {
- top_scope_->EnableStrictMode();
- }
-
+ ASSERT(scope->strict_mode_flag() == kNonStrictMode ||
+ scope->strict_mode_flag() == info->strict_mode_flag());
+ ASSERT(info->strict_mode_flag() == shared_info->strict_mode_flag());
+ scope->SetStrictModeFlag(shared_info->strict_mode_flag());
FunctionLiteral::Type type = shared_info->is_expression()
? (shared_info->is_anonymous()
? FunctionLiteral::ANONYMOUS_EXPRESSION
@@ -1128,14 +1138,14 @@ Statement* Parser::ParseSourceElement(ZoneStringList* labels,
// In harmony mode we allow additionally the following productions
// SourceElement:
// LetDeclaration
+ // ConstDeclaration
if (peek() == Token::FUNCTION) {
return ParseFunctionDeclaration(ok);
- } else if (peek() == Token::LET) {
+ } else if (peek() == Token::LET || peek() == Token::CONST) {
return ParseVariableStatement(kSourceElement, ok);
- } else {
- return ParseStatement(labels, ok);
}
+ return ParseStatement(labels, ok);
}
@@ -1183,7 +1193,7 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
directive->Equals(isolate()->heap()->use_strict()) &&
token_loc.end_pos - token_loc.beg_pos ==
isolate()->heap()->use_strict()->length() + 2) {
- top_scope_->EnableStrictMode();
+ top_scope_->SetStrictModeFlag(kStrictMode);
// "use strict" is the only directive for now.
directive_prologue = false;
}
@@ -1321,7 +1331,7 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) {
// FunctionDeclaration
// Common language extension is to allow function declaration in place
// of any statement. This language extension is disabled in strict mode.
- if (top_scope_->is_strict_mode()) {
+ if (top_scope_->is_strict_mode() || harmony_scoping_) {
ReportMessageAt(scanner().peek_location(), "strict_function",
Vector<const char*>::empty());
*ok = false;
@@ -1353,6 +1363,10 @@ VariableProxy* Parser::Declare(Handle<String> name,
// If we are inside a function, a declaration of a var/const variable is a
// truly local variable, and the scope of the variable is always the function
// scope.
+ // Let/const variables in harmony mode are always added to the immediately
+ // enclosing scope.
+ Scope* declaration_scope = (mode == LET || mode == CONST_HARMONY)
+ ? top_scope_ : top_scope_->DeclarationScope();
// If a function scope exists, then we can statically declare this
// variable and also set its mode. In any case, a Declaration node
@@ -1362,9 +1376,8 @@ VariableProxy* Parser::Declare(Handle<String> name,
// to the calling function context.
// Similarly, strict mode eval scope does not leak variable declarations to
// the caller's scope so we declare all locals, too.
-
- Scope* declaration_scope = mode == LET ? top_scope_
- : top_scope_->DeclarationScope();
+ // Also for block scoped let/const bindings the variable can be
+ // statically declared.
if (declaration_scope->is_function_scope() ||
declaration_scope->is_strict_mode_eval_scope() ||
declaration_scope->is_block_scope()) {
@@ -1389,6 +1402,7 @@ VariableProxy* Parser::Declare(Handle<String> name,
// We only have vars, consts and lets in declarations.
ASSERT(var->mode() == VAR ||
var->mode() == CONST ||
+ var->mode() == CONST_HARMONY ||
var->mode() == LET);
if (harmony_scoping_) {
// In harmony mode we treat re-declarations as early errors. See
@@ -1400,8 +1414,8 @@ VariableProxy* Parser::Declare(Handle<String> name,
*ok = false;
return NULL;
}
- const char* type = (var->mode() == VAR) ? "var" :
- (var->mode() == CONST) ? "const" : "let";
+ const char* type = (var->mode() == VAR)
+ ? "var" : var->is_const_mode() ? "const" : "let";
Handle<String> type_string =
isolate()->factory()->NewStringFromUtf8(CStrVector(type), TENURED);
Expression* expression =
@@ -1429,12 +1443,13 @@ VariableProxy* Parser::Declare(Handle<String> name,
// a performance issue since it may lead to repeated
// Runtime::DeclareContextSlot() calls.
VariableProxy* proxy = declaration_scope->NewUnresolved(
- name, false, scanner().location().beg_pos);
+ name, scanner().location().beg_pos);
declaration_scope->AddDeclaration(
new(zone()) Declaration(proxy, mode, fun, top_scope_));
// For global const variables we bind the proxy to a variable.
- if (mode == CONST && declaration_scope->is_global_scope()) {
+ if ((mode == CONST || mode == CONST_HARMONY) &&
+ declaration_scope->is_global_scope()) {
ASSERT(resolve); // should be set by all callers
Variable::Kind kind = Variable::NORMAL;
var = new(zone()) Variable(declaration_scope, name, CONST, true, kind);
@@ -1582,20 +1597,14 @@ Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) {
// Construct block expecting 16 statements.
Block* body = new(zone()) Block(isolate(), labels, 16, false);
- Scope* saved_scope = top_scope_;
- Scope* block_scope = NewScope(top_scope_,
- Scope::BLOCK_SCOPE,
- inside_with());
- if (top_scope_->is_strict_mode()) {
- block_scope->EnableStrictMode();
- }
- top_scope_ = block_scope;
+ Scope* block_scope = NewScope(top_scope_, BLOCK_SCOPE);
// Parse the statements and collect escaping labels.
- TargetCollector collector;
- Target target(&this->target_stack_, &collector);
Expect(Token::LBRACE, CHECK_OK);
- {
+ block_scope->set_start_position(scanner().location().beg_pos);
+ { SaveScope save_scope(this, block_scope);
+ TargetCollector collector;
+ Target target(&this->target_stack_, &collector);
Target target_body(&this->target_stack_, body);
InitializationBlockFinder block_finder(top_scope_, target_stack_);
@@ -1608,8 +1617,7 @@ Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) {
}
}
Expect(Token::RBRACE, CHECK_OK);
- top_scope_ = saved_scope;
-
+ block_scope->set_end_position(scanner().location().end_pos);
block_scope = block_scope->FinalizeBlockScope();
body->set_block_scope(block_scope);
return body;
@@ -1623,6 +1631,7 @@ Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context,
Handle<String> ignore;
Block* result = ParseVariableDeclarations(var_context,
+ NULL,
&ignore,
CHECK_OK);
ExpectSemicolon(CHECK_OK);
@@ -1641,12 +1650,24 @@ bool Parser::IsEvalOrArguments(Handle<String> string) {
// *var is untouched; in particular, it is the caller's responsibility
// to initialize it properly. This mechanism is used for the parsing
// of 'for-in' loops.
-Block* Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
- Handle<String>* out,
- bool* ok) {
+Block* Parser::ParseVariableDeclarations(
+ VariableDeclarationContext var_context,
+ VariableDeclarationProperties* decl_props,
+ Handle<String>* out,
+ bool* ok) {
// VariableDeclarations ::
- // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[',']
-
+ // ('var' | 'const' | 'let') (Identifier ('=' AssignmentExpression)?)+[',']
+ //
+ // The ES6 Draft Rev3 specifies the following grammar for const declarations
+ //
+ // ConstDeclaration ::
+ // const ConstBinding (',' ConstBinding)* ';'
+ // ConstBinding ::
+ // Identifier '=' AssignmentExpression
+ //
+ // TODO(ES6):
+ // ConstBinding ::
+ // BindingPattern '=' AssignmentExpression
VariableMode mode = VAR;
// True if the binding needs initialization. 'let' and 'const' declared
// bindings are created uninitialized by their declaration nodes and
@@ -1659,19 +1680,32 @@ Block* Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
Consume(Token::VAR);
} else if (peek() == Token::CONST) {
Consume(Token::CONST);
- if (top_scope_->is_strict_mode()) {
+ if (harmony_scoping_) {
+ if (var_context != kSourceElement &&
+ var_context != kForStatement) {
+ // In harmony mode 'const' declarations are only allowed in source
+ // element positions.
+ ReportMessage("unprotected_const", Vector<const char*>::empty());
+ *ok = false;
+ return NULL;
+ }
+ mode = CONST_HARMONY;
+ init_op = Token::INIT_CONST_HARMONY;
+ } else if (top_scope_->is_strict_mode()) {
ReportMessage("strict_const", Vector<const char*>::empty());
*ok = false;
return NULL;
+ } else {
+ mode = CONST;
+ init_op = Token::INIT_CONST;
}
- mode = CONST;
is_const = true;
needs_init = true;
- init_op = Token::INIT_CONST;
} else if (peek() == Token::LET) {
Consume(Token::LET);
if (var_context != kSourceElement &&
var_context != kForStatement) {
+ // Let declarations are only allowed in source element positions.
ASSERT(var_context == kStatement);
ReportMessage("unprotected_let", Vector<const char*>::empty());
*ok = false;
@@ -1684,7 +1718,7 @@ Block* Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
UNREACHABLE(); // by current callers
}
- Scope* declaration_scope = (mode == LET)
+ Scope* declaration_scope = (mode == LET || mode == CONST_HARMONY)
? top_scope_ : top_scope_->DeclarationScope();
// The scope of a var/const declared variable anywhere inside a function
// is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). Thus we can
@@ -1729,8 +1763,10 @@ Block* Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
// If we have a const declaration, in an inner scope, the proxy is always
// bound to the declared variable (independent of possibly surrounding with
// statements).
- Declare(name, mode, NULL, is_const /* always bound for CONST! */,
- CHECK_OK);
+ // For let/const declarations in harmony mode, we can also immediately
+ // pre-resolve the proxy because it resides in the same scope as the
+ // declaration.
+ Declare(name, mode, NULL, mode != VAR, CHECK_OK);
nvars++;
if (declaration_scope->num_var_or_const() > kMaxNumFunctionLocals) {
ReportMessageAt(scanner().location(), "too_many_variables",
@@ -1769,7 +1805,8 @@ Block* Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
Scope* initialization_scope = is_const ? declaration_scope : top_scope_;
Expression* value = NULL;
int position = -1;
- if (peek() == Token::ASSIGN) {
+ // Harmony consts have non-optional initializers.
+ if (peek() == Token::ASSIGN || mode == CONST_HARMONY) {
Expect(Token::ASSIGN, CHECK_OK);
position = scanner().location().beg_pos;
value = ParseAssignmentExpression(var_context != kForStatement, CHECK_OK);
@@ -1781,6 +1818,7 @@ Block* Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
} else {
fni_->RemoveLastFunction();
}
+ if (decl_props != NULL) *decl_props = kHasInitializers;
}
// Make sure that 'const x' and 'let x' initialize 'x' to undefined.
@@ -1807,7 +1845,6 @@ Block* Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
// declaration statement has been executed. This is important in
// browsers where the global object (window) has lots of
// properties defined in prototype objects.
-
if (initialization_scope->is_global_scope()) {
// Compute the arguments for the runtime call.
ZoneList<Expression*>* arguments = new(zone()) ZoneList<Expression*>(3);
@@ -1832,9 +1869,7 @@ Block* Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
} else {
// Add strict mode.
// We may want to pass singleton to avoid Literal allocations.
- StrictModeFlag flag = initialization_scope->is_strict_mode()
- ? kStrictMode
- : kNonStrictMode;
+ StrictModeFlag flag = initialization_scope->strict_mode_flag();
arguments->Add(NewNumberLiteral(flag));
// Be careful not to assign a value to the global variable if
@@ -1871,18 +1906,14 @@ Block* Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
// dynamically looked-up variables and constants (the start context
// for constant lookups is always the function context, while it is
// the top context for var declared variables). Sigh...
- // For 'let' declared variables the initialization is in the same scope
- // as the declaration. Thus dynamic lookups are unnecessary even if the
- // block scope is inside a with.
+ // For 'let' and 'const' declared variables in harmony mode the
+ // initialization is in the same scope as the declaration. Thus dynamic
+ // lookups are unnecessary even if the block scope is inside a with.
if (value != NULL) {
- bool in_with = (mode == VAR) ? inside_with() : false;
- VariableProxy* proxy =
- initialization_scope->NewUnresolved(name, in_with);
+ VariableProxy* proxy = initialization_scope->NewUnresolved(name);
Assignment* assignment =
new(zone()) Assignment(isolate(), init_op, proxy, value, position);
- if (block) {
- block->AddStatement(new(zone()) ExpressionStatement(assignment));
- }
+ block->AddStatement(new(zone()) ExpressionStatement(assignment));
}
if (fni_ != NULL) fni_->Leave();
@@ -2105,10 +2136,14 @@ Statement* Parser::ParseWithStatement(ZoneStringList* labels, bool* ok) {
Expression* expr = ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
- ++with_nesting_level_;
top_scope_->DeclarationScope()->RecordWithStatement();
- Statement* stmt = ParseStatement(labels, CHECK_OK);
- --with_nesting_level_;
+ Scope* with_scope = NewScope(top_scope_, WITH_SCOPE);
+ Statement* stmt;
+ { SaveScope save_scope(this, with_scope);
+ with_scope->set_start_position(scanner().peek_location().beg_pos);
+ stmt = ParseStatement(labels, CHECK_OK);
+ with_scope->set_end_position(scanner().location().end_pos);
+ }
return new(zone()) WithStatement(expr, stmt);
}
@@ -2233,6 +2268,8 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
Consume(Token::CATCH);
Expect(Token::LPAREN, CHECK_OK);
+ catch_scope = NewScope(top_scope_, CATCH_SCOPE);
+ catch_scope->set_start_position(scanner().location().beg_pos);
name = ParseIdentifier(CHECK_OK);
if (top_scope_->is_strict_mode() && IsEvalOrArguments(name)) {
@@ -2245,21 +2282,15 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
if (peek() == Token::LBRACE) {
Target target(&this->target_stack_, &catch_collector);
- catch_scope = NewScope(top_scope_, Scope::CATCH_SCOPE, inside_with());
- if (top_scope_->is_strict_mode()) {
- catch_scope->EnableStrictMode();
- }
VariableMode mode = harmony_scoping_ ? LET : VAR;
catch_variable = catch_scope->DeclareLocal(name, mode);
- Scope* saved_scope = top_scope_;
- top_scope_ = catch_scope;
+ SaveScope save_scope(this, catch_scope);
catch_block = ParseBlock(NULL, CHECK_OK);
- top_scope_ = saved_scope;
} else {
Expect(Token::LBRACE, CHECK_OK);
}
-
+ catch_scope->set_end_position(scanner().location().end_pos);
tok = peek();
}
@@ -2365,16 +2396,22 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
Statement* init = NULL;
+ // Create an in-between scope for let-bound iteration variables.
+ Scope* saved_scope = top_scope_;
+ Scope* for_scope = NewScope(top_scope_, BLOCK_SCOPE);
+ top_scope_ = for_scope;
+
Expect(Token::FOR, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK);
+ for_scope->set_start_position(scanner().location().beg_pos);
if (peek() != Token::SEMICOLON) {
if (peek() == Token::VAR || peek() == Token::CONST) {
Handle<String> name;
Block* variable_statement =
- ParseVariableDeclarations(kForStatement, &name, CHECK_OK);
+ ParseVariableDeclarations(kForStatement, NULL, &name, CHECK_OK);
if (peek() == Token::IN && !name.is_null()) {
- VariableProxy* each = top_scope_->NewUnresolved(name, inside_with());
+ VariableProxy* each = top_scope_->NewUnresolved(name);
ForInStatement* loop = new(zone()) ForInStatement(isolate(), labels);
Target target(&this->target_stack_, loop);
@@ -2387,12 +2424,73 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
Block* result = new(zone()) Block(isolate(), NULL, 2, false);
result->AddStatement(variable_statement);
result->AddStatement(loop);
+ top_scope_ = saved_scope;
+ for_scope->set_end_position(scanner().location().end_pos);
+ for_scope = for_scope->FinalizeBlockScope();
+ ASSERT(for_scope == NULL);
// Parsed for-in loop w/ variable/const declaration.
return result;
} else {
init = variable_statement;
}
+ } else if (peek() == Token::LET) {
+ Handle<String> name;
+ VariableDeclarationProperties decl_props = kHasNoInitializers;
+ Block* variable_statement =
+ ParseVariableDeclarations(kForStatement,
+ &decl_props,
+ &name,
+ CHECK_OK);
+ bool accept_IN = !name.is_null() && decl_props != kHasInitializers;
+ if (peek() == Token::IN && accept_IN) {
+ // Rewrite a for-in statement of the form
+ //
+ // for (let x in e) b
+ //
+ // into
+ //
+ // <let x' be a temporary variable>
+ // for (x' in e) {
+ // let x;
+ // x = x';
+ // b;
+ // }
+
+ // TODO(keuchel): Move the temporary variable to the block scope, after
+ // implementing stack allocated block scoped variables.
+ Variable* temp = top_scope_->DeclarationScope()->NewTemporary(name);
+ VariableProxy* temp_proxy = new(zone()) VariableProxy(isolate(), temp);
+ VariableProxy* each = top_scope_->NewUnresolved(name, inside_with());
+ ForInStatement* loop = new(zone()) ForInStatement(isolate(), labels);
+ Target target(&this->target_stack_, loop);
+
+ Expect(Token::IN, CHECK_OK);
+ Expression* enumerable = ParseExpression(true, CHECK_OK);
+ Expect(Token::RPAREN, CHECK_OK);
+ Statement* body = ParseStatement(NULL, CHECK_OK);
+ Block* body_block = new(zone()) Block(isolate(), NULL, 3, false);
+ Assignment* assignment = new(zone()) Assignment(isolate(),
+ Token::ASSIGN,
+ each,
+ temp_proxy,
+ RelocInfo::kNoPosition);
+ Statement* assignment_statement =
+ new(zone()) ExpressionStatement(assignment);
+ body_block->AddStatement(variable_statement);
+ body_block->AddStatement(assignment_statement);
+ body_block->AddStatement(body);
+ loop->Initialize(temp_proxy, enumerable, body_block);
+ top_scope_ = saved_scope;
+ for_scope->set_end_position(scanner().location().end_pos);
+ for_scope = for_scope->FinalizeBlockScope();
+ body_block->set_block_scope(for_scope);
+ // Parsed for-in loop w/ let declaration.
+ return loop;
+
+ } else {
+ init = variable_statement;
+ }
} else {
Expression* expression = ParseExpression(false, CHECK_OK);
if (peek() == Token::IN) {
@@ -2414,6 +2512,10 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
Statement* body = ParseStatement(NULL, CHECK_OK);
if (loop) loop->Initialize(expression, enumerable, body);
+ top_scope_ = saved_scope;
+ for_scope->set_end_position(scanner().location().end_pos);
+ for_scope = for_scope->FinalizeBlockScope();
+ ASSERT(for_scope == NULL);
// Parsed for-in loop.
return loop;
@@ -2444,8 +2546,31 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
Expect(Token::RPAREN, CHECK_OK);
Statement* body = ParseStatement(NULL, CHECK_OK);
- if (loop) loop->Initialize(init, cond, next, body);
- return loop;
+ top_scope_ = saved_scope;
+ for_scope->set_end_position(scanner().location().end_pos);
+ for_scope = for_scope->FinalizeBlockScope();
+ if (for_scope != NULL) {
+ // Rewrite a for statement of the form
+ //
+ // for (let x = i; c; n) b
+ //
+ // into
+ //
+ // {
+ // let x = i;
+ // for (; c; n) b
+ // }
+ ASSERT(init != NULL);
+ Block* result = new(zone()) Block(isolate(), NULL, 2, false);
+ result->AddStatement(init);
+ result->AddStatement(loop);
+ result->set_block_scope(for_scope);
+ if (loop) loop->Initialize(NULL, cond, next, body);
+ return result;
+ } else {
+ if (loop) loop->Initialize(init, cond, next, body);
+ return loop;
+ }
}
@@ -3065,9 +3190,7 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) {
case Token::FUTURE_STRICT_RESERVED_WORD: {
Handle<String> name = ParseIdentifier(CHECK_OK);
if (fni_ != NULL) fni_->PushVariableName(name);
- result = top_scope_->NewUnresolved(name,
- inside_with(),
- scanner().location().beg_pos);
+ result = top_scope_->NewUnresolved(name, scanner().location().beg_pos);
break;
}
@@ -3184,9 +3307,11 @@ Expression* Parser::ParseArrayLiteral(bool* ok) {
// Update the scope information before the pre-parsing bailout.
int literal_index = lexical_scope_->NextMaterializedLiteralIndex();
- // Allocate a fixed array with all the literals.
- Handle<FixedArray> literals =
+ // Allocate a fixed array to hold all the object literals.
+ Handle<FixedArray> object_literals =
isolate()->factory()->NewFixedArray(values->length(), TENURED);
+ Handle<FixedDoubleArray> double_literals;
+ ElementsKind elements_kind = FAST_SMI_ONLY_ELEMENTS;
// Fill in the literals.
bool is_simple = true;
@@ -3198,19 +3323,75 @@ Expression* Parser::ParseArrayLiteral(bool* ok) {
}
Handle<Object> boilerplate_value = GetBoilerplateValue(values->at(i));
if (boilerplate_value->IsUndefined()) {
- literals->set_the_hole(i);
+ object_literals->set_the_hole(i);
+ if (elements_kind == FAST_DOUBLE_ELEMENTS) {
+ double_literals->set_the_hole(i);
+ }
is_simple = false;
} else {
- literals->set(i, *boilerplate_value);
+ // Examine each literal element, and adjust the ElementsKind if the
+ // literal element is not of a type that can be stored in the current
+ // ElementsKind. Start with FAST_SMI_ONLY_ELEMENTS, and transition to
+ // FAST_DOUBLE_ELEMENTS and FAST_ELEMENTS as necessary. Always remember
+ // the tagged value, no matter what the ElementsKind is in case we
+ // ultimately end up in FAST_ELEMENTS.
+ object_literals->set(i, *boilerplate_value);
+ if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
+ // Smi only elements. Notice if a transition to FAST_DOUBLE_ELEMENTS or
+ // FAST_ELEMENTS is required.
+ if (!boilerplate_value->IsSmi()) {
+ if (boilerplate_value->IsNumber() && FLAG_smi_only_arrays) {
+ // Allocate a double array on the FAST_DOUBLE_ELEMENTS transition to
+ // avoid over-allocating in TENURED space.
+ double_literals = isolate()->factory()->NewFixedDoubleArray(
+ values->length(), TENURED);
+ // Copy the contents of the FAST_SMI_ONLY_ELEMENT array to the
+ // FAST_DOUBLE_ELEMENTS array so that they are in sync.
+ for (int j = 0; j < i; ++j) {
+ Object* smi_value = object_literals->get(j);
+ if (smi_value->IsTheHole()) {
+ double_literals->set_the_hole(j);
+ } else {
+ double_literals->set(j, Smi::cast(smi_value)->value());
+ }
+ }
+ double_literals->set(i, boilerplate_value->Number());
+ elements_kind = FAST_DOUBLE_ELEMENTS;
+ } else {
+ elements_kind = FAST_ELEMENTS;
+ }
+ }
+ } else if (elements_kind == FAST_DOUBLE_ELEMENTS) {
+ // Continue to store double values in to FAST_DOUBLE_ELEMENTS arrays
+ // until the first value is seen that can't be stored as a double.
+ if (boilerplate_value->IsNumber()) {
+ double_literals->set(i, boilerplate_value->Number());
+ } else {
+ elements_kind = FAST_ELEMENTS;
+ }
+ }
}
}
// Simple and shallow arrays can be lazily copied, we transform the
// elements array to a copy-on-write array.
- if (is_simple && depth == 1 && values->length() > 0) {
- literals->set_map(isolate()->heap()->fixed_cow_array_map());
+ if (is_simple && depth == 1 && values->length() > 0 &&
+ elements_kind != FAST_DOUBLE_ELEMENTS) {
+ object_literals->set_map(isolate()->heap()->fixed_cow_array_map());
}
+ Handle<FixedArrayBase> element_values = elements_kind == FAST_DOUBLE_ELEMENTS
+ ? Handle<FixedArrayBase>(double_literals)
+ : Handle<FixedArrayBase>(object_literals);
+
+ // Remember both the literal's constant values as well as the ElementsKind
+ // in a 2-element FixedArray.
+ Handle<FixedArray> literals =
+ isolate()->factory()->NewFixedArray(2, TENURED);
+
+ literals->set(0, Smi::FromInt(elements_kind));
+ literals->set(1, *element_values);
+
return new(zone()) ArrayLiteral(
isolate(), literals, values, literal_index, is_simple, depth);
}
@@ -3715,13 +3896,11 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
// hoisted. In harmony block scoping mode they are block scoped, so they
// are not hoisted.
Scope* scope = (type == FunctionLiteral::DECLARATION && !harmony_scoping_)
- ? NewScope(top_scope_->DeclarationScope(), Scope::FUNCTION_SCOPE, false)
- : NewScope(top_scope_, Scope::FUNCTION_SCOPE, inside_with());
+ ? NewScope(top_scope_->DeclarationScope(), FUNCTION_SCOPE)
+ : NewScope(top_scope_, FUNCTION_SCOPE);
ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(8);
int materialized_literal_count;
int expected_property_count;
- int start_pos;
- int end_pos;
bool only_simple_this_property_assignments;
Handle<FixedArray> this_property_assignments;
bool has_duplicate_parameters = false;
@@ -3732,7 +3911,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
// FormalParameterList ::
// '(' (Identifier)*[','] ')'
Expect(Token::LPAREN, CHECK_OK);
- start_pos = scanner().location().beg_pos;
+ scope->set_start_position(scanner().location().beg_pos);
Scanner::Location name_loc = Scanner::Location::invalid();
Scanner::Location dupe_loc = Scanner::Location::invalid();
Scanner::Location reserved_loc = Scanner::Location::invalid();
@@ -3778,13 +3957,21 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
// future we can change the AST to only refer to VariableProxies
// instead of Variables and Proxis as is the case now.
if (type == FunctionLiteral::NAMED_EXPRESSION) {
- Variable* fvar = top_scope_->DeclareFunctionVar(function_name);
- VariableProxy* fproxy =
- top_scope_->NewUnresolved(function_name, inside_with());
+ VariableMode fvar_mode;
+ Token::Value fvar_init_op;
+ if (harmony_scoping_) {
+ fvar_mode = CONST_HARMONY;
+ fvar_init_op = Token::INIT_CONST_HARMONY;
+ } else {
+ fvar_mode = CONST;
+ fvar_init_op = Token::INIT_CONST;
+ }
+ Variable* fvar = top_scope_->DeclareFunctionVar(function_name, fvar_mode);
+ VariableProxy* fproxy = top_scope_->NewUnresolved(function_name);
fproxy->BindTo(fvar);
body->Add(new(zone()) ExpressionStatement(
new(zone()) Assignment(isolate(),
- Token::INIT_CONST,
+ fvar_init_op,
fproxy,
new(zone()) ThisFunction(isolate()),
RelocInfo::kNoPosition)));
@@ -3808,18 +3995,18 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
// compile after all.
is_lazily_compiled = false;
} else {
- end_pos = entry.end_pos();
- if (end_pos <= function_block_pos) {
+ scope->set_end_position(entry.end_pos());
+ if (scope->end_position() <= function_block_pos) {
// End position greater than end of stream is safe, and hard to check.
ReportInvalidPreparseData(function_name, CHECK_OK);
}
isolate()->counters()->total_preparse_skipped()->Increment(
- end_pos - function_block_pos);
+ scope->end_position() - function_block_pos);
// Seek to position just before terminal '}'.
- scanner().SeekForward(end_pos - 1);
+ scanner().SeekForward(scope->end_position() - 1);
materialized_literal_count = entry.literal_count();
expected_property_count = entry.property_count();
- if (entry.strict_mode()) top_scope_->EnableStrictMode();
+ if (entry.strict_mode()) top_scope_->SetStrictModeFlag(kStrictMode);
only_simple_this_property_assignments = false;
this_property_assignments = isolate()->factory()->empty_fixed_array();
Expect(Token::RBRACE, CHECK_OK);
@@ -3836,12 +4023,13 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
this_property_assignments = lexical_scope.this_property_assignments();
Expect(Token::RBRACE, CHECK_OK);
- end_pos = scanner().location().end_pos;
+ scope->set_end_position(scanner().location().end_pos);
}
// Validate strict mode.
if (top_scope_->is_strict_mode()) {
if (IsEvalOrArguments(function_name)) {
+ int start_pos = scope->start_position();
int position = function_token_position != RelocInfo::kNoPosition
? function_token_position
: (start_pos > 0 ? start_pos - 1 : start_pos);
@@ -3864,6 +4052,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
return NULL;
}
if (name_is_strict_reserved) {
+ int start_pos = scope->start_position();
int position = function_token_position != RelocInfo::kNoPosition
? function_token_position
: (start_pos > 0 ? start_pos - 1 : start_pos);
@@ -3879,7 +4068,9 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
*ok = false;
return NULL;
}
- CheckOctalLiteral(start_pos, end_pos, CHECK_OK);
+ CheckOctalLiteral(scope->start_position(),
+ scope->end_position(),
+ CHECK_OK);
}
}
@@ -3897,8 +4088,6 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
only_simple_this_property_assignments,
this_property_assignments,
num_parameters,
- start_pos,
- end_pos,
type,
has_duplicate_parameters);
function_literal->set_function_token_position(function_token_position);
@@ -5119,17 +5308,16 @@ int ScriptDataImpl::ReadNumber(byte** source) {
// Create a Scanner for the preparser to use as input, and preparse the source.
static ScriptDataImpl* DoPreParse(UC16CharacterStream* source,
- bool allow_lazy,
- ParserRecorder* recorder,
- bool harmony_scoping) {
+ int flags,
+ ParserRecorder* recorder) {
Isolate* isolate = Isolate::Current();
JavaScriptScanner scanner(isolate->unicode_cache());
- scanner.SetHarmonyScoping(harmony_scoping);
+ scanner.SetHarmonyScoping((flags & kHarmonyScoping) != 0);
scanner.Initialize(source);
intptr_t stack_limit = isolate->stack_guard()->real_climit();
if (!preparser::PreParser::PreParseProgram(&scanner,
recorder,
- allow_lazy,
+ flags,
stack_limit)) {
isolate->StackOverflow();
return NULL;
@@ -5146,25 +5334,28 @@ static ScriptDataImpl* DoPreParse(UC16CharacterStream* source,
// even if the preparser data is only used once.
ScriptDataImpl* ParserApi::PartialPreParse(UC16CharacterStream* source,
v8::Extension* extension,
- bool harmony_scoping) {
+ int flags) {
bool allow_lazy = FLAG_lazy && (extension == NULL);
if (!allow_lazy) {
// Partial preparsing is only about lazily compiled functions.
// If we don't allow lazy compilation, the log data will be empty.
return NULL;
}
+ flags |= kAllowLazy;
PartialParserRecorder recorder;
- return DoPreParse(source, allow_lazy, &recorder, harmony_scoping);
+ return DoPreParse(source, flags, &recorder);
}
ScriptDataImpl* ParserApi::PreParse(UC16CharacterStream* source,
v8::Extension* extension,
- bool harmony_scoping) {
+ int flags) {
Handle<Script> no_script;
- bool allow_lazy = FLAG_lazy && (extension == NULL);
+ if (FLAG_lazy && (extension == NULL)) {
+ flags |= kAllowLazy;
+ }
CompleteParserRecorder recorder;
- return DoPreParse(source, allow_lazy, &recorder, harmony_scoping);
+ return DoPreParse(source, flags, &recorder);
}
@@ -5196,13 +5387,16 @@ bool ParserApi::Parse(CompilationInfo* info) {
Handle<Script> script = info->script();
bool harmony_scoping = !info->is_native() && FLAG_harmony_scoping;
if (info->is_lazy()) {
- Parser parser(script, true, NULL, NULL);
+ bool allow_natives_syntax =
+ FLAG_allow_natives_syntax ||
+ info->is_native();
+ Parser parser(script, allow_natives_syntax, NULL, NULL);
parser.SetHarmonyScoping(harmony_scoping);
result = parser.ParseLazy(info);
} else {
// Whether we allow %identifier(..) syntax.
bool allow_natives_syntax =
- info->allows_natives_syntax() || FLAG_allow_natives_syntax;
+ info->is_native() || FLAG_allow_natives_syntax;
ScriptDataImpl* pre_data = info->pre_parse_data();
Parser parser(script,
allow_natives_syntax,
@@ -5224,7 +5418,7 @@ bool ParserApi::Parse(CompilationInfo* info) {
Handle<String> source = Handle<String>(String::cast(script->source()));
result = parser.ParseProgram(source,
info->is_global(),
- info->StrictMode());
+ info->strict_mode_flag());
}
}
info->SetFunction(result);
diff --git a/deps/v8/src/parser.h b/deps/v8/src/parser.h
index 359bb38482..268b094747 100644
--- a/deps/v8/src/parser.h
+++ b/deps/v8/src/parser.h
@@ -33,6 +33,7 @@
#include "preparse-data-format.h"
#include "preparse-data.h"
#include "scopes.h"
+#include "preparser.h"
namespace v8 {
namespace internal {
@@ -43,6 +44,7 @@ class ParserLog;
class PositionStack;
class Target;
class LexicalScope;
+class SaveScope;
template <typename T> class ZoneListWrapper;
@@ -164,13 +166,13 @@ class ParserApi {
// Generic preparser generating full preparse data.
static ScriptDataImpl* PreParse(UC16CharacterStream* source,
v8::Extension* extension,
- bool harmony_scoping);
+ int flags);
// Preparser that only does preprocessing that makes sense if only used
// immediately after.
static ScriptDataImpl* PartialPreParse(UC16CharacterStream* source,
v8::Extension* extension,
- bool harmony_scoping);
+ int flags);
};
// ----------------------------------------------------------------------------
@@ -459,6 +461,12 @@ class Parser {
kForStatement
};
+ // If a list of variable declarations includes any initializers.
+ enum VariableDeclarationProperties {
+ kHasInitializers,
+ kHasNoInitializers
+ };
+
Isolate* isolate() { return isolate_; }
Zone* zone() { return isolate_->zone(); }
@@ -473,7 +481,7 @@ class Parser {
void ReportInvalidPreparseData(Handle<String> name, bool* ok);
void ReportMessage(const char* message, Vector<const char*> args);
- bool inside_with() const { return with_nesting_level_ > 0; }
+ bool inside_with() const { return top_scope_->inside_with(); }
JavaScriptScanner& scanner() { return scanner_; }
Mode mode() const { return mode_; }
ScriptDataImpl* pre_data() const { return pre_data_; }
@@ -492,10 +500,10 @@ class Parser {
Statement* ParseFunctionDeclaration(bool* ok);
Statement* ParseNativeDeclaration(bool* ok);
Block* ParseBlock(ZoneStringList* labels, bool* ok);
- Block* ParseScopedBlock(ZoneStringList* labels, bool* ok);
Block* ParseVariableStatement(VariableDeclarationContext var_context,
bool* ok);
Block* ParseVariableDeclarations(VariableDeclarationContext var_context,
+ VariableDeclarationProperties* decl_props,
Handle<String>* out,
bool* ok);
Statement* ParseExpressionOrLabelledStatement(ZoneStringList* labels,
@@ -515,6 +523,9 @@ class Parser {
TryStatement* ParseTryStatement(bool* ok);
DebuggerStatement* ParseDebuggerStatement(bool* ok);
+ // Support for hamony block scoped bindings.
+ Block* ParseScopedBlock(ZoneStringList* labels, bool* ok);
+
Expression* ParseExpression(bool accept_IN, bool* ok);
Expression* ParseAssignmentExpression(bool accept_IN, bool* ok);
Expression* ParseConditionalExpression(bool accept_IN, bool* ok);
@@ -669,7 +680,7 @@ class Parser {
return &empty;
}
- Scope* NewScope(Scope* parent, Scope::Type type, bool inside_with);
+ Scope* NewScope(Scope* parent, ScopeType type);
Handle<String> LookupSymbol(int symbol_id);
@@ -714,7 +725,6 @@ class Parser {
JavaScriptScanner scanner_;
Scope* top_scope_;
- int with_nesting_level_;
LexicalScope* lexical_scope_;
Mode mode_;
@@ -734,6 +744,7 @@ class Parser {
bool harmony_scoping_;
friend class LexicalScope;
+ friend class SaveScope;
};
diff --git a/deps/v8/src/platform-solaris.cc b/deps/v8/src/platform-solaris.cc
index 7e0153f07a..035d394453 100644
--- a/deps/v8/src/platform-solaris.cc
+++ b/deps/v8/src/platform-solaris.cc
@@ -54,7 +54,6 @@
#include "platform.h"
#include "vm-state-inl.h"
-#include "v8threads.h"
// It seems there is a bug in some Solaris distributions (experienced in
@@ -84,33 +83,6 @@ namespace internal {
static const pthread_t kNoThread = (pthread_t) 0;
-static void* GetRandomMmapAddr() {
- Isolate* isolate = Isolate::UncheckedCurrent();
- // Note that the current isolate isn't set up in a call path via
- // CpuFeatures::Probe. We don't care about randomization in this case because
- // the code page is immediately freed.
- if (isolate != NULL) {
-#ifdef V8_TARGET_ARCH_X64
- uint64_t rnd1 = V8::RandomPrivate(isolate);
- uint64_t rnd2 = V8::RandomPrivate(isolate);
- uint64_t raw_addr = (rnd1 << 32) ^ rnd2;
- // Currently available CPUs have 48 bits of virtual addressing. Truncate
- // the hint address to 46 bits to give the kernel a fighting chance of
- // fulfilling our placement request.
- raw_addr &= V8_UINT64_C(0x3ffffffff000);
-#else
- uint32_t raw_addr = V8::RandomPrivate(isolate);
- // The range 0x20000000 - 0x60000000 is relatively unpopulated across a
- // variety of ASLR modes (PAE kernel, NX compat mode, etc).
- raw_addr &= 0x3ffff000;
- raw_addr += 0x20000000;
-#endif
- return reinterpret_cast<void*>(raw_addr);
- }
- return NULL;
-}
-
-
double ceiling(double x) {
return ceil(x);
}
@@ -350,126 +322,43 @@ static const int kMmapFd = -1;
static const int kMmapFdOffset = 0;
-VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
-
VirtualMemory::VirtualMemory(size_t size) {
- address_ = ReserveRegion(size);
+ address_ = mmap(NULL, size, PROT_NONE,
+ MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
+ kMmapFd, kMmapFdOffset);
size_ = size;
}
-VirtualMemory::VirtualMemory(size_t size, size_t alignment)
- : address_(NULL), size_(0) {
- ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment())));
- size_t request_size = RoundUp(size + alignment,
- static_cast<intptr_t>(OS::AllocateAlignment()));
- void* reservation = mmap(GetRandomMmapAddr(),
- request_size,
- PROT_NONE,
- MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
- kMmapFd,
- kMmapFdOffset);
- if (reservation == MAP_FAILED) return;
-
- Address base = static_cast<Address>(reservation);
- Address aligned_base = RoundUp(base, alignment);
- ASSERT_LE(base, aligned_base);
-
- // Unmap extra memory reserved before and after the desired block.
- if (aligned_base != base) {
- size_t prefix_size = static_cast<size_t>(aligned_base - base);
- OS::Free(base, prefix_size);
- request_size -= prefix_size;
- }
-
- size_t aligned_size = RoundUp(size, OS::AllocateAlignment());
- ASSERT_LE(aligned_size, request_size);
-
- if (aligned_size != request_size) {
- size_t suffix_size = request_size - aligned_size;
- OS::Free(aligned_base + aligned_size, suffix_size);
- request_size -= suffix_size;
- }
-
- ASSERT(aligned_size == request_size);
-
- address_ = static_cast<void*>(aligned_base);
- size_ = aligned_size;
-}
-
-
VirtualMemory::~VirtualMemory() {
if (IsReserved()) {
- bool result = ReleaseRegion(address(), size());
- ASSERT(result);
- USE(result);
+ if (0 == munmap(address(), size())) address_ = MAP_FAILED;
}
}
bool VirtualMemory::IsReserved() {
- return address_ != NULL;
-}
-
-
-void VirtualMemory::Reset() {
- address_ = NULL;
- size_ = 0;
-}
-
-
-bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
- return CommitRegion(address, size, is_executable);
+ return address_ != MAP_FAILED;
}
-bool VirtualMemory::Uncommit(void* address, size_t size) {
- return UncommitRegion(address, size);
-}
-
-
-void* VirtualMemory::ReserveRegion(size_t size) {
- void* result = mmap(GetRandomMmapAddr(),
- size,
- PROT_NONE,
- MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
- kMmapFd,
- kMmapFdOffset);
-
- if (result == MAP_FAILED) return NULL;
-
- return result;
-}
-
-
-bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
- int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
- if (MAP_FAILED == mmap(base,
- size,
- prot,
- MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
- kMmapFd,
- kMmapFdOffset)) {
+bool VirtualMemory::Commit(void* address, size_t size, bool executable) {
+ int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
+ if (MAP_FAILED == mmap(address, size, prot,
+ MAP_PRIVATE | MAP_ANON | MAP_FIXED,
+ kMmapFd, kMmapFdOffset)) {
return false;
}
- UpdateAllocatedSpaceLimits(base, size);
+ UpdateAllocatedSpaceLimits(address, size);
return true;
}
-bool VirtualMemory::UncommitRegion(void* base, size_t size) {
- return mmap(base,
- size,
- PROT_NONE,
- MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_FIXED,
- kMmapFd,
- kMmapFdOffset) != MAP_FAILED;
-}
-
-
-bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
- return munmap(base, size) == 0;
+bool VirtualMemory::Uncommit(void* address, size_t size) {
+ return mmap(address, size, PROT_NONE,
+ MAP_PRIVATE | MAP_ANON | MAP_NORESERVE | MAP_FIXED,
+ kMmapFd, kMmapFdOffset) != MAP_FAILED;
}
diff --git a/deps/v8/src/preparser-api.cc b/deps/v8/src/preparser-api.cc
index 899489e250..25c7a823c3 100644
--- a/deps/v8/src/preparser-api.cc
+++ b/deps/v8/src/preparser-api.cc
@@ -188,7 +188,7 @@ PreParserData Preparse(UnicodeInputStream* input, size_t max_stack) {
preparser::PreParser::PreParseResult result =
preparser::PreParser::PreParseProgram(&scanner,
&recorder,
- true,
+ internal::kAllowLazy,
stack_limit);
if (result == preparser::PreParser::kPreParseStackOverflow) {
return PreParserData::StackOverflow();
diff --git a/deps/v8/src/preparser.cc b/deps/v8/src/preparser.cc
index 9f8e1eecc2..3313658ef7 100644
--- a/deps/v8/src/preparser.cc
+++ b/deps/v8/src/preparser.cc
@@ -125,11 +125,13 @@ PreParser::Statement PreParser::ParseSourceElement(bool* ok) {
// In harmony mode we allow additionally the following productions
// SourceElement:
// LetDeclaration
+ // ConstDeclaration
switch (peek()) {
case i::Token::FUNCTION:
return ParseFunctionDeclaration(ok);
case i::Token::LET:
+ case i::Token::CONST:
return ParseVariableStatement(kSourceElement, ok);
default:
return ParseStatement(ok);
@@ -240,7 +242,7 @@ PreParser::Statement PreParser::ParseStatement(bool* ok) {
i::Scanner::Location start_location = scanner_->peek_location();
Statement statement = ParseFunctionDeclaration(CHECK_OK);
i::Scanner::Location end_location = scanner_->location();
- if (strict_mode()) {
+ if (strict_mode() || harmony_scoping_) {
ReportMessageAt(start_location.beg_pos, end_location.end_pos,
"strict_function", NULL);
*ok = false;
@@ -312,6 +314,7 @@ PreParser::Statement PreParser::ParseVariableStatement(
Statement result = ParseVariableDeclarations(var_context,
NULL,
+ NULL,
CHECK_OK);
ExpectSemicolon(CHECK_OK);
return result;
@@ -325,15 +328,37 @@ PreParser::Statement PreParser::ParseVariableStatement(
// of 'for-in' loops.
PreParser::Statement PreParser::ParseVariableDeclarations(
VariableDeclarationContext var_context,
+ VariableDeclarationProperties* decl_props,
int* num_decl,
bool* ok) {
// VariableDeclarations ::
// ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[',']
-
+ //
+ // The ES6 Draft Rev3 specifies the following grammar for const declarations
+ //
+ // ConstDeclaration ::
+ // const ConstBinding (',' ConstBinding)* ';'
+ // ConstBinding ::
+ // Identifier '=' AssignmentExpression
+ //
+ // TODO(ES6):
+ // ConstBinding ::
+ // BindingPattern '=' AssignmentExpression
+ bool require_initializer = false;
if (peek() == i::Token::VAR) {
Consume(i::Token::VAR);
} else if (peek() == i::Token::CONST) {
- if (strict_mode()) {
+ if (harmony_scoping_) {
+ if (var_context != kSourceElement &&
+ var_context != kForStatement) {
+ i::Scanner::Location location = scanner_->peek_location();
+ ReportMessageAt(location.beg_pos, location.end_pos,
+ "unprotected_const", NULL);
+ *ok = false;
+ return Statement::Default();
+ }
+ require_initializer = true;
+ } else if (strict_mode()) {
i::Scanner::Location location = scanner_->peek_location();
ReportMessageAt(location, "strict_const", NULL);
*ok = false;
@@ -372,9 +397,10 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
return Statement::Default();
}
nvars++;
- if (peek() == i::Token::ASSIGN) {
+ if (peek() == i::Token::ASSIGN || require_initializer) {
Expect(i::Token::ASSIGN, CHECK_OK);
ParseAssignmentExpression(var_context != kForStatement, CHECK_OK);
+ if (decl_props != NULL) *decl_props = kHasInitializers;
}
} while (peek() == i::Token::COMMA);
@@ -569,9 +595,14 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
if (peek() != i::Token::SEMICOLON) {
if (peek() == i::Token::VAR || peek() == i::Token::CONST ||
peek() == i::Token::LET) {
+ bool is_let = peek() == i::Token::LET;
int decl_count;
- ParseVariableDeclarations(kForStatement, &decl_count, CHECK_OK);
- if (peek() == i::Token::IN && decl_count == 1) {
+ VariableDeclarationProperties decl_props = kHasNoInitializers;
+ ParseVariableDeclarations(
+ kForStatement, &decl_props, &decl_count, CHECK_OK);
+ bool accept_IN = decl_count == 1 &&
+ !(is_let && decl_props == kHasInitializers);
+ if (peek() == i::Token::IN && accept_IN) {
Expect(i::Token::IN, CHECK_OK);
ParseExpression(true, CHECK_OK);
Expect(i::Token::RPAREN, CHECK_OK);
@@ -1353,8 +1384,11 @@ PreParser::Expression PreParser::ParseFunctionLiteral(bool* ok) {
PreParser::Expression PreParser::ParseV8Intrinsic(bool* ok) {
// CallRuntime ::
// '%' Identifier Arguments
-
Expect(i::Token::MOD, CHECK_OK);
+ if (!allow_natives_syntax_) {
+ *ok = false;
+ return Expression::Default();
+ }
ParseIdentifier(CHECK_OK);
ParseArguments(ok);
diff --git a/deps/v8/src/preparser.h b/deps/v8/src/preparser.h
index cb1d5fb4eb..6a0b97a56e 100644
--- a/deps/v8/src/preparser.h
+++ b/deps/v8/src/preparser.h
@@ -118,9 +118,12 @@ class PreParser {
// during parsing.
static PreParseResult PreParseProgram(i::JavaScriptScanner* scanner,
i::ParserRecorder* log,
- bool allow_lazy,
+ int flags,
uintptr_t stack_limit) {
- return PreParser(scanner, log, stack_limit, allow_lazy).PreParse();
+ bool allow_lazy = (flags & i::kAllowLazy) != 0;
+ bool allow_natives_syntax = (flags & i::kAllowNativesSyntax) != 0;
+ return PreParser(scanner, log, stack_limit,
+ allow_lazy, allow_natives_syntax).PreParse();
}
private:
@@ -179,6 +182,12 @@ class PreParser {
kForStatement
};
+ // If a list of variable declarations includes any initializers.
+ enum VariableDeclarationProperties {
+ kHasInitializers,
+ kHasNoInitializers
+ };
+
class Expression;
class Identifier {
@@ -399,6 +408,16 @@ class PreParser {
typedef int Arguments;
+ // The Strict Mode (ECMA-262 5th edition, 4.2.2).
+ enum StrictModeFlag {
+ kNonStrictMode,
+ kStrictMode,
+ // This value is never used, but is needed to prevent GCC 4.5 from failing
+ // to compile when we assert that a flag is either kNonStrictMode or
+ // kStrictMode.
+ kInvalidStrictFlag
+ };
+
class Scope {
public:
Scope(Scope** variable, ScopeType type)
@@ -408,7 +427,8 @@ class PreParser {
materialized_literal_count_(0),
expected_properties_(0),
with_nesting_count_(0),
- strict_((prev_ != NULL) && prev_->is_strict()) {
+ strict_mode_flag_((prev_ != NULL) ? prev_->strict_mode_flag()
+ : kNonStrictMode) {
*variable = this;
}
~Scope() { *variable_ = prev_; }
@@ -418,8 +438,13 @@ class PreParser {
int expected_properties() { return expected_properties_; }
int materialized_literal_count() { return materialized_literal_count_; }
bool IsInsideWith() { return with_nesting_count_ != 0; }
- bool is_strict() { return strict_; }
- void set_strict() { strict_ = true; }
+ bool is_strict_mode() { return strict_mode_flag_ == kStrictMode; }
+ StrictModeFlag strict_mode_flag() {
+ return strict_mode_flag_;
+ }
+ void set_strict_mode_flag(StrictModeFlag strict_mode_flag) {
+ strict_mode_flag_ = strict_mode_flag;
+ }
void EnterWith() { with_nesting_count_++; }
void LeaveWith() { with_nesting_count_--; }
@@ -430,14 +455,15 @@ class PreParser {
int materialized_literal_count_;
int expected_properties_;
int with_nesting_count_;
- bool strict_;
+ StrictModeFlag strict_mode_flag_;
};
// Private constructor only used in PreParseProgram.
PreParser(i::JavaScriptScanner* scanner,
i::ParserRecorder* log,
uintptr_t stack_limit,
- bool allow_lazy)
+ bool allow_lazy,
+ bool allow_natives_syntax)
: scanner_(scanner),
log_(log),
scope_(NULL),
@@ -445,7 +471,8 @@ class PreParser {
strict_mode_violation_location_(i::Scanner::Location::invalid()),
strict_mode_violation_type_(NULL),
stack_overflow_(false),
- allow_lazy_(true),
+ allow_lazy_(allow_lazy),
+ allow_natives_syntax_(allow_natives_syntax),
parenthesized_function_(false),
harmony_scoping_(scanner->HarmonyScoping()) { }
@@ -459,7 +486,7 @@ class PreParser {
if (stack_overflow_) return kPreParseStackOverflow;
if (!ok) {
ReportUnexpectedToken(scanner_->current_token());
- } else if (scope_->is_strict()) {
+ } else if (scope_->is_strict_mode()) {
CheckOctalLiteral(start_position, scanner_->location().end_pos, &ok);
}
return kPreParseSuccess;
@@ -493,6 +520,7 @@ class PreParser {
Statement ParseVariableStatement(VariableDeclarationContext var_context,
bool* ok);
Statement ParseVariableDeclarations(VariableDeclarationContext var_context,
+ VariableDeclarationProperties* decl_props,
int* num_decl,
bool* ok);
Statement ParseExpressionOrLabelledStatement(bool* ok);
@@ -563,10 +591,10 @@ class PreParser {
bool peek_any_identifier();
void set_strict_mode() {
- scope_->set_strict();
+ scope_->set_strict_mode_flag(kStrictMode);
}
- bool strict_mode() { return scope_->is_strict(); }
+ bool strict_mode() { return scope_->strict_mode_flag() == kStrictMode; }
void Consume(i::Token::Value token) { Next(); }
@@ -607,6 +635,7 @@ class PreParser {
const char* strict_mode_violation_type_;
bool stack_overflow_;
bool allow_lazy_;
+ bool allow_natives_syntax_;
bool parenthesized_function_;
bool harmony_scoping_;
};
diff --git a/deps/v8/src/profile-generator.cc b/deps/v8/src/profile-generator.cc
index bae35c89ed..9812c26e9e 100644
--- a/deps/v8/src/profile-generator.cc
+++ b/deps/v8/src/profile-generator.cc
@@ -1930,9 +1930,11 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
SetInternalReference(js_fun, entry,
"context", js_fun->unchecked_context(),
JSFunction::kContextOffset);
- TagObject(js_fun->literals(), "(function literals)");
+ TagObject(js_fun->literals_or_bindings(),
+ "(function literals_or_bindings)");
SetInternalReference(js_fun, entry,
- "literals", js_fun->literals(),
+ "literals_or_bindings",
+ js_fun->literals_or_bindings(),
JSFunction::kLiteralsOffset);
}
TagObject(js_obj->properties(), "(object properties)");
@@ -1949,6 +1951,10 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
SetInternalReference(obj, entry, 1, cs->first());
SetInternalReference(obj, entry, 2, cs->second());
}
+ if (obj->IsSlicedString()) {
+ SlicedString* ss = SlicedString::cast(obj);
+ SetInternalReference(obj, entry, "parent", ss->parent());
+ }
extract_indexed_refs = false;
} else if (obj->IsGlobalContext()) {
Context* context = Context::cast(obj);
@@ -2164,15 +2170,16 @@ void V8HeapExplorer::ExtractInternalReferences(JSObject* js_obj,
String* V8HeapExplorer::GetConstructorName(JSObject* object) {
- if (object->IsJSFunction()) return HEAP->closure_symbol();
+ Heap* heap = object->GetHeap();
+ if (object->IsJSFunction()) return heap->closure_symbol();
String* constructor_name = object->constructor_name();
- if (constructor_name == HEAP->Object_symbol()) {
+ if (constructor_name == heap->Object_symbol()) {
// Look up an immediate "constructor" property, if it is a function,
// return its name. This is for instances of binding objects, which
// have prototype constructor type "Object".
Object* constructor_prop = NULL;
- LookupResult result;
- object->LocalLookupRealNamedProperty(HEAP->constructor_symbol(), &result);
+ LookupResult result(heap->isolate());
+ object->LocalLookupRealNamedProperty(heap->constructor_symbol(), &result);
if (result.IsProperty()) {
constructor_prop = result.GetLazyValue();
}
diff --git a/deps/v8/src/property.cc b/deps/v8/src/property.cc
index 7cc2df5a3c..6e043e2685 100644
--- a/deps/v8/src/property.cc
+++ b/deps/v8/src/property.cc
@@ -31,6 +31,15 @@ namespace v8 {
namespace internal {
+void LookupResult::Iterate(ObjectVisitor* visitor) {
+ LookupResult* current = this; // Could be NULL.
+ while (current != NULL) {
+ visitor->VisitPointer(BitCast<Object**>(&current->holder_));
+ current = current->next_;
+ }
+}
+
+
#ifdef OBJECT_PRINT
void LookupResult::Print(FILE* out) {
if (!IsFound()) {
diff --git a/deps/v8/src/property.h b/deps/v8/src/property.h
index ee2e8c844e..ffea41e666 100644
--- a/deps/v8/src/property.h
+++ b/deps/v8/src/property.h
@@ -164,10 +164,20 @@ class CallbacksDescriptor: public Descriptor {
class LookupResult BASE_EMBEDDED {
public:
- LookupResult()
- : lookup_type_(NOT_FOUND),
+ explicit LookupResult(Isolate* isolate)
+ : isolate_(isolate),
+ next_(isolate->top_lookup_result()),
+ lookup_type_(NOT_FOUND),
+ holder_(NULL),
cacheable_(true),
- details_(NONE, NORMAL) {}
+ details_(NONE, NORMAL) {
+ isolate->SetTopLookupResult(this);
+ }
+
+ ~LookupResult() {
+ ASSERT(isolate_->top_lookup_result() == this);
+ isolate_->SetTopLookupResult(next_);
+ }
void DescriptorResult(JSObject* holder, PropertyDetails details, int number) {
lookup_type_ = DESCRIPTOR_TYPE;
@@ -215,6 +225,7 @@ class LookupResult BASE_EMBEDDED {
void NotFound() {
lookup_type_ = NOT_FOUND;
+ holder_ = NULL;
}
JSObject* holder() {
@@ -346,7 +357,12 @@ class LookupResult BASE_EMBEDDED {
return holder()->GetNormalizedProperty(this);
}
+ void Iterate(ObjectVisitor* visitor);
+
private:
+ Isolate* isolate_;
+ LookupResult* next_;
+
// Where did we find the result;
enum {
NOT_FOUND,
diff --git a/deps/v8/src/proxy.js b/deps/v8/src/proxy.js
index a51f09ae50..3cd467faf2 100644
--- a/deps/v8/src/proxy.js
+++ b/deps/v8/src/proxy.js
@@ -32,7 +32,10 @@ var $Proxy = global.Proxy
$Proxy.create = function(handler, proto) {
if (!IS_SPEC_OBJECT(handler))
throw MakeTypeError("handler_non_object", ["create"])
- if (!IS_SPEC_OBJECT(proto)) proto = null // Mozilla does this...
+ if (IS_UNDEFINED(proto))
+ proto = null
+ else if (!(IS_SPEC_OBJECT(proto) || proto === null))
+ throw MakeTypeError("proto_non_object", ["create"])
return %CreateJSProxy(handler, proto)
}
@@ -41,20 +44,20 @@ $Proxy.createFunction = function(handler, callTrap, constructTrap) {
throw MakeTypeError("handler_non_object", ["create"])
if (!IS_SPEC_FUNCTION(callTrap))
throw MakeTypeError("trap_function_expected", ["createFunction", "call"])
- var construct
if (IS_UNDEFINED(constructTrap)) {
- construct = DerivedConstructTrap(callTrap)
+ constructTrap = DerivedConstructTrap(callTrap)
} else if (IS_SPEC_FUNCTION(constructTrap)) {
- construct = function() {
- // Make sure the trap receives 'undefined' as this.
- return %Apply(constructTrap, void 0, arguments, 0, %_ArgumentsLength());
+ // Make sure the trap receives 'undefined' as this.
+ var construct = constructTrap
+ constructTrap = function() {
+ return %Apply(construct, void 0, arguments, 0, %_ArgumentsLength());
}
} else {
throw MakeTypeError("trap_function_expected",
["createFunction", "construct"])
}
return %CreateJSFunctionProxy(
- handler, callTrap, construct, $Function.prototype)
+ handler, callTrap, constructTrap, $Function.prototype)
}
@@ -153,9 +156,32 @@ function DerivedKeysTrap() {
var enumerableNames = []
for (var i = 0, count = 0; i < names.length; ++i) {
var name = names[i]
- if (this.getOwnPropertyDescriptor(TO_STRING_INLINE(name)).enumerable) {
+ var desc = this.getOwnPropertyDescriptor(TO_STRING_INLINE(name))
+ if (!IS_UNDEFINED(desc) && desc.enumerable) {
enumerableNames[count++] = names[i]
}
}
return enumerableNames
}
+
+function DerivedEnumerateTrap() {
+ var names = this.getPropertyNames()
+ var enumerableNames = []
+ for (var i = 0, count = 0; i < names.length; ++i) {
+ var name = names[i]
+ var desc = this.getPropertyDescriptor(TO_STRING_INLINE(name))
+ if (!IS_UNDEFINED(desc) && desc.enumerable) {
+ enumerableNames[count++] = names[i]
+ }
+ }
+ return enumerableNames
+}
+
+function ProxyEnumerate(proxy) {
+ var handler = %GetHandler(proxy)
+ if (IS_UNDEFINED(handler.enumerate)) {
+ return %Apply(DerivedEnumerateTrap, handler, [], 0, 0)
+ } else {
+ return ToStringArray(handler.enumerate(), "enumerate")
+ }
+}
diff --git a/deps/v8/src/regexp.js b/deps/v8/src/regexp.js
index 0ab86f3338..f373ceb67e 100644
--- a/deps/v8/src/regexp.js
+++ b/deps/v8/src/regexp.js
@@ -174,13 +174,6 @@ function RegExpExec(string) {
['RegExp.prototype.exec', this]);
}
- if (%_ArgumentsLength() === 0) {
- var regExpInput = LAST_INPUT(lastMatchInfo);
- if (IS_UNDEFINED(regExpInput)) {
- throw MakeError('no_input_to_regexp', [this]);
- }
- string = regExpInput;
- }
string = TO_STRING_INLINE(string);
var lastIndex = this.lastIndex;
@@ -229,14 +222,6 @@ function RegExpTest(string) {
throw MakeTypeError('incompatible_method_receiver',
['RegExp.prototype.test', this]);
}
- if (%_ArgumentsLength() == 0) {
- var regExpInput = LAST_INPUT(lastMatchInfo);
- if (IS_UNDEFINED(regExpInput)) {
- throw MakeError('no_input_to_regexp', [this]);
- }
- string = regExpInput;
- }
-
string = TO_STRING_INLINE(string);
var lastIndex = this.lastIndex;
diff --git a/deps/v8/src/runtime.cc b/deps/v8/src/runtime.cc
index e0f507e177..9c23c2c967 100644
--- a/deps/v8/src/runtime.cc
+++ b/deps/v8/src/runtime.cc
@@ -432,64 +432,77 @@ static Handle<Object> CreateArrayLiteralBoilerplate(
// Create the JSArray.
Handle<JSFunction> constructor(
JSFunction::GlobalContextFromLiterals(*literals)->array_function());
- Handle<Object> object = isolate->factory()->NewJSObject(constructor);
-
- if (elements->length() > kSmiOnlyLiteralMinimumLength) {
- Handle<Map> smi_array_map = isolate->factory()->GetElementsTransitionMap(
- Handle<JSObject>::cast(object),
- FAST_SMI_ONLY_ELEMENTS);
- HeapObject::cast(*object)->set_map(*smi_array_map);
- }
-
- const bool is_cow =
- (elements->map() == isolate->heap()->fixed_cow_array_map());
- Handle<FixedArray> copied_elements =
- is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
-
- Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
- bool has_non_smi = false;
- if (is_cow) {
- // Copy-on-write arrays must be shallow (and simple).
- for (int i = 0; i < content->length(); i++) {
- Object* current = content->get(i);
- ASSERT(!current->IsFixedArray());
- if (!current->IsSmi() && !current->IsTheHole()) {
- has_non_smi = true;
- }
- }
+ Handle<JSArray> object =
+ Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
+
+ ElementsKind constant_elements_kind =
+ static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
+ Handle<FixedArrayBase> constant_elements_values(
+ FixedArrayBase::cast(elements->get(1)));
+
+ ASSERT(FLAG_smi_only_arrays || constant_elements_kind == FAST_ELEMENTS ||
+ constant_elements_kind == FAST_SMI_ONLY_ELEMENTS);
+ bool allow_literal_kind_transition = FLAG_smi_only_arrays &&
+ constant_elements_kind > object->GetElementsKind();
+
+ if (!FLAG_smi_only_arrays &&
+ constant_elements_values->length() > kSmiOnlyLiteralMinimumLength &&
+ constant_elements_kind != object->GetElementsKind()) {
+ allow_literal_kind_transition = true;
+ }
+
+ // If the ElementsKind of the constant values of the array literal are less
+ // specific than the ElementsKind of the boilerplate array object, change the
+ // boilerplate array object's map to reflect that kind.
+ if (allow_literal_kind_transition) {
+ Handle<Map> transitioned_array_map =
+ isolate->factory()->GetElementsTransitionMap(object,
+ constant_elements_kind);
+ object->set_map(*transitioned_array_map);
+ }
+
+ Handle<FixedArrayBase> copied_elements_values;
+ if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
+ ASSERT(FLAG_smi_only_arrays);
+ copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
+ Handle<FixedDoubleArray>::cast(constant_elements_values));
+ } else {
+ ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
+ constant_elements_kind == FAST_ELEMENTS);
+ const bool is_cow =
+ (constant_elements_values->map() ==
+ isolate->heap()->fixed_cow_array_map());
+ if (is_cow) {
+ copied_elements_values = constant_elements_values;
#if DEBUG
- for (int i = 0; i < content->length(); i++) {
- ASSERT(!content->get(i)->IsFixedArray());
- }
+ Handle<FixedArray> fixed_array_values =
+ Handle<FixedArray>::cast(copied_elements_values);
+ for (int i = 0; i < fixed_array_values->length(); i++) {
+ ASSERT(!fixed_array_values->get(i)->IsFixedArray());
+ }
#endif
- } else {
- for (int i = 0; i < content->length(); i++) {
- Object* current = content->get(i);
- if (current->IsFixedArray()) {
- // The value contains the constant_properties of a
- // simple object or array literal.
- Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
- Handle<Object> result =
- CreateLiteralBoilerplate(isolate, literals, fa);
- if (result.is_null()) return result;
- content->set(i, *result);
- has_non_smi = true;
- } else {
- if (!current->IsSmi() && !current->IsTheHole()) {
- has_non_smi = true;
+ } else {
+ Handle<FixedArray> fixed_array_values =
+ Handle<FixedArray>::cast(constant_elements_values);
+ Handle<FixedArray> fixed_array_values_copy =
+ isolate->factory()->CopyFixedArray(fixed_array_values);
+ copied_elements_values = fixed_array_values_copy;
+ for (int i = 0; i < fixed_array_values->length(); i++) {
+ Object* current = fixed_array_values->get(i);
+ if (current->IsFixedArray()) {
+ // The value contains the constant_properties of a
+ // simple object or array literal.
+ Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
+ Handle<Object> result =
+ CreateLiteralBoilerplate(isolate, literals, fa);
+ if (result.is_null()) return result;
+ fixed_array_values_copy->set(i, *result);
}
}
}
}
-
- // Set the elements.
- Handle<JSArray> js_object(Handle<JSArray>::cast(object));
- isolate->factory()->SetContent(js_object, content);
-
- if (has_non_smi && js_object->HasFastSmiOnlyElements()) {
- isolate->factory()->EnsureCanContainNonSmiElements(js_object);
- }
-
+ object->set_elements(*copied_elements_values);
+ object->set_length(Smi::FromInt(copied_elements_values->length()));
return object;
}
@@ -704,6 +717,82 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 1);
+ CONVERT_ARG_CHECKED(JSSet, holder, 0);
+ Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
+ holder->set_table(*table);
+ return *holder;
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 2);
+ CONVERT_ARG_CHECKED(JSSet, holder, 0);
+ Handle<Object> key(args[1]);
+ Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
+ table = ObjectHashSetAdd(table, key);
+ holder->set_table(*table);
+ return isolate->heap()->undefined_symbol();
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 2);
+ CONVERT_ARG_CHECKED(JSSet, holder, 0);
+ Handle<Object> key(args[1]);
+ Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
+ return isolate->heap()->ToBoolean(table->Contains(*key));
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 2);
+ CONVERT_ARG_CHECKED(JSSet, holder, 0);
+ Handle<Object> key(args[1]);
+ Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
+ table = ObjectHashSetRemove(table, key);
+ holder->set_table(*table);
+ return isolate->heap()->undefined_symbol();
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 1);
+ CONVERT_ARG_CHECKED(JSMap, holder, 0);
+ Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
+ holder->set_table(*table);
+ return *holder;
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 2);
+ CONVERT_ARG_CHECKED(JSMap, holder, 0);
+ Handle<Object> key(args[1]);
+ return ObjectHashTable::cast(holder->table())->Lookup(*key);
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 3);
+ CONVERT_ARG_CHECKED(JSMap, holder, 0);
+ Handle<Object> key(args[1]);
+ Handle<Object> value(args[2]);
+ Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
+ Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
+ holder->set_table(*new_table);
+ return *value;
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
HandleScope scope(isolate);
ASSERT(args.length() == 1);
@@ -961,7 +1050,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
HandleScope scope(isolate);
Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
- LookupResult result;
+ LookupResult result(isolate);
CONVERT_ARG_CHECKED(JSObject, obj, 0);
CONVERT_ARG_CHECKED(String, name, 1);
@@ -992,7 +1081,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
case JSObject::INTERCEPTED_ELEMENT:
case JSObject::FAST_ELEMENT: {
elms->set(IS_ACCESSOR_INDEX, heap->false_value());
- Handle<Object> value = GetElement(obj, index);
+ Handle<Object> value = Object::GetElement(obj, index);
RETURN_IF_EMPTY_HANDLE(isolate, value);
elms->set(VALUE_INDEX, *value);
elms->set(WRITABLE_INDEX, heap->true_value());
@@ -1036,7 +1125,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
case NORMAL: {
// This is a data property.
elms->set(IS_ACCESSOR_INDEX, heap->false_value());
- Handle<Object> value = GetElement(obj, index);
+ Handle<Object> value = Object::GetElement(obj, index);
ASSERT(!value.is_null());
elms->set(VALUE_INDEX, *value);
elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
@@ -1240,7 +1329,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
if (value->IsUndefined() || is_const_property) {
// Lookup the property in the global object, and don't set the
// value of the variable if the property is already there.
- LookupResult lookup;
+ LookupResult lookup(isolate);
global->Lookup(*name, &lookup);
if (lookup.IsProperty()) {
// We found an existing property. Unless it was an interceptor
@@ -1267,7 +1356,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
value = function;
}
- LookupResult lookup;
+ LookupResult lookup(isolate);
global->LocalLookup(*name, &lookup);
// Compute the property attributes. According to ECMA-262, section
@@ -1275,10 +1364,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
// non-deletable. However, neither SpiderMonkey nor KJS creates the
// property as read-only, so we don't either.
int attr = NONE;
- if ((flags & kDeclareGlobalsEvalFlag) == 0) {
+ if (!DeclareGlobalsEvalFlag::decode(flags)) {
attr |= DONT_DELETE;
}
- bool is_native = (flags & kDeclareGlobalsNativeFlag) != 0;
+ bool is_native = DeclareGlobalsNativeFlag::decode(flags);
if (is_const_property || (is_native && is_function_declaration)) {
attr |= READ_ONLY;
}
@@ -1303,9 +1392,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
value,
attributes));
} else {
- StrictModeFlag strict_mode =
- ((flags & kDeclareGlobalsStrictModeFlag) != 0) ? kStrictMode
- : kNonStrictMode;
+ StrictModeFlag strict_mode = DeclareGlobalsStrictModeFlag::decode(flags);
RETURN_IF_EMPTY_HANDLE(isolate,
SetProperty(global,
name,
@@ -1399,7 +1486,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
// not real JSObjects.
if (initial_value->IsTheHole() &&
!object->IsJSContextExtensionObject()) {
- LookupResult lookup;
+ LookupResult lookup(isolate);
object->Lookup(*name, &lookup);
if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
return ThrowRedeclarationError(isolate, "const", name);
@@ -1443,7 +1530,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
// Note that objects can have hidden prototypes, so we need to traverse
// the whole chain of hidden prototypes to do a 'local' lookup.
Object* object = global;
- LookupResult lookup;
+ LookupResult lookup(isolate);
while (object->IsJSObject() &&
JSObject::cast(object)->map()->is_hidden_prototype()) {
JSObject* raw_holder = JSObject::cast(object);
@@ -1497,7 +1584,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
// add it as a local property even in case of callbacks in the
// prototype chain (this rules out using SetProperty).
// We use SetLocalPropertyIgnoreAttributes instead
- LookupResult lookup;
+ LookupResult lookup(isolate);
global->LocalLookup(*name, &lookup);
if (!lookup.IsProperty()) {
return global->SetLocalPropertyIgnoreAttributes(*name,
@@ -1614,7 +1701,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
// This is the property that was introduced by the const declaration.
// Set it if it hasn't been set before. NOTE: We cannot use
// GetProperty() to get the current value as it 'unholes' the value.
- LookupResult lookup;
+ LookupResult lookup(isolate);
object->LocalLookupRealNamedProperty(*name, &lookup);
ASSERT(lookup.IsProperty()); // the property was declared
ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
@@ -1663,19 +1750,6 @@ RUNTIME_FUNCTION(MaybeObject*,
}
-RUNTIME_FUNCTION(MaybeObject*, Runtime_NonSmiElementStored) {
- ASSERT(args.length() == 1);
- CONVERT_ARG_CHECKED(JSObject, object, 0);
- if (object->HasFastSmiOnlyElements()) {
- MaybeObject* maybe_map = object->GetElementsTransitionMap(FAST_ELEMENTS);
- Map* map;
- if (!maybe_map->To<Map>(&map)) return maybe_map;
- object->set_map(Map::cast(map));
- }
- return *object;
-}
-
-
RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
HandleScope scope(isolate);
ASSERT(args.length() == 4);
@@ -1930,15 +2004,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
}
-RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetBound) {
- HandleScope scope(isolate);
- ASSERT(args.length() == 1);
-
- CONVERT_CHECKED(JSFunction, fun, args[0]);
- fun->shared()->set_bound(true);
- return isolate->heap()->undefined_value();
-}
-
RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
NoHandleAllocation ha;
ASSERT(args.length() == 1);
@@ -2017,24 +2082,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
}
-// Creates a local, readonly, property called length with the correct
-// length (when read by the user). This effectively overwrites the
-// interceptor used to normally provide the length.
-RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionSetLength) {
- NoHandleAllocation ha;
- ASSERT(args.length() == 2);
- CONVERT_CHECKED(JSFunction, fun, args[0]);
- CONVERT_CHECKED(Smi, length, args[1]);
- MaybeObject* maybe_name =
- isolate->heap()->AllocateStringFromAscii(CStrVector("length"));
- String* name;
- if (!maybe_name->To(&name)) return maybe_name;
- PropertyAttributes attr =
- static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
- return fun->AddProperty(name, length, attr, kNonStrictMode);
-}
-
-
RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
NoHandleAllocation ha;
ASSERT(args.length() == 2);
@@ -2137,13 +2184,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
Handle<SharedFunctionInfo> shared(fun->shared());
- if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
+ if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
return Failure::Exception();
}
// Since we don't store the source for this we should never
// optimize this.
shared->code()->set_optimizable(false);
-
// Set the code, scope info, formal parameter count,
// and the length of the target function.
target->shared()->set_code(shared->code());
@@ -4069,11 +4115,6 @@ MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
return prototype->GetElement(index);
}
- return GetElement(object, index);
-}
-
-
-MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
return object->GetElement(index);
}
@@ -4162,7 +4203,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
}
// Lookup cache miss. Perform lookup and update the cache if appropriate.
- LookupResult result;
+ LookupResult result(isolate);
receiver->LocalLookup(key, &result);
if (result.IsProperty() && result.type() == FIELD) {
int offset = result.GetFieldIndex();
@@ -4217,7 +4258,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
int unchecked = flag_attr->value();
RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
RUNTIME_ASSERT(!obj->IsNull());
- LookupResult result;
+ LookupResult result(isolate);
obj->LocalLookupRealNamedProperty(name, &result);
PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
@@ -4259,11 +4300,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
uint32_t index;
bool is_element = name->AsArrayIndex(&index);
- // Special case for elements if any of the flags are true.
+ // Special case for elements if any of the flags might be involved.
// If elements are in fast case we always implicitly assume that:
// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
- if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
- is_element) {
+ if (is_element && (attr != NONE ||
+ js_object->HasLocalElement(index) == JSObject::DICTIONARY_ELEMENT)) {
// Normalize the elements to enable attributes on the property.
if (js_object->IsJSGlobalProxy()) {
// We do not need to do access checks here since these has already
@@ -4301,7 +4342,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
return *obj_value;
}
- LookupResult result;
+ LookupResult result(isolate);
js_object->LocalLookupRealNamedProperty(*name, &result);
// To be compatible with safari we do not change the value on API objects
@@ -4568,6 +4609,39 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
}
+MaybeObject* TransitionElements(Handle<Object> object,
+ ElementsKind to_kind,
+ Isolate* isolate) {
+ HandleScope scope(isolate);
+ if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
+ ElementsKind from_kind =
+ Handle<JSObject>::cast(object)->map()->elements_kind();
+ if (Map::IsValidElementsTransition(from_kind, to_kind)) {
+ Handle<Object> result =
+ TransitionElementsKind(Handle<JSObject>::cast(object), to_kind);
+ if (result.is_null()) return isolate->ThrowIllegalOperation();
+ return *result;
+ }
+ return isolate->ThrowIllegalOperation();
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
+ NoHandleAllocation ha;
+ RUNTIME_ASSERT(args.length() == 1);
+ Handle<Object> object = args.at<Object>(0);
+ return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
+ NoHandleAllocation ha;
+ RUNTIME_ASSERT(args.length() == 1);
+ Handle<Object> object = args.at<Object>(0);
+ return TransitionElements(object, FAST_ELEMENTS, isolate);
+}
+
+
// Set the native flag on the function.
// This is used to decide if we should transform null and undefined
// into the global object when doing call and apply.
@@ -4751,8 +4825,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
HandleScope scope(isolate);
ASSERT(args.length() == 1);
- CONVERT_ARG_CHECKED(JSObject, object, 0);
- return *GetKeysFor(object);
+ CONVERT_ARG_CHECKED(JSReceiver, object, 0);
+ bool threw = false;
+ Handle<JSArray> result = GetKeysFor(object, &threw);
+ if (threw) return Failure::Exception();
+ return *result;
}
@@ -4764,14 +4841,16 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
ASSERT(args.length() == 1);
- CONVERT_CHECKED(JSObject, raw_object, args[0]);
+ CONVERT_CHECKED(JSReceiver, raw_object, args[0]);
if (raw_object->IsSimpleEnum()) return raw_object->map();
HandleScope scope(isolate);
- Handle<JSObject> object(raw_object);
- Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
- INCLUDE_PROTOS);
+ Handle<JSReceiver> object(raw_object);
+ bool threw = false;
+ Handle<FixedArray> content =
+ GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
+ if (threw) return Failure::Exception();
// Test again, since cache may have been built by preceding call.
if (object->IsSimpleEnum()) return object->map();
@@ -4968,8 +5047,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
object = Handle<JSObject>::cast(proto);
}
- Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
- LOCAL_ONLY);
+ bool threw = false;
+ Handle<FixedArray> contents =
+ GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
+ if (threw) return Failure::Exception();
+
// Some fast paths through GetKeysInFixedArrayFor reuse a cached
// property array and since the result is mutable we have to create
// a fresh clone on each invocation.
@@ -7762,14 +7844,21 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
int year, month, day;
DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
- RUNTIME_ASSERT(res_array->elements()->map() ==
- isolate->heap()->fixed_array_map());
- FixedArray* elms = FixedArray::cast(res_array->elements());
- RUNTIME_ASSERT(elms->length() == 3);
+ FixedArrayBase* elms_base = FixedArrayBase::cast(res_array->elements());
+ RUNTIME_ASSERT(elms_base->length() == 3);
+ RUNTIME_ASSERT(res_array->GetElementsKind() <= FAST_DOUBLE_ELEMENTS);
- elms->set(0, Smi::FromInt(year));
- elms->set(1, Smi::FromInt(month));
- elms->set(2, Smi::FromInt(day));
+ if (res_array->HasFastDoubleElements()) {
+ FixedDoubleArray* elms = FixedDoubleArray::cast(res_array->elements());
+ elms->set(0, year);
+ elms->set(1, month);
+ elms->set(2, day);
+ } else {
+ FixedArray* elms = FixedArray::cast(res_array->elements());
+ elms->set(0, Smi::FromInt(year));
+ elms->set(1, Smi::FromInt(month));
+ elms->set(2, Smi::FromInt(day));
+ }
return isolate->heap()->undefined_value();
}
@@ -7926,8 +8015,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
}
-static SmartArrayPointer<Handle<Object> > GetNonBoundArguments(
- int bound_argc,
+// Find the arguments of the JavaScript function invocation that called
+// into C++ code. Collect these in a newly allocated array of handles (possibly
+// prefixed by a number of empty handles).
+static SmartArrayPointer<Handle<Object> > GetCallerArguments(
+ int prefix_argc,
int* total_argc) {
// Find frame containing arguments passed to the caller.
JavaScriptFrameIterator it;
@@ -7943,12 +8035,12 @@ static SmartArrayPointer<Handle<Object> > GetNonBoundArguments(
inlined_frame_index,
&args_slots);
- *total_argc = bound_argc + args_count;
+ *total_argc = prefix_argc + args_count;
SmartArrayPointer<Handle<Object> > param_data(
NewArray<Handle<Object> >(*total_argc));
for (int i = 0; i < args_count; i++) {
Handle<Object> val = args_slots[i].GetValue();
- param_data[bound_argc + i] = val;
+ param_data[prefix_argc + i] = val;
}
return param_data;
} else {
@@ -7956,49 +8048,131 @@ static SmartArrayPointer<Handle<Object> > GetNonBoundArguments(
frame = it.frame();
int args_count = frame->ComputeParametersCount();
- *total_argc = bound_argc + args_count;
+ *total_argc = prefix_argc + args_count;
SmartArrayPointer<Handle<Object> > param_data(
NewArray<Handle<Object> >(*total_argc));
for (int i = 0; i < args_count; i++) {
Handle<Object> val = Handle<Object>(frame->GetParameter(i));
- param_data[bound_argc + i] = val;
+ param_data[prefix_argc + i] = val;
}
return param_data;
}
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 4);
+ CONVERT_ARG_CHECKED(JSFunction, bound_function, 0);
+ RUNTIME_ASSERT(args[3]->IsNumber());
+ Handle<Object> bindee = args.at<Object>(1);
+
+ // TODO(lrn): Create bound function in C++ code from premade shared info.
+ bound_function->shared()->set_bound(true);
+ // Get all arguments of calling function (Function.prototype.bind).
+ int argc = 0;
+ SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
+ // Don't count the this-arg.
+ if (argc > 0) {
+ ASSERT(*arguments[0] == args[2]);
+ argc--;
+ } else {
+ ASSERT(args[2]->IsUndefined());
+ }
+ // Initialize array of bindings (function, this, and any existing arguments
+ // if the function was already bound).
+ Handle<FixedArray> new_bindings;
+ int i;
+ if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
+ Handle<FixedArray> old_bindings(
+ JSFunction::cast(*bindee)->function_bindings());
+ new_bindings =
+ isolate->factory()->NewFixedArray(old_bindings->length() + argc);
+ bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
+ i = 0;
+ for (int n = old_bindings->length(); i < n; i++) {
+ new_bindings->set(i, old_bindings->get(i));
+ }
+ } else {
+ int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
+ new_bindings = isolate->factory()->NewFixedArray(array_size);
+ new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
+ new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
+ i = 2;
+ }
+ // Copy arguments, skipping the first which is "this_arg".
+ for (int j = 0; j < argc; j++, i++) {
+ new_bindings->set(i, *arguments[j + 1]);
+ }
+ new_bindings->set_map(isolate->heap()->fixed_cow_array_map());
+ bound_function->set_function_bindings(*new_bindings);
+
+ // Update length.
+ Handle<String> length_symbol = isolate->factory()->length_symbol();
+ Handle<Object> new_length(args.at<Object>(3));
+ PropertyAttributes attr =
+ static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
+ ForceSetProperty(bound_function, length_symbol, new_length, attr);
+ return *bound_function;
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
+ HandleScope handles(isolate);
+ ASSERT(args.length() == 1);
+ CONVERT_ARG_CHECKED(JSObject, callable, 0);
+ if (callable->IsJSFunction()) {
+ Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
+ if (function->shared()->bound()) {
+ Handle<FixedArray> bindings(function->function_bindings());
+ ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
+ return *isolate->factory()->NewJSArrayWithElements(bindings);
+ }
+ }
+ return isolate->heap()->undefined_value();
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
HandleScope scope(isolate);
- ASSERT(args.length() == 2);
+ ASSERT(args.length() == 1);
// First argument is a function to use as a constructor.
CONVERT_ARG_CHECKED(JSFunction, function, 0);
-
- // Second argument is either null or an array of bound arguments.
- Handle<FixedArray> bound_args;
- int bound_argc = 0;
- if (!args[1]->IsNull()) {
- CONVERT_ARG_CHECKED(JSArray, params, 1);
- RUNTIME_ASSERT(params->HasFastTypeElements());
- bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
- bound_argc = Smi::cast(params->length())->value();
- }
+ RUNTIME_ASSERT(function->shared()->bound());
+
+ // The argument is a bound function. Extract its bound arguments
+ // and callable.
+ Handle<FixedArray> bound_args =
+ Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
+ int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
+ Handle<Object> bound_function(
+ JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
+ ASSERT(!bound_function->IsJSFunction() ||
+ !Handle<JSFunction>::cast(bound_function)->shared()->bound());
int total_argc = 0;
SmartArrayPointer<Handle<Object> > param_data =
- GetNonBoundArguments(bound_argc, &total_argc);
+ GetCallerArguments(bound_argc, &total_argc);
for (int i = 0; i < bound_argc; i++) {
- Handle<Object> val = Handle<Object>(bound_args->get(i));
- param_data[i] = val;
+ param_data[i] = Handle<Object>(bound_args->get(
+ JSFunction::kBoundArgumentsStartIndex + i));
}
+ if (!bound_function->IsJSFunction()) {
+ bool exception_thrown;
+ bound_function = Execution::TryGetConstructorDelegate(bound_function,
+ &exception_thrown);
+ if (exception_thrown) return Failure::Exception();
+ }
+ ASSERT(bound_function->IsJSFunction());
+
bool exception = false;
Handle<Object> result =
- Execution::New(function, total_argc, *param_data, &exception);
+ Execution::New(Handle<JSFunction>::cast(bound_function),
+ total_argc, *param_data, &exception);
if (exception) {
- return Failure::Exception();
+ return Failure::Exception();
}
-
ASSERT(!result.is_null());
return *result;
}
@@ -8011,7 +8185,8 @@ static void TrySettingInlineConstructStub(Isolate* isolate,
prototype = Handle<Object>(function->instance_prototype(), isolate);
}
if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
- ConstructStubCompiler compiler;
+ HandleScope scope(isolate);
+ ConstructStubCompiler compiler(isolate);
MaybeObject* code = compiler.CompileConstructStub(*function);
if (!code->IsFailure()) {
function->shared()->set_construct_stub(
@@ -8075,9 +8250,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
// available. We cannot use EnsureCompiled because that forces a
// compilation through the shared function info which makes it
// impossible for us to optimize.
- Handle<SharedFunctionInfo> shared(function->shared(), isolate);
- if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
+ if (!function->is_compiled()) {
+ JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
+ }
+ Handle<SharedFunctionInfo> shared(function->shared(), isolate);
if (!function->has_initial_map() &&
shared->IsInobjectSlackTrackingInProgress()) {
// The tracking is already in progress for another function. We can only
@@ -8128,7 +8305,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
// Compile the target function.
ASSERT(!function->is_compiled());
- if (!CompileLazy(function, KEEP_EXCEPTION)) {
+ if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
return Failure::Exception();
}
@@ -8165,7 +8342,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
function->ReplaceCode(function->shared()->code());
return function->code();
}
- if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
+ if (JSFunction::CompileOptimized(function,
+ AstNode::kNoNumber,
+ CLEAR_EXCEPTION)) {
return function->code();
}
if (FLAG_trace_opt) {
@@ -8406,7 +8585,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
// Try to compile the optimized code. A true return value from
// CompileOptimized means that compilation succeeded, not necessarily
// that optimization succeeded.
- if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
+ if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
function->IsOptimized()) {
DeoptimizationInputData* data = DeoptimizationInputData::cast(
function->code()->deoptimization_data());
@@ -8762,13 +8941,26 @@ static ObjectPair LoadContextSlotHelper(Arguments args,
Handle<Object> receiver = isolate->factory()->the_hole_value();
Object* value = Context::cast(*holder)->get(index);
// Check for uninitialized bindings.
- if (binding_flags == MUTABLE_CHECK_INITIALIZED && value->IsTheHole()) {
- Handle<Object> reference_error =
- isolate->factory()->NewReferenceError("not_defined",
- HandleVector(&name, 1));
- return MakePair(isolate->Throw(*reference_error), NULL);
- } else {
- return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
+ switch (binding_flags) {
+ case MUTABLE_CHECK_INITIALIZED:
+ case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
+ if (value->IsTheHole()) {
+ Handle<Object> reference_error =
+ isolate->factory()->NewReferenceError("not_defined",
+ HandleVector(&name, 1));
+ return MakePair(isolate->Throw(*reference_error), NULL);
+ }
+ // FALLTHROUGH
+ case MUTABLE_IS_INITIALIZED:
+ case IMMUTABLE_IS_INITIALIZED:
+ case IMMUTABLE_IS_INITIALIZED_HARMONY:
+ ASSERT(!value->IsTheHole());
+ return MakePair(value, *receiver);
+ case IMMUTABLE_CHECK_INITIALIZED:
+ return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
+ case MISSING_BINDING:
+ UNREACHABLE();
+ return MakePair(NULL, NULL);
}
}
@@ -8947,42 +9139,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
}
-// NOTE: These PrintXXX functions are defined for all builds (not just
-// DEBUG builds) because we may want to be able to trace function
-// calls in all modes.
-static void PrintString(String* str) {
- // not uncommon to have empty strings
- if (str->length() > 0) {
- SmartArrayPointer<char> s =
- str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
- PrintF("%s", *s);
- }
-}
-
-
-static void PrintObject(Object* obj) {
- if (obj->IsSmi()) {
- PrintF("%d", Smi::cast(obj)->value());
- } else if (obj->IsString() || obj->IsSymbol()) {
- PrintString(String::cast(obj));
- } else if (obj->IsNumber()) {
- PrintF("%g", obj->Number());
- } else if (obj->IsFailure()) {
- PrintF("<failure>");
- } else if (obj->IsUndefined()) {
- PrintF("<undefined>");
- } else if (obj->IsNull()) {
- PrintF("<null>");
- } else if (obj->IsTrue()) {
- PrintF("<true>");
- } else if (obj->IsFalse()) {
- PrintF("<false>");
- } else {
- PrintF("%p", reinterpret_cast<void*>(obj));
- }
-}
-
-
static int StackSize() {
int n = 0;
for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
@@ -9001,38 +9157,33 @@ static void PrintTransition(Object* result) {
}
if (result == NULL) {
- // constructor calls
- JavaScriptFrameIterator it;
- JavaScriptFrame* frame = it.frame();
- if (frame->IsConstructor()) PrintF("new ");
- // function name
- Object* fun = frame->function();
- if (fun->IsJSFunction()) {
- PrintObject(JSFunction::cast(fun)->shared()->name());
- } else {
- PrintObject(fun);
- }
- // function arguments
- // (we are intentionally only printing the actually
- // supplied parameters, not all parameters required)
- PrintF("(this=");
- PrintObject(frame->receiver());
- const int length = frame->ComputeParametersCount();
- for (int i = 0; i < length; i++) {
- PrintF(", ");
- PrintObject(frame->GetParameter(i));
- }
- PrintF(") {\n");
-
+ JavaScriptFrame::PrintTop(stdout, true, false);
+ PrintF(" {\n");
} else {
// function result
PrintF("} -> ");
- PrintObject(result);
+ result->ShortPrint();
PrintF("\n");
}
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceElementsKindTransition) {
+ ASSERT(args.length() == 5);
+ CONVERT_ARG_CHECKED(JSObject, obj, 0);
+ CONVERT_SMI_ARG_CHECKED(from_kind, 1);
+ CONVERT_ARG_CHECKED(FixedArrayBase, from_elements, 2);
+ CONVERT_SMI_ARG_CHECKED(to_kind, 3);
+ CONVERT_ARG_CHECKED(FixedArrayBase, to_elements, 4);
+ NoHandleAllocation ha;
+ PrintF("*");
+ obj->PrintElementsTransition(stdout,
+ static_cast<ElementsKind>(from_kind), *from_elements,
+ static_cast<ElementsKind>(to_kind), *to_elements);
+ return isolate->heap()->undefined_value();
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
ASSERT(args.length() == 0);
NoHandleAllocation ha;
@@ -9781,8 +9932,8 @@ static bool IterateElements(Isolate* isolate,
} else if (receiver->HasElement(j)) {
// Call GetElement on receiver, not its prototype, or getters won't
// have the correct receiver.
- element_value = GetElement(receiver, j);
- if (element_value.is_null()) return false;
+ element_value = Object::GetElement(receiver, j);
+ RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
visitor->visit(j, element_value);
}
}
@@ -9800,8 +9951,8 @@ static bool IterateElements(Isolate* isolate,
while (j < n) {
HandleScope loop_scope;
uint32_t index = indices[j];
- Handle<Object> element = GetElement(receiver, index);
- if (element.is_null()) return false;
+ Handle<Object> element = Object::GetElement(receiver, index);
+ RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
visitor->visit(index, element);
// Skip to next different index (i.e., omit duplicates).
do {
@@ -10051,9 +10202,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
}
Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
- Handle<Object> tmp1 = GetElement(jsobject, index1);
+ Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
- Handle<Object> tmp2 = GetElement(jsobject, index2);
+ Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
RETURN_IF_EMPTY_HANDLE(isolate,
@@ -10078,7 +10229,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
if (array->elements()->IsDictionary()) {
// Create an array and get all the keys into it, then remove all the
// keys that are not integers in the range 0 to length-1.
- Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
+ bool threw = false;
+ Handle<FixedArray> keys =
+ GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
+ if (threw) return Failure::Exception();
+
int keys_length = keys->length();
for (int i = 0; i < keys_length; i++) {
Object* key = keys->get(i);
@@ -10303,7 +10458,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
// Try local lookup on each of the objects.
Handle<JSObject> jsproto = obj;
for (int i = 0; i < length; i++) {
- LookupResult result;
+ LookupResult result(isolate);
jsproto->LocalLookup(*name, &result);
if (result.IsProperty()) {
// LookupResult is not GC safe as it holds raw object pointers.
@@ -10360,7 +10515,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
CONVERT_ARG_CHECKED(JSObject, obj, 0);
CONVERT_ARG_CHECKED(String, name, 1);
- LookupResult result;
+ LookupResult result(isolate);
obj->Lookup(*name, &result);
if (result.IsProperty()) {
return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
@@ -10897,7 +11052,11 @@ static Handle<JSObject> MaterializeLocalScope(
if (function_context->has_extension() &&
!function_context->IsGlobalContext()) {
Handle<JSObject> ext(JSObject::cast(function_context->extension()));
- Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
+ bool threw = false;
+ Handle<FixedArray> keys =
+ GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
+ if (threw) return Handle<JSObject>();
+
for (int i = 0; i < keys->length(); i++) {
// Names of variables introduced by eval are strings.
ASSERT(keys->get(i)->IsString());
@@ -10945,7 +11104,11 @@ static Handle<JSObject> MaterializeClosure(Isolate* isolate,
// be variables introduced by eval.
if (context->has_extension()) {
Handle<JSObject> ext(JSObject::cast(context->extension()));
- Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
+ bool threw = false;
+ Handle<FixedArray> keys =
+ GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
+ if (threw) return Handle<JSObject>();
+
for (int i = 0; i < keys->length(); i++) {
// Names of variables introduced by eval are strings.
ASSERT(keys->get(i)->IsString());
@@ -11010,9 +11173,10 @@ static Handle<JSObject> MaterializeBlockScope(
}
-// Iterate over the actual scopes visible from a stack frame. All scopes are
+// Iterate over the actual scopes visible from a stack frame. The iteration
+// proceeds from the innermost visible nested scope outwards. All scopes are
// backed by an actual context except the local scope, which is inserted
-// "artifically" in the context chain.
+// "artificially" in the context chain.
class ScopeIterator {
public:
enum ScopeType {
@@ -11032,28 +11196,52 @@ class ScopeIterator {
inlined_frame_index_(inlined_frame_index),
function_(JSFunction::cast(frame->function())),
context_(Context::cast(frame->context())),
- local_done_(false),
- at_local_(false) {
+ nested_scope_chain_(4) {
- // Check whether the first scope is actually a local scope.
- // If there is a stack slot for .result then this local scope has been
- // created for evaluating top level code and it is not a real local scope.
+ // Catch the case when the debugger stops in an internal function.
+ Handle<SharedFunctionInfo> shared_info(function_->shared());
+ if (shared_info->script() == isolate->heap()->undefined_value()) {
+ while (context_->closure() == *function_) {
+ context_ = Handle<Context>(context_->previous(), isolate_);
+ }
+ return;
+ }
+
+ // Check whether we are in global code or function code. If there is a stack
+ // slot for .result then this function has been created for evaluating
+ // global code and it is not a real function.
// Checking for the existence of .result seems fragile, but the scope info
// saved with the code object does not otherwise have that information.
- int index = function_->shared()->scope_info()->
+ int index = shared_info->scope_info()->
StackSlotIndex(isolate_->heap()->result_symbol());
+
+ // Reparse the code and analyze the scopes.
+ ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
+ Handle<Script> script(Script::cast(shared_info->script()));
+ Scope* scope;
if (index >= 0) {
- local_done_ = true;
- } else if (context_->IsGlobalContext() ||
- context_->IsFunctionContext()) {
- at_local_ = true;
- } else if (context_->closure() != *function_) {
- // The context_ is a block or with or catch block from the outer function.
- ASSERT(context_->IsWithContext() ||
- context_->IsCatchContext() ||
- context_->IsBlockContext());
- at_local_ = true;
+ // Global code
+ CompilationInfo info(script);
+ info.MarkAsGlobal();
+ bool result = ParserApi::Parse(&info);
+ ASSERT(result);
+ result = Scope::Analyze(&info);
+ ASSERT(result);
+ scope = info.function()->scope();
+ } else {
+ // Function code
+ CompilationInfo info(shared_info);
+ bool result = ParserApi::Parse(&info);
+ ASSERT(result);
+ result = Scope::Analyze(&info);
+ ASSERT(result);
+ scope = info.function()->scope();
}
+
+ // Retrieve the scope chain for the current position.
+ int statement_position =
+ shared_info->code()->SourceStatementPosition(frame_->pc());
+ scope->GetNestedScopeChain(&nested_scope_chain_, statement_position);
}
// More scopes?
@@ -11061,40 +11249,48 @@ class ScopeIterator {
// Move to the next scope.
void Next() {
- // If at a local scope mark the local scope as passed.
- if (at_local_) {
- at_local_ = false;
- local_done_ = true;
-
- // If the current context is not associated with the local scope the
- // current context is the next real scope, so don't move to the next
- // context in this case.
- if (context_->closure() != *function_) {
- return;
- }
- }
-
- // The global scope is always the last in the chain.
- if (context_->IsGlobalContext()) {
+ ScopeType scope_type = Type();
+ if (scope_type == ScopeTypeGlobal) {
+ // The global scope is always the last in the chain.
+ ASSERT(context_->IsGlobalContext());
context_ = Handle<Context>();
return;
}
-
- // Move to the next context.
- context_ = Handle<Context>(context_->previous(), isolate_);
-
- // If passing the local scope indicate that the current scope is now the
- // local scope.
- if (!local_done_ &&
- (context_->IsGlobalContext() || context_->IsFunctionContext())) {
- at_local_ = true;
+ if (nested_scope_chain_.is_empty()) {
+ context_ = Handle<Context>(context_->previous(), isolate_);
+ } else {
+ if (nested_scope_chain_.last()->HasContext()) {
+ context_ = Handle<Context>(context_->previous(), isolate_);
+ }
+ nested_scope_chain_.RemoveLast();
}
}
// Return the type of the current scope.
ScopeType Type() {
- if (at_local_) {
- return ScopeTypeLocal;
+ if (!nested_scope_chain_.is_empty()) {
+ Handle<SerializedScopeInfo> scope_info = nested_scope_chain_.last();
+ switch (scope_info->Type()) {
+ case FUNCTION_SCOPE:
+ ASSERT(context_->IsFunctionContext() ||
+ !scope_info->HasContext());
+ return ScopeTypeLocal;
+ case GLOBAL_SCOPE:
+ ASSERT(context_->IsGlobalContext());
+ return ScopeTypeGlobal;
+ case WITH_SCOPE:
+ ASSERT(context_->IsWithContext());
+ return ScopeTypeWith;
+ case CATCH_SCOPE:
+ ASSERT(context_->IsCatchContext());
+ return ScopeTypeCatch;
+ case BLOCK_SCOPE:
+ ASSERT(!scope_info->HasContext() ||
+ context_->IsBlockContext());
+ return ScopeTypeBlock;
+ case EVAL_SCOPE:
+ UNREACHABLE();
+ }
}
if (context_->IsGlobalContext()) {
ASSERT(context_->global()->IsGlobalObject());
@@ -11120,6 +11316,7 @@ class ScopeIterator {
return Handle<JSObject>(CurrentContext()->global());
case ScopeIterator::ScopeTypeLocal:
// Materialize the content of the local scope into a JSObject.
+ ASSERT(nested_scope_chain_.length() == 1);
return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
case ScopeIterator::ScopeTypeWith:
// Return the with object.
@@ -11136,13 +11333,30 @@ class ScopeIterator {
return Handle<JSObject>();
}
+ Handle<SerializedScopeInfo> CurrentScopeInfo() {
+ if (!nested_scope_chain_.is_empty()) {
+ return nested_scope_chain_.last();
+ } else if (context_->IsBlockContext()) {
+ return Handle<SerializedScopeInfo>(
+ SerializedScopeInfo::cast(context_->extension()));
+ } else if (context_->IsFunctionContext()) {
+ return Handle<SerializedScopeInfo>(
+ context_->closure()->shared()->scope_info());
+ }
+ return Handle<SerializedScopeInfo>::null();
+ }
+
// Return the context for this scope. For the local context there might not
// be an actual context.
Handle<Context> CurrentContext() {
- if (at_local_ && context_->closure() != *function_) {
+ if (Type() == ScopeTypeGlobal ||
+ nested_scope_chain_.is_empty()) {
+ return context_;
+ } else if (nested_scope_chain_.last()->HasContext()) {
+ return context_;
+ } else {
return Handle<Context>();
}
- return context_;
}
#ifdef DEBUG
@@ -11205,8 +11419,7 @@ class ScopeIterator {
int inlined_frame_index_;
Handle<JSFunction> function_;
Handle<Context> context_;
- bool local_done_;
- bool at_local_;
+ List<Handle<SerializedScopeInfo> > nested_scope_chain_;
DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
};
@@ -11521,7 +11734,7 @@ Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
if (!done) {
// If the candidate is not compiled compile it to reveal any inner
// functions which might contain the requested source position.
- CompileLazyShared(target, KEEP_EXCEPTION);
+ SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
}
} // End while loop.
@@ -11669,46 +11882,65 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
// Creates a copy of the with context chain. The copy of the context chain is
// is linked to the function context supplied.
-static Handle<Context> CopyWithContextChain(Isolate* isolate,
- Handle<JSFunction> function,
- Handle<Context> current,
- Handle<Context> base) {
- // At the end of the chain. Return the base context to link to.
- if (current->IsFunctionContext() || current->IsGlobalContext()) {
- return base;
+static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
+ Handle<JSFunction> function,
+ Handle<Context> base,
+ JavaScriptFrame* frame,
+ int inlined_frame_index) {
+ HandleScope scope(isolate);
+ List<Handle<SerializedScopeInfo> > scope_chain;
+ List<Handle<Context> > context_chain;
+
+ ScopeIterator it(isolate, frame, inlined_frame_index);
+ for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
+ it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
+ ASSERT(!it.Done());
+ scope_chain.Add(it.CurrentScopeInfo());
+ context_chain.Add(it.CurrentContext());
}
- // Recursively copy the with and catch contexts.
- HandleScope scope(isolate);
- Handle<Context> previous(current->previous());
- Handle<Context> new_previous =
- CopyWithContextChain(isolate, function, previous, base);
- Handle<Context> new_current;
- if (current->IsCatchContext()) {
- Handle<String> name(String::cast(current->extension()));
- Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
- new_current =
- isolate->factory()->NewCatchContext(function,
- new_previous,
- name,
- thrown_object);
- } else if (current->IsBlockContext()) {
- Handle<SerializedScopeInfo> scope_info(
- SerializedScopeInfo::cast(current->extension()));
- new_current =
- isolate->factory()->NewBlockContext(function, new_previous, scope_info);
- // Copy context slots.
- int num_context_slots = scope_info->NumberOfContextSlots();
- for (int i = Context::MIN_CONTEXT_SLOTS; i < num_context_slots; ++i) {
- new_current->set(i, current->get(i));
+ // At the end of the chain. Return the base context to link to.
+ Handle<Context> context = base;
+
+ // Iteratively copy and or materialize the nested contexts.
+ while (!scope_chain.is_empty()) {
+ Handle<SerializedScopeInfo> scope_info = scope_chain.RemoveLast();
+ Handle<Context> current = context_chain.RemoveLast();
+ ASSERT(!(scope_info->HasContext() & current.is_null()));
+
+ if (scope_info->Type() == CATCH_SCOPE) {
+ Handle<String> name(String::cast(current->extension()));
+ Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
+ context =
+ isolate->factory()->NewCatchContext(function,
+ context,
+ name,
+ thrown_object);
+ } else if (scope_info->Type() == BLOCK_SCOPE) {
+ // Materialize the contents of the block scope into a JSObject.
+ Handle<JSObject> block_scope_object =
+ MaterializeBlockScope(isolate, current);
+ if (block_scope_object.is_null()) {
+ return Handle<Context>::null();
+ }
+ // Allocate a new function context for the debug evaluation and set the
+ // extension object.
+ Handle<Context> new_context =
+ isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
+ function);
+ new_context->set_extension(*block_scope_object);
+ new_context->set_previous(*context);
+ context = new_context;
+ } else {
+ ASSERT(scope_info->Type() == WITH_SCOPE);
+ ASSERT(current->IsWithContext());
+ Handle<JSObject> extension(JSObject::cast(current->extension()));
+ context =
+ isolate->factory()->NewWithContext(function, context, extension);
}
- } else {
- ASSERT(current->IsWithContext());
- Handle<JSObject> extension(JSObject::cast(current->extension()));
- new_current =
- isolate->factory()->NewWithContext(function, new_previous, extension);
}
- return scope.CloseAndEscape(new_current);
+
+ return scope.CloseAndEscape(context);
}
@@ -11846,7 +12078,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
if (scope_info->HasHeapAllocatedLocals()) {
function_context = Handle<Context>(frame_context->declaration_context());
}
- context = CopyWithContextChain(isolate, go_between, frame_context, context);
+ context = CopyNestedScopeContextChain(isolate,
+ go_between,
+ context,
+ frame,
+ inlined_frame_index);
if (additional_context->IsJSObject()) {
Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
@@ -12245,7 +12481,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
// Get the function and make sure it is compiled.
CONVERT_ARG_CHECKED(JSFunction, func, 0);
Handle<SharedFunctionInfo> shared(func->shared());
- if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
+ if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
return Failure::Exception();
}
func->code()->PrintLn();
@@ -12261,7 +12497,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
// Get the function and make sure it is compiled.
CONVERT_ARG_CHECKED(JSFunction, func, 0);
Handle<SharedFunctionInfo> shared(func->shared());
- if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
+ if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
return Failure::Exception();
}
shared->construct_stub()->PrintLn();
@@ -12867,34 +13103,32 @@ static bool ShowFrameInStackTrace(StackFrame* raw_frame,
Object* caller,
bool* seen_caller) {
// Only display JS frames.
- if (!raw_frame->is_java_script())
+ if (!raw_frame->is_java_script()) {
return false;
+ }
JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
Object* raw_fun = frame->function();
// Not sure when this can happen but skip it just in case.
- if (!raw_fun->IsJSFunction())
+ if (!raw_fun->IsJSFunction()) {
return false;
+ }
if ((raw_fun == caller) && !(*seen_caller)) {
*seen_caller = true;
return false;
}
// Skip all frames until we've seen the caller.
if (!(*seen_caller)) return false;
- // Also, skip the most obvious builtin calls. We recognize builtins
- // as (1) functions called with the builtins object as the receiver and
- // as (2) functions from native scripts called with undefined as the
- // receiver (direct calls to helper functions in the builtins
- // code). Some builtin calls (such as Number.ADD which is invoked
- // using 'call') are very difficult to recognize so we're leaving
- // them in for now.
- if (frame->receiver()->IsJSBuiltinsObject()) {
- return false;
- }
- JSFunction* fun = JSFunction::cast(raw_fun);
- Object* raw_script = fun->shared()->script();
- if (frame->receiver()->IsUndefined() && raw_script->IsScript()) {
- int script_type = Script::cast(raw_script)->type()->value();
- return script_type != Script::TYPE_NATIVE;
+ // Also, skip non-visible built-in functions and any call with the builtins
+ // object as receiver, so as to not reveal either the builtins object or
+ // an internal function.
+ // The --builtins-in-stack-traces command line flag allows including
+ // internal call sites in the stack trace for debugging purposes.
+ if (!FLAG_builtins_in_stack_traces) {
+ JSFunction* fun = JSFunction::cast(raw_fun);
+ if (frame->receiver()->IsJSBuiltinsObject() ||
+ (fun->IsBuiltin() && !fun->shared()->native())) {
+ return false;
+ }
}
return true;
}
@@ -13041,7 +13275,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
}
#ifdef DEBUG
- cache_handle->JSFunctionResultCacheVerify();
+ if (FLAG_verify_heap) {
+ cache_handle->JSFunctionResultCacheVerify();
+ }
#endif
// Function invocation may have cleared the cache. Reread all the data.
@@ -13070,7 +13306,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
cache_handle->set_finger_index(index);
#ifdef DEBUG
- cache_handle->JSFunctionResultCacheVerify();
+ if (FLAG_verify_heap) {
+ cache_handle->JSFunctionResultCacheVerify();
+ }
#endif
return *value;
diff --git a/deps/v8/src/runtime.h b/deps/v8/src/runtime.h
index ed9c2b8891..67fc6282a2 100644
--- a/deps/v8/src/runtime.h
+++ b/deps/v8/src/runtime.h
@@ -211,14 +211,14 @@ namespace internal {
/* Reflection */ \
F(FunctionSetInstanceClassName, 2, 1) \
F(FunctionSetLength, 2, 1) \
- F(BoundFunctionSetLength, 2, 1) \
F(FunctionSetPrototype, 2, 1) \
F(FunctionSetReadOnlyPrototype, 1, 1) \
F(FunctionGetName, 1, 1) \
F(FunctionSetName, 2, 1) \
F(FunctionNameShouldPrintAsAnonymous, 1, 1) \
F(FunctionMarkNameShouldPrintAsAnonymous, 1, 1) \
- F(FunctionSetBound, 1, 1) \
+ F(FunctionBindArguments, 4, 1) \
+ F(BoundFunctionGetBindings, 1, 1) \
F(FunctionRemovePrototype, 1, 1) \
F(FunctionGetSourceCode, 1, 1) \
F(FunctionGetScript, 1, 1) \
@@ -278,7 +278,7 @@ namespace internal {
\
/* Literals */ \
F(MaterializeRegExpLiteral, 4, 1)\
- F(CreateArrayLiteralBoilerplate, 3, 1) \
+ F(CreateArrayLiteralBoilerplate, 4, 1) \
F(CloneLiteralBoilerplate, 1, 1) \
F(CloneShallowLiteralBoilerplate, 1, 1) \
F(CreateObjectLiteral, 4, 1) \
@@ -296,6 +296,17 @@ namespace internal {
F(GetConstructTrap, 1, 1) \
F(Fix, 1, 1) \
\
+ /* Harmony sets */ \
+ F(SetInitialize, 1, 1) \
+ F(SetAdd, 2, 1) \
+ F(SetHas, 2, 1) \
+ F(SetDelete, 2, 1) \
+ \
+ /* Harmony maps */ \
+ F(MapInitialize, 1, 1) \
+ F(MapGet, 2, 1) \
+ F(MapSet, 3, 1) \
+ \
/* Harmony weakmaps */ \
F(WeakMapInitialize, 1, 1) \
F(WeakMapGet, 2, 1) \
@@ -304,7 +315,7 @@ namespace internal {
/* Statements */ \
F(NewClosure, 3, 1) \
F(NewObject, 1, 1) \
- F(NewObjectFromBound, 2, 1) \
+ F(NewObjectFromBound, 1, 1) \
F(FinalizeInstanceSize, 1, 1) \
F(Throw, 1, 1) \
F(ReThrow, 1, 1) \
@@ -330,11 +341,10 @@ namespace internal {
F(InitializeConstContextSlot, 3, 1) \
F(OptimizeObjectForAddingMultipleProperties, 2, 1) \
\
- /* Arrays */ \
- F(NonSmiElementStored, 1, 1) \
/* Debugging */ \
F(DebugPrint, 1, 1) \
F(DebugTrace, 0, 1) \
+ F(TraceElementsKindTransition, 5, 1) \
F(TraceEnter, 0, 1) \
F(TraceExit, 1, 1) \
F(Abort, 2, 1) \
@@ -370,6 +380,8 @@ namespace internal {
F(HasExternalUnsignedIntElements, 1, 1) \
F(HasExternalFloatElements, 1, 1) \
F(HasExternalDoubleElements, 1, 1) \
+ F(TransitionElementsSmiToDouble, 1, 1) \
+ F(TransitionElementsDoubleToObject, 1, 1) \
F(HaveSameMap, 2, 1) \
/* profiler */ \
F(ProfilerResume, 0, 1) \
@@ -628,16 +640,14 @@ class Runtime : public AllStatic {
static bool IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch);
- // TODO(1240886): The following three methods are *not* handle safe,
- // but accept handle arguments. This seems fragile.
+ // TODO(1240886): Some of the following methods are *not* handle safe, but
+ // accept handle arguments. This seems fragile.
// Support getting the characters in a string using [] notation as
// in Firefox/SpiderMonkey, Safari and Opera.
MUST_USE_RESULT static MaybeObject* GetElementOrCharAt(Isolate* isolate,
Handle<Object> object,
uint32_t index);
- MUST_USE_RESULT static MaybeObject* GetElement(Handle<Object> object,
- uint32_t index);
MUST_USE_RESULT static MaybeObject* SetObjectProperty(
Isolate* isolate,
@@ -677,11 +687,9 @@ class Runtime : public AllStatic {
//---------------------------------------------------------------------------
// Constants used by interface to runtime functions.
-enum kDeclareGlobalsFlags {
- kDeclareGlobalsEvalFlag = 1 << 0,
- kDeclareGlobalsStrictModeFlag = 1 << 1,
- kDeclareGlobalsNativeFlag = 1 << 2
-};
+class DeclareGlobalsEvalFlag: public BitField<bool, 0, 1> {};
+class DeclareGlobalsStrictModeFlag: public BitField<StrictModeFlag, 1, 1> {};
+class DeclareGlobalsNativeFlag: public BitField<bool, 2, 1> {};
} } // namespace v8::internal
diff --git a/deps/v8/src/runtime.js b/deps/v8/src/runtime.js
index a12f6c7b09..108b928ea8 100644
--- a/deps/v8/src/runtime.js
+++ b/deps/v8/src/runtime.js
@@ -375,6 +375,12 @@ function INSTANCE_OF(F) {
return 1;
}
+ // Check if function is bound, if so, get [[BoundFunction]] from it
+ // and use that instead of F.
+ var bindings = %BoundFunctionGetBindings(F);
+ if (bindings) {
+ F = bindings[kBoundFunctionIndex]; // Always a non-bound function.
+ }
// Get the prototype of F; if it is not an object, throw an error.
var O = F.prototype;
if (!IS_SPEC_OBJECT(O)) {
@@ -386,13 +392,6 @@ function INSTANCE_OF(F) {
}
-// Get an array of property keys for the given object. Used in
-// for-in statements.
-function GET_KEYS() {
- return %GetPropertyNames(this);
-}
-
-
// Filter a given key against an object by checking if the object
// has a property with the given key; return the key as a string if
// it has. Otherwise returns 0 (smi). Used in for-in statements.
@@ -463,7 +462,7 @@ function APPLY_PREPARE(args) {
}
// Make sure the arguments list has the right type.
- if (args != null && !IS_ARRAY(args) && !IS_ARGUMENTS(args)) {
+ if (args != null && !IS_SPEC_OBJECT(args)) {
throw %MakeTypeError('apply_wrong_args', []);
}
diff --git a/deps/v8/src/scanner.h b/deps/v8/src/scanner.h
index 6651c38755..a2e64a9d20 100644
--- a/deps/v8/src/scanner.h
+++ b/deps/v8/src/scanner.h
@@ -41,6 +41,17 @@
namespace v8 {
namespace internal {
+
+// General collection of bit-flags that can be passed to scanners and
+// parsers to signify their (initial) mode of operation.
+enum ParsingFlags {
+ kNoParsingFlags = 0,
+ kAllowLazy = 1,
+ kAllowNativesSyntax = 2,
+ kHarmonyScoping = 4
+};
+
+
// Returns the value (0 .. 15) of a hexadecimal character c.
// If c is not a legal hexadecimal character, returns a value < 0.
inline int HexValue(uc32 c) {
diff --git a/deps/v8/src/scopeinfo.cc b/deps/v8/src/scopeinfo.cc
index 1aa51603db..8ea5f1e734 100644
--- a/deps/v8/src/scopeinfo.cc
+++ b/deps/v8/src/scopeinfo.cc
@@ -51,6 +51,7 @@ ScopeInfo<Allocator>::ScopeInfo(Scope* scope)
: function_name_(FACTORY->empty_symbol()),
calls_eval_(scope->calls_eval()),
is_strict_mode_(scope->is_strict_mode()),
+ type_(scope->type()),
parameters_(scope->num_parameters()),
stack_slots_(scope->num_stack_slots()),
context_slots_(scope->num_heap_slots()),
@@ -138,7 +139,7 @@ ScopeInfo<Allocator>::ScopeInfo(Scope* scope)
ASSERT(proxy->var()->index() - Context::MIN_CONTEXT_SLOTS ==
context_modes_.length());
context_slots_.Add(FACTORY->empty_symbol());
- context_modes_.Add(INTERNAL);
+ context_modes_.Add(proxy->var()->mode());
}
}
}
@@ -150,6 +151,10 @@ ScopeInfo<Allocator>::ScopeInfo(Scope* scope)
//
// - calls eval boolean flag
//
+// - is strict mode scope
+//
+// - scope type
+//
// - number of variables in the context object (smi) (= function context
// slot index + 1)
// - list of pairs (name, Var mode) of context-allocated variables (starting
@@ -181,8 +186,9 @@ ScopeInfo<Allocator>::ScopeInfo(Scope* scope)
// present)
-static inline Object** ReadInt(Object** p, int* x) {
- *x = (reinterpret_cast<Smi*>(*p++))->value();
+template <class T>
+static inline Object** ReadInt(Object** p, T* x) {
+ *x = static_cast<T>((reinterpret_cast<Smi*>(*p++))->value());
return p;
}
@@ -193,20 +199,21 @@ static inline Object** ReadBool(Object** p, bool* x) {
}
-static inline Object** ReadSymbol(Object** p, Handle<String>* s) {
- *s = Handle<String>(reinterpret_cast<String*>(*p++));
+template <class T>
+static inline Object** ReadObject(Object** p, Handle<T>* s) {
+ *s = Handle<T>::cast(Handle<Object>(*p++));
return p;
}
-template <class Allocator>
-static Object** ReadList(Object** p, List<Handle<String>, Allocator >* list) {
+template <class Allocator, class T>
+static Object** ReadList(Object** p, List<Handle<T>, Allocator >* list) {
ASSERT(list->is_empty());
int n;
p = ReadInt(p, &n);
while (n-- > 0) {
- Handle<String> s;
- p = ReadSymbol(p, &s);
+ Handle<T> s;
+ p = ReadObject(p, &s);
list->Add(s);
}
return p;
@@ -223,7 +230,7 @@ static Object** ReadList(Object** p,
while (n-- > 0) {
Handle<String> s;
int m;
- p = ReadSymbol(p, &s);
+ p = ReadObject(p, &s);
p = ReadInt(p, &m);
list->Add(s);
modes->Add(static_cast<VariableMode>(m));
@@ -242,9 +249,10 @@ ScopeInfo<Allocator>::ScopeInfo(SerializedScopeInfo* data)
if (data->length() > 0) {
Object** p0 = data->data_start();
Object** p = p0;
- p = ReadSymbol(p, &function_name_);
+ p = ReadObject(p, &function_name_);
p = ReadBool(p, &calls_eval_);
p = ReadBool(p, &is_strict_mode_);
+ p = ReadInt(p, &type_);
p = ReadList<Allocator>(p, &context_slots_, &context_modes_);
p = ReadList<Allocator>(p, &parameters_);
p = ReadList<Allocator>(p, &stack_slots_);
@@ -265,18 +273,19 @@ static inline Object** WriteBool(Object** p, bool b) {
}
-static inline Object** WriteSymbol(Object** p, Handle<String> s) {
+template <class T>
+static inline Object** WriteObject(Object** p, Handle<T> s) {
*p++ = *s;
return p;
}
-template <class Allocator>
-static Object** WriteList(Object** p, List<Handle<String>, Allocator >* list) {
+template <class Allocator, class T>
+static Object** WriteList(Object** p, List<Handle<T>, Allocator >* list) {
const int n = list->length();
p = WriteInt(p, n);
for (int i = 0; i < n; i++) {
- p = WriteSymbol(p, list->at(i));
+ p = WriteObject(p, list->at(i));
}
return p;
}
@@ -289,7 +298,7 @@ static Object** WriteList(Object** p,
const int n = list->length();
p = WriteInt(p, n);
for (int i = 0; i < n; i++) {
- p = WriteSymbol(p, list->at(i));
+ p = WriteObject(p, list->at(i));
p = WriteInt(p, modes->at(i));
}
return p;
@@ -298,8 +307,9 @@ static Object** WriteList(Object** p,
template<class Allocator>
Handle<SerializedScopeInfo> ScopeInfo<Allocator>::Serialize() {
- // function name, calls eval, is_strict_mode, length for 3 tables:
- const int extra_slots = 1 + 1 + 1 + 3;
+ // function name, calls eval, is_strict_mode, scope type,
+ // length for 3 tables:
+ const int extra_slots = 1 + 1 + 1 + 1 + 3;
int length = extra_slots +
context_slots_.length() * 2 +
parameters_.length() +
@@ -311,9 +321,10 @@ Handle<SerializedScopeInfo> ScopeInfo<Allocator>::Serialize() {
Object** p0 = data->data_start();
Object** p = p0;
- p = WriteSymbol(p, function_name_);
+ p = WriteObject(p, function_name_);
p = WriteBool(p, calls_eval_);
p = WriteBool(p, is_strict_mode_);
+ p = WriteInt(p, type_);
p = WriteList(p, &context_slots_, &context_modes_);
p = WriteList(p, &parameters_);
p = WriteList(p, &stack_slots_);
@@ -361,8 +372,8 @@ SerializedScopeInfo* SerializedScopeInfo::Empty() {
Object** SerializedScopeInfo::ContextEntriesAddr() {
ASSERT(length() > 0);
- // +3 for function name, calls eval, strict mode.
- return data_start() + 3;
+ // +4 for function name, calls eval, strict mode, scope type.
+ return data_start() + 4;
}
@@ -406,6 +417,16 @@ bool SerializedScopeInfo::IsStrictMode() {
}
+ScopeType SerializedScopeInfo::Type() {
+ ASSERT(length() > 0);
+ // +3 for function name, calls eval, strict mode.
+ Object** p = data_start() + 3;
+ ScopeType type;
+ p = ReadInt(p, &type);
+ return type;
+}
+
+
int SerializedScopeInfo::NumberOfStackSlots() {
if (length() > 0) {
Object** p = StackSlotEntriesAddr();
@@ -439,6 +460,12 @@ bool SerializedScopeInfo::HasHeapAllocatedLocals() {
}
+bool SerializedScopeInfo::HasContext() {
+ return HasHeapAllocatedLocals() ||
+ Type() == WITH_SCOPE;
+}
+
+
int SerializedScopeInfo::StackSlotIndex(String* name) {
ASSERT(name->IsSymbol());
if (length() > 0) {
@@ -513,16 +540,24 @@ int SerializedScopeInfo::ParameterIndex(String* name) {
}
-int SerializedScopeInfo::FunctionContextSlotIndex(String* name) {
+int SerializedScopeInfo::FunctionContextSlotIndex(String* name,
+ VariableMode* mode) {
ASSERT(name->IsSymbol());
if (length() > 0) {
Object** p = data_start();
if (*p == name) {
p = ContextEntriesAddr();
int number_of_context_slots;
- ReadInt(p, &number_of_context_slots);
+ p = ReadInt(p, &number_of_context_slots);
ASSERT(number_of_context_slots != 0);
// The function context slot is the last entry.
+ if (mode != NULL) {
+ // Seek to context slot entry.
+ p += (number_of_context_slots - 1) * 2;
+ // Seek to mode.
+ ++p;
+ ReadInt(p, mode);
+ }
return number_of_context_slots + Context::MIN_CONTEXT_SLOTS - 1;
}
}
diff --git a/deps/v8/src/scopeinfo.h b/deps/v8/src/scopeinfo.h
index 03f321be7d..eeb30475f4 100644
--- a/deps/v8/src/scopeinfo.h
+++ b/deps/v8/src/scopeinfo.h
@@ -35,17 +35,10 @@
namespace v8 {
namespace internal {
-// Scope information represents information about a functions's
-// scopes (currently only one, because we don't do any inlining)
-// and the allocation of the scope's variables. Scope information
-// is stored in a compressed form in FixedArray objects and is used
+// ScopeInfo represents information about different scopes of a source
+// program and the allocation of the scope's variables. Scope information
+// is stored in a compressed form in SerializedScopeInfo objects and is used
// at runtime (stack dumps, deoptimization, etc.).
-//
-// Historical note: In other VMs built by this team, ScopeInfo was
-// usually called DebugInfo since the information was used (among
-// other things) for on-demand debugging (Self, Smalltalk). However,
-// DebugInfo seems misleading, since this information is primarily used
-// in debugging-unrelated contexts.
// Forward defined as
// template <class Allocator = FreeStoreAllocationPolicy> class ScopeInfo;
@@ -83,6 +76,7 @@ class ScopeInfo BASE_EMBEDDED {
Handle<String> LocalName(int i) const;
int NumberOfLocals() const;
+ ScopeType type() const { return type_; }
// --------------------------------------------------------------------------
// Debugging support
@@ -94,6 +88,7 @@ class ScopeInfo BASE_EMBEDDED {
Handle<String> function_name_;
bool calls_eval_;
bool is_strict_mode_;
+ ScopeType type_;
List<Handle<String>, Allocator > parameters_;
List<Handle<String>, Allocator > stack_slots_;
List<Handle<String>, Allocator > context_slots_;
diff --git a/deps/v8/src/scopes.cc b/deps/v8/src/scopes.cc
index e67b7f8267..3167c4d092 100644
--- a/deps/v8/src/scopes.cc
+++ b/deps/v8/src/scopes.cc
@@ -114,7 +114,7 @@ Variable* VariableMap::Lookup(Handle<String> name) {
// Dummy constructor
-Scope::Scope(Type type)
+Scope::Scope(ScopeType type)
: isolate_(Isolate::Current()),
inner_scopes_(0),
variables_(false),
@@ -127,7 +127,7 @@ Scope::Scope(Type type)
}
-Scope::Scope(Scope* outer_scope, Type type)
+Scope::Scope(Scope* outer_scope, ScopeType type)
: isolate_(Isolate::Current()),
inner_scopes_(4),
variables_(),
@@ -146,7 +146,7 @@ Scope::Scope(Scope* outer_scope, Type type)
Scope::Scope(Scope* inner_scope,
- Type type,
+ ScopeType type,
Handle<SerializedScopeInfo> scope_info)
: isolate_(Isolate::Current()),
inner_scopes_(4),
@@ -156,9 +156,8 @@ Scope::Scope(Scope* inner_scope,
unresolved_(16),
decls_(4),
already_resolved_(true) {
- ASSERT(!scope_info.is_null());
SetDefaults(type, NULL, scope_info);
- if (scope_info->HasHeapAllocatedLocals()) {
+ if (!scope_info.is_null() && scope_info->HasHeapAllocatedLocals()) {
num_heap_slots_ = scope_info_->NumberOfContextSlots();
}
AddInnerScope(inner_scope);
@@ -186,7 +185,7 @@ Scope::Scope(Scope* inner_scope, Handle<String> catch_variable_name)
}
-void Scope::SetDefaults(Type type,
+void Scope::SetDefaults(ScopeType type,
Scope* outer_scope,
Handle<SerializedScopeInfo> scope_info) {
outer_scope_ = outer_scope;
@@ -201,16 +200,17 @@ void Scope::SetDefaults(Type type,
scope_contains_with_ = false;
scope_calls_eval_ = false;
// Inherit the strict mode from the parent scope.
- strict_mode_ = (outer_scope != NULL) && outer_scope->strict_mode_;
- outer_scope_calls_eval_ = false;
+ strict_mode_flag_ = (outer_scope != NULL)
+ ? outer_scope->strict_mode_flag_ : kNonStrictMode;
outer_scope_calls_non_strict_eval_ = false;
inner_scope_calls_eval_ = false;
- outer_scope_is_eval_scope_ = false;
force_eager_compilation_ = false;
num_var_or_const_ = 0;
num_stack_slots_ = 0;
num_heap_slots_ = 0;
scope_info_ = scope_info;
+ start_position_ = RelocInfo::kNoPosition;
+ end_position_ = RelocInfo::kNoPosition;
}
@@ -224,30 +224,31 @@ Scope* Scope::DeserializeScopeChain(CompilationInfo* info,
bool contains_with = false;
while (!context->IsGlobalContext()) {
if (context->IsWithContext()) {
+ Scope* with_scope = new Scope(current_scope, WITH_SCOPE,
+ Handle<SerializedScopeInfo>::null());
+ current_scope = with_scope;
// All the inner scopes are inside a with.
contains_with = true;
for (Scope* s = innermost_scope; s != NULL; s = s->outer_scope()) {
s->scope_inside_with_ = true;
}
+ } else if (context->IsFunctionContext()) {
+ SerializedScopeInfo* scope_info =
+ context->closure()->shared()->scope_info();
+ current_scope = new Scope(current_scope, FUNCTION_SCOPE,
+ Handle<SerializedScopeInfo>(scope_info));
+ } else if (context->IsBlockContext()) {
+ SerializedScopeInfo* scope_info =
+ SerializedScopeInfo::cast(context->extension());
+ current_scope = new Scope(current_scope, BLOCK_SCOPE,
+ Handle<SerializedScopeInfo>(scope_info));
} else {
- if (context->IsFunctionContext()) {
- SerializedScopeInfo* scope_info =
- context->closure()->shared()->scope_info();
- current_scope = new Scope(current_scope, FUNCTION_SCOPE,
- Handle<SerializedScopeInfo>(scope_info));
- } else if (context->IsBlockContext()) {
- SerializedScopeInfo* scope_info =
- SerializedScopeInfo::cast(context->extension());
- current_scope = new Scope(current_scope, BLOCK_SCOPE,
- Handle<SerializedScopeInfo>(scope_info));
- } else {
- ASSERT(context->IsCatchContext());
- String* name = String::cast(context->extension());
- current_scope = new Scope(current_scope, Handle<String>(name));
- }
- if (contains_with) current_scope->RecordWithStatement();
- if (innermost_scope == NULL) innermost_scope = current_scope;
+ ASSERT(context->IsCatchContext());
+ String* name = String::cast(context->extension());
+ current_scope = new Scope(current_scope, Handle<String>(name));
}
+ if (contains_with) current_scope->RecordWithStatement();
+ if (innermost_scope == NULL) innermost_scope = current_scope;
// Forget about a with when we move to a context for a different function.
if (context->previous()->closure() != context->closure()) {
@@ -281,15 +282,15 @@ bool Scope::Analyze(CompilationInfo* info) {
}
-void Scope::Initialize(bool inside_with) {
+void Scope::Initialize() {
ASSERT(!already_resolved());
// Add this scope as a new inner scope of the outer scope.
if (outer_scope_ != NULL) {
outer_scope_->inner_scopes_.Add(this);
- scope_inside_with_ = outer_scope_->scope_inside_with_ || inside_with;
+ scope_inside_with_ = outer_scope_->scope_inside_with_ || is_with_scope();
} else {
- scope_inside_with_ = inside_with;
+ scope_inside_with_ = is_with_scope();
}
// Declare convenience variables.
@@ -300,13 +301,7 @@ void Scope::Initialize(bool inside_with) {
// instead load them directly from the stack. Currently, the only
// such parameter is 'this' which is passed on the stack when
// invoking scripts
- if (is_catch_scope() || is_block_scope()) {
- ASSERT(outer_scope() != NULL);
- receiver_ = outer_scope()->receiver();
- } else {
- ASSERT(is_function_scope() ||
- is_global_scope() ||
- is_eval_scope());
+ if (is_declaration_scope()) {
Variable* var =
variables_.Declare(this,
isolate_->factory()->this_symbol(),
@@ -315,6 +310,9 @@ void Scope::Initialize(bool inside_with) {
Variable::THIS);
var->AllocateTo(Variable::PARAMETER, -1);
receiver_ = var;
+ } else {
+ ASSERT(outer_scope() != NULL);
+ receiver_ = outer_scope()->receiver();
}
if (is_function_scope()) {
@@ -381,7 +379,7 @@ Variable* Scope::LocalLookup(Handle<String> name) {
index = scope_info_->ParameterIndex(*name);
if (index < 0) {
// Check the function name.
- index = scope_info_->FunctionContextSlotIndex(*name);
+ index = scope_info_->FunctionContextSlotIndex(*name, NULL);
if (index < 0) return NULL;
}
}
@@ -404,10 +402,10 @@ Variable* Scope::Lookup(Handle<String> name) {
}
-Variable* Scope::DeclareFunctionVar(Handle<String> name) {
+Variable* Scope::DeclareFunctionVar(Handle<String> name, VariableMode mode) {
ASSERT(is_function_scope() && function_ == NULL);
Variable* function_var =
- new Variable(this, name, CONST, true, Variable::NORMAL);
+ new Variable(this, name, mode, true, Variable::NORMAL);
function_ = new(isolate_->zone()) VariableProxy(isolate_, function_var);
return function_var;
}
@@ -427,7 +425,10 @@ Variable* Scope::DeclareLocal(Handle<String> name, VariableMode mode) {
// This function handles VAR and CONST modes. DYNAMIC variables are
// introduces during variable allocation, INTERNAL variables are allocated
// explicitly, and TEMPORARY variables are allocated via NewTemporary().
- ASSERT(mode == VAR || mode == CONST || mode == LET);
+ ASSERT(mode == VAR ||
+ mode == CONST ||
+ mode == CONST_HARMONY ||
+ mode == LET);
++num_var_or_const_;
return variables_.Declare(this, name, mode, true, Variable::NORMAL);
}
@@ -441,15 +442,13 @@ Variable* Scope::DeclareGlobal(Handle<String> name) {
}
-VariableProxy* Scope::NewUnresolved(Handle<String> name,
- bool inside_with,
- int position) {
+VariableProxy* Scope::NewUnresolved(Handle<String> name, int position) {
// Note that we must not share the unresolved variables with
// the same name because they may be removed selectively via
// RemoveUnresolved().
ASSERT(!already_resolved());
VariableProxy* proxy = new(isolate_->zone()) VariableProxy(
- isolate_, name, false, inside_with, position);
+ isolate_, name, false, position);
unresolved_.Add(proxy);
return proxy;
}
@@ -505,17 +504,19 @@ Declaration* Scope::CheckConflictingVarDeclarations() {
Declaration* decl = decls_[i];
if (decl->mode() != VAR) continue;
Handle<String> name = decl->proxy()->name();
- bool cond = true;
- for (Scope* scope = decl->scope(); cond ; scope = scope->outer_scope_) {
+
+ // Iterate through all scopes until and including the declaration scope.
+ Scope* previous = NULL;
+ Scope* current = decl->scope();
+ do {
// There is a conflict if there exists a non-VAR binding.
- Variable* other_var = scope->variables_.Lookup(name);
+ Variable* other_var = current->variables_.Lookup(name);
if (other_var != NULL && other_var->mode() != VAR) {
return decl;
}
-
- // Include declaration scope in the iteration but stop after.
- if (!scope->is_block_scope() && !scope->is_catch_scope()) cond = false;
- }
+ previous = current;
+ current = current->outer_scope_;
+ } while (!previous->is_declaration_scope());
}
return NULL;
}
@@ -563,16 +564,11 @@ void Scope::AllocateVariables(Handle<Context> context) {
// this information in the ScopeInfo and then use it here (by traversing
// the call chain stack, at compile time).
- bool eval_scope = is_eval_scope();
- bool outer_scope_calls_eval = false;
bool outer_scope_calls_non_strict_eval = false;
if (!is_global_scope()) {
- context->ComputeEvalScopeInfo(&outer_scope_calls_eval,
- &outer_scope_calls_non_strict_eval);
+ context->ComputeEvalScopeInfo(&outer_scope_calls_non_strict_eval);
}
- PropagateScopeInfo(outer_scope_calls_eval,
- outer_scope_calls_non_strict_eval,
- eval_scope);
+ PropagateScopeInfo(outer_scope_calls_non_strict_eval);
// 2) Resolve variables.
Scope* global_scope = NULL;
@@ -625,8 +621,7 @@ int Scope::ContextChainLength(Scope* scope) {
Scope* Scope::DeclarationScope() {
Scope* scope = this;
- while (scope->is_catch_scope() ||
- scope->is_block_scope()) {
+ while (!scope->is_declaration_scope()) {
scope = scope->outer_scope();
}
return scope;
@@ -641,14 +636,33 @@ Handle<SerializedScopeInfo> Scope::GetSerializedScopeInfo() {
}
+void Scope::GetNestedScopeChain(
+ List<Handle<SerializedScopeInfo> >* chain,
+ int position) {
+ chain->Add(Handle<SerializedScopeInfo>(GetSerializedScopeInfo()));
+
+ for (int i = 0; i < inner_scopes_.length(); i++) {
+ Scope* scope = inner_scopes_[i];
+ int beg_pos = scope->start_position();
+ int end_pos = scope->end_position();
+ ASSERT(beg_pos >= 0 && end_pos >= 0);
+ if (beg_pos <= position && position <= end_pos) {
+ scope->GetNestedScopeChain(chain, position);
+ return;
+ }
+ }
+}
+
+
#ifdef DEBUG
-static const char* Header(Scope::Type type) {
+static const char* Header(ScopeType type) {
switch (type) {
- case Scope::EVAL_SCOPE: return "eval";
- case Scope::FUNCTION_SCOPE: return "function";
- case Scope::GLOBAL_SCOPE: return "global";
- case Scope::CATCH_SCOPE: return "catch";
- case Scope::BLOCK_SCOPE: return "block";
+ case EVAL_SCOPE: return "eval";
+ case FUNCTION_SCOPE: return "function";
+ case GLOBAL_SCOPE: return "global";
+ case CATCH_SCOPE: return "catch";
+ case BLOCK_SCOPE: return "block";
+ case WITH_SCOPE: return "with";
}
UNREACHABLE();
return NULL;
@@ -748,14 +762,10 @@ void Scope::Print(int n) {
if (scope_inside_with_) Indent(n1, "// scope inside 'with'\n");
if (scope_contains_with_) Indent(n1, "// scope contains 'with'\n");
if (scope_calls_eval_) Indent(n1, "// scope calls 'eval'\n");
- if (outer_scope_calls_eval_) Indent(n1, "// outer scope calls 'eval'\n");
if (outer_scope_calls_non_strict_eval_) {
Indent(n1, "// outer scope calls 'eval' in non-strict context\n");
}
if (inner_scope_calls_eval_) Indent(n1, "// inner scope calls 'eval'\n");
- if (outer_scope_is_eval_scope_) {
- Indent(n1, "// outer scope is 'eval' scope\n");
- }
if (num_stack_slots_ > 0) { Indent(n1, "// ");
PrintF("%d stack slots\n", num_stack_slots_); }
if (num_heap_slots_ > 0) { Indent(n1, "// ");
@@ -809,74 +819,68 @@ Variable* Scope::NonLocal(Handle<String> name, VariableMode mode) {
}
-// Lookup a variable starting with this scope. The result is either
-// the statically resolved variable belonging to an outer scope, or
-// NULL. It may be NULL because a) we couldn't find a variable, or b)
-// because the variable is just a guess (and may be shadowed by
-// another variable that is introduced dynamically via an 'eval' call
-// or a 'with' statement).
Variable* Scope::LookupRecursive(Handle<String> name,
- bool from_inner_scope,
- Variable** invalidated_local) {
- // If we find a variable, but the current scope calls 'eval', the found
- // variable may not be the correct one (the 'eval' may introduce a
- // property with the same name). In that case, remember that the variable
- // found is just a guess.
- bool guess = scope_calls_eval_;
-
+ Handle<Context> context,
+ BindingKind* binding_kind) {
+ ASSERT(binding_kind != NULL);
// Try to find the variable in this scope.
Variable* var = LocalLookup(name);
+ // We found a variable and we are done. (Even if there is an 'eval' in
+ // this scope which introduces the same variable again, the resulting
+ // variable remains the same.)
if (var != NULL) {
- // We found a variable. If this is not an inner lookup, we are done.
- // (Even if there is an 'eval' in this scope which introduces the
- // same variable again, the resulting variable remains the same.
- // Note that enclosing 'with' statements are handled at the call site.)
- if (!from_inner_scope)
- return var;
-
- } else {
- // We did not find a variable locally. Check against the function variable,
- // if any. We can do this for all scopes, since the function variable is
- // only present - if at all - for function scopes.
- //
- // This lookup corresponds to a lookup in the "intermediate" scope sitting
- // between this scope and the outer scope. (ECMA-262, 3rd., requires that
- // the name of named function literal is kept in an intermediate scope
- // in between this scope and the next outer scope.)
- if (function_ != NULL && function_->name().is_identical_to(name)) {
- var = function_->var();
-
- } else if (outer_scope_ != NULL) {
- var = outer_scope_->LookupRecursive(name, true, invalidated_local);
- // We may have found a variable in an outer scope. However, if
- // the current scope is inside a 'with', the actual variable may
- // be a property introduced via the 'with' statement. Then, the
- // variable we may have found is just a guess.
- if (scope_inside_with_)
- guess = true;
- }
-
- // If we did not find a variable, we are done.
- if (var == NULL)
- return NULL;
+ *binding_kind = BOUND;
+ return var;
}
- ASSERT(var != NULL);
-
- // If this is a lookup from an inner scope, mark the variable.
- if (from_inner_scope) {
- var->MarkAsAccessedFromInnerScope();
+ // We did not find a variable locally. Check against the function variable,
+ // if any. We can do this for all scopes, since the function variable is
+ // only present - if at all - for function scopes.
+ //
+ // This lookup corresponds to a lookup in the "intermediate" scope sitting
+ // between this scope and the outer scope. (ECMA-262, 3rd., requires that
+ // the name of named function literal is kept in an intermediate scope
+ // in between this scope and the next outer scope.)
+ *binding_kind = UNBOUND;
+ if (function_ != NULL && function_->name().is_identical_to(name)) {
+ var = function_->var();
+ *binding_kind = BOUND;
+ } else if (outer_scope_ != NULL) {
+ var = outer_scope_->LookupRecursive(name, context, binding_kind);
+ if (*binding_kind == BOUND) var->MarkAsAccessedFromInnerScope();
}
- // If the variable we have found is just a guess, invalidate the
- // result. If the found variable is local, record that fact so we
- // can generate fast code to get it if it is not shadowed by eval.
- if (guess) {
- if (!var->is_global()) *invalidated_local = var;
- var = NULL;
+ if (is_with_scope()) {
+ // The current scope is a with scope, so the variable binding can not be
+ // statically resolved. However, note that it was necessary to do a lookup
+ // in the outer scope anyway, because if a binding exists in an outer scope,
+ // the associated variable has to be marked as potentially being accessed
+ // from inside of an inner with scope (the property may not be in the 'with'
+ // object).
+ *binding_kind = DYNAMIC_LOOKUP;
+ return NULL;
+ } else if (is_eval_scope()) {
+ // No local binding was found, no 'with' statements have been encountered
+ // and the code is executed as part of a call to 'eval'. The calling context
+ // contains scope information that we can use to determine if the variable
+ // is global, i.e. the calling context chain does not contain a binding and
+ // no 'with' contexts.
+ ASSERT(*binding_kind == UNBOUND);
+ *binding_kind = context->GlobalIfNotShadowedByEval(name)
+ ? UNBOUND_EVAL_SHADOWED : DYNAMIC_LOOKUP;
+ return NULL;
+ } else if (calls_non_strict_eval()) {
+ // A variable binding may have been found in an outer scope, but the current
+ // scope makes a non-strict 'eval' call, so the found variable may not be
+ // the correct one (the 'eval' may introduce a binding with the same name).
+ // In that case, change the lookup result to reflect this situation.
+ if (*binding_kind == BOUND) {
+ *binding_kind = BOUND_EVAL_SHADOWED;
+ } else if (*binding_kind == UNBOUND) {
+ *binding_kind = UNBOUND_EVAL_SHADOWED;
+ }
}
-
return var;
}
@@ -891,71 +895,44 @@ void Scope::ResolveVariable(Scope* global_scope,
if (proxy->var() != NULL) return;
// Otherwise, try to resolve the variable.
- Variable* invalidated_local = NULL;
- Variable* var = LookupRecursive(proxy->name(), false, &invalidated_local);
-
- if (proxy->inside_with()) {
- // If we are inside a local 'with' statement, all bets are off
- // and we cannot resolve the proxy to a local variable even if
- // we found an outer matching variable.
- // Note that we must do a lookup anyway, because if we find one,
- // we must mark that variable as potentially accessed from this
- // inner scope (the property may not be in the 'with' object).
- var = NonLocal(proxy->name(), DYNAMIC);
-
- } else {
- // We are not inside a local 'with' statement.
-
- if (var == NULL) {
- // We did not find the variable. We have a global variable
- // if we are in the global scope (we know already that we
- // are outside a 'with' statement) or if there is no way
- // that the variable might be introduced dynamically (through
- // a local or outer eval() call, or an outer 'with' statement),
- // or we don't know about the outer scope (because we are
- // in an eval scope).
- if (is_global_scope() ||
- !(scope_inside_with_ || outer_scope_is_eval_scope_ ||
- scope_calls_eval_ || outer_scope_calls_eval_)) {
- // We must have a global variable.
- ASSERT(global_scope != NULL);
- var = global_scope->DeclareGlobal(proxy->name());
-
- } else if (scope_inside_with_) {
- // If we are inside a with statement we give up and look up
- // the variable at runtime.
- var = NonLocal(proxy->name(), DYNAMIC);
-
- } else if (invalidated_local != NULL) {
- // No with statements are involved and we found a local
- // variable that might be shadowed by eval introduced
- // variables.
- var = NonLocal(proxy->name(), DYNAMIC_LOCAL);
- var->set_local_if_not_shadowed(invalidated_local);
-
- } else if (outer_scope_is_eval_scope_) {
- // No with statements and we did not find a local and the code
- // is executed with a call to eval. The context contains
- // scope information that we can use to determine if the
- // variable is global if it is not shadowed by eval-introduced
- // variables.
- if (context->GlobalIfNotShadowedByEval(proxy->name())) {
- var = NonLocal(proxy->name(), DYNAMIC_GLOBAL);
-
- } else {
- var = NonLocal(proxy->name(), DYNAMIC);
- }
+ BindingKind binding_kind;
+ Variable* var = LookupRecursive(proxy->name(), context, &binding_kind);
+ switch (binding_kind) {
+ case BOUND:
+ // We found a variable binding.
+ break;
- } else {
- // No with statements and we did not find a local and the code
- // is not executed with a call to eval. We know that this
- // variable is global unless it is shadowed by eval-introduced
- // variables.
+ case BOUND_EVAL_SHADOWED:
+ // We found a variable variable binding that might be shadowed
+ // by 'eval' introduced variable bindings.
+ if (var->is_global()) {
var = NonLocal(proxy->name(), DYNAMIC_GLOBAL);
+ } else {
+ Variable* invalidated = var;
+ var = NonLocal(proxy->name(), DYNAMIC_LOCAL);
+ var->set_local_if_not_shadowed(invalidated);
}
- }
+ break;
+
+ case UNBOUND:
+ // No binding has been found. Declare a variable in global scope.
+ ASSERT(global_scope != NULL);
+ var = global_scope->DeclareGlobal(proxy->name());
+ break;
+
+ case UNBOUND_EVAL_SHADOWED:
+ // No binding has been found. But some scope makes a
+ // non-strict 'eval' call.
+ var = NonLocal(proxy->name(), DYNAMIC_GLOBAL);
+ break;
+
+ case DYNAMIC_LOOKUP:
+ // The variable could not be resolved statically.
+ var = NonLocal(proxy->name(), DYNAMIC);
+ break;
}
+ ASSERT(var != NULL);
proxy->BindTo(var);
}
@@ -976,31 +953,17 @@ void Scope::ResolveVariablesRecursively(Scope* global_scope,
}
-bool Scope::PropagateScopeInfo(bool outer_scope_calls_eval,
- bool outer_scope_calls_non_strict_eval,
- bool outer_scope_is_eval_scope) {
- if (outer_scope_calls_eval) {
- outer_scope_calls_eval_ = true;
- }
-
+bool Scope::PropagateScopeInfo(bool outer_scope_calls_non_strict_eval ) {
if (outer_scope_calls_non_strict_eval) {
outer_scope_calls_non_strict_eval_ = true;
}
- if (outer_scope_is_eval_scope) {
- outer_scope_is_eval_scope_ = true;
- }
-
- bool calls_eval = scope_calls_eval_ || outer_scope_calls_eval_;
- bool is_eval = is_eval_scope() || outer_scope_is_eval_scope_;
bool calls_non_strict_eval =
(scope_calls_eval_ && !is_strict_mode()) ||
outer_scope_calls_non_strict_eval_;
for (int i = 0; i < inner_scopes_.length(); i++) {
Scope* inner_scope = inner_scopes_[i];
- if (inner_scope->PropagateScopeInfo(calls_eval,
- calls_non_strict_eval,
- is_eval)) {
+ if (inner_scope->PropagateScopeInfo(calls_non_strict_eval)) {
inner_scope_calls_eval_ = true;
}
if (inner_scope->force_eager_compilation_) {
diff --git a/deps/v8/src/scopes.h b/deps/v8/src/scopes.h
index 7e789b8bd0..a1418874e9 100644
--- a/deps/v8/src/scopes.h
+++ b/deps/v8/src/scopes.h
@@ -89,15 +89,7 @@ class Scope: public ZoneObject {
// ---------------------------------------------------------------------------
// Construction
- enum Type {
- EVAL_SCOPE, // The top-level scope for an eval source.
- FUNCTION_SCOPE, // The top-level scope for a function.
- GLOBAL_SCOPE, // The top-level scope for a program or a top-level eval.
- CATCH_SCOPE, // The scope introduced by catch.
- BLOCK_SCOPE // The scope introduced by a new block.
- };
-
- Scope(Scope* outer_scope, Type type);
+ Scope(Scope* outer_scope, ScopeType type);
// Compute top scope and allocate variables. For lazy compilation the top
// scope only contains the single lazily compiled function, so this
@@ -110,7 +102,7 @@ class Scope: public ZoneObject {
// The scope name is only used for printing/debugging.
void SetScopeName(Handle<String> scope_name) { scope_name_ = scope_name; }
- void Initialize(bool inside_with);
+ void Initialize();
// Checks if the block scope is redundant, i.e. it does not contain any
// block scoped declarations. In that case it is removed from the scope
@@ -130,7 +122,7 @@ class Scope: public ZoneObject {
// Declare the function variable for a function literal. This variable
// is in an intermediate scope between this function scope and the the
// outer scope. Only possible for function scopes; at most one variable.
- Variable* DeclareFunctionVar(Handle<String> name);
+ Variable* DeclareFunctionVar(Handle<String> name, VariableMode mode);
// Declare a parameter in this scope. When there are duplicated
// parameters the rightmost one 'wins'. However, the implementation
@@ -149,7 +141,6 @@ class Scope: public ZoneObject {
// Create a new unresolved variable.
VariableProxy* NewUnresolved(Handle<String> name,
- bool inside_with,
int position = RelocInfo::kNoPosition);
// Remove a unresolved variable. During parsing, an unresolved variable
@@ -199,11 +190,42 @@ class Scope: public ZoneObject {
void RecordWithStatement() { scope_contains_with_ = true; }
// Inform the scope that the corresponding code contains an eval call.
- void RecordEvalCall() { scope_calls_eval_ = true; }
+ void RecordEvalCall() { if (!is_global_scope()) scope_calls_eval_ = true; }
- // Enable strict mode for the scope (unless disabled by a global flag).
- void EnableStrictMode() {
- strict_mode_ = FLAG_strict_mode;
+ // Set the strict mode flag (unless disabled by a global flag).
+ void SetStrictModeFlag(StrictModeFlag strict_mode_flag) {
+ strict_mode_flag_ = FLAG_strict_mode ? strict_mode_flag : kNonStrictMode;
+ }
+
+ // Position in the source where this scope begins and ends.
+ //
+ // * For the scope of a with statement
+ // with (obj) stmt
+ // start position: start position of first token of 'stmt'
+ // end position: end position of last token of 'stmt'
+ // * For the scope of a block
+ // { stmts }
+ // start position: start position of '{'
+ // end position: end position of '}'
+ // * For the scope of a function literal or decalaration
+ // function fun(a,b) { stmts }
+ // start position: start position of '('
+ // end position: end position of '}'
+ // * For the scope of a catch block
+ // try { stms } catch(e) { stmts }
+ // start position: start position of '('
+ // end position: end position of ')'
+ // * For the scope of a for-statement
+ // for (let x ...) stmt
+ // start position: start position of '('
+ // end position: end position of last token of 'stmt'
+ int start_position() const { return start_position_; }
+ void set_start_position(int statement_pos) {
+ start_position_ = statement_pos;
+ }
+ int end_position() const { return end_position_; }
+ void set_end_position(int statement_pos) {
+ end_position_ = statement_pos;
}
// ---------------------------------------------------------------------------
@@ -215,14 +237,20 @@ class Scope: public ZoneObject {
bool is_global_scope() const { return type_ == GLOBAL_SCOPE; }
bool is_catch_scope() const { return type_ == CATCH_SCOPE; }
bool is_block_scope() const { return type_ == BLOCK_SCOPE; }
- bool is_strict_mode() const { return strict_mode_; }
+ bool is_with_scope() const { return type_ == WITH_SCOPE; }
+ bool is_declaration_scope() const {
+ return is_eval_scope() || is_function_scope() || is_global_scope();
+ }
+ bool is_strict_mode() const { return strict_mode_flag() == kStrictMode; }
bool is_strict_mode_eval_scope() const {
return is_eval_scope() && is_strict_mode();
}
// Information about which scopes calls eval.
bool calls_eval() const { return scope_calls_eval_; }
- bool outer_scope_calls_eval() const { return outer_scope_calls_eval_; }
+ bool calls_non_strict_eval() {
+ return scope_calls_eval_ && !is_strict_mode();
+ }
bool outer_scope_calls_non_strict_eval() const {
return outer_scope_calls_non_strict_eval_;
}
@@ -238,6 +266,12 @@ class Scope: public ZoneObject {
// ---------------------------------------------------------------------------
// Accessors.
+ // The type of this scope.
+ ScopeType type() const { return type_; }
+
+ // The strict mode of this scope.
+ StrictModeFlag strict_mode_flag() const { return strict_mode_flag_; }
+
// The variable corresponding the 'this' value.
Variable* receiver() { return receiver_; }
@@ -264,6 +298,8 @@ class Scope: public ZoneObject {
// Declarations list.
ZoneList<Declaration*>* declarations() { return &decls_; }
+ // Inner scope list.
+ ZoneList<Scope*>* inner_scopes() { return &inner_scopes_; }
// ---------------------------------------------------------------------------
// Variable allocation.
@@ -307,6 +343,13 @@ class Scope: public ZoneObject {
Handle<SerializedScopeInfo> GetSerializedScopeInfo();
+ // Get the chain of nested scopes within this scope for the source statement
+ // position. The scopes will be added to the list from the outermost scope to
+ // the innermost scope. Only nested block, catch or with scopes are tracked
+ // and will be returned, but no inner function scopes.
+ void GetNestedScopeChain(List<Handle<SerializedScopeInfo> >* chain,
+ int statement_position);
+
// ---------------------------------------------------------------------------
// Strict mode support.
bool IsDeclared(Handle<String> name) {
@@ -330,7 +373,7 @@ class Scope: public ZoneObject {
protected:
friend class ParserFactory;
- explicit Scope(Type type);
+ explicit Scope(ScopeType type);
Isolate* const isolate_;
@@ -339,7 +382,7 @@ class Scope: public ZoneObject {
ZoneList<Scope*> inner_scopes_; // the immediately enclosed inner scopes
// The scope type.
- Type type_;
+ ScopeType type_;
// Debugging support.
Handle<String> scope_name_;
@@ -380,13 +423,14 @@ class Scope: public ZoneObject {
// the 'eval' call site this scope is the declaration scope.
bool scope_calls_eval_;
// This scope is a strict mode scope.
- bool strict_mode_;
+ StrictModeFlag strict_mode_flag_;
+ // Source positions.
+ int start_position_;
+ int end_position_;
// Computed via PropagateScopeInfo.
- bool outer_scope_calls_eval_;
bool outer_scope_calls_non_strict_eval_;
bool inner_scope_calls_eval_;
- bool outer_scope_is_eval_scope_;
bool force_eager_compilation_;
// True if it doesn't need scope resolution (e.g., if the scope was
@@ -396,7 +440,7 @@ class Scope: public ZoneObject {
// Computed as variables are declared.
int num_var_or_const_;
- // Computed via AllocateVariables; function scopes only.
+ // Computed via AllocateVariables; function, block and catch scopes only.
int num_stack_slots_;
int num_heap_slots_;
@@ -409,9 +453,57 @@ class Scope: public ZoneObject {
Variable* NonLocal(Handle<String> name, VariableMode mode);
// Variable resolution.
+ // Possible results of a recursive variable lookup telling if and how a
+ // variable is bound. These are returned in the output parameter *binding_kind
+ // of the LookupRecursive function.
+ enum BindingKind {
+ // The variable reference could be statically resolved to a variable binding
+ // which is returned. There is no 'with' statement between the reference and
+ // the binding and no scope between the reference scope (inclusive) and
+ // binding scope (exclusive) makes a non-strict 'eval' call.
+ BOUND,
+
+ // The variable reference could be statically resolved to a variable binding
+ // which is returned. There is no 'with' statement between the reference and
+ // the binding, but some scope between the reference scope (inclusive) and
+ // binding scope (exclusive) makes a non-strict 'eval' call, that might
+ // possibly introduce variable bindings shadowing the found one. Thus the
+ // found variable binding is just a guess.
+ BOUND_EVAL_SHADOWED,
+
+ // The variable reference could not be statically resolved to any binding
+ // and thus should be considered referencing a global variable. NULL is
+ // returned. The variable reference is not inside any 'with' statement and
+ // no scope between the reference scope (inclusive) and global scope
+ // (exclusive) makes a non-strict 'eval' call.
+ UNBOUND,
+
+ // The variable reference could not be statically resolved to any binding
+ // NULL is returned. The variable reference is not inside any 'with'
+ // statement, but some scope between the reference scope (inclusive) and
+ // global scope (exclusive) makes a non-strict 'eval' call, that might
+ // possibly introduce a variable binding. Thus the reference should be
+ // considered referencing a global variable unless it is shadowed by an
+ // 'eval' introduced binding.
+ UNBOUND_EVAL_SHADOWED,
+
+ // The variable could not be statically resolved and needs to be looked up
+ // dynamically. NULL is returned. There are two possible reasons:
+ // * A 'with' statement has been encountered and there is no variable
+ // binding for the name between the variable reference and the 'with'.
+ // The variable potentially references a property of the 'with' object.
+ // * The code is being executed as part of a call to 'eval' and the calling
+ // context chain contains either a variable binding for the name or it
+ // contains a 'with' context.
+ DYNAMIC_LOOKUP
+ };
+
+ // Lookup a variable reference given by name recursively starting with this
+ // scope. If the code is executed because of a call to 'eval', the context
+ // parameter should be set to the calling context of 'eval'.
Variable* LookupRecursive(Handle<String> name,
- bool from_inner_function,
- Variable** invalidated_local);
+ Handle<Context> context,
+ BindingKind* binding_kind);
void ResolveVariable(Scope* global_scope,
Handle<Context> context,
VariableProxy* proxy);
@@ -419,9 +511,7 @@ class Scope: public ZoneObject {
Handle<Context> context);
// Scope analysis.
- bool PropagateScopeInfo(bool outer_scope_calls_eval,
- bool outer_scope_calls_non_strict_eval,
- bool outer_scope_is_eval_scope);
+ bool PropagateScopeInfo(bool outer_scope_calls_non_strict_eval);
bool HasTrivialContext() const;
// Predicates.
@@ -438,8 +528,10 @@ class Scope: public ZoneObject {
void AllocateVariablesRecursively();
private:
- // Construct a function or block scope based on the scope info.
- Scope(Scope* inner_scope, Type type, Handle<SerializedScopeInfo> scope_info);
+ // Construct a scope based on the scope info.
+ Scope(Scope* inner_scope,
+ ScopeType type,
+ Handle<SerializedScopeInfo> scope_info);
// Construct a catch scope with a binding for the name.
Scope(Scope* inner_scope, Handle<String> catch_variable_name);
@@ -451,7 +543,7 @@ class Scope: public ZoneObject {
}
}
- void SetDefaults(Type type,
+ void SetDefaults(ScopeType type,
Scope* outer_scope,
Handle<SerializedScopeInfo> scope_info);
};
diff --git a/deps/v8/src/serialize.cc b/deps/v8/src/serialize.cc
index 84ab94a97d..ba7b2a5184 100644
--- a/deps/v8/src/serialize.cc
+++ b/deps/v8/src/serialize.cc
@@ -318,10 +318,10 @@ void ExternalReferenceTable::PopulateTable(Isolate* isolate) {
// Miscellaneous
- Add(ExternalReference::roots_address(isolate).address(),
+ Add(ExternalReference::roots_array_start(isolate).address(),
UNCLASSIFIED,
3,
- "Heap::roots_address()");
+ "Heap::roots_array_start()");
Add(ExternalReference::address_of_stack_limit(isolate).address(),
UNCLASSIFIED,
4,
@@ -490,6 +490,10 @@ void ExternalReferenceTable::PopulateTable(Isolate* isolate) {
UNCLASSIFIED,
44,
"canonical_nan");
+ Add(ExternalReference::address_of_the_hole_nan().address(),
+ UNCLASSIFIED,
+ 45,
+ "the_hole_nan");
}
@@ -753,8 +757,13 @@ static const int kUnknownOffsetFromStart = -1;
void Deserializer::ReadChunk(Object** current,
Object** limit,
int source_space,
- Address address) {
+ Address current_object_address) {
Isolate* const isolate = isolate_;
+ bool write_barrier_needed = (current_object_address != NULL &&
+ source_space != NEW_SPACE &&
+ source_space != CELL_SPACE &&
+ source_space != CODE_SPACE &&
+ source_space != OLD_DATA_SPACE);
while (current < limit) {
int data = source_->Get();
switch (data) {
@@ -774,9 +783,7 @@ void Deserializer::ReadChunk(Object** current,
if (where == kNewObject && how == kPlain && within == kStartOfObject) {\
ASSIGN_DEST_SPACE(space_number) \
ReadObject(space_number, dest_space, current); \
- emit_write_barrier = (space_number == NEW_SPACE && \
- source_space != NEW_SPACE && \
- source_space != CELL_SPACE); \
+ emit_write_barrier = (space_number == NEW_SPACE); \
} else { \
Object* new_object = NULL; /* May not be a real Object pointer. */ \
if (where == kNewObject) { \
@@ -784,27 +791,25 @@ void Deserializer::ReadChunk(Object** current,
ReadObject(space_number, dest_space, &new_object); \
} else if (where == kRootArray) { \
int root_id = source_->GetInt(); \
- new_object = isolate->heap()->roots_address()[root_id]; \
+ new_object = isolate->heap()->roots_array_start()[root_id]; \
+ emit_write_barrier = isolate->heap()->InNewSpace(new_object); \
} else if (where == kPartialSnapshotCache) { \
int cache_index = source_->GetInt(); \
new_object = isolate->serialize_partial_snapshot_cache() \
[cache_index]; \
+ emit_write_barrier = isolate->heap()->InNewSpace(new_object); \
} else if (where == kExternalReference) { \
int reference_id = source_->GetInt(); \
Address address = external_reference_decoder_-> \
Decode(reference_id); \
new_object = reinterpret_cast<Object*>(address); \
} else if (where == kBackref) { \
- emit_write_barrier = (space_number == NEW_SPACE && \
- source_space != NEW_SPACE && \
- source_space != CELL_SPACE); \
+ emit_write_barrier = (space_number == NEW_SPACE); \
new_object = GetAddressFromEnd(data & kSpaceMask); \
} else { \
ASSERT(where == kFromStart); \
if (offset_from_start == kUnknownOffsetFromStart) { \
- emit_write_barrier = (space_number == NEW_SPACE && \
- source_space != NEW_SPACE && \
- source_space != CELL_SPACE); \
+ emit_write_barrier = (space_number == NEW_SPACE); \
new_object = GetAddressFromStart(data & kSpaceMask); \
} else { \
Address object_address = pages_[space_number][0] + \
@@ -831,12 +836,14 @@ void Deserializer::ReadChunk(Object** current,
*current = new_object; \
} \
} \
- if (emit_write_barrier) { \
- isolate->heap()->RecordWrite(address, static_cast<int>( \
- reinterpret_cast<Address>(current) - address)); \
+ if (emit_write_barrier && write_barrier_needed) { \
+ Address current_address = reinterpret_cast<Address>(current); \
+ isolate->heap()->RecordWrite( \
+ current_object_address, \
+ static_cast<int>(current_address - current_object_address)); \
} \
if (!current_was_incremented) { \
- current++; /* Increment current if it wasn't done above. */ \
+ current++; \
} \
break; \
} \
@@ -883,11 +890,17 @@ void Deserializer::ReadChunk(Object** current,
CASE_STATEMENT(where, how, within, kLargeCode) \
CASE_BODY(where, how, within, kLargeCode, kUnknownOffsetFromStart)
-#define EMIT_COMMON_REFERENCE_PATTERNS(pseudo_space_number, \
- space_number, \
- offset_from_start) \
- CASE_STATEMENT(kFromStart, kPlain, kStartOfObject, pseudo_space_number) \
- CASE_BODY(kFromStart, kPlain, kStartOfObject, space_number, offset_from_start)
+#define FOUR_CASES(byte_code) \
+ case byte_code: \
+ case byte_code + 1: \
+ case byte_code + 2: \
+ case byte_code + 3:
+
+#define SIXTEEN_CASES(byte_code) \
+ FOUR_CASES(byte_code) \
+ FOUR_CASES(byte_code + 4) \
+ FOUR_CASES(byte_code + 8) \
+ FOUR_CASES(byte_code + 12)
// We generate 15 cases and bodies that process special tags that combine
// the raw data tag and the length into one byte.
@@ -911,6 +924,38 @@ void Deserializer::ReadChunk(Object** current,
break;
}
+ SIXTEEN_CASES(kRootArrayLowConstants)
+ SIXTEEN_CASES(kRootArrayHighConstants) {
+ int root_id = RootArrayConstantFromByteCode(data);
+ Object* object = isolate->heap()->roots_array_start()[root_id];
+ ASSERT(!isolate->heap()->InNewSpace(object));
+ *current++ = object;
+ break;
+ }
+
+ case kRepeat: {
+ int repeats = source_->GetInt();
+ Object* object = current[-1];
+ ASSERT(!isolate->heap()->InNewSpace(object));
+ for (int i = 0; i < repeats; i++) current[i] = object;
+ current += repeats;
+ break;
+ }
+
+ STATIC_ASSERT(kRootArrayNumberOfConstantEncodings ==
+ Heap::kOldSpaceRoots);
+ STATIC_ASSERT(kMaxRepeats == 12);
+ FOUR_CASES(kConstantRepeat)
+ FOUR_CASES(kConstantRepeat + 4)
+ FOUR_CASES(kConstantRepeat + 8) {
+ int repeats = RepeatsForCode(data);
+ Object* object = current[-1];
+ ASSERT(!isolate->heap()->InNewSpace(object));
+ for (int i = 0; i < repeats; i++) current[i] = object;
+ current += repeats;
+ break;
+ }
+
// Deserialize a new object and write a pointer to it to the current
// object.
ONE_PER_SPACE(kNewObject, kPlain, kStartOfObject)
@@ -936,9 +981,6 @@ void Deserializer::ReadChunk(Object** current,
// start and write a pointer to its first instruction to the current code
// object.
ALL_SPACES(kFromStart, kFromCode, kFirstInstruction)
- // Find an already deserialized object at one of the predetermined popular
- // offsets from the start and write a pointer to it in the current object.
- COMMON_REFERENCE_PATTERNS(EMIT_COMMON_REFERENCE_PATTERNS)
// Find an object in the roots array and write a pointer to it to the
// current object.
CASE_STATEMENT(kRootArray, kPlain, kStartOfObject, 0)
@@ -980,7 +1022,6 @@ void Deserializer::ReadChunk(Object** current,
#undef CASE_BODY
#undef ONE_PER_SPACE
#undef ALL_SPACES
-#undef EMIT_COMMON_REFERENCE_PATTERNS
#undef ASSIGN_DEST_SPACE
case kNewPage: {
@@ -1067,7 +1108,8 @@ Serializer::Serializer(SnapshotByteSink* sink)
: sink_(sink),
current_root_index_(0),
external_reference_encoder_(new ExternalReferenceEncoder),
- large_object_total_(0) {
+ large_object_total_(0),
+ root_index_wave_front_(0) {
// The serializer is meant to be used only to generate initial heap images
// from a context in which there is only one isolate.
ASSERT(Isolate::Current()->IsDefaultIsolate());
@@ -1124,6 +1166,10 @@ void Serializer::VisitPointers(Object** start, Object** end) {
Isolate* isolate = Isolate::Current();
for (Object** current = start; current < end; current++) {
+ if (start == isolate->heap()->roots_array_start()) {
+ root_index_wave_front_ =
+ Max(root_index_wave_front_, static_cast<intptr_t>(current - start));
+ }
if (reinterpret_cast<Address>(current) ==
isolate->heap()->store_buffer()->TopAddress()) {
sink_->Put(kSkip, "Skip");
@@ -1191,10 +1237,12 @@ int PartialSerializer::PartialSnapshotCacheIndex(HeapObject* heap_object) {
}
-int PartialSerializer::RootIndex(HeapObject* heap_object) {
- for (int i = 0; i < Heap::kRootListLength; i++) {
- Object* root = HEAP->roots_address()[i];
- if (root == heap_object) return i;
+int Serializer::RootIndex(HeapObject* heap_object) {
+ Heap* heap = HEAP;
+ if (heap->InNewSpace(heap_object)) return kInvalidRootIndex;
+ for (int i = 0; i < root_index_wave_front_; i++) {
+ Object* root = heap->roots_array_start()[i];
+ if (!root->IsSmi() && root == heap_object) return i;
}
return kInvalidRootIndex;
}
@@ -1230,18 +1278,8 @@ void Serializer::SerializeReferenceToPreviousObject(
// all objects) then we should shift out the bits that are always 0.
if (!SpaceIsLarge(space)) address >>= kObjectAlignmentBits;
if (from_start) {
-#define COMMON_REFS_CASE(pseudo_space, actual_space, offset) \
- if (space == actual_space && address == offset && \
- how_to_code == kPlain && where_to_point == kStartOfObject) { \
- sink_->Put(kFromStart + how_to_code + where_to_point + \
- pseudo_space, "RefSer"); \
- } else /* NOLINT */
- COMMON_REFERENCE_PATTERNS(COMMON_REFS_CASE)
-#undef COMMON_REFS_CASE
- { /* NOLINT */
- sink_->Put(kFromStart + how_to_code + where_to_point + space, "RefSer");
- sink_->PutInt(address, "address");
- }
+ sink_->Put(kFromStart + how_to_code + where_to_point + space, "RefSer");
+ sink_->PutInt(address, "address");
} else {
sink_->Put(kBackref + how_to_code + where_to_point + space, "BackRefSer");
sink_->PutInt(address, "address");
@@ -1256,6 +1294,12 @@ void StartupSerializer::SerializeObject(
CHECK(o->IsHeapObject());
HeapObject* heap_object = HeapObject::cast(o);
+ int root_index;
+ if ((root_index = RootIndex(heap_object)) != kInvalidRootIndex) {
+ PutRoot(root_index, heap_object, how_to_code, where_to_point);
+ return;
+ }
+
if (address_mapper_.IsMapped(heap_object)) {
int space = SpaceOfAlreadySerializedObject(heap_object);
int address = address_mapper_.MappedTo(heap_object);
@@ -1286,6 +1330,28 @@ void StartupSerializer::SerializeWeakReferences() {
}
+void Serializer::PutRoot(int root_index,
+ HeapObject* object,
+ SerializerDeserializer::HowToCode how_to_code,
+ SerializerDeserializer::WhereToPoint where_to_point) {
+ if (how_to_code == kPlain &&
+ where_to_point == kStartOfObject &&
+ root_index < kRootArrayNumberOfConstantEncodings &&
+ !HEAP->InNewSpace(object)) {
+ if (root_index < kRootArrayNumberOfLowConstantEncodings) {
+ sink_->Put(kRootArrayLowConstants + root_index, "RootLoConstant");
+ } else {
+ sink_->Put(kRootArrayHighConstants + root_index -
+ kRootArrayNumberOfLowConstantEncodings,
+ "RootHiConstant");
+ }
+ } else {
+ sink_->Put(kRootArray + how_to_code + where_to_point, "RootSerialization");
+ sink_->PutInt(root_index, "root_index");
+ }
+}
+
+
void PartialSerializer::SerializeObject(
Object* o,
HowToCode how_to_code,
@@ -1295,8 +1361,7 @@ void PartialSerializer::SerializeObject(
int root_index;
if ((root_index = RootIndex(heap_object)) != kInvalidRootIndex) {
- sink_->Put(kRootArray + how_to_code + where_to_point, "RootSerialization");
- sink_->PutInt(root_index, "root_index");
+ PutRoot(root_index, heap_object, how_to_code, where_to_point);
return;
}
@@ -1374,9 +1439,33 @@ void Serializer::ObjectSerializer::VisitPointers(Object** start,
if (current < end) OutputRawData(reinterpret_cast<Address>(current));
while (current < end && !(*current)->IsSmi()) {
- serializer_->SerializeObject(*current, kPlain, kStartOfObject);
- bytes_processed_so_far_ += kPointerSize;
- current++;
+ HeapObject* current_contents = HeapObject::cast(*current);
+ int root_index = serializer_->RootIndex(current_contents);
+ // Repeats are not subject to the write barrier so there are only some
+ // objects that can be used in a repeat encoding. These are the early
+ // ones in the root array that are never in new space.
+ if (current != start &&
+ root_index != kInvalidRootIndex &&
+ root_index < kRootArrayNumberOfConstantEncodings &&
+ current_contents == current[-1]) {
+ ASSERT(!HEAP->InNewSpace(current_contents));
+ int repeat_count = 1;
+ while (current < end - 1 && current[repeat_count] == current_contents) {
+ repeat_count++;
+ }
+ current += repeat_count;
+ bytes_processed_so_far_ += repeat_count * kPointerSize;
+ if (repeat_count > kMaxRepeats) {
+ sink_->Put(kRepeat, "SerializeRepeats");
+ sink_->PutInt(repeat_count, "SerializeRepeats");
+ } else {
+ sink_->Put(CodeForRepeats(repeat_count), "SerializeRepeats");
+ }
+ } else {
+ serializer_->SerializeObject(current_contents, kPlain, kStartOfObject);
+ bytes_processed_so_far_ += kPointerSize;
+ current++;
+ }
}
}
}
diff --git a/deps/v8/src/serialize.h b/deps/v8/src/serialize.h
index c070923326..49695ec964 100644
--- a/deps/v8/src/serialize.h
+++ b/deps/v8/src/serialize.h
@@ -187,24 +187,6 @@ class SnapshotByteSource {
};
-// It is very common to have a reference to objects at certain offsets in the
-// heap. These offsets have been determined experimentally. We code
-// references to such objects in a single byte that encodes the way the pointer
-// is written (only plain pointers allowed), the space number and the offset.
-// This only works for objects in the first page of a space. Don't use this for
-// things in newspace since it bypasses the write barrier.
-
-static const int k64 = (sizeof(uintptr_t) - 4) / 4;
-
-#define COMMON_REFERENCE_PATTERNS(f) \
- f(kNumberOfSpaces, 2, (11 - k64)) \
- f((kNumberOfSpaces + 1), 2, 0) \
- f((kNumberOfSpaces + 2), 2, (142 - 16 * k64)) \
- f((kNumberOfSpaces + 3), 2, (74 - 15 * k64)) \
- f((kNumberOfSpaces + 4), 2, 5) \
- f((kNumberOfSpaces + 5), 1, 135) \
- f((kNumberOfSpaces + 6), 2, (228 - 39 * k64))
-
#define COMMON_RAW_LENGTHS(f) \
f(1, 1) \
f(2, 2) \
@@ -242,7 +224,7 @@ class SerializerDeserializer: public ObjectVisitor {
// 0xd-0xf Free.
kBackref = 0x10, // Object is described relative to end.
// 0x11-0x18 One per space.
- // 0x19-0x1f Common backref offsets.
+ // 0x19-0x1f Free.
kFromStart = 0x20, // Object is described relative to start.
// 0x21-0x28 One per space.
// 0x29-0x2f Free.
@@ -279,9 +261,29 @@ class SerializerDeserializer: public ObjectVisitor {
// is referred to from external strings in the snapshot.
static const int kNativesStringResource = 0x71;
static const int kNewPage = 0x72;
- // 0x73-0x7f Free.
- // 0xb0-0xbf Free.
- // 0xf0-0xff Free.
+ static const int kRepeat = 0x73;
+ static const int kConstantRepeat = 0x74;
+ // 0x74-0x7f Repeat last word (subtract 0x73 to get the count).
+ static const int kMaxRepeats = 0x7f - 0x73;
+ static int CodeForRepeats(int repeats) {
+ ASSERT(repeats >= 1 && repeats <= kMaxRepeats);
+ return 0x73 + repeats;
+ }
+ static int RepeatsForCode(int byte_code) {
+ ASSERT(byte_code >= kConstantRepeat && byte_code <= 0x7f);
+ return byte_code - 0x73;
+ }
+ static const int kRootArrayLowConstants = 0xb0;
+ // 0xb0-0xbf Things from the first 16 elements of the root array.
+ static const int kRootArrayHighConstants = 0xf0;
+ // 0xf0-0xff Things from the next 16 elements of the root array.
+ static const int kRootArrayNumberOfConstantEncodings = 0x20;
+ static const int kRootArrayNumberOfLowConstantEncodings = 0x10;
+ static int RootArrayConstantFromByteCode(int byte_code) {
+ int constant = (byte_code & 0xf) | ((byte_code & 0x40) >> 2);
+ ASSERT(constant >= 0 && constant < kRootArrayNumberOfConstantEncodings);
+ return constant;
+ }
static const int kLargeData = LAST_SPACE;
@@ -354,7 +356,13 @@ class Deserializer: public SerializerDeserializer {
UNREACHABLE();
}
- void ReadChunk(Object** start, Object** end, int space, Address address);
+ // Fills in some heap data in an area from start to end (non-inclusive). The
+ // space id is used for the write barrier. The object_address is the address
+ // of the object we are writing into, or NULL if we are not writing into an
+ // object, ie if we are writing a series of tagged values that are not on the
+ // heap.
+ void ReadChunk(
+ Object** start, Object** end, int space, Address object_address);
HeapObject* GetAddressFromStart(int space);
inline HeapObject* GetAddressFromEnd(int space);
Address Allocate(int space_number, Space* space, int size);
@@ -475,14 +483,22 @@ class Serializer : public SerializerDeserializer {
static void TooLateToEnableNow() { too_late_to_enable_now_ = true; }
static bool enabled() { return serialization_enabled_; }
SerializationAddressMapper* address_mapper() { return &address_mapper_; }
+ void PutRoot(
+ int index, HeapObject* object, HowToCode how, WhereToPoint where);
#ifdef DEBUG
virtual void Synchronize(const char* tag);
#endif
protected:
static const int kInvalidRootIndex = -1;
- virtual int RootIndex(HeapObject* heap_object) = 0;
+
+ int RootIndex(HeapObject* heap_object);
virtual bool ShouldBeInThePartialSnapshotCache(HeapObject* o) = 0;
+ intptr_t root_index_wave_front() { return root_index_wave_front_; }
+ void set_root_index_wave_front(intptr_t value) {
+ ASSERT(value >= root_index_wave_front_);
+ root_index_wave_front_ = value;
+ }
class ObjectSerializer : public ObjectVisitor {
public:
@@ -558,6 +574,7 @@ class Serializer : public SerializerDeserializer {
static bool too_late_to_enable_now_;
int large_object_total_;
SerializationAddressMapper address_mapper_;
+ intptr_t root_index_wave_front_;
friend class ObjectSerializer;
friend class Deserializer;
@@ -572,6 +589,7 @@ class PartialSerializer : public Serializer {
SnapshotByteSink* sink)
: Serializer(sink),
startup_serializer_(startup_snapshot_serializer) {
+ set_root_index_wave_front(Heap::kStrongRootListLength);
}
// Serialize the objects reachable from a single object pointer.
@@ -581,7 +599,6 @@ class PartialSerializer : public Serializer {
WhereToPoint where_to_point);
protected:
- virtual int RootIndex(HeapObject* o);
virtual int PartialSnapshotCacheIndex(HeapObject* o);
virtual bool ShouldBeInThePartialSnapshotCache(HeapObject* o) {
// Scripts should be referred only through shared function infos. We can't
@@ -606,7 +623,7 @@ class StartupSerializer : public Serializer {
explicit StartupSerializer(SnapshotByteSink* sink) : Serializer(sink) {
// Clear the cache of objects used by the partial snapshot. After the
// strong roots have been serialized we can create a partial snapshot
- // which will repopulate the cache with objects neede by that partial
+ // which will repopulate the cache with objects needed by that partial
// snapshot.
Isolate::Current()->set_serialize_partial_snapshot_cache_length(0);
}
@@ -625,7 +642,6 @@ class StartupSerializer : public Serializer {
}
private:
- virtual int RootIndex(HeapObject* o) { return kInvalidRootIndex; }
virtual bool ShouldBeInThePartialSnapshotCache(HeapObject* o) {
return false;
}
diff --git a/deps/v8/src/spaces-inl.h b/deps/v8/src/spaces-inl.h
index d9e6053ad6..1973b3a350 100644
--- a/deps/v8/src/spaces-inl.h
+++ b/deps/v8/src/spaces-inl.h
@@ -257,16 +257,12 @@ HeapObject* PagedSpace::AllocateLinearly(int size_in_bytes) {
if (new_top > allocation_info_.limit) return NULL;
allocation_info_.top = new_top;
- ASSERT(allocation_info_.VerifyPagedAllocation());
- ASSERT(current_top != NULL);
return HeapObject::FromAddress(current_top);
}
// Raw allocation.
MaybeObject* PagedSpace::AllocateRaw(int size_in_bytes) {
- ASSERT(HasBeenSetup());
- ASSERT_OBJECT_SIZE(size_in_bytes);
HeapObject* object = AllocateLinearly(size_in_bytes);
if (object != NULL) {
if (identity() == CODE_SPACE) {
diff --git a/deps/v8/src/spaces.cc b/deps/v8/src/spaces.cc
index 61b318118a..f467f710ce 100644
--- a/deps/v8/src/spaces.cc
+++ b/deps/v8/src/spaces.cc
@@ -95,10 +95,6 @@ void HeapObjectIterator::Initialize(PagedSpace* space,
cur_end_ = end;
page_mode_ = mode;
size_func_ = size_f;
-
-#ifdef DEBUG
- Verify();
-#endif
}
@@ -123,13 +119,6 @@ bool HeapObjectIterator::AdvanceToNextPage() {
}
-#ifdef DEBUG
-void HeapObjectIterator::Verify() {
- // TODO(gc): We should do something here.
-}
-#endif
-
-
// -----------------------------------------------------------------------------
// CodeRange
@@ -1909,11 +1898,24 @@ intptr_t FreeList::SumFreeLists() {
bool NewSpace::ReserveSpace(int bytes) {
// We can't reliably unpack a partial snapshot that needs more new space
- // space than the minimum NewSpace size.
+ // space than the minimum NewSpace size. The limit can be set lower than
+ // the end of new space either because there is more space on the next page
+ // or because we have lowered the limit in order to get periodic incremental
+ // marking. The most reliable way to ensure that there is linear space is
+ // to do the allocation, then rewind the limit.
ASSERT(bytes <= InitialCapacity());
- Address limit = allocation_info_.limit;
+ MaybeObject* maybe = AllocateRawInternal(bytes);
+ Object* object = NULL;
+ if (!maybe->ToObject(&object)) return false;
+ HeapObject* allocation = HeapObject::cast(object);
Address top = allocation_info_.top;
- return limit - top >= bytes;
+ if ((top - bytes) == allocation->address()) {
+ allocation_info_.top = allocation->address();
+ return true;
+ }
+ // There may be a borderline case here where the allocation succeeded, but
+ // the limit and top have moved on to a new page. In that case we try again.
+ return ReserveSpace(bytes);
}
@@ -2278,8 +2280,11 @@ HeapObject* LargeObjectIterator::Next() {
// -----------------------------------------------------------------------------
// LargeObjectSpace
-LargeObjectSpace::LargeObjectSpace(Heap* heap, AllocationSpace id)
+LargeObjectSpace::LargeObjectSpace(Heap* heap,
+ intptr_t max_capacity,
+ AllocationSpace id)
: Space(heap, id, NOT_EXECUTABLE), // Managed on a per-allocation basis
+ max_capacity_(max_capacity),
first_page_(NULL),
size_(0),
page_count_(0),
@@ -2319,6 +2324,10 @@ MaybeObject* LargeObjectSpace::AllocateRaw(int object_size,
return Failure::RetryAfterGC(identity());
}
+ if (Size() + object_size > max_capacity_) {
+ return Failure::RetryAfterGC(identity());
+ }
+
LargePage* page = heap()->isolate()->memory_allocator()->
AllocateLargePage(object_size, executable, this);
if (page == NULL) return Failure::RetryAfterGC(identity());
diff --git a/deps/v8/src/spaces.h b/deps/v8/src/spaces.h
index ce8e382aaa..45e008c002 100644
--- a/deps/v8/src/spaces.h
+++ b/deps/v8/src/spaces.h
@@ -459,7 +459,6 @@ class MemoryChunk {
live_byte_count_ = 0;
}
void IncrementLiveBytes(int by) {
- ASSERT_LE(static_cast<unsigned>(live_byte_count_), size_);
if (FLAG_gc_verbose) {
printf("UpdateLiveBytes:%p:%x%c=%x->%x\n",
static_cast<void*>(this), live_byte_count_,
@@ -642,7 +641,6 @@ class Page : public MemoryChunk {
// [page_addr + kObjectStartOffset .. page_addr + kPageSize].
INLINE(static Page* FromAllocationTop(Address top)) {
Page* p = FromAddress(top - kPointerSize);
- ASSERT_PAGE_OFFSET(p->Offset(top));
return p;
}
@@ -666,7 +664,6 @@ class Page : public MemoryChunk {
// Returns the offset of a given address to this page.
INLINE(int Offset(Address a)) {
int offset = static_cast<int>(a - address());
- ASSERT_PAGE_OFFSET(offset);
return offset;
}
@@ -1134,11 +1131,6 @@ class HeapObjectIterator: public ObjectIterator {
Address end,
PageMode mode,
HeapObjectCallback size_func);
-
-#ifdef DEBUG
- // Verifies whether fields have valid values.
- void Verify();
-#endif
};
@@ -1741,7 +1733,6 @@ class NewSpacePage : public MemoryChunk {
reinterpret_cast<Address>(reinterpret_cast<uintptr_t>(address_in_page) &
~Page::kPageAlignmentMask);
NewSpacePage* page = reinterpret_cast<NewSpacePage*>(page_start);
- ASSERT(page->InNewSpace());
return page;
}
@@ -1818,7 +1809,6 @@ class SemiSpace : public Space {
// Returns the start address of the current page of the space.
Address page_low() {
- ASSERT(anchor_.next_page() != &anchor_);
return current_page_->body();
}
@@ -2084,7 +2074,7 @@ class NewSpace : public Space {
// Return the current capacity of a semispace.
intptr_t EffectiveCapacity() {
- ASSERT(to_space_.Capacity() == from_space_.Capacity());
+ SLOW_ASSERT(to_space_.Capacity() == from_space_.Capacity());
return (to_space_.Capacity() / Page::kPageSize) * Page::kObjectAreaSize;
}
@@ -2100,10 +2090,9 @@ class NewSpace : public Space {
return Capacity();
}
- // Return the available bytes without growing or switching page in the
- // active semispace.
+ // Return the available bytes without growing.
intptr_t Available() {
- return allocation_info_.limit - allocation_info_.top;
+ return Capacity() - Size();
}
// Return the maximum capacity of a semispace.
@@ -2317,9 +2306,9 @@ class OldSpace : public PagedSpace {
// For contiguous spaces, top should be in the space (or at the end) and limit
// should be the end of the space.
#define ASSERT_SEMISPACE_ALLOCATION_INFO(info, space) \
- ASSERT((space).page_low() <= (info).top \
- && (info).top <= (space).page_high() \
- && (info).limit <= (space).page_high())
+ SLOW_ASSERT((space).page_low() <= (info).top \
+ && (info).top <= (space).page_high() \
+ && (info).limit <= (space).page_high())
// -----------------------------------------------------------------------------
@@ -2447,7 +2436,7 @@ class CellSpace : public FixedSpace {
class LargeObjectSpace : public Space {
public:
- LargeObjectSpace(Heap* heap, AllocationSpace id);
+ LargeObjectSpace(Heap* heap, intptr_t max_capacity, AllocationSpace id);
virtual ~LargeObjectSpace() {}
// Initializes internal data structures.
@@ -2517,6 +2506,7 @@ class LargeObjectSpace : public Space {
bool SlowContains(Address addr) { return !FindObject(addr)->IsFailure(); }
private:
+ intptr_t max_capacity_;
// The head of the linked list of large object chunks.
LargePage* first_page_;
intptr_t size_; // allocated bytes
diff --git a/deps/v8/src/store-buffer-inl.h b/deps/v8/src/store-buffer-inl.h
index 34f35a487f..dd65cbcc9c 100644
--- a/deps/v8/src/store-buffer-inl.h
+++ b/deps/v8/src/store-buffer-inl.h
@@ -55,10 +55,10 @@ void StoreBuffer::Mark(Address addr) {
void StoreBuffer::EnterDirectlyIntoStoreBuffer(Address addr) {
if (store_buffer_rebuilding_enabled_) {
- ASSERT(!heap_->cell_space()->Contains(addr));
- ASSERT(!heap_->code_space()->Contains(addr));
- ASSERT(!heap_->old_data_space()->Contains(addr));
- ASSERT(!heap_->new_space()->Contains(addr));
+ SLOW_ASSERT(!heap_->cell_space()->Contains(addr) &&
+ !heap_->code_space()->Contains(addr) &&
+ !heap_->old_data_space()->Contains(addr) &&
+ !heap_->new_space()->Contains(addr));
Address* top = old_top_;
*top++ = addr;
old_top_ = top;
diff --git a/deps/v8/src/store-buffer.cc b/deps/v8/src/store-buffer.cc
index ab810e4006..7c8b5f2077 100644
--- a/deps/v8/src/store-buffer.cc
+++ b/deps/v8/src/store-buffer.cc
@@ -401,7 +401,9 @@ void StoreBuffer::Verify() {
void StoreBuffer::GCEpilogue() {
during_gc_ = false;
- Verify();
+ if (FLAG_verify_heap) {
+ Verify();
+ }
}
diff --git a/deps/v8/src/stub-cache.cc b/deps/v8/src/stub-cache.cc
index 67451f2b88..139bc2dcf9 100644
--- a/deps/v8/src/stub-cache.cc
+++ b/deps/v8/src/stub-cache.cc
@@ -109,8 +109,8 @@ Code* StubCache::Set(String* name, Map* map, Code* code) {
}
-MaybeObject* StubCache::ComputeLoadNonexistent(String* name,
- JSObject* receiver) {
+Handle<Code> StubCache::ComputeLoadNonexistent(Handle<String> name,
+ Handle<JSObject> receiver) {
ASSERT(receiver->IsGlobalObject() || receiver->HasFastProperties());
// If no global objects are present in the prototype chain, the load
// nonexistent IC stub can be shared for all names for a given map
@@ -118,385 +118,328 @@ MaybeObject* StubCache::ComputeLoadNonexistent(String* name,
// there are global objects involved, we need to check global
// property cells in the stub and therefore the stub will be
// specific to the name.
- String* cache_name = heap()->empty_string();
+ Handle<String> cache_name = factory()->empty_string();
if (receiver->IsGlobalObject()) cache_name = name;
- JSObject* last = receiver;
+ Handle<JSObject> last = receiver;
while (last->GetPrototype() != heap()->null_value()) {
- last = JSObject::cast(last->GetPrototype());
+ last = Handle<JSObject>(JSObject::cast(last->GetPrototype()));
if (last->IsGlobalObject()) cache_name = name;
}
// Compile the stub that is either shared for all names or
// name specific if there are global objects involved.
Code::Flags flags =
Code::ComputeMonomorphicFlags(Code::LOAD_IC, NONEXISTENT);
- Object* code = receiver->map()->FindInCodeCache(cache_name, flags);
- if (code->IsUndefined()) {
- LoadStubCompiler compiler;
- { MaybeObject* maybe_code =
- compiler.CompileLoadNonexistent(cache_name, receiver, last);
- if (!maybe_code->ToObject(&code)) return maybe_code;
- }
- PROFILE(isolate_,
- CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), cache_name));
- GDBJIT(AddCode(GDBJITInterface::LOAD_IC, cache_name, Code::cast(code)));
- Object* result;
- { MaybeObject* maybe_result =
- receiver->UpdateMapCodeCache(cache_name, Code::cast(code));
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- }
+ Handle<Object> probe(receiver->map()->FindInCodeCache(*cache_name, flags));
+ if (probe->IsCode()) return Handle<Code>::cast(probe);
+
+ LoadStubCompiler compiler(isolate_);
+ Handle<Code> code =
+ compiler.CompileLoadNonexistent(cache_name, receiver, last);
+ PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *cache_name));
+ GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *cache_name, *code));
+ JSObject::UpdateMapCodeCache(receiver, cache_name, code);
return code;
}
-MaybeObject* StubCache::ComputeLoadField(String* name,
- JSObject* receiver,
- JSObject* holder,
+Handle<Code> StubCache::ComputeLoadField(Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> holder,
int field_index) {
- ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
+ ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, FIELD);
- Object* code = receiver->map()->FindInCodeCache(name, flags);
- if (code->IsUndefined()) {
- LoadStubCompiler compiler;
- { MaybeObject* maybe_code =
- compiler.CompileLoadField(receiver, holder, field_index, name);
- if (!maybe_code->ToObject(&code)) return maybe_code;
- }
- PROFILE(isolate_,
- CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
- GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
- Object* result;
- { MaybeObject* maybe_result =
- receiver->UpdateMapCodeCache(name, Code::cast(code));
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- }
+ Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
+ if (probe->IsCode()) return Handle<Code>::cast(probe);
+
+ LoadStubCompiler compiler(isolate_);
+ Handle<Code> code =
+ compiler.CompileLoadField(receiver, holder, field_index, name);
+ PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
+ GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
+ JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
-MaybeObject* StubCache::ComputeLoadCallback(String* name,
- JSObject* receiver,
- JSObject* holder,
- AccessorInfo* callback) {
+Handle<Code> LoadStubCompiler::CompileLoadCallback(
+ Handle<String> name,
+ Handle<JSObject> object,
+ Handle<JSObject> holder,
+ Handle<AccessorInfo> callback) {
+ CALL_HEAP_FUNCTION(isolate(),
+ (set_failure(NULL),
+ CompileLoadCallback(*name, *object, *holder, *callback)),
+ Code);
+}
+
+
+Handle<Code> StubCache::ComputeLoadCallback(Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> holder,
+ Handle<AccessorInfo> callback) {
ASSERT(v8::ToCData<Address>(callback->getter()) != 0);
- ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
+ ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, CALLBACKS);
- Object* code = receiver->map()->FindInCodeCache(name, flags);
- if (code->IsUndefined()) {
- LoadStubCompiler compiler;
- { MaybeObject* maybe_code =
- compiler.CompileLoadCallback(name, receiver, holder, callback);
- if (!maybe_code->ToObject(&code)) return maybe_code;
- }
- PROFILE(isolate_,
- CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
- GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
- Object* result;
- { MaybeObject* maybe_result =
- receiver->UpdateMapCodeCache(name, Code::cast(code));
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- }
+ Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
+ if (probe->IsCode()) return Handle<Code>::cast(probe);
+
+ LoadStubCompiler compiler(isolate_);
+ Handle<Code> code =
+ compiler.CompileLoadCallback(name, receiver, holder, callback);
+ PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
+ GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
+ JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
-MaybeObject* StubCache::ComputeLoadConstant(String* name,
- JSObject* receiver,
- JSObject* holder,
- Object* value) {
- ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
+Handle<Code> StubCache::ComputeLoadConstant(Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> holder,
+ Handle<Object> value) {
+ ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
Code::Flags flags =
Code::ComputeMonomorphicFlags(Code::LOAD_IC, CONSTANT_FUNCTION);
- Object* code = receiver->map()->FindInCodeCache(name, flags);
- if (code->IsUndefined()) {
- LoadStubCompiler compiler;
- { MaybeObject* maybe_code =
- compiler.CompileLoadConstant(receiver, holder, value, name);
- if (!maybe_code->ToObject(&code)) return maybe_code;
- }
- PROFILE(isolate_,
- CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
- GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
- Object* result;
- { MaybeObject* maybe_result =
- receiver->UpdateMapCodeCache(name, Code::cast(code));
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- }
+ Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
+ if (probe->IsCode()) return Handle<Code>::cast(probe);
+
+ LoadStubCompiler compiler(isolate_);
+ Handle<Code> code =
+ compiler.CompileLoadConstant(receiver, holder, value, name);
+ PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
+ GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
+ JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
-MaybeObject* StubCache::ComputeLoadInterceptor(String* name,
- JSObject* receiver,
- JSObject* holder) {
- ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
+Handle<Code> LoadStubCompiler::CompileLoadInterceptor(Handle<JSObject> object,
+ Handle<JSObject> holder,
+ Handle<String> name) {
+ CALL_HEAP_FUNCTION(isolate(),
+ (set_failure(NULL),
+ CompileLoadInterceptor(*object, *holder, *name)),
+ Code);
+}
+
+
+Handle<Code> StubCache::ComputeLoadInterceptor(Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> holder) {
+ ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, INTERCEPTOR);
- Object* code = receiver->map()->FindInCodeCache(name, flags);
- if (code->IsUndefined()) {
- LoadStubCompiler compiler;
- { MaybeObject* maybe_code =
- compiler.CompileLoadInterceptor(receiver, holder, name);
- if (!maybe_code->ToObject(&code)) return maybe_code;
- }
- PROFILE(isolate_,
- CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
- GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
- Object* result;
- { MaybeObject* maybe_result =
- receiver->UpdateMapCodeCache(name, Code::cast(code));
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- }
+ Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
+ if (probe->IsCode()) return Handle<Code>::cast(probe);
+
+ LoadStubCompiler compiler(isolate_);
+ Handle<Code> code =
+ compiler.CompileLoadInterceptor(receiver, holder, name);
+ PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
+ GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
+ JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
-MaybeObject* StubCache::ComputeLoadNormal() {
- return isolate_->builtins()->builtin(Builtins::kLoadIC_Normal);
+Handle<Code> StubCache::ComputeLoadNormal() {
+ return isolate_->builtins()->LoadIC_Normal();
}
-MaybeObject* StubCache::ComputeLoadGlobal(String* name,
- JSObject* receiver,
- GlobalObject* holder,
- JSGlobalPropertyCell* cell,
+Handle<Code> StubCache::ComputeLoadGlobal(Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<GlobalObject> holder,
+ Handle<JSGlobalPropertyCell> cell,
bool is_dont_delete) {
- ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
+ ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL);
- Object* code = receiver->map()->FindInCodeCache(name, flags);
- if (code->IsUndefined()) {
- LoadStubCompiler compiler;
- { MaybeObject* maybe_code = compiler.CompileLoadGlobal(receiver,
- holder,
- cell,
- name,
- is_dont_delete);
- if (!maybe_code->ToObject(&code)) return maybe_code;
- }
- PROFILE(isolate_,
- CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
- GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
- Object* result;
- { MaybeObject* maybe_result =
- receiver->UpdateMapCodeCache(name, Code::cast(code));
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- }
+ Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
+ if (probe->IsCode()) return Handle<Code>::cast(probe);
+
+ LoadStubCompiler compiler(isolate_);
+ Handle<Code> code =
+ compiler.CompileLoadGlobal(receiver, holder, cell, name, is_dont_delete);
+ PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
+ GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
+ JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
-MaybeObject* StubCache::ComputeKeyedLoadField(String* name,
- JSObject* receiver,
- JSObject* holder,
+Handle<Code> StubCache::ComputeKeyedLoadField(Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> holder,
int field_index) {
- ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
+ ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, FIELD);
- Object* code = receiver->map()->FindInCodeCache(name, flags);
- if (code->IsUndefined()) {
- KeyedLoadStubCompiler compiler;
- { MaybeObject* maybe_code =
- compiler.CompileLoadField(name, receiver, holder, field_index);
- if (!maybe_code->ToObject(&code)) return maybe_code;
- }
- PROFILE(isolate_,
- CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
- GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
- Object* result;
- { MaybeObject* maybe_result =
- receiver->UpdateMapCodeCache(name, Code::cast(code));
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- }
+ Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
+ if (probe->IsCode()) return Handle<Code>::cast(probe);
+
+ KeyedLoadStubCompiler compiler(isolate_);
+ Handle<Code> code =
+ compiler.CompileLoadField(name, receiver, holder, field_index);
+ PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
+ GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
+ JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
-MaybeObject* StubCache::ComputeKeyedLoadConstant(String* name,
- JSObject* receiver,
- JSObject* holder,
- Object* value) {
- ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
+Handle<Code> StubCache::ComputeKeyedLoadConstant(Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> holder,
+ Handle<Object> value) {
+ ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
Code::Flags flags =
Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CONSTANT_FUNCTION);
- Object* code = receiver->map()->FindInCodeCache(name, flags);
- if (code->IsUndefined()) {
- KeyedLoadStubCompiler compiler;
- { MaybeObject* maybe_code =
- compiler.CompileLoadConstant(name, receiver, holder, value);
- if (!maybe_code->ToObject(&code)) return maybe_code;
- }
- PROFILE(isolate_,
- CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
- GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
- Object* result;
- { MaybeObject* maybe_result =
- receiver->UpdateMapCodeCache(name, Code::cast(code));
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- }
+ Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
+ if (probe->IsCode()) return Handle<Code>::cast(probe);
+
+ KeyedLoadStubCompiler compiler(isolate_);
+ Handle<Code> code =
+ compiler.CompileLoadConstant(name, receiver, holder, value);
+ PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
+ GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
+ JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
-MaybeObject* StubCache::ComputeKeyedLoadInterceptor(String* name,
- JSObject* receiver,
- JSObject* holder) {
- ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
+Handle<Code> KeyedLoadStubCompiler::CompileLoadInterceptor(
+ Handle<JSObject> object,
+ Handle<JSObject> holder,
+ Handle<String> name) {
+ CALL_HEAP_FUNCTION(isolate(),
+ (set_failure(NULL),
+ CompileLoadInterceptor(*object, *holder, *name)),
+ Code);
+}
+
+
+Handle<Code> StubCache::ComputeKeyedLoadInterceptor(Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> holder) {
+ ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
Code::Flags flags =
Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, INTERCEPTOR);
- Object* code = receiver->map()->FindInCodeCache(name, flags);
- if (code->IsUndefined()) {
- KeyedLoadStubCompiler compiler;
- { MaybeObject* maybe_code =
- compiler.CompileLoadInterceptor(receiver, holder, name);
- if (!maybe_code->ToObject(&code)) return maybe_code;
- }
- PROFILE(isolate_,
- CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
- GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
- Object* result;
- { MaybeObject* maybe_result =
- receiver->UpdateMapCodeCache(name, Code::cast(code));
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- }
+ Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
+ if (probe->IsCode()) return Handle<Code>::cast(probe);
+
+ KeyedLoadStubCompiler compiler(isolate_);
+ Handle<Code> code = compiler.CompileLoadInterceptor(receiver, holder, name);
+ PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
+ GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
+ JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
-MaybeObject* StubCache::ComputeKeyedLoadCallback(String* name,
- JSObject* receiver,
- JSObject* holder,
- AccessorInfo* callback) {
- ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
+Handle<Code> KeyedLoadStubCompiler::CompileLoadCallback(
+ Handle<String> name,
+ Handle<JSObject> object,
+ Handle<JSObject> holder,
+ Handle<AccessorInfo> callback) {
+ CALL_HEAP_FUNCTION(isolate(),
+ (set_failure(NULL),
+ CompileLoadCallback(*name, *object, *holder, *callback)),
+ Code);
+}
+
+
+Handle<Code> StubCache::ComputeKeyedLoadCallback(
+ Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> holder,
+ Handle<AccessorInfo> callback) {
+ ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
Code::Flags flags =
Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
- Object* code = receiver->map()->FindInCodeCache(name, flags);
- if (code->IsUndefined()) {
- KeyedLoadStubCompiler compiler;
- { MaybeObject* maybe_code =
- compiler.CompileLoadCallback(name, receiver, holder, callback);
- if (!maybe_code->ToObject(&code)) return maybe_code;
- }
- PROFILE(isolate_,
- CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
- GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
- Object* result;
- { MaybeObject* maybe_result =
- receiver->UpdateMapCodeCache(name, Code::cast(code));
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- }
+ Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
+ if (probe->IsCode()) return Handle<Code>::cast(probe);
+
+ KeyedLoadStubCompiler compiler(isolate_);
+ Handle<Code> code =
+ compiler.CompileLoadCallback(name, receiver, holder, callback);
+ PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
+ GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
+ JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
-
-MaybeObject* StubCache::ComputeKeyedLoadArrayLength(String* name,
- JSArray* receiver) {
+Handle<Code> StubCache::ComputeKeyedLoadArrayLength(Handle<String> name,
+ Handle<JSArray> receiver) {
Code::Flags flags =
Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
- ASSERT(receiver->IsJSObject());
- Object* code = receiver->map()->FindInCodeCache(name, flags);
- if (code->IsUndefined()) {
- KeyedLoadStubCompiler compiler;
- { MaybeObject* maybe_code = compiler.CompileLoadArrayLength(name);
- if (!maybe_code->ToObject(&code)) return maybe_code;
- }
- PROFILE(isolate_,
- CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
- GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
- Object* result;
- { MaybeObject* maybe_result =
- receiver->UpdateMapCodeCache(name, Code::cast(code));
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- }
+ Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
+ if (probe->IsCode()) return Handle<Code>::cast(probe);
+
+ KeyedLoadStubCompiler compiler(isolate_);
+ Handle<Code> code = compiler.CompileLoadArrayLength(name);
+ PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
+ GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
+ JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
-MaybeObject* StubCache::ComputeKeyedLoadStringLength(String* name,
- String* receiver) {
+Handle<Code> StubCache::ComputeKeyedLoadStringLength(Handle<String> name,
+ Handle<String> receiver) {
Code::Flags flags =
Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
- Map* map = receiver->map();
- Object* code = map->FindInCodeCache(name, flags);
- if (code->IsUndefined()) {
- KeyedLoadStubCompiler compiler;
- { MaybeObject* maybe_code = compiler.CompileLoadStringLength(name);
- if (!maybe_code->ToObject(&code)) return maybe_code;
- }
- PROFILE(isolate_,
- CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
- GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
- Object* result;
- { MaybeObject* maybe_result = map->UpdateCodeCache(name, Code::cast(code));
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- }
+ Handle<Map> map(receiver->map());
+ Handle<Object> probe(map->FindInCodeCache(*name, flags));
+ if (probe->IsCode()) return Handle<Code>::cast(probe);
+
+ KeyedLoadStubCompiler compiler(isolate_);
+ Handle<Code> code = compiler.CompileLoadStringLength(name);
+ PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
+ GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
+ Map::UpdateCodeCache(map, name, code);
return code;
}
-MaybeObject* StubCache::ComputeKeyedLoadFunctionPrototype(
- String* name,
- JSFunction* receiver) {
+Handle<Code> StubCache::ComputeKeyedLoadFunctionPrototype(
+ Handle<String> name,
+ Handle<JSFunction> receiver) {
Code::Flags flags =
Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
- Object* code = receiver->map()->FindInCodeCache(name, flags);
- if (code->IsUndefined()) {
- KeyedLoadStubCompiler compiler;
- { MaybeObject* maybe_code = compiler.CompileLoadFunctionPrototype(name);
- if (!maybe_code->ToObject(&code)) return maybe_code;
- }
- PROFILE(isolate_,
- CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
- GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
- Object* result;
- { MaybeObject* maybe_result =
- receiver->UpdateMapCodeCache(name, Code::cast(code));
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- }
+ Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
+ if (probe->IsCode()) return Handle<Code>::cast(probe);
+
+ KeyedLoadStubCompiler compiler(isolate_);
+ Handle<Code> code = compiler.CompileLoadFunctionPrototype(name);
+ PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
+ GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
+ JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
-MaybeObject* StubCache::ComputeStoreField(String* name,
- JSObject* receiver,
+Handle<Code> StubCache::ComputeStoreField(Handle<String> name,
+ Handle<JSObject> receiver,
int field_index,
- Map* transition,
+ Handle<Map> transition,
StrictModeFlag strict_mode) {
- PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
+ PropertyType type = (transition.is_null()) ? FIELD : MAP_TRANSITION;
Code::Flags flags = Code::ComputeMonomorphicFlags(
Code::STORE_IC, type, strict_mode);
- Object* code = receiver->map()->FindInCodeCache(name, flags);
- if (code->IsUndefined()) {
- StoreStubCompiler compiler(strict_mode);
- { MaybeObject* maybe_code =
- compiler.CompileStoreField(receiver, field_index, transition, name);
- if (!maybe_code->ToObject(&code)) return maybe_code;
- }
- PROFILE(isolate_,
- CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
- GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
- Object* result;
- { MaybeObject* maybe_result =
- receiver->UpdateMapCodeCache(name, Code::cast(code));
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- }
+ Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
+ if (probe->IsCode()) return Handle<Code>::cast(probe);
+
+ StoreStubCompiler compiler(isolate_, strict_mode);
+ Handle<Code> code =
+ compiler.CompileStoreField(receiver, field_index, transition, name);
+ PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
+ GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
+ JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
-MaybeObject* StubCache::ComputeKeyedLoadOrStoreElement(
- JSObject* receiver,
+Handle<Code> StubCache::ComputeKeyedLoadOrStoreElement(
+ Handle<JSObject> receiver,
KeyedIC::StubKind stub_kind,
StrictModeFlag strict_mode) {
Code::Flags flags =
@@ -505,189 +448,159 @@ MaybeObject* StubCache::ComputeKeyedLoadOrStoreElement(
: Code::KEYED_STORE_IC,
NORMAL,
strict_mode);
- String* name = NULL;
+ Handle<String> name;
switch (stub_kind) {
case KeyedIC::LOAD:
- name = isolate()->heap()->KeyedLoadElementMonomorphic_symbol();
+ name = isolate()->factory()->KeyedLoadElementMonomorphic_symbol();
break;
case KeyedIC::STORE_NO_TRANSITION:
- name = isolate()->heap()->KeyedStoreElementMonomorphic_symbol();
+ name = isolate()->factory()->KeyedStoreElementMonomorphic_symbol();
break;
default:
UNREACHABLE();
break;
}
- Object* maybe_code = receiver->map()->FindInCodeCache(name, flags);
- if (!maybe_code->IsUndefined()) return Code::cast(maybe_code);
+ Handle<Map> receiver_map(receiver->map());
+ Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags));
+ if (probe->IsCode()) return Handle<Code>::cast(probe);
- Map* receiver_map = receiver->map();
- MaybeObject* maybe_new_code = NULL;
+ Handle<Code> code;
switch (stub_kind) {
case KeyedIC::LOAD: {
- KeyedLoadStubCompiler compiler;
- maybe_new_code = compiler.CompileLoadElement(receiver_map);
+ KeyedLoadStubCompiler compiler(isolate_);
+ code = compiler.CompileLoadElement(receiver_map);
break;
}
case KeyedIC::STORE_NO_TRANSITION: {
- KeyedStoreStubCompiler compiler(strict_mode);
- maybe_new_code = compiler.CompileStoreElement(receiver_map);
+ KeyedStoreStubCompiler compiler(isolate_, strict_mode);
+ code = compiler.CompileStoreElement(receiver_map);
break;
}
default:
UNREACHABLE();
break;
}
- Code* code = NULL;
- if (!maybe_new_code->To(&code)) return maybe_new_code;
+
+ ASSERT(!code.is_null());
if (stub_kind == KeyedIC::LOAD) {
- PROFILE(isolate_,
- CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG,
- Code::cast(code), 0));
+ PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, 0));
} else {
- PROFILE(isolate_,
- CodeCreateEvent(Logger::KEYED_STORE_IC_TAG,
- Code::cast(code), 0));
- }
- ASSERT(code->IsCode());
- Object* result;
- { MaybeObject* maybe_result =
- receiver->UpdateMapCodeCache(name, Code::cast(code));
- if (!maybe_result->ToObject(&result)) return maybe_result;
+ PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, *code, 0));
}
+ JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
-MaybeObject* StubCache::ComputeStoreNormal(StrictModeFlag strict_mode) {
- return isolate_->builtins()->builtin((strict_mode == kStrictMode)
- ? Builtins::kStoreIC_Normal_Strict
- : Builtins::kStoreIC_Normal);
+Handle<Code> StubCache::ComputeStoreNormal(StrictModeFlag strict_mode) {
+ return (strict_mode == kStrictMode)
+ ? isolate_->builtins()->Builtins::StoreIC_Normal_Strict()
+ : isolate_->builtins()->Builtins::StoreIC_Normal();
}
-MaybeObject* StubCache::ComputeStoreGlobal(String* name,
- GlobalObject* receiver,
- JSGlobalPropertyCell* cell,
+Handle<Code> StubCache::ComputeStoreGlobal(Handle<String> name,
+ Handle<GlobalObject> receiver,
+ Handle<JSGlobalPropertyCell> cell,
StrictModeFlag strict_mode) {
Code::Flags flags = Code::ComputeMonomorphicFlags(
Code::STORE_IC, NORMAL, strict_mode);
- Object* code = receiver->map()->FindInCodeCache(name, flags);
- if (code->IsUndefined()) {
- StoreStubCompiler compiler(strict_mode);
- { MaybeObject* maybe_code =
- compiler.CompileStoreGlobal(receiver, cell, name);
- if (!maybe_code->ToObject(&code)) return maybe_code;
- }
- PROFILE(isolate_,
- CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
- GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
- Object* result;
- { MaybeObject* maybe_result =
- receiver->UpdateMapCodeCache(name, Code::cast(code));
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- }
+ Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
+ if (probe->IsCode()) return Handle<Code>::cast(probe);
+
+ StoreStubCompiler compiler(isolate_, strict_mode);
+ Handle<Code> code = compiler.CompileStoreGlobal(receiver, cell, name);
+ PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
+ GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
+ JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
-MaybeObject* StubCache::ComputeStoreCallback(
- String* name,
- JSObject* receiver,
- AccessorInfo* callback,
- StrictModeFlag strict_mode) {
+Handle<Code> StubCache::ComputeStoreCallback(Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<AccessorInfo> callback,
+ StrictModeFlag strict_mode) {
ASSERT(v8::ToCData<Address>(callback->setter()) != 0);
Code::Flags flags = Code::ComputeMonomorphicFlags(
Code::STORE_IC, CALLBACKS, strict_mode);
- Object* code = receiver->map()->FindInCodeCache(name, flags);
- if (code->IsUndefined()) {
- StoreStubCompiler compiler(strict_mode);
- { MaybeObject* maybe_code =
- compiler.CompileStoreCallback(receiver, callback, name);
- if (!maybe_code->ToObject(&code)) return maybe_code;
- }
- PROFILE(isolate_,
- CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
- GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
- Object* result;
- { MaybeObject* maybe_result =
- receiver->UpdateMapCodeCache(name, Code::cast(code));
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- }
+ Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
+ if (probe->IsCode()) return Handle<Code>::cast(probe);
+
+ StoreStubCompiler compiler(isolate_, strict_mode);
+ Handle<Code> code = compiler.CompileStoreCallback(receiver, callback, name);
+ PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
+ GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
+ JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
-MaybeObject* StubCache::ComputeStoreInterceptor(
- String* name,
- JSObject* receiver,
- StrictModeFlag strict_mode) {
+Handle<Code> StubCache::ComputeStoreInterceptor(Handle<String> name,
+ Handle<JSObject> receiver,
+ StrictModeFlag strict_mode) {
Code::Flags flags = Code::ComputeMonomorphicFlags(
Code::STORE_IC, INTERCEPTOR, strict_mode);
- Object* code = receiver->map()->FindInCodeCache(name, flags);
- if (code->IsUndefined()) {
- StoreStubCompiler compiler(strict_mode);
- { MaybeObject* maybe_code =
- compiler.CompileStoreInterceptor(receiver, name);
- if (!maybe_code->ToObject(&code)) return maybe_code;
- }
- PROFILE(isolate_,
- CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
- GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
- Object* result;
- { MaybeObject* maybe_result =
- receiver->UpdateMapCodeCache(name, Code::cast(code));
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- }
+ Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
+ if (probe->IsCode()) return Handle<Code>::cast(probe);
+
+ StoreStubCompiler compiler(isolate_, strict_mode);
+ Handle<Code> code = compiler.CompileStoreInterceptor(receiver, name);
+ PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
+ GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
+ JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
-
-MaybeObject* StubCache::ComputeKeyedStoreField(String* name,
- JSObject* receiver,
+Handle<Code> StubCache::ComputeKeyedStoreField(Handle<String> name,
+ Handle<JSObject> receiver,
int field_index,
- Map* transition,
+ Handle<Map> transition,
StrictModeFlag strict_mode) {
- PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
+ PropertyType type = (transition.is_null()) ? FIELD : MAP_TRANSITION;
Code::Flags flags = Code::ComputeMonomorphicFlags(
Code::KEYED_STORE_IC, type, strict_mode);
- Object* code = receiver->map()->FindInCodeCache(name, flags);
- if (code->IsUndefined()) {
- KeyedStoreStubCompiler compiler(strict_mode);
- { MaybeObject* maybe_code =
- compiler.CompileStoreField(receiver, field_index, transition, name);
- if (!maybe_code->ToObject(&code)) return maybe_code;
- }
- PROFILE(isolate(),
- CodeCreateEvent(Logger::KEYED_STORE_IC_TAG,
- Code::cast(code), name));
- GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC, name, Code::cast(code)));
- Object* result;
- { MaybeObject* maybe_result =
- receiver->UpdateMapCodeCache(name, Code::cast(code));
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- }
+ Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
+ if (probe->IsCode()) return Handle<Code>::cast(probe);
+
+ KeyedStoreStubCompiler compiler(isolate(), strict_mode);
+ Handle<Code> code =
+ compiler.CompileStoreField(receiver, field_index, transition, name);
+ PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, *code, *name));
+ GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC, *name, *code));
+ JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
+
#define CALL_LOGGER_TAG(kind, type) \
(kind == Code::CALL_IC ? Logger::type : Logger::KEYED_##type)
-MaybeObject* StubCache::ComputeCallConstant(int argc,
+Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object,
+ Handle<JSObject> holder,
+ Handle<JSFunction> function,
+ Handle<String> name,
+ CheckType check) {
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ (set_failure(NULL),
+ CompileCallConstant(*object, *holder, *function, *name, check)),
+ Code);
+}
+
+
+Handle<Code> StubCache::ComputeCallConstant(int argc,
Code::Kind kind,
- Code::ExtraICState extra_ic_state,
- String* name,
- Object* object,
- JSObject* holder,
- JSFunction* function) {
+ Code::ExtraICState extra_state,
+ Handle<String> name,
+ Handle<Object> object,
+ Handle<JSObject> holder,
+ Handle<JSFunction> function) {
// Compute the check type and the map.
InlineCacheHolderFlag cache_holder =
- IC::GetCodeCacheForObject(object, holder);
- JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
+ IC::GetCodeCacheForObject(*object, *holder);
+ Handle<JSObject> map_holder(IC::GetCodeCacheHolder(*object, cache_holder));
// Compute check type based on receiver/holder.
CheckType check = RECEIVER_MAP_CHECK;
@@ -699,51 +612,36 @@ MaybeObject* StubCache::ComputeCallConstant(int argc,
check = BOOLEAN_CHECK;
}
- Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
- CONSTANT_FUNCTION,
- extra_ic_state,
- cache_holder,
- argc);
- Object* code = map_holder->map()->FindInCodeCache(name, flags);
- if (code->IsUndefined()) {
- // If the function hasn't been compiled yet, we cannot do it now
- // because it may cause GC. To avoid this issue, we return an
- // internal error which will make sure we do not update any
- // caches.
- if (!function->is_compiled()) return Failure::InternalError();
- // Compile the stub - only create stubs for fully compiled functions.
- CallStubCompiler compiler(argc, kind, extra_ic_state, cache_holder);
- { MaybeObject* maybe_code =
- compiler.CompileCallConstant(object, holder, function, name, check);
- if (!maybe_code->ToObject(&code)) return maybe_code;
- }
- Code::cast(code)->set_check_type(check);
- ASSERT_EQ(flags, Code::cast(code)->flags());
- PROFILE(isolate_,
- CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
- Code::cast(code), name));
- GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
- Object* result;
- { MaybeObject* maybe_result =
- map_holder->UpdateMapCodeCache(name, Code::cast(code));
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- }
+ Code::Flags flags =
+ Code::ComputeMonomorphicFlags(kind, CONSTANT_FUNCTION, extra_state,
+ cache_holder, argc);
+ Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags));
+ if (probe->IsCode()) return Handle<Code>::cast(probe);
+
+ CallStubCompiler compiler(isolate_, argc, kind, extra_state, cache_holder);
+ Handle<Code> code =
+ compiler.CompileCallConstant(object, holder, function, name, check);
+ code->set_check_type(check);
+ ASSERT_EQ(flags, code->flags());
+ PROFILE(isolate_,
+ CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
+ GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
+ JSObject::UpdateMapCodeCache(map_holder, name, code);
return code;
}
-MaybeObject* StubCache::ComputeCallField(int argc,
+Handle<Code> StubCache::ComputeCallField(int argc,
Code::Kind kind,
- Code::ExtraICState extra_ic_state,
- String* name,
- Object* object,
- JSObject* holder,
+ Code::ExtraICState extra_state,
+ Handle<String> name,
+ Handle<Object> object,
+ Handle<JSObject> holder,
int index) {
// Compute the check type and the map.
InlineCacheHolderFlag cache_holder =
- IC::GetCodeCacheForObject(object, holder);
- JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
+ IC::GetCodeCacheForObject(*object, *holder);
+ Handle<JSObject> map_holder(IC::GetCodeCacheHolder(*object, cache_holder));
// TODO(1233596): We cannot do receiver map check for non-JS objects
// because they may be represented as immediates without a
@@ -752,47 +650,45 @@ MaybeObject* StubCache::ComputeCallField(int argc,
object = holder;
}
- Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
- FIELD,
- extra_ic_state,
- cache_holder,
- argc);
- Object* code = map_holder->map()->FindInCodeCache(name, flags);
- if (code->IsUndefined()) {
- CallStubCompiler compiler(argc, kind, extra_ic_state, cache_holder);
- { MaybeObject* maybe_code =
- compiler.CompileCallField(JSObject::cast(object),
- holder,
- index,
- name);
- if (!maybe_code->ToObject(&code)) return maybe_code;
- }
- ASSERT_EQ(flags, Code::cast(code)->flags());
- PROFILE(isolate_,
- CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
- Code::cast(code), name));
- GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
- Object* result;
- { MaybeObject* maybe_result =
- map_holder->UpdateMapCodeCache(name, Code::cast(code));
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- }
+ Code::Flags flags =
+ Code::ComputeMonomorphicFlags(kind, FIELD, extra_state,
+ cache_holder, argc);
+ Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags));
+ if (probe->IsCode()) return Handle<Code>::cast(probe);
+
+ CallStubCompiler compiler(isolate_, argc, kind, extra_state, cache_holder);
+ Handle<Code> code =
+ compiler.CompileCallField(Handle<JSObject>::cast(object),
+ holder, index, name);
+ ASSERT_EQ(flags, code->flags());
+ PROFILE(isolate_,
+ CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
+ GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
+ JSObject::UpdateMapCodeCache(map_holder, name, code);
return code;
}
-MaybeObject* StubCache::ComputeCallInterceptor(
- int argc,
- Code::Kind kind,
- Code::ExtraICState extra_ic_state,
- String* name,
- Object* object,
- JSObject* holder) {
+Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
+ Handle<JSObject> holder,
+ Handle<String> name) {
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ (set_failure(NULL), CompileCallInterceptor(*object, *holder, *name)),
+ Code);
+}
+
+
+Handle<Code> StubCache::ComputeCallInterceptor(int argc,
+ Code::Kind kind,
+ Code::ExtraICState extra_state,
+ Handle<String> name,
+ Handle<Object> object,
+ Handle<JSObject> holder) {
// Compute the check type and the map.
InlineCacheHolderFlag cache_holder =
- IC::GetCodeCacheForObject(object, holder);
- JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
+ IC::GetCodeCacheForObject(*object, *holder);
+ Handle<JSObject> map_holder(IC::GetCodeCacheHolder(*object, cache_holder));
// TODO(1233596): We cannot do receiver map check for non-JS objects
// because they may be represented as immediates without a
@@ -801,134 +697,75 @@ MaybeObject* StubCache::ComputeCallInterceptor(
object = holder;
}
- Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
- INTERCEPTOR,
- extra_ic_state,
- cache_holder,
- argc);
- Object* code = map_holder->map()->FindInCodeCache(name, flags);
- if (code->IsUndefined()) {
- CallStubCompiler compiler(argc, kind, extra_ic_state, cache_holder);
- { MaybeObject* maybe_code =
- compiler.CompileCallInterceptor(JSObject::cast(object), holder, name);
- if (!maybe_code->ToObject(&code)) return maybe_code;
- }
- ASSERT_EQ(flags, Code::cast(code)->flags());
- PROFILE(isolate(),
- CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
- Code::cast(code), name));
- GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
- Object* result;
- { MaybeObject* maybe_result =
- map_holder->UpdateMapCodeCache(name, Code::cast(code));
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- }
+ Code::Flags flags =
+ Code::ComputeMonomorphicFlags(kind, INTERCEPTOR, extra_state,
+ cache_holder, argc);
+ Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags));
+ if (probe->IsCode()) return Handle<Code>::cast(probe);
+
+ CallStubCompiler compiler(isolate(), argc, kind, extra_state, cache_holder);
+ Handle<Code> code =
+ compiler.CompileCallInterceptor(Handle<JSObject>::cast(object),
+ holder, name);
+ ASSERT_EQ(flags, code->flags());
+ PROFILE(isolate(),
+ CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
+ GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
+ JSObject::UpdateMapCodeCache(map_holder, name, code);
return code;
}
-MaybeObject* StubCache::ComputeCallNormal(int argc,
- Code::Kind kind,
- Code::ExtraICState extra_ic_state,
- String* name,
- JSObject* receiver) {
- Object* code;
- { MaybeObject* maybe_code = ComputeCallNormal(argc, kind, extra_ic_state);
- if (!maybe_code->ToObject(&code)) return maybe_code;
- }
- return code;
+Handle<Code> CallStubCompiler::CompileCallGlobal(
+ Handle<JSObject> object,
+ Handle<GlobalObject> holder,
+ Handle<JSGlobalPropertyCell> cell,
+ Handle<JSFunction> function,
+ Handle<String> name) {
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ (set_failure(NULL),
+ CompileCallGlobal(*object, *holder, *cell, *function, *name)),
+ Code);
}
-MaybeObject* StubCache::ComputeCallGlobal(int argc,
+Handle<Code> StubCache::ComputeCallGlobal(int argc,
Code::Kind kind,
- Code::ExtraICState extra_ic_state,
- String* name,
- JSObject* receiver,
- GlobalObject* holder,
- JSGlobalPropertyCell* cell,
- JSFunction* function) {
+ Code::ExtraICState extra_state,
+ Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<GlobalObject> holder,
+ Handle<JSGlobalPropertyCell> cell,
+ Handle<JSFunction> function) {
InlineCacheHolderFlag cache_holder =
- IC::GetCodeCacheForObject(receiver, holder);
- JSObject* map_holder = IC::GetCodeCacheHolder(receiver, cache_holder);
- Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
- NORMAL,
- extra_ic_state,
- cache_holder,
- argc);
- Object* code = map_holder->map()->FindInCodeCache(name, flags);
- if (code->IsUndefined()) {
- // If the function hasn't been compiled yet, we cannot do it now
- // because it may cause GC. To avoid this issue, we return an
- // internal error which will make sure we do not update any
- // caches.
- if (!function->is_compiled()) return Failure::InternalError();
- CallStubCompiler compiler(argc, kind, extra_ic_state, cache_holder);
- { MaybeObject* maybe_code =
- compiler.CompileCallGlobal(receiver, holder, cell, function, name);
- if (!maybe_code->ToObject(&code)) return maybe_code;
- }
- ASSERT_EQ(flags, Code::cast(code)->flags());
- PROFILE(isolate(),
- CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
- Code::cast(code), name));
- GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
- Object* result;
- { MaybeObject* maybe_result =
- map_holder->UpdateMapCodeCache(name, Code::cast(code));
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- }
+ IC::GetCodeCacheForObject(*receiver, *holder);
+ Handle<JSObject> map_holder(IC::GetCodeCacheHolder(*receiver, cache_holder));
+ Code::Flags flags =
+ Code::ComputeMonomorphicFlags(kind, NORMAL, extra_state,
+ cache_holder, argc);
+ Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags));
+ if (probe->IsCode()) return Handle<Code>::cast(probe);
+
+ CallStubCompiler compiler(isolate(), argc, kind, extra_state, cache_holder);
+ Handle<Code> code =
+ compiler.CompileCallGlobal(receiver, holder, cell, function, name);
+ ASSERT_EQ(flags, code->flags());
+ PROFILE(isolate(),
+ CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
+ GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
+ JSObject::UpdateMapCodeCache(map_holder, name, code);
return code;
}
-static Object* GetProbeValue(Isolate* isolate, Code::Flags flags) {
- // Use raw_unchecked... so we don't get assert failures during GC.
- NumberDictionary* dictionary =
- isolate->heap()->raw_unchecked_non_monomorphic_cache();
- int entry = dictionary->FindEntry(isolate, flags);
- if (entry != -1) return dictionary->ValueAt(entry);
- return isolate->heap()->raw_unchecked_undefined_value();
-}
-
-
-MUST_USE_RESULT static MaybeObject* ProbeCache(Isolate* isolate,
- Code::Flags flags) {
- Heap* heap = isolate->heap();
- Object* probe = GetProbeValue(isolate, flags);
- if (probe != heap->undefined_value()) return probe;
- // Seed the cache with an undefined value to make sure that any
- // generated code object can always be inserted into the cache
- // without causing allocation failures.
- Object* result;
- { MaybeObject* maybe_result =
- heap->non_monomorphic_cache()->AtNumberPut(flags,
- heap->undefined_value());
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- heap->public_set_non_monomorphic_cache(NumberDictionary::cast(result));
- return probe;
-}
-
-
-static MaybeObject* FillCache(Isolate* isolate, MaybeObject* maybe_code) {
- Object* code;
- if (maybe_code->ToObject(&code)) {
- if (code->IsCode()) {
- Heap* heap = isolate->heap();
- int entry = heap->non_monomorphic_cache()->FindEntry(
- Code::cast(code)->flags());
- // The entry must be present see comment in ProbeCache.
- ASSERT(entry != -1);
- ASSERT(heap->non_monomorphic_cache()->ValueAt(entry) ==
- heap->undefined_value());
- heap->non_monomorphic_cache()->ValueAtPut(entry, code);
- CHECK(GetProbeValue(isolate, Code::cast(code)->flags()) == code);
- }
- }
- return maybe_code;
+static void FillCache(Isolate* isolate, Handle<Code> code) {
+ Handle<NumberDictionary> dictionary =
+ NumberDictionarySet(isolate->factory()->non_monomorphic_cache(),
+ code->flags(),
+ code,
+ PropertyDetails(NONE, NORMAL));
+ isolate->heap()->public_set_non_monomorphic_cache(*dictionary);
}
@@ -938,188 +775,198 @@ Code* StubCache::FindCallInitialize(int argc,
Code::ExtraICState extra_state =
CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) |
CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT);
- Code::Flags flags = Code::ComputeFlags(kind,
- UNINITIALIZED,
- extra_state,
- NORMAL,
- argc);
- Object* result = ProbeCache(isolate(), flags)->ToObjectUnchecked();
- ASSERT(result != heap()->undefined_value());
+ Code::Flags flags =
+ Code::ComputeFlags(kind, UNINITIALIZED, extra_state, NORMAL, argc);
+
+ // Use raw_unchecked... so we don't get assert failures during GC.
+ NumberDictionary* dictionary =
+ isolate()->heap()->raw_unchecked_non_monomorphic_cache();
+ int entry = dictionary->FindEntry(isolate(), flags);
+ ASSERT(entry != -1);
+ Object* code = dictionary->ValueAt(entry);
// This might be called during the marking phase of the collector
// hence the unchecked cast.
- return reinterpret_cast<Code*>(result);
+ return reinterpret_cast<Code*>(code);
}
-MaybeObject* StubCache::ComputeCallInitialize(int argc,
+Handle<Code> StubCache::ComputeCallInitialize(int argc,
RelocInfo::Mode mode,
Code::Kind kind) {
Code::ExtraICState extra_state =
CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) |
CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT);
- Code::Flags flags = Code::ComputeFlags(kind,
- UNINITIALIZED,
- extra_state,
- NORMAL,
- argc);
- Object* probe;
- { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
- if (!maybe_probe->ToObject(&probe)) return maybe_probe;
- }
- if (!probe->IsUndefined()) return probe;
- StubCompiler compiler;
- return FillCache(isolate_, compiler.CompileCallInitialize(flags));
+ Code::Flags flags =
+ Code::ComputeFlags(kind, UNINITIALIZED, extra_state, NORMAL, argc);
+ Handle<NumberDictionary> cache = isolate_->factory()->non_monomorphic_cache();
+ int entry = cache->FindEntry(isolate_, flags);
+ if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
+
+ StubCompiler compiler(isolate_);
+ Handle<Code> code = compiler.CompileCallInitialize(flags);
+ FillCache(isolate_, code);
+ return code;
}
-Handle<Code> StubCache::ComputeCallInitialize(int argc,
- RelocInfo::Mode mode) {
- CALL_HEAP_FUNCTION(isolate_,
- ComputeCallInitialize(argc, mode, Code::CALL_IC),
- Code);
+Handle<Code> StubCache::ComputeCallInitialize(int argc, RelocInfo::Mode mode) {
+ return ComputeCallInitialize(argc, mode, Code::CALL_IC);
}
Handle<Code> StubCache::ComputeKeyedCallInitialize(int argc) {
- CALL_HEAP_FUNCTION(
- isolate_,
- ComputeCallInitialize(argc, RelocInfo::CODE_TARGET, Code::KEYED_CALL_IC),
- Code);
+ return ComputeCallInitialize(argc, RelocInfo::CODE_TARGET,
+ Code::KEYED_CALL_IC);
}
-MaybeObject* StubCache::ComputeCallPreMonomorphic(
+Handle<Code> StubCache::ComputeCallPreMonomorphic(
int argc,
Code::Kind kind,
- Code::ExtraICState extra_ic_state) {
- Code::Flags flags = Code::ComputeFlags(kind,
- PREMONOMORPHIC,
- extra_ic_state,
- NORMAL,
- argc);
- Object* probe;
- { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
- if (!maybe_probe->ToObject(&probe)) return maybe_probe;
- }
- if (!probe->IsUndefined()) return probe;
- StubCompiler compiler;
- return FillCache(isolate_, compiler.CompileCallPreMonomorphic(flags));
+ Code::ExtraICState extra_state) {
+ Code::Flags flags =
+ Code::ComputeFlags(kind, PREMONOMORPHIC, extra_state, NORMAL, argc);
+ Handle<NumberDictionary> cache = isolate_->factory()->non_monomorphic_cache();
+ int entry = cache->FindEntry(isolate_, flags);
+ if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
+
+ StubCompiler compiler(isolate_);
+ Handle<Code> code = compiler.CompileCallPreMonomorphic(flags);
+ FillCache(isolate_, code);
+ return code;
}
-MaybeObject* StubCache::ComputeCallNormal(int argc,
+Handle<Code> StubCache::ComputeCallNormal(int argc,
Code::Kind kind,
- Code::ExtraICState extra_ic_state) {
- Code::Flags flags = Code::ComputeFlags(kind,
- MONOMORPHIC,
- extra_ic_state,
- NORMAL,
- argc);
- Object* probe;
- { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
- if (!maybe_probe->ToObject(&probe)) return maybe_probe;
- }
- if (!probe->IsUndefined()) return probe;
- StubCompiler compiler;
- return FillCache(isolate_, compiler.CompileCallNormal(flags));
+ Code::ExtraICState extra_state) {
+ Code::Flags flags =
+ Code::ComputeFlags(kind, MONOMORPHIC, extra_state, NORMAL, argc);
+ Handle<NumberDictionary> cache = isolate_->factory()->non_monomorphic_cache();
+ int entry = cache->FindEntry(isolate_, flags);
+ if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
+
+ StubCompiler compiler(isolate_);
+ Handle<Code> code = compiler.CompileCallNormal(flags);
+ FillCache(isolate_, code);
+ return code;
}
-MaybeObject* StubCache::ComputeCallArguments(int argc, Code::Kind kind) {
+Handle<Code> StubCache::ComputeCallArguments(int argc, Code::Kind kind) {
ASSERT(kind == Code::KEYED_CALL_IC);
- Code::Flags flags = Code::ComputeFlags(kind,
- MEGAMORPHIC,
- Code::kNoExtraICState,
- NORMAL,
- argc);
- Object* probe;
- { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
- if (!maybe_probe->ToObject(&probe)) return maybe_probe;
- }
- if (!probe->IsUndefined()) return probe;
- StubCompiler compiler;
- return FillCache(isolate_, compiler.CompileCallArguments(flags));
+ Code::Flags flags =
+ Code::ComputeFlags(kind, MEGAMORPHIC, Code::kNoExtraICState,
+ NORMAL, argc);
+ Handle<NumberDictionary> cache = isolate_->factory()->non_monomorphic_cache();
+ int entry = cache->FindEntry(isolate_, flags);
+ if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
+
+ StubCompiler compiler(isolate_);
+ Handle<Code> code = compiler.CompileCallArguments(flags);
+ FillCache(isolate_, code);
+ return code;
}
-MaybeObject* StubCache::ComputeCallMegamorphic(
+Handle<Code> StubCache::ComputeCallMegamorphic(
int argc,
Code::Kind kind,
- Code::ExtraICState extra_ic_state) {
- Code::Flags flags = Code::ComputeFlags(kind,
- MEGAMORPHIC,
- extra_ic_state,
- NORMAL,
- argc);
- Object* probe;
- { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
- if (!maybe_probe->ToObject(&probe)) return maybe_probe;
- }
- if (!probe->IsUndefined()) return probe;
- StubCompiler compiler;
- return FillCache(isolate_, compiler.CompileCallMegamorphic(flags));
+ Code::ExtraICState extra_state) {
+ Code::Flags flags =
+ Code::ComputeFlags(kind, MEGAMORPHIC, extra_state,
+ NORMAL, argc);
+ Handle<NumberDictionary> cache = isolate_->factory()->non_monomorphic_cache();
+ int entry = cache->FindEntry(isolate_, flags);
+ if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
+
+ StubCompiler compiler(isolate_);
+ Handle<Code> code = compiler.CompileCallMegamorphic(flags);
+ FillCache(isolate_, code);
+ return code;
}
-MaybeObject* StubCache::ComputeCallMiss(int argc,
+Handle<Code> StubCache::ComputeCallMiss(int argc,
Code::Kind kind,
- Code::ExtraICState extra_ic_state) {
+ Code::ExtraICState extra_state) {
// MONOMORPHIC_PROTOTYPE_FAILURE state is used to make sure that miss stubs
// and monomorphic stubs are not mixed up together in the stub cache.
- Code::Flags flags = Code::ComputeFlags(kind,
- MONOMORPHIC_PROTOTYPE_FAILURE,
- extra_ic_state,
- NORMAL,
- argc,
- OWN_MAP);
- Object* probe;
- { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
- if (!maybe_probe->ToObject(&probe)) return maybe_probe;
- }
- if (!probe->IsUndefined()) return probe;
- StubCompiler compiler;
- return FillCache(isolate_, compiler.CompileCallMiss(flags));
+ Code::Flags flags =
+ Code::ComputeFlags(kind, MONOMORPHIC_PROTOTYPE_FAILURE, extra_state,
+ NORMAL, argc, OWN_MAP);
+ Handle<NumberDictionary> cache = isolate_->factory()->non_monomorphic_cache();
+ int entry = cache->FindEntry(isolate_, flags);
+ if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
+
+ StubCompiler compiler(isolate_);
+ Handle<Code> code = compiler.CompileCallMiss(flags);
+ FillCache(isolate_, code);
+ return code;
+}
+
+
+// The CallStubCompiler needs a version of ComputeCallMiss that does not
+// perform GC. This function is temporary, because the stub cache but not
+// yet the stub compiler uses handles.
+MaybeObject* StubCache::TryComputeCallMiss(int argc,
+ Code::Kind kind,
+ Code::ExtraICState extra_state) {
+ Code::Flags flags =
+ Code::ComputeFlags(kind, MONOMORPHIC_PROTOTYPE_FAILURE, extra_state,
+ NORMAL, argc, OWN_MAP);
+ NumberDictionary* cache = isolate_->heap()->non_monomorphic_cache();
+ int entry = cache->FindEntry(isolate_, flags);
+ if (entry != -1) return cache->ValueAt(entry);
+
+ StubCompiler compiler(isolate_);
+ Code* code = NULL;
+ MaybeObject* maybe_code = compiler.TryCompileCallMiss(flags);
+ if (!maybe_code->To(&code)) return maybe_code;
+
+ NumberDictionary* new_cache = NULL;
+ MaybeObject* maybe_new_cache = cache->AtNumberPut(flags, code);
+ if (!maybe_new_cache->To(&new_cache)) return maybe_new_cache;
+ isolate_->heap()->public_set_non_monomorphic_cache(new_cache);
+
+ return code;
}
#ifdef ENABLE_DEBUGGER_SUPPORT
-MaybeObject* StubCache::ComputeCallDebugBreak(
- int argc,
- Code::Kind kind) {
+Handle<Code> StubCache::ComputeCallDebugBreak(int argc,
+ Code::Kind kind) {
// Extra IC state is irrelevant for debug break ICs. They jump to
// the actual call ic to carry out the work.
- Code::Flags flags = Code::ComputeFlags(kind,
- DEBUG_BREAK,
- Code::kNoExtraICState,
- NORMAL,
- argc);
- Object* probe;
- { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
- if (!maybe_probe->ToObject(&probe)) return maybe_probe;
- }
- if (!probe->IsUndefined()) return probe;
- StubCompiler compiler;
- return FillCache(isolate_, compiler.CompileCallDebugBreak(flags));
+ Code::Flags flags =
+ Code::ComputeFlags(kind, DEBUG_BREAK, Code::kNoExtraICState,
+ NORMAL, argc);
+ Handle<NumberDictionary> cache = isolate_->factory()->non_monomorphic_cache();
+ int entry = cache->FindEntry(isolate_, flags);
+ if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
+
+ StubCompiler compiler(isolate_);
+ Handle<Code> code = compiler.CompileCallDebugBreak(flags);
+ FillCache(isolate_, code);
+ return code;
}
-MaybeObject* StubCache::ComputeCallDebugPrepareStepIn(
- int argc,
- Code::Kind kind) {
+Handle<Code> StubCache::ComputeCallDebugPrepareStepIn(int argc,
+ Code::Kind kind) {
// Extra IC state is irrelevant for debug break ICs. They jump to
// the actual call ic to carry out the work.
- Code::Flags flags = Code::ComputeFlags(kind,
- DEBUG_PREPARE_STEP_IN,
- Code::kNoExtraICState,
- NORMAL,
- argc);
- Object* probe;
- { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
- if (!maybe_probe->ToObject(&probe)) return maybe_probe;
- }
- if (!probe->IsUndefined()) return probe;
- StubCompiler compiler;
- return FillCache(isolate_, compiler.CompileCallDebugPrepareStepIn(flags));
+ Code::Flags flags =
+ Code::ComputeFlags(kind, DEBUG_PREPARE_STEP_IN, Code::kNoExtraICState,
+ NORMAL, argc);
+ Handle<NumberDictionary> cache = isolate_->factory()->non_monomorphic_cache();
+ int entry = cache->FindEntry(isolate_, flags);
+ if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
+
+ StubCompiler compiler(isolate_);
+ Handle<Code> code = compiler.CompileCallDebugPrepareStepIn(flags);
+ FillCache(isolate_, code);
+ return code;
}
#endif
@@ -1384,62 +1231,47 @@ RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor) {
}
-MaybeObject* StubCompiler::CompileCallInitialize(Code::Flags flags) {
- HandleScope scope(isolate());
+Handle<Code> StubCompiler::CompileCallInitialize(Code::Flags flags) {
int argc = Code::ExtractArgumentsCountFromFlags(flags);
Code::Kind kind = Code::ExtractKindFromFlags(flags);
- Code::ExtraICState extra_ic_state = Code::ExtractExtraICStateFromFlags(flags);
+ Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
if (kind == Code::CALL_IC) {
- CallIC::GenerateInitialize(masm(), argc, extra_ic_state);
+ CallIC::GenerateInitialize(masm(), argc, extra_state);
} else {
KeyedCallIC::GenerateInitialize(masm(), argc);
}
- Object* result;
- { MaybeObject* maybe_result =
- GetCodeWithFlags(flags, "CompileCallInitialize");
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
+ Handle<Code> code = GetCodeWithFlags(flags, "CompileCallInitialize");
isolate()->counters()->call_initialize_stubs()->Increment();
- Code* code = Code::cast(result);
- USE(code);
PROFILE(isolate(),
CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_INITIALIZE_TAG),
- code, code->arguments_count()));
- GDBJIT(AddCode(GDBJITInterface::CALL_INITIALIZE, Code::cast(code)));
- return result;
+ *code, code->arguments_count()));
+ GDBJIT(AddCode(GDBJITInterface::CALL_INITIALIZE, *code));
+ return code;
}
-MaybeObject* StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
- HandleScope scope(isolate());
+Handle<Code> StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
int argc = Code::ExtractArgumentsCountFromFlags(flags);
// The code of the PreMonomorphic stub is the same as the code
// of the Initialized stub. They just differ on the code object flags.
Code::Kind kind = Code::ExtractKindFromFlags(flags);
- Code::ExtraICState extra_ic_state = Code::ExtractExtraICStateFromFlags(flags);
+ Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
if (kind == Code::CALL_IC) {
- CallIC::GenerateInitialize(masm(), argc, extra_ic_state);
+ CallIC::GenerateInitialize(masm(), argc, extra_state);
} else {
KeyedCallIC::GenerateInitialize(masm(), argc);
}
- Object* result;
- { MaybeObject* maybe_result =
- GetCodeWithFlags(flags, "CompileCallPreMonomorphic");
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
+ Handle<Code> code = GetCodeWithFlags(flags, "CompileCallPreMonomorphic");
isolate()->counters()->call_premonomorphic_stubs()->Increment();
- Code* code = Code::cast(result);
- USE(code);
PROFILE(isolate(),
CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_PRE_MONOMORPHIC_TAG),
- code, code->arguments_count()));
- GDBJIT(AddCode(GDBJITInterface::CALL_PRE_MONOMORPHIC, Code::cast(code)));
- return result;
+ *code, code->arguments_count()));
+ GDBJIT(AddCode(GDBJITInterface::CALL_PRE_MONOMORPHIC, *code));
+ return code;
}
-MaybeObject* StubCompiler::CompileCallNormal(Code::Flags flags) {
- HandleScope scope(isolate());
+Handle<Code> StubCompiler::CompileCallNormal(Code::Flags flags) {
int argc = Code::ExtractArgumentsCountFromFlags(flags);
Code::Kind kind = Code::ExtractKindFromFlags(flags);
if (kind == Code::CALL_IC) {
@@ -1450,79 +1282,81 @@ MaybeObject* StubCompiler::CompileCallNormal(Code::Flags flags) {
} else {
KeyedCallIC::GenerateNormal(masm(), argc);
}
- Object* result;
- { MaybeObject* maybe_result = GetCodeWithFlags(flags, "CompileCallNormal");
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
+ Handle<Code> code = GetCodeWithFlags(flags, "CompileCallNormal");
isolate()->counters()->call_normal_stubs()->Increment();
- Code* code = Code::cast(result);
- USE(code);
PROFILE(isolate(),
CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_NORMAL_TAG),
- code, code->arguments_count()));
- GDBJIT(AddCode(GDBJITInterface::CALL_NORMAL, Code::cast(code)));
- return result;
+ *code, code->arguments_count()));
+ GDBJIT(AddCode(GDBJITInterface::CALL_NORMAL, *code));
+ return code;
}
-MaybeObject* StubCompiler::CompileCallMegamorphic(Code::Flags flags) {
- HandleScope scope(isolate());
+Handle<Code> StubCompiler::CompileCallMegamorphic(Code::Flags flags) {
int argc = Code::ExtractArgumentsCountFromFlags(flags);
Code::Kind kind = Code::ExtractKindFromFlags(flags);
- Code::ExtraICState extra_ic_state = Code::ExtractExtraICStateFromFlags(flags);
+ Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
if (kind == Code::CALL_IC) {
- CallIC::GenerateMegamorphic(masm(), argc, extra_ic_state);
+ CallIC::GenerateMegamorphic(masm(), argc, extra_state);
} else {
KeyedCallIC::GenerateMegamorphic(masm(), argc);
}
- Object* result;
- { MaybeObject* maybe_result =
- GetCodeWithFlags(flags, "CompileCallMegamorphic");
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
+ Handle<Code> code = GetCodeWithFlags(flags, "CompileCallMegamorphic");
isolate()->counters()->call_megamorphic_stubs()->Increment();
- Code* code = Code::cast(result);
- USE(code);
PROFILE(isolate(),
CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MEGAMORPHIC_TAG),
- code, code->arguments_count()));
- GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, Code::cast(code)));
- return result;
+ *code, code->arguments_count()));
+ GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, *code));
+ return code;
}
-MaybeObject* StubCompiler::CompileCallArguments(Code::Flags flags) {
- HandleScope scope(isolate());
+Handle<Code> StubCompiler::CompileCallArguments(Code::Flags flags) {
int argc = Code::ExtractArgumentsCountFromFlags(flags);
KeyedCallIC::GenerateNonStrictArguments(masm(), argc);
+ Handle<Code> code = GetCodeWithFlags(flags, "CompileCallArguments");
+ PROFILE(isolate(),
+ CodeCreateEvent(CALL_LOGGER_TAG(Code::ExtractKindFromFlags(flags),
+ CALL_MEGAMORPHIC_TAG),
+ *code, code->arguments_count()));
+ GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, *code));
+ return code;
+}
+
+
+Handle<Code> StubCompiler::CompileCallMiss(Code::Flags flags) {
+ int argc = Code::ExtractArgumentsCountFromFlags(flags);
Code::Kind kind = Code::ExtractKindFromFlags(flags);
- Object* result;
- { MaybeObject* maybe_result =
- GetCodeWithFlags(flags, "CompileCallArguments");
- if (!maybe_result->ToObject(&result)) return maybe_result;
+ Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
+ if (kind == Code::CALL_IC) {
+ CallIC::GenerateMiss(masm(), argc, extra_state);
+ } else {
+ KeyedCallIC::GenerateMiss(masm(), argc);
}
- Code* code = Code::cast(result);
- USE(code);
+ Handle<Code> code = GetCodeWithFlags(flags, "CompileCallMiss");
+ isolate()->counters()->call_megamorphic_stubs()->Increment();
PROFILE(isolate(),
- CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MEGAMORPHIC_TAG),
- code, code->arguments_count()));
- GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, Code::cast(code)));
- return result;
+ CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MISS_TAG),
+ *code, code->arguments_count()));
+ GDBJIT(AddCode(GDBJITInterface::CALL_MISS, *code));
+ return code;
}
-MaybeObject* StubCompiler::CompileCallMiss(Code::Flags flags) {
+// TODO(kmillikin): This annoying raw pointer implementation should be
+// eliminated when the stub compiler no longer needs it.
+MaybeObject* StubCompiler::TryCompileCallMiss(Code::Flags flags) {
HandleScope scope(isolate());
int argc = Code::ExtractArgumentsCountFromFlags(flags);
Code::Kind kind = Code::ExtractKindFromFlags(flags);
- Code::ExtraICState extra_ic_state = Code::ExtractExtraICStateFromFlags(flags);
+ Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
if (kind == Code::CALL_IC) {
- CallIC::GenerateMiss(masm(), argc, extra_ic_state);
+ CallIC::GenerateMiss(masm(), argc, extra_state);
} else {
KeyedCallIC::GenerateMiss(masm(), argc);
}
Object* result;
- { MaybeObject* maybe_result = GetCodeWithFlags(flags, "CompileCallMiss");
+ { MaybeObject* maybe_result = TryGetCodeWithFlags(flags, "CompileCallMiss");
if (!maybe_result->ToObject(&result)) return maybe_result;
}
isolate()->counters()->call_megamorphic_stubs()->Increment();
@@ -1537,29 +1371,20 @@ MaybeObject* StubCompiler::CompileCallMiss(Code::Flags flags) {
#ifdef ENABLE_DEBUGGER_SUPPORT
-MaybeObject* StubCompiler::CompileCallDebugBreak(Code::Flags flags) {
- HandleScope scope(isolate());
+Handle<Code> StubCompiler::CompileCallDebugBreak(Code::Flags flags) {
Debug::GenerateCallICDebugBreak(masm());
- Object* result;
- { MaybeObject* maybe_result =
- GetCodeWithFlags(flags, "CompileCallDebugBreak");
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- Code* code = Code::cast(result);
- USE(code);
- Code::Kind kind = Code::ExtractKindFromFlags(flags);
- USE(kind);
+ Handle<Code> code = GetCodeWithFlags(flags, "CompileCallDebugBreak");
PROFILE(isolate(),
- CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_DEBUG_BREAK_TAG),
- code, code->arguments_count()));
- return result;
+ CodeCreateEvent(CALL_LOGGER_TAG(Code::ExtractKindFromFlags(flags),
+ CALL_DEBUG_BREAK_TAG),
+ *code, code->arguments_count()));
+ return code;
}
-MaybeObject* StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
- HandleScope scope(isolate());
- // Use the same code for the the step in preparations as we do for
- // the miss case.
+Handle<Code> StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
+ // Use the same code for the the step in preparations as we do for the
+ // miss case.
int argc = Code::ExtractArgumentsCountFromFlags(flags);
Code::Kind kind = Code::ExtractKindFromFlags(flags);
if (kind == Code::CALL_IC) {
@@ -1568,26 +1393,42 @@ MaybeObject* StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
} else {
KeyedCallIC::GenerateMiss(masm(), argc);
}
- Object* result;
- { MaybeObject* maybe_result =
- GetCodeWithFlags(flags, "CompileCallDebugPrepareStepIn");
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- Code* code = Code::cast(result);
- USE(code);
+ Handle<Code> code = GetCodeWithFlags(flags, "CompileCallDebugPrepareStepIn");
PROFILE(isolate(),
CodeCreateEvent(
CALL_LOGGER_TAG(kind, CALL_DEBUG_PREPARE_STEP_IN_TAG),
- code,
+ *code,
code->arguments_count()));
- return result;
+ return code;
}
-#endif
+#endif // ENABLE_DEBUGGER_SUPPORT
#undef CALL_LOGGER_TAG
-MaybeObject* StubCompiler::GetCodeWithFlags(Code::Flags flags,
+
+Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags,
const char* name) {
+ // Create code object in the heap.
+ CodeDesc desc;
+ masm_.GetCode(&desc);
+ Handle<Code> code = factory()->NewCode(desc, flags, masm_.CodeObject());
+#ifdef ENABLE_DISASSEMBLER
+ if (FLAG_print_code_stubs) code->Disassemble(name);
+#endif
+ return code;
+}
+
+
+Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags,
+ Handle<String> name) {
+ return (FLAG_print_code_stubs && !name.is_null())
+ ? GetCodeWithFlags(flags, *name->ToCString())
+ : GetCodeWithFlags(flags, reinterpret_cast<char*>(NULL));
+}
+
+
+MaybeObject* StubCompiler::TryGetCodeWithFlags(Code::Flags flags,
+ const char* name) {
// Check for allocation failures during stub compilation.
if (failure_->IsFailure()) return failure_;
@@ -1604,11 +1445,12 @@ MaybeObject* StubCompiler::GetCodeWithFlags(Code::Flags flags,
}
-MaybeObject* StubCompiler::GetCodeWithFlags(Code::Flags flags, String* name) {
- if (FLAG_print_code_stubs && (name != NULL)) {
- return GetCodeWithFlags(flags, *name->ToCString());
+MaybeObject* StubCompiler::TryGetCodeWithFlags(Code::Flags flags,
+ String* name) {
+ if (FLAG_print_code_stubs && name != NULL) {
+ return TryGetCodeWithFlags(flags, *name->ToCString());
}
- return GetCodeWithFlags(flags, reinterpret_cast<char*>(NULL));
+ return TryGetCodeWithFlags(flags, reinterpret_cast<char*>(NULL));
}
@@ -1626,10 +1468,20 @@ void StubCompiler::LookupPostInterceptor(JSObject* holder,
}
+Handle<Code> LoadStubCompiler::GetCode(PropertyType type, Handle<String> name) {
+ Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, type);
+ Handle<Code> code = GetCodeWithFlags(flags, name);
+ PROFILE(isolate(), CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
+ GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
+ return code;
+}
+
-MaybeObject* LoadStubCompiler::GetCode(PropertyType type, String* name) {
+// TODO(ulan): Eliminate this function when the stub cache is fully
+// handlified.
+MaybeObject* LoadStubCompiler::TryGetCode(PropertyType type, String* name) {
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, type);
- MaybeObject* result = GetCodeWithFlags(flags, name);
+ MaybeObject* result = TryGetCodeWithFlags(flags, name);
if (!result->IsFailure()) {
PROFILE(isolate(),
CodeCreateEvent(Logger::LOAD_IC_TAG,
@@ -1643,12 +1495,25 @@ MaybeObject* LoadStubCompiler::GetCode(PropertyType type, String* name) {
}
-MaybeObject* KeyedLoadStubCompiler::GetCode(PropertyType type,
+Handle<Code> KeyedLoadStubCompiler::GetCode(PropertyType type,
+ Handle<String> name,
+ InlineCacheState state) {
+ Code::Flags flags = Code::ComputeFlags(
+ Code::KEYED_LOAD_IC, state, Code::kNoExtraICState, type);
+ Handle<Code> code = GetCodeWithFlags(flags, name);
+ PROFILE(isolate(), CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
+ GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
+ return code;
+}
+
+// TODO(ulan): Eliminate this function when the stub cache is fully
+// handlified.
+MaybeObject* KeyedLoadStubCompiler::TryGetCode(PropertyType type,
String* name,
InlineCacheState state) {
Code::Flags flags = Code::ComputeFlags(
Code::KEYED_LOAD_IC, state, Code::kNoExtraICState, type);
- MaybeObject* result = GetCodeWithFlags(flags, name);
+ MaybeObject* result = TryGetCodeWithFlags(flags, name);
if (!result->IsFailure()) {
PROFILE(isolate(),
CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG,
@@ -1662,39 +1527,26 @@ MaybeObject* KeyedLoadStubCompiler::GetCode(PropertyType type,
}
-MaybeObject* StoreStubCompiler::GetCode(PropertyType type, String* name) {
+Handle<Code> StoreStubCompiler::GetCode(PropertyType type,
+ Handle<String> name) {
Code::Flags flags =
Code::ComputeMonomorphicFlags(Code::STORE_IC, type, strict_mode_);
- MaybeObject* result = GetCodeWithFlags(flags, name);
- if (!result->IsFailure()) {
- PROFILE(isolate(),
- CodeCreateEvent(Logger::STORE_IC_TAG,
- Code::cast(result->ToObjectUnchecked()),
- name));
- GDBJIT(AddCode(GDBJITInterface::STORE_IC,
- name,
- Code::cast(result->ToObjectUnchecked())));
- }
- return result;
+ Handle<Code> code = GetCodeWithFlags(flags, name);
+ PROFILE(isolate(), CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
+ GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
+ return code;
}
-MaybeObject* KeyedStoreStubCompiler::GetCode(PropertyType type,
- String* name,
+Handle<Code> KeyedStoreStubCompiler::GetCode(PropertyType type,
+ Handle<String> name,
InlineCacheState state) {
Code::Flags flags =
Code::ComputeFlags(Code::KEYED_STORE_IC, state, strict_mode_, type);
- MaybeObject* result = GetCodeWithFlags(flags, name);
- if (!result->IsFailure()) {
- PROFILE(isolate(),
- CodeCreateEvent(Logger::KEYED_STORE_IC_TAG,
- Code::cast(result->ToObjectUnchecked()),
- name));
- GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC,
- name,
- Code::cast(result->ToObjectUnchecked())));
- }
- return result;
+ Handle<Code> code = GetCodeWithFlags(flags, name);
+ PROFILE(isolate(), CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, *code, *name));
+ GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC, *name, *code));
+ return code;
}
@@ -1704,13 +1556,15 @@ void KeyedStoreStubCompiler::GenerateStoreDictionaryElement(
}
-CallStubCompiler::CallStubCompiler(int argc,
+CallStubCompiler::CallStubCompiler(Isolate* isolate,
+ int argc,
Code::Kind kind,
- Code::ExtraICState extra_ic_state,
+ Code::ExtraICState extra_state,
InlineCacheHolderFlag cache_holder)
- : arguments_(argc),
+ : StubCompiler(isolate),
+ arguments_(argc),
kind_(kind),
- extra_ic_state_(extra_ic_state),
+ extra_state_(extra_state),
cache_holder_(cache_holder) {
}
@@ -1763,30 +1617,54 @@ MaybeObject* CallStubCompiler::CompileCustomCall(Object* object,
}
-MaybeObject* CallStubCompiler::GetCode(PropertyType type, String* name) {
+Handle<Code> CallStubCompiler::GetCode(PropertyType type, Handle<String> name) {
int argc = arguments_.immediate();
Code::Flags flags = Code::ComputeMonomorphicFlags(kind_,
type,
- extra_ic_state_,
+ extra_state_,
cache_holder_,
argc);
return GetCodeWithFlags(flags, name);
}
-MaybeObject* CallStubCompiler::GetCode(JSFunction* function) {
+Handle<Code> CallStubCompiler::GetCode(Handle<JSFunction> function) {
+ Handle<String> function_name;
+ if (function->shared()->name()->IsString()) {
+ function_name = Handle<String>(String::cast(function->shared()->name()));
+ }
+ return GetCode(CONSTANT_FUNCTION, function_name);
+}
+
+
+// TODO(kmillikin): Eliminate this function when the stub cache is fully
+// handlified.
+MaybeObject* CallStubCompiler::TryGetCode(PropertyType type, String* name) {
+ int argc = arguments_.immediate();
+ Code::Flags flags = Code::ComputeMonomorphicFlags(kind_,
+ type,
+ extra_state_,
+ cache_holder_,
+ argc);
+ return TryGetCodeWithFlags(flags, name);
+}
+
+
+// TODO(kmillikin): Eliminate this function when the stub cache is fully
+// handlified.
+MaybeObject* CallStubCompiler::TryGetCode(JSFunction* function) {
String* function_name = NULL;
if (function->shared()->name()->IsString()) {
function_name = String::cast(function->shared()->name());
}
- return GetCode(CONSTANT_FUNCTION, function_name);
+ return TryGetCode(CONSTANT_FUNCTION, function_name);
}
MaybeObject* ConstructStubCompiler::GetCode() {
Code::Flags flags = Code::ComputeFlags(Code::STUB);
Object* result;
- { MaybeObject* maybe_result = GetCodeWithFlags(flags, "ConstructStub");
+ { MaybeObject* maybe_result = TryGetCodeWithFlags(flags, "ConstructStub");
if (!maybe_result->ToObject(&result)) return maybe_result;
}
Code* code = Code::cast(result);
diff --git a/deps/v8/src/stub-cache.h b/deps/v8/src/stub-cache.h
index d9ec88f514..11fdb89ebe 100644
--- a/deps/v8/src/stub-cache.h
+++ b/deps/v8/src/stub-cache.h
@@ -76,207 +76,171 @@ class StubCache {
// Computes the right stub matching. Inserts the result in the
// cache before returning. This might compile a stub if needed.
- MUST_USE_RESULT MaybeObject* ComputeLoadNonexistent(
- String* name,
- JSObject* receiver);
-
- MUST_USE_RESULT MaybeObject* ComputeLoadField(String* name,
- JSObject* receiver,
- JSObject* holder,
- int field_index);
-
- MUST_USE_RESULT MaybeObject* ComputeLoadCallback(
- String* name,
- JSObject* receiver,
- JSObject* holder,
- AccessorInfo* callback);
+ Handle<Code> ComputeLoadNonexistent(Handle<String> name,
+ Handle<JSObject> receiver);
- MUST_USE_RESULT MaybeObject* ComputeLoadConstant(String* name,
- JSObject* receiver,
- JSObject* holder,
- Object* value);
+ Handle<Code> ComputeLoadField(Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> holder,
+ int field_index);
- MUST_USE_RESULT MaybeObject* ComputeLoadInterceptor(
- String* name,
- JSObject* receiver,
- JSObject* holder);
+ Handle<Code> ComputeLoadCallback(Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> holder,
+ Handle<AccessorInfo> callback);
- MUST_USE_RESULT MaybeObject* ComputeLoadNormal();
+ Handle<Code> ComputeLoadConstant(Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> holder,
+ Handle<Object> value);
+ Handle<Code> ComputeLoadInterceptor(Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> holder);
- MUST_USE_RESULT MaybeObject* ComputeLoadGlobal(
- String* name,
- JSObject* receiver,
- GlobalObject* holder,
- JSGlobalPropertyCell* cell,
- bool is_dont_delete);
+ Handle<Code> ComputeLoadNormal();
+ Handle<Code> ComputeLoadGlobal(Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<GlobalObject> holder,
+ Handle<JSGlobalPropertyCell> cell,
+ bool is_dont_delete);
// ---
- MUST_USE_RESULT MaybeObject* ComputeKeyedLoadField(String* name,
- JSObject* receiver,
- JSObject* holder,
- int field_index);
+ Handle<Code> ComputeKeyedLoadField(Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> holder,
+ int field_index);
- MUST_USE_RESULT MaybeObject* ComputeKeyedLoadCallback(
- String* name,
- JSObject* receiver,
- JSObject* holder,
- AccessorInfo* callback);
+ Handle<Code> ComputeKeyedLoadCallback(Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> holder,
+ Handle<AccessorInfo> callback);
- MUST_USE_RESULT MaybeObject* ComputeKeyedLoadConstant(
- String* name,
- JSObject* receiver,
- JSObject* holder,
- Object* value);
+ Handle<Code> ComputeKeyedLoadConstant(Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> holder,
+ Handle<Object> value);
- MUST_USE_RESULT MaybeObject* ComputeKeyedLoadInterceptor(
- String* name,
- JSObject* receiver,
- JSObject* holder);
+ Handle<Code> ComputeKeyedLoadInterceptor(Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> holder);
- MUST_USE_RESULT MaybeObject* ComputeKeyedLoadArrayLength(
- String* name,
- JSArray* receiver);
+ Handle<Code> ComputeKeyedLoadArrayLength(Handle<String> name,
+ Handle<JSArray> receiver);
- MUST_USE_RESULT MaybeObject* ComputeKeyedLoadStringLength(
- String* name,
- String* receiver);
+ Handle<Code> ComputeKeyedLoadStringLength(Handle<String> name,
+ Handle<String> receiver);
- MUST_USE_RESULT MaybeObject* ComputeKeyedLoadFunctionPrototype(
- String* name,
- JSFunction* receiver);
+ Handle<Code> ComputeKeyedLoadFunctionPrototype(Handle<String> name,
+ Handle<JSFunction> receiver);
// ---
- MUST_USE_RESULT MaybeObject* ComputeStoreField(
- String* name,
- JSObject* receiver,
- int field_index,
- Map* transition,
- StrictModeFlag strict_mode);
+ Handle<Code> ComputeStoreField(Handle<String> name,
+ Handle<JSObject> receiver,
+ int field_index,
+ Handle<Map> transition,
+ StrictModeFlag strict_mode);
- MUST_USE_RESULT MaybeObject* ComputeStoreNormal(
- StrictModeFlag strict_mode);
+ Handle<Code> ComputeStoreNormal(StrictModeFlag strict_mode);
- MUST_USE_RESULT MaybeObject* ComputeStoreGlobal(
- String* name,
- GlobalObject* receiver,
- JSGlobalPropertyCell* cell,
- StrictModeFlag strict_mode);
+ Handle<Code> ComputeStoreGlobal(Handle<String> name,
+ Handle<GlobalObject> receiver,
+ Handle<JSGlobalPropertyCell> cell,
+ StrictModeFlag strict_mode);
- MUST_USE_RESULT MaybeObject* ComputeStoreCallback(
- String* name,
- JSObject* receiver,
- AccessorInfo* callback,
- StrictModeFlag strict_mode);
+ Handle<Code> ComputeStoreCallback(Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<AccessorInfo> callback,
+ StrictModeFlag strict_mode);
- MUST_USE_RESULT MaybeObject* ComputeStoreInterceptor(
- String* name,
- JSObject* receiver,
- StrictModeFlag strict_mode);
+ Handle<Code> ComputeStoreInterceptor(Handle<String> name,
+ Handle<JSObject> receiver,
+ StrictModeFlag strict_mode);
// ---
- MUST_USE_RESULT MaybeObject* ComputeKeyedStoreField(
- String* name,
- JSObject* receiver,
- int field_index,
- Map* transition,
- StrictModeFlag strict_mode);
+ Handle<Code> ComputeKeyedStoreField(Handle<String> name,
+ Handle<JSObject> receiver,
+ int field_index,
+ Handle<Map> transition,
+ StrictModeFlag strict_mode);
- MUST_USE_RESULT MaybeObject* ComputeKeyedLoadOrStoreElement(
- JSObject* receiver,
- KeyedIC::StubKind stub_kind,
- StrictModeFlag strict_mode);
+ Handle<Code> ComputeKeyedLoadOrStoreElement(Handle<JSObject> receiver,
+ KeyedIC::StubKind stub_kind,
+ StrictModeFlag strict_mode);
// ---
- MUST_USE_RESULT MaybeObject* ComputeCallField(
- int argc,
- Code::Kind,
- Code::ExtraICState extra_ic_state,
- String* name,
- Object* object,
- JSObject* holder,
- int index);
-
- MUST_USE_RESULT MaybeObject* ComputeCallConstant(
- int argc,
- Code::Kind,
- Code::ExtraICState extra_ic_state,
- String* name,
- Object* object,
- JSObject* holder,
- JSFunction* function);
-
- MUST_USE_RESULT MaybeObject* ComputeCallNormal(
- int argc,
- Code::Kind,
- Code::ExtraICState extra_ic_state,
- String* name,
- JSObject* receiver);
-
- MUST_USE_RESULT MaybeObject* ComputeCallInterceptor(
- int argc,
- Code::Kind,
- Code::ExtraICState extra_ic_state,
- String* name,
- Object* object,
- JSObject* holder);
-
- MUST_USE_RESULT MaybeObject* ComputeCallGlobal(
- int argc,
- Code::Kind,
- Code::ExtraICState extra_ic_state,
- String* name,
- JSObject* receiver,
- GlobalObject* holder,
- JSGlobalPropertyCell* cell,
- JSFunction* function);
+ Handle<Code> ComputeCallField(int argc,
+ Code::Kind,
+ Code::ExtraICState extra_state,
+ Handle<String> name,
+ Handle<Object> object,
+ Handle<JSObject> holder,
+ int index);
+
+ Handle<Code> ComputeCallConstant(int argc,
+ Code::Kind,
+ Code::ExtraICState extra_state,
+ Handle<String> name,
+ Handle<Object> object,
+ Handle<JSObject> holder,
+ Handle<JSFunction> function);
+
+ Handle<Code> ComputeCallInterceptor(int argc,
+ Code::Kind,
+ Code::ExtraICState extra_state,
+ Handle<String> name,
+ Handle<Object> object,
+ Handle<JSObject> holder);
+
+ Handle<Code> ComputeCallGlobal(int argc,
+ Code::Kind,
+ Code::ExtraICState extra_state,
+ Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<GlobalObject> holder,
+ Handle<JSGlobalPropertyCell> cell,
+ Handle<JSFunction> function);
// ---
- MUST_USE_RESULT MaybeObject* ComputeCallInitialize(int argc,
- RelocInfo::Mode mode,
- Code::Kind kind);
-
- Handle<Code> ComputeCallInitialize(int argc,
- RelocInfo::Mode mode);
+ Handle<Code> ComputeCallInitialize(int argc, RelocInfo::Mode mode);
Handle<Code> ComputeKeyedCallInitialize(int argc);
- MUST_USE_RESULT MaybeObject* ComputeCallPreMonomorphic(
- int argc,
- Code::Kind kind,
- Code::ExtraICState extra_ic_state);
+ Handle<Code> ComputeCallPreMonomorphic(int argc,
+ Code::Kind kind,
+ Code::ExtraICState extra_state);
+
+ Handle<Code> ComputeCallNormal(int argc,
+ Code::Kind kind,
+ Code::ExtraICState state);
- MUST_USE_RESULT MaybeObject* ComputeCallNormal(int argc,
- Code::Kind kind,
- Code::ExtraICState state);
+ Handle<Code> ComputeCallArguments(int argc, Code::Kind kind);
- MUST_USE_RESULT MaybeObject* ComputeCallArguments(int argc,
- Code::Kind kind);
+ Handle<Code> ComputeCallMegamorphic(int argc,
+ Code::Kind kind,
+ Code::ExtraICState state);
- MUST_USE_RESULT MaybeObject* ComputeCallMegamorphic(int argc,
- Code::Kind kind,
- Code::ExtraICState state);
+ Handle<Code> ComputeCallMiss(int argc,
+ Code::Kind kind,
+ Code::ExtraICState state);
- MUST_USE_RESULT MaybeObject* ComputeCallMiss(int argc,
- Code::Kind kind,
- Code::ExtraICState state);
+ MUST_USE_RESULT MaybeObject* TryComputeCallMiss(int argc,
+ Code::Kind kind,
+ Code::ExtraICState state);
// Finds the Code object stored in the Heap::non_monomorphic_cache().
- MUST_USE_RESULT Code* FindCallInitialize(int argc,
- RelocInfo::Mode mode,
- Code::Kind kind);
+ Code* FindCallInitialize(int argc, RelocInfo::Mode mode, Code::Kind kind);
#ifdef ENABLE_DEBUGGER_SUPPORT
- MUST_USE_RESULT MaybeObject* ComputeCallDebugBreak(int argc, Code::Kind kind);
+ Handle<Code> ComputeCallDebugBreak(int argc, Code::Kind kind);
- MUST_USE_RESULT MaybeObject* ComputeCallDebugPrepareStepIn(int argc,
- Code::Kind kind);
+ Handle<Code> ComputeCallDebugPrepareStepIn(int argc, Code::Kind kind);
#endif
// Update cache for entry hash(name, map).
@@ -330,16 +294,14 @@ class StubCache {
Isolate* isolate() { return isolate_; }
Heap* heap() { return isolate()->heap(); }
+ Factory* factory() { return isolate()->factory(); }
private:
explicit StubCache(Isolate* isolate);
- friend class Isolate;
- friend class SCTableReference;
- static const int kPrimaryTableSize = 2048;
- static const int kSecondaryTableSize = 512;
- Entry primary_[kPrimaryTableSize];
- Entry secondary_[kSecondaryTableSize];
+ Handle<Code> ComputeCallInitialize(int argc,
+ RelocInfo::Mode mode,
+ Code::Kind kind);
// Computes the hashed offsets for primary and secondary caches.
static int PrimaryOffset(String* name, Code::Flags flags, Map* map) {
@@ -384,8 +346,16 @@ class StubCache {
reinterpret_cast<Address>(table) + (offset << shift_amount));
}
+ static const int kPrimaryTableSize = 2048;
+ static const int kSecondaryTableSize = 512;
+
+ Entry primary_[kPrimaryTableSize];
+ Entry secondary_[kSecondaryTableSize];
Isolate* isolate_;
+ friend class Isolate;
+ friend class SCTableReference;
+
DISALLOW_COPY_AND_ASSIGN(StubCache);
};
@@ -407,21 +377,26 @@ DECLARE_RUNTIME_FUNCTION(MaybeObject*, CallInterceptorProperty);
DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor);
-// The stub compiler compiles stubs for the stub cache.
+// The stub compilers compile stubs for the stub cache.
class StubCompiler BASE_EMBEDDED {
public:
- StubCompiler()
- : scope_(), masm_(Isolate::Current(), NULL, 256), failure_(NULL) { }
-
- MUST_USE_RESULT MaybeObject* CompileCallInitialize(Code::Flags flags);
- MUST_USE_RESULT MaybeObject* CompileCallPreMonomorphic(Code::Flags flags);
- MUST_USE_RESULT MaybeObject* CompileCallNormal(Code::Flags flags);
- MUST_USE_RESULT MaybeObject* CompileCallMegamorphic(Code::Flags flags);
- MUST_USE_RESULT MaybeObject* CompileCallArguments(Code::Flags flags);
- MUST_USE_RESULT MaybeObject* CompileCallMiss(Code::Flags flags);
+ explicit StubCompiler(Isolate* isolate)
+ : isolate_(isolate), masm_(isolate, NULL, 256), failure_(NULL) { }
+
+ // Functions to compile either CallIC or KeyedCallIC. The specific kind
+ // is extracted from the code flags.
+ Handle<Code> CompileCallInitialize(Code::Flags flags);
+ Handle<Code> CompileCallPreMonomorphic(Code::Flags flags);
+ Handle<Code> CompileCallNormal(Code::Flags flags);
+ Handle<Code> CompileCallMegamorphic(Code::Flags flags);
+ Handle<Code> CompileCallArguments(Code::Flags flags);
+ Handle<Code> CompileCallMiss(Code::Flags flags);
+
+ MUST_USE_RESULT MaybeObject* TryCompileCallMiss(Code::Flags flags);
+
#ifdef ENABLE_DEBUGGER_SUPPORT
- MUST_USE_RESULT MaybeObject* CompileCallDebugBreak(Code::Flags flags);
- MUST_USE_RESULT MaybeObject* CompileCallDebugPrepareStepIn(Code::Flags flags);
+ Handle<Code> CompileCallDebugBreak(Code::Flags flags);
+ Handle<Code> CompileCallDebugPrepareStepIn(Code::Flags flags);
#endif
// Static functions for generating parts of stubs.
@@ -441,8 +416,10 @@ class StubCompiler BASE_EMBEDDED {
Label* miss);
static void GenerateFastPropertyLoad(MacroAssembler* masm,
- Register dst, Register src,
- JSObject* holder, int index);
+ Register dst,
+ Register src,
+ Handle<JSObject> holder,
+ int index);
static void GenerateLoadArrayLength(MacroAssembler* masm,
Register receiver,
@@ -463,9 +440,9 @@ class StubCompiler BASE_EMBEDDED {
Label* miss_label);
static void GenerateStoreField(MacroAssembler* masm,
- JSObject* object,
+ Handle<JSObject> object,
int index,
- Map* transition,
+ Handle<Map> transition,
Register receiver_reg,
Register name_reg,
Register scratch,
@@ -491,7 +468,30 @@ class StubCompiler BASE_EMBEDDED {
// The function can optionally (when save_at_depth !=
// kInvalidProtoDepth) save the object at the given depth by moving
// it to [esp + kPointerSize].
+ Register CheckPrototypes(Handle<JSObject> object,
+ Register object_reg,
+ Handle<JSObject> holder,
+ Register holder_reg,
+ Register scratch1,
+ Register scratch2,
+ Handle<String> name,
+ Label* miss) {
+ return CheckPrototypes(object, object_reg, holder, holder_reg, scratch1,
+ scratch2, name, kInvalidProtoDepth, miss);
+ }
+ Register CheckPrototypes(Handle<JSObject> object,
+ Register object_reg,
+ Handle<JSObject> holder,
+ Register holder_reg,
+ Register scratch1,
+ Register scratch2,
+ Handle<String> name,
+ int save_at_depth,
+ Label* miss);
+
+ // TODO(kmillikin): Eliminate this function when the stub cache is fully
+ // handlified.
Register CheckPrototypes(JSObject* object,
Register object_reg,
JSObject* holder,
@@ -504,6 +504,8 @@ class StubCompiler BASE_EMBEDDED {
scratch2, name, kInvalidProtoDepth, miss);
}
+ // TODO(kmillikin): Eliminate this function when the stub cache is fully
+ // handlified.
Register CheckPrototypes(JSObject* object,
Register object_reg,
JSObject* holder,
@@ -515,20 +517,25 @@ class StubCompiler BASE_EMBEDDED {
Label* miss);
protected:
- MaybeObject* GetCodeWithFlags(Code::Flags flags, const char* name);
- MaybeObject* GetCodeWithFlags(Code::Flags flags, String* name);
+ Handle<Code> GetCodeWithFlags(Code::Flags flags, const char* name);
+ Handle<Code> GetCodeWithFlags(Code::Flags flags, Handle<String> name);
+
+ MUST_USE_RESULT MaybeObject* TryGetCodeWithFlags(Code::Flags flags,
+ const char* name);
+ MUST_USE_RESULT MaybeObject* TryGetCodeWithFlags(Code::Flags flags,
+ String* name);
MacroAssembler* masm() { return &masm_; }
void set_failure(Failure* failure) { failure_ = failure; }
- void GenerateLoadField(JSObject* object,
- JSObject* holder,
+ void GenerateLoadField(Handle<JSObject> object,
+ Handle<JSObject> holder,
Register receiver,
Register scratch1,
Register scratch2,
Register scratch3,
int index,
- String* name,
+ Handle<String> name,
Label* miss);
MaybeObject* GenerateLoadCallback(JSObject* object,
@@ -542,14 +549,14 @@ class StubCompiler BASE_EMBEDDED {
String* name,
Label* miss);
- void GenerateLoadConstant(JSObject* object,
- JSObject* holder,
+ void GenerateLoadConstant(Handle<JSObject> object,
+ Handle<JSObject> holder,
Register receiver,
Register scratch1,
Register scratch2,
Register scratch3,
- Object* value,
- String* name,
+ Handle<Object> value,
+ Handle<String> name,
Label* miss);
void GenerateLoadInterceptor(JSObject* object,
@@ -567,12 +574,12 @@ class StubCompiler BASE_EMBEDDED {
String* name,
LookupResult* lookup);
- Isolate* isolate() { return scope_.isolate(); }
+ Isolate* isolate() { return isolate_; }
Heap* heap() { return isolate()->heap(); }
Factory* factory() { return isolate()->factory(); }
private:
- HandleScope scope_;
+ Isolate* isolate_;
MacroAssembler masm_;
Failure* failure_;
};
@@ -580,70 +587,95 @@ class StubCompiler BASE_EMBEDDED {
class LoadStubCompiler: public StubCompiler {
public:
- MUST_USE_RESULT MaybeObject* CompileLoadNonexistent(String* name,
- JSObject* object,
- JSObject* last);
+ explicit LoadStubCompiler(Isolate* isolate) : StubCompiler(isolate) { }
+
+ Handle<Code> CompileLoadNonexistent(Handle<String> name,
+ Handle<JSObject> object,
+ Handle<JSObject> last);
- MUST_USE_RESULT MaybeObject* CompileLoadField(JSObject* object,
- JSObject* holder,
- int index,
- String* name);
+ Handle<Code> CompileLoadField(Handle<JSObject> object,
+ Handle<JSObject> holder,
+ int index,
+ Handle<String> name);
+
+ Handle<Code> CompileLoadCallback(Handle<String> name,
+ Handle<JSObject> object,
+ Handle<JSObject> holder,
+ Handle<AccessorInfo> callback);
MUST_USE_RESULT MaybeObject* CompileLoadCallback(String* name,
JSObject* object,
JSObject* holder,
AccessorInfo* callback);
- MUST_USE_RESULT MaybeObject* CompileLoadConstant(JSObject* object,
- JSObject* holder,
- Object* value,
- String* name);
+ Handle<Code> CompileLoadConstant(Handle<JSObject> object,
+ Handle<JSObject> holder,
+ Handle<Object> value,
+ Handle<String> name);
+
+ Handle<Code> CompileLoadInterceptor(Handle<JSObject> object,
+ Handle<JSObject> holder,
+ Handle<String> name);
MUST_USE_RESULT MaybeObject* CompileLoadInterceptor(JSObject* object,
JSObject* holder,
String* name);
- MUST_USE_RESULT MaybeObject* CompileLoadGlobal(JSObject* object,
- GlobalObject* holder,
- JSGlobalPropertyCell* cell,
- String* name,
- bool is_dont_delete);
+ Handle<Code> CompileLoadGlobal(Handle<JSObject> object,
+ Handle<GlobalObject> holder,
+ Handle<JSGlobalPropertyCell> cell,
+ Handle<String> name,
+ bool is_dont_delete);
private:
- MUST_USE_RESULT MaybeObject* GetCode(PropertyType type, String* name);
+ MUST_USE_RESULT MaybeObject* TryGetCode(PropertyType type, String* name);
+
+ Handle<Code> GetCode(PropertyType type, Handle<String> name);
};
class KeyedLoadStubCompiler: public StubCompiler {
public:
- MUST_USE_RESULT MaybeObject* CompileLoadField(String* name,
- JSObject* object,
- JSObject* holder,
- int index);
+ explicit KeyedLoadStubCompiler(Isolate* isolate) : StubCompiler(isolate) { }
+
+ Handle<Code> CompileLoadField(Handle<String> name,
+ Handle<JSObject> object,
+ Handle<JSObject> holder,
+ int index);
+
+ Handle<Code> CompileLoadCallback(Handle<String> name,
+ Handle<JSObject> object,
+ Handle<JSObject> holder,
+ Handle<AccessorInfo> callback);
MUST_USE_RESULT MaybeObject* CompileLoadCallback(String* name,
JSObject* object,
JSObject* holder,
AccessorInfo* callback);
- MUST_USE_RESULT MaybeObject* CompileLoadConstant(String* name,
- JSObject* object,
- JSObject* holder,
- Object* value);
+ Handle<Code> CompileLoadConstant(Handle<String> name,
+ Handle<JSObject> object,
+ Handle<JSObject> holder,
+ Handle<Object> value);
+
+ Handle<Code> CompileLoadInterceptor(Handle<JSObject> object,
+ Handle<JSObject> holder,
+ Handle<String> name);
MUST_USE_RESULT MaybeObject* CompileLoadInterceptor(JSObject* object,
JSObject* holder,
String* name);
- MUST_USE_RESULT MaybeObject* CompileLoadArrayLength(String* name);
- MUST_USE_RESULT MaybeObject* CompileLoadStringLength(String* name);
- MUST_USE_RESULT MaybeObject* CompileLoadFunctionPrototype(String* name);
+ Handle<Code> CompileLoadArrayLength(Handle<String> name);
- MUST_USE_RESULT MaybeObject* CompileLoadElement(Map* receiver_map);
+ Handle<Code> CompileLoadStringLength(Handle<String> name);
- MUST_USE_RESULT MaybeObject* CompileLoadPolymorphic(
- MapList* receiver_maps,
- CodeList* handler_ics);
+ Handle<Code> CompileLoadFunctionPrototype(Handle<String> name);
+
+ Handle<Code> CompileLoadElement(Handle<Map> receiver_map);
+
+ Handle<Code> CompileLoadPolymorphic(MapHandleList* receiver_maps,
+ CodeHandleList* handler_ics);
static void GenerateLoadExternalArray(MacroAssembler* masm,
ElementsKind elements_kind);
@@ -655,34 +687,40 @@ class KeyedLoadStubCompiler: public StubCompiler {
static void GenerateLoadDictionaryElement(MacroAssembler* masm);
private:
- MaybeObject* GetCode(PropertyType type,
- String* name,
+ MaybeObject* TryGetCode(PropertyType type,
+ String* name,
+ InlineCacheState state = MONOMORPHIC);
+
+ Handle<Code> GetCode(PropertyType type,
+ Handle<String> name,
InlineCacheState state = MONOMORPHIC);
};
class StoreStubCompiler: public StubCompiler {
public:
- explicit StoreStubCompiler(StrictModeFlag strict_mode)
- : strict_mode_(strict_mode) { }
+ StoreStubCompiler(Isolate* isolate, StrictModeFlag strict_mode)
+ : StubCompiler(isolate), strict_mode_(strict_mode) { }
- MUST_USE_RESULT MaybeObject* CompileStoreField(JSObject* object,
- int index,
- Map* transition,
- String* name);
- MUST_USE_RESULT MaybeObject* CompileStoreCallback(JSObject* object,
- AccessorInfo* callbacks,
- String* name);
- MUST_USE_RESULT MaybeObject* CompileStoreInterceptor(JSObject* object,
- String* name);
- MUST_USE_RESULT MaybeObject* CompileStoreGlobal(GlobalObject* object,
- JSGlobalPropertyCell* holder,
- String* name);
+ Handle<Code> CompileStoreField(Handle<JSObject> object,
+ int index,
+ Handle<Map> transition,
+ Handle<String> name);
+
+ Handle<Code> CompileStoreCallback(Handle<JSObject> object,
+ Handle<AccessorInfo> callback,
+ Handle<String> name);
+ Handle<Code> CompileStoreInterceptor(Handle<JSObject> object,
+ Handle<String> name);
+
+ Handle<Code> CompileStoreGlobal(Handle<GlobalObject> object,
+ Handle<JSGlobalPropertyCell> holder,
+ Handle<String> name);
private:
- MaybeObject* GetCode(PropertyType type, String* name);
+ Handle<Code> GetCode(PropertyType type, Handle<String> name);
StrictModeFlag strict_mode_;
};
@@ -690,20 +728,19 @@ class StoreStubCompiler: public StubCompiler {
class KeyedStoreStubCompiler: public StubCompiler {
public:
- explicit KeyedStoreStubCompiler(StrictModeFlag strict_mode)
- : strict_mode_(strict_mode) { }
+ KeyedStoreStubCompiler(Isolate* isolate, StrictModeFlag strict_mode)
+ : StubCompiler(isolate), strict_mode_(strict_mode) { }
- MUST_USE_RESULT MaybeObject* CompileStoreField(JSObject* object,
- int index,
- Map* transition,
- String* name);
+ Handle<Code> CompileStoreField(Handle<JSObject> object,
+ int index,
+ Handle<Map> transition,
+ Handle<String> name);
- MUST_USE_RESULT MaybeObject* CompileStoreElement(Map* receiver_map);
+ Handle<Code> CompileStoreElement(Handle<Map> receiver_map);
- MUST_USE_RESULT MaybeObject* CompileStorePolymorphic(
- MapList* receiver_maps,
- CodeList* handler_stubs,
- MapList* transitioned_maps);
+ Handle<Code> CompileStorePolymorphic(MapHandleList* receiver_maps,
+ CodeHandleList* handler_stubs,
+ MapHandleList* transitioned_maps);
static void GenerateStoreFastElement(MacroAssembler* masm,
bool is_js_array,
@@ -718,8 +755,8 @@ class KeyedStoreStubCompiler: public StubCompiler {
static void GenerateStoreDictionaryElement(MacroAssembler* masm);
private:
- MaybeObject* GetCode(PropertyType type,
- String* name,
+ Handle<Code> GetCode(PropertyType type,
+ Handle<String> name,
InlineCacheState state = MONOMORPHIC);
StrictModeFlag strict_mode_;
@@ -742,35 +779,48 @@ class CallOptimization;
class CallStubCompiler: public StubCompiler {
public:
- CallStubCompiler(int argc,
+ CallStubCompiler(Isolate* isolate,
+ int argc,
Code::Kind kind,
- Code::ExtraICState extra_ic_state,
+ Code::ExtraICState extra_state,
InlineCacheHolderFlag cache_holder);
- MUST_USE_RESULT MaybeObject* CompileCallField(
- JSObject* object,
- JSObject* holder,
- int index,
- String* name);
+ Handle<Code> CompileCallField(Handle<JSObject> object,
+ Handle<JSObject> holder,
+ int index,
+ Handle<String> name);
- MUST_USE_RESULT MaybeObject* CompileCallConstant(
- Object* object,
- JSObject* holder,
- JSFunction* function,
- String* name,
- CheckType check);
+ Handle<Code> CompileCallConstant(Handle<Object> object,
+ Handle<JSObject> holder,
+ Handle<JSFunction> function,
+ Handle<String> name,
+ CheckType check);
- MUST_USE_RESULT MaybeObject* CompileCallInterceptor(
- JSObject* object,
- JSObject* holder,
- String* name);
+ MUST_USE_RESULT MaybeObject* CompileCallConstant(Object* object,
+ JSObject* holder,
+ JSFunction* function,
+ String* name,
+ CheckType check);
- MUST_USE_RESULT MaybeObject* CompileCallGlobal(
- JSObject* object,
- GlobalObject* holder,
- JSGlobalPropertyCell* cell,
- JSFunction* function,
- String* name);
+ Handle<Code> CompileCallInterceptor(Handle<JSObject> object,
+ Handle<JSObject> holder,
+ Handle<String> name);
+
+ MUST_USE_RESULT MaybeObject* CompileCallInterceptor(JSObject* object,
+ JSObject* holder,
+ String* name);
+
+ Handle<Code> CompileCallGlobal(Handle<JSObject> object,
+ Handle<GlobalObject> holder,
+ Handle<JSGlobalPropertyCell> cell,
+ Handle<JSFunction> function,
+ Handle<String> name);
+
+ MUST_USE_RESULT MaybeObject* CompileCallGlobal(JSObject* object,
+ GlobalObject* holder,
+ JSGlobalPropertyCell* cell,
+ JSFunction* function,
+ String* name);
static bool HasCustomCallGenerator(JSFunction* function);
@@ -803,18 +853,20 @@ class CallStubCompiler: public StubCompiler {
const ParameterCount arguments_;
const Code::Kind kind_;
- const Code::ExtraICState extra_ic_state_;
+ const Code::ExtraICState extra_state_;
const InlineCacheHolderFlag cache_holder_;
const ParameterCount& arguments() { return arguments_; }
- MUST_USE_RESULT MaybeObject* GetCode(PropertyType type, String* name);
+ Handle<Code> GetCode(PropertyType type, Handle<String> name);
+ Handle<Code> GetCode(Handle<JSFunction> function);
- // Convenience function. Calls GetCode above passing
- // CONSTANT_FUNCTION type and the name of the given function.
- MUST_USE_RESULT MaybeObject* GetCode(JSFunction* function);
+ // TODO(kmillikin): Eliminate these functions when the stub cache is fully
+ // handlified.
+ MUST_USE_RESULT MaybeObject* TryGetCode(PropertyType type, String* name);
+ MUST_USE_RESULT MaybeObject* TryGetCode(JSFunction* function);
- void GenerateNameCheck(String* name, Label* miss);
+ void GenerateNameCheck(Handle<String> name, Label* miss);
void GenerateGlobalReceiverCheck(JSObject* object,
JSObject* holder,
@@ -827,15 +879,18 @@ class CallStubCompiler: public StubCompiler {
JSFunction* function,
Label* miss);
- // Generates a jump to CallIC miss stub. Returns Failure if the jump cannot
- // be generated.
- MUST_USE_RESULT MaybeObject* GenerateMissBranch();
+ // Generates a jump to CallIC miss stub.
+ void GenerateMissBranch();
+
+ // TODO(kmillikin): Eliminate this function when the stub cache is fully
+ // handlified.
+ MUST_USE_RESULT MaybeObject* TryGenerateMissBranch();
};
class ConstructStubCompiler: public StubCompiler {
public:
- explicit ConstructStubCompiler() {}
+ explicit ConstructStubCompiler(Isolate* isolate) : StubCompiler(isolate) { }
MUST_USE_RESULT MaybeObject* CompileConstructStub(JSFunction* function);
diff --git a/deps/v8/src/token.h b/deps/v8/src/token.h
index de4972dd73..7a2156c950 100644
--- a/deps/v8/src/token.h
+++ b/deps/v8/src/token.h
@@ -73,6 +73,7 @@ namespace internal {
T(INIT_VAR, "=init_var", 2) /* AST-use only. */ \
T(INIT_LET, "=init_let", 2) /* AST-use only. */ \
T(INIT_CONST, "=init_const", 2) /* AST-use only. */ \
+ T(INIT_CONST_HARMONY, "=init_const_harmony", 2) /* AST-use only. */ \
T(ASSIGN, "=", 2) \
T(ASSIGN_BIT_OR, "|=", 2) \
T(ASSIGN_BIT_XOR, "^=", 2) \
diff --git a/deps/v8/src/type-info.cc b/deps/v8/src/type-info.cc
index a4b16f4f30..afec71a99a 100644
--- a/deps/v8/src/type-info.cc
+++ b/deps/v8/src/type-info.cc
@@ -423,6 +423,14 @@ void TypeFeedbackOracle::CollectReceiverTypes(unsigned ast_id,
}
+static void AddMapIfMissing(Handle<Map> map, SmallMapList* list) {
+ for (int i = 0; i < list->length(); ++i) {
+ if (list->at(i).is_identical_to(map)) return;
+ }
+ list->Add(map);
+}
+
+
void TypeFeedbackOracle::CollectKeyedReceiverTypes(unsigned ast_id,
SmallMapList* types) {
Handle<Object> object = GetInfo(ast_id);
@@ -436,7 +444,7 @@ void TypeFeedbackOracle::CollectKeyedReceiverTypes(unsigned ast_id,
RelocInfo* info = it.rinfo();
Object* object = info->target_object();
if (object->IsMap()) {
- types->Add(Handle<Map>(Map::cast(object)));
+ AddMapIfMissing(Handle<Map>(Map::cast(object)), types);
}
}
}
@@ -496,61 +504,56 @@ void TypeFeedbackOracle::RelocateRelocInfos(ZoneList<RelocInfo>* infos,
void TypeFeedbackOracle::ProcessRelocInfos(ZoneList<RelocInfo>* infos) {
for (int i = 0; i < infos->length(); i++) {
- Address target_address = (*infos)[i].target_address();
+ RelocInfo reloc_entry = (*infos)[i];
+ Address target_address = reloc_entry.target_address();
unsigned ast_id = static_cast<unsigned>((*infos)[i].data());
- ProcessTargetAt(target_address, ast_id);
- }
-}
-
+ Code* target = Code::GetCodeFromTargetAddress(target_address);
+ switch (target->kind()) {
+ case Code::LOAD_IC:
+ case Code::STORE_IC:
+ case Code::CALL_IC:
+ case Code::KEYED_CALL_IC:
+ if (target->ic_state() == MONOMORPHIC) {
+ if (target->kind() == Code::CALL_IC &&
+ target->check_type() != RECEIVER_MAP_CHECK) {
+ SetInfo(ast_id, Smi::FromInt(target->check_type()));
+ } else {
+ Object* map = target->FindFirstMap();
+ SetInfo(ast_id, map == NULL ? static_cast<Object*>(target) : map);
+ }
+ } else if (target->ic_state() == MEGAMORPHIC) {
+ SetInfo(ast_id, target);
+ }
+ break;
-void TypeFeedbackOracle::ProcessTargetAt(Address target_address,
- unsigned ast_id) {
- Code* target = Code::GetCodeFromTargetAddress(target_address);
- switch (target->kind()) {
- case Code::LOAD_IC:
- case Code::STORE_IC:
- case Code::CALL_IC:
- case Code::KEYED_CALL_IC:
- if (target->ic_state() == MONOMORPHIC) {
- if (target->kind() == Code::CALL_IC &&
- target->check_type() != RECEIVER_MAP_CHECK) {
- SetInfo(ast_id, Smi::FromInt(target->check_type()));
- } else {
- Object* map = target->FindFirstMap();
- SetInfo(ast_id, map == NULL ? static_cast<Object*>(target) : map);
+ case Code::KEYED_LOAD_IC:
+ case Code::KEYED_STORE_IC:
+ if (target->ic_state() == MONOMORPHIC ||
+ target->ic_state() == MEGAMORPHIC) {
+ SetInfo(ast_id, target);
}
- } else if (target->ic_state() == MEGAMORPHIC) {
- SetInfo(ast_id, target);
- }
- break;
+ break;
- case Code::KEYED_LOAD_IC:
- case Code::KEYED_STORE_IC:
- if (target->ic_state() == MONOMORPHIC ||
- target->ic_state() == MEGAMORPHIC) {
+ case Code::UNARY_OP_IC:
+ case Code::BINARY_OP_IC:
+ case Code::COMPARE_IC:
+ case Code::TO_BOOLEAN_IC:
SetInfo(ast_id, target);
- }
- break;
-
- case Code::UNARY_OP_IC:
- case Code::BINARY_OP_IC:
- case Code::COMPARE_IC:
- case Code::TO_BOOLEAN_IC:
- SetInfo(ast_id, target);
- break;
-
- case Code::STUB:
- if (target->major_key() == CodeStub::CallFunction &&
- target->has_function_cache()) {
- Object* value = CallFunctionStub::GetCachedValue(target_address);
- if (value->IsJSFunction()) {
- SetInfo(ast_id, value);
+ break;
+
+ case Code::STUB:
+ if (target->major_key() == CodeStub::CallFunction &&
+ target->has_function_cache()) {
+ Object* value = CallFunctionStub::GetCachedValue(reloc_entry.pc());
+ if (value->IsJSFunction()) {
+ SetInfo(ast_id, value);
+ }
}
- }
- break;
+ break;
- default:
- break;
+ default:
+ break;
+ }
}
}
diff --git a/deps/v8/src/type-info.h b/deps/v8/src/type-info.h
index 0ba10aaa5f..2c3543eafb 100644
--- a/deps/v8/src/type-info.h
+++ b/deps/v8/src/type-info.h
@@ -277,7 +277,6 @@ class TypeFeedbackOracle BASE_EMBEDDED {
byte* old_start,
byte* new_start);
void ProcessRelocInfos(ZoneList<RelocInfo>* infos);
- void ProcessTargetAt(Address target_address, unsigned ast_id);
// Returns an element from the backing store. Returns undefined if
// there is no information.
diff --git a/deps/v8/src/utils.h b/deps/v8/src/utils.h
index a523118a39..2e6cfbd90d 100644
--- a/deps/v8/src/utils.h
+++ b/deps/v8/src/utils.h
@@ -143,6 +143,16 @@ static int PointerValueCompare(const T* a, const T* b) {
}
+// Compare function to compare the object pointer value of two
+// handlified objects. The handles are passed as pointers to the
+// handles.
+template<typename T> class Handle; // Forward declaration.
+template <typename T>
+static int HandleObjectPointerCompare(const Handle<T>* a, const Handle<T>* b) {
+ return Compare<T*>(*(*a), *(*b));
+}
+
+
// Returns the smallest power of two which is >= x. If you pass in a
// number that is already a power of two, it is returned as is.
// Implementation is from "Hacker's Delight" by Henry S. Warren, Jr.,
@@ -168,7 +178,6 @@ static inline uint32_t RoundDownToPowerOf2(uint32_t x) {
template <typename T, typename U>
static inline bool IsAligned(T value, U alignment) {
- ASSERT(IsPowerOf2(alignment));
return (value & (alignment - 1)) == 0;
}
@@ -257,6 +266,18 @@ static inline uint32_t ComputeIntegerHash(uint32_t key) {
}
+static inline uint32_t ComputeLongHash(uint64_t key) {
+ uint64_t hash = key;
+ hash = ~hash + (hash << 18); // hash = (hash << 18) - hash - 1;
+ hash = hash ^ (hash >> 31);
+ hash = hash * 21; // hash = (hash + (hash << 2)) + (hash << 4);
+ hash = hash ^ (hash >> 11);
+ hash = hash + (hash << 6);
+ hash = hash ^ (hash >> 22);
+ return (uint32_t) hash;
+}
+
+
static inline uint32_t ComputePointerHash(void* ptr) {
return ComputeIntegerHash(
static_cast<uint32_t>(reinterpret_cast<intptr_t>(ptr)));
diff --git a/deps/v8/src/v8.cc b/deps/v8/src/v8.cc
index a04114e701..66c65e7b00 100644
--- a/deps/v8/src/v8.cc
+++ b/deps/v8/src/v8.cc
@@ -63,7 +63,7 @@ bool V8::Initialize(Deserializer* des) {
FLAG_harmony_typeof = true;
FLAG_harmony_scoping = true;
FLAG_harmony_proxies = true;
- FLAG_harmony_weakmaps = true;
+ FLAG_harmony_collections = true;
}
InitializeOncePerProcess();
@@ -150,9 +150,10 @@ void V8::SetEntropySource(EntropySource source) {
// Used by JavaScript APIs
-uint32_t V8::Random(Isolate* isolate) {
- ASSERT(isolate == Isolate::Current());
- return random_base(isolate->random_seed());
+uint32_t V8::Random(Context* context) {
+ ASSERT(context->IsGlobalContext());
+ ByteArray* seed = context->random_seed();
+ return random_base(reinterpret_cast<uint32_t*>(seed->GetDataStartAddress()));
}
@@ -182,8 +183,9 @@ typedef union {
} double_int_union;
-Object* V8::FillHeapNumberWithRandom(Object* heap_number, Isolate* isolate) {
- uint64_t random_bits = Random(isolate);
+Object* V8::FillHeapNumberWithRandom(Object* heap_number,
+ Context* context) {
+ uint64_t random_bits = Random(context);
// Make a double* from address (heap_number + sizeof(double)).
double_int_union* r = reinterpret_cast<double_int_union*>(
reinterpret_cast<char*>(heap_number) +
diff --git a/deps/v8/src/v8.h b/deps/v8/src/v8.h
index 2e039d429f..01feefce6f 100644
--- a/deps/v8/src/v8.h
+++ b/deps/v8/src/v8.h
@@ -96,14 +96,14 @@ class V8 : public AllStatic {
// generation.
static void SetEntropySource(EntropySource source);
// Random number generation support. Not cryptographically safe.
- static uint32_t Random(Isolate* isolate);
+ static uint32_t Random(Context* context);
// We use random numbers internally in memory allocation and in the
// compilers for security. In order to prevent information leaks we
// use a separate random state for internal random number
// generation.
static uint32_t RandomPrivate(Isolate* isolate);
static Object* FillHeapNumberWithRandom(Object* heap_number,
- Isolate* isolate);
+ Context* context);
// Idle notification directly from the API.
static bool IdleNotification();
diff --git a/deps/v8/src/v8globals.h b/deps/v8/src/v8globals.h
index 09d26d2f11..f4703ff090 100644
--- a/deps/v8/src/v8globals.h
+++ b/deps/v8/src/v8globals.h
@@ -509,6 +509,16 @@ enum CallKind {
};
+enum ScopeType {
+ EVAL_SCOPE, // The top-level scope for an eval source.
+ FUNCTION_SCOPE, // The top-level scope for a function.
+ GLOBAL_SCOPE, // The top-level scope for a program or a top-level eval.
+ CATCH_SCOPE, // The scope introduced by catch.
+ BLOCK_SCOPE, // The scope introduced by a new block.
+ WITH_SCOPE // The scope introduced by with.
+};
+
+
static const uint32_t kHoleNanUpper32 = 0x7FFFFFFF;
static const uint32_t kHoleNanLower32 = 0xFFFFFFFF;
static const uint32_t kNaNOrInfinityLowerBoundUpper32 = 0x7FF00000;
@@ -521,11 +531,13 @@ const uint64_t kLastNonNaNInt64 =
enum VariableMode {
// User declared variables:
- VAR, // declared via 'var', and 'function' declarations
+ VAR, // declared via 'var', and 'function' declarations
+
+ CONST, // declared via 'const' declarations
- CONST, // declared via 'const' declarations
+ CONST_HARMONY, // declared via 'const' declarations in harmony mode
- LET, // declared via 'let' declarations
+ LET, // declared via 'let' declarations
// Variables introduced by the compiler:
DYNAMIC, // always require dynamic lookup (we don't know
@@ -547,6 +559,13 @@ enum VariableMode {
// in a context
};
+
+enum ClearExceptionFlag {
+ KEEP_EXCEPTION,
+ CLEAR_EXCEPTION
+};
+
+
} } // namespace v8::internal
#endif // V8_V8GLOBALS_H_
diff --git a/deps/v8/src/v8natives.js b/deps/v8/src/v8natives.js
index dee3032378..e6669d58ae 100644
--- a/deps/v8/src/v8natives.js
+++ b/deps/v8/src/v8natives.js
@@ -373,6 +373,7 @@ function IsDataDescriptor(desc) {
// ES5 8.10.3.
function IsGenericDescriptor(desc) {
+ if (IS_UNDEFINED(desc)) return false;
return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc));
}
@@ -704,7 +705,7 @@ function DefineObjectProperty(obj, p, desc, should_throw) {
if (should_throw) {
throw MakeTypeError("define_disallowed", [p]);
} else {
- return;
+ return false;
}
}
@@ -734,7 +735,7 @@ function DefineObjectProperty(obj, p, desc, should_throw) {
if (should_throw) {
throw MakeTypeError("redefine_disallowed", [p]);
} else {
- return;
+ return false;
}
}
// Step 8
@@ -744,7 +745,7 @@ function DefineObjectProperty(obj, p, desc, should_throw) {
if (should_throw) {
throw MakeTypeError("redefine_disallowed", [p]);
} else {
- return;
+ return false;
}
}
// Step 10a
@@ -753,7 +754,7 @@ function DefineObjectProperty(obj, p, desc, should_throw) {
if (should_throw) {
throw MakeTypeError("redefine_disallowed", [p]);
} else {
- return;
+ return false;
}
}
if (!current.isWritable() && desc.hasValue() &&
@@ -761,7 +762,7 @@ function DefineObjectProperty(obj, p, desc, should_throw) {
if (should_throw) {
throw MakeTypeError("redefine_disallowed", [p]);
} else {
- return;
+ return false;
}
}
}
@@ -771,14 +772,14 @@ function DefineObjectProperty(obj, p, desc, should_throw) {
if (should_throw) {
throw MakeTypeError("redefine_disallowed", [p]);
} else {
- return;
+ return false;
}
}
if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) {
if (should_throw) {
throw MakeTypeError("redefine_disallowed", [p]);
} else {
- return;
+ return false;
}
}
}
@@ -881,7 +882,7 @@ function DefineArrayProperty(obj, p, desc, should_throw) {
if (should_throw) {
throw MakeTypeError("define_disallowed", [p]);
} else {
- return;
+ return false;
}
}
if (index >= length) {
@@ -936,14 +937,14 @@ function ToStringArray(obj, trap) {
}
var n = ToUint32(obj.length);
var array = new $Array(n);
- var names = {}
+ var names = {} // TODO(rossberg): use sets once they are ready.
for (var index = 0; index < n; index++) {
var s = ToString(obj[index]);
if (s in names) {
throw MakeTypeError("proxy_repeated_prop_name", [obj, trap, s])
}
array[index] = s;
- names.s = 0;
+ names[s] = 0;
}
return array;
}
@@ -1078,10 +1079,12 @@ function ObjectDefineProperties(obj, properties) {
throw MakeTypeError("obj_ctor_property_non_object", ["defineProperties"]);
var props = ToObject(properties);
var names = GetOwnEnumerablePropertyNames(props);
+ var descriptors = new InternalArray();
for (var i = 0; i < names.length; i++) {
- var name = names[i];
- var desc = ToPropertyDescriptor(props[name]);
- DefineOwnProperty(obj, name, desc, true);
+ descriptors.push(ToPropertyDescriptor(props[names[i]]));
+ }
+ for (var i = 0; i < names.length; i++) {
+ DefineOwnProperty(obj, names[i], descriptors[i], true);
}
return obj;
}
@@ -1517,53 +1520,53 @@ function FunctionToString() {
// ES5 15.3.4.5
function FunctionBind(this_arg) { // Length is 1.
if (!IS_SPEC_FUNCTION(this)) {
- throw new $TypeError('Bind must be called on a function');
- }
- // this_arg is not an argument that should be bound.
- var argc_bound = (%_ArgumentsLength() || 1) - 1;
- var fn = this;
-
- if (argc_bound == 0) {
- var result = function() {
- if (%_IsConstructCall()) {
- // %NewObjectFromBound implicitly uses arguments passed to this
- // function. We do not pass the arguments object explicitly to avoid
- // materializing it and guarantee that this function will be optimized.
- return %NewObjectFromBound(fn, null);
- }
- return %Apply(fn, this_arg, arguments, 0, %_ArgumentsLength());
- };
- } else {
- var bound_args = new InternalArray(argc_bound);
- for(var i = 0; i < argc_bound; i++) {
- bound_args[i] = %_Arguments(i+1);
+ throw new $TypeError('Bind must be called on a function');
+ }
+ var boundFunction = function () {
+ // Poison .arguments and .caller, but is otherwise not detectable.
+ "use strict";
+ // This function must not use any object literals (Object, Array, RegExp),
+ // since the literals-array is being used to store the bound data.
+ if (%_IsConstructCall()) {
+ return %NewObjectFromBound(boundFunction);
}
+ var bindings = %BoundFunctionGetBindings(boundFunction);
- var result = function() {
- // If this is a construct call we use a special runtime method
- // to generate the actual object using the bound function.
- if (%_IsConstructCall()) {
- // %NewObjectFromBound implicitly uses arguments passed to this
- // function. We do not pass the arguments object explicitly to avoid
- // materializing it and guarantee that this function will be optimized.
- return %NewObjectFromBound(fn, bound_args);
- }
-
- // Combine the args we got from the bind call with the args
- // given as argument to the invocation.
+ var argc = %_ArgumentsLength();
+ if (argc == 0) {
+ return %Apply(bindings[0], bindings[1], bindings, 2, bindings.length - 2);
+ }
+ if (bindings.length === 2) {
+ return %Apply(bindings[0], bindings[1], arguments, 0, argc);
+ }
+ var bound_argc = bindings.length - 2;
+ var argv = new InternalArray(bound_argc + argc);
+ for (var i = 0; i < bound_argc; i++) {
+ argv[i] = bindings[i + 2];
+ }
+ for (var j = 0; j < argc; j++) {
+ argv[i++] = %_Arguments(j);
+ }
+ return %Apply(bindings[0], bindings[1], argv, 0, bound_argc + argc);
+ };
+
+ %FunctionRemovePrototype(boundFunction);
+ var new_length = 0;
+ if (%_ClassOf(this) == "Function") {
+ // Function or FunctionProxy.
+ var old_length = this.length;
+ // FunctionProxies might provide a non-UInt32 value. If so, ignore it.
+ if ((typeof old_length === "number") &&
+ ((old_length >>> 0) === old_length)) {
var argc = %_ArgumentsLength();
- var args = new InternalArray(argc + argc_bound);
- // Add bound arguments.
- for (var i = 0; i < argc_bound; i++) {
- args[i] = bound_args[i];
- }
- // Add arguments from call.
- for (var i = 0; i < argc; i++) {
- args[argc_bound + i] = %_Arguments(i);
- }
- return %Apply(fn, this_arg, args, 0, argc + argc_bound);
- };
+ if (argc > 0) argc--; // Don't count the thisArg as parameter.
+ new_length = old_length - argc;
+ if (new_length < 0) new_length = 0;
+ }
}
+ // This runtime function finds any remaining arguments on the stack,
+ // so we don't pass the arguments object.
+ var result = %FunctionBindArguments(boundFunction, this, this_arg, new_length);
// We already have caller and arguments properties on functions,
// which are non-configurable. It therefore makes no sence to
@@ -1571,17 +1574,7 @@ function FunctionBind(this_arg) { // Length is 1.
// that bind should make these throw a TypeError if get or set
// is called and make them non-enumerable and non-configurable.
// To be consistent with our normal functions we leave this as it is.
-
- %FunctionRemovePrototype(result);
- %FunctionSetBound(result);
- // Set the correct length. If this is a function proxy, this.length might
- // throw, or return a bogus result. Leave length alone in that case.
- // TODO(rossberg): This is underspecified in the current proxy proposal.
- try {
- var old_length = ToInteger(this.length);
- var length = (old_length - argc_bound) > 0 ? old_length - argc_bound : 0;
- %BoundFunctionSetLength(result, length);
- } catch(x) {}
+ // TODO(lrn): Do set these to be thrower.
return result;
}
diff --git a/deps/v8/src/variables.cc b/deps/v8/src/variables.cc
index 076cdc0a48..d85e1b270a 100644
--- a/deps/v8/src/variables.cc
+++ b/deps/v8/src/variables.cc
@@ -41,6 +41,7 @@ const char* Variable::Mode2String(VariableMode mode) {
switch (mode) {
case VAR: return "VAR";
case CONST: return "CONST";
+ case CONST_HARMONY: return "CONST";
case LET: return "LET";
case DYNAMIC: return "DYNAMIC";
case DYNAMIC_GLOBAL: return "DYNAMIC_GLOBAL";
diff --git a/deps/v8/src/variables.h b/deps/v8/src/variables.h
index 612d8d33c4..8b2d869568 100644
--- a/deps/v8/src/variables.h
+++ b/deps/v8/src/variables.h
@@ -118,6 +118,15 @@ class Variable: public ZoneObject {
mode_ == DYNAMIC_GLOBAL ||
mode_ == DYNAMIC_LOCAL);
}
+ bool is_const_mode() const {
+ return (mode_ == CONST ||
+ mode_ == CONST_HARMONY);
+ }
+ bool binding_needs_init() const {
+ return (mode_ == LET ||
+ mode_ == CONST ||
+ mode_ == CONST_HARMONY);
+ }
bool is_global() const;
bool is_this() const { return kind_ == THIS; }
@@ -154,6 +163,10 @@ class Variable: public ZoneObject {
Location location_;
int index_;
+ // If this field is set, this variable references the stored locally bound
+ // variable, but it might be shadowed by variable bindings introduced by
+ // non-strict 'eval' calls between the reference scope (inclusive) and the
+ // binding scope (exclusive).
Variable* local_if_not_shadowed_;
// Valid as a LHS? (const and this are not valid LHS, for example)
diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc
index 30402266a1..d34638bf82 100644
--- a/deps/v8/src/version.cc
+++ b/deps/v8/src/version.cc
@@ -34,7 +34,7 @@
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 3
#define MINOR_VERSION 7
-#define BUILD_NUMBER 0
+#define BUILD_NUMBER 1
#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
diff --git a/deps/v8/src/x64/assembler-x64-inl.h b/deps/v8/src/x64/assembler-x64-inl.h
index 10f0b886da..f7b87ec041 100644
--- a/deps/v8/src/x64/assembler-x64-inl.h
+++ b/deps/v8/src/x64/assembler-x64-inl.h
@@ -238,12 +238,12 @@ 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);
if (IsCodeTarget(rmode_)) {
Assembler::set_target_address_at(pc_, target);
Object* target_code = Code::GetCodeFromTargetAddress(target);
- if (host() != NULL) {
+ if (mode == UPDATE_WRITE_BARRIER && host() != NULL) {
host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
host(), this, HeapObject::cast(target_code));
}
@@ -282,11 +282,13 @@ Address* RelocInfo::target_reference_address() {
}
-void RelocInfo::set_target_object(Object* target) {
+void RelocInfo::set_target_object(Object* target, WriteBarrierMode mode) {
ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
Memory::Object_at(pc_) = target;
CPU::FlushICache(pc_, sizeof(Address));
- 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));
}
@@ -310,12 +312,14 @@ 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;
CPU::FlushICache(pc_, sizeof(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/x64/builtins-x64.cc b/deps/v8/src/x64/builtins-x64.cc
index 79ddb1393e..8baa2f32ff 100644
--- a/deps/v8/src/x64/builtins-x64.cc
+++ b/deps/v8/src/x64/builtins-x64.cc
@@ -670,7 +670,7 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
__ testq(rax, rax);
__ j(not_zero, &done);
__ pop(rbx);
- __ Push(FACTORY->undefined_value());
+ __ Push(masm->isolate()->factory()->undefined_value());
__ push(rbx);
__ incq(rax);
__ bind(&done);
@@ -993,10 +993,6 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
}
-// Number of empty elements to allocate for an empty array.
-static const int kPreallocatedArrayElements = 4;
-
-
// Allocate an empty JSArray. The allocated array is put into the result
// register. If the parameter initial_capacity is larger than zero an elements
// backing store is allocated with this size and filled with the hole values.
@@ -1007,9 +1003,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.
__ movq(scratch1, FieldOperand(array_function,
@@ -1033,9 +1029,10 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
// result: JSObject
// scratch1: initial map
// scratch2: start of next object
+ Factory* factory = masm->isolate()->factory();
__ movq(FieldOperand(result, JSObject::kMapOffset), scratch1);
__ Move(FieldOperand(result, JSArray::kPropertiesOffset),
- FACTORY->empty_fixed_array());
+ factory->empty_fixed_array());
// Field JSArray::kElementsOffset is initialized later.
__ Move(FieldOperand(result, JSArray::kLengthOffset), Smi::FromInt(0));
@@ -1043,7 +1040,7 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
// fixed array.
if (initial_capacity == 0) {
__ Move(FieldOperand(result, JSArray::kElementsOffset),
- FACTORY->empty_fixed_array());
+ factory->empty_fixed_array());
return;
}
@@ -1060,15 +1057,14 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
// scratch1: elements array
// scratch2: start of next object
__ Move(FieldOperand(scratch1, HeapObject::kMapOffset),
- FACTORY->fixed_array_map());
+ factory->fixed_array_map());
__ Move(FieldOperand(scratch1, FixedArray::kLengthOffset),
Smi::FromInt(initial_capacity));
// Fill the FixedArray with the hole value. Inline the code if short.
// Reconsider loop unfolding if kPreallocatedArrayElements gets changed.
static const int kLoopUnfoldLimit = 4;
- ASSERT(kPreallocatedArrayElements <= kLoopUnfoldLimit);
- __ Move(scratch3, FACTORY->the_hole_value());
+ __ LoadRoot(scratch3, Heap::kTheHoleValueRootIndex);
if (initial_capacity <= kLoopUnfoldLimit) {
// Use a scratch register here to have only one reloc info when unfolding
// the loop.
@@ -1101,38 +1097,25 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
// register elements_array 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,
Register elements_array_end,
Register scratch,
bool fill_with_hole,
Label* gc_required) {
- Label not_empty, allocated;
-
// Load the initial map from the array function.
__ movq(elements_array,
FieldOperand(array_function,
JSFunction::kPrototypeOrInitialMapOffset));
- // Check whether an empty sized array is requested.
- __ testq(array_size, array_size);
- __ j(not_zero, &not_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(kPreallocatedArrayElements);
- __ AllocateInNewSpace(size,
- result,
- elements_array_end,
- scratch,
- gc_required,
- TAG_OBJECT);
- __ jmp(&allocated);
+ if (FLAG_debug_code) { // Assert that array size is not zero.
+ __ testq(array_size, array_size);
+ __ Assert(not_zero, "array size is unexpectedly 0");
+ }
// Allocate the JSArray object together with space for a FixedArray with the
// requested elements.
- __ bind(&not_empty);
SmiIndex index =
masm->SmiToIndex(kScratchRegister, array_size, kPointerSizeLog2);
__ AllocateInNewSpace(JSArray::kSize + FixedArray::kHeaderSize,
@@ -1150,9 +1133,9 @@ static void AllocateJSArray(MacroAssembler* masm,
// elements_array: initial map
// elements_array_end: start of next object
// array_size: size of array (smi)
- __ bind(&allocated);
+ Factory* factory = masm->isolate()->factory();
__ movq(FieldOperand(result, JSObject::kMapOffset), elements_array);
- __ Move(elements_array, FACTORY->empty_fixed_array());
+ __ Move(elements_array, factory->empty_fixed_array());
__ movq(FieldOperand(result, JSArray::kPropertiesOffset), elements_array);
// Field JSArray::kElementsOffset is initialized later.
__ movq(FieldOperand(result, JSArray::kLengthOffset), array_size);
@@ -1171,16 +1154,7 @@ static void AllocateJSArray(MacroAssembler* masm,
// elements_array_end: start of next object
// array_size: size of array (smi)
__ Move(FieldOperand(elements_array, JSObject::kMapOffset),
- FACTORY->fixed_array_map());
- Label not_empty_2, fill_array;
- __ SmiTest(array_size);
- __ j(not_zero, &not_empty_2);
- // Length of the FixedArray is the number of pre-allocated elements even
- // though the actual JSArray has length 0.
- __ Move(FieldOperand(elements_array, FixedArray::kLengthOffset),
- Smi::FromInt(kPreallocatedArrayElements));
- __ jmp(&fill_array);
- __ bind(&not_empty_2);
+ factory->fixed_array_map());
// For non-empty JSArrays the length of the FixedArray and the JSArray is the
// same.
__ movq(FieldOperand(elements_array, FixedArray::kLengthOffset), array_size);
@@ -1189,10 +1163,9 @@ static void AllocateJSArray(MacroAssembler* masm,
// result: JSObject
// elements_array: elements array
// elements_array_end: start of next object
- __ bind(&fill_array);
if (fill_with_hole) {
Label loop, entry;
- __ Move(scratch, FACTORY->the_hole_value());
+ __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
__ lea(elements_array, Operand(elements_array,
FixedArray::kHeaderSize - kHeapObjectTag));
__ jmp(&entry);
@@ -1222,12 +1195,13 @@ static void AllocateJSArray(MacroAssembler* masm,
// a construct call and a normal call.
static void ArrayNativeCode(MacroAssembler* masm,
Label *call_generic_code) {
- Label argc_one_or_more, argc_two_or_more;
+ Label argc_one_or_more, argc_two_or_more, empty_array, not_empty_array;
// Check for array construction with zero arguments.
__ testq(rax, rax);
__ j(not_zero, &argc_one_or_more);
+ __ bind(&empty_array);
// Handle construction of an empty array.
AllocateEmptyJSArray(masm,
rdi,
@@ -1235,7 +1209,6 @@ static void ArrayNativeCode(MacroAssembler* masm,
rcx,
rdx,
r8,
- kPreallocatedArrayElements,
call_generic_code);
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->array_function_native(), 1);
@@ -1248,6 +1221,16 @@ static void ArrayNativeCode(MacroAssembler* masm,
__ cmpq(rax, Immediate(1));
__ j(not_equal, &argc_two_or_more);
__ movq(rdx, Operand(rsp, kPointerSize)); // Get the argument from the stack.
+
+ __ SmiTest(rdx);
+ __ j(not_zero, &not_empty_array);
+ __ pop(r8); // Adjust stack.
+ __ Drop(1);
+ __ push(r8);
+ __ movq(rax, Immediate(0)); // Treat this as a call with argc of zero.
+ __ jmp(&empty_array);
+
+ __ bind(&not_empty_array);
__ JumpUnlessNonNegativeSmi(rdx, call_generic_code);
// Handle construction of an empty array of a certain size. Bail out if size
diff --git a/deps/v8/src/x64/code-stubs-x64.cc b/deps/v8/src/x64/code-stubs-x64.cc
index 7d41ffe539..3dfebeec41 100644
--- a/deps/v8/src/x64/code-stubs-x64.cc
+++ b/deps/v8/src/x64/code-stubs-x64.cc
@@ -227,7 +227,12 @@ void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
// [rsp + (3 * 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 rcx and check if we need to create a
@@ -247,6 +252,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";
@@ -280,9 +288,24 @@ void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
__ movq(FieldOperand(rax, JSArray::kElementsOffset), rdx);
// Copy the elements array.
- for (int i = 0; i < elements_size; i += kPointerSize) {
- __ movq(rbx, FieldOperand(rcx, i));
- __ movq(FieldOperand(rdx, i), rbx);
+ if (mode_ == CLONE_ELEMENTS) {
+ for (int i = 0; i < elements_size; i += kPointerSize) {
+ __ movq(rbx, FieldOperand(rcx, i));
+ __ movq(FieldOperand(rdx, i), rbx);
+ }
+ } else {
+ ASSERT(mode_ == CLONE_DOUBLE_ELEMENTS);
+ int i;
+ for (i = 0; i < FixedDoubleArray::kHeaderSize; i += kPointerSize) {
+ __ movq(rbx, FieldOperand(rcx, i));
+ __ movq(FieldOperand(rdx, i), rbx);
+ }
+ while (i < elements_size) {
+ __ movsd(xmm0, FieldOperand(rcx, i));
+ __ movsd(FieldOperand(rdx, i), xmm0);
+ i += kDoubleSize;
+ }
+ ASSERT(i == elements_size);
}
}
@@ -3879,7 +3902,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
__ bind(&miss);
}
- __ TryGetFunctionPrototype(rdx, rbx, &slow);
+ __ TryGetFunctionPrototype(rdx, rbx, &slow, true);
// Check that the function prototype is a JS object.
__ JumpIfSmi(rbx, &slow);
@@ -5438,7 +5461,68 @@ void ICCompareStub::GenerateMiss(MacroAssembler* masm) {
}
-MaybeObject* StringDictionaryLookupStub::GenerateNegativeLookup(
+void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
+ Label* miss,
+ Label* done,
+ Register properties,
+ Handle<String> name,
+ Register r0) {
+ // 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++) {
+ // r0 points to properties hash.
+ // Compute the masked index: (hash + i + i * i) & mask.
+ Register index = r0;
+ // Capacity is smi 2^n.
+ __ SmiToInteger32(index, FieldOperand(properties, kCapacityOffset));
+ __ decl(index);
+ __ and_(index,
+ Immediate(name->Hash() + StringDictionary::GetProbeOffset(i)));
+
+ // Scale the index by multiplying by the entry size.
+ ASSERT(StringDictionary::kEntrySize == 3);
+ __ lea(index, Operand(index, index, times_2, 0)); // index *= 3.
+
+ Register entity_name = r0;
+ // Having undefined at this place means the name is not contained.
+ ASSERT_EQ(kSmiTagSize, 1);
+ __ movq(entity_name, Operand(properties,
+ index,
+ times_pointer_size,
+ kElementsStartOffset - kHeapObjectTag));
+ __ Cmp(entity_name, masm->isolate()->factory()->undefined_value());
+ __ j(equal, done);
+
+ // Stop if found the property.
+ __ Cmp(entity_name, Handle<String>(name));
+ __ j(equal, miss);
+
+ // Check if the entry name is not a symbol.
+ __ movq(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset));
+ __ testb(FieldOperand(entity_name, Map::kInstanceTypeOffset),
+ Immediate(kIsSymbolMask));
+ __ j(zero, miss);
+ }
+
+ StringDictionaryLookupStub stub(properties,
+ r0,
+ r0,
+ StringDictionaryLookupStub::NEGATIVE_LOOKUP);
+ __ Push(Handle<Object>(name));
+ __ push(Immediate(name->Hash()));
+ __ CallStub(&stub);
+ __ testq(r0, r0);
+ __ j(not_zero, miss);
+ __ jmp(done);
+}
+
+
+// TODO(kmillikin): Eliminate this function when the stub cache is fully
+// handlified.
+MaybeObject* StringDictionaryLookupStub::TryGenerateNegativeLookup(
MacroAssembler* masm,
Label* miss,
Label* done,
@@ -5665,6 +5749,15 @@ struct AheadOfTimeWriteBarrierStubList kAheadOfTime[] = {
{ rbx, rdx, rcx, EMIT_REMEMBERED_SET},
// KeyedStoreStubCompiler::GenerateStoreFastElement.
{ rdi, rdx, rcx, EMIT_REMEMBERED_SET},
+ // ElementsTransitionGenerator::GenerateSmiOnlyToObject
+ // and ElementsTransitionGenerator::GenerateSmiOnlyToObject
+ // and ElementsTransitionGenerator::GenerateDoubleToObject
+ { rdx, rbx, rdi, EMIT_REMEMBERED_SET},
+ // ElementsTransitionGenerator::GenerateSmiOnlyToDouble
+ // and ElementsTransitionGenerator::GenerateDoubleToObject
+ { rdx, r11, r15, EMIT_REMEMBERED_SET},
+ // ElementsTransitionGenerator::GenerateDoubleToObject
+ { r11, rax, r15, EMIT_REMEMBERED_SET},
// Null termination.
{ no_reg, no_reg, no_reg, EMIT_REMEMBERED_SET}
};
@@ -5912,7 +6005,6 @@ void RecordWriteStub::CheckNeedsToInformIncrementalMarker(
// Fall through when we need to inform the incremental marker.
}
-
#undef __
} } // namespace v8::internal
diff --git a/deps/v8/src/x64/code-stubs-x64.h b/deps/v8/src/x64/code-stubs-x64.h
index 698ba403cd..ffa3f4d202 100644
--- a/deps/v8/src/x64/code-stubs-x64.h
+++ b/deps/v8/src/x64/code-stubs-x64.h
@@ -423,7 +423,16 @@ class StringDictionaryLookupStub: public CodeStub {
void Generate(MacroAssembler* masm);
- MUST_USE_RESULT static MaybeObject* GenerateNegativeLookup(
+ static void GenerateNegativeLookup(MacroAssembler* masm,
+ Label* miss,
+ Label* done,
+ Register properties,
+ Handle<String> name,
+ Register r0);
+
+ // 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/x64/codegen-x64.cc b/deps/v8/src/x64/codegen-x64.cc
index f6102c7c73..4c216e8f2c 100644
--- a/deps/v8/src/x64/codegen-x64.cc
+++ b/deps/v8/src/x64/codegen-x64.cc
@@ -30,6 +30,7 @@
#if defined(V8_TARGET_ARCH_X64)
#include "codegen.h"
+#include "macro-assembler.h"
namespace v8 {
namespace internal {
@@ -143,6 +144,224 @@ ModuloFunction CreateModuloFunction() {
#endif
+#undef __
+
+// -------------------------------------------------------------------------
+// Code generators
+
+#define __ ACCESS_MASM(masm)
+
+void ElementsTransitionGenerator::GenerateSmiOnlyToObject(
+ MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- rax : value
+ // -- rbx : target map
+ // -- rcx : key
+ // -- rdx : receiver
+ // -- rsp[0] : return address
+ // -----------------------------------
+ // Set transitioned map.
+ __ movq(FieldOperand(rdx, HeapObject::kMapOffset), rbx);
+ __ RecordWriteField(rdx,
+ HeapObject::kMapOffset,
+ rbx,
+ rdi,
+ kDontSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+}
+
+
+void ElementsTransitionGenerator::GenerateSmiOnlyToDouble(
+ MacroAssembler* masm, Label* fail) {
+ // ----------- S t a t e -------------
+ // -- rax : value
+ // -- rbx : target map
+ // -- rcx : key
+ // -- rdx : receiver
+ // -- rsp[0] : return address
+ // -----------------------------------
+ // The fail label is not actually used since we do not allocate.
+ Label allocated, cow_array;
+
+ // Check backing store for COW-ness. If the negative case, we do not have to
+ // allocate a new array, since FixedArray and FixedDoubleArray do not differ
+ // in size.
+ __ movq(r8, FieldOperand(rdx, JSObject::kElementsOffset));
+ __ SmiToInteger32(r9, FieldOperand(r8, FixedDoubleArray::kLengthOffset));
+ __ CompareRoot(FieldOperand(r8, HeapObject::kMapOffset),
+ Heap::kFixedCOWArrayMapRootIndex);
+ __ j(equal, &cow_array);
+ __ movq(r14, r8); // Destination array equals source array.
+
+ __ bind(&allocated);
+ // r8 : source FixedArray
+ // r9 : elements array length
+ // r14: destination FixedDoubleArray
+ // Set backing store's map
+ __ LoadRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex);
+ __ movq(FieldOperand(r14, HeapObject::kMapOffset), rdi);
+
+ // Set transitioned map.
+ __ movq(FieldOperand(rdx, HeapObject::kMapOffset), rbx);
+ __ RecordWriteField(rdx,
+ HeapObject::kMapOffset,
+ rbx,
+ rdi,
+ kDontSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+
+ // Convert smis to doubles and holes to hole NaNs. The Array's length
+ // remains unchanged.
+ STATIC_ASSERT(FixedDoubleArray::kLengthOffset == FixedArray::kLengthOffset);
+ STATIC_ASSERT(FixedDoubleArray::kHeaderSize == FixedArray::kHeaderSize);
+
+ Label loop, entry, convert_hole;
+ __ movq(r15, BitCast<int64_t, uint64_t>(kHoleNanInt64), RelocInfo::NONE);
+ // r15: the-hole NaN
+ __ jmp(&entry);
+
+ // Allocate new array if the source array is a COW array.
+ __ bind(&cow_array);
+ __ lea(rdi, Operand(r9, times_pointer_size, FixedArray::kHeaderSize));
+ __ AllocateInNewSpace(rdi, r14, r11, r15, fail, TAG_OBJECT);
+ // Set receiver's backing store.
+ __ movq(FieldOperand(rdx, JSObject::kElementsOffset), r14);
+ __ movq(r11, r14);
+ __ RecordWriteField(rdx,
+ JSObject::kElementsOffset,
+ r11,
+ r15,
+ kDontSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+ // Set backing store's length.
+ __ Integer32ToSmi(r11, r9);
+ __ movq(FieldOperand(r14, FixedDoubleArray::kLengthOffset), r11);
+ __ jmp(&allocated);
+
+ // Conversion loop.
+ __ bind(&loop);
+ __ decq(r9);
+ __ movq(rbx,
+ FieldOperand(r8, r9, times_8, FixedArray::kHeaderSize));
+ // r9 : current element's index
+ // rbx: current element (smi-tagged)
+ __ JumpIfNotSmi(rbx, &convert_hole);
+ __ SmiToInteger32(rbx, rbx);
+ __ cvtlsi2sd(xmm0, rbx);
+ __ movsd(FieldOperand(r14, r9, times_8, FixedDoubleArray::kHeaderSize),
+ xmm0);
+ __ jmp(&entry);
+ __ bind(&convert_hole);
+ __ movq(FieldOperand(r14, r9, times_8, FixedDoubleArray::kHeaderSize), r15);
+ __ bind(&entry);
+ __ testq(r9, r9);
+ __ j(not_zero, &loop);
+}
+
+
+void ElementsTransitionGenerator::GenerateDoubleToObject(
+ MacroAssembler* masm, Label* fail) {
+ // ----------- S t a t e -------------
+ // -- rax : value
+ // -- rbx : target map
+ // -- rcx : key
+ // -- rdx : receiver
+ // -- rsp[0] : return address
+ // -----------------------------------
+ Label loop, entry, convert_hole, gc_required;
+ __ push(rax);
+
+ __ movq(r8, FieldOperand(rdx, JSObject::kElementsOffset));
+ __ SmiToInteger32(r9, FieldOperand(r8, FixedDoubleArray::kLengthOffset));
+ // r8 : source FixedDoubleArray
+ // r9 : number of elements
+ __ lea(rdi, Operand(r9, times_pointer_size, FixedArray::kHeaderSize));
+ __ AllocateInNewSpace(rdi, r11, r14, r15, &gc_required, TAG_OBJECT);
+ // r11: destination FixedArray
+ __ LoadRoot(rdi, Heap::kFixedArrayMapRootIndex);
+ __ movq(FieldOperand(r11, HeapObject::kMapOffset), rdi);
+ __ Integer32ToSmi(r14, r9);
+ __ movq(FieldOperand(r11, FixedArray::kLengthOffset), r14);
+
+ // Prepare for conversion loop.
+ __ movq(rsi, BitCast<int64_t, uint64_t>(kHoleNanInt64), RelocInfo::NONE);
+ __ LoadRoot(rdi, Heap::kTheHoleValueRootIndex);
+ // rsi: the-hole NaN
+ // rdi: pointer to the-hole
+ __ jmp(&entry);
+
+ // Call into runtime if GC is required.
+ __ bind(&gc_required);
+ __ pop(rax);
+ __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
+ __ jmp(fail);
+
+ // Box doubles into heap numbers.
+ __ bind(&loop);
+ __ decq(r9);
+ __ movq(r14, FieldOperand(r8,
+ r9,
+ times_pointer_size,
+ FixedDoubleArray::kHeaderSize));
+ // r9 : current element's index
+ // r14: current element
+ __ cmpq(r14, rsi);
+ __ j(equal, &convert_hole);
+
+ // Non-hole double, copy value into a heap number.
+ __ AllocateHeapNumber(rax, r15, &gc_required);
+ // rax: new heap number
+ __ movq(FieldOperand(rax, HeapNumber::kValueOffset), r14);
+ __ movq(FieldOperand(r11,
+ r9,
+ times_pointer_size,
+ FixedArray::kHeaderSize),
+ rax);
+ __ movq(r15, r9);
+ __ RecordWriteArray(r11,
+ rax,
+ r15,
+ kDontSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+ __ jmp(&entry, Label::kNear);
+
+ // Replace the-hole NaN with the-hole pointer.
+ __ bind(&convert_hole);
+ __ movq(FieldOperand(r11,
+ r9,
+ times_pointer_size,
+ FixedArray::kHeaderSize),
+ rdi);
+
+ __ bind(&entry);
+ __ testq(r9, r9);
+ __ j(not_zero, &loop);
+
+ // Set transitioned map.
+ __ movq(FieldOperand(rdx, HeapObject::kMapOffset), rbx);
+ __ RecordWriteField(rdx,
+ HeapObject::kMapOffset,
+ rbx,
+ rdi,
+ kDontSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+ // Replace receiver's backing store with newly created and filled FixedArray.
+ __ movq(FieldOperand(rdx, JSObject::kElementsOffset), r11);
+ __ RecordWriteField(rdx,
+ JSObject::kElementsOffset,
+ r11,
+ r15,
+ kDontSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+ __ pop(rax);
+ __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
+}
#undef __
diff --git a/deps/v8/src/x64/deoptimizer-x64.cc b/deps/v8/src/x64/deoptimizer-x64.cc
index b7e334ee75..d0a052b42d 100644
--- a/deps/v8/src/x64/deoptimizer-x64.cc
+++ b/deps/v8/src/x64/deoptimizer-x64.cc
@@ -258,16 +258,13 @@ void Deoptimizer::PatchStackCheckCodeAt(Code* unoptimized_code,
Assembler::set_target_address_at(call_target_address,
replacement_code->entry());
- RelocInfo rinfo(call_target_address,
- 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, call_target_address, replacement_code);
}
-void Deoptimizer::RevertStackCheckCodeAt(Address pc_after,
+void Deoptimizer::RevertStackCheckCodeAt(Code* unoptimized_code,
+ Address pc_after,
Code* check_code,
Code* replacement_code) {
Address call_target_address = pc_after - kIntSize;
@@ -282,8 +279,9 @@ void Deoptimizer::RevertStackCheckCodeAt(Address pc_after,
*(call_target_address - 2) = 0x07; // offset
Assembler::set_target_address_at(call_target_address,
check_code->entry());
- check_code->GetHeap()->incremental_marking()->
- RecordCodeTargetPatch(call_target_address, check_code);
+
+ check_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
+ unoptimized_code, call_target_address, check_code);
}
diff --git a/deps/v8/src/x64/full-codegen-x64.cc b/deps/v8/src/x64/full-codegen-x64.cc
index b5c5fc5e71..bf640dbcb1 100644
--- a/deps/v8/src/x64/full-codegen-x64.cc
+++ b/deps/v8/src/x64/full-codegen-x64.cc
@@ -254,7 +254,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());
}
@@ -684,6 +687,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);
@@ -695,7 +700,7 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
Comment cmnt(masm_, "[ Declaration");
VisitForAccumulatorValue(function);
__ movq(StackOperand(variable), result_register());
- } else if (mode == CONST || mode == LET) {
+ } else if (binding_needs_init) {
Comment cmnt(masm_, "[ Declaration");
__ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
__ movq(StackOperand(variable), kScratchRegister);
@@ -728,7 +733,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(kScratchRegister, Heap::kTheHoleValueRootIndex);
__ movq(ContextOperand(rsi, variable->index()), kScratchRegister);
@@ -741,9 +746,13 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
Comment cmnt(masm_, "[ Declaration");
__ push(rsi);
__ Push(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;
__ Push(Smi::FromInt(attr));
// Push initial value, if any.
// Note: For variables we must not push an initial value (such as
@@ -751,7 +760,7 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
// must not destroy the current value.
if (function != NULL) {
VisitForStackValue(function);
- } else if (mode == CONST || mode == LET) {
+ } else if (binding_needs_init) {
__ PushRoot(Heap::kTheHoleValueRootIndex);
} else {
__ Push(Smi::FromInt(0)); // Indicates no initial value.
@@ -890,11 +899,17 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
__ bind(&done_convert);
__ push(rax);
+ // Check for proxies.
+ Label call_runtime;
+ STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
+ __ CmpObjectType(rax, LAST_JS_PROXY_TYPE, rcx);
+ __ j(below_equal, &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;
Register empty_fixed_array_value = r8;
__ LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
Register empty_descriptor_array_value = r9;
@@ -970,9 +985,17 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
__ jmp(&loop);
// We got a fixed array in register rax. Iterate through that.
+ Label non_proxy;
__ bind(&fixed_array);
- __ Push(Smi::FromInt(0)); // Map (0) - force slow check.
- __ push(rax);
+ __ Move(rbx, Smi::FromInt(1)); // Smi indicates slow check
+ __ movq(rcx, Operand(rsp, 0 * kPointerSize)); // Get enumerated object
+ STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
+ __ CmpObjectType(rcx, LAST_JS_PROXY_TYPE, rcx);
+ __ j(above, &non_proxy);
+ __ Move(rbx, Smi::FromInt(0)); // Zero indicates proxy
+ __ bind(&non_proxy);
+ __ push(rbx); // Smi
+ __ push(rax); // Array
__ movq(rax, FieldOperand(rax, FixedArray::kLengthOffset));
__ push(rax); // Fixed array length (as smi).
__ Push(Smi::FromInt(0)); // Initial index.
@@ -991,17 +1014,22 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
index.scale,
FixedArray::kHeaderSize));
- // 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 rdx.
__ movq(rdx, Operand(rsp, 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;
__ movq(rcx, Operand(rsp, 4 * kPointerSize));
__ cmpq(rdx, FieldOperand(rcx, HeapObject::kMapOffset));
__ j(equal, &update_each, Label::kNear);
+ // For proxies, no filtering is done.
+ // TODO(rossberg): What if only a prototype is a proxy? Not specified yet.
+ __ Cmp(rdx, Smi::FromInt(0));
+ __ j(equal, &update_each, Label::kNear);
+
// Convert the entry to a string or null if it isn't a property
// anymore. If the property has been removed while iterating, we
// just skip it.
@@ -1055,7 +1083,7 @@ void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
!pretenure &&
scope()->is_function_scope() &&
info->num_literals() == 0) {
- FastNewClosureStub stub(info->strict_mode() ? kStrictMode : kNonStrictMode);
+ FastNewClosureStub stub(info->strict_mode_flag());
__ Push(info);
__ CallStub(&stub);
} else {
@@ -1085,7 +1113,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.
__ cmpq(ContextOperand(context, Context::EXTENSION_INDEX),
Immediate(0));
@@ -1099,7 +1127,7 @@ void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var,
// If no outer scope calls eval, we do not need to check more
// context extensions. If we have reached an eval scope, we check
// all extensions from this point.
- 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();
}
@@ -1145,7 +1173,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.
__ cmpq(ContextOperand(context, Context::EXTENSION_INDEX),
Immediate(0));
@@ -1182,12 +1210,14 @@ void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var,
} else if (var->mode() == DYNAMIC_LOCAL) {
Variable* local = var->local_if_not_shadowed();
__ movq(rax, ContextSlotOperandCheckExtensions(local, slow));
- if (local->mode() == CONST || local->mode() == LET) {
+ if (local->mode() == CONST ||
+ local->mode() == CONST_HARMONY ||
+ local->mode() == LET) {
__ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
__ j(not_equal, done);
if (local->mode() == CONST) {
__ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
- } else { // LET
+ } else { // LET || CONST_HARMONY
__ Push(var->name());
__ CallRuntime(Runtime::kThrowReferenceError, 1);
}
@@ -1221,7 +1251,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
case Variable::LOCAL:
case Variable::CONTEXT: {
Comment cmnt(masm_, var->IsContextSlot() ? "Context slot" : "Stack slot");
- if (var->mode() != LET && var->mode() != CONST) {
+ if (!var->binding_needs_init()) {
context()->Plug(var);
} else {
// Let and const need a read barrier.
@@ -1229,10 +1259,14 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
GetVar(rax, var);
__ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
__ j(not_equal, &done, Label::kNear);
- 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.
__ Push(var->name());
__ CallRuntime(Runtime::kThrowReferenceError, 1);
- } else { // CONST
+ } else {
+ // Uninitalized const bindings outside of harmony mode are unholed.
+ ASSERT(var->mode() == CONST);
__ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
}
__ bind(&done);
@@ -1417,12 +1451,18 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
ZoneList<Expression*>* subexprs = expr->values();
int length = subexprs->length();
+ Handle<FixedArray> constant_elements = expr->constant_elements();
+ ASSERT_EQ(2, constant_elements->length());
+ ElementsKind constant_elements_kind =
+ static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
+ Handle<FixedArrayBase> constant_elements_values(
+ FixedArrayBase::cast(constant_elements->get(1)));
__ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
__ push(FieldOperand(rbx, JSFunction::kLiteralsOffset));
__ Push(Smi::FromInt(expr->literal_index()));
- __ Push(expr->constant_elements());
- if (expr->constant_elements()->map() ==
+ __ Push(constant_elements);
+ if (constant_elements_values->map() ==
isolate()->heap()->fixed_cow_array_map()) {
FastCloneShallowArrayStub stub(
FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length);
@@ -1433,8 +1473,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);
}
@@ -1459,22 +1505,59 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
// Store the subexpression value in the array's elements.
__ movq(r8, Operand(rsp, 0)); // Copy of array literal.
+ __ movq(rdi, FieldOperand(r8, JSObject::kMapOffset));
__ movq(rbx, FieldOperand(r8, JSObject::kElementsOffset));
int offset = FixedArray::kHeaderSize + (i * kPointerSize);
- __ movq(FieldOperand(rbx, offset), result_register());
- Label no_map_change;
- __ JumpIfSmi(result_register(), &no_map_change);
+ Label element_done;
+ Label double_elements;
+ Label smi_element;
+ Label slow_elements;
+ Label fast_elements;
+ __ CheckFastElements(rdi, &double_elements);
+
+ // FAST_SMI_ONLY_ELEMENTS or FAST_ELEMENTS
+ __ JumpIfSmi(result_register(), &smi_element);
+ __ CheckFastSmiOnlyElements(rdi, &fast_elements);
+
+ // Store into the array literal requires a elements transition. Call into
+ // the runtime.
+ __ bind(&slow_elements);
+ __ push(r8); // Copy of array literal.
+ __ Push(Smi::FromInt(i));
+ __ push(result_register());
+ __ Push(Smi::FromInt(NONE)); // PropertyAttributes
+ __ Push(Smi::FromInt(strict_mode_flag())); // Strict mode.
+ __ CallRuntime(Runtime::kSetProperty, 5);
+ __ jmp(&element_done);
+
+ // Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS.
+ __ bind(&double_elements);
+ __ movq(rcx, Immediate(i));
+ __ StoreNumberToDoubleElements(result_register(),
+ rbx,
+ rcx,
+ xmm0,
+ &slow_elements);
+ __ jmp(&element_done);
+
+ // Array literal has ElementsKind of FAST_ELEMENTS and value is an object.
+ __ bind(&fast_elements);
+ __ movq(FieldOperand(rbx, offset), result_register());
// Update the write barrier for the array store.
__ RecordWriteField(rbx, offset, result_register(), rcx,
kDontSaveFPRegs,
EMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
- __ movq(rdi, FieldOperand(rbx, JSObject::kMapOffset));
- __ CheckFastSmiOnlyElements(rdi, &no_map_change, Label::kNear);
- __ push(r8);
- __ CallRuntime(Runtime::kNonSmiElementStored, 1);
- __ bind(&no_map_change);
+ __ jmp(&element_done);
+
+ // Array literal has ElementsKind of FAST_SMI_ONLY_ELEMENTS or
+ // FAST_ELEMENTS, and value is Smi.
+ __ bind(&smi_element);
+ __ movq(FieldOperand(rbx, offset), result_register());
+ // Fall through
+
+ __ bind(&element_done);
PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
}
@@ -1805,8 +1888,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, rcx);
if (FLAG_debug_code && op == Token::INIT_LET) {
@@ -2657,9 +2741,12 @@ void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) {
// The fresh HeapNumber is in rbx, which is callee-save on both x64 ABIs.
__ PrepareCallCFunction(1);
#ifdef _WIN64
- __ LoadAddress(rcx, ExternalReference::isolate_address());
+ __ movq(rcx, ContextOperand(context_register(), Context::GLOBAL_INDEX));
+ __ movq(rcx, FieldOperand(rcx, GlobalObject::kGlobalContextOffset));
+
#else
- __ LoadAddress(rdi, ExternalReference::isolate_address());
+ __ movq(rdi, ContextOperand(context_register(), Context::GLOBAL_INDEX));
+ __ movq(rdi, FieldOperand(rdi, GlobalObject::kGlobalContextOffset));
#endif
__ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
@@ -3997,33 +4084,25 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
case Token::EQ_STRICT:
case Token::EQ:
cc = equal;
- __ pop(rdx);
break;
case Token::LT:
cc = less;
- __ pop(rdx);
break;
case Token::GT:
- // Reverse left and right sizes to obtain ECMA-262 conversion order.
- cc = less;
- __ movq(rdx, result_register());
- __ pop(rax);
+ cc = greater;
break;
case Token::LTE:
- // Reverse left and right sizes to obtain ECMA-262 conversion order.
- cc = greater_equal;
- __ movq(rdx, result_register());
- __ pop(rax);
+ cc = less_equal;
break;
case Token::GTE:
cc = greater_equal;
- __ pop(rdx);
break;
case Token::IN:
case Token::INSTANCEOF:
default:
UNREACHABLE();
}
+ __ pop(rdx);
bool inline_smi_code = ShouldInlineSmiCase(op);
JumpPatchSite patch_site(masm_);
diff --git a/deps/v8/src/x64/ic-x64.cc b/deps/v8/src/x64/ic-x64.cc
index 27a96674cf..e8ab06cdab 100644
--- a/deps/v8/src/x64/ic-x64.cc
+++ b/deps/v8/src/x64/ic-x64.cc
@@ -712,12 +712,11 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
// Writing a non-smi, check whether array allows non-smi elements.
// r9: receiver's map
__ CheckFastObjectElements(r9, &slow, Label::kNear);
- __ lea(rcx,
- FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize));
- __ movq(Operand(rcx, 0), rax);
- __ movq(rdx, rax);
- __ RecordWrite(
- rbx, rcx, rdx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
+ __ movq(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize),
+ rax);
+ __ movq(rdx, rax); // Preserve the value which is returned.
+ __ RecordWriteArray(
+ rbx, rdx, rcx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
__ ret(0);
__ bind(&fast_double_with_map_check);
@@ -736,10 +735,10 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
// 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 -------------
// rcx : function name
// rdx : receiver
@@ -749,7 +748,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(masm, flags, rdx, rcx, rbx,
@@ -822,7 +821,7 @@ static void GenerateFunctionTailCall(MacroAssembler* masm,
// The generated code falls through if the call should be handled by runtime.
-static void GenerateCallNormal(MacroAssembler* masm, int argc) {
+void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) {
// ----------- S t a t e -------------
// rcx : function name
// rsp[0] : return address
@@ -849,10 +848,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 -------------
// rcx : function name
// rsp[0] : return address
@@ -910,7 +909,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);
@@ -942,39 +941,6 @@ void CallIC::GenerateMegamorphic(MacroAssembler* masm,
}
-void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
- // ----------- S t a t e -------------
- // rcx : function name
- // rsp[0] : return address
- // rsp[8] : argument argc
- // rsp[16] : argument argc - 1
- // ...
- // rsp[argc * 8] : argument 1
- // rsp[(argc + 1) * 8] : argument 0 = receiver
- // -----------------------------------
-
- GenerateCallNormal(masm, argc);
- GenerateMiss(masm, argc, Code::kNoExtraICState);
-}
-
-
-void CallIC::GenerateMiss(MacroAssembler* masm,
- int argc,
- Code::ExtraICState extra_ic_state) {
- // ----------- S t a t e -------------
- // rcx : function name
- // rsp[0] : return address
- // rsp[8] : argument argc
- // rsp[16] : argument argc - 1
- // ...
- // rsp[argc * 8] : argument 1
- // rsp[(argc + 1) * 8] : argument 0 = receiver
- // -----------------------------------
-
- GenerateCallMiss(masm, argc, IC::kCallIC_Miss, extra_ic_state);
-}
-
-
void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
// ----------- S t a t e -------------
// rcx : function name
@@ -1102,27 +1068,12 @@ void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
__ JumpIfSmi(rcx, &miss);
Condition cond = masm->IsObjectStringType(rcx, rax, rax);
__ j(NegateCondition(cond), &miss);
- GenerateCallNormal(masm, argc);
+ CallICBase::GenerateNormal(masm, argc);
__ bind(&miss);
GenerateMiss(masm, argc);
}
-void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) {
- // ----------- S t a t e -------------
- // rcx : function name
- // rsp[0] : return address
- // rsp[8] : argument argc
- // rsp[16] : argument argc - 1
- // ...
- // rsp[argc * 8] : argument 1
- // rsp[(argc + 1) * 8] : argument 0 = receiver
- // -----------------------------------
-
- GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss, Code::kNoExtraICState);
-}
-
-
static Operand GenerateMappedArgumentsLookup(MacroAssembler* masm,
Register object,
Register key,
@@ -1602,6 +1553,51 @@ void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
}
+void KeyedStoreIC::GenerateTransitionElementsSmiToDouble(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- rbx : target map
+ // -- rdx : receiver
+ // -- rsp[0] : return address
+ // -----------------------------------
+ // Must return the modified receiver in eax.
+ if (!FLAG_trace_elements_transitions) {
+ Label fail;
+ ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &fail);
+ __ movq(rax, rdx);
+ __ Ret();
+ __ bind(&fail);
+ }
+
+ __ pop(rbx);
+ __ push(rdx);
+ __ push(rbx); // return address
+ __ TailCallRuntime(Runtime::kTransitionElementsSmiToDouble, 1, 1);
+}
+
+
+void KeyedStoreIC::GenerateTransitionElementsDoubleToObject(
+ MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- rbx : target map
+ // -- rdx : receiver
+ // -- rsp[0] : return address
+ // -----------------------------------
+ // Must return the modified receiver in eax.
+ if (!FLAG_trace_elements_transitions) {
+ Label fail;
+ ElementsTransitionGenerator::GenerateDoubleToObject(masm, &fail);
+ __ movq(rax, rdx);
+ __ Ret();
+ __ bind(&fail);
+ }
+
+ __ pop(rbx);
+ __ push(rdx);
+ __ push(rbx); // return address
+ __ TailCallRuntime(Runtime::kTransitionElementsDoubleToObject, 1, 1);
+}
+
+
#undef __
@@ -1613,11 +1609,9 @@ Condition CompareIC::ComputeCondition(Token::Value op) {
case Token::LT:
return less;
case Token::GT:
- // Reverse left and right operands to obtain ECMA-262 conversion order.
- return less;
+ return greater;
case Token::LTE:
- // Reverse left and right operands to obtain ECMA-262 conversion order.
- return greater_equal;
+ return less_equal;
case Token::GTE:
return greater_equal;
default:
diff --git a/deps/v8/src/x64/lithium-codegen-x64.cc b/deps/v8/src/x64/lithium-codegen-x64.cc
index 45aaad7549..38a8c18be3 100644
--- a/deps/v8/src/x64/lithium-codegen-x64.cc
+++ b/deps/v8/src/x64/lithium-codegen-x64.cc
@@ -374,6 +374,12 @@ int LCodeGen::ToInteger32(LConstantOperand* op) const {
}
+double LCodeGen::ToDouble(LConstantOperand* op) const {
+ Handle<Object> value = chunk_->LookupLiteral(op);
+ return value->Number();
+}
+
+
Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
Handle<Object> literal = chunk_->LookupLiteral(op);
ASSERT(chunk_->LookupLiteralRepresentation(op).IsTagged());
@@ -1526,39 +1532,51 @@ inline Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
}
-void LCodeGen::EmitCmpI(LOperand* left, LOperand* right) {
- if (right->IsConstantOperand()) {
- int32_t value = ToInteger32(LConstantOperand::cast(right));
- if (left->IsRegister()) {
- __ cmpl(ToRegister(left), Immediate(value));
- } else {
- __ cmpl(ToOperand(left), Immediate(value));
- }
- } else if (right->IsRegister()) {
- __ cmpl(ToRegister(left), ToRegister(right));
- } else {
- __ cmpl(ToRegister(left), ToOperand(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());
+ Condition cc = TokenToCondition(instr->op(), instr->is_double());
- if (instr->is_double()) {
- // Don't base result on EFLAGS when a NaN is involved. Instead
- // jump to the false block.
- __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
- __ j(parity_even, chunk_->GetAssemblyLabel(false_block));
+ 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()) {
+ // Don't base result on EFLAGS when a NaN is involved. Instead
+ // jump to the false block.
+ __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
+ __ j(parity_even, chunk_->GetAssemblyLabel(false_block));
+ } else {
+ int32_t value;
+ if (right->IsConstantOperand()) {
+ value = ToInteger32(LConstantOperand::cast(right));
+ __ cmpl(ToRegister(left), Immediate(value));
+ } else if (left->IsConstantOperand()) {
+ value = ToInteger32(LConstantOperand::cast(left));
+ if (right->IsRegister()) {
+ __ cmpl(ToRegister(right), Immediate(value));
+ } else {
+ __ cmpl(ToOperand(right), Immediate(value));
+ }
+ // We transposed the operands. Reverse the condition.
+ cc = ReverseCondition(cc);
+ } else {
+ if (right->IsRegister()) {
+ __ cmpl(ToRegister(left), ToRegister(right));
+ } else {
+ __ cmpl(ToRegister(left), ToOperand(right));
+ }
+ }
+ }
+ EmitBranch(true_block, false_block, cc);
}
-
- Condition cc = TokenToCondition(instr->op(), instr->is_double());
- EmitBranch(true_block, false_block, cc);
}
@@ -1979,9 +1997,6 @@ void LCodeGen::DoCmpT(LCmpT* instr) {
CallCode(ic, RelocInfo::CODE_TARGET, instr);
Condition condition = TokenToCondition(op, false);
- if (op == Token::GT || op == Token::LTE) {
- condition = ReverseCondition(condition);
- }
Label true_value, done;
__ testq(rax, rax);
__ j(condition, &true_value, Label::kNear);
@@ -2055,19 +2070,24 @@ void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
// Store the value.
__ movq(Operand(address, 0), value);
- Label smi_store;
- __ JumpIfSmi(value, &smi_store, Label::kNear);
+ if (instr->hydrogen()->NeedsWriteBarrier()) {
+ Label smi_store;
+ HType type = instr->hydrogen()->value()->type();
+ if (!type.IsHeapNumber() && !type.IsString() && !type.IsNonPrimitive()) {
+ __ JumpIfSmi(value, &smi_store, Label::kNear);
+ }
- int offset = JSGlobalPropertyCell::kValueOffset - kHeapObjectTag;
- __ lea(object, Operand(address, -offset));
- // Cells are always in the remembered set.
- __ RecordWrite(object,
- address,
- value,
- kSaveFPRegs,
- OMIT_REMEMBERED_SET,
- OMIT_SMI_CHECK);
- __ bind(&smi_store);
+ int offset = JSGlobalPropertyCell::kValueOffset - kHeapObjectTag;
+ __ lea(object, Operand(address, -offset));
+ // Cells are always in the remembered set.
+ __ RecordWrite(object,
+ address,
+ value,
+ kSaveFPRegs,
+ OMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+ __ bind(&smi_store);
+ }
}
@@ -2094,10 +2114,19 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
Register context = ToRegister(instr->context());
Register value = ToRegister(instr->value());
__ movq(ContextOperand(context, instr->slot_index()), value);
- 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;
int offset = Context::SlotOffset(instr->slot_index());
Register scratch = ToRegister(instr->TempAt(0));
- __ RecordWriteContextSlot(context, offset, value, scratch, kSaveFPRegs);
+ __ RecordWriteContextSlot(context,
+ offset,
+ value,
+ scratch,
+ kSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ check_needed);
}
}
@@ -2118,7 +2147,7 @@ void LCodeGen::EmitLoadFieldOrConstantFunction(Register result,
Register object,
Handle<Map> type,
Handle<String> name) {
- LookupResult lookup;
+ LookupResult lookup(isolate());
type->LookupInDescriptors(NULL, *name, &lookup);
ASSERT(lookup.IsProperty() &&
(lookup.type() == FIELD || lookup.type() == CONSTANT_FUNCTION));
@@ -2561,7 +2590,7 @@ void LCodeGen::DoPushArgument(LPushArgument* instr) {
void LCodeGen::DoThisFunction(LThisFunction* instr) {
Register result = ToRegister(instr->result());
- __ movq(result, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
+ LoadHeapObject(result, instr->hydrogen()->closure());
}
@@ -3061,21 +3090,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()) {
__ movq(FieldOperand(object, offset), value);
- if (instr->needs_write_barrier()) {
+ if (instr->hydrogen()->NeedsWriteBarrier()) {
Register temp = ToRegister(instr->TempAt(0));
// Update the write barrier for the object for in-object properties.
- __ RecordWriteField(object, offset, value, temp, kSaveFPRegs);
+ __ RecordWriteField(object,
+ offset,
+ value,
+ temp,
+ kSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ check_needed);
}
} else {
Register temp = ToRegister(instr->TempAt(0));
__ movq(temp, FieldOperand(object, JSObject::kPropertiesOffset));
__ movq(FieldOperand(temp, offset), value);
- 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(temp, offset, value, object, kSaveFPRegs);
+ __ RecordWriteField(temp,
+ offset,
+ value,
+ object,
+ kSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ check_needed);
}
}
}
@@ -3182,12 +3226,20 @@ 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.
__ lea(key, FieldOperand(elements,
key,
times_pointer_size,
FixedArray::kHeaderSize));
- __ RecordWrite(elements, key, value, kSaveFPRegs);
+ __ RecordWrite(elements,
+ key,
+ value,
+ kSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ check_needed);
}
}
@@ -3223,6 +3275,47 @@ 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());
+
+ Handle<Map> from_map = instr->original_map();
+ Handle<Map> to_map = instr->transitioned_map();
+ ElementsKind from_kind = from_map->elements_kind();
+ ElementsKind to_kind = to_map->elements_kind();
+
+ Label not_applicable;
+ __ Cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map);
+ __ j(not_equal, &not_applicable);
+ __ movq(new_map_reg, to_map, RelocInfo::EMBEDDED_OBJECT);
+ if (from_kind == FAST_SMI_ONLY_ELEMENTS && to_kind == FAST_ELEMENTS) {
+ __ movq(FieldOperand(object_reg, HeapObject::kMapOffset), new_map_reg);
+ // Write barrier.
+ ASSERT_NE(instr->temp_reg(), NULL);
+ __ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg,
+ ToRegister(instr->temp_reg()), 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(rdx));
+ ASSERT(new_map_reg.is(rbx));
+ __ movq(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(rdx));
+ ASSERT(new_map_reg.is(rbx));
+ __ movq(fixed_object_reg, object_reg);
+ CallCode(isolate()->builtins()->TransitionElementsDoubleToObject(),
+ RelocInfo::CODE_TARGET, instr);
+ } else {
+ UNREACHABLE();
+ }
+ __ bind(&not_applicable);
+}
+
+
void LCodeGen::DoStringAdd(LStringAdd* instr) {
EmitPushTaggedOperand(instr->left());
EmitPushTaggedOperand(instr->right());
@@ -3825,6 +3918,11 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
+ Handle<FixedArray> constant_elements = instr->hydrogen()->constant_elements();
+ ASSERT_EQ(2, constant_elements->length());
+ ElementsKind constant_elements_kind =
+ static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
+
// Setup the parameters to the stub/runtime call.
__ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
__ push(FieldOperand(rax, JSFunction::kLiteralsOffset));
@@ -3845,7 +3943,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);
}
@@ -3934,8 +4034,7 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
Handle<SharedFunctionInfo> 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());
__ Push(shared_info);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
} else {
@@ -3975,12 +4074,11 @@ void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
Label* true_label = chunk_->GetAssemblyLabel(true_block);
Label* false_label = chunk_->GetAssemblyLabel(false_block);
- Condition final_branch_condition = EmitTypeofIs(true_label,
- false_label,
- input,
- instr->type_literal());
-
- EmitBranch(true_block, false_block, final_branch_condition);
+ Condition final_branch_condition =
+ EmitTypeofIs(true_label, false_label, input, instr->type_literal());
+ if (final_branch_condition != no_condition) {
+ EmitBranch(true_block, false_block, final_branch_condition);
+ }
}
@@ -4048,7 +4146,6 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
final_branch_condition = zero;
} else {
- final_branch_condition = never;
__ jmp(false_label);
}
diff --git a/deps/v8/src/x64/lithium-codegen-x64.h b/deps/v8/src/x64/lithium-codegen-x64.h
index 106d7bb2e5..f3cb667973 100644
--- a/deps/v8/src/x64/lithium-codegen-x64.h
+++ b/deps/v8/src/x64/lithium-codegen-x64.h
@@ -77,6 +77,7 @@ class LCodeGen BASE_EMBEDDED {
XMMRegister ToDoubleRegister(LOperand* op) const;
bool IsInteger32Constant(LConstantOperand* op) const;
int ToInteger32(LConstantOperand* op) const;
+ double ToDouble(LConstantOperand* op) const;
bool IsTaggedConstant(LConstantOperand* op) const;
Handle<Object> ToHandle(LConstantOperand* op) const;
Operand ToOperand(LOperand* op) const;
@@ -125,8 +126,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_; }
@@ -190,9 +191,8 @@ class LCodeGen BASE_EMBEDDED {
int argc,
LInstruction* instr);
-
// Generate a direct call to a known function. Expects the function
- // to be in edi.
+ // to be in rdi.
void CallKnownFunction(Handle<JSFunction> function,
int arity,
LInstruction* instr,
@@ -251,7 +251,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,
XMMRegister result,
bool deoptimize_on_undefined,
@@ -260,8 +259,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<String> type_name);
+ Condition EmitTypeofIs(Label* true_label,
+ Label* false_label,
+ Register input,
+ Handle<String> 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/x64/lithium-x64.cc b/deps/v8/src/x64/lithium-x64.cc
index a67a59320e..0af2ce4fc4 100644
--- a/deps/v8/src/x64/lithium-x64.cc
+++ b/deps/v8/src/x64/lithium-x64.cc
@@ -447,6 +447,12 @@ void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
}
+void LTransitionElementsKind::PrintDataTo(StringStream* stream) {
+ object()->PrintTo(stream);
+ stream->Add(" %p -> %p", *original_map(), *transitioned_map());
+}
+
+
void LChunk::AddInstruction(LInstruction* instr, HBasicBlock* block) {
LInstructionGap* gap = new LInstructionGap(block);
int index = -1;
@@ -1396,12 +1402,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 ? rax : rdx);
- LOperand* right = UseFixed(instr->right(), reversed ? rdx : rax);
+ LOperand* left = UseFixed(instr->left(), rdx);
+ LOperand* right = UseFixed(instr->right(), rax);
LCmpT* result = new LCmpT(left, right);
return MarkAsCall(DefineFixed(result, rax), instr);
}
@@ -1413,15 +1417,22 @@ LInstruction* LChunkBuilder::DoCompareIDAndBranch(
if (r.IsInteger32()) {
ASSERT(instr->left()->representation().IsInteger32());
ASSERT(instr->right()->representation().IsInteger32());
- LOperand* left = UseRegisterAtStart(instr->left());
+ LOperand* left = UseRegisterOrConstantAtStart(instr->left());
LOperand* right = UseOrConstantAtStart(instr->right());
return new LCmpIDAndBranch(left, right);
} else {
ASSERT(r.IsDouble());
ASSERT(instr->left()->representation().IsDouble());
ASSERT(instr->right()->representation().IsDouble());
- LOperand* left = UseRegisterAtStart(instr->left());
- LOperand* right = UseRegisterAtStart(instr->right());
+ LOperand* left;
+ LOperand* right;
+ if (instr->left()->IsConstant() && instr->right()->IsConstant()) {
+ left = UseRegisterOrConstantAtStart(instr->left());
+ right = UseRegisterOrConstantAtStart(instr->right());
+ } else {
+ left = UseRegisterAtStart(instr->left());
+ right = UseRegisterAtStart(instr->right());
+ }
return new LCmpIDAndBranch(left, right);
}
}
@@ -1956,6 +1967,27 @@ 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();
+ LOperand* temp_reg = TempRegister();
+ LTransitionElementsKind* result =
+ new LTransitionElementsKind(object, new_map_reg, temp_reg);
+ return DefineSameAsFirst(result);
+ } else {
+ LOperand* object = UseFixed(instr->object(), rax);
+ LOperand* fixed_object_reg = FixedTemp(rdx);
+ LOperand* new_map_reg = FixedTemp(rbx);
+ LTransitionElementsKind* result =
+ new LTransitionElementsKind(object, new_map_reg, fixed_object_reg);
+ return MarkAsCall(DefineFixed(result, rax), instr);
+ }
+}
+
+
LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
bool needs_write_barrier = instr->NeedsWriteBarrier();
diff --git a/deps/v8/src/x64/lithium-x64.h b/deps/v8/src/x64/lithium-x64.h
index d43a86a9a5..20a69373c1 100644
--- a/deps/v8/src/x64/lithium-x64.h
+++ b/deps/v8/src/x64/lithium-x64.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, 1> {
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)
};
@@ -1551,7 +1553,6 @@ class LStoreNamedField: public LTemplateInstruction<0, 2, 1> {
Handle<Object> 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<Map> transition() const { return hydrogen()->transition(); }
};
@@ -1571,7 +1572,8 @@ class LStoreNamedGeneric: public LTemplateInstruction<0, 2, 0> {
LOperand* object() { return inputs_[0]; }
LOperand* value() { return inputs_[1]; }
Handle<Object> 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; }
};
@@ -1660,6 +1662,30 @@ class LStoreKeyedGeneric: 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<Map> original_map() { return hydrogen()->original_map(); }
+ Handle<Map> 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/x64/macro-assembler-x64.cc b/deps/v8/src/x64/macro-assembler-x64.cc
index 7fe6d5821e..e3d463400f 100644
--- a/deps/v8/src/x64/macro-assembler-x64.cc
+++ b/deps/v8/src/x64/macro-assembler-x64.cc
@@ -55,7 +55,7 @@ MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size)
static intptr_t RootRegisterDelta(ExternalReference other, Isolate* isolate) {
Address roots_register_value = kRootRegisterBias +
- reinterpret_cast<Address>(isolate->heap()->roots_address());
+ reinterpret_cast<Address>(isolate->heap()->roots_array_start());
intptr_t delta = other.address() - roots_register_value;
return delta;
}
@@ -326,6 +326,40 @@ void MacroAssembler::RecordWriteField(
}
+void MacroAssembler::RecordWriteArray(Register object,
+ Register value,
+ Register index,
+ SaveFPRegsMode save_fp,
+ RememberedSetAction remembered_set_action,
+ SmiCheck smi_check) {
+ // First, check if a write barrier is even needed. The tests below
+ // catch stores of Smis.
+ Label done;
+
+ // Skip barrier if writing a smi.
+ if (smi_check == INLINE_SMI_CHECK) {
+ JumpIfSmi(value, &done);
+ }
+
+ // Array access: calculate the destination address. Index is not a smi.
+ Register dst = index;
+ lea(dst, Operand(object, index, times_pointer_size,
+ FixedArray::kHeaderSize - kHeapObjectTag));
+
+ RecordWrite(
+ object, dst, value, save_fp, remembered_set_action, OMIT_SMI_CHECK);
+
+ bind(&done);
+
+ // Clobber clobbered input registers when running with the debug-code flag
+ // turned on to provoke errors.
+ if (emit_debug_code()) {
+ movq(value, BitCast<int64_t>(kZapValue), RelocInfo::NONE);
+ movq(index, BitCast<int64_t>(kZapValue), RelocInfo::NONE);
+ }
+}
+
+
void MacroAssembler::RecordWrite(Register object,
Register address,
Register value,
@@ -2317,6 +2351,13 @@ void MacroAssembler::Test(const Operand& src, Smi* source) {
}
+void MacroAssembler::TestBit(const Operand& src, int bits) {
+ int byte_offset = bits / kBitsPerByte;
+ int bit_in_byte = bits & (kBitsPerByte - 1);
+ testb(Operand(src, byte_offset), Immediate(1 << bit_in_byte));
+}
+
+
void MacroAssembler::Jump(ExternalReference ext) {
LoadAddress(kScratchRegister, ext);
jmp(kScratchRegister);
@@ -2683,7 +2724,7 @@ void MacroAssembler::CheckFastSmiOnlyElements(Register map,
void MacroAssembler::StoreNumberToDoubleElements(
Register maybe_number,
Register elements,
- Register key,
+ Register index,
XMMRegister xmm_scratch,
Label* fail) {
Label smi_value, is_nan, maybe_nan, not_nan, have_double_value, done;
@@ -2704,7 +2745,7 @@ void MacroAssembler::StoreNumberToDoubleElements(
bind(&not_nan);
movsd(xmm_scratch, FieldOperand(maybe_number, HeapNumber::kValueOffset));
bind(&have_double_value);
- movsd(FieldOperand(elements, key, times_8, FixedDoubleArray::kHeaderSize),
+ movsd(FieldOperand(elements, index, times_8, FixedDoubleArray::kHeaderSize),
xmm_scratch);
jmp(&done);
@@ -2727,7 +2768,7 @@ void MacroAssembler::StoreNumberToDoubleElements(
// Preserve original value.
SmiToInteger32(kScratchRegister, maybe_number);
cvtlsi2sd(xmm_scratch, kScratchRegister);
- movsd(FieldOperand(elements, key, times_8, FixedDoubleArray::kHeaderSize),
+ movsd(FieldOperand(elements, index, times_8, FixedDoubleArray::kHeaderSize),
xmm_scratch);
bind(&done);
}
@@ -2866,7 +2907,8 @@ Condition MacroAssembler::IsObjectStringType(Register heap_object,
void MacroAssembler::TryGetFunctionPrototype(Register function,
Register result,
- Label* miss) {
+ Label* miss,
+ bool miss_on_bound_function) {
// Check that the receiver isn't a smi.
testl(function, Immediate(kSmiTagMask));
j(zero, miss);
@@ -2875,6 +2917,17 @@ void MacroAssembler::TryGetFunctionPrototype(Register function,
CmpObjectType(function, JS_FUNCTION_TYPE, result);
j(not_equal, miss);
+ if (miss_on_bound_function) {
+ movq(kScratchRegister,
+ FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
+ // It's not smi-tagged (stored in the top half of a smi-tagged 8-byte
+ // field).
+ TestBit(FieldOperand(kScratchRegister,
+ SharedFunctionInfo::kCompilerHintsOffset),
+ SharedFunctionInfo::kBoundFunction);
+ j(not_zero, miss);
+ }
+
// Make sure that the function has an instance prototype.
Label non_instance;
testb(FieldOperand(result, Map::kBitFieldOffset),
@@ -3067,29 +3120,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.
Move(rdi, Handle<JSFunction>(function));
movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
- if (V8::UseCrankshaft()) {
- // Since Crankshaft can recompile a function, we need to load
- // the Code object every time we call the function.
- movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
- ParameterCount expected(function->shared()->formal_parameter_count());
- InvokeCode(rdx, expected, actual, flag, call_wrapper, call_kind);
- } else {
- // Invoke the cached code.
- Handle<Code> code(function->code());
- ParameterCount expected(function->shared()->formal_parameter_count());
- InvokeCode(code,
- expected,
- actual,
- RelocInfo::CODE_TARGET,
- flag,
- call_wrapper,
- 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.
+ movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
+ ParameterCount expected(function->shared()->formal_parameter_count());
+ InvokeCode(rdx, expected, actual, flag, call_wrapper, call_kind);
}
diff --git a/deps/v8/src/x64/macro-assembler-x64.h b/deps/v8/src/x64/macro-assembler-x64.h
index 7e0ba00546..f5f81b1316 100644
--- a/deps/v8/src/x64/macro-assembler-x64.h
+++ b/deps/v8/src/x64/macro-assembler-x64.h
@@ -256,8 +256,8 @@ class MacroAssembler: public Assembler {
// Notify the garbage collector that we wrote a pointer into a fixed array.
// |array| is the array being stored into, |value| is the
- // object being stored. |index| is the array index represented as a
- // Smi. All registers are clobbered by the operation RecordWriteArray
+ // object being stored. |index| is the array index represented as a non-smi.
+ // All registers are clobbered by the operation RecordWriteArray
// filters out smis so it does not update the write barrier if the
// value is a smi.
void RecordWriteArray(
@@ -319,9 +319,9 @@ class MacroAssembler: public Assembler {
void LoadFromSafepointRegisterSlot(Register dst, Register src);
void InitializeRootRegister() {
- ExternalReference roots_address =
- ExternalReference::roots_address(isolate());
- movq(kRootRegister, roots_address);
+ ExternalReference roots_array_start =
+ ExternalReference::roots_array_start(isolate());
+ movq(kRootRegister, roots_array_start);
addq(kRootRegister, Immediate(kRootRegisterBias));
}
@@ -726,6 +726,7 @@ class MacroAssembler: public Assembler {
void Push(Smi* smi);
void Test(const Operand& dst, Smi* source);
+
// ---------------------------------------------------------------------------
// String macros.
@@ -771,6 +772,9 @@ class MacroAssembler: public Assembler {
// Move if the registers are not identical.
void Move(Register target, Register source);
+ // Bit-field support.
+ void TestBit(const Operand& dst, int bit_index);
+
// Handle support
void Move(Register dst, Handle<Object> source);
void Move(const Operand& dst, Handle<Object> source);
@@ -860,12 +864,12 @@ class MacroAssembler: public Assembler {
Label::Distance distance = Label::kFar);
// Check to see if maybe_number can be stored as a double in
- // FastDoubleElements. If it can, store it at the index specified by key in
- // the FastDoubleElements array elements, otherwise jump to fail.
- // Note that key must not be smi-tagged.
+ // FastDoubleElements. If it can, store it at the index specified by index in
+ // the FastDoubleElements array elements, otherwise jump to fail. Note that
+ // index must not be smi-tagged.
void StoreNumberToDoubleElements(Register maybe_number,
Register elements,
- Register key,
+ Register index,
XMMRegister xmm_scratch,
Label* fail);
@@ -1074,7 +1078,8 @@ class MacroAssembler: public Assembler {
// clobbered.
void TryGetFunctionPrototype(Register function,
Register result,
- Label* miss);
+ Label* miss,
+ bool miss_on_bound_function = false);
// Generates code for reporting that an illegal operation has
// occurred.
diff --git a/deps/v8/src/x64/regexp-macro-assembler-x64.cc b/deps/v8/src/x64/regexp-macro-assembler-x64.cc
index 55fabc0036..1e0cd6a38c 100644
--- a/deps/v8/src/x64/regexp-macro-assembler-x64.cc
+++ b/deps/v8/src/x64/regexp-macro-assembler-x64.cc
@@ -1248,6 +1248,11 @@ int RegExpMacroAssemblerX64::CheckStackGuardState(Address* return_address,
frame_entry<const String*>(re_frame, kInputString) = *subject;
frame_entry<const byte*>(re_frame, kInputStart) = new_address;
frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length;
+ } else if (frame_entry<const String*>(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<const String*>(re_frame, kInputString) = *subject;
}
return 0;
diff --git a/deps/v8/src/x64/stub-cache-x64.cc b/deps/v8/src/x64/stub-cache-x64.cc
index c4b2672f60..8af1bf2c4c 100644
--- a/deps/v8/src/x64/stub-cache-x64.cc
+++ b/deps/v8/src/x64/stub-cache-x64.cc
@@ -82,7 +82,55 @@ 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<String> name,
+ Register r0,
+ Register r1) {
+ ASSERT(name->IsSymbol());
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->negative_lookups(), 1);
+ __ IncrementCounter(counters->negative_lookups_miss(), 1);
+
+ __ movq(r0, FieldOperand(receiver, HeapObject::kMapOffset));
+
+ const int kInterceptorOrAccessCheckNeededMask =
+ (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
+
+ // Bail out if the receiver has a named interceptor or requires access checks.
+ __ testb(FieldOperand(r0, Map::kBitFieldOffset),
+ Immediate(kInterceptorOrAccessCheckNeededMask));
+ __ j(not_zero, miss_label);
+
+ // Check that receiver is a JSObject.
+ __ CmpInstanceType(r0, FIRST_SPEC_OBJECT_TYPE);
+ __ j(below, miss_label);
+
+ // Load properties array.
+ Register properties = r0;
+ __ movq(properties, FieldOperand(receiver, JSObject::kPropertiesOffset));
+
+ // Check that the properties array is a dictionary.
+ __ CompareRoot(FieldOperand(properties, HeapObject::kMapOffset),
+ Heap::kHashTableMapRootIndex);
+ __ j(not_equal, miss_label);
+
+ Label done;
+ StringDictionaryLookupStub::GenerateNegativeLookup(masm,
+ miss_label,
+ &done,
+ properties,
+ name,
+ r1);
+ __ bind(&done);
+ __ DecrementCounter(counters->negative_lookups_miss(), 1);
+}
+
+
+// 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,
@@ -118,7 +166,7 @@ MUST_USE_RESULT static MaybeObject* GenerateDictionaryNegativeLookup(
__ j(not_equal, miss_label);
Label done;
- MaybeObject* result = StringDictionaryLookupStub::GenerateNegativeLookup(
+ MaybeObject* result = StringDictionaryLookupStub::TryGenerateNegativeLookup(
masm,
miss_label,
&done,
@@ -312,8 +360,10 @@ void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
// 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<JSObject> holder,
+ int index) {
// Adjust for the number of properties stored in the holder.
index -= holder->map()->inobject_properties();
if (index < 0) {
@@ -700,15 +750,10 @@ class CallInterceptorCompiler BASE_EMBEDDED {
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<Code> ic(code);
- __ Jump(ic, RelocInfo::CODE_TARGET);
+ Handle<Code> code = (kind == Code::LOAD_IC)
+ ? masm->isolate()->builtins()->LoadIC_Miss()
+ : masm->isolate()->builtins()->KeyedLoadIC_Miss();
+ __ Jump(code, RelocInfo::CODE_TARGET);
}
@@ -723,9 +768,9 @@ void StubCompiler::GenerateKeyedLoadMissForceGeneric(MacroAssembler* masm) {
// Both name_reg and receiver_reg are preserved on jumps to miss_label,
// but may be destroyed if store is successful.
void StubCompiler::GenerateStoreField(MacroAssembler* masm,
- JSObject* object,
+ Handle<JSObject> object,
int index,
- Map* transition,
+ Handle<Map> transition,
Register receiver_reg,
Register name_reg,
Register scratch,
@@ -748,12 +793,12 @@ 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.
__ pop(scratch); // Return address.
__ push(receiver_reg);
- __ Push(Handle<Map>(transition));
+ __ Push(transition);
__ push(rax);
__ push(scratch);
__ TailCallExternalReference(
@@ -764,11 +809,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.
- __ Move(FieldOperand(receiver_reg, HeapObject::kMapOffset),
- Handle<Map>(transition));
+ __ Move(FieldOperand(receiver_reg, HeapObject::kMapOffset), transition);
}
// Adjust for the number of properties stored in the object. Even in the
@@ -808,7 +852,24 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
// 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<GlobalObject> global,
+ Handle<String> name,
+ Register scratch,
+ Label* miss) {
+ Handle<JSGlobalPropertyCell> cell =
+ GlobalObject::EnsurePropertyCell(global, name);
+ ASSERT(cell->value()->IsTheHole());
+ __ Move(scratch, cell);
+ __ Cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
+ masm->isolate()->factory()->the_hole_value());
+ __ j(not_equal, 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,
@@ -828,10 +889,172 @@ MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCell(
}
+// Calls GenerateCheckPropertyCell for each global object in the prototype chain
+// from object to (but not including) holder.
+static void GenerateCheckPropertyCells(MacroAssembler* masm,
+ Handle<JSObject> object,
+ Handle<JSObject> holder,
+ Handle<String> name,
+ Register scratch,
+ Label* miss) {
+ Handle<JSObject> current = object;
+ while (!current.is_identical_to(holder)) {
+ if (current->IsGlobalObject()) {
+ GenerateCheckPropertyCell(masm,
+ Handle<GlobalObject>::cast(current),
+ name,
+ scratch,
+ miss);
+ }
+ current = Handle<JSObject>(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,
+ String* name,
+ Register scratch,
+ Label* miss) {
+ JSObject* current = object;
+ while (current != holder) {
+ if (current->IsGlobalObject()) {
+ // Returns a cell or a failure.
+ MaybeObject* result = TryGenerateCheckPropertyCell(
+ masm,
+ GlobalObject::cast(current),
+ name,
+ scratch,
+ miss);
+ if (result->IsFailure()) return result;
+ }
+ ASSERT(current->IsJSObject());
+ current = JSObject::cast(current->GetPrototype());
+ }
+ return NULL;
+}
+
+
#undef __
#define __ ACCESS_MASM((masm()))
+Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
+ Register object_reg,
+ Handle<JSObject> holder,
+ Register holder_reg,
+ Register scratch1,
+ Register scratch2,
+ Handle<String> 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. On the first
+ // iteration, reg is an alias for object_reg, on later iterations,
+ // it is an alias for holder_reg.
+ Register reg = object_reg;
+ int depth = 0;
+
+ if (save_at_depth == depth) {
+ __ movq(Operand(rsp, kPointerSize), object_reg);
+ }
+
+ // Check the maps in the prototype chain.
+ // Traverse the prototype chain from the object and do map checks.
+ Handle<JSObject> 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<JSObject> 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);
+
+ __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
+ reg = holder_reg; // From now on the object will be in holder_reg.
+ __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
+ } else {
+ bool in_new_space = heap()->InNewSpace(*prototype);
+ Handle<Map> current_map(current->map());
+ if (in_new_space) {
+ // Save the map in scratch1 for later.
+ __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
+ __ Cmp(scratch1, current_map);
+ } else {
+ __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), current_map);
+ }
+ // Branch on the result of the map check.
+ __ j(not_equal, 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 (in_new_space) {
+ // The prototype is in new space; we cannot store a reference to it
+ // in the code. Load it from the map.
+ __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
+ } else {
+ // The prototype is in old space; load it directly.
+ __ Move(reg, prototype);
+ }
+ }
+
+ if (save_at_depth == depth) {
+ __ movq(Operand(rsp, kPointerSize), reg);
+ }
+
+ // Go to the next object in the prototype chain.
+ current = prototype;
+ }
+ ASSERT(current.is_identical_to(holder));
+
+ // Log the check depth.
+ LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
+
+ // Check the holder map.
+ __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), Handle<Map>(holder->map()));
+ __ j(not_equal, miss);
+
+ // Perform security check for access to the global object.
+ ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
+ if (current->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;
+}
+
+
Register StubCompiler::CheckPrototypes(JSObject* object,
Register object_reg,
JSObject* holder,
@@ -882,12 +1105,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;
@@ -960,43 +1184,34 @@ Register StubCompiler::CheckPrototypes(JSObject* object,
// 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.
- current = object;
- while (current != holder) {
- if (current->IsGlobalObject()) {
- MaybeObject* cell = GenerateCheckPropertyCell(masm(),
- GlobalObject::cast(current),
- name,
- scratch1,
- miss);
- if (cell->IsFailure()) {
- set_failure(Failure::cast(cell));
- return reg;
- }
- }
- current = JSObject::cast(current->GetPrototype());
- }
+ MaybeObject* result = TryGenerateCheckPropertyCells(masm(),
+ object,
+ holder,
+ name,
+ scratch1,
+ miss);
+ if (result->IsFailure()) set_failure(Failure::cast(result));
// Return the register containing the holder.
return reg;
}
-void StubCompiler::GenerateLoadField(JSObject* object,
- JSObject* holder,
+void StubCompiler::GenerateLoadField(Handle<JSObject> object,
+ Handle<JSObject> holder,
Register receiver,
Register scratch1,
Register scratch2,
Register scratch3,
int index,
- String* name,
+ Handle<String> name,
Label* miss) {
// Check that the receiver isn't a smi.
__ JumpIfSmi(receiver, miss);
// Check the prototype chain.
- Register reg =
- CheckPrototypes(object, receiver, holder,
- scratch1, scratch2, scratch3, name, miss);
+ Register reg = CheckPrototypes(
+ object, receiver, holder, scratch1, scratch2, scratch3, name, miss);
// Get the value from the properties.
GenerateFastPropertyLoad(masm(), rax, reg, holder, index);
@@ -1081,24 +1296,24 @@ MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object,
}
-void StubCompiler::GenerateLoadConstant(JSObject* object,
- JSObject* holder,
+void StubCompiler::GenerateLoadConstant(Handle<JSObject> object,
+ Handle<JSObject> holder,
Register receiver,
Register scratch1,
Register scratch2,
Register scratch3,
- Object* value,
- String* name,
+ Handle<Object> value,
+ Handle<String> 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.
- __ Move(rax, Handle<Object>(value));
+ __ Move(rax, value);
__ ret(0);
}
@@ -1198,7 +1413,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(), rax, holder_reg,
- lookup->holder(), lookup->GetFieldIndex());
+ Handle<JSObject>(lookup->holder()),
+ lookup->GetFieldIndex());
__ ret(0);
} else {
// We found CALLBACKS property in prototype chain of interceptor's
@@ -1244,9 +1460,9 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object,
}
-void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) {
+void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
if (kind_ == Code::KEYED_CALL_IC) {
- __ Cmp(rcx, Handle<String>(name));
+ __ Cmp(rcx, name);
__ j(not_equal, miss);
}
}
@@ -1305,11 +1521,22 @@ void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
}
-MaybeObject* CallStubCompiler::GenerateMissBranch() {
- MaybeObject* maybe_obj =
+void CallStubCompiler::GenerateMissBranch() {
+ Handle<Code> 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>(Code::cast(obj)), RelocInfo::CODE_TARGET);
@@ -1317,10 +1544,10 @@ MaybeObject* CallStubCompiler::GenerateMissBranch() {
}
-MaybeObject* CallStubCompiler::CompileCallField(JSObject* object,
- JSObject* holder,
+Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
+ Handle<JSObject> holder,
int index,
- String* name) {
+ Handle<String> name) {
// ----------- S t a t e -------------
// rcx : function name
// rsp[0] : return address
@@ -1360,7 +1587,7 @@ MaybeObject* CallStubCompiler::CompileCallField(JSObject* object,
}
// 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;
__ InvokeFunction(rdi, arguments(), JUMP_FUNCTION,
@@ -1368,8 +1595,7 @@ MaybeObject* CallStubCompiler::CompileCallField(JSObject* object,
// 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);
@@ -1394,7 +1620,7 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
Label miss;
- GenerateNameCheck(name, &miss);
+ GenerateNameCheck(Handle<String>(name), &miss);
// Get the receiver from the stack.
const int argc = arguments().immediate();
@@ -1488,8 +1714,8 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
// the new element is non-Smi. For now, delegate to the builtin.
Label no_fast_elements_check;
__ JumpIfSmi(rdi, &no_fast_elements_check);
- __ movq(rsi, FieldOperand(rdx, HeapObject::kMapOffset));
- __ CheckFastObjectElements(rsi, &call_builtin, Label::kFar);
+ __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset));
+ __ CheckFastObjectElements(rcx, &call_builtin, Label::kFar);
__ bind(&no_fast_elements_check);
ExternalReference new_space_allocation_top =
@@ -1553,11 +1779,11 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
}
__ 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);
}
@@ -1579,7 +1805,7 @@ MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object,
Label miss, return_undefined, call_builtin;
- GenerateNameCheck(name, &miss);
+ GenerateNameCheck(Handle<String>(name), &miss);
// Get the receiver from the stack.
const int argc = arguments().immediate();
@@ -1636,11 +1862,11 @@ MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object,
1);
__ 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);
}
@@ -1669,12 +1895,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<String>(name), &name_miss);
// Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype(masm(),
@@ -1720,11 +1946,11 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
// Restore function name in rcx.
__ Move(rcx, Handle<String>(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);
}
@@ -1753,12 +1979,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<String>(name), &name_miss);
// Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype(masm(),
@@ -1806,11 +2032,11 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall(
// Restore function name in rcx.
__ Move(rcx, Handle<String>(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);
}
@@ -1835,7 +2061,7 @@ MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall(
if (!object->IsJSObject() || argc != 1) return heap()->undefined_value();
Label miss;
- GenerateNameCheck(name, &miss);
+ GenerateNameCheck(Handle<String>(name), &miss);
if (cell == NULL) {
__ movq(rdx, Operand(rsp, 2 * kPointerSize));
@@ -1871,7 +2097,7 @@ MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall(
// Tail call the full function. We do not have to patch the receiver
// because the function makes no use of it.
__ bind(&slow);
- 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,
@@ -1879,11 +2105,11 @@ MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall(
__ bind(&miss);
// rcx: 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);
}
@@ -1917,7 +2143,7 @@ MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object,
if (!object->IsJSObject() || argc != 1) return heap()->undefined_value();
Label miss;
- GenerateNameCheck(name, &miss);
+ GenerateNameCheck(Handle<String>(name), &miss);
if (cell == NULL) {
__ movq(rdx, Operand(rsp, 2 * kPointerSize));
@@ -1988,7 +2214,7 @@ MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object,
// Tail call the full function. We do not have to patch the receiver
// because the function makes no use of it.
__ bind(&slow);
- 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,
@@ -1996,11 +2222,11 @@ MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object,
__ bind(&miss);
// rcx: 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);
}
@@ -2023,7 +2249,7 @@ MaybeObject* CallStubCompiler::CompileFastApiCall(
Label miss, miss_before_stack_reserved;
- GenerateNameCheck(name, &miss_before_stack_reserved);
+ GenerateNameCheck(Handle<String>(name), &miss_before_stack_reserved);
// Get the receiver from the stack.
const int argc = arguments().immediate();
@@ -2055,11 +2281,11 @@ MaybeObject* CallStubCompiler::CompileFastApiCall(
__ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
__ 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);
}
@@ -2089,7 +2315,7 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
Label miss;
- GenerateNameCheck(name, &miss);
+ GenerateNameCheck(Handle<String>(name), &miss);
// Get the receiver from the stack.
const int argc = arguments().immediate();
@@ -2186,7 +2412,7 @@ 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,
@@ -2194,11 +2420,11 @@ MaybeObject* CallStubCompiler::CompileCallConstant(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);
}
@@ -2216,18 +2442,18 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
// -----------------------------------
Label miss;
- GenerateNameCheck(name, &miss);
+ GenerateNameCheck(Handle<String>(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.
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
- CallInterceptorCompiler compiler(this, arguments(), rcx, extra_ic_state_);
+ CallInterceptorCompiler compiler(this, arguments(), rcx, extra_state_);
MaybeObject* result = compiler.Compile(masm(),
object,
holder,
@@ -2257,7 +2483,7 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
// Invoke the function.
__ movq(rdi, rax);
- CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
+ CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
? CALL_AS_FUNCTION
: CALL_AS_METHOD;
__ InvokeFunction(rdi, arguments(), JUMP_FUNCTION,
@@ -2265,11 +2491,11 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
// Handle load 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);
}
@@ -2299,7 +2525,7 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
Label miss;
- GenerateNameCheck(name, &miss);
+ GenerateNameCheck(Handle<String>(name), &miss);
// Get the number of arguments.
const int argc = arguments().immediate();
@@ -2320,39 +2546,32 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
// Jump to the cached code (tail call).
Counters* counters = isolate()->counters();
__ IncrementCounter(counters->call_global_inline(), 1);
- ASSERT(function->is_compiled());
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.
- __ movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
- __ InvokeCode(rdx, expected, arguments(), JUMP_FUNCTION,
- NullCallWrapper(), call_kind);
- } else {
- Handle<Code> code(function->code());
- __ InvokeCode(code, expected, arguments(),
- RelocInfo::CODE_TARGET, JUMP_FUNCTION,
- NullCallWrapper(), 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.
+ __ movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
+ __ InvokeCode(rdx, expected, arguments(), JUMP_FUNCTION,
+ NullCallWrapper(), call_kind);
+
// Handle call cache miss.
__ bind(&miss);
__ IncrementCounter(counters->call_global_inline_miss(), 1);
- 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<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
int index,
- Map* transition,
- String* name) {
+ Handle<Map> transition,
+ Handle<String> name) {
// ----------- S t a t e -------------
// -- rax : value
// -- rcx : name
@@ -2362,12 +2581,7 @@ MaybeObject* StoreStubCompiler::CompileStoreField(JSObject* object,
Label miss;
// Generate store field code. Preserves receiver and name on jump to miss.
- GenerateStoreField(masm(),
- object,
- index,
- transition,
- rdx, rcx, rbx,
- &miss);
+ GenerateStoreField(masm(), object, index, transition, rdx, rcx, rbx, &miss);
// Handle store cache miss.
__ bind(&miss);
@@ -2375,13 +2589,14 @@ MaybeObject* StoreStubCompiler::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* StoreStubCompiler::CompileStoreCallback(JSObject* object,
- AccessorInfo* callback,
- String* name) {
+Handle<Code> StoreStubCompiler::CompileStoreCallback(
+ Handle<JSObject> object,
+ Handle<AccessorInfo> callback,
+ Handle<String> name) {
// ----------- S t a t e -------------
// -- rax : value
// -- rcx : name
@@ -2409,7 +2624,7 @@ MaybeObject* StoreStubCompiler::CompileStoreCallback(JSObject* object,
__ pop(rbx); // remove the return address
__ push(rdx); // receiver
- __ Push(Handle<AccessorInfo>(callback)); // callback info
+ __ Push(callback); // callback info
__ push(rcx); // name
__ push(rax); // value
__ push(rbx); // restore return address
@@ -2429,8 +2644,9 @@ MaybeObject* StoreStubCompiler::CompileStoreCallback(JSObject* object,
}
-MaybeObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
- String* name) {
+Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
+ Handle<JSObject> receiver,
+ Handle<String> name) {
// ----------- S t a t e -------------
// -- rax : value
// -- rcx : name
@@ -2478,9 +2694,10 @@ MaybeObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
}
-MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
- JSGlobalPropertyCell* cell,
- String* name) {
+Handle<Code> StoreStubCompiler::CompileStoreGlobal(
+ Handle<GlobalObject> object,
+ Handle<JSGlobalPropertyCell> cell,
+ Handle<String> name) {
// ----------- S t a t e -------------
// -- rax : value
// -- rcx : name
@@ -2495,7 +2712,7 @@ MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
__ j(not_equal, &miss);
// Compute the cell operand to use.
- __ Move(rbx, Handle<JSGlobalPropertyCell>(cell));
+ __ Move(rbx, cell);
Operand cell_operand = FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset);
// Check that the value in the cell is not the hole. If it is, this
@@ -2539,10 +2756,10 @@ MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
}
-MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
+Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
int index,
- Map* transition,
- String* name) {
+ Handle<Map> transition,
+ Handle<String> name) {
// ----------- S t a t e -------------
// -- rax : value
// -- rcx : key
@@ -2555,16 +2772,11 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
__ IncrementCounter(counters->keyed_store_field(), 1);
// Check that the name has not changed.
- __ Cmp(rcx, Handle<String>(name));
+ __ Cmp(rcx, name);
__ j(not_equal, &miss);
// Generate store field code. Preserves receiver and name on jump to miss.
- GenerateStoreField(masm(),
- object,
- index,
- transition,
- rdx, rcx, rbx,
- &miss);
+ GenerateStoreField(masm(), object, index, transition, rdx, rcx, rbx, &miss);
// Handle store cache miss.
__ bind(&miss);
@@ -2573,40 +2785,38 @@ 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<Code> KeyedStoreStubCompiler::CompileStoreElement(
+ Handle<Map> receiver_map) {
// ----------- S t a t e -------------
// -- rax : value
// -- rcx : key
// -- rdx : receiver
// -- rsp[0] : return address
// -----------------------------------
- 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(rdx,
- Handle<Map>(receiver_map),
- Handle<Code>(stub),
- DO_SMI_CHECK);
+ Handle<Code> stub =
+ KeyedStoreElementStub(is_js_array, elements_kind).GetCode();
+
+ __ DispatchMap(rdx, receiver_map, stub, DO_SMI_CHECK);
Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
__ jmp(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<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
+ MapHandleList* receiver_maps,
+ CodeHandleList* handler_stubs,
+ MapHandleList* transitioned_maps) {
// ----------- S t a t e -------------
// -- rax : value
// -- rcx : key
@@ -2620,17 +2830,14 @@ MaybeObject* KeyedStoreStubCompiler::CompileStorePolymorphic(
int receiver_count = receiver_maps->length();
for (int i = 0; i < receiver_count; ++i) {
// Check map and tail call if there's a match
- Handle<Map> map(receiver_maps->at(i));
- __ Cmp(rdi, map);
- if (transitioned_maps->at(i) == NULL) {
- __ j(equal, Handle<Code>(handler_stubs->at(i)), RelocInfo::CODE_TARGET);
+ __ Cmp(rdi, receiver_maps->at(i));
+ if (transitioned_maps->at(i).is_null()) {
+ __ j(equal, handler_stubs->at(i), RelocInfo::CODE_TARGET);
} else {
Label next_map;
__ j(not_equal, &next_map, Label::kNear);
- __ movq(rbx,
- Handle<Map>(transitioned_maps->at(i)),
- RelocInfo::EMBEDDED_OBJECT);
- __ jmp(Handle<Code>(handler_stubs->at(i)), RelocInfo::CODE_TARGET);
+ __ movq(rbx, transitioned_maps->at(i), RelocInfo::EMBEDDED_OBJECT);
+ __ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET);
__ bind(&next_map);
}
}
@@ -2640,13 +2847,13 @@ MaybeObject* KeyedStoreStubCompiler::CompileStorePolymorphic(
__ jmp(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
- return GetCode(NORMAL, NULL, MEGAMORPHIC);
+ return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC);
}
-MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name,
- JSObject* object,
- JSObject* last) {
+Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
+ Handle<JSObject> object,
+ Handle<JSObject> last) {
// ----------- S t a t e -------------
// -- rax : receiver
// -- rcx : name
@@ -2665,15 +2872,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,
- rdx,
- &miss);
- if (cell->IsFailure()) {
- miss.Unuse();
- return cell;
- }
+ GenerateCheckPropertyCell(
+ masm(), Handle<GlobalObject>::cast(last), name, rdx, &miss);
}
// Return undefined if maps of the full prototype chain are still the
@@ -2685,14 +2885,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<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
+ Handle<JSObject> holder,
int index,
- String* name) {
+ Handle<String> name) {
// ----------- S t a t e -------------
// -- rax : receiver
// -- rcx : name
@@ -2731,14 +2931,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<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object,
+ Handle<JSObject> holder,
+ Handle<Object> value,
+ Handle<String> name) {
// ----------- S t a t e -------------
// -- rax : receiver
// -- rcx : name
@@ -2765,7 +2965,7 @@ MaybeObject* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
// -----------------------------------
Label miss;
- LookupResult lookup;
+ LookupResult lookup(isolate());
LookupPostInterceptor(holder, name, &lookup);
// TODO(368): Compile in the whole chain: all the interceptors in
@@ -2785,15 +2985,16 @@ MaybeObject* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
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<Code> LoadStubCompiler::CompileLoadGlobal(
+ Handle<JSObject> object,
+ Handle<GlobalObject> holder,
+ Handle<JSGlobalPropertyCell> cell,
+ Handle<String> name,
+ bool is_dont_delete) {
// ----------- S t a t e -------------
// -- rax : receiver
// -- rcx : name
@@ -2804,7 +3005,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 loads. In this case,
// the receiver cannot be a smi.
- if (object != holder) {
+ if (!object.is_identical_to(holder)) {
__ JumpIfSmi(rax, &miss);
}
@@ -2812,7 +3013,7 @@ MaybeObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
CheckPrototypes(object, rax, holder, rbx, rdx, rdi, name, &miss);
// Get the value from the cell.
- __ Move(rbx, Handle<JSGlobalPropertyCell>(cell));
+ __ Move(rbx, cell);
__ movq(rbx, FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset));
// Check for deleted property if property can actually be deleted.
@@ -2838,9 +3039,9 @@ MaybeObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
}
-MaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name,
- JSObject* receiver,
- JSObject* holder,
+Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> holder,
int index) {
// ----------- S t a t e -------------
// -- rax : key
@@ -2853,7 +3054,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name,
__ IncrementCounter(counters->keyed_load_field(), 1);
// Check that the name has not changed.
- __ Cmp(rax, Handle<String>(name));
+ __ Cmp(rax, name);
__ j(not_equal, &miss);
GenerateLoadField(receiver, holder, rdx, rbx, rcx, rdi, index, name, &miss);
@@ -2899,14 +3100,15 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback(
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
- return GetCode(CALLBACKS, name);
+ return TryGetCode(CALLBACKS, name);
}
-MaybeObject* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
- JSObject* receiver,
- JSObject* holder,
- Object* value) {
+Handle<Code> KeyedLoadStubCompiler::CompileLoadConstant(
+ Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> holder,
+ Handle<Object> value) {
// ----------- S t a t e -------------
// -- rax : key
// -- rdx : receiver
@@ -2949,7 +3151,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
__ Cmp(rax, Handle<String>(name));
__ j(not_equal, &miss);
- LookupResult lookup;
+ LookupResult lookup(isolate());
LookupPostInterceptor(holder, name, &lookup);
GenerateLoadInterceptor(receiver,
holder,
@@ -2966,11 +3168,12 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
- return GetCode(INTERCEPTOR, name);
+ return TryGetCode(INTERCEPTOR, name);
}
-MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
+Handle<Code> KeyedLoadStubCompiler::CompileLoadArrayLength(
+ Handle<String> name) {
// ----------- S t a t e -------------
// -- rax : key
// -- rdx : receiver
@@ -2982,7 +3185,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
__ IncrementCounter(counters->keyed_load_array_length(), 1);
// Check that the name has not changed.
- __ Cmp(rax, Handle<String>(name));
+ __ Cmp(rax, name);
__ j(not_equal, &miss);
GenerateLoadArrayLength(masm(), rdx, rcx, &miss);
@@ -2995,7 +3198,8 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
}
-MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
+Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength(
+ Handle<String> name) {
// ----------- S t a t e -------------
// -- rax : key
// -- rdx : receiver
@@ -3007,7 +3211,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
__ IncrementCounter(counters->keyed_load_string_length(), 1);
// Check that the name has not changed.
- __ Cmp(rax, Handle<String>(name));
+ __ Cmp(rax, name);
__ j(not_equal, &miss);
GenerateLoadStringLength(masm(), rdx, rcx, rbx, &miss, true);
@@ -3020,7 +3224,8 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
}
-MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
+Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype(
+ Handle<String> name) {
// ----------- S t a t e -------------
// -- rax : key
// -- rdx : receiver
@@ -3032,7 +3237,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
__ IncrementCounter(counters->keyed_load_function_prototype(), 1);
// Check that the name has not changed.
- __ Cmp(rax, Handle<String>(name));
+ __ Cmp(rax, name);
__ j(not_equal, &miss);
GenerateLoadFunctionPrototype(masm(), rdx, rcx, rbx, &miss);
@@ -3045,32 +3250,29 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
}
-MaybeObject* KeyedLoadStubCompiler::CompileLoadElement(Map* receiver_map) {
+Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
+ Handle<Map> receiver_map) {
// ----------- S t a t e -------------
// -- rax : key
// -- rdx : receiver
// -- rsp[0] : return address
// -----------------------------------
- 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(rdx,
- Handle<Map>(receiver_map),
- Handle<Code>(stub),
- DO_SMI_CHECK);
+ Handle<Code> stub = KeyedLoadElementStub(elements_kind).GetCode();
+
+ __ DispatchMap(rdx, receiver_map, stub, DO_SMI_CHECK);
Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
__ jmp(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<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
+ MapHandleList* receiver_maps,
+ CodeHandleList* handler_ics) {
// ----------- S t a t e -------------
// -- rax : key
// -- rdx : receiver
@@ -3084,18 +3286,15 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadPolymorphic(
int receiver_count = receiver_maps->length();
for (int current = 0; current < receiver_count; ++current) {
// Check map and tail call if there's a match
- Handle<Map> map(receiver_maps->at(current));
- __ Cmp(map_reg, map);
- __ j(equal,
- Handle<Code>(handler_ics->at(current)),
- RelocInfo::CODE_TARGET);
+ __ Cmp(map_reg, receiver_maps->at(current));
+ __ j(equal, handler_ics->at(current), RelocInfo::CODE_TARGET);
}
__ bind(&miss);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
- return GetCode(NORMAL, NULL, MEGAMORPHIC);
+ return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC);
}
diff --git a/deps/v8/test/cctest/cctest.status b/deps/v8/test/cctest/cctest.status
index 759f69f339..7161345ece 100644
--- a/deps/v8/test/cctest/cctest.status
+++ b/deps/v8/test/cctest/cctest.status
@@ -52,9 +52,6 @@ test-profile-generator/RecordStackTraceAtStartProfiling: PASS || FAIL
# We do not yet shrink weak maps after they have been emptied by the GC
test-weakmaps/Shrinking: FAIL
-# NewGC: BUG(1717)
-test-api/OutOfMemoryNested: PASS || TIMEOUT
-
##############################################################################
[ $arch == arm ]
diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc
index 167c4cd155..5081a648bc 100644
--- a/deps/v8/test/cctest/test-api.cc
+++ b/deps/v8/test/cctest/test-api.cc
@@ -5438,67 +5438,109 @@ static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
THREADED_TEST(StringWrite) {
+ LocalContext context;
v8::HandleScope scope;
v8::Handle<String> str = v8_str("abcde");
// abc<Icelandic eth><Unicode snowman>.
v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
+ const int kStride = 4; // Must match stride in for loops in JS below.
+ CompileRun(
+ "var left = '';"
+ "for (var i = 0; i < 0xd800; i += 4) {"
+ " left = left + String.fromCharCode(i);"
+ "}");
+ CompileRun(
+ "var right = '';"
+ "for (var i = 0; i < 0xd800; i += 4) {"
+ " right = String.fromCharCode(i) + right;"
+ "}");
+ v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
+ Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
+ Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
CHECK_EQ(5, str2->Length());
+ CHECK_EQ(0xd800 / kStride, left_tree->Length());
+ CHECK_EQ(0xd800 / kStride, right_tree->Length());
char buf[100];
- char utf8buf[100];
+ char utf8buf[0xd800 * 3];
uint16_t wbuf[100];
int len;
int charlen;
- memset(utf8buf, 0x1, sizeof(utf8buf));
+ memset(utf8buf, 0x1, 1000);
len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
CHECK_EQ(9, len);
CHECK_EQ(5, charlen);
CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
- memset(utf8buf, 0x1, sizeof(utf8buf));
+ memset(utf8buf, 0x1, 1000);
len = str2->WriteUtf8(utf8buf, 8, &charlen);
CHECK_EQ(8, len);
CHECK_EQ(5, charlen);
CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
- memset(utf8buf, 0x1, sizeof(utf8buf));
+ memset(utf8buf, 0x1, 1000);
len = str2->WriteUtf8(utf8buf, 7, &charlen);
CHECK_EQ(5, len);
CHECK_EQ(4, charlen);
CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
- memset(utf8buf, 0x1, sizeof(utf8buf));
+ memset(utf8buf, 0x1, 1000);
len = str2->WriteUtf8(utf8buf, 6, &charlen);
CHECK_EQ(5, len);
CHECK_EQ(4, charlen);
CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
- memset(utf8buf, 0x1, sizeof(utf8buf));
+ memset(utf8buf, 0x1, 1000);
len = str2->WriteUtf8(utf8buf, 5, &charlen);
CHECK_EQ(5, len);
CHECK_EQ(4, charlen);
CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
- memset(utf8buf, 0x1, sizeof(utf8buf));
+ memset(utf8buf, 0x1, 1000);
len = str2->WriteUtf8(utf8buf, 4, &charlen);
CHECK_EQ(3, len);
CHECK_EQ(3, charlen);
CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
- memset(utf8buf, 0x1, sizeof(utf8buf));
+ memset(utf8buf, 0x1, 1000);
len = str2->WriteUtf8(utf8buf, 3, &charlen);
CHECK_EQ(3, len);
CHECK_EQ(3, charlen);
CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
- memset(utf8buf, 0x1, sizeof(utf8buf));
+ memset(utf8buf, 0x1, 1000);
len = str2->WriteUtf8(utf8buf, 2, &charlen);
CHECK_EQ(2, len);
CHECK_EQ(2, charlen);
CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
+ memset(utf8buf, 0x1, sizeof(utf8buf));
+ len = left_tree->Utf8Length();
+ int utf8_expected =
+ (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
+ CHECK_EQ(utf8_expected, len);
+ len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
+ CHECK_EQ(utf8_expected, len);
+ CHECK_EQ(0xd800 / kStride, charlen);
+ CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
+ CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
+ CHECK_EQ(0xc0 - kStride,
+ static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
+ CHECK_EQ(1, utf8buf[utf8_expected]);
+
+ memset(utf8buf, 0x1, sizeof(utf8buf));
+ len = right_tree->Utf8Length();
+ CHECK_EQ(utf8_expected, len);
+ len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
+ CHECK_EQ(utf8_expected, len);
+ CHECK_EQ(0xd800 / kStride, charlen);
+ CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
+ CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
+ CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
+ CHECK_EQ(1, utf8buf[utf8_expected]);
+
memset(buf, 0x1, sizeof(buf));
memset(wbuf, 0x1, sizeof(wbuf));
len = str->WriteAscii(buf);
@@ -11440,6 +11482,7 @@ static void MorphAString(i::String* string,
// Test that we can still flatten a string if the components it is built up
// from have been turned into 16 bit strings in the mean time.
THREADED_TEST(MorphCompositeStringTest) {
+ char utf_buffer[129];
const char* c_string = "Now is the time for all good men"
" to come to the aid of the party";
uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
@@ -11468,6 +11511,17 @@ THREADED_TEST(MorphCompositeStringTest) {
MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
+ // This should UTF-8 without flattening, since everything is ASCII.
+ Handle<String> cons = v8_compile("cons")->Run().As<String>();
+ CHECK_EQ(128, cons->Utf8Length());
+ int nchars = -1;
+ CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
+ CHECK_EQ(128, nchars);
+ CHECK_EQ(0, strcmp(
+ utf_buffer,
+ "Now is the time for all good men to come to the aid of the party"
+ "Now is the time for all good men to come to the aid of the party"));
+
// Now do some stuff to make sure the strings are flattened, etc.
CompileRun(
"/[^a-z]/.test(cons);"
diff --git a/deps/v8/test/cctest/test-debug.cc b/deps/v8/test/cctest/test-debug.cc
index de60d4999d..cf723bafbd 100644
--- a/deps/v8/test/cctest/test-debug.cc
+++ b/deps/v8/test/cctest/test-debug.cc
@@ -409,11 +409,8 @@ Handle<FixedArray> GetDebuggedFunctions() {
static Handle<Code> ComputeCallDebugBreak(int argc) {
- CALL_HEAP_FUNCTION(
- v8::internal::Isolate::Current(),
- v8::internal::Isolate::Current()->stub_cache()->ComputeCallDebugBreak(
- argc, Code::CALL_IC),
- Code);
+ return Isolate::Current()->stub_cache()->ComputeCallDebugBreak(argc,
+ Code::CALL_IC);
}
@@ -425,8 +422,8 @@ void CheckDebuggerUnloaded(bool check_functions) {
CHECK_EQ(NULL, Isolate::Current()->debug()->debug_info_list_);
// Collect garbage to ensure weak handles are cleared.
- HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
- HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
+ HEAP->CollectAllGarbage(Heap::kNoGCFlags);
+ HEAP->CollectAllGarbage(Heap::kMakeHeapIterableMask);
// Iterate the head and check that there are no debugger related objects left.
HeapIterator iterator;
diff --git a/deps/v8/test/cctest/test-dictionary.cc b/deps/v8/test/cctest/test-dictionary.cc
index 15a854b363..793e228a97 100644
--- a/deps/v8/test/cctest/test-dictionary.cc
+++ b/deps/v8/test/cctest/test-dictionary.cc
@@ -38,6 +38,7 @@
using namespace v8::internal;
+
TEST(ObjectHashTable) {
v8::HandleScope scope;
LocalContext context;
@@ -66,7 +67,8 @@ TEST(ObjectHashTable) {
CHECK_EQ(table->NumberOfDeletedElements(), 1);
CHECK_EQ(table->Lookup(*a), HEAP->undefined_value());
- // Keys should map back to their respective values.
+ // Keys should map back to their respective values and also should get
+ // an identity hash code generated.
for (int i = 0; i < 100; i++) {
Handle<JSObject> key = FACTORY->NewJSArray(7);
Handle<JSObject> value = FACTORY->NewJSArray(11);
@@ -74,12 +76,67 @@ TEST(ObjectHashTable) {
CHECK_EQ(table->NumberOfElements(), i + 1);
CHECK_NE(table->FindEntry(*key), ObjectHashTable::kNotFound);
CHECK_EQ(table->Lookup(*key), *value);
+ CHECK(key->GetIdentityHash(OMIT_CREATION)->ToObjectChecked()->IsSmi());
+ }
+
+ // Keys never added to the map which already have an identity hash
+ // code should not be found.
+ for (int i = 0; i < 100; i++) {
+ Handle<JSObject> key = FACTORY->NewJSArray(7);
+ CHECK(key->GetIdentityHash(ALLOW_CREATION)->ToObjectChecked()->IsSmi());
+ CHECK_EQ(table->FindEntry(*key), ObjectHashTable::kNotFound);
+ CHECK_EQ(table->Lookup(*key), HEAP->undefined_value());
+ CHECK(key->GetIdentityHash(OMIT_CREATION)->ToObjectChecked()->IsSmi());
}
- // Keys never added to the map should not be found.
- for (int i = 0; i < 1000; i++) {
- Handle<JSObject> o = FACTORY->NewJSArray(100);
- CHECK_EQ(table->FindEntry(*o), ObjectHashTable::kNotFound);
- CHECK_EQ(table->Lookup(*o), HEAP->undefined_value());
+ // Keys that don't have an identity hash should not be found and also
+ // should not get an identity hash code generated.
+ for (int i = 0; i < 100; i++) {
+ Handle<JSObject> key = FACTORY->NewJSArray(7);
+ CHECK_EQ(table->Lookup(*key), HEAP->undefined_value());
+ CHECK_EQ(key->GetIdentityHash(OMIT_CREATION), HEAP->undefined_value());
}
}
+
+
+#ifdef DEBUG
+TEST(ObjectHashSetCausesGC) {
+ v8::HandleScope scope;
+ LocalContext context;
+ Handle<ObjectHashSet> table = FACTORY->NewObjectHashSet(1);
+ Handle<JSObject> key = FACTORY->NewJSArray(0);
+
+ // Simulate a full heap so that generating an identity hash code
+ // in subsequent calls will request GC.
+ FLAG_gc_interval = 0;
+
+ // Calling Contains() should not cause GC ever.
+ CHECK(!table->Contains(*key));
+
+ // Calling Remove() should not cause GC ever.
+ CHECK(!table->Remove(*key)->IsFailure());
+
+ // Calling Add() should request GC by returning a failure.
+ CHECK(table->Add(*key)->IsRetryAfterGC());
+}
+#endif
+
+
+#ifdef DEBUG
+TEST(ObjectHashTableCausesGC) {
+ v8::HandleScope scope;
+ LocalContext context;
+ Handle<ObjectHashTable> table = FACTORY->NewObjectHashTable(1);
+ Handle<JSObject> key = FACTORY->NewJSArray(0);
+
+ // Simulate a full heap so that generating an identity hash code
+ // in subsequent calls will request GC.
+ FLAG_gc_interval = 0;
+
+ // Calling Lookup() should not cause GC ever.
+ CHECK(table->Lookup(*key)->IsUndefined());
+
+ // Calling Put() should request GC by returning a failure.
+ CHECK(table->Put(*key, *key)->IsRetryAfterGC());
+}
+#endif
diff --git a/deps/v8/test/cctest/test-heap-profiler.cc b/deps/v8/test/cctest/test-heap-profiler.cc
index d695d7438f..87e7a7d0f9 100644
--- a/deps/v8/test/cctest/test-heap-profiler.cc
+++ b/deps/v8/test/cctest/test-heap-profiler.cc
@@ -252,6 +252,28 @@ TEST(HeapSnapshotHeapNumbers) {
CHECK_EQ(v8::HeapGraphNode::kHeapNumber, b->GetType());
}
+TEST(HeapSnapshotSlicedString) {
+ v8::HandleScope scope;
+ LocalContext env;
+ CompileRun(
+ "parent_string = \"123456789.123456789.123456789.123456789.123456789."
+ "123456789.123456789.123456789.123456789.123456789."
+ "123456789.123456789.123456789.123456789.123456789."
+ "123456789.123456789.123456789.123456789.123456789.\";"
+ "child_string = parent_string.slice(100);");
+ const v8::HeapSnapshot* snapshot =
+ v8::HeapProfiler::TakeSnapshot(v8_str("strings"));
+ const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
+ const v8::HeapGraphNode* parent_string =
+ GetProperty(global, v8::HeapGraphEdge::kShortcut, "parent_string");
+ CHECK_NE(NULL, parent_string);
+ const v8::HeapGraphNode* child_string =
+ GetProperty(global, v8::HeapGraphEdge::kShortcut, "child_string");
+ CHECK_NE(NULL, child_string);
+ const v8::HeapGraphNode* parent =
+ GetProperty(child_string, v8::HeapGraphEdge::kInternal, "parent");
+ CHECK_EQ(parent_string, parent);
+}
TEST(HeapSnapshotInternalReferences) {
v8::HandleScope scope;
diff --git a/deps/v8/test/cctest/test-parsing.cc b/deps/v8/test/cctest/test-parsing.cc
index 8f217e6cde..8cfd5f71fd 100755
--- a/deps/v8/test/cctest/test-parsing.cc
+++ b/deps/v8/test/cctest/test-parsing.cc
@@ -260,10 +260,11 @@ TEST(StandAlonePreParser) {
i::JavaScriptScanner scanner(i::Isolate::Current()->unicode_cache());
scanner.Initialize(&stream);
+ int flags = i::kAllowLazy | i::kAllowNativesSyntax;
v8::preparser::PreParser::PreParseResult result =
v8::preparser::PreParser::PreParseProgram(&scanner,
&log,
- true,
+ flags,
stack_limit);
CHECK_EQ(v8::preparser::PreParser::kPreParseSuccess, result);
i::ScriptDataImpl data(log.ExtractData());
@@ -272,6 +273,43 @@ TEST(StandAlonePreParser) {
}
+TEST(StandAlonePreParserNoNatives) {
+ v8::V8::Initialize();
+
+ int marker;
+ i::Isolate::Current()->stack_guard()->SetStackLimit(
+ reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
+
+ const char* programs[] = {
+ "%ArgleBargle(glop);",
+ "var x = %_IsSmi(42);",
+ NULL
+ };
+
+ uintptr_t stack_limit = i::Isolate::Current()->stack_guard()->real_climit();
+ for (int i = 0; programs[i]; i++) {
+ const char* program = programs[i];
+ i::Utf8ToUC16CharacterStream stream(
+ reinterpret_cast<const i::byte*>(program),
+ static_cast<unsigned>(strlen(program)));
+ i::CompleteParserRecorder log;
+ i::JavaScriptScanner scanner(i::Isolate::Current()->unicode_cache());
+ scanner.Initialize(&stream);
+
+ // Flags don't allow natives syntax.
+ v8::preparser::PreParser::PreParseResult result =
+ v8::preparser::PreParser::PreParseProgram(&scanner,
+ &log,
+ i::kAllowLazy,
+ stack_limit);
+ CHECK_EQ(v8::preparser::PreParser::kPreParseSuccess, result);
+ i::ScriptDataImpl data(log.ExtractData());
+ // Data contains syntax error.
+ CHECK(data.has_error());
+ }
+}
+
+
TEST(RegressChromium62639) {
v8::V8::Initialize();
@@ -706,3 +744,135 @@ TEST(RegExpScanning) {
TestScanRegExp("/=/", "=");
TestScanRegExp("/=?/", "=?");
}
+
+
+TEST(ScopePositions) {
+ // Test the parser for correctly setting the start and end positions
+ // of a scope. We check the scope positions of exactly one scope
+ // nested in the global scope of a program. 'inner source' is the
+ // source code that determines the part of the source belonging
+ // to the nested scope. 'outer_prefix' and 'outer_suffix' are
+ // parts of the source that belong to the global scope.
+ struct SourceData {
+ const char* outer_prefix;
+ const char* inner_source;
+ const char* outer_suffix;
+ i::ScopeType scope_type;
+ };
+
+ const SourceData source_data[] = {
+ { " with ({}) ", "{ block; }", " more;", i::WITH_SCOPE },
+ { " with ({}) ", "{ block; }", "; more;", i::WITH_SCOPE },
+ { " with ({}) ", "{\n"
+ " block;\n"
+ " }", "\n"
+ " more;", i::WITH_SCOPE },
+ { " with ({}) ", "statement;", " more;", i::WITH_SCOPE },
+ { " with ({}) ", "statement", "\n"
+ " more;", i::WITH_SCOPE },
+ { " with ({})\n"
+ " ", "statement;", "\n"
+ " more;", i::WITH_SCOPE },
+ { " try {} catch ", "(e) { block; }", " more;", i::CATCH_SCOPE },
+ { " try {} catch ", "(e) { block; }", "; more;", i::CATCH_SCOPE },
+ { " try {} catch ", "(e) {\n"
+ " block;\n"
+ " }", "\n"
+ " more;", i::CATCH_SCOPE },
+ { " try {} catch ", "(e) { block; }", " finally { block; } more;",
+ i::CATCH_SCOPE },
+ { " start;\n"
+ " ", "{ let block; }", " more;", i::BLOCK_SCOPE },
+ { " start;\n"
+ " ", "{ let block; }", "; more;", i::BLOCK_SCOPE },
+ { " start;\n"
+ " ", "{\n"
+ " let block;\n"
+ " }", "\n"
+ " more;", i::BLOCK_SCOPE },
+ { " start;\n"
+ " function fun", "(a,b) { infunction; }", " more;",
+ i::FUNCTION_SCOPE },
+ { " start;\n"
+ " function fun", "(a,b) {\n"
+ " infunction;\n"
+ " }", "\n"
+ " more;", i::FUNCTION_SCOPE },
+ { " (function fun", "(a,b) { infunction; }", ")();",
+ i::FUNCTION_SCOPE },
+ { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", " more;",
+ i::BLOCK_SCOPE },
+ { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", "; more;",
+ i::BLOCK_SCOPE },
+ { " for ", "(let x = 1 ; x < 10; ++ x) {\n"
+ " block;\n"
+ " }", "\n"
+ " more;", i::BLOCK_SCOPE },
+ { " for ", "(let x = 1 ; x < 10; ++ x) statement;", " more;",
+ i::BLOCK_SCOPE },
+ { " for ", "(let x = 1 ; x < 10; ++ x) statement", "\n"
+ " more;", i::BLOCK_SCOPE },
+ { " for ", "(let x = 1 ; x < 10; ++ x)\n"
+ " statement;", "\n"
+ " more;", i::BLOCK_SCOPE },
+ { " for ", "(let x in {}) { block; }", " more;", i::BLOCK_SCOPE },
+ { " for ", "(let x in {}) { block; }", "; more;", i::BLOCK_SCOPE },
+ { " for ", "(let x in {}) {\n"
+ " block;\n"
+ " }", "\n"
+ " more;", i::BLOCK_SCOPE },
+ { " for ", "(let x in {}) statement;", " more;", i::BLOCK_SCOPE },
+ { " for ", "(let x in {}) statement", "\n"
+ " more;", i::BLOCK_SCOPE },
+ { " for ", "(let x in {})\n"
+ " statement;", "\n"
+ " more;", i::BLOCK_SCOPE },
+ { NULL, NULL, NULL, i::EVAL_SCOPE }
+ };
+
+ v8::HandleScope handles;
+ v8::Persistent<v8::Context> context = v8::Context::New();
+ v8::Context::Scope context_scope(context);
+
+ int marker;
+ i::Isolate::Current()->stack_guard()->SetStackLimit(
+ reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
+
+ for (int i = 0; source_data[i].outer_prefix; i++) {
+ int kPrefixLen = i::StrLength(source_data[i].outer_prefix);
+ int kInnerLen = i::StrLength(source_data[i].inner_source);
+ int kSuffixLen = i::StrLength(source_data[i].outer_suffix);
+ int kProgramSize = kPrefixLen + kInnerLen + kSuffixLen;
+ i::Vector<char> program = i::Vector<char>::New(kProgramSize + 1);
+ int length;
+ length = i::OS::SNPrintF(program, "%s%s%s",
+ source_data[i].outer_prefix,
+ source_data[i].inner_source,
+ source_data[i].outer_suffix);
+ ASSERT(length == kProgramSize);
+
+ // Parse program source.
+ i::Handle<i::String> source(
+ FACTORY->NewStringFromAscii(i::CStrVector(program.start())));
+ i::Handle<i::Script> script = FACTORY->NewScript(source);
+ i::Parser parser(script, false, NULL, NULL);
+ parser.SetHarmonyScoping(true);
+ i::FunctionLiteral* function =
+ parser.ParseProgram(source, true, i::kNonStrictMode);
+ ASSERT(function != NULL);
+
+ // Check scope types and positions.
+ i::Scope* scope = function->scope();
+ CHECK(scope->is_global_scope());
+ CHECK_EQ(scope->start_position(), 0);
+ CHECK_EQ(scope->end_position(), kProgramSize);
+ CHECK_EQ(scope->inner_scopes()->length(), 1);
+
+ i::Scope* inner_scope = scope->inner_scopes()->at(0);
+ CHECK_EQ(inner_scope->type(), source_data[i].scope_type);
+ CHECK_EQ(inner_scope->start_position(), kPrefixLen);
+ // The end position of a token is one position after the last
+ // character belonging to that token.
+ CHECK_EQ(inner_scope->end_position(), kPrefixLen + kInnerLen);
+ }
+}
diff --git a/deps/v8/test/cctest/test-serialize.cc b/deps/v8/test/cctest/test-serialize.cc
index cccd2eec0c..b5c1a09763 100644
--- a/deps/v8/test/cctest/test-serialize.cc
+++ b/deps/v8/test/cctest/test-serialize.cc
@@ -130,7 +130,8 @@ TEST(ExternalReferenceEncoder) {
encoder.Encode(
ExternalReference::new_space_start(isolate).address()));
CHECK_EQ(make_code(UNCLASSIFIED, 3),
- encoder.Encode(ExternalReference::roots_address(isolate).address()));
+ encoder.Encode(
+ ExternalReference::roots_array_start(isolate).address()));
}
diff --git a/deps/v8/test/mjsunit/apply.js b/deps/v8/test/mjsunit/apply.js
index c166110df0..413ee937c6 100644
--- a/deps/v8/test/mjsunit/apply.js
+++ b/deps/v8/test/mjsunit/apply.js
@@ -190,3 +190,10 @@ assertEquals("morseper",
"moreseper-prime");
delete(Array.prototype["1"]);
+
+// Check correct handling of non-array argument lists.
+assertSame(this, f0.apply(this, {}), "non-array-1");
+assertSame(this, f0.apply(this, { length:1 }), "non-array-2");
+assertEquals(void 0, f1.apply(this, { length:1 }), "non-array-3");
+assertEquals(void 0, f1.apply(this, { 0:"foo" }), "non-array-4");
+assertEquals("foo", f1.apply(this, { length:1, 0:"foo" }), "non-array-5");
diff --git a/deps/v8/test/mjsunit/array-literal-transitions.js b/deps/v8/test/mjsunit/array-literal-transitions.js
new file mode 100644
index 0000000000..321340c4b6
--- /dev/null
+++ b/deps/v8/test/mjsunit/array-literal-transitions.js
@@ -0,0 +1,125 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --smi-only-arrays --expose-gc
+// Test element kind of objects.
+// Since --smi-only-arrays affects builtins, its default setting at compile
+// time sticks if built with snapshot. If --smi-only-arrays is deactivated
+// by default, only a no-snapshot build actually has smi-only arrays enabled
+// in this test case. Depending on whether smi-only arrays are actually
+// enabled, this test takes the appropriate code path to check smi-only arrays.
+
+support_smi_only_arrays = %HasFastSmiOnlyElements(new Array());
+
+// IC and Crankshaft support for smi-only elements in dynamic array literals.
+function get(foo) { return foo; } // Used to generate dynamic values.
+
+function array_literal_test() {
+ var a0 = [1, 2, 3];
+ assertTrue(%HasFastSmiOnlyElements(a0));
+ var a1 = [get(1), get(2), get(3)];
+ assertTrue(%HasFastSmiOnlyElements(a1));
+
+ var b0 = [1, 2, get("three")];
+ assertTrue(%HasFastElements(b0));
+ var b1 = [get(1), get(2), get("three")];
+ assertTrue(%HasFastElements(b1));
+
+ var c0 = [1, 2, get(3.5)];
+ assertTrue(%HasFastDoubleElements(c0));
+ assertEquals(3.5, c0[2]);
+ assertEquals(2, c0[1]);
+ assertEquals(1, c0[0]);
+
+ var c1 = [1, 2, 3.5];
+ assertTrue(%HasFastDoubleElements(c1));
+ assertEquals(3.5, c1[2]);
+ assertEquals(2, c1[1]);
+ assertEquals(1, c1[0]);
+
+ var c2 = [get(1), get(2), get(3.5)];
+ assertTrue(%HasFastDoubleElements(c2));
+ assertEquals(3.5, c2[2]);
+ assertEquals(2, c2[1]);
+ assertEquals(1, c2[0]);
+
+ var object = new Object();
+ var d0 = [1, 2, object];
+ assertTrue(%HasFastElements(d0));
+ assertEquals(object, d0[2]);
+ assertEquals(2, d0[1]);
+ assertEquals(1, d0[0]);
+
+ var e0 = [1, 2, 3.5];
+ assertTrue(%HasFastDoubleElements(e0));
+ assertEquals(3.5, e0[2]);
+ assertEquals(2, e0[1]);
+ assertEquals(1, e0[0]);
+
+ var f0 = [1, 2, [1, 2]];
+ assertTrue(%HasFastElements(f0));
+ assertEquals([1,2], f0[2]);
+ assertEquals(2, f0[1]);
+ assertEquals(1, f0[0]);
+}
+
+if (support_smi_only_arrays) {
+ for (var i = 0; i < 3; i++) {
+ array_literal_test();
+ }
+ %OptimizeFunctionOnNextCall(array_literal_test);
+ array_literal_test();
+
+ function test_large_literal() {
+
+ function d() {
+ gc();
+ return 2.5;
+ }
+
+ function o() {
+ gc();
+ return new Object();
+ }
+
+ large =
+ [ 0, 1, 2, 3, 4, 5, d(), d(), d(), d(), d(), d(), o(), o(), o(), o() ];
+ assertFalse(%HasDictionaryElements(large));
+ assertFalse(%HasFastSmiOnlyElements(large));
+ assertFalse(%HasFastDoubleElements(large));
+ assertTrue(%HasFastElements(large));
+ assertEquals(large,
+ [0, 1, 2, 3, 4, 5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5,
+ new Object(), new Object(), new Object(), new Object()]);
+ }
+
+ for (var i = 0; i < 3; i++) {
+ test_large_literal();
+ }
+ %OptimizeFunctionOnNextCall(test_large_literal);
+ test_large_literal();
+}
diff --git a/deps/v8/test/mjsunit/compiler/compare.js b/deps/v8/test/mjsunit/compiler/compare.js
index 3f96087002..460b0ab003 100644
--- a/deps/v8/test/mjsunit/compiler/compare.js
+++ b/deps/v8/test/mjsunit/compiler/compare.js
@@ -83,9 +83,9 @@ function TestNonPrimitive(order, f) {
}
TestNonPrimitive("xy", MaxLT);
-TestNonPrimitive("yx", MaxLE);
+TestNonPrimitive("xy", MaxLE);
TestNonPrimitive("xy", MaxGE);
-TestNonPrimitive("yx", MaxGT);
+TestNonPrimitive("xy", MaxGT);
// Test compare in case of aliased registers.
function CmpX(x) { if (x == x) return 42; }
diff --git a/deps/v8/test/mjsunit/compiler/regress-deopt-call-as-function.js b/deps/v8/test/mjsunit/compiler/regress-deopt-call-as-function.js
new file mode 100644
index 0000000000..d82c690ad6
--- /dev/null
+++ b/deps/v8/test/mjsunit/compiler/regress-deopt-call-as-function.js
@@ -0,0 +1,62 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test deoptimization after inlined call.
+
+function bar(a, b) {try { return a; } finally { } }
+
+function test_context() {
+ function foo(x) { return 42; }
+ var s, t;
+ for (var i = 0x7ff00000; i < 0x80000000; i++) {
+ bar(t = foo(i) ? bar(42 + i - i) : bar(0), s = i + t);
+ }
+ return s;
+}
+assertEquals(0x7fffffff + 42, test_context());
+
+
+function value_context() {
+ function foo(x) { return 42; }
+ var s, t;
+ for (var i = 0x7ff00000; i < 0x80000000; i++) {
+ bar(t = foo(i), s = i + t);
+ }
+ return s;
+}
+assertEquals(0x7fffffff + 42, value_context());
+
+
+function effect_context() {
+ function foo(x) { return 42; }
+ var s, t;
+ for (var i = 0x7ff00000; i < 0x80000000; i++) {
+ bar(foo(i), s = i + 42);
+ }
+ return s;
+}
+assertEquals(0x7fffffff + 42, effect_context());
diff --git a/deps/v8/test/mjsunit/cyclic-error-to-string.js b/deps/v8/test/mjsunit/compiler/regress-inline-callfunctionstub.js
index 2502b5340f..a39d26df0e 100644
--- a/deps/v8/test/mjsunit/cyclic-error-to-string.js
+++ b/deps/v8/test/mjsunit/compiler/regress-inline-callfunctionstub.js
@@ -25,22 +25,22 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Test printing of cyclic errors which return the empty string for
-// compatibility with Safari and Firefox.
+// Flags: --allow-natives-syntax
-var e = new Error();
-assertEquals('Error', e + '');
+// Test inlined of calls-as-function two levels deep.
+function f() { return 42; }
-e = new Error();
-e.name = e;
-e.message = e;
-e.stack = e;
-e.arguments = e;
-assertEquals(': ', e + '');
+var o = {g : function () { return f(); } }
+function main(func) {
+ var v=0;
+ for (var i=0; i<1; i++) {
+ if (func()) v = 42;
+ }
+}
+
+main(o.g);
+main(o.g);
+main(o.g);
+%OptimizeFunctionOnNextCall(main);
+main(o.g);
-e = new Error();
-e.name = [ e ];
-e.message = [ e ];
-e.stack = [ e ];
-e.arguments = [ e ];
-assertEquals(': ', e + '');
diff --git a/deps/v8/test/mjsunit/compiler/strict-recompile.js b/deps/v8/test/mjsunit/compiler/strict-recompile.js
new file mode 100644
index 0000000000..96e8bcab78
--- /dev/null
+++ b/deps/v8/test/mjsunit/compiler/strict-recompile.js
@@ -0,0 +1,51 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax
+
+function foo() {
+ try {
+ var o = {};
+ Object.defineProperty(o, 'x', {value: 12, writable: false});
+ o.x = 13;
+ } catch(e) {
+ return true;
+ }
+ return false;
+}
+
+assertFalse(foo());
+
+function do_eval(str) {
+ "use strict";
+ return eval(str);
+}
+
+var eval_foo = do_eval('(' + foo + ')');
+for (var i = 0; i < 5; i++) assertTrue(eval_foo());
+%OptimizeFunctionOnNextCall(eval_foo);
+assertTrue(eval_foo());
diff --git a/deps/v8/test/mjsunit/debug-scopes.js b/deps/v8/test/mjsunit/debug-scopes.js
index 1c23b0bf99..0788a55b0e 100644
--- a/deps/v8/test/mjsunit/debug-scopes.js
+++ b/deps/v8/test/mjsunit/debug-scopes.js
@@ -1,4 +1,4 @@
-// Copyright 2008 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -25,7 +25,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Flags: --expose-debug-as debug
+// Flags: --expose-debug-as debug --allow-natives-syntax
// The functions used for testing backtraces. They are at the top to make the
// testing of source line/column easier.
@@ -439,6 +439,26 @@ with(with_object) {
EndTest();
+// With block in function that is marked for optimization while being executed.
+BeginTest("With 7");
+
+function with_7() {
+ with({}) {
+ %OptimizeFunctionOnNextCall(with_7);
+ debugger;
+ }
+}
+
+listener_delegate = function(exec_state) {
+ CheckScopeChain([debug.ScopeType.With,
+ debug.ScopeType.Local,
+ debug.ScopeType.Global], exec_state);
+ CheckScopeContent({}, 0, exec_state);
+};
+with_7();
+EndTest();
+
+
// Simple closure formed by returning an inner function referering the outer
// functions arguments.
BeginTest("Closure 1");
@@ -950,6 +970,28 @@ try {
EndTest();
+// Catch block in function that is marked for optimization while being executed.
+BeginTest("Catch block 7");
+function catch_block_7() {
+ %OptimizeFunctionOnNextCall(catch_block_7);
+ try {
+ throw 'Exception';
+ } catch (e) {
+ debugger;
+ }
+};
+
+
+listener_delegate = function(exec_state) {
+ CheckScopeChain([debug.ScopeType.Catch,
+ debug.ScopeType.Local,
+ debug.ScopeType.Global], exec_state);
+ CheckScopeContent({e:'Exception'}, 0, exec_state);
+};
+catch_block_7();
+EndTest();
+
+
assertEquals(begin_test_count, break_count,
'one or more tests did not enter the debugger');
assertEquals(begin_test_count, end_test_count,
diff --git a/deps/v8/test/mjsunit/debug-step-3.js b/deps/v8/test/mjsunit/debug-step-3.js
new file mode 100644
index 0000000000..ad036678ee
--- /dev/null
+++ b/deps/v8/test/mjsunit/debug-step-3.js
@@ -0,0 +1,95 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+
+// This test tests that full code compiled without debug break slots
+// is recompiled with debug break slots when debugging is started.
+
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+var bp;
+var done = false;
+var step_count = 0;
+var set_bp = false
+
+// Debug event listener which steps until the global variable done is true.
+function listener(event, exec_state, event_data, data) {
+ if (event == Debug.DebugEvent.Break) {
+ if (!done) exec_state.prepareStep(Debug.StepAction.StepNext);
+ step_count++;
+ }
+};
+
+// Set the global variables state to prpare the stepping test.
+function prepare_step_test() {
+ done = false;
+ step_count = 0;
+}
+
+// Test function to step through.
+function f() {
+ var a = 0;
+ if (set_bp) { bp = Debug.setBreakPoint(f, 3); }
+ var i = 1;
+ var j = 2;
+ done = true;
+};
+
+prepare_step_test();
+f();
+
+// Add the debug event listener.
+Debug.setListener(listener);
+
+// Make f set a breakpoint with an activation on the stack.
+prepare_step_test();
+set_bp = true;
+f();
+// TODO(1782): Fix issue to bring back this assert.
+//assertEquals(4, step_count);
+Debug.clearBreakPoint(bp);
+
+// Set a breakpoint on the first var statement (line 1).
+set_bp = false;
+bp = Debug.setBreakPoint(f, 3);
+
+// Step through the function ensuring that the var statements are hit as well.
+prepare_step_test();
+f();
+// TODO(1782): Fix issue to bring back this assert.
+//assertEquals(4, step_count);
+
+// Clear the breakpoint and check that no stepping happens.
+Debug.clearBreakPoint(bp);
+prepare_step_test();
+f();
+assertEquals(0, step_count);
+
+// Get rid of the debug event listener.
+Debug.setListener(null);
diff --git a/deps/v8/test/mjsunit/element-kind.js b/deps/v8/test/mjsunit/element-kind.js
deleted file mode 100644
index 46fd8f567d..0000000000
--- a/deps/v8/test/mjsunit/element-kind.js
+++ /dev/null
@@ -1,261 +0,0 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Flags: --allow-natives-syntax --smi-only-arrays
-// Test element kind of objects.
-// Since --smi-only-arrays affects builtins, its default setting at compile
-// time sticks if built with snapshot. If --smi-only-arrays is deactivated
-// by default, only a no-snapshot build actually has smi-only arrays enabled
-// in this test case. Depending on whether smi-only arrays are actually
-// enabled, this test takes the appropriate code path to check smi-only arrays.
-
-
-support_smi_only_arrays = %HasFastSmiOnlyElements([]);
-
-if (support_smi_only_arrays) {
- print("Tests include smi-only arrays.");
-} else {
- print("Tests do NOT include smi-only arrays.");
-}
-
-var element_kind = {
- fast_smi_only_elements : 0,
- fast_elements : 1,
- fast_double_elements : 2,
- dictionary_elements : 3,
- external_byte_elements : 4,
- external_unsigned_byte_elements : 5,
- external_short_elements : 6,
- external_unsigned_short_elements : 7,
- external_int_elements : 8,
- external_unsigned_int_elements : 9,
- external_float_elements : 10,
- external_double_elements : 11,
- external_pixel_elements : 12
-}
-
-// We expect an object to only be of one element kind.
-function assertKind(expected, obj) {
- if (support_smi_only_arrays) {
- assertEquals(expected == element_kind.fast_smi_only_elements,
- %HasFastSmiOnlyElements(obj));
- assertEquals(expected == element_kind.fast_elements,
- %HasFastElements(obj));
- } else {
- assertEquals(expected == element_kind.fast_elements ||
- expected == element_kind.fast_smi_only_elements,
- %HasFastElements(obj));
- }
- assertEquals(expected == element_kind.fast_double_elements,
- %HasFastDoubleElements(obj));
- assertEquals(expected == element_kind.dictionary_elements,
- %HasDictionaryElements(obj));
- assertEquals(expected == element_kind.external_byte_elements,
- %HasExternalByteElements(obj));
- assertEquals(expected == element_kind.external_unsigned_byte_elements,
- %HasExternalUnsignedByteElements(obj));
- assertEquals(expected == element_kind.external_short_elements,
- %HasExternalShortElements(obj));
- assertEquals(expected == element_kind.external_unsigned_short_elements,
- %HasExternalUnsignedShortElements(obj));
- assertEquals(expected == element_kind.external_int_elements,
- %HasExternalIntElements(obj));
- assertEquals(expected == element_kind.external_unsigned_int_elements,
- %HasExternalUnsignedIntElements(obj));
- assertEquals(expected == element_kind.external_float_elements,
- %HasExternalFloatElements(obj));
- assertEquals(expected == element_kind.external_double_elements,
- %HasExternalDoubleElements(obj));
- assertEquals(expected == element_kind.external_pixel_elements,
- %HasExternalPixelElements(obj));
- // every external kind is also an external array
- assertEquals(expected >= element_kind.external_byte_elements,
- %HasExternalArrayElements(obj));
-}
-
-var me = {};
-assertKind(element_kind.fast_elements, me);
-me.dance = 0xD15C0;
-me.drink = 0xC0C0A;
-assertKind(element_kind.fast_elements, me);
-
-var too = [1,2,3];
-assertKind(element_kind.fast_smi_only_elements, too);
-too.dance = 0xD15C0;
-too.drink = 0xC0C0A;
-assertKind(element_kind.fast_smi_only_elements, too);
-
-// Make sure the element kind transitions from smionly when a non-smi is stored.
-var you = new Array();
-assertKind(element_kind.fast_smi_only_elements, you);
-for (var i = 0; i < 1337; i++) {
- var val = i;
- if (i == 1336) {
- assertKind(element_kind.fast_smi_only_elements, you);
- val = new Object();
- }
- you[i] = val;
-}
-assertKind(element_kind.fast_elements, you);
-
-assertKind(element_kind.dictionary_elements, new Array(0xDECAF));
-
-var fast_double_array = new Array(0xDECAF);
-for (var i = 0; i < 0xDECAF; i++) fast_double_array[i] = i / 2;
-assertKind(element_kind.fast_double_elements, fast_double_array);
-
-assertKind(element_kind.external_byte_elements, new Int8Array(9001));
-assertKind(element_kind.external_unsigned_byte_elements, new Uint8Array(007));
-assertKind(element_kind.external_short_elements, new Int16Array(666));
-assertKind(element_kind.external_unsigned_short_elements, new Uint16Array(42));
-assertKind(element_kind.external_int_elements, new Int32Array(0xF));
-assertKind(element_kind.external_unsigned_int_elements, new Uint32Array(23));
-assertKind(element_kind.external_float_elements, new Float32Array(7));
-assertKind(element_kind.external_double_elements, new Float64Array(0));
-assertKind(element_kind.external_pixel_elements, new PixelArray(512));
-
-// Crankshaft support for smi-only array elements.
-function monomorphic(array) {
- for (var i = 0; i < 3; i++) {
- array[i] = i + 10;
- }
- assertKind(element_kind.fast_smi_only_elements, array);
- for (var i = 0; i < 3; i++) {
- var a = array[i];
- assertEquals(i + 10, a);
- }
-}
-var smi_only = [1, 2, 3];
-for (var i = 0; i < 3; i++) monomorphic(smi_only);
-%OptimizeFunctionOnNextCall(monomorphic);
-monomorphic(smi_only);
-function polymorphic(array, expected_kind) {
- array[1] = 42;
- assertKind(expected_kind, array);
- var a = array[1];
- assertEquals(42, a);
-}
-var smis = [1, 2, 3];
-var strings = ["one", "two", "three"];
-var doubles = [0, 0, 0]; doubles[0] = 1.5; doubles[1] = 2.5; doubles[2] = 3.5;
-assertKind(support_smi_only_arrays
- ? element_kind.fast_double_elements
- : element_kind.fast_elements,
- doubles);
-for (var i = 0; i < 3; i++) {
- polymorphic(smis, element_kind.fast_smi_only_elements);
- polymorphic(strings, element_kind.fast_elements);
- polymorphic(doubles, support_smi_only_arrays
- ? element_kind.fast_double_elements
- : element_kind.fast_elements);
-}
-%OptimizeFunctionOnNextCall(polymorphic);
-polymorphic(smis, element_kind.fast_smi_only_elements);
-polymorphic(strings, element_kind.fast_elements);
-polymorphic(doubles, support_smi_only_arrays
- ? element_kind.fast_double_elements
- : element_kind.fast_elements);
-
-// Crankshaft support for smi-only elements in dynamic array literals.
-function get(foo) { return foo; } // Used to generate dynamic values.
-
-function crankshaft_test() {
- var a = [get(1), get(2), get(3)];
- assertKind(element_kind.fast_smi_only_elements, a);
- var b = [get(1), get(2), get("three")];
- assertKind(element_kind.fast_elements, b);
- var c = [get(1), get(2), get(3.5)];
- // The full code generator doesn't support conversion to fast_double_elements
- // yet. Crankshaft does, but only with --smi-only-arrays support.
- if ((%GetOptimizationStatus(crankshaft_test) & 1) &&
- support_smi_only_arrays) {
- assertKind(element_kind.fast_double_elements, c);
- } else {
- assertKind(element_kind.fast_elements, c);
- }
-}
-for (var i = 0; i < 3; i++) {
- crankshaft_test();
-}
-%OptimizeFunctionOnNextCall(crankshaft_test);
-crankshaft_test();
-
-// Elements_kind transitions for arrays.
-
-// A map can have three different elements_kind transitions: SMI->DOUBLE,
-// DOUBLE->OBJECT, and SMI->OBJECT. No matter in which order these three are
-// created, they must always end up with the same FAST map.
-
-// This test is meaningless without FAST_SMI_ONLY_ELEMENTS.
-if (support_smi_only_arrays) {
- // Preparation: create one pair of identical objects for each case.
- var a = [1, 2, 3];
- var b = [1, 2, 3];
- assertTrue(%HaveSameMap(a, b));
- assertKind(element_kind.fast_smi_only_elements, a);
- var c = [1, 2, 3];
- c["case2"] = true;
- var d = [1, 2, 3];
- d["case2"] = true;
- assertTrue(%HaveSameMap(c, d));
- assertFalse(%HaveSameMap(a, c));
- assertKind(element_kind.fast_smi_only_elements, c);
- var e = [1, 2, 3];
- e["case3"] = true;
- var f = [1, 2, 3];
- f["case3"] = true;
- assertTrue(%HaveSameMap(e, f));
- assertFalse(%HaveSameMap(a, e));
- assertFalse(%HaveSameMap(c, e));
- assertKind(element_kind.fast_smi_only_elements, e);
- // Case 1: SMI->DOUBLE, DOUBLE->OBJECT, SMI->OBJECT.
- a[0] = 1.5;
- assertKind(element_kind.fast_double_elements, a);
- a[0] = "foo";
- assertKind(element_kind.fast_elements, a);
- b[0] = "bar";
- assertTrue(%HaveSameMap(a, b));
- // Case 2: SMI->DOUBLE, SMI->OBJECT, DOUBLE->OBJECT.
- c[0] = 1.5;
- assertKind(element_kind.fast_double_elements, c);
- assertFalse(%HaveSameMap(c, d));
- d[0] = "foo";
- assertKind(element_kind.fast_elements, d);
- assertFalse(%HaveSameMap(c, d));
- c[0] = "bar";
- assertTrue(%HaveSameMap(c, d));
- // Case 3: SMI->OBJECT, SMI->DOUBLE, DOUBLE->OBJECT.
- e[0] = "foo";
- assertKind(element_kind.fast_elements, e);
- assertFalse(%HaveSameMap(e, f));
- f[0] = 1.5;
- assertKind(element_kind.fast_double_elements, f);
- assertFalse(%HaveSameMap(e, f));
- f[0] = "bar";
- assertKind(element_kind.fast_elements, f);
- assertTrue(%HaveSameMap(e, f));
-}
diff --git a/deps/v8/test/mjsunit/elements-kind.js b/deps/v8/test/mjsunit/elements-kind.js
new file mode 100644
index 0000000000..cfd47c7781
--- /dev/null
+++ b/deps/v8/test/mjsunit/elements-kind.js
@@ -0,0 +1,309 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --smi-only-arrays --expose-gc
+
+// Test element kind of objects.
+// Since --smi-only-arrays affects builtins, its default setting at compile
+// time sticks if built with snapshot. If --smi-only-arrays is deactivated
+// by default, only a no-snapshot build actually has smi-only arrays enabled
+// in this test case. Depending on whether smi-only arrays are actually
+// enabled, this test takes the appropriate code path to check smi-only arrays.
+
+support_smi_only_arrays = %HasFastSmiOnlyElements([]);
+
+if (support_smi_only_arrays) {
+ print("Tests include smi-only arrays.");
+} else {
+ print("Tests do NOT include smi-only arrays.");
+}
+
+var elements_kind = {
+ fast_smi_only : 'fast smi only elements',
+ fast : 'fast elements',
+ fast_double : 'fast double elements',
+ dictionary : 'dictionary elements',
+ external_byte : 'external byte elements',
+ external_unsigned_byte : 'external unsigned byte elements',
+ external_short : 'external short elements',
+ external_unsigned_short : 'external unsigned short elements',
+ external_int : 'external int elements',
+ external_unsigned_int : 'external unsigned int elements',
+ external_float : 'external float elements',
+ external_double : 'external double elements',
+ external_pixel : 'external pixel elements'
+}
+
+function getKind(obj) {
+ if (%HasFastSmiOnlyElements(obj)) return elements_kind.fast_smi_only;
+ if (%HasFastElements(obj)) return elements_kind.fast;
+ if (%HasFastDoubleElements(obj)) return elements_kind.fast_double;
+ if (%HasDictionaryElements(obj)) return elements_kind.dictionary;
+ // Every external kind is also an external array.
+ assertTrue(%HasExternalArrayElements(obj));
+ if (%HasExternalByteElements(obj)) {
+ return elements_kind.external_byte;
+ }
+ if (%HasExternalUnsignedByteElements(obj)) {
+ return elements_kind.external_unsigned_byte;
+ }
+ if (%HasExternalShortElements(obj)) {
+ return elements_kind.external_short;
+ }
+ if (%HasExternalUnsignedShortElements(obj)) {
+ return elements_kind.external_unsigned_short;
+ }
+ if (%HasExternalIntElements(obj)) {
+ return elements_kind.external_int;
+ }
+ if (%HasExternalUnsignedIntElements(obj)) {
+ return elements_kind.external_unsigned_int;
+ }
+ if (%HasExternalFloatElements(obj)) {
+ return elements_kind.external_float;
+ }
+ if (%HasExternalDoubleElements(obj)) {
+ return elements_kind.external_double;
+ }
+ if (%HasExternalPixelElements(obj)) {
+ return elements_kind.external_pixel;
+ }
+}
+
+function assertKind(expected, obj, name_opt) {
+ if (!support_smi_only_arrays &&
+ expected == elements_kind.fast_smi_only) {
+ expected = elements_kind.fast;
+ }
+ assertEquals(expected, getKind(obj), name_opt);
+}
+
+var me = {};
+assertKind(elements_kind.fast, me);
+me.dance = 0xD15C0;
+me.drink = 0xC0C0A;
+assertKind(elements_kind.fast, me);
+
+var too = [1,2,3];
+assertKind(elements_kind.fast_smi_only, too);
+too.dance = 0xD15C0;
+too.drink = 0xC0C0A;
+assertKind(elements_kind.fast_smi_only, too);
+
+// Make sure the element kind transitions from smionly when a non-smi is stored.
+var you = new Array();
+assertKind(elements_kind.fast_smi_only, you);
+for (var i = 0; i < 1337; i++) {
+ var val = i;
+ if (i == 1336) {
+ assertKind(elements_kind.fast_smi_only, you);
+ val = new Object();
+ }
+ you[i] = val;
+}
+assertKind(elements_kind.fast, you);
+
+assertKind(elements_kind.dictionary, new Array(0xDECAF));
+
+var fast_double_array = new Array(0xDECAF);
+for (var i = 0; i < 0xDECAF; i++) fast_double_array[i] = i / 2;
+assertKind(elements_kind.fast_double, fast_double_array);
+
+assertKind(elements_kind.external_byte, new Int8Array(9001));
+assertKind(elements_kind.external_unsigned_byte, new Uint8Array(007));
+assertKind(elements_kind.external_short, new Int16Array(666));
+assertKind(elements_kind.external_unsigned_short, new Uint16Array(42));
+assertKind(elements_kind.external_int, new Int32Array(0xF));
+assertKind(elements_kind.external_unsigned_int, new Uint32Array(23));
+assertKind(elements_kind.external_float, new Float32Array(7));
+assertKind(elements_kind.external_double, new Float64Array(0));
+assertKind(elements_kind.external_pixel, new PixelArray(512));
+
+// Crankshaft support for smi-only array elements.
+function monomorphic(array) {
+ for (var i = 0; i < 3; i++) {
+ array[i] = i + 10;
+ }
+ assertKind(elements_kind.fast_smi_only, array);
+ for (var i = 0; i < 3; i++) {
+ var a = array[i];
+ assertEquals(i + 10, a);
+ }
+}
+var smi_only = [1, 2, 3];
+for (var i = 0; i < 3; i++) monomorphic(smi_only);
+%OptimizeFunctionOnNextCall(monomorphic);
+monomorphic(smi_only);
+
+if (support_smi_only_arrays) {
+ function construct_smis() {
+ var a = [0, 0, 0];
+ a[0] = 0; // Send the COW array map to the steak house.
+ assertKind(elements_kind.fast_smi_only, a);
+ return a;
+ }
+ function construct_doubles() {
+ var a = construct_smis();
+ a[0] = 1.5;
+ assertKind(elements_kind.fast_double, a);
+ return a;
+ }
+ function construct_objects() {
+ var a = construct_smis();
+ a[0] = "one";
+ assertKind(elements_kind.fast, a);
+ return a;
+ }
+
+ // Test crankshafted transition SMI->DOUBLE.
+ function convert_to_double(array) {
+ array[1] = 2.5;
+ assertKind(elements_kind.fast_double, array);
+ assertEquals(2.5, array[1]);
+ }
+ var smis = construct_smis();
+ for (var i = 0; i < 3; i++) convert_to_double(smis);
+ %OptimizeFunctionOnNextCall(convert_to_double);
+ smis = construct_smis();
+ convert_to_double(smis);
+ // Test crankshafted transitions SMI->FAST and DOUBLE->FAST.
+ function convert_to_fast(array) {
+ array[1] = "two";
+ assertKind(elements_kind.fast, array);
+ assertEquals("two", array[1]);
+ }
+ smis = construct_smis();
+ for (var i = 0; i < 3; i++) convert_to_fast(smis);
+ var doubles = construct_doubles();
+ for (var i = 0; i < 3; i++) convert_to_fast(doubles);
+ smis = construct_smis();
+ doubles = construct_doubles();
+ %OptimizeFunctionOnNextCall(convert_to_fast);
+ convert_to_fast(smis);
+ convert_to_fast(doubles);
+ // Test transition chain SMI->DOUBLE->FAST (crankshafted function will
+ // transition to FAST directly).
+ function convert_mixed(array, value, kind) {
+ array[1] = value;
+ assertKind(kind, array);
+ assertEquals(value, array[1]);
+ }
+ smis = construct_smis();
+ for (var i = 0; i < 3; i++) {
+ convert_mixed(smis, 1.5, elements_kind.fast_double);
+ }
+ doubles = construct_doubles();
+ for (var i = 0; i < 3; i++) {
+ convert_mixed(doubles, "three", elements_kind.fast);
+ }
+ smis = construct_smis();
+ doubles = construct_doubles();
+ %OptimizeFunctionOnNextCall(convert_mixed);
+ convert_mixed(smis, 1, elements_kind.fast);
+ convert_mixed(doubles, 1, elements_kind.fast);
+ assertTrue(%HaveSameMap(smis, doubles));
+}
+
+// Crankshaft support for smi-only elements in dynamic array literals.
+function get(foo) { return foo; } // Used to generate dynamic values.
+
+function crankshaft_test() {
+ var a = [get(1), get(2), get(3)];
+ assertKind(elements_kind.fast_smi_only, a);
+ var b = [get(1), get(2), get("three")];
+ assertKind(elements_kind.fast, b);
+ var c = [get(1), get(2), get(3.5)];
+ if (support_smi_only_arrays) {
+ assertKind(elements_kind.fast_double, c);
+ } else {
+ assertKind(elements_kind.fast, c);
+ }
+}
+for (var i = 0; i < 3; i++) {
+ crankshaft_test();
+}
+%OptimizeFunctionOnNextCall(crankshaft_test);
+crankshaft_test();
+
+// Elements_kind transitions for arrays.
+
+// A map can have three different elements_kind transitions: SMI->DOUBLE,
+// DOUBLE->OBJECT, and SMI->OBJECT. No matter in which order these three are
+// created, they must always end up with the same FAST map.
+
+// This test is meaningless without FAST_SMI_ONLY_ELEMENTS.
+if (support_smi_only_arrays) {
+ // Preparation: create one pair of identical objects for each case.
+ var a = [1, 2, 3];
+ var b = [1, 2, 3];
+ assertTrue(%HaveSameMap(a, b));
+ assertKind(elements_kind.fast_smi_only, a);
+ var c = [1, 2, 3];
+ c["case2"] = true;
+ var d = [1, 2, 3];
+ d["case2"] = true;
+ assertTrue(%HaveSameMap(c, d));
+ assertFalse(%HaveSameMap(a, c));
+ assertKind(elements_kind.fast_smi_only, c);
+ var e = [1, 2, 3];
+ e["case3"] = true;
+ var f = [1, 2, 3];
+ f["case3"] = true;
+ assertTrue(%HaveSameMap(e, f));
+ assertFalse(%HaveSameMap(a, e));
+ assertFalse(%HaveSameMap(c, e));
+ assertKind(elements_kind.fast_smi_only, e);
+ // Case 1: SMI->DOUBLE, DOUBLE->OBJECT, SMI->OBJECT.
+ a[0] = 1.5;
+ assertKind(elements_kind.fast_double, a);
+ a[0] = "foo";
+ assertKind(elements_kind.fast, a);
+ b[0] = "bar";
+ assertTrue(%HaveSameMap(a, b));
+ // Case 2: SMI->DOUBLE, SMI->OBJECT, DOUBLE->OBJECT.
+ c[0] = 1.5;
+ assertKind(elements_kind.fast_double, c);
+ assertFalse(%HaveSameMap(c, d));
+ d[0] = "foo";
+ assertKind(elements_kind.fast, d);
+ assertFalse(%HaveSameMap(c, d));
+ c[0] = "bar";
+ assertTrue(%HaveSameMap(c, d));
+ // Case 3: SMI->OBJECT, SMI->DOUBLE, DOUBLE->OBJECT.
+ e[0] = "foo";
+ assertKind(elements_kind.fast, e);
+ assertFalse(%HaveSameMap(e, f));
+ f[0] = 1.5;
+ assertKind(elements_kind.fast_double, f);
+ assertFalse(%HaveSameMap(e, f));
+ f[0] = "bar";
+ assertKind(elements_kind.fast, f);
+ assertTrue(%HaveSameMap(e, f));
+}
+
+// Throw away type information in the ICs for next stress run.
+gc();
diff --git a/deps/v8/test/mjsunit/elements-transition.js b/deps/v8/test/mjsunit/elements-transition.js
new file mode 100644
index 0000000000..5f6cc4fa37
--- /dev/null
+++ b/deps/v8/test/mjsunit/elements-transition.js
@@ -0,0 +1,107 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --smi-only-arrays
+
+support_smi_only_arrays = %HasFastSmiOnlyElements([]);
+
+if (support_smi_only_arrays) {
+ function test(test_double, test_object, set, length) {
+ // We apply the same operations to two identical arrays. The first array
+ // triggers an IC miss, upon which the conversion stub is generated, but the
+ // actual conversion is done in runtime. The second array, arriving at
+ // the previously patched IC, is then converted using the conversion stub.
+ var array_1 = new Array(length);
+ var array_2 = new Array(length);
+
+ assertTrue(%HasFastSmiOnlyElements(array_1));
+ assertTrue(%HasFastSmiOnlyElements(array_2));
+ for (var i = 0; i < length; i++) {
+ if (i == length - 5 && test_double) {
+ // Trigger conversion to fast double elements at length-5.
+ set(array_1, i, 0.5);
+ set(array_2, i, 0.5);
+ assertTrue(%HasFastDoubleElements(array_1));
+ assertTrue(%HasFastDoubleElements(array_2));
+ } else if (i == length - 3 && test_object) {
+ // Trigger conversion to fast object elements at length-3.
+ set(array_1, i, 'object');
+ set(array_2, i, 'object');
+ assertTrue(%HasFastElements(array_1));
+ assertTrue(%HasFastElements(array_2));
+ } else if (i != length - 7) {
+ // Set the element to an integer but leave a hole at length-7.
+ set(array_1, i, 2*i+1);
+ set(array_2, i, 2*i+1);
+ }
+ }
+
+ for (var i = 0; i < length; i++) {
+ if (i == length - 5 && test_double) {
+ assertEquals(0.5, array_1[i]);
+ assertEquals(0.5, array_2[i]);
+ } else if (i == length - 3 && test_object) {
+ assertEquals('object', array_1[i]);
+ assertEquals('object', array_2[i]);
+ } else if (i != length - 7) {
+ assertEquals(2*i+1, array_1[i]);
+ assertEquals(2*i+1, array_2[i]);
+ } else {
+ assertEquals(undefined, array_1[i]);
+ assertEquals(undefined, array_2[i]);
+ }
+ }
+
+ assertEquals(length, array_1.length);
+ assertEquals(length, array_2.length);
+ }
+
+ test(false, false, function(a,i,v){ a[i] = v; }, 20);
+ test(true, false, function(a,i,v){ a[i] = v; }, 20);
+ test(false, true, function(a,i,v){ a[i] = v; }, 20);
+ test(true, true, function(a,i,v){ a[i] = v; }, 20);
+
+ test(false, false, function(a,i,v){ a[i] = v; }, 10000);
+ test(true, false, function(a,i,v){ a[i] = v; }, 10000);
+ test(false, true, function(a,i,v){ a[i] = v; }, 10000);
+ test(true, true, function(a,i,v){ a[i] = v; }, 10000);
+
+ // Check COW arrays
+ function get_cow() { return [1, 2, 3]; }
+
+ function transition(x) { x[0] = 1.5; }
+
+ var ignore = get_cow();
+ transition(ignore); // Handled by runtime.
+ var a = get_cow();
+ var b = get_cow();
+ transition(a); // Handled by IC.
+ assertEquals(1.5, a[0]);
+ assertEquals(1, b[0]);
+} else {
+ print("Test skipped because smi only arrays are not supported.");
+} \ No newline at end of file
diff --git a/deps/v8/test/mjsunit/error-tostring.js b/deps/v8/test/mjsunit/error-tostring.js
new file mode 100644
index 0000000000..a28564144f
--- /dev/null
+++ b/deps/v8/test/mjsunit/error-tostring.js
@@ -0,0 +1,85 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+// Test default string representation of an Error object.
+
+var e = new Error();
+assertEquals('Error', e.toString());
+
+
+// Test printing of cyclic errors which return the empty string for
+// compatibility with Safari and Firefox.
+
+e = new Error();
+e.name = e;
+e.message = e;
+e.stack = "Does not occur in output";
+e.arguments = "Does not occur in output";
+e.type = "Does not occur in output";
+assertEquals('', e.toString());
+
+e = new Error();
+e.name = [ e ];
+e.message = [ e ];
+e.stack = "Does not occur in output";
+e.arguments = "Does not occur in output";
+e.type = "Does not occur in output";
+assertEquals('', e.toString());
+
+
+// Test the sequence in which getters and toString operations are called
+// on a given Error object. Verify the produced string representation.
+
+function testErrorToString(nameValue, messageValue) {
+ var seq = [];
+ var e = {
+ get name() {
+ seq.push(1);
+ return (nameValue === undefined) ? nameValue : {
+ toString: function() { seq.push(2); return nameValue; }
+ };
+ },
+ get message() {
+ seq.push(3);
+ return (messageValue === undefined) ? messageValue : {
+ toString: function() { seq.push(4); return messageValue; }
+ };
+ }
+ };
+ var string = Error.prototype.toString.call(e);
+ return [string,seq];
+}
+
+assertEquals(["Error",[1,3]], testErrorToString(undefined, undefined));
+assertEquals(["e1",[1,2,3]], testErrorToString("e1", undefined));
+assertEquals(["e1: null",[1,2,3,4]], testErrorToString("e1", null));
+assertEquals(["e1",[1,2,3,4]], testErrorToString("e1", ""));
+assertEquals(["Error: e2",[1,3,4]], testErrorToString(undefined, "e2"));
+assertEquals(["null: e2",[1,2,3,4]], testErrorToString(null, "e2"));
+assertEquals(["e2",[1,2,3,4]], testErrorToString("", "e2"));
+assertEquals(["e1: e2",[1,2,3,4]], testErrorToString("e1", "e2"));
diff --git a/deps/v8/test/mjsunit/function-bind.js b/deps/v8/test/mjsunit/function-bind.js
index e9d02213e0..4a8f2d2a62 100644
--- a/deps/v8/test/mjsunit/function-bind.js
+++ b/deps/v8/test/mjsunit/function-bind.js
@@ -29,29 +29,31 @@
// Simple tests.
function foo(x, y, z) {
- return x + y + z;
+ return [this, arguments.length, x];
}
+assertEquals(3, foo.length);
+
var f = foo.bind(foo);
-assertEquals(3, f(1, 1, 1));
+assertEquals([foo, 3, 1], f(1, 2, 3));
assertEquals(3, f.length);
-f = foo.bind(foo, 2);
-assertEquals(4, f(1, 1));
+f = foo.bind(foo, 1);
+assertEquals([foo, 3, 1], f(2, 3));
assertEquals(2, f.length);
-f = foo.bind(foo, 2, 2);
-assertEquals(5, f(1));
+f = foo.bind(foo, 1, 2);
+assertEquals([foo, 3, 1], f(3));
assertEquals(1, f.length);
-f = foo.bind(foo, 2, 2, 2);
-assertEquals(6, f());
+f = foo.bind(foo, 1, 2, 3);
+assertEquals([foo, 3, 1], f());
assertEquals(0, f.length);
// Test that length works correctly even if more than the actual number
// of arguments are given when binding.
f = foo.bind(foo, 1, 2, 3, 4, 5, 6, 7, 8, 9);
-assertEquals(6, f());
+assertEquals([foo, 9, 1], f());
assertEquals(0, f.length);
// Use a different bound object.
@@ -78,64 +80,97 @@ assertEquals(0, f.length);
// When only giving the thisArg, any number of binds should have
// the same effect.
f = foo.bind(foo);
-assertEquals(3, f(1, 1, 1));
-f = foo.bind(foo).bind(foo).bind(foo).bind(foo);
-assertEquals(3, f(1, 1, 1));
+assertEquals([foo, 3, 1], f(1, 2, 3));
+
+var not_foo = {};
+f = foo.bind(foo).bind(not_foo).bind(not_foo).bind(not_foo);
+assertEquals([foo, 3, 1], f(1, 2, 3));
assertEquals(3, f.length);
// Giving bound parameters should work at any place in the chain.
-f = foo.bind(foo, 1).bind(foo).bind(foo).bind(foo);
-assertEquals(3, f(1, 1));
+f = foo.bind(foo, 1).bind(not_foo).bind(not_foo).bind(not_foo);
+assertEquals([foo, 3, 1], f(2, 3));
assertEquals(2, f.length);
-f = foo.bind(foo).bind(foo, 1).bind(foo).bind(foo);
-assertEquals(3, f(1, 1));
+f = foo.bind(foo).bind(not_foo, 1).bind(not_foo).bind(not_foo);
+assertEquals([foo, 3, 1], f(2, 3));
assertEquals(2, f.length);
-f = foo.bind(foo).bind(foo).bind(foo,1 ).bind(foo);
-assertEquals(3, f(1, 1));
+f = foo.bind(foo).bind(not_foo).bind(not_foo,1 ).bind(not_foo);
+assertEquals([foo, 3, 1], f(2, 3));
assertEquals(2, f.length);
-f = foo.bind(foo).bind(foo).bind(foo).bind(foo, 1);
-assertEquals(3, f(1, 1));
+f = foo.bind(foo).bind(not_foo).bind(not_foo).bind(not_foo, 1);
+assertEquals([foo, 3, 1], f(2, 3));
assertEquals(2, f.length);
-// Several parameters can be given, and given in different bind invokations.
-f = foo.bind(foo, 1, 1).bind(foo).bind(foo).bind(foo);
-assertEquals(3, f(1));
+// Several parameters can be given, and given in different bind invocations.
+f = foo.bind(foo, 1, 2).bind(not_foo).bind(not_foo).bind(not_foo);
+assertEquals([foo, 3, 1], f(3));
+assertEquals(1, f.length);
+
+f = foo.bind(foo).bind(not_foo, 1, 2).bind(not_foo).bind(not_foo);
+assertEquals([foo, 3, 1], f(1));
assertEquals(1, f.length);
-f = foo.bind(foo).bind(foo, 1, 1).bind(foo).bind(foo);
-assertEquals(3, f(1));
+f = foo.bind(foo).bind(not_foo, 1, 2).bind(not_foo).bind(not_foo);
+assertEquals([foo, 3, 1], f(3));
assertEquals(1, f.length);
-f = foo.bind(foo).bind(foo, 1, 1).bind(foo).bind(foo);
-assertEquals(3, f(1));
+f = foo.bind(foo).bind(not_foo).bind(not_foo, 1, 2).bind(not_foo);
+assertEquals([foo, 3, 1], f(1));
assertEquals(1, f.length);
-f = foo.bind(foo).bind(foo).bind(foo, 1, 1).bind(foo);
-assertEquals(3, f(1));
+f = foo.bind(foo).bind(not_foo).bind(not_foo).bind(not_foo, 1, 2);
+assertEquals([foo, 3, 1], f(3));
assertEquals(1, f.length);
-f = foo.bind(foo).bind(foo).bind(foo).bind(foo, 1, 1);
-assertEquals(3, f(1));
+f = foo.bind(foo, 1).bind(not_foo, 2).bind(not_foo).bind(not_foo);
+assertEquals([foo, 3, 1], f(3));
assertEquals(1, f.length);
-f = foo.bind(foo, 1).bind(foo, 1).bind(foo).bind(foo);
-assertEquals(3, f(1));
+f = foo.bind(foo, 1).bind(not_foo).bind(not_foo, 2).bind(not_foo);
+assertEquals([foo, 3, 1], f(3));
assertEquals(1, f.length);
-f = foo.bind(foo, 1).bind(foo).bind(foo, 1).bind(foo);
-assertEquals(3, f(1));
+f = foo.bind(foo, 1).bind(not_foo).bind(not_foo).bind(not_foo, 2);
+assertEquals([foo, 3, 1], f(3));
assertEquals(1, f.length);
-f = foo.bind(foo, 1).bind(foo).bind(foo).bind(foo, 1);
-assertEquals(3, f(1));
+f = foo.bind(foo).bind(not_foo, 1).bind(not_foo).bind(not_foo, 2);
+assertEquals([foo, 3, 1], f(3));
assertEquals(1, f.length);
-f = foo.bind(foo).bind(foo, 1).bind(foo).bind(foo, 1);
-assertEquals(3, f(1));
+// The wrong number of arguments can be given to bound functions too.
+f = foo.bind(foo);
+assertEquals(3, f.length);
+assertEquals([foo, 0, undefined], f());
+assertEquals([foo, 1, 1], f(1));
+assertEquals([foo, 2, 1], f(1, 2));
+assertEquals([foo, 3, 1], f(1, 2, 3));
+assertEquals([foo, 4, 1], f(1, 2, 3, 4));
+
+f = foo.bind(foo, 1);
+assertEquals(2, f.length);
+assertEquals([foo, 1, 1], f());
+assertEquals([foo, 2, 1], f(2));
+assertEquals([foo, 3, 1], f(2, 3));
+assertEquals([foo, 4, 1], f(2, 3, 4));
+
+f = foo.bind(foo, 1, 2);
assertEquals(1, f.length);
+assertEquals([foo, 2, 1], f());
+assertEquals([foo, 3, 1], f(3));
+assertEquals([foo, 4, 1], f(3, 4));
+
+f = foo.bind(foo, 1, 2, 3);
+assertEquals(0, f.length);
+assertEquals([foo, 3, 1], f());
+assertEquals([foo, 4, 1], f(4));
+
+f = foo.bind(foo, 1, 2, 3, 4);
+assertEquals(0, f.length);
+assertEquals([foo, 4, 1], f());
// Test constructor calls.
@@ -171,13 +206,91 @@ assertEquals(3, obj2.z);
// Test bind chains when used as a constructor.
-
f = bar.bind(bar, 1).bind(bar, 2).bind(bar, 3);
obj2 = new f();
assertEquals(1, obj2.x);
assertEquals(2, obj2.y);
assertEquals(3, obj2.z);
-// Test instanceof obj2 is bar, not f.
+// Test obj2 is instanceof both bar and f.
assertTrue(obj2 instanceof bar);
-assertFalse(obj2 instanceof f);
+assertTrue(obj2 instanceof f);
+
+// This-args are not relevant to instanceof.
+f = bar.bind(foo.prototype, 1).
+ bind(String.prototype, 2).
+ bind(Function.prototype, 3);
+var obj3 = new f();
+assertTrue(obj3 instanceof bar);
+assertTrue(obj3 instanceof f);
+assertFalse(obj3 instanceof foo);
+assertFalse(obj3 instanceof Function);
+assertFalse(obj3 instanceof String);
+
+// thisArg is converted to object.
+f = foo.bind(undefined);
+assertEquals([this, 0, undefined], f());
+
+f = foo.bind(null);
+assertEquals([this, 0, undefined], f());
+
+f = foo.bind(42);
+assertEquals([Object(42), 0, undefined], f());
+
+f = foo.bind("foo");
+assertEquals([Object("foo"), 0, undefined], f());
+
+f = foo.bind(true);
+assertEquals([Object(true), 0, undefined], f());
+
+// Strict functions don't convert thisArg.
+function soo(x, y, z) {
+ "use strict";
+ return [this, arguments.length, x];
+}
+
+var s = soo.bind(undefined);
+assertEquals([undefined, 0, undefined], s());
+
+s = soo.bind(null);
+assertEquals([null, 0, undefined], s());
+
+s = soo.bind(42);
+assertEquals([42, 0, undefined], s());
+
+s = soo.bind("foo");
+assertEquals(["foo", 0, undefined], s());
+
+s = soo.bind(true);
+assertEquals([true, 0, undefined], s());
+
+// Test that .arguments and .caller are poisoned according to the ES5 spec.
+
+// Check that property descriptors are correct (unconfigurable, unenumerable,
+// and both get and set is the ThrowTypeError function).
+var cdesc = Object.getOwnPropertyDescriptor(f, "caller");
+var adesc = Object.getOwnPropertyDescriptor(f, "arguments");
+
+assertFalse(cdesc.enumerable);
+assertFalse(cdesc.configurable);
+
+assertFalse(adesc.enumerable);
+assertFalse(adesc.configurable);
+
+assertSame(cdesc.get, cdesc.set);
+assertSame(cdesc.get, adesc.get);
+assertSame(cdesc.get, adesc.set);
+
+assertTrue(cdesc.get instanceof Function);
+assertEquals(0, cdesc.get.length);
+assertThrows(cdesc.get, TypeError);
+
+assertThrows(function() { return f.caller; }, TypeError);
+assertThrows(function() { f.caller = 42; }, TypeError);
+assertThrows(function() { return f.arguments; }, TypeError);
+assertThrows(function() { f.arguments = 42; }, TypeError);
+
+// Shouldn't throw. Accessing the functions caller must throw if
+// the caller is strict and the callee isn't. A bound function is built-in,
+// but not considered strict.
+(function foo() { return foo.caller; }).bind()();
diff --git a/deps/v8/test/mjsunit/harmony/block-conflicts.js b/deps/v8/test/mjsunit/harmony/block-conflicts.js
index 8b171f1710..e27d6a1d38 100644
--- a/deps/v8/test/mjsunit/harmony/block-conflicts.js
+++ b/deps/v8/test/mjsunit/harmony/block-conflicts.js
@@ -80,6 +80,11 @@ var letbinds = [ "let x",
"let x = function() {}",
"let x, y",
"let y, x",
+ "const x = 0",
+ "const x = undefined",
+ "const x = function() {}",
+ "const x = 2, y = 3",
+ "const y = 4, x = 5",
];
var varbinds = [ "var x",
"var x = 0",
diff --git a/deps/v8/test/mjsunit/harmony/block-for.js b/deps/v8/test/mjsunit/harmony/block-for.js
new file mode 100644
index 0000000000..1f68037a25
--- /dev/null
+++ b/deps/v8/test/mjsunit/harmony/block-for.js
@@ -0,0 +1,142 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --harmony-scoping
+
+function props(x) {
+ var array = [];
+ for (let p in x) array.push(p);
+ return array.sort();
+}
+
+assertEquals(0, props({}).length);
+assertEquals(1, props({x:1}).length);
+assertEquals(2, props({x:1, y:2}).length);
+
+assertArrayEquals(["x"], props({x:1}));
+assertArrayEquals(["x", "y"], props({x:1, y:2}));
+assertArrayEquals(["x", "y", "zoom"], props({x:1, y:2, zoom:3}));
+
+assertEquals(0, props([]).length);
+assertEquals(1, props([1]).length);
+assertEquals(2, props([1,2]).length);
+
+assertArrayEquals(["0"], props([1]));
+assertArrayEquals(["0", "1"], props([1,2]));
+assertArrayEquals(["0", "1", "2"], props([1,2,3]));
+
+var o = {};
+var a = [];
+let i = "outer_i";
+let s = "outer_s";
+for (let i = 0x0020; i < 0x01ff; i+=2) {
+ let s = 'char:' + String.fromCharCode(i);
+ a.push(s);
+ o[s] = i;
+}
+assertArrayEquals(a, props(o));
+assertEquals(i, "outer_i");
+assertEquals(s, "outer_s");
+
+var a = [];
+assertEquals(0, props(a).length);
+a[Math.pow(2,30)-1] = 0;
+assertEquals(1, props(a).length);
+a[Math.pow(2,31)-1] = 0;
+assertEquals(2, props(a).length);
+a[1] = 0;
+assertEquals(3, props(a).length);
+
+var result = '';
+for (let p in {a : [0], b : 1}) { result += p; }
+assertEquals('ab', result);
+
+var result = '';
+for (let p in {a : {v:1}, b : 1}) { result += p; }
+assertEquals('ab', result);
+
+var result = '';
+for (let p in { get a() {}, b : 1}) { result += p; }
+assertEquals('ab', result);
+
+var result = '';
+for (let p in { get a() {}, set a(x) {}, b : 1}) { result += p; }
+assertEquals('ab', result);
+
+
+// Check that there is exactly one variable without initializer
+// in a for-in statement with let variables.
+assertThrows("function foo() { for (let in {}) { } }", SyntaxError);
+assertThrows("function foo() { for (let x = 3 in {}) { } }", SyntaxError);
+assertThrows("function foo() { for (let x, y in {}) { } }", SyntaxError);
+assertThrows("function foo() { for (let x = 3, y in {}) { } }", SyntaxError);
+assertThrows("function foo() { for (let x, y = 4 in {}) { } }", SyntaxError);
+assertThrows("function foo() { for (let x = 3, y = 4 in {}) { } }", SyntaxError);
+
+
+// In a normal for statement the iteration variable is not
+// freshly allocated for each iteration.
+function closures1() {
+ let a = [];
+ for (let i = 0; i < 5; ++i) {
+ a.push(function () { return i; });
+ }
+ for (let j = 0; j < 5; ++j) {
+ assertEquals(5, a[j]());
+ }
+}
+closures1();
+
+
+function closures2() {
+ let a = [], b = [];
+ for (let i = 0, j = 10; i < 5; ++i, ++j) {
+ a.push(function () { return i; });
+ b.push(function () { return j; });
+ }
+ for (let k = 0; k < 5; ++k) {
+ assertEquals(5, a[k]());
+ assertEquals(15, b[k]());
+ }
+}
+closures2();
+
+
+// In a for-in statement the iteration variable is fresh
+// for earch iteration.
+function closures3(x) {
+ let a = [];
+ for (let p in x) {
+ a.push(function () { return p; });
+ }
+ let k = 0;
+ for (let q in x) {
+ assertEquals(q, a[k]());
+ ++k;
+ }
+}
+closures3({a : [0], b : 1, c : {v : 1}, get d() {}, set e(x) {}});
diff --git a/deps/v8/test/mjsunit/harmony/block-let-declaration.js b/deps/v8/test/mjsunit/harmony/block-let-declaration.js
index 7f3264f257..a1acc28da9 100644
--- a/deps/v8/test/mjsunit/harmony/block-let-declaration.js
+++ b/deps/v8/test/mjsunit/harmony/block-let-declaration.js
@@ -32,15 +32,18 @@
// Global
let x;
let y = 2;
+const z = 4;
// Block local
{
let y;
let x = 3;
+ const z = 5;
}
assertEquals(undefined, x);
assertEquals(2,y);
+assertEquals(4,z);
if (true) {
let y;
@@ -58,7 +61,7 @@ function TestLocalDoesNotThrow(str) {
assertDoesNotThrow("(function(){" + str + "})()");
}
-// Test let declarations statement positions.
+// Test let declarations in statement positions.
TestLocalThrows("if (true) let x;", SyntaxError);
TestLocalThrows("if (true) {} else let x;", SyntaxError);
TestLocalThrows("do let x; while (false)", SyntaxError);
@@ -68,7 +71,32 @@ TestLocalThrows("for (;false;) let x;", SyntaxError);
TestLocalThrows("switch (true) { case true: let x; }", SyntaxError);
TestLocalThrows("switch (true) { default: let x; }", SyntaxError);
-// Test var declarations statement positions.
+// Test const declarations with initialisers in statement positions.
+TestLocalThrows("if (true) const x = 1;", SyntaxError);
+TestLocalThrows("if (true) {} else const x = 1;", SyntaxError);
+TestLocalThrows("do const x = 1; while (false)", SyntaxError);
+TestLocalThrows("while (false) const x = 1;", SyntaxError);
+TestLocalThrows("label: const x = 1;", SyntaxError);
+TestLocalThrows("for (;false;) const x = 1;", SyntaxError);
+TestLocalThrows("switch (true) { case true: const x = 1; }", SyntaxError);
+TestLocalThrows("switch (true) { default: const x = 1; }", SyntaxError);
+
+// Test const declarations without initialisers.
+TestLocalThrows("const x;", SyntaxError);
+TestLocalThrows("const x = 1, y;", SyntaxError);
+TestLocalThrows("const x, y = 1;", SyntaxError);
+
+// Test const declarations without initialisers in statement positions.
+TestLocalThrows("if (true) const x;", SyntaxError);
+TestLocalThrows("if (true) {} else const x;", SyntaxError);
+TestLocalThrows("do const x; while (false)", SyntaxError);
+TestLocalThrows("while (false) const x;", SyntaxError);
+TestLocalThrows("label: const x;", SyntaxError);
+TestLocalThrows("for (;false;) const x;", SyntaxError);
+TestLocalThrows("switch (true) { case true: const x; }", SyntaxError);
+TestLocalThrows("switch (true) { default: const x; }", SyntaxError);
+
+// Test var declarations in statement positions.
TestLocalDoesNotThrow("if (true) var x;");
TestLocalDoesNotThrow("if (true) {} else var x;");
TestLocalDoesNotThrow("do var x; while (false)");
@@ -93,24 +121,15 @@ function f() {
{
function g1() { }
}
- // Non-strict statement positions.
- if (true) function g2() { }
- if (true) {} else function g3() { }
- do function g4() { } while (false)
- while (false) function g5() { }
- label: function g6() { }
- for (;false;) function g7() { }
- switch (true) { case true: function g8() { } }
- switch (true) { default: function g9() { } }
}
f();
// Test function declarations in statement position in strict mode.
-TestLocalThrows("function f() { 'use strict'; if (true) function g() {}", SyntaxError);
-TestLocalThrows("function f() { 'use strict'; if (true) {} else function g() {}", SyntaxError);
-TestLocalThrows("function f() { 'use strict'; do function g() {} while (false)", SyntaxError);
-TestLocalThrows("function f() { 'use strict'; while (false) function g() {}", SyntaxError);
-TestLocalThrows("function f() { 'use strict'; label: function g() {}", SyntaxError);
-TestLocalThrows("function f() { 'use strict'; for (;false;) function g() {}", SyntaxError);
-TestLocalThrows("function f() { 'use strict'; switch (true) { case true: function g() {} }", SyntaxError);
-TestLocalThrows("function f() { 'use strict'; switch (true) { default: function g() {} }", SyntaxError);
+TestLocalThrows("function f() { if (true) function g() {}", SyntaxError);
+TestLocalThrows("function f() { if (true) {} else function g() {}", SyntaxError);
+TestLocalThrows("function f() { do function g() {} while (false)", SyntaxError);
+TestLocalThrows("function f() { while (false) function g() {}", SyntaxError);
+TestLocalThrows("function f() { label: function g() {}", SyntaxError);
+TestLocalThrows("function f() { for (;false;) function g() {}", SyntaxError);
+TestLocalThrows("function f() { switch (true) { case true: function g() {} }", SyntaxError);
+TestLocalThrows("function f() { switch (true) { default: function g() {} }", SyntaxError);
diff --git a/deps/v8/test/mjsunit/harmony/block-let-semantics.js b/deps/v8/test/mjsunit/harmony/block-let-semantics.js
index 94020a4ca9..f45b72ff0f 100644
--- a/deps/v8/test/mjsunit/harmony/block-let-semantics.js
+++ b/deps/v8/test/mjsunit/harmony/block-let-semantics.js
@@ -61,6 +61,7 @@ TestAll('let x = x + 1');
TestAll('let x = x += 1');
TestAll('let x = x++');
TestAll('let x = ++x');
+TestAll('const x = x + 1');
// Use before initialization in prior statement.
TestAll('x + 1; let x;');
@@ -68,18 +69,21 @@ TestAll('x = 1; let x;');
TestAll('x += 1; let x;');
TestAll('++x; let x;');
TestAll('x++; let x;');
+TestAll('let y = x; const x = 1;');
TestAll('f(); let x; function f() { return x + 1; }');
TestAll('f(); let x; function f() { x = 1; }');
TestAll('f(); let x; function f() { x += 1; }');
TestAll('f(); let x; function f() { ++x; }');
TestAll('f(); let x; function f() { x++; }');
+TestAll('f(); const x = 1; function f() { return x; }');
TestAll('f()(); let x; function f() { return function() { return x + 1; } }');
TestAll('f()(); let x; function f() { return function() { x = 1; } }');
TestAll('f()(); let x; function f() { return function() { x += 1; } }');
TestAll('f()(); let x; function f() { return function() { ++x; } }');
TestAll('f()(); let x; function f() { return function() { x++; } }');
+TestAll('f()(); const x = 1; function f() { return function() { return x; } }');
// Use before initialization with a dynamic lookup.
TestAll('eval("x + 1;"); let x;');
@@ -87,6 +91,7 @@ TestAll('eval("x = 1;"); let x;');
TestAll('eval("x += 1;"); let x;');
TestAll('eval("++x;"); let x;');
TestAll('eval("x++;"); let x;');
+TestAll('eval("x"); const x = 1;');
// Use before initialization with check for eval-shadowed bindings.
TestAll('function f() { eval("var y = 2;"); x + 1; }; f(); let x;');
@@ -139,10 +144,31 @@ function f2() {
function h() {
return b + c;
}
- let b = 3;
+ let c = 3;
}
assertEquals(5, n());
+
+ {
+ o = i;
+ function i() {
+ return d;
+ }
+ let d = 4;
+ }
+ assertEquals(4, o());
+
+ try {
+ throw 5;
+ } catch(e) {
+ p = j;
+ function j() {
+ return e + f;
+ }
+ let f = 6;
+ }
+ assertEquals(11, p());
}
+f2();
// Test that resolution of let bound variables works with scopes that call eval.
function outer() {
diff --git a/deps/v8/test/mjsunit/harmony/block-scoping.js b/deps/v8/test/mjsunit/harmony/block-scoping.js
index c70b3b6ea8..0d0526afab 100644
--- a/deps/v8/test/mjsunit/harmony/block-scoping.js
+++ b/deps/v8/test/mjsunit/harmony/block-scoping.js
@@ -44,12 +44,16 @@ f1();
function f2(one) {
var x = one + 1;
let y = one + 2;
+ const u = one + 4;
{
let z = one + 3;
+ const v = one + 5;
assertEquals(1, eval('one'));
assertEquals(2, eval('x'));
assertEquals(3, eval('y'));
assertEquals(4, eval('z'));
+ assertEquals(5, eval('u'));
+ assertEquals(6, eval('v'));
}
}
f2(1);
@@ -59,12 +63,17 @@ f2(1);
function f3(one) {
var x = one + 1;
let y = one + 2;
+ const u = one + 4;
{
let z = one + 3;
+ const v = one + 5;
assertEquals(1, one);
assertEquals(2, x);
assertEquals(3, y);
assertEquals(4, z);
+ assertEquals(5, u);
+ assertEquals(6, v);
+
}
}
f3(1);
@@ -74,13 +83,17 @@ f3(1);
function f4(one) {
var x = one + 1;
let y = one + 2;
+ const u = one + 4;
{
let z = one + 3;
+ const v = one + 5;
function f() {
assertEquals(1, eval('one'));
assertEquals(2, eval('x'));
assertEquals(3, eval('y'));
assertEquals(4, eval('z'));
+ assertEquals(5, eval('u'));
+ assertEquals(6, eval('v'));
};
}
}
@@ -91,13 +104,17 @@ f4(1);
function f5(one) {
var x = one + 1;
let y = one + 2;
+ const u = one + 4;
{
let z = one + 3;
+ const v = one + 5;
function f() {
assertEquals(1, one);
assertEquals(2, x);
assertEquals(3, y);
assertEquals(4, z);
+ assertEquals(5, u);
+ assertEquals(6, v);
};
}
}
@@ -107,8 +124,10 @@ f5(1);
// Return from block.
function f6() {
let x = 1;
+ const u = 3;
{
let y = 2;
+ const v = 4;
return x + y;
}
}
@@ -120,13 +139,26 @@ function f7(a) {
let b = 1;
var c = 1;
var d = 1;
- { // let variables shadowing argument, let and var variables
+ const e = 1;
+ { // let variables shadowing argument, let, const and var variables
let a = 2;
let b = 2;
let c = 2;
+ let e = 2;
+ assertEquals(2,a);
+ assertEquals(2,b);
+ assertEquals(2,c);
+ assertEquals(2,e);
+ }
+ { // const variables shadowing argument, let, const and var variables
+ const a = 2;
+ const b = 2;
+ const c = 2;
+ const e = 2;
assertEquals(2,a);
assertEquals(2,b);
assertEquals(2,c);
+ assertEquals(2,e);
}
try {
throw 'stuff1';
@@ -156,6 +188,12 @@ function f7(a) {
} catch (c) {
// catch variable shadowing var variable
assertEquals('stuff3',c);
+ {
+ // const variable shadowing catch variable
+ const c = 3;
+ assertEquals(3,c);
+ }
+ assertEquals('stuff3',c);
try {
throw 'stuff4';
} catch(c) {
@@ -178,14 +216,16 @@ function f7(a) {
c = 2;
}
assertEquals(1,c);
- (function(a,b,c) {
- // arguments shadowing argument, let and var variable
+ (function(a,b,c,e) {
+ // arguments shadowing argument, let, const and var variable
a = 2;
b = 2;
c = 2;
+ e = 2;
assertEquals(2,a);
assertEquals(2,b);
assertEquals(2,c);
+ assertEquals(2,e);
// var variable shadowing var variable
var d = 2;
})(1,1);
@@ -193,24 +233,30 @@ function f7(a) {
assertEquals(1,b);
assertEquals(1,c);
assertEquals(1,d);
+ assertEquals(1,e);
}
f7(1);
-// Ensure let variables are block local and var variables function local.
+// Ensure let and const variables are block local
+// and var variables function local.
function f8() {
var let_accessors = [];
var var_accessors = [];
+ var const_accessors = [];
for (var i = 0; i < 10; i++) {
let x = i;
var y = i;
+ const z = i;
let_accessors[i] = function() { return x; }
var_accessors[i] = function() { return y; }
+ const_accessors[i] = function() { return z; }
}
for (var j = 0; j < 10; j++) {
y = j + 10;
assertEquals(j, let_accessors[j]());
assertEquals(y, var_accessors[j]());
+ assertEquals(j, const_accessors[j]());
}
}
f8();
diff --git a/deps/v8/test/mjsunit/harmony/collections.js b/deps/v8/test/mjsunit/harmony/collections.js
new file mode 100644
index 0000000000..1ad1c6f349
--- /dev/null
+++ b/deps/v8/test/mjsunit/harmony/collections.js
@@ -0,0 +1,273 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --harmony-collections --expose-gc
+
+
+// Test valid getter and setter calls on Sets.
+function TestValidSetCalls(m) {
+ assertDoesNotThrow(function () { m.add(new Object) });
+ assertDoesNotThrow(function () { m.has(new Object) });
+ assertDoesNotThrow(function () { m.delete(new Object) });
+}
+TestValidSetCalls(new Set);
+
+
+// Test valid getter and setter calls on Maps and WeakMaps
+function TestValidMapCalls(m) {
+ assertDoesNotThrow(function () { m.get(new Object) });
+ assertDoesNotThrow(function () { m.set(new Object) });
+ assertDoesNotThrow(function () { m.has(new Object) });
+ assertDoesNotThrow(function () { m.delete(new Object) });
+}
+TestValidMapCalls(new Map);
+TestValidMapCalls(new WeakMap);
+
+
+// Test invalid getter and setter calls for WeakMap only
+function TestInvalidCalls(m) {
+ assertThrows(function () { m.get(undefined) }, TypeError);
+ assertThrows(function () { m.set(undefined, 0) }, TypeError);
+ assertThrows(function () { m.get(0) }, TypeError);
+ assertThrows(function () { m.set(0, 0) }, TypeError);
+ assertThrows(function () { m.get('a-key') }, TypeError);
+ assertThrows(function () { m.set('a-key', 0) }, TypeError);
+}
+TestInvalidCalls(new WeakMap);
+
+
+// Test expected behavior for Sets
+function TestSet(set, key) {
+ assertFalse(set.has(key));
+ set.add(key);
+ assertTrue(set.has(key));
+ set.delete(key);
+ assertFalse(set.has(key));
+}
+function TestSetBehavior(set) {
+ for (i = 0; i < 20; i++) {
+ TestSet(set, new Object);
+ }
+}
+TestSet(new Set, 23);
+TestSet(new Set, 'foo');
+TestSetBehavior(new Set);
+
+
+// Test expected mapping behavior for Maps and WeakMaps
+function TestMapping(map, key, value) {
+ map.set(key, value);
+ assertSame(value, map.get(key));
+}
+function TestMapBehavior1(m) {
+ TestMapping(m, new Object, 23);
+ TestMapping(m, new Object, 'the-value');
+ TestMapping(m, new Object, new Object);
+}
+TestMapBehavior1(new Map);
+TestMapBehavior1(new WeakMap);
+
+
+// Test expected mapping behavior for Maps only
+function TestMapBehavior2(m) {
+ for (var i = 0; i < 20; i++) {
+ TestMapping(m, i, new Object);
+ TestMapping(m, i / 10, new Object);
+ TestMapping(m, 'key-' + i, new Object);
+ }
+ var keys = [ +0, -0, +Infinity, -Infinity, true, false ];
+ for (var i = 0; i < keys.length; i++) {
+ TestMapping(m, keys[i], new Object);
+ }
+}
+TestMapBehavior2(new Map);
+
+
+// Test expected querying behavior of Maps and WeakMaps
+function TestQuery(m) {
+ var key = new Object;
+ TestMapping(m, key, 'to-be-present');
+ assertTrue(m.has(key));
+ assertFalse(m.has(new Object));
+ TestMapping(m, key, undefined);
+ assertFalse(m.has(key));
+ assertFalse(m.has(new Object));
+}
+TestQuery(new Map);
+TestQuery(new WeakMap);
+
+
+// Test expected deletion behavior of Maps and WeakMaps
+function TestDelete(m) {
+ var key = new Object;
+ TestMapping(m, key, 'to-be-deleted');
+ assertTrue(m.delete(key));
+ assertFalse(m.delete(key));
+ assertFalse(m.delete(new Object));
+ assertSame(m.get(key), undefined);
+}
+TestDelete(new Map);
+TestDelete(new WeakMap);
+
+
+// Test GC of Maps and WeakMaps with entry
+function TestGC1(m) {
+ var key = new Object;
+ m.set(key, 'not-collected');
+ gc();
+ assertSame('not-collected', m.get(key));
+}
+TestGC1(new Map);
+TestGC1(new WeakMap);
+
+
+// Test GC of Maps and WeakMaps with chained entries
+function TestGC2(m) {
+ var head = new Object;
+ for (key = head, i = 0; i < 10; i++, key = m.get(key)) {
+ m.set(key, new Object);
+ }
+ gc();
+ var count = 0;
+ for (key = head; key != undefined; key = m.get(key)) {
+ count++;
+ }
+ assertEquals(11, count);
+}
+TestGC2(new Map);
+TestGC2(new WeakMap);
+
+
+// Test property attribute [[Enumerable]]
+function TestEnumerable(func) {
+ function props(x) {
+ var array = [];
+ for (var p in x) array.push(p);
+ return array.sort();
+ }
+ assertArrayEquals([], props(func));
+ assertArrayEquals([], props(func.prototype));
+ assertArrayEquals([], props(new func()));
+}
+TestEnumerable(Set);
+TestEnumerable(Map);
+TestEnumerable(WeakMap);
+
+
+// Test arbitrary properties on Maps and WeakMaps
+function TestArbitrary(m) {
+ function TestProperty(map, property, value) {
+ map[property] = value;
+ assertEquals(value, map[property]);
+ }
+ for (i = 0; i < 20; i++) {
+ TestProperty(m, i, 'val' + i);
+ TestProperty(m, 'foo' + i, 'bar' + i);
+ }
+ TestMapping(m, new Object, 'foobar');
+}
+TestArbitrary(new Map);
+TestArbitrary(new WeakMap);
+
+
+// Test direct constructor call
+assertTrue(Set() instanceof Set);
+assertTrue(Map() instanceof Map);
+assertTrue(WeakMap() instanceof WeakMap);
+
+
+// Test whether NaN values as keys are treated correctly.
+var s = new Set;
+assertFalse(s.has(NaN));
+assertFalse(s.has(NaN + 1));
+assertFalse(s.has(23));
+s.add(NaN);
+assertTrue(s.has(NaN));
+assertTrue(s.has(NaN + 1));
+assertFalse(s.has(23));
+var m = new Map;
+assertFalse(m.has(NaN));
+assertFalse(m.has(NaN + 1));
+assertFalse(m.has(23));
+m.set(NaN, 'a-value');
+assertTrue(m.has(NaN));
+assertTrue(m.has(NaN + 1));
+assertFalse(m.has(23));
+
+
+// Test some common JavaScript idioms for Sets
+var s = new Set;
+assertTrue(s instanceof Set);
+assertTrue(Set.prototype.add instanceof Function)
+assertTrue(Set.prototype.has instanceof Function)
+assertTrue(Set.prototype.delete instanceof Function)
+
+
+// Test some common JavaScript idioms for Maps
+var m = new Map;
+assertTrue(m instanceof Map);
+assertTrue(Map.prototype.set instanceof Function)
+assertTrue(Map.prototype.get instanceof Function)
+assertTrue(Map.prototype.has instanceof Function)
+assertTrue(Map.prototype.delete instanceof Function)
+
+
+// Test some common JavaScript idioms for WeakMaps
+var m = new WeakMap;
+assertTrue(m instanceof WeakMap);
+assertTrue(WeakMap.prototype.set instanceof Function)
+assertTrue(WeakMap.prototype.get instanceof Function)
+assertTrue(WeakMap.prototype.has instanceof Function)
+assertTrue(WeakMap.prototype.delete instanceof Function)
+
+
+// Regression test for WeakMap prototype.
+assertTrue(WeakMap.prototype.constructor === WeakMap)
+assertTrue(Object.getPrototypeOf(WeakMap.prototype) === Object.prototype)
+
+
+// Regression test for issue 1617: The prototype of the WeakMap constructor
+// needs to be unique (i.e. different from the one of the Object constructor).
+assertFalse(WeakMap.prototype === Object.prototype);
+var o = Object.create({});
+assertFalse("get" in o);
+assertFalse("set" in o);
+assertEquals(undefined, o.get);
+assertEquals(undefined, o.set);
+var o = Object.create({}, { myValue: {
+ value: 10,
+ enumerable: false,
+ configurable: true,
+ writable: true
+}});
+assertEquals(10, o.myValue);
+
+
+// Stress Test
+// There is a proposed stress-test available at the es-discuss mailing list
+// which cannot be reasonably automated. Check it out by hand if you like:
+// https://mail.mozilla.org/pipermail/es-discuss/2011-May/014096.html \ No newline at end of file
diff --git a/deps/v8/test/mjsunit/harmony/debug-blockscopes.js b/deps/v8/test/mjsunit/harmony/debug-blockscopes.js
index 020f52774b..4c49d9a4b0 100644
--- a/deps/v8/test/mjsunit/harmony/debug-blockscopes.js
+++ b/deps/v8/test/mjsunit/harmony/debug-blockscopes.js
@@ -464,3 +464,112 @@ listener_delegate = function(exec_state) {
};
closure_1(1)();
EndTest();
+
+
+// Simple for-in loop over the keys of an object.
+BeginTest("For loop 1");
+
+function for_loop_1() {
+ for (let x in {y:undefined}) {
+ debugger;
+ }
+}
+
+listener_delegate = function(exec_state) {
+ CheckScopeChain([debug.ScopeType.Block,
+ debug.ScopeType.Local,
+ debug.ScopeType.Global], exec_state);
+ CheckScopeContent({x:'y'}, 0, exec_state);
+ // The function scope contains a temporary iteration variable.
+ CheckScopeContent({x:'y'}, 1, exec_state);
+};
+for_loop_1();
+EndTest();
+
+
+// For-in loop over the keys of an object with a block scoped let variable
+// shadowing the iteration variable.
+BeginTest("For loop 2");
+
+function for_loop_2() {
+ for (let x in {y:undefined}) {
+ let x = 3;
+ debugger;
+ }
+}
+
+listener_delegate = function(exec_state) {
+ CheckScopeChain([debug.ScopeType.Block,
+ debug.ScopeType.Block,
+ debug.ScopeType.Local,
+ debug.ScopeType.Global], exec_state);
+ CheckScopeContent({x:3}, 0, exec_state);
+ CheckScopeContent({x:'y'}, 1, exec_state);
+ // The function scope contains a temporary iteration variable.
+ CheckScopeContent({x:'y'}, 2, exec_state);
+};
+for_loop_2();
+EndTest();
+
+
+// Simple for loop.
+BeginTest("For loop 3");
+
+function for_loop_3() {
+ for (let x = 3; x < 4; ++x) {
+ debugger;
+ }
+}
+
+listener_delegate = function(exec_state) {
+ CheckScopeChain([debug.ScopeType.Block,
+ debug.ScopeType.Local,
+ debug.ScopeType.Global], exec_state);
+ CheckScopeContent({x:3}, 0, exec_state);
+ CheckScopeContent({}, 1, exec_state);
+};
+for_loop_3();
+EndTest();
+
+
+// For loop with a block scoped let variable shadowing the iteration variable.
+BeginTest("For loop 4");
+
+function for_loop_4() {
+ for (let x = 3; x < 4; ++x) {
+ let x = 5;
+ debugger;
+ }
+}
+
+listener_delegate = function(exec_state) {
+ CheckScopeChain([debug.ScopeType.Block,
+ debug.ScopeType.Block,
+ debug.ScopeType.Local,
+ debug.ScopeType.Global], exec_state);
+ CheckScopeContent({x:5}, 0, exec_state);
+ CheckScopeContent({x:3}, 1, exec_state);
+ CheckScopeContent({}, 2, exec_state);
+};
+for_loop_4();
+EndTest();
+
+
+// For loop with two variable declarations.
+BeginTest("For loop 5");
+
+function for_loop_5() {
+ for (let x = 3, y = 5; x < 4; ++x) {
+ debugger;
+ }
+}
+
+listener_delegate = function(exec_state) {
+ CheckScopeChain([debug.ScopeType.Block,
+ debug.ScopeType.Local,
+ debug.ScopeType.Global], exec_state);
+ CheckScopeContent({x:3,y:5}, 0, exec_state);
+ CheckScopeContent({}, 1, exec_state);
+};
+for_loop_5();
+EndTest();
diff --git a/deps/v8/test/mjsunit/harmony/proxies-for.js b/deps/v8/test/mjsunit/harmony/proxies-for.js
new file mode 100644
index 0000000000..3d419c6dca
--- /dev/null
+++ b/deps/v8/test/mjsunit/harmony/proxies-for.js
@@ -0,0 +1,168 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --harmony-proxies
+
+
+// Helper.
+
+function TestWithProxies(test, x, y, z) {
+ test(Proxy.create, x, y, z)
+ test(function(h) {return Proxy.createFunction(h, function() {})}, x, y, z)
+}
+
+
+// Iterate over a proxy.
+
+function TestForIn(properties, handler) {
+ TestWithProxies(TestForIn2, properties, handler)
+}
+
+function TestForIn2(create, properties, handler) {
+ var p = create(handler)
+ var found = []
+ for (var x in p) found.push(x)
+ assertArrayEquals(properties, found)
+}
+
+TestForIn(["0", "a"], {
+ enumerate: function() { return [0, "a"] }
+})
+
+TestForIn(["null", "a"], {
+ enumerate: function() { return this.enumerate2() },
+ enumerate2: function() { return [null, "a"] }
+})
+
+TestForIn(["b", "d"], {
+ getPropertyNames: function() { return ["a", "b", "c", "d", "e"] },
+ getPropertyDescriptor: function(k) {
+ switch (k) {
+ case "a": return {enumerable: false, value: "3"};
+ case "b": return {enumerable: true, get get() {}};
+ case "c": return {value: 4};
+ case "d": return {get enumerable() { return true }};
+ default: return undefined;
+ }
+ }
+})
+
+TestForIn(["b", "a", "0", "c"], Proxy.create({
+ get: function(pr, pk) {
+ return function() { return ["b", "a", 0, "c"] }
+ }
+}))
+
+
+
+// Iterate over an object with a proxy prototype.
+
+function TestForInDerived(properties, handler) {
+ TestWithProxies(TestForInDerived2, properties, handler)
+}
+
+function TestForInDerived2(create, properties, handler) {
+ var p = create(handler)
+ var o = Object.create(p)
+ o.z = 0
+ var found = []
+ for (var x in o) found.push(x)
+ assertArrayEquals(["z"].concat(properties), found)
+
+ var oo = Object.create(o)
+ oo.y = 0
+ var found = []
+ for (var x in oo) found.push(x)
+ assertArrayEquals(["y", "z"].concat(properties), found)
+}
+
+TestForInDerived(["0", "a"], {
+ enumerate: function() { return [0, "a"] },
+ getPropertyDescriptor: function(k) {
+ return k == "0" || k == "a" ? {} : undefined
+ }
+})
+
+TestForInDerived(["null", "a"], {
+ enumerate: function() { return this.enumerate2() },
+ enumerate2: function() { return [null, "a"] },
+ getPropertyDescriptor: function(k) {
+ return k == "null" || k == "a" ? {} : undefined
+ }
+})
+
+TestForInDerived(["b", "d"], {
+ getPropertyNames: function() { return ["a", "b", "c", "d", "e"] },
+ getPropertyDescriptor: function(k) {
+ switch (k) {
+ case "a": return {enumerable: false, value: "3"};
+ case "b": return {enumerable: true, get get() {}};
+ case "c": return {value: 4};
+ case "d": return {get enumerable() { return true }};
+ default: return undefined;
+ }
+ }
+})
+
+
+
+// Throw exception in enumerate trap.
+
+function TestForInThrow(handler) {
+ TestWithProxies(TestForInThrow2, handler)
+}
+
+function TestForInThrow2(create, handler) {
+ var p = create(handler)
+ var o = Object.create(p)
+ assertThrows(function(){ for (var x in p) {} }, "myexn")
+ assertThrows(function(){ for (var x in o) {} }, "myexn")
+}
+
+TestForInThrow({
+ enumerate: function() { throw "myexn" }
+})
+
+TestForInThrow({
+ enumerate: function() { return this.enumerate2() },
+ enumerate2: function() { throw "myexn" }
+})
+
+TestForInThrow({
+ getPropertyNames: function() { throw "myexn" }
+})
+
+TestForInThrow({
+ getPropertyNames: function() { return ["a"] },
+ getPropertyDescriptor: function() { throw "myexn" }
+})
+
+TestForInThrow(Proxy.create({
+ get: function(pr, pk) {
+ return function() { throw "myexn" }
+ }
+}))
diff --git a/deps/v8/test/mjsunit/harmony/proxies-function.js b/deps/v8/test/mjsunit/harmony/proxies-function.js
index 541bca8cc8..6a88d19b3b 100644
--- a/deps/v8/test/mjsunit/harmony/proxies-function.js
+++ b/deps/v8/test/mjsunit/harmony/proxies-function.js
@@ -38,6 +38,13 @@ function CreateFrozen(handler, callTrap, constructTrap) {
}
+// Ensures that checking the "length" property of a function proxy doesn't
+// crash due to lack of a [[Get]] method.
+var handler = {
+ get : function(r, n) { return n == "length" ? 2 : undefined }
+}
+
+
// Calling (call, Function.prototype.call, Function.prototype.apply,
// Function.prototype.bind).
@@ -46,81 +53,167 @@ var receiver
function TestCall(isStrict, callTrap) {
assertEquals(42, callTrap(5, 37))
- // TODO(rossberg): unrelated bug: this does not succeed for optimized code:
- // assertEquals(isStrict ? undefined : global_object, receiver)
+ assertEquals(isStrict ? undefined : global_object, receiver)
+
+ var handler = {
+ get: function(r, k) {
+ return k == "length" ? 2 : Function.prototype[k]
+ }
+ }
+ var f = Proxy.createFunction(handler, callTrap)
- var f = Proxy.createFunction({}, callTrap)
receiver = 333
assertEquals(42, f(11, 31))
assertEquals(isStrict ? undefined : global_object, receiver)
- var o = {}
+ var o = {f: f}
+ receiver = 333
+ assertEquals(42, o.f(10, 32))
+ assertSame(o, receiver)
+ receiver = 333
+ assertEquals(42, o["f"](9, 33))
+ assertSame(o, receiver)
+ receiver = 333
+ assertEquals(42, (1, o).f(8, 34))
+ assertSame(o, receiver)
+ receiver = 333
+ assertEquals(42, (1, o)["f"](7, 35))
+ assertSame(o, receiver)
+ receiver = 333
+ assertEquals(42, f.call(o, 32, 10))
+ assertSame(o, receiver)
+ receiver = 333
+ assertEquals(42, f.call(null, 33, 9))
+ assertSame(isStrict ? null : global_object, receiver)
+ receiver = 333
+ assertEquals(44, f.call(2, 21, 23))
+ assertSame(2, receiver.valueOf())
+ receiver = 333
assertEquals(42, Function.prototype.call.call(f, o, 20, 22))
- assertEquals(o, receiver)
+ assertSame(o, receiver)
+ receiver = 333
assertEquals(43, Function.prototype.call.call(f, null, 20, 23))
- assertEquals(isStrict ? null : global_object, receiver)
+ assertSame(isStrict ? null : global_object, receiver)
assertEquals(44, Function.prototype.call.call(f, 2, 21, 23))
assertEquals(2, receiver.valueOf())
receiver = 333
+ assertEquals(32, f.apply(o, [16, 16]))
+ assertSame(o, receiver)
+ receiver = 333
assertEquals(32, Function.prototype.apply.call(f, o, [17, 15]))
- assertEquals(o, receiver)
+ assertSame(o, receiver)
+
var ff = Function.prototype.bind.call(f, o, 12)
+ assertTrue(ff.length <= 1) // TODO(rossberg): Not spec'ed yet, be lax.
receiver = 333
assertEquals(42, ff(30))
- assertEquals(o, receiver)
+ assertSame(o, receiver)
receiver = 333
assertEquals(32, Function.prototype.apply.call(ff, {}, [20]))
- assertEquals(o, receiver)
+ assertSame(o, receiver)
+
+ var fff = Function.prototype.bind.call(ff, o, 30)
+ assertEquals(0, fff.length)
+ receiver = 333
+ assertEquals(42, fff())
+ assertSame(o, receiver)
+ receiver = 333
+ assertEquals(42, Function.prototype.call.call(fff, {}))
+ assertSame(o, receiver)
var f = CreateFrozen({}, callTrap)
receiver = 333
assertEquals(42, f(11, 31))
- // TODO(rossberg): unrelated bug: this does not succeed for optimized code.
- // assertEquals(isStrict ? undefined : global, receiver)
+ assertSame(isStrict ? undefined : global_object, receiver)
+ var o = {f: f}
+ receiver = 333
+ assertEquals(42, o.f(10, 32))
+ assertSame(o, receiver)
+ receiver = 333
+ assertEquals(42, o["f"](9, 33))
+ assertSame(o, receiver)
+ receiver = 333
+ assertEquals(42, (1, o).f(8, 34))
+ assertSame(o, receiver)
+ receiver = 333
+ assertEquals(42, (1, o)["f"](7, 35))
+ assertSame(o, receiver)
receiver = 333
assertEquals(42, Function.prototype.call.call(f, o, 20, 22))
- assertEquals(o, receiver)
+ assertSame(o, receiver)
receiver = 333
assertEquals(32, Function.prototype.apply.call(f, o, [17, 15]))
- assertEquals(o, receiver)
+ assertSame(o, receiver)
receiver = 333
assertEquals(42, ff(30))
- assertEquals(o, receiver)
+ assertSame(o, receiver)
receiver = 333
assertEquals(32, Function.prototype.apply.call(ff, {}, [20]))
- assertEquals(o, receiver)
+ assertSame(o, receiver)
}
TestCall(false, function(x, y) {
- receiver = this; return x + y
+ receiver = this
+ return x + y
})
TestCall(true, function(x, y) {
- "use strict";
- receiver = this; return x + y
+ "use strict"
+ receiver = this
+ return x + y
})
-TestCall(false, Proxy.createFunction({}, function(x, y) {
- receiver = this; return x + y
+TestCall(false, function() {
+ receiver = this; return arguments[0] + arguments[1]
+})
+
+TestCall(false, Proxy.createFunction(handler, function(x, y) {
+ receiver = this
+ return x + y
}))
-TestCall(true, Proxy.createFunction({}, function(x, y) {
- "use strict";
- receiver = this; return x + y
+TestCall(true, Proxy.createFunction(handler, function(x, y) {
+ "use strict"
+ receiver = this
+ return x + y
}))
-TestCall(false, CreateFrozen({}, function(x, y) {
- receiver = this; return x + y
+TestCall(false, CreateFrozen(handler, function(x, y) {
+ receiver = this
+ return x + y
}))
+
+// Using intrinsics as call traps.
+
+function TestCallIntrinsic(type, callTrap) {
+ var f = Proxy.createFunction({}, callTrap)
+ var x = f()
+ assertTrue(typeof x == type)
+}
+
+TestCallIntrinsic("boolean", Boolean)
+TestCallIntrinsic("number", Number)
+TestCallIntrinsic("string", String)
+TestCallIntrinsic("object", Object)
+TestCallIntrinsic("function", Function)
+
+
+
+// Throwing from call trap.
+
function TestCallThrow(callTrap) {
var f = Proxy.createFunction({}, callTrap)
assertThrows(function(){ f(11) }, "myexn")
+ assertThrows(function(){ ({x: f}).x(11) }, "myexn")
+ assertThrows(function(){ ({x: f})["x"](11) }, "myexn")
assertThrows(function(){ Function.prototype.call.call(f, {}, 2) }, "myexn")
assertThrows(function(){ Function.prototype.apply.call(f, {}, [1]) }, "myexn")
var f = CreateFrozen({}, callTrap)
assertThrows(function(){ f(11) }, "myexn")
+ assertThrows(function(){ ({x: f}).x(11) }, "myexn")
+ assertThrows(function(){ ({x: f})["x"](11) }, "myexn")
assertThrows(function(){ Function.prototype.call.call(f, {}, 2) }, "myexn")
assertThrows(function(){ Function.prototype.apply.call(f, {}, [1]) }, "myexn")
}
@@ -137,24 +230,48 @@ var prototype = {}
var receiver
var handlerWithPrototype = {
- fix: function() { return {prototype: prototype} },
- get: function(r, n) { assertEquals("prototype", n); return prototype }
+ fix: function() { return { prototype: { value: prototype } }; },
+ get: function(r, n) {
+ if (n == "length") return 2;
+ assertEquals("prototype", n);
+ return prototype;
+ }
}
var handlerSansPrototype = {
- fix: function() { return {} },
- get: function(r, n) { assertEquals("prototype", n); return undefined }
+ fix: function() { return { length: { value: 2 } } },
+ get: function(r, n) {
+ if (n == "length") return 2;
+ assertEquals("prototype", n);
+ return undefined;
+ }
+}
+
+function ReturnUndef(x, y) {
+ "use strict";
+ receiver = this;
+ this.sum = x + y;
+}
+
+function ReturnThis(x, y) {
+ "use strict";
+ receiver = this;
+ this.sum = x + y;
+ return this;
+}
+
+function ReturnNew(x, y) {
+ "use strict";
+ receiver = this;
+ return {sum: x + y};
}
-function ReturnUndef(x, y) { "use strict"; receiver = this; this.sum = x + y }
-function ReturnThis(x, y) { "use strict"; receiver = this; this.sum = x + y; return this }
-function ReturnNew(x, y) { "use strict"; receiver = this; return {sum: x + y} }
function ReturnNewWithProto(x, y) {
"use strict";
receiver = this;
- var result = Object.create(prototype)
- result.sum = x + y
- return result
+ var result = Object.create(prototype);
+ result.sum = x + y;
+ return result;
}
function TestConstruct(proto, constructTrap) {
@@ -165,15 +282,13 @@ function TestConstruct(proto, constructTrap) {
function TestConstruct2(proto, constructTrap, handler) {
var f = Proxy.createFunction(handler, function() {}, constructTrap)
var o = new f(11, 31)
- // TODO(rossberg): doesn't hold, due to unrelated bug.
- // assertEquals(undefined, receiver)
+ assertEquals(undefined, receiver)
assertEquals(42, o.sum)
assertSame(proto, Object.getPrototypeOf(o))
var f = CreateFrozen(handler, function() {}, constructTrap)
var o = new f(11, 32)
- // TODO(rossberg): doesn't hold, due to unrelated bug.
- // assertEquals(undefined, receiver)
+ assertEquals(undefined, receiver)
assertEquals(43, o.sum)
assertSame(proto, Object.getPrototypeOf(o))
}
@@ -181,13 +296,16 @@ function TestConstruct2(proto, constructTrap, handler) {
TestConstruct(Object.prototype, ReturnNew)
TestConstruct(prototype, ReturnNewWithProto)
-TestConstruct(Object.prototype, Proxy.createFunction({}, ReturnNew))
-TestConstruct(prototype, Proxy.createFunction({}, ReturnNewWithProto))
+TestConstruct(Object.prototype, Proxy.createFunction(handler, ReturnNew))
+TestConstruct(prototype, Proxy.createFunction(handler, ReturnNewWithProto))
+
+TestConstruct(Object.prototype, CreateFrozen(handler, ReturnNew))
+TestConstruct(prototype, CreateFrozen(handler, ReturnNewWithProto))
-TestConstruct(Object.prototype, CreateFrozen({}, ReturnNew))
-TestConstruct(prototype, CreateFrozen({}, ReturnNewWithProto))
+// Construction with derived construct trap.
+
function TestConstructFromCall(proto, returnsThis, callTrap) {
TestConstructFromCall2(proto, returnsThis, callTrap, handlerWithPrototype)
TestConstructFromCall2(proto, returnsThis, callTrap, handlerSansPrototype)
@@ -212,10 +330,14 @@ TestConstructFromCall(Object.prototype, true, ReturnThis)
TestConstructFromCall(Object.prototype, false, ReturnNew)
TestConstructFromCall(prototype, false, ReturnNewWithProto)
-TestConstructFromCall(Object.prototype, true, Proxy.createFunction({}, ReturnUndef))
-TestConstructFromCall(Object.prototype, true, Proxy.createFunction({}, ReturnThis))
-TestConstructFromCall(Object.prototype, false, Proxy.createFunction({}, ReturnNew))
-TestConstructFromCall(prototype, false, Proxy.createFunction({}, ReturnNewWithProto))
+TestConstructFromCall(Object.prototype, true,
+ Proxy.createFunction(handler, ReturnUndef))
+TestConstructFromCall(Object.prototype, true,
+ Proxy.createFunction(handler, ReturnThis))
+TestConstructFromCall(Object.prototype, false,
+ Proxy.createFunction(handler, ReturnNew))
+TestConstructFromCall(prototype, false,
+ Proxy.createFunction(handler, ReturnNewWithProto))
TestConstructFromCall(Object.prototype, true, CreateFrozen({}, ReturnUndef))
TestConstructFromCall(Object.prototype, true, CreateFrozen({}, ReturnThis))
@@ -232,26 +354,44 @@ TestConstructFromCall(prototype, true, ReturnThis)
TestConstructFromCall(Object.prototype, false, ReturnNew)
TestConstructFromCall(prototype, false, ReturnNewWithProto)
-TestConstructFromCall(Object.prototype, true, Proxy.createFunction({}, ReturnUndef))
-TestConstructFromCall(Object.prototype, true, Proxy.createFunction({}, ReturnThis))
-TestConstructFromCall(Object.prototype, false, Proxy.createFunction({}, ReturnNew))
-TestConstructFromCall(prototype, false, Proxy.createFunction({}, ReturnNewWithProto))
-
-TestConstructFromCall(prototype, true, Proxy.createFunction(handlerWithPrototype, ReturnUndef))
-TestConstructFromCall(prototype, true, Proxy.createFunction(handlerWithPrototype, ReturnThis))
-TestConstructFromCall(Object.prototype, false, Proxy.createFunction(handlerWithPrototype, ReturnNew))
-TestConstructFromCall(prototype, false, Proxy.createFunction(handlerWithPrototype, ReturnNewWithProto))
-
-TestConstructFromCall(prototype, true, CreateFrozen(handlerWithPrototype, ReturnUndef))
-TestConstructFromCall(prototype, true, CreateFrozen(handlerWithPrototype, ReturnThis))
-TestConstructFromCall(Object.prototype, false, CreateFrozen(handlerWithPrototype, ReturnNew))
-TestConstructFromCall(prototype, false, CreateFrozen(handlerWithPrototype, ReturnNewWithProto))
-
+TestConstructFromCall(Object.prototype, true,
+ Proxy.createFunction(handler, ReturnUndef))
+TestConstructFromCall(Object.prototype, true,
+ Proxy.createFunction(handler, ReturnThis))
+TestConstructFromCall(Object.prototype, false,
+ Proxy.createFunction(handler, ReturnNew))
+TestConstructFromCall(prototype, false,
+ Proxy.createFunction(handler, ReturnNewWithProto))
+
+TestConstructFromCall(prototype, true,
+ Proxy.createFunction(handlerWithPrototype, ReturnUndef))
+TestConstructFromCall(prototype, true,
+ Proxy.createFunction(handlerWithPrototype, ReturnThis))
+TestConstructFromCall(Object.prototype, false,
+ Proxy.createFunction(handlerWithPrototype, ReturnNew))
+TestConstructFromCall(prototype, false,
+ Proxy.createFunction(handlerWithPrototype,
+ ReturnNewWithProto))
+
+TestConstructFromCall(prototype, true,
+ CreateFrozen(handlerWithPrototype, ReturnUndef))
+TestConstructFromCall(prototype, true,
+ CreateFrozen(handlerWithPrototype, ReturnThis))
+TestConstructFromCall(Object.prototype, false,
+ CreateFrozen(handlerWithPrototype, ReturnNew))
+TestConstructFromCall(prototype, false,
+ CreateFrozen(handlerWithPrototype, ReturnNewWithProto))
+
+
+
+// Throwing from the construct trap.
function TestConstructThrow(trap) {
- TestConstructThrow2(Proxy.createFunction({fix: function() {return {}}}, trap))
- TestConstructThrow2(Proxy.createFunction({fix: function() {return {}}},
- function() {}, trap))
+ TestConstructThrow2(Proxy.createFunction({ fix: function() {return {};} },
+ trap))
+ TestConstructThrow2(Proxy.createFunction({ fix: function() {return {};} },
+ function() {},
+ trap))
}
function TestConstructThrow2(f) {
@@ -266,13 +406,13 @@ TestConstructThrow(CreateFrozen({}, function() { throw "myexn" }))
-// Getters and setters.
+// Using function proxies as getters and setters.
var value
var receiver
function TestAccessorCall(getterCallTrap, setterCallTrap) {
- var handler = {fix: function() { return {} }}
+ var handler = { fix: function() { return {} } }
var pgetter = Proxy.createFunction(handler, getterCallTrap)
var psetter = Proxy.createFunction(handler, setterCallTrap)
diff --git a/deps/v8/test/mjsunit/harmony/proxies-hash.js b/deps/v8/test/mjsunit/harmony/proxies-hash.js
index 2bf1830134..abfc0f5f0e 100644
--- a/deps/v8/test/mjsunit/harmony/proxies-hash.js
+++ b/deps/v8/test/mjsunit/harmony/proxies-hash.js
@@ -25,42 +25,98 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Flags: --harmony-proxies --harmony-weakmaps
+// Flags: --harmony-proxies --harmony-collections
// Helper.
-function TestWithProxies(test, handler) {
- test(handler, Proxy.create)
- test(handler, function(h) {return Proxy.createFunction(h, function() {})})
+function TestWithProxies(test, construct, handler) {
+ test(construct, handler, Proxy.create)
+ test(construct, handler, function(h) {
+ return Proxy.createFunction(h, function() {})
+ })
}
-// Weak maps.
+// Sets.
-function TestWeakMap(fix) {
- TestWithProxies(TestWeakMap2, fix)
+function TestSet(construct, fix) {
+ TestWithProxies(TestSet2, construct, fix)
}
-function TestWeakMap2(fix, create) {
+function TestSet2(construct, fix, create) {
var handler = {fix: function() { return {} }}
var p1 = create(handler)
var p2 = create(handler)
var p3 = create(handler)
fix(p3)
- var m = new WeakMap
+ var s = construct();
+ s.add(p1);
+ s.add(p2);
+ assertTrue(s.has(p1));
+ assertTrue(s.has(p2));
+ assertFalse(s.has(p3));
+
+ fix(p1)
+ fix(p2)
+ assertTrue(s.has(p1));
+ assertTrue(s.has(p2));
+ assertFalse(s.has(p3));
+
+ s.delete(p2);
+ assertTrue(s.has(p1));
+ assertFalse(s.has(p2));
+ assertFalse(s.has(p3));
+}
+
+TestSet(Set, Object.seal)
+TestSet(Set, Object.freeze)
+TestSet(Set, Object.preventExtensions)
+
+
+// Maps and weak maps.
+
+function TestMap(construct, fix) {
+ TestWithProxies(TestMap2, construct, fix)
+}
+
+function TestMap2(construct, fix, create) {
+ var handler = {fix: function() { return {} }}
+ var p1 = create(handler)
+ var p2 = create(handler)
+ var p3 = create(handler)
+ fix(p3)
+
+ var m = construct();
m.set(p1, 123);
m.set(p2, 321);
+ assertTrue(m.has(p1));
+ assertTrue(m.has(p2));
+ assertFalse(m.has(p3));
assertSame(123, m.get(p1));
assertSame(321, m.get(p2));
fix(p1)
fix(p2)
+ assertTrue(m.has(p1));
+ assertTrue(m.has(p2));
+ assertFalse(m.has(p3));
assertSame(123, m.get(p1));
assertSame(321, m.get(p2));
+
+ m.delete(p2);
+ assertTrue(m.has(p1));
+ assertFalse(m.has(p2));
+ assertFalse(m.has(p3));
+ assertSame(123, m.get(p1));
+ assertSame(undefined, m.get(p2));
}
-TestWeakMap(Object.seal)
-TestWeakMap(Object.freeze)
-TestWeakMap(Object.preventExtensions)
+TestMap(Map, Object.seal)
+TestMap(Map, Object.freeze)
+TestMap(Map, Object.preventExtensions)
+
+TestMap(WeakMap, Object.seal)
+TestMap(WeakMap, Object.freeze)
+TestMap(WeakMap, Object.preventExtensions)
diff --git a/deps/v8/test/mjsunit/harmony/proxies.js b/deps/v8/test/mjsunit/harmony/proxies.js
index ad8d86a5dd..1ce7a32d8e 100644
--- a/deps/v8/test/mjsunit/harmony/proxies.js
+++ b/deps/v8/test/mjsunit/harmony/proxies.js
@@ -28,9 +28,6 @@
// Flags: --harmony-proxies
-// TODO(rossberg): for-in not implemented on proxies.
-
-
// Helper.
function TestWithProxies(test, x, y, z) {
@@ -138,6 +135,10 @@ function TestGet2(create, handler) {
assertEquals("b", key)
assertEquals(42, p[99])
assertEquals("99", key)
+ assertEquals(42, (function(n) { return p[n] })("c"))
+ assertEquals("c", key)
+ assertEquals(42, (function(n) { return p[n] })(101))
+ assertEquals("101", key)
var o = Object.create(p, {x: {value: 88}})
assertEquals(42, o.a)
@@ -148,6 +149,11 @@ function TestGet2(create, handler) {
assertEquals("99", key)
assertEquals(88, o.x)
assertEquals(88, o["x"])
+ assertEquals(42, (function(n) { return o[n] })("c"))
+ assertEquals("c", key)
+ assertEquals(42, (function(n) { return o[n] })(101))
+ assertEquals("101", key)
+ assertEquals(88, (function(n) { return o[n] })("x"))
}
TestGet({
@@ -201,6 +207,10 @@ function TestGetCall2(create, handler) {
assertEquals(55, p[101].call(p))
assertEquals(55, p.withargs(45, 5))
assertEquals(55, p.withargs.call(p, 11, 22))
+ assertEquals(55, (function(n) { return p[n]() })("f"))
+ assertEquals(55, (function(n) { return p[n].call(p) })("f"))
+ assertEquals(55, (function(n) { return p[n](15, 20) })("withargs"))
+ assertEquals(55, (function(n) { return p[n].call(p, 13, 21) })("withargs"))
assertEquals("6655", "66" + p) // calls p.toString
var o = Object.create(p, {g: {value: function(x) { return x + 88 }}})
@@ -216,6 +226,13 @@ function TestGetCall2(create, handler) {
assertEquals(90, o.g(2))
assertEquals(91, o.g.call(o, 3))
assertEquals(92, o.g.call(p, 4))
+ assertEquals(55, (function(n) { return o[n]() })("f"))
+ assertEquals(55, (function(n) { return o[n].call(o) })("f"))
+ assertEquals(55, (function(n) { return o[n](15, 20) })("withargs"))
+ assertEquals(55, (function(n) { return o[n].call(o, 13, 21) })("withargs"))
+ assertEquals(93, (function(n) { return o[n](5) })("g"))
+ assertEquals(94, (function(n) { return o[n].call(o, 6) })("g"))
+ assertEquals(95, (function(n) { return o[n].call(p, 7) })("g"))
assertEquals("6655", "66" + o) // calls o.toString
}
@@ -282,14 +299,15 @@ function TestGetThrow2(create, handler) {
assertThrows(function(){ p.a }, "myexn")
assertThrows(function(){ p["b"] }, "myexn")
assertThrows(function(){ p[3] }, "myexn")
+ assertThrows(function(){ (function(n) { p[n] })("c") }, "myexn")
+ assertThrows(function(){ (function(n) { p[n] })(99) }, "myexn")
var o = Object.create(p, {x: {value: 88}, '4': {value: 89}})
assertThrows(function(){ o.a }, "myexn")
assertThrows(function(){ o["b"] }, "myexn")
assertThrows(function(){ o[3] }, "myexn")
- assertEquals(88, o.x)
- assertEquals(88, o["x"])
- assertEquals(89, o[4])
+ assertThrows(function(){ (function(n) { o[n] })("c") }, "myexn")
+ assertThrows(function(){ (function(n) { o[n] })(99) }, "myexn")
}
TestGetThrow({
@@ -353,6 +371,13 @@ function TestSet2(create, handler) {
assertEquals(44, p[77] = 44)
assertEquals("77", key)
assertEquals(44, val)
+
+ assertEquals(45, (function(n) { return p[n] = 45 })("c"))
+ assertEquals("c", key)
+ assertEquals(45, val)
+ assertEquals(46, (function(n) { return p[n] = 46 })(99))
+ assertEquals("99", key)
+ assertEquals(46, val)
}
TestSet({
@@ -434,6 +459,8 @@ function TestSetThrow2(create, handler) {
assertThrows(function(){ p.a = 42 }, "myexn")
assertThrows(function(){ p["b"] = 42 }, "myexn")
assertThrows(function(){ p[22] = 42 }, "myexn")
+ assertThrows(function(){ (function(n) { p[n] = 45 })("c") }, "myexn")
+ assertThrows(function(){ (function(n) { p[n] = 46 })(99) }, "myexn")
}
TestSetThrow({
@@ -719,17 +746,17 @@ function TestDefine2(create, handler) {
assertEquals("zzz", key)
assertEquals(0, Object.getOwnPropertyNames(desc).length)
-// TODO(rossberg): This test requires for-in on proxies.
-// var d = create({
-// get: function(r, k) { return (k === "value") ? 77 : void 0 },
-// getOwnPropertyNames: function() { return ["value"] }
-// })
-// assertEquals(1, Object.getOwnPropertyNames(d).length)
-// assertEquals(77, d.value)
-// assertEquals(p, Object.defineProperty(p, "p", d))
-// assertEquals("p", key)
-// assertEquals(1, Object.getOwnPropertyNames(desc).length)
-// assertEquals(77, desc.value)
+ var d = create({
+ get: function(r, k) { return (k === "value") ? 77 : void 0 },
+ getOwnPropertyNames: function() { return ["value"] },
+ enumerate: function() { return ["value"] }
+ })
+ assertEquals(1, Object.getOwnPropertyNames(d).length)
+ assertEquals(77, d.value)
+ assertEquals(p, Object.defineProperty(p, "p", d))
+ assertEquals("p", key)
+ assertEquals(1, Object.getOwnPropertyNames(desc).length)
+ assertEquals(77, desc.value)
var props = {
'11': {},
@@ -774,17 +801,16 @@ function TestDefineThrow2(create, handler) {
assertThrows(function(){ Object.defineProperty(p, "a", {value: 44})}, "myexn")
assertThrows(function(){ Object.defineProperty(p, 0, {value: 44})}, "myexn")
-// TODO(rossberg): These tests require for-in on proxies.
-// var d1 = create({
-// get: function(r, k) { throw "myexn" },
-// getOwnPropertyNames: function() { return ["value"] }
-// })
-// assertThrows(function(){ Object.defineProperty(p, "p", d1) }, "myexn")
-// var d2 = create({
-// get: function(r, k) { return 77 },
-// getOwnPropertyNames: function() { throw "myexn" }
-// })
-// assertThrows(function(){ Object.defineProperty(p, "p", d2) }, "myexn")
+ var d1 = create({
+ get: function(r, k) { throw "myexn" },
+ getOwnPropertyNames: function() { return ["value"] }
+ })
+ assertThrows(function(){ Object.defineProperty(p, "p", d1) }, "myexn")
+ var d2 = create({
+ get: function(r, k) { return 77 },
+ getOwnPropertyNames: function() { throw "myexn" }
+ })
+ assertThrows(function(){ Object.defineProperty(p, "p", d2) }, "myexn")
var props = {bla: {get value() { throw "otherexn" }}}
assertThrows(function(){ Object.defineProperties(p, props) }, "otherexn")
@@ -1468,7 +1494,7 @@ function TestPrototype() {
var p1 = Proxy.create({})
var p2 = Proxy.create({}, o1)
var p3 = Proxy.create({}, p2)
- var p4 = Proxy.create({}, 666)
+ var p4 = Proxy.create({}, null)
var o2 = Object.create(p3)
assertSame(Object.getPrototypeOf(o1), Object.prototype)
@@ -1606,7 +1632,9 @@ TestKeys(["[object Object]"], {
TestKeys(["a", "0"], {
getOwnPropertyNames: function() { return ["a", 23, "zz", "", 0] },
- getOwnPropertyDescriptor: function(k) { return {enumerable: k.length == 1} }
+ getOwnPropertyDescriptor: function(k) {
+ return k == "" ? undefined : {enumerable: k.length == 1}
+ }
})
TestKeys(["23", "zz", ""], {
@@ -1620,10 +1648,12 @@ TestKeys(["23", "zz", ""], {
TestKeys(["a", "b", "c", "5"], {
get getOwnPropertyNames() {
- return function() { return ["0", 4, "a", "b", "c", 5] }
+ return function() { return ["0", 4, "a", "b", "c", 5, "ety"] }
},
get getOwnPropertyDescriptor() {
- return function(k) { return {enumerable: k >= "44"} }
+ return function(k) {
+ return k == "ety" ? undefined : {enumerable: k >= "44"}
+ }
}
})
diff --git a/deps/v8/test/mjsunit/harmony/weakmaps.js b/deps/v8/test/mjsunit/harmony/weakmaps.js
deleted file mode 100644
index 7b5dcaf0c1..0000000000
--- a/deps/v8/test/mjsunit/harmony/weakmaps.js
+++ /dev/null
@@ -1,167 +0,0 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Flags: --harmony-weakmaps --expose-gc
-
-
-// Test valid getter and setter calls
-var m = new WeakMap;
-assertDoesNotThrow(function () { m.get(new Object) });
-assertDoesNotThrow(function () { m.set(new Object) });
-assertDoesNotThrow(function () { m.has(new Object) });
-assertDoesNotThrow(function () { m.delete(new Object) });
-
-
-// Test invalid getter and setter calls
-var m = new WeakMap;
-assertThrows(function () { m.get(undefined) }, TypeError);
-assertThrows(function () { m.set(undefined, 0) }, TypeError);
-assertThrows(function () { m.get(0) }, TypeError);
-assertThrows(function () { m.set(0, 0) }, TypeError);
-assertThrows(function () { m.get('a-key') }, TypeError);
-assertThrows(function () { m.set('a-key', 0) }, TypeError);
-
-
-// Test expected mapping behavior
-var m = new WeakMap;
-function TestMapping(map, key, value) {
- map.set(key, value);
- assertSame(value, map.get(key));
-}
-TestMapping(m, new Object, 23);
-TestMapping(m, new Object, 'the-value');
-TestMapping(m, new Object, new Object);
-
-
-// Test expected querying behavior
-var m = new WeakMap;
-var key = new Object;
-TestMapping(m, key, 'to-be-present');
-assertTrue(m.has(key));
-assertFalse(m.has(new Object));
-TestMapping(m, key, undefined);
-assertFalse(m.has(key));
-assertFalse(m.has(new Object));
-
-
-// Test expected deletion behavior
-var m = new WeakMap;
-var key = new Object;
-TestMapping(m, key, 'to-be-deleted');
-assertTrue(m.delete(key));
-assertFalse(m.delete(key));
-assertFalse(m.delete(new Object));
-assertSame(m.get(key), undefined);
-
-
-// Test GC of map with entry
-var m = new WeakMap;
-var key = new Object;
-m.set(key, 'not-collected');
-gc();
-assertSame('not-collected', m.get(key));
-
-
-// Test GC of map with chained entries
-var m = new WeakMap;
-var head = new Object;
-for (key = head, i = 0; i < 10; i++, key = m.get(key)) {
- m.set(key, new Object);
-}
-gc();
-var count = 0;
-for (key = head; key != undefined; key = m.get(key)) {
- count++;
-}
-assertEquals(11, count);
-
-
-// Test property attribute [[Enumerable]]
-var m = new WeakMap;
-function props(x) {
- var array = [];
- for (var p in x) array.push(p);
- return array.sort();
-}
-assertArrayEquals([], props(WeakMap));
-assertArrayEquals([], props(WeakMap.prototype));
-assertArrayEquals([], props(m));
-
-
-// Test arbitrary properties on weak maps
-var m = new WeakMap;
-function TestProperty(map, property, value) {
- map[property] = value;
- assertEquals(value, map[property]);
-}
-for (i = 0; i < 20; i++) {
- TestProperty(m, i, 'val' + i);
- TestProperty(m, 'foo' + i, 'bar' + i);
-}
-TestMapping(m, new Object, 'foobar');
-
-
-// Test direct constructor call
-var m = WeakMap();
-assertTrue(m instanceof WeakMap);
-
-
-// Test some common JavaScript idioms
-var m = new WeakMap;
-assertTrue(m instanceof WeakMap);
-assertTrue(WeakMap.prototype.set instanceof Function)
-assertTrue(WeakMap.prototype.get instanceof Function)
-assertTrue(WeakMap.prototype.has instanceof Function)
-assertTrue(WeakMap.prototype.delete instanceof Function)
-
-
-// Regression test for WeakMap prototype.
-assertTrue(WeakMap.prototype.constructor === WeakMap)
-assertTrue(Object.getPrototypeOf(WeakMap.prototype) === Object.prototype)
-
-
-// Regression test for issue 1617: The prototype of the WeakMap constructor
-// needs to be unique (i.e. different from the one of the Object constructor).
-assertFalse(WeakMap.prototype === Object.prototype);
-var o = Object.create({});
-assertFalse("get" in o);
-assertFalse("set" in o);
-assertEquals(undefined, o.get);
-assertEquals(undefined, o.set);
-var o = Object.create({}, { myValue: {
- value: 10,
- enumerable: false,
- configurable: true,
- writable: true
-}});
-assertEquals(10, o.myValue);
-
-
-// Stress Test
-// There is a proposed stress-test available at the es-discuss mailing list
-// which cannot be reasonably automated. Check it out by hand if you like:
-// https://mail.mozilla.org/pipermail/es-discuss/2011-May/014096.html
diff --git a/deps/v8/test/mjsunit/mjsunit.status b/deps/v8/test/mjsunit/mjsunit.status
index 941e0e8cc5..8a1b68bfb2 100644
--- a/deps/v8/test/mjsunit/mjsunit.status
+++ b/deps/v8/test/mjsunit/mjsunit.status
@@ -65,6 +65,20 @@ regress/regress-524: (PASS || TIMEOUT), SKIP if $mode == debug
debug-liveedit-check-stack: SKIP
debug-liveedit-patch-positions-replace: SKIP
+# Liveedit messes with the frame hights - see bug 1791
+debug-liveedit-1: SKIP
+debug-liveedit-2: SKIP
+debug-liveedit-3: SKIP
+debug-liveedit-breakpoints: SKIP
+debug-liveedit-check-stack: SKIP
+debug-liveedit-diff: SKIP
+debug-liveedit-newsource: SKIP
+debug-liveedit-patch-positions: SKIP
+debug-liveedit-patch-positions-replace: SKIP
+debug-liveedit-utils: SKIP
+
+
+
##############################################################################
[ $arch == arm ]
diff --git a/deps/v8/test/mjsunit/object-define-properties.js b/deps/v8/test/mjsunit/object-define-properties.js
index 128df694d3..6d5032e044 100644
--- a/deps/v8/test/mjsunit/object-define-properties.js
+++ b/deps/v8/test/mjsunit/object-define-properties.js
@@ -54,3 +54,19 @@ var x = Object.defineProperties(obj, desc);
assertEquals(x.foo, 10);
assertEquals(x.bar, 42);
+
+
+// Make sure that all property descriptors are calculated before any
+// modifications are done.
+
+var object = {};
+
+assertThrows(function() {
+ Object.defineProperties(object, {
+ foo: { value: 1 },
+ bar: { value: 2, get: function() { return 3; } }
+ });
+ }, TypeError);
+
+assertEquals(undefined, object.foo);
+assertEquals(undefined, object.bar);
diff --git a/deps/v8/test/mjsunit/optimized-typeof.js b/deps/v8/test/mjsunit/optimized-typeof.js
new file mode 100644
index 0000000000..b0c0725c51
--- /dev/null
+++ b/deps/v8/test/mjsunit/optimized-typeof.js
@@ -0,0 +1,47 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax
+
+function typeofDirectly() {
+ return typeof({}) === "undefined";
+}
+
+typeofDirectly();
+typeofDirectly();
+%OptimizeFunctionOnNextCall(typeofDirectly);
+typeofDirectly();
+
+function typeofViaVariable() {
+ var foo = typeof({})
+ return foo === "undefined";
+}
+
+typeofViaVariable();
+typeofViaVariable();
+%OptimizeFunctionOnNextCall(typeofViaVariable);
+typeofViaVariable();
diff --git a/deps/v8/test/mjsunit/regexp-static.js b/deps/v8/test/mjsunit/regexp-static.js
index 0f849687cc..8f283f6cee 100644
--- a/deps/v8/test/mjsunit/regexp-static.js
+++ b/deps/v8/test/mjsunit/regexp-static.js
@@ -25,18 +25,6 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Test that we throw exceptions when calling test and exec with no
-// input. This is not part of the spec, but we do it for
-// compatibility with JSC.
-assertThrows("/a/.test()");
-assertThrows("/a/.exec()");
-
-// Test that we do not throw exceptions once the static RegExp.input
-// field has been set.
-RegExp.input = "a";
-assertDoesNotThrow("/a/.test()");
-assertDoesNotThrow("/a/.exec()");
-
// Test the (deprecated as of JS 1.5) properties of the RegExp function.
var re = /((\d+)\.(\d+))/;
var s = 'abc123.456def';
@@ -166,3 +154,8 @@ assertTrue(typeof RegExp.input == typeof String(), "RegExp.input coerces values
var foo = "lsdfj sldkfj sdklfj læsdfjl sdkfjlsdk fjsdl fjsdljskdj flsj flsdkj flskd regexp: /foobar/\nldkfj sdlkfj sdkl";
assertTrue(/^([a-z]+): (.*)/.test(foo.substring(foo.indexOf("regexp:"))), "regexp: setup");
assertEquals("regexp", RegExp.$1, "RegExp.$1");
+
+
+// Check that calling with no argument is the same as calling with undefined.
+assertTrue(/^undefined$/.test());
+assertEquals(["undefined"], /^undefined$/.exec());
diff --git a/deps/v8/test/mjsunit/regress/regress-100409.js b/deps/v8/test/mjsunit/regress/regress-100409.js
new file mode 100644
index 0000000000..c29250f28d
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-100409.js
@@ -0,0 +1,55 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax
+
+function outer () {
+ var val = 0;
+
+ function foo () {
+ val = 0;
+ val;
+ var z = false;
+ var y = true;
+ if (!z) {
+ while (z = !z) {
+ if (y) val++;
+ }
+ }
+ return val++;
+ }
+
+ return foo;
+}
+
+
+var foo = outer();
+
+assertEquals(1, foo());
+assertEquals(1, foo());
+ %OptimizeFunctionOnNextCall(foo);
+assertEquals(1, foo());
diff --git a/deps/v8/test/mjsunit/regress/regress-100702.js b/deps/v8/test/mjsunit/regress/regress-100702.js
new file mode 100644
index 0000000000..46494ab71d
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-100702.js
@@ -0,0 +1,44 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Regression test for correct handling of non-object receiver values
+// passed to built-in array functions.
+
+String.prototype.isThatMe = function () {
+ assertFalse(this === str);
+};
+
+var str = "abc";
+str.isThatMe();
+str.isThatMe.call(str);
+
+var arr = [1];
+arr.forEach("".isThatMe, str);
+arr.filter("".isThatMe, str);
+arr.some("".isThatMe, str);
+arr.every("".isThatMe, str);
+arr.map("".isThatMe, str);
diff --git a/deps/v8/test/mjsunit/regress/regress-1229.js b/deps/v8/test/mjsunit/regress/regress-1229.js
index e16d278b38..c0dcba912a 100644
--- a/deps/v8/test/mjsunit/regress/regress-1229.js
+++ b/deps/v8/test/mjsunit/regress/regress-1229.js
@@ -35,10 +35,10 @@ function foo(x, y, z) {
assertEquals(3, z);
}
-var bound_arg = [1];
+var foob = foo.bind({}, 1);
function f(y, z) {
- return %NewObjectFromBound(foo, bound_arg);
+ return %NewObjectFromBound(foob);
}
// Check that %NewObjectFromBound looks at correct frame for inlined function.
diff --git a/deps/v8/test/mjsunit/regress/regress-1521.js b/deps/v8/test/mjsunit/regress/regress-1521.js
index 415db67803..3149f05a5e 100644
--- a/deps/v8/test/mjsunit/regress/regress-1521.js
+++ b/deps/v8/test/mjsunit/regress/regress-1521.js
@@ -24,6 +24,8 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Flags: --allow-natives-syntax
// Optimized variable access inside through a catch context should work.
function test(x) {
@@ -44,4 +46,3 @@ function test(x) {
}
test(3);
-
diff --git a/deps/v8/test/mjsunit/stack-traces-2.js b/deps/v8/test/mjsunit/stack-traces-2.js
new file mode 100644
index 0000000000..165c4dfcec
--- /dev/null
+++ b/deps/v8/test/mjsunit/stack-traces-2.js
@@ -0,0 +1,87 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --builtins-in-stack-traces
+
+
+// Poisonous object that throws a reference error if attempted converted to
+// a primitive values.
+var thrower = { valueOf: function() { FAIL; },
+ toString: function() { FAIL; } };
+
+// Tests that a native constructor function is included in the
+// stack trace.
+function testTraceNativeConstructor(nativeFunc) {
+ var nativeFuncName = nativeFunc.name;
+ try {
+ new nativeFunc(thrower);
+ assertUnreachable(nativeFuncName);
+ } catch (e) {
+ assertTrue(e.stack.indexOf(nativeFuncName) >= 0, nativeFuncName);
+ }
+}
+
+// Tests that a native conversion function is included in the
+// stack trace.
+function testTraceNativeConversion(nativeFunc) {
+ var nativeFuncName = nativeFunc.name;
+ try {
+ nativeFunc(thrower);
+ assertUnreachable(nativeFuncName);
+ } catch (e) {
+ assertTrue(e.stack.indexOf(nativeFuncName) >= 0, nativeFuncName);
+ }
+}
+
+
+function testNotOmittedBuiltin(throwing, included) {
+ try {
+ throwing();
+ assertUnreachable(included);
+ } catch (e) {
+ assertTrue(e.stack.indexOf(included) >= 0, included);
+ }
+}
+
+
+testTraceNativeConversion(String); // Does ToString on argument.
+testTraceNativeConversion(Number); // Does ToNumber on argument.
+testTraceNativeConversion(RegExp); // Does ToString on argument.
+
+testTraceNativeConstructor(String); // Does ToString on argument.
+testTraceNativeConstructor(Number); // Does ToNumber on argument.
+testTraceNativeConstructor(RegExp); // Does ToString on argument.
+testTraceNativeConstructor(Date); // Does ToNumber on argument.
+
+// QuickSort has builtins object as receiver, and is non-native
+// builtin. Should not be omitted with the --builtins-in-stack-traces flag.
+testNotOmittedBuiltin(function(){ [thrower, 2].sort(function (a,b) {
+ (b < a) - (a < b); });
+ }, "QuickSort");
+
+// Not omitted even though ADD from runtime.js is a non-native builtin.
+testNotOmittedBuiltin(function(){ thrower + 2; }, "ADD"); \ No newline at end of file
diff --git a/deps/v8/test/mjsunit/stack-traces.js b/deps/v8/test/mjsunit/stack-traces.js
index 47a5cc594a..536e71bbb5 100644
--- a/deps/v8/test/mjsunit/stack-traces.js
+++ b/deps/v8/test/mjsunit/stack-traces.js
@@ -194,6 +194,46 @@ function testErrorsDuringFormatting() {
}
+// Poisonous object that throws a reference error if attempted converted to
+// a primitive values.
+var thrower = { valueOf: function() { FAIL; },
+ toString: function() { FAIL; } };
+
+// Tests that a native constructor function is included in the
+// stack trace.
+function testTraceNativeConstructor(nativeFunc) {
+ var nativeFuncName = nativeFunc.name;
+ try {
+ new nativeFunc(thrower);
+ assertUnreachable(nativeFuncName);
+ } catch (e) {
+ assertTrue(e.stack.indexOf(nativeFuncName) >= 0, nativeFuncName);
+ }
+}
+
+// Tests that a native conversion function is included in the
+// stack trace.
+function testTraceNativeConversion(nativeFunc) {
+ var nativeFuncName = nativeFunc.name;
+ try {
+ nativeFunc(thrower);
+ assertUnreachable(nativeFuncName);
+ } catch (e) {
+ assertTrue(e.stack.indexOf(nativeFuncName) >= 0, nativeFuncName);
+ }
+}
+
+
+function testOmittedBuiltin(throwing, omitted) {
+ try {
+ throwing();
+ assertUnreachable(omitted);
+ } catch (e) {
+ assertTrue(e.stack.indexOf(omitted) < 0, omitted);
+ }
+}
+
+
testTrace("testArrayNative", testArrayNative, ["Array.map (native)"]);
testTrace("testNested", testNested, ["at one", "at two", "at three"]);
testTrace("testMethodNameInference", testMethodNameInference, ["at Foo.bar"]);
@@ -217,3 +257,21 @@ testTrace("testStrippedCustomError", testStrippedCustomError, ["hep-hey"],
testCallerCensorship();
testUnintendedCallerCensorship();
testErrorsDuringFormatting();
+
+testTraceNativeConversion(String); // Does ToString on argument.
+testTraceNativeConversion(Number); // Does ToNumber on argument.
+testTraceNativeConversion(RegExp); // Does ToString on argument.
+
+testTraceNativeConstructor(String); // Does ToString on argument.
+testTraceNativeConstructor(Number); // Does ToNumber on argument.
+testTraceNativeConstructor(RegExp); // Does ToString on argument.
+testTraceNativeConstructor(Date); // Does ToNumber on argument.
+
+// Omitted because QuickSort has builtins object as receiver, and is non-native
+// builtin.
+testOmittedBuiltin(function(){ [thrower, 2].sort(function (a,b) {
+ (b < a) - (a < b); });
+ }, "QuickSort");
+
+// Omitted because ADD from runtime.js is non-native builtin.
+testOmittedBuiltin(function(){ thrower + 2; }, "ADD"); \ No newline at end of file
diff --git a/deps/v8/test/mjsunit/strict-mode.js b/deps/v8/test/mjsunit/strict-mode.js
index 30234ba6fa..9c9bdfd52d 100644
--- a/deps/v8/test/mjsunit/strict-mode.js
+++ b/deps/v8/test/mjsunit/strict-mode.js
@@ -1051,14 +1051,20 @@ function CheckPillDescriptor(func, name) {
}
assertThrows(function() { strict.caller; }, TypeError);
assertThrows(function() { strict.arguments; }, TypeError);
+ assertThrows(function() { strict.caller = 42; }, TypeError);
+ assertThrows(function() { strict.arguments = 42; }, TypeError);
var another = new Function("'use strict'");
assertThrows(function() { another.caller; }, TypeError);
assertThrows(function() { another.arguments; }, TypeError);
+ assertThrows(function() { another.caller = 42; }, TypeError);
+ assertThrows(function() { another.arguments = 42; }, TypeError);
var third = (function() { "use strict"; return function() {}; })();
assertThrows(function() { third.caller; }, TypeError);
assertThrows(function() { third.arguments; }, TypeError);
+ assertThrows(function() { third.caller = 42; }, TypeError);
+ assertThrows(function() { third.arguments = 42; }, TypeError);
CheckPillDescriptor(strict, "caller");
CheckPillDescriptor(strict, "arguments");
diff --git a/deps/v8/test/mjsunit/to_number_order.js b/deps/v8/test/mjsunit/to_number_order.js
index d17e600050..50e4bc762e 100644
--- a/deps/v8/test/mjsunit/to_number_order.js
+++ b/deps/v8/test/mjsunit/to_number_order.js
@@ -161,7 +161,7 @@ assertEquals("fiskfisk", x, "Compare objects b >= b valueOf order");
x = "";
assertFalse(a > b, "Compare objects a > b");
-assertEquals("fiskhest", x, "Compare objects a > b valueOf order");
+assertEquals("hestfisk", x, "Compare objects a > b valueOf order");
x = "";
assertFalse(a > void(0), "Compare objects a > undefined");
@@ -195,7 +195,7 @@ function identical_object_comparison() {
x = "";
assertFalse(a > b, "Compare objects a > b");
- assertEquals("fiskhest", x, "Compare objects a > b valueOf order");
+ assertEquals("hestfisk", x, "Compare objects a > b valueOf order");
x = "";
assertFalse(a > void(0), "Compare objects a > undefined");
diff --git a/deps/v8/test/mozilla/mozilla.status b/deps/v8/test/mozilla/mozilla.status
index 6a5c08640c..e31a630b8a 100644
--- a/deps/v8/test/mozilla/mozilla.status
+++ b/deps/v8/test/mozilla/mozilla.status
@@ -300,6 +300,11 @@ js1_2/regexp/RegExp_multiline_as_array: FAIL_OK
js1_2/regexp/beginLine: FAIL_OK
js1_2/regexp/endLine: FAIL_OK
+# We no longer let calls to test and exec with no argument implicitly
+# use the previous input.
+js1_2/regexp/RegExp_input: FAIL_OK
+js1_2/regexp/RegExp_input_as_array: FAIL_OK
+
# To be compatible with safari typeof a regexp yields 'function';
# in firefox it yields 'object'.
@@ -410,12 +415,6 @@ js1_5/extensions/regress-435345-01: FAIL_OK
js1_5/extensions/regress-455413: FAIL_OK
-# The spec specifies reverse evaluation order for < and >=.
-# See section 11.8.2 and 11.8.5.
-# We implement the spec here but the test tests the more straigtforward order.
-ecma_3/Operators/order-01: FAIL_OK
-
-
# Uses Mozilla-specific QName, XML, XMLList and Iterator.
js1_5/Regress/regress-407323: FAIL_OK
js1_5/Regress/regress-407957: FAIL_OK
diff --git a/deps/v8/test/sputnik/sputnik.status b/deps/v8/test/sputnik/sputnik.status
index 99db598af4..135540e7cf 100644
--- a/deps/v8/test/sputnik/sputnik.status
+++ b/deps/v8/test/sputnik/sputnik.status
@@ -30,10 +30,6 @@ def FAIL_OK = FAIL, OKAY
############################### BUGS ###################################
-# A bound function should fail on access to 'caller' and 'arguments'.
-S15.3.4.5_A1: FAIL
-S15.3.4.5_A2: FAIL
-
# '__proto__' should be treated as a normal property in JSON.
S15.12.2_A1: FAIL
@@ -46,12 +42,6 @@ S15.8.2.16_A7: PASS || FAIL_OK
S15.8.2.18_A7: PASS || FAIL_OK
S15.8.2.13_A23: PASS || FAIL_OK
-# We allow calls to regexp exec() with no arguments to fail for
-# compatibility reasons.
-S15.10.6.2_A1_T16: FAIL_OK
-S15.10.6.2_A12: FAIL_OK
-S15.10.6.3_A1_T16: FAIL_OK
-
# Sputnik tests (r97) assume RegExp.prototype is an Object, not a RegExp.
S15.10.6_A2: FAIL_OK
@@ -162,6 +152,10 @@ S11.1.5_A4.2: FAIL_OK
S9.9_A1: FAIL_OK
S9.9_A2: FAIL_OK
+# The expected evaluation order of comparison operations changed.
+S11.8.2_A2.3_T1: FAIL_OK
+S11.8.3_A2.3_T1: FAIL_OK
+
# Calls builtins without an explicit receiver which means that
# undefined is passed to the builtin. The tests expect the global
# object to be passed which was true in ES3 but not in ES5.
@@ -187,6 +181,10 @@ S15.1.1.2_A2_T1: FAIL_OK # Infinity
S15.1.1.3_A2_T1: FAIL_OK # undefined
S15.1.1.3_A2_T2: FAIL_OK # undefined
+# Function.prototype.apply can handle arbitrary object as argument list.
+S15.3.4.3_A6_T1: FAIL_OK
+S15.3.4.3_A6_T4: FAIL_OK
+
# Array.prototype.to[Locale]String is generic in ES5.
S15.4.4.2_A2_T1: FAIL_OK
S15.4.4.3_A2_T1: FAIL_OK
diff --git a/deps/v8/test/test262/test262.status b/deps/v8/test/test262/test262.status
index 1a619547d7..3eefbd7462 100644
--- a/deps/v8/test/test262/test262.status
+++ b/deps/v8/test/test262/test262.status
@@ -30,10 +30,6 @@ def FAIL_OK = FAIL, OKAY
############################### BUGS ###################################
-# A bound function should fail on access to 'caller' and 'arguments'.
-S15.3.4.5_A1: FAIL
-S15.3.4.5_A2: FAIL
-
# '__proto__' should be treated as a normal property in JSON.
S15.12.2_A1: FAIL
@@ -43,22 +39,6 @@ S8.7_A5_T2: FAIL
# V8 Bug: http://code.google.com/p/v8/issues/detail?id=1624
S10.4.2.1_A1: FAIL
-# V8 Bug: http://code.google.com/p/v8/issues/detail?id=1752
-S11.8.2_A2.3_T1: FAIL
-S11.8.3_A2.3_T1: FAIL
-11.8.2-1: FAIL
-11.8.2-2: FAIL
-11.8.2-3: FAIL
-11.8.2-4: FAIL
-11.8.3-1: FAIL
-11.8.3-2: FAIL
-11.8.3-3: FAIL
-11.8.3-4: FAIL
-11.8.3-5: FAIL
-
-# V8 Bug.
-S13.2.3_A1: FAIL
-
# V8 Bug: http://code.google.com/p/v8/issues/detail?id=1530
S15.3.3.1_A4: FAIL
@@ -165,12 +145,6 @@ S15.8.2.16_A7: PASS || FAIL_OK
S15.8.2.18_A7: PASS || FAIL_OK
S15.8.2.13_A23: PASS || FAIL_OK
-# We allow calls to regexp exec() with no arguments to fail for
-# compatibility reasons.
-S15.10.6.2_A1_T16: FAIL_OK
-S15.10.6.2_A12: FAIL_OK
-S15.10.6.3_A1_T16: FAIL_OK
-
# Sputnik tests (r97) assume RegExp.prototype is an Object, not a RegExp.
S15.10.6_A2: FAIL_OK
@@ -342,80 +316,6 @@ S15.4.4.3_A2_T1: FAIL_OK
######################### UNANALYZED FAILURES ##########################
-# Bug? Object.defineProperty - Update [[Enumerable]] attribute of 'name'
-# property to true successfully when [[Enumerable]] attribute of 'name'
-# is false and [[Configurable]] attribute of 'name' is true, the 'desc'
-# is a generic descriptor which only contains [[Enumerable]] attribute
-# as true, 'name' property is an index data property (8.12.9 step 8)
-15.2.3.6-4-82-18: FAIL
-# Bug? Object.defineProperty - Update [[Enumerable]] attribute of 'name'
-# property to false successfully when [[Enumerable]] and [[Configurable]]
-# attributes of 'name' property are true, the 'desc' is a generic
-# descriptor which only contains [Enumerable]] attribute as false and
-# 'name' property is an index accessor property (8.12.9 step 8)
-15.2.3.6-4-82-19: FAIL
-# Bug? Object.defineProperty - Update [[Enumerable]] attribute of 'name'
-# property to false successfully when [[Enumerable]] and [[Configurable]]
-# attributes of 'name' property are true, the 'desc' is a generic
-# descriptor which contains [Enumerable]] attribute as false and
-# [[Configurable]] property is true, 'name' property is an index accessor
-# property (8.12.9 step 8)
-15.2.3.6-4-82-20: FAIL
-# Bug? Object.defineProperty - Update [[Configurable]] attribute of 'name'
-# property to false successfully when [[Enumerable]] and [[Configurable]]
-# attributes of 'name' property are true, the 'desc' is a generic
-# descriptor which only contains [[Configurable]] attribute as false,
-# 'name' property is an index accessor property (8.12.9 step 8)
-15.2.3.6-4-82-21: FAIL
-# Bug? Object.defineProperty - Update [[Configurable]] attribute of 'name'
-# property to false successfully when [[Enumerable]] and [[Configurable]]
-# attributes of 'name' property are true, the 'desc' is a generic
-# descriptor which contains [[Enumerable]] attribute as true and
-# [[Configurable]] attribute is false, 'name' property is an index accessor
-# property (8.12.9 step 8)
-15.2.3.6-4-82-22: FAIL
-# Bug? Object.defineProperty - Update [[Enumerable]] and [[Configurable]]
-# attributes of 'name' property to false successfully when [[Enumerable]]
-# and [[Configurable]] attributes of 'name' property are true, the 'desc'
-# is a generic descriptor which contains [[Enumerable]] and
-# [[Configurable]] attributes as false, 'name' property is an index
-# accessor property (8.12.9 step 8)
-15.2.3.6-4-82-23: FAIL
-# Bug? Object.defineProperty - Update [[Enumerable]] attributes of 'name'
-# property to true successfully when [[Enumerable]] attribute of 'name' is
-# false and [[Configurable]] attribute of 'name' is true, the 'desc' is a
-# generic descriptor which only contains [[Enumerable]] attribute as true,
-# 'name' property is an index accessor property (8.12.9 step 8)
-15.2.3.6-4-82-24: FAIL
-# Bug? Object.defineProperty - 'O' is an Array, 'name' is an array index named
-# property, 'desc' is accessor descriptor, test updating all attribute
-# values of 'name' (15.4.5.1 step 4.c)
-15.2.3.6-4-209: FAIL
-# Bug? Object.defineProperty - 'O' is an Array, 'name' is an array index named
-# property, name is accessor property and 'desc' is accessor descriptor,
-# test updating the [[Enumerable]] attribute value of 'name' (15.4.5.1 step
-# 4.c)
-15.2.3.6-4-271: FAIL
-# Bug? Object.defineProperty - 'O' is an Array, 'name' is an array index named
-# property, name is accessor property and 'desc' is accessor descriptor,
-# test updating the [[Configurable]] attribute value of 'name' (15.4.5.1
-# step 4.c)
-15.2.3.6-4-272: FAIL
-# Bug? Object.defineProperty - 'O' is an Array, 'name' is an array index named
-# property, name is accessor property and 'desc' is accessor descriptor,
-# test updating multiple attribute values of 'name' (15.4.5.1 step 4.c)
-15.2.3.6-4-273: FAIL
-# Bug? Object.defineProperty - 'O' is an Arguments object of a function that has
-# formal parameters, 'name' is own accessor property of 'O' which is also
-# defined in [[ParameterMap]] of 'O', and 'desc' is accessor descriptor,
-# test updating multiple attribute values of 'name' (10.6
-# [[DefineOwnProperty]] step 3 and 5.a.i)
-15.2.3.6-4-291-1: FAIL
-# Bug? Object.defineProperty - 'O' is an Arguments object, 'name' is own
-# accessor property of 'O', and 'desc' is accessor descriptor, test
-# updating multiple attribute values of 'name' (10.6 [[DefineOwnProperty]]
-# step 3)
-15.2.3.6-4-291: FAIL
# Bug? Object.defineProperty - 'O' is an Arguments object of a function that has
# formal parameters, 'name' is own property of 'O' which is also defined in
# [[ParameterMap]] of 'O', and 'desc' is data descriptor, test updating
@@ -454,11 +354,6 @@ S15.4.4.3_A2_T1: FAIL_OK
# updating the [[Configurable]] attribute value of 'name' which is defined
# as non-configurable (10.6 [[DefineOwnProperty]] step 4 and step 5b)
15.2.3.6-4-296-1: FAIL
-# Bug? Object.defineProperty - 'O' is an Arguments object, 'name' is an index
-# named accessor property of 'O' but not defined in [[ParameterMap]] of
-# 'O', and 'desc' is accessor descriptor, test updating multiple attribute
-# values of 'name' (10.6 [[DefineOwnProperty]] step 3)
-15.2.3.6-4-303: FAIL
# Bug? ES5 Attributes - indexed property 'P' with attributes [[Writable]]: true,
# [[Enumerable]]: true, [[Configurable]]: false is writable using simple
# assignment, 'O' is an Arguments object
@@ -519,30 +414,6 @@ S15.4.4.3_A2_T1: FAIL_OK
15.2.3.6-4-623: FAIL
# Bug? ES5 Attributes - all attributes in Date.prototype.toJSON are correct
15.2.3.6-4-624: FAIL
-# Bug? Object.defineProperties - 'O' is an Array, 'P' is an array index named
-# property, 'desc' is accessor descriptor, test updating all attribute
-# values of 'P' (15.4.5.1 step 4.c)
-15.2.3.7-6-a-205: FAIL
-# Bug? Object.defineProperties - 'O' is an Array, 'P' is an array index named
-# property that already exists on 'O' is accessor property and 'desc' is
-# accessor descriptor, test updating the [[Enumerable]] attribute value of
-# 'P' (15.4.5.1 step 4.c)
-15.2.3.7-6-a-260: FAIL
-# Bug? Object.defineProperties - 'O' is an Array, 'P' is an array index named
-# property that already exists on 'O' is accessor property and 'desc' is
-# accessor descriptor, test updating the [[Configurable]] attribute value
-# of 'P' (15.4.5.1 step 4.c)
-15.2.3.7-6-a-261: FAIL
-# Bug? Object.defineProperties - 'O' is an Array, 'P' is an array index named
-# property that already exists on 'O' is accessor property and 'desc' is
-# accessor descriptor, test updating multiple attribute values of 'P'
-# (15.4.5.1 step 4.c)
-15.2.3.7-6-a-262: FAIL
-# Bug? Object.defineProperties - 'O' is an Arguments object, 'P' is own accessor
-# property of 'O' which is also defined in [[ParameterMap]] of 'O', and
-# 'desc' is accessor descriptor, test updating multiple attribute values of
-# 'P' (10.6 [[DefineOwnProperty]] step 3)
-15.2.3.7-6-a-280: FAIL
# Bug? Object.defineProperties - 'O' is an Arguments object, 'P' is own data
# property of 'O' which is also defined in [[ParameterMap]] of 'O', and
# 'desc' is data descriptor, test updating multiple attribute values of 'P'
@@ -571,32 +442,6 @@ S15.4.4.3_A2_T1: FAIL_OK
# 'P' which is defined as non-configurable (10.6 [[DefineOwnProperty]] step
# 4)
15.2.3.7-6-a-285: FAIL
-# Bug? Object.defineProperties - 'O' is an Arguments object, 'P' is an array
-# index named accessor property of 'O' but not defined in [[ParameterMap]]
-# of 'O', and 'desc' is accessor descriptor, test updating multiple
-# attribute values of 'P' (10.6 [[DefineOwnProperty]] step 3)
-15.2.3.7-6-a-292: FAIL
-# Bug? Strict Mode - 'this' value is a string which cannot be converted to
-# wrapper objects when the function is called with an array of arguments
-15.3.4.3-1-s: FAIL
-# Bug? Strict Mode - 'this' value is a number which cannot be converted to
-# wrapper objects when the function is called with an array of arguments
-15.3.4.3-2-s: FAIL
-# Bug? Strict Mode - 'this' value is a boolean which cannot be converted to
-# wrapper objects when the function is called with an array of arguments
-15.3.4.3-3-s: FAIL
-# Bug? Function.prototype.bind - [[Get]] attribute of 'caller' property in 'F'
-# is thrower
-15.3.4.5-20-2: FAIL
-# Bug? Function.prototype.bind - [[Set]] attribute of 'caller' property in 'F'
-# is thrower
-15.3.4.5-20-3: FAIL
-# Bug? Function.prototype.bind - [[Get]] attribute of 'arguments' property in
-# 'F' is thrower
-15.3.4.5-21-2: FAIL
-# Bug? Function.prototype.bind - [[Set]] attribute of 'arguments' property in
-# 'F' is thrower
-15.3.4.5-21-3: FAIL
# Bug? Array.prototype.indexOf - decreasing length of array does not delete
# non-configurable properties
15.4.4.14-9-a-19: FAIL
@@ -615,24 +460,9 @@ S15.4.4.3_A2_T1: FAIL_OK
# Bug? Array.prototype.map - decreasing length of array does not delete
# non-configurable properties
15.4.4.19-8-b-16: FAIL
-# Bug? Array.prototype.filter - properties can be added to prototype after
-# current position are visited on an Array-like object
-15.4.4.20-9-b-6: FAIL
# Bug? Array.prototype.filter - decreasing length of array does not delete
# non-configurable properties
15.4.4.20-9-b-16: FAIL
-# Bug? Array.prototype.filter - element to be retrieved is own data property
-# that overrides an inherited accessor property on an Array
-15.4.4.20-9-c-i-6: FAIL
-# Bug? Array.prototype.filter - element to be retrieved is own accessor property
-# that overrides an inherited accessor property on an Array
-15.4.4.20-9-c-i-14: FAIL
-# Bug? Array.prototype.filter - element to be retrieved is inherited accessor
-# property on an Array
-15.4.4.20-9-c-i-16: FAIL
-# Bug? Array.prototype.filter - element to be retrieved is inherited accessor
-# property without a get function on an Array
-15.4.4.20-9-c-i-22: FAIL
# Bug? Array.prototype.reduce - decreasing length of array in step 8 does not
# delete non-configurable properties
15.4.4.21-9-b-16: FAIL
@@ -666,9 +496,6 @@ S15.4.4.3_A2_T1: FAIL_OK
# Bug? Date.prototype.toISOString - value of year is Infinity
# Date.prototype.toISOString throw the RangeError
15.9.5.43-0-15: FAIL
-# Bug? Error.prototype.toString return the value of 'msg' when 'name' is empty
-# string and 'msg' isn't undefined
-15.11.4.4-8-1: FAIL
############################ SKIPPED TESTS #############################
diff --git a/deps/v8/tools/gyp/v8.gyp b/deps/v8/tools/gyp/v8.gyp
index 4812930072..34ad4c43be 100644
--- a/deps/v8/tools/gyp/v8.gyp
+++ b/deps/v8/tools/gyp/v8.gyp
@@ -709,7 +709,7 @@
'experimental_library_files': [
'../../src/macros.py',
'../../src/proxy.js',
- '../../src/weakmap.js',
+ '../../src/collection.js',
],
},
'actions': [