Version 3.12.15
Added PRESERVE_ASCII_NULL option to String::WriteAscii. (issue 2252)
Added dependency to HLoadKeyed* instructions to prevent invalid hoisting. (Chromium issue 137768)
Enabled building d8 for Android on Mac.
Interpret negative hexadecimal literals as NaN. (issue 2240)
Expose counters in javascript when using --track-gc-object-stats.
Enabled building and testing V8 on Android IA.
Added --trace-parse flag to parser.
Performance and stability improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@12180 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index 1dd4bb9..047929a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+2012-07-24: Version 3.12.15
+
+ Added PRESERVE_ASCII_NULL option to String::WriteAscii.
+ (issue 2252)
+
+ Added dependency to HLoadKeyed* instructions to prevent invalid
+ hoisting. (Chromium issue 137768)
+
+ Enabled building d8 for Android on Mac.
+
+ Interpret negative hexadecimal literals as NaN.
+ (issue 2240)
+
+ Expose counters in javascript when using --track-gc-object-stats.
+
+ Enabled building and testing V8 on Android IA.
+
+ Added --trace-parse flag to parser.
+
+ Performance and stability improvements on all platforms.
+
+
2012-07-18: Version 3.12.14
Deactivated optimization of packed arrays.
diff --git a/Makefile b/Makefile
index b963089..3989a17 100644
--- a/Makefile
+++ b/Makefile
@@ -34,7 +34,6 @@
GYPFLAGS ?=
TESTFLAGS ?=
ANDROID_NDK_ROOT ?=
-ANDROID_TOOL_PREFIX = $(ANDROID_NDK_ROOT)/toolchain/bin/arm-linux-androideabi
ANDROID_V8 ?= /data/local/v8
# Special build flags. Use them like this: "make library=shared"
@@ -121,7 +120,7 @@
ARCHES = ia32 x64 arm mipsel
DEFAULT_ARCHES = ia32 x64 arm
MODES = release debug
-ANDROID_MODES = android.release android.debug
+ANDROID_ARCHES = android_ia32 android_arm
# List of files that trigger Makefile regeneration:
GYPFILES = build/all.gyp build/common.gypi build/standalone.gypi \
@@ -130,14 +129,18 @@
# Generates all combinations of ARCHES and MODES, e.g. "ia32.release".
BUILDS = $(foreach mode,$(MODES),$(addsuffix .$(mode),$(ARCHES)))
+ANDROID_BUILDS = $(foreach mode,$(MODES), \
+ $(addsuffix .$(mode),$(ANDROID_ARCHES)))
# Generates corresponding test targets, e.g. "ia32.release.check".
CHECKS = $(addsuffix .check,$(BUILDS))
+ANDROID_CHECKS = $(addsuffix .check,$(ANDROID_BUILDS))
# File where previously used GYPFLAGS are stored.
ENVFILE = $(OUTDIR)/environment
.PHONY: all check clean dependencies $(ENVFILE).new native \
$(ARCHES) $(MODES) $(BUILDS) $(CHECKS) $(addsuffix .clean,$(ARCHES)) \
$(addsuffix .check,$(MODES)) $(addsuffix .check,$(ARCHES)) \
+ $(ANDROID_ARCHES) $(ANDROID_BUILDS) $(ANDROID_CHECKS) \
must-set-ANDROID_NDK_ROOT
# Target definitions. "all" is the default.
@@ -172,19 +175,12 @@
CXX="$(CXX)" LINK="$(LINK)" BUILDTYPE=Release \
builddir="$(shell pwd)/$(OUTDIR)/$@"
-android: $(ANDROID_MODES)
+$(ANDROID_ARCHES): $(addprefix $$@.,$(MODES))
-$(ANDROID_MODES): $(OUTDIR)/Makefile.android
- @$(MAKE) -C "$(OUTDIR)" -f Makefile.android \
- CXX="$(ANDROID_TOOL_PREFIX)-g++" \
- AR="$(ANDROID_TOOL_PREFIX)-ar" \
- RANLIB="$(ANDROID_TOOL_PREFIX)-ranlib" \
- CC="$(ANDROID_TOOL_PREFIX)-gcc" \
- LD="$(ANDROID_TOOL_PREFIX)-ld" \
- LINK="$(ANDROID_TOOL_PREFIX)-g++" \
- BUILDTYPE=$(shell echo $(subst .,,$(suffix $@)) | \
- python -c "print raw_input().capitalize()") \
- builddir="$(shell pwd)/$(OUTDIR)/$@"
+$(ANDROID_BUILDS): $(GYPFILES) $(ENVFILE) build/android.gypi \
+ must-set-ANDROID_NDK_ROOT
+ @tools/android-build.sh $(basename $@) $(subst .,,$(suffix $@)) \
+ $(OUTDIR) $(GYPFLAGS)
# Test targets.
check: all
@@ -204,23 +200,24 @@
@tools/test-wrapper-gypbuild.py $(TESTJOBS) --outdir=$(OUTDIR) \
--arch-and-mode=$(basename $@) $(TESTFLAGS)
-$(addsuffix .sync, $(ANDROID_MODES)): $$(basename $$@)
+$(addsuffix .sync, $(ANDROID_BUILDS)): $$(basename $$@)
@tools/android-sync.sh $(basename $@) $(OUTDIR) \
$(shell pwd) $(ANDROID_V8)
-$(addsuffix .check, $(ANDROID_MODES)): $$(basename $$@).sync
+$(addsuffix .check, $(ANDROID_BUILDS)): $$(basename $$@).sync
@tools/test-wrapper-gypbuild.py $(TESTJOBS) --outdir=$(OUTDIR) \
--arch-and-mode=$(basename $@) \
--special-command="tools/android-run.py @"
-android.check: android.release.check android.debug.check
+$(addsuffix .check, $(ANDROID_ARCHES)): \
+ $(addprefix $$(basename $$@).,$(MODES)).check
native.check: native
@tools/test-wrapper-gypbuild.py $(TESTJOBS) --outdir=$(OUTDIR)/native \
--arch-and-mode=. $(TESTFLAGS)
# Clean targets. You can clean each architecture individually, or everything.
-$(addsuffix .clean,$(ARCHES)) android.clean:
+$(addsuffix .clean, $(ARCHES) $(ANDROID_ARCHES)):
rm -f $(OUTDIR)/Makefile.$(basename $@)
rm -rf $(OUTDIR)/$(basename $@).release
rm -rf $(OUTDIR)/$(basename $@).debug
@@ -231,7 +228,7 @@
rm -rf $(OUTDIR)/native
find $(OUTDIR) -regex '.*\(host\|target\).native\.mk' -delete
-clean: $(addsuffix .clean,$(ARCHES)) native.clean android.clean
+clean: $(addsuffix .clean, $(ARCHES) $(ANDROID_ARCHES)) native.clean
# GYP file generation targets.
MAKEFILES = $(addprefix $(OUTDIR)/Makefile.,$(ARCHES))
@@ -247,15 +244,6 @@
build/gyp/gyp --generator-output="$(OUTDIR)" build/all.gyp \
-Ibuild/standalone.gypi --depth=. -S.native $(GYPFLAGS)
-$(OUTDIR)/Makefile.android: $(GYPFILES) $(ENVFILE) build/android.gypi \
- must-set-ANDROID_NDK_ROOT
- GYP_GENERATORS=make \
- CC="${ANDROID_TOOL_PREFIX}-gcc" \
- CXX="${ANDROID_TOOL_PREFIX}-g++" \
- build/gyp/gyp --generator-output="$(OUTDIR)" build/all.gyp \
- -Ibuild/standalone.gypi --depth=. -Ibuild/android.gypi \
- -S.android $(GYPFLAGS)
-
must-set-ANDROID_NDK_ROOT:
ifndef ANDROID_NDK_ROOT
$(error ANDROID_NDK_ROOT is not set)
diff --git a/build/android.gypi b/build/android.gypi
index ffd0648..c084b63 100644
--- a/build/android.gypi
+++ b/build/android.gypi
@@ -35,7 +35,6 @@
'variables': {
'variables': {
'android_ndk_root%': '<!(/bin/echo -n $ANDROID_NDK_ROOT)',
- 'android_target_arch%': 'arm', # target_arch in android terms.
# Switch between different build types, currently only '0' is
# supported.
@@ -57,11 +56,6 @@
'android_build_type%': '<(android_build_type)',
'OS': 'android',
- 'target_arch': 'arm',
- 'v8_target_arch': 'arm',
- 'armv7': 1,
- 'arm_neon': 0,
- 'arm_fpu': 'vfpv3',
}, # variables
'target_defaults': {
'defines': [
@@ -101,9 +95,6 @@
# Note: This include is in cflags to ensure that it comes after
# all of the includes.
'-I<(android_ndk_include)',
- '-march=armv7-a',
- '-mtune=cortex-a8',
- '-mfpu=vfp3',
],
'defines': [
'ANDROID',
@@ -120,7 +111,6 @@
'ldflags': [
'-nostdlib',
'-Wl,--no-undefined',
- '-Wl,--icf=safe', # Enable identical code folding to reduce size
# Don't export symbols from statically linked libraries.
'-Wl,--exclude-libs=ALL',
],
@@ -148,6 +138,19 @@
'-L<(android_ndk_lib)',
],
}],
+ ['target_arch == "arm"', {
+ 'ldflags': [
+ # Enable identical code folding to reduce size.
+ '-Wl,--icf=safe',
+ ],
+ }],
+ ['target_arch=="arm" and armv7==1', {
+ 'cflags': [
+ '-march=armv7-a',
+ '-mtune=cortex-a8',
+ '-mfpu=vfp3',
+ ],
+ }],
# NOTE: The stlport header include paths below are specified in
# cflags rather than include_dirs because they need to come
# after include_dirs. Think of them like system headers, but
diff --git a/build/common.gypi b/build/common.gypi
index 523b56a..b5f991e 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -164,7 +164,7 @@
'V8_TARGET_ARCH_MIPS',
],
'variables': {
- 'mipscompiler': '<!($(echo ${CXX:-$(which g++)}) -v 2>&1 | grep -q "^Target: mips-" && echo "yes" || echo "no")',
+ 'mipscompiler': '<!($(echo ${CXX:-$(which g++)}) -v 2>&1 | grep -q "^Target: mips" && echo "yes" || echo "no")',
},
'conditions': [
['mipscompiler=="yes"', {
@@ -279,7 +279,7 @@
'target_conditions': [
['_toolset=="host"', {
'variables': {
- 'm32flag': '<!((echo | $(echo ${CXX_host:-$(which g++)}) -m32 -E - > /dev/null 2>&1) && echo -n "-m32" || true)',
+ 'm32flag': '<!((echo | $(echo ${CXX_host:-$(which g++)}) -m32 -E - > /dev/null 2>&1) && echo "-m32" || true)',
},
'cflags': [ '<(m32flag)' ],
'ldflags': [ '<(m32flag)' ],
@@ -289,7 +289,7 @@
}],
['_toolset=="target"', {
'variables': {
- 'm32flag': '<!((echo | $(echo ${CXX_target:-${CXX:-$(which g++)}}) -m32 -E - > /dev/null 2>&1) && echo -n "-m32" || true)',
+ 'm32flag': '<!((echo | $(echo ${CXX_target:-${CXX:-$(which g++)}}) -m32 -E - > /dev/null 2>&1) && echo "-m32" || true)',
},
'cflags': [ '<(m32flag)' ],
'ldflags': [ '<(m32flag)' ],
diff --git a/build/standalone.gypi b/build/standalone.gypi
index cb4299b..7145a16 100644
--- a/build/standalone.gypi
+++ b/build/standalone.gypi
@@ -68,7 +68,8 @@
'conditions': [
['(v8_target_arch=="arm" and host_arch!="arm") or \
(v8_target_arch=="mipsel" and host_arch!="mipsel") or \
- (v8_target_arch=="x64" and host_arch!="x64")', {
+ (v8_target_arch=="x64" and host_arch!="x64") or \
+ (OS=="android")', {
'want_separate_host_toolset': 1,
}, {
'want_separate_host_toolset': 0,
diff --git a/include/v8.h b/include/v8.h
index 34995d0..5c2c8b6 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -1064,7 +1064,8 @@
enum WriteOptions {
NO_OPTIONS = 0,
HINT_MANY_WRITES_EXPECTED = 1,
- NO_NULL_TERMINATION = 2
+ NO_NULL_TERMINATION = 2,
+ PRESERVE_ASCII_NULL = 4
};
// 16-bit character codes.
diff --git a/src/SConscript b/src/SConscript
index cd35910..16bfb55 100755
--- a/src/SConscript
+++ b/src/SConscript
@@ -72,6 +72,7 @@
execution.cc
extensions/externalize-string-extension.cc
extensions/gc-extension.cc
+ extensions/statistics-extension.cc
factory.cc
fast-dtoa.cc
fixed-dtoa.cc
@@ -105,6 +106,7 @@
objects-visiting.cc
objects.cc
once.cc
+ optimizing-compiler-thread.cc
parser.cc
preparse-data.cc
preparser.cc
diff --git a/src/api.cc b/src/api.cc
index 8218ad4..cd0684b 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -3847,6 +3847,9 @@
LOG_API(isolate, "String::WriteUtf8");
ENTER_V8(isolate);
i::Handle<i::String> str = Utils::OpenHandle(this);
+ if (options & HINT_MANY_WRITES_EXPECTED) {
+ FlattenString(str); // Flatten the string for efficiency.
+ }
int string_length = str->length();
if (str->IsAsciiRepresentation()) {
int len;
@@ -3903,11 +3906,7 @@
// Slow case.
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.
- FlattenString(str);
- }
+
write_input_buffer.Reset(0, *str);
int len = str->length();
// Encode the first K - 3 bytes directly into the buffer since we
@@ -3949,8 +3948,9 @@
c,
unibrow::Utf16::kNoPreviousCharacter);
if (pos + written <= capacity) {
- for (int j = 0; j < written; j++)
+ for (int j = 0; j < written; j++) {
buffer[pos + j] = intermediate[j];
+ }
pos += written;
nchars++;
} else {
@@ -3963,8 +3963,9 @@
}
if (nchars_ref != NULL) *nchars_ref = nchars;
if (!(options & NO_NULL_TERMINATION) &&
- (i == len && (capacity == -1 || pos < capacity)))
+ (i == len && (capacity == -1 || pos < capacity))) {
buffer[pos++] = '\0';
+ }
return pos;
}
@@ -3977,28 +3978,45 @@
if (IsDeadCheck(isolate, "v8::String::WriteAscii()")) return 0;
LOG_API(isolate, "String::WriteAscii");
ENTER_V8(isolate);
- i::StringInputBuffer& write_input_buffer = *isolate->write_input_buffer();
ASSERT(start >= 0 && length >= -1);
i::Handle<i::String> str = Utils::OpenHandle(this);
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); // Flatten the string for efficiency.
}
+
+ if (str->IsAsciiRepresentation()) {
+ // WriteToFlat is faster than using the StringInputBuffer.
+ if (length == -1) length = str->length() + 1;
+ int len = i::Min(length, str->length() - start);
+ i::String::WriteToFlat(*str, buffer, start, start + len);
+ if (!(options & PRESERVE_ASCII_NULL)) {
+ for (int i = 0; i < len; i++) {
+ if (buffer[i] == '\0') buffer[i] = ' ';
+ }
+ }
+ if (!(options & NO_NULL_TERMINATION) && length > len) {
+ buffer[len] = '\0';
+ }
+ return len;
+ }
+
+ i::StringInputBuffer& write_input_buffer = *isolate->write_input_buffer();
int end = length;
- if ( (length == -1) || (length > str->length() - start) )
+ if ((length == -1) || (length > str->length() - start)) {
end = str->length() - start;
+ }
if (end < 0) return 0;
write_input_buffer.Reset(start, *str);
int i;
for (i = 0; i < end; i++) {
char c = static_cast<char>(write_input_buffer.GetNext());
- if (c == '\0') c = ' ';
+ if (c == '\0' && !(options & PRESERVE_ASCII_NULL)) c = ' ';
buffer[i] = c;
}
- if (!(options & NO_NULL_TERMINATION) && (length == -1 || i < length))
+ if (!(options & NO_NULL_TERMINATION) && (length == -1 || i < length)) {
buffer[i] = '\0';
+ }
return i;
}
@@ -4017,7 +4035,7 @@
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);
}
int end = start + length;
if ((length == -1) || (length > str->length() - start) )
@@ -4203,8 +4221,9 @@
i::Handle<i::Foreign> foreign =
isolate->factory()->NewForeign(
reinterpret_cast<i::Address>(value), i::TENURED);
- if (!foreign.is_null())
- Utils::OpenHandle(this)->SetInternalField(index, *foreign);
+ if (!foreign.is_null()) {
+ Utils::OpenHandle(this)->SetInternalField(index, *foreign);
+ }
}
ASSERT_EQ(value, GetPointerFromInternalField(index));
}
@@ -6422,12 +6441,6 @@
Object** start = reinterpret_cast<Object**>(&saved_contexts_.first());
v->VisitPointers(start, start + saved_contexts_.length());
}
-
- for (DeferredHandles* deferred = deferred_handles_head_;
- deferred != NULL;
- deferred = deferred->next_) {
- deferred->Iterate(v);
- }
}
@@ -6448,8 +6461,8 @@
DeferredHandles* HandleScopeImplementer::Detach(Object** prev_limit) {
- DeferredHandles* deferred = new DeferredHandles(
- deferred_handles_head_, isolate()->handle_scope_data()->next, this);
+ DeferredHandles* deferred =
+ new DeferredHandles(isolate()->handle_scope_data()->next, isolate());
while (!blocks_.is_empty()) {
Object** block_start = blocks_.last();
@@ -6470,41 +6483,12 @@
ASSERT(prev_limit == NULL || !blocks_.is_empty());
ASSERT(!blocks_.is_empty() && prev_limit != NULL);
- deferred_handles_head_ = deferred;
ASSERT(last_handle_before_deferred_block_ != NULL);
last_handle_before_deferred_block_ = NULL;
return deferred;
}
-void HandleScopeImplementer::DestroyDeferredHandles(DeferredHandles* deferred) {
-#ifdef DEBUG
- DeferredHandles* deferred_iterator = deferred;
- while (deferred_iterator->previous_ != NULL) {
- deferred_iterator = deferred_iterator->previous_;
- }
- ASSERT(deferred_handles_head_ == deferred_iterator);
-#endif
- if (deferred_handles_head_ == deferred) {
- deferred_handles_head_ = deferred_handles_head_->next_;
- }
- if (deferred->next_ != NULL) {
- deferred->next_->previous_ = deferred->previous_;
- }
- if (deferred->previous_ != NULL) {
- deferred->previous_->next_ = deferred->next_;
- }
- for (int i = 0; i < deferred->blocks_.length(); i++) {
-#ifdef DEBUG
- HandleScope::ZapRange(deferred->blocks_[i],
- &deferred->blocks_[i][kHandleBlockSize]);
-#endif
- if (spare_ != NULL) DeleteArray(spare_);
- spare_ = deferred->blocks_[i];
- }
-}
-
-
void HandleScopeImplementer::BeginDeferredScope() {
ASSERT(last_handle_before_deferred_block_ == NULL);
last_handle_before_deferred_block_ = isolate()->handle_scope_data()->next;
@@ -6512,7 +6496,14 @@
DeferredHandles::~DeferredHandles() {
- impl_->DestroyDeferredHandles(this);
+ isolate_->UnlinkDeferredHandles(this);
+
+ for (int i = 0; i < blocks_.length(); i++) {
+#ifdef DEBUG
+ HandleScope::ZapRange(blocks_[i], &blocks_[i][kHandleBlockSize]);
+#endif
+ isolate_->handle_scope_implementer()->ReturnBlock(blocks_[i]);
+ }
}
diff --git a/src/api.h b/src/api.h
index 6be4474..ea70dca 100644
--- a/src/api.h
+++ b/src/api.h
@@ -397,13 +397,12 @@
~DeferredHandles();
private:
- DeferredHandles(DeferredHandles* next, Object** first_block_limit,
- HandleScopeImplementer* impl)
- : next_(next),
+ DeferredHandles(Object** first_block_limit, Isolate* isolate)
+ : next_(NULL),
previous_(NULL),
first_block_limit_(first_block_limit),
- impl_(impl) {
- if (next != NULL) next->previous_ = this;
+ isolate_(isolate) {
+ isolate->LinkDeferredHandles(this);
}
void Iterate(ObjectVisitor* v);
@@ -412,9 +411,10 @@
DeferredHandles* next_;
DeferredHandles* previous_;
Object** first_block_limit_;
- HandleScopeImplementer* impl_;
+ Isolate* isolate_;
friend class HandleScopeImplementer;
+ friend class Isolate;
};
@@ -436,8 +436,7 @@
saved_contexts_(0),
spare_(NULL),
call_depth_(0),
- last_handle_before_deferred_block_(NULL),
- deferred_handles_head_(NULL) { }
+ last_handle_before_deferred_block_(NULL) { }
~HandleScopeImplementer() {
DeleteArray(spare_);
@@ -475,13 +474,18 @@
inline List<internal::Object**>* blocks() { return &blocks_; }
Isolate* isolate() const { return isolate_; }
+ void ReturnBlock(Object** block) {
+ ASSERT(block != NULL);
+ if (spare_ != NULL) DeleteArray(spare_);
+ spare_ = block;
+ }
+
private:
void ResetAfterArchive() {
blocks_.Initialize(0);
entered_contexts_.Initialize(0);
saved_contexts_.Initialize(0);
spare_ = NULL;
- deferred_handles_head_ = NULL;
last_handle_before_deferred_block_ = NULL;
call_depth_ = 0;
}
@@ -490,7 +494,6 @@
ASSERT(blocks_.length() == 0);
ASSERT(entered_contexts_.length() == 0);
ASSERT(saved_contexts_.length() == 0);
- ASSERT(deferred_handles_head_ == NULL);
blocks_.Free();
entered_contexts_.Free();
saved_contexts_.Free();
@@ -503,7 +506,6 @@
void BeginDeferredScope();
DeferredHandles* Detach(Object** prev_limit);
- void DestroyDeferredHandles(DeferredHandles* handles);
Isolate* isolate_;
List<internal::Object**> blocks_;
@@ -514,7 +516,6 @@
Object** spare_;
int call_depth_;
Object** last_handle_before_deferred_block_;
- DeferredHandles* deferred_handles_head_;
// This is only used for threading support.
v8::ImplementationUtilities::HandleScopeData handle_scope_data_;
diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc
index d875796..42343b1 100644
--- a/src/arm/assembler-arm.cc
+++ b/src/arm/assembler-arm.cc
@@ -1834,6 +1834,7 @@
int sd, d;
first.split_code(&sd, &d);
int count = last.code() - first.code() + 1;
+ ASSERT(count <= 16);
emit(cond | B27 | B26 | am | d*B22 | B20 | base.code()*B16 | sd*B12 |
0xB*B8 | count*2);
}
@@ -1855,6 +1856,7 @@
int sd, d;
first.split_code(&sd, &d);
int count = last.code() - first.code() + 1;
+ ASSERT(count <= 16);
emit(cond | B27 | B26 | am | d*B22 | base.code()*B16 | sd*B12 |
0xB*B8 | count*2);
}
diff --git a/src/arm/builtins-arm.cc b/src/arm/builtins-arm.cc
index 578bd81..12a914b 100644
--- a/src/arm/builtins-arm.cc
+++ b/src/arm/builtins-arm.cc
@@ -697,6 +697,43 @@
}
+static void GenerateTailCallToSharedCode(MacroAssembler* masm) {
+ __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
+ __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kCodeOffset));
+ __ add(r2, r2, Operand(Code::kHeaderSize - kHeapObjectTag));
+ __ mov(pc, r2);
+}
+
+
+void Builtins::Generate_InRecompileQueue(MacroAssembler* masm) {
+ GenerateTailCallToSharedCode(masm);
+}
+
+
+void Builtins::Generate_ParallelRecompile(MacroAssembler* masm) {
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+
+ // Push a copy of the function onto the stack.
+ __ push(r1);
+ // Push call kind information.
+ __ push(r5);
+
+ __ push(r1); // Function is also the parameter to the runtime call.
+ __ CallRuntime(Runtime::kParallelRecompile, 1);
+
+ // Restore call kind information.
+ __ pop(r5);
+ // Restore receiver.
+ __ pop(r1);
+
+ // Tear down internal frame.
+ }
+
+ GenerateTailCallToSharedCode(masm);
+}
+
+
static void Generate_JSConstructStubHelper(MacroAssembler* masm,
bool is_api_function,
bool count_constructions) {
diff --git a/src/arm/constants-arm.h b/src/arm/constants-arm.h
index e767001..5aadc3c 100644
--- a/src/arm/constants-arm.h
+++ b/src/arm/constants-arm.h
@@ -56,8 +56,9 @@
# define CAN_USE_ARMV6_INSTRUCTIONS 1
#endif
-#if defined(__ARM_ARCH_5T__) || \
- defined(__ARM_ARCH_5TE__) || \
+#if defined(__ARM_ARCH_5T__) || \
+ defined(__ARM_ARCH_5TE__) || \
+ defined(__ARM_ARCH_5TEJ__) || \
defined(CAN_USE_ARMV6_INSTRUCTIONS)
# define CAN_USE_ARMV5_INSTRUCTIONS 1
# define CAN_USE_THUMB_INSTRUCTIONS 1
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index a24f310..f55956c 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -1144,7 +1144,7 @@
// We got a map in register r0. Get the enumeration cache from it.
__ bind(&use_cache);
__ LoadInstanceDescriptors(r0, r1, r2);
- __ ldr(r1, FieldMemOperand(r1, DescriptorArray::kLastAddedOffset));
+ __ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumCacheOffset));
__ ldr(r2, FieldMemOperand(r1, DescriptorArray::kEnumCacheBridgeCacheOffset));
// Set up the four remaining stack slots.
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index 4f63b50..91afec5 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -1835,7 +1835,8 @@
LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
HLoadKeyedFastElement* instr) {
ASSERT(instr->representation().IsTagged());
- ASSERT(instr->key()->representation().IsInteger32());
+ ASSERT(instr->key()->representation().IsInteger32() ||
+ instr->key()->representation().IsTagged());
LOperand* obj = UseRegisterAtStart(instr->object());
LOperand* key = UseRegisterAtStart(instr->key());
LLoadKeyedFastElement* result = new(zone()) LLoadKeyedFastElement(obj, key);
@@ -1847,7 +1848,8 @@
LInstruction* LChunkBuilder::DoLoadKeyedFastDoubleElement(
HLoadKeyedFastDoubleElement* instr) {
ASSERT(instr->representation().IsDouble());
- ASSERT(instr->key()->representation().IsInteger32());
+ ASSERT(instr->key()->representation().IsInteger32() ||
+ instr->key()->representation().IsTagged());
LOperand* elements = UseTempRegister(instr->elements());
LOperand* key = UseRegisterOrConstantAtStart(instr->key());
LLoadKeyedFastDoubleElement* result =
@@ -1866,7 +1868,8 @@
(instr->representation().IsDouble() &&
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
(elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
- ASSERT(instr->key()->representation().IsInteger32());
+ ASSERT(instr->key()->representation().IsInteger32() ||
+ instr->key()->representation().IsTagged());
LOperand* external_pointer = UseRegister(instr->external_pointer());
LOperand* key = UseRegisterOrConstant(instr->key());
LLoadKeyedSpecializedArrayElement* result =
@@ -1894,7 +1897,8 @@
bool needs_write_barrier = instr->NeedsWriteBarrier();
ASSERT(instr->value()->representation().IsTagged());
ASSERT(instr->object()->representation().IsTagged());
- ASSERT(instr->key()->representation().IsInteger32());
+ ASSERT(instr->key()->representation().IsInteger32() ||
+ instr->key()->representation().IsTagged());
LOperand* obj = UseTempRegister(instr->object());
LOperand* val = needs_write_barrier
@@ -1911,7 +1915,8 @@
HStoreKeyedFastDoubleElement* instr) {
ASSERT(instr->value()->representation().IsDouble());
ASSERT(instr->elements()->representation().IsTagged());
- ASSERT(instr->key()->representation().IsInteger32());
+ ASSERT(instr->key()->representation().IsInteger32() ||
+ instr->key()->representation().IsTagged());
LOperand* elements = UseRegisterAtStart(instr->elements());
LOperand* val = UseTempRegister(instr->value());
@@ -1932,7 +1937,8 @@
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
(elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
ASSERT(instr->external_pointer()->representation().IsExternal());
- ASSERT(instr->key()->representation().IsInteger32());
+ ASSERT(instr->key()->representation().IsInteger32() ||
+ instr->key()->representation().IsTagged());
LOperand* external_pointer = UseRegister(instr->external_pointer());
bool val_is_temp_register =
diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h
index c7910a3..9982bf0 100644
--- a/src/arm/lithium-arm.h
+++ b/src/arm/lithium-arm.h
@@ -859,6 +859,7 @@
LOperand* length() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(BoundsCheck, "bounds-check")
+ DECLARE_HYDROGEN_ACCESSOR(BoundsCheck)
};
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index cf0c35c..d94a1fe 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -2784,7 +2784,12 @@
Register scratch = scratch0();
// Load the result.
- __ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2));
+ if (instr->hydrogen()->key()->representation().IsTagged()) {
+ __ add(scratch, elements,
+ Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize));
+ } else {
+ __ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2));
+ }
uint32_t offset = FixedArray::kHeaderSize +
(instr->additional_index() << kPointerSizeLog2);
__ ldr(result, FieldMemOperand(scratch, offset));
@@ -2811,8 +2816,9 @@
DwVfpRegister result = ToDoubleRegister(instr->result());
Register scratch = scratch0();
- int shift_size =
- ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS);
+ int element_size_shift = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS);
+ int shift_size = (instr->hydrogen()->key()->representation().IsTagged())
+ ? (element_size_shift - kSmiTagSize) : element_size_shift;
int constant_key = 0;
if (key_is_constant) {
constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
@@ -2824,14 +2830,15 @@
}
Operand operand = key_is_constant
- ? Operand(((constant_key + instr->additional_index()) << shift_size) +
+ ? Operand(((constant_key + instr->additional_index()) <<
+ element_size_shift) +
FixedDoubleArray::kHeaderSize - kHeapObjectTag)
: Operand(key, LSL, shift_size);
__ add(elements, elements, operand);
if (!key_is_constant) {
__ add(elements, elements,
Operand((FixedDoubleArray::kHeaderSize - kHeapObjectTag) +
- (instr->additional_index() << shift_size)));
+ (instr->additional_index() << element_size_shift)));
}
if (instr->hydrogen()->RequiresHoleCheck()) {
@@ -2844,6 +2851,42 @@
}
+MemOperand LCodeGen::PrepareKeyedOperand(Register key,
+ Register base,
+ bool key_is_constant,
+ int constant_key,
+ int element_size,
+ int shift_size,
+ int additional_index,
+ int additional_offset) {
+ if (additional_index != 0 && !key_is_constant) {
+ additional_index *= 1 << (element_size - shift_size);
+ __ add(scratch0(), key, Operand(additional_index));
+ }
+
+ if (key_is_constant) {
+ return MemOperand(base,
+ (constant_key << element_size) + additional_offset);
+ }
+
+ if (additional_index == 0) {
+ if (shift_size >= 0) {
+ return MemOperand(base, key, LSL, shift_size);
+ } else {
+ ASSERT_EQ(-1, shift_size);
+ return MemOperand(base, key, LSR, 1);
+ }
+ }
+
+ if (shift_size >= 0) {
+ return MemOperand(base, scratch0(), LSL, shift_size);
+ } else {
+ ASSERT_EQ(-1, shift_size);
+ return MemOperand(base, scratch0(), LSR, 1);
+ }
+}
+
+
void LCodeGen::DoLoadKeyedSpecializedArrayElement(
LLoadKeyedSpecializedArrayElement* instr) {
Register external_pointer = ToRegister(instr->external_pointer());
@@ -2859,15 +2902,17 @@
} else {
key = ToRegister(instr->key());
}
- int shift_size = ElementsKindToShiftSize(elements_kind);
- int additional_offset = instr->additional_index() << shift_size;
+ int element_size_shift = ElementsKindToShiftSize(elements_kind);
+ int shift_size = (instr->hydrogen()->key()->representation().IsTagged())
+ ? (element_size_shift - kSmiTagSize) : element_size_shift;
+ int additional_offset = instr->additional_index() << element_size_shift;
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
CpuFeatures::Scope scope(VFP3);
DwVfpRegister result = ToDoubleRegister(instr->result());
Operand operand = key_is_constant
- ? Operand(constant_key << shift_size)
+ ? Operand(constant_key << element_size_shift)
: Operand(key, LSL, shift_size);
__ add(scratch0(), external_pointer, operand);
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
@@ -2878,15 +2923,10 @@
}
} else {
Register result = ToRegister(instr->result());
- if (instr->additional_index() != 0 && !key_is_constant) {
- __ add(scratch0(), key, Operand(instr->additional_index()));
- }
- MemOperand mem_operand(key_is_constant
- ? MemOperand(external_pointer,
- (constant_key << shift_size) + additional_offset)
- : (instr->additional_index() == 0
- ? MemOperand(external_pointer, key, LSL, shift_size)
- : MemOperand(external_pointer, scratch0(), LSL, shift_size)));
+ MemOperand mem_operand = PrepareKeyedOperand(
+ key, external_pointer, key_is_constant, constant_key,
+ element_size_shift, shift_size,
+ instr->additional_index(), additional_offset);
switch (elements_kind) {
case EXTERNAL_BYTE_ELEMENTS:
__ ldrsb(result, mem_operand);
@@ -3803,7 +3843,12 @@
+ FixedArray::kHeaderSize;
__ str(value, FieldMemOperand(elements, offset));
} else {
- __ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2));
+ if (instr->hydrogen()->key()->representation().IsTagged()) {
+ __ add(scratch, elements,
+ Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize));
+ } else {
+ __ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2));
+ }
if (instr->additional_index() != 0) {
__ add(scratch,
scratch,
@@ -3848,9 +3893,11 @@
} else {
key = ToRegister(instr->key());
}
- int shift_size = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS);
+ int element_size_shift = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS);
+ int shift_size = (instr->hydrogen()->key()->representation().IsTagged())
+ ? (element_size_shift - kSmiTagSize) : element_size_shift;
Operand operand = key_is_constant
- ? Operand((constant_key << shift_size) +
+ ? Operand((constant_key << element_size_shift) +
FixedDoubleArray::kHeaderSize - kHeapObjectTag)
: Operand(key, LSL, shift_size);
__ add(scratch, elements, operand);
@@ -3868,7 +3915,7 @@
vs);
}
- __ vstr(value, scratch, instr->additional_index() << shift_size);
+ __ vstr(value, scratch, instr->additional_index() << element_size_shift);
}
@@ -3888,15 +3935,18 @@
} else {
key = ToRegister(instr->key());
}
- int shift_size = ElementsKindToShiftSize(elements_kind);
- int additional_offset = instr->additional_index() << shift_size;
+ int element_size_shift = ElementsKindToShiftSize(elements_kind);
+ int shift_size = (instr->hydrogen()->key()->representation().IsTagged())
+ ? (element_size_shift - kSmiTagSize) : element_size_shift;
+ int additional_offset = instr->additional_index() << element_size_shift;
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
CpuFeatures::Scope scope(VFP3);
DwVfpRegister value(ToDoubleRegister(instr->value()));
- Operand operand(key_is_constant ? Operand(constant_key << shift_size)
- : Operand(key, LSL, shift_size));
+ Operand operand(key_is_constant
+ ? Operand(constant_key << element_size_shift)
+ : Operand(key, LSL, shift_size));
__ add(scratch0(), external_pointer, operand);
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
__ vcvt_f32_f64(double_scratch0().low(), value);
@@ -3906,16 +3956,10 @@
}
} else {
Register value(ToRegister(instr->value()));
- if (instr->additional_index() != 0 && !key_is_constant) {
- __ add(scratch0(), key, Operand(instr->additional_index()));
- }
- MemOperand mem_operand(key_is_constant
- ? MemOperand(external_pointer,
- ((constant_key + instr->additional_index())
- << shift_size))
- : (instr->additional_index() == 0
- ? MemOperand(external_pointer, key, LSL, shift_size)
- : MemOperand(external_pointer, scratch0(), LSL, shift_size)));
+ MemOperand mem_operand = PrepareKeyedOperand(
+ key, external_pointer, key_is_constant, constant_key,
+ element_size_shift, shift_size,
+ instr->additional_index(), additional_offset);
switch (elements_kind) {
case EXTERNAL_PIXEL_ELEMENTS:
case EXTERNAL_BYTE_ELEMENTS:
@@ -5364,7 +5408,7 @@
Register scratch = ToRegister(instr->scratch());
__ LoadInstanceDescriptors(map, result, scratch);
__ ldr(result,
- FieldMemOperand(result, DescriptorArray::kLastAddedOffset));
+ FieldMemOperand(result, DescriptorArray::kEnumCacheOffset));
__ ldr(result,
FieldMemOperand(result, FixedArray::SizeFor(instr->idx())));
__ cmp(result, Operand(0));
diff --git a/src/arm/lithium-codegen-arm.h b/src/arm/lithium-codegen-arm.h
index c871a57..d380f4b 100644
--- a/src/arm/lithium-codegen-arm.h
+++ b/src/arm/lithium-codegen-arm.h
@@ -132,6 +132,15 @@
void DoParallelMove(LParallelMove* move);
void DoGap(LGap* instr);
+ MemOperand PrepareKeyedOperand(Register key,
+ Register base,
+ bool key_is_constant,
+ int constant_key,
+ int element_size,
+ int shift_size,
+ int additional_index,
+ int additional_offset);
+
// Emit frame translation commands for an environment.
void WriteTranslation(LEnvironment* environment, Translation* translation);
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index 84e866e..88e5dec 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -3723,7 +3723,7 @@
// Check that there is an enum cache in the non-empty instance
// descriptors (r3). This is the case if the next enumeration
// index field does not contain a smi.
- ldr(r3, FieldMemOperand(r3, DescriptorArray::kLastAddedOffset));
+ ldr(r3, FieldMemOperand(r3, DescriptorArray::kEnumCacheOffset));
JumpIfSmi(r3, call_runtime);
// For all objects but the receiver, check that the cache is empty.
diff --git a/src/ast.cc b/src/ast.cc
index adbad41..e7f70c5 100644
--- a/src/ast.cc
+++ b/src/ast.cc
@@ -125,7 +125,7 @@
value_(value),
pos_(pos),
binary_operation_(NULL),
- compound_load_id_(kNoNumber),
+ compound_load_id_(GetNextId(isolate)),
assignment_id_(GetNextId(isolate)),
block_start_(false),
block_end_(false),
diff --git a/src/ast.h b/src/ast.h
index e38def8..8c9606a 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -37,7 +37,7 @@
#include "list-inl.h"
#include "runtime.h"
#include "small-pointer-list.h"
-#include "smart-array-pointer.h"
+#include "smart-pointers.h"
#include "token.h"
#include "utils.h"
#include "variables.h"
@@ -211,7 +211,7 @@
virtual ~AstNode() { }
virtual void Accept(AstVisitor* v) = 0;
- virtual Type node_type() const { return kInvalid; }
+ virtual Type node_type() const = 0;
// Type testing & conversion functions overridden by concrete subclasses.
#define DECLARE_NODE_FUNCTIONS(type) \
@@ -220,9 +220,6 @@
AST_NODE_LIST(DECLARE_NODE_FUNCTIONS)
#undef DECLARE_NODE_FUNCTIONS
- virtual Declaration* AsDeclaration() { return NULL; }
- virtual Statement* AsStatement() { return NULL; }
- virtual Expression* AsExpression() { return NULL; }
virtual TargetCollector* AsTargetCollector() { return NULL; }
virtual BreakableStatement* AsBreakableStatement() { return NULL; }
virtual IterationStatement* AsIterationStatement() { return NULL; }
@@ -252,8 +249,6 @@
public:
Statement() : statement_pos_(RelocInfo::kNoPosition) {}
- virtual Statement* AsStatement() { return this; }
-
bool IsEmpty() { return AsEmptyStatement() != NULL; }
void set_statement_pos(int statement_pos) { statement_pos_ = statement_pos; }
@@ -314,8 +309,6 @@
return 0;
}
- virtual Expression* AsExpression() { return this; }
-
virtual bool IsValidLeftHandSide() { return false; }
// Helpers for ToBoolean conversion.
@@ -365,8 +358,8 @@
test_id_(GetNextId(isolate)) {}
private:
- int id_;
- int test_id_;
+ const int id_;
+ const int test_id_;
};
@@ -408,8 +401,8 @@
ZoneStringList* labels_;
Type type_;
Label break_target_;
- int entry_id_;
- int exit_id_;
+ const int entry_id_;
+ const int exit_id_;
};
@@ -456,8 +449,6 @@
virtual InitializationFlag initialization() const = 0;
virtual bool IsInlineable() const;
- virtual Declaration* AsDeclaration() { return this; }
-
protected:
Declaration(VariableProxy* proxy,
VariableMode mode,
@@ -707,7 +698,7 @@
private:
Statement* body_;
Label continue_target_;
- int osr_entry_id_;
+ const int osr_entry_id_;
};
@@ -746,8 +737,8 @@
private:
Expression* cond_;
int condition_position_;
- int continue_id_;
- int back_edge_id_;
+ const int continue_id_;
+ const int back_edge_id_;
};
@@ -787,7 +778,7 @@
Expression* cond_;
// True if there is a function literal subexpression in the condition.
bool may_have_function_literal_;
- int body_id_;
+ const int body_id_;
};
@@ -846,8 +837,8 @@
// True if there is a function literal subexpression in the condition.
bool may_have_function_literal_;
Variable* loop_variable_;
- int continue_id_;
- int body_id_;
+ const int continue_id_;
+ const int body_id_;
};
@@ -883,8 +874,8 @@
private:
Expression* each_;
Expression* enumerable_;
- int body_id_;
- int prepare_id_;
+ const int body_id_;
+ const int prepare_id_;
};
@@ -1018,8 +1009,8 @@
OBJECT_ONLY
};
CompareTypeFeedback compare_type_;
- int compare_id_;
- int entry_id_;
+ const int compare_id_;
+ const int entry_id_;
};
@@ -1088,9 +1079,9 @@
Expression* condition_;
Statement* then_statement_;
Statement* else_statement_;
- int if_id_;
- int then_id_;
- int else_id_;
+ const int if_id_;
+ const int then_id_;
+ const int else_id_;
};
@@ -1107,6 +1098,7 @@
// Virtual behaviour. TargetCollectors are never part of the AST.
virtual void Accept(AstVisitor* v) { UNREACHABLE(); }
+ virtual Type node_type() const { return kInvalid; }
virtual TargetCollector* AsTargetCollector() { return this; }
ZoneList<Label*>* targets() { return &targets_; }
@@ -1453,7 +1445,7 @@
private:
Handle<FixedArray> constant_elements_;
ZoneList<Expression*>* values_;
- int first_element_id_;
+ const int first_element_id_;
};
@@ -1625,7 +1617,7 @@
Handle<JSObject> holder_;
Handle<JSGlobalPropertyCell> cell_;
- int return_id_;
+ const int return_id_;
};
@@ -1666,7 +1658,7 @@
bool is_monomorphic_;
Handle<JSFunction> target_;
- int return_id_;
+ const int return_id_;
};
@@ -1726,13 +1718,9 @@
op_(op),
expression_(expression),
pos_(pos),
- materialize_true_id_(AstNode::kNoNumber),
- materialize_false_id_(AstNode::kNoNumber) {
+ materialize_true_id_(GetNextId(isolate)),
+ materialize_false_id_(GetNextId(isolate)) {
ASSERT(Token::IsUnaryOp(op));
- if (op == Token::NOT) {
- materialize_true_id_ = GetNextId(isolate);
- materialize_false_id_ = GetNextId(isolate);
- }
}
private:
@@ -1742,8 +1730,8 @@
// For unary not (Token::NOT), the AST ids where true and false will
// actually be materialized, respectively.
- int materialize_true_id_;
- int materialize_false_id_;
+ const int materialize_true_id_;
+ const int materialize_false_id_;
};
@@ -1769,11 +1757,13 @@
Expression* left,
Expression* right,
int pos)
- : Expression(isolate), op_(op), left_(left), right_(right), pos_(pos) {
+ : Expression(isolate),
+ op_(op),
+ left_(left),
+ right_(right),
+ pos_(pos),
+ right_id_(GetNextId(isolate)) {
ASSERT(Token::IsBinaryOp(op));
- right_id_ = (op == Token::AND || op == Token::OR)
- ? GetNextId(isolate)
- : AstNode::kNoNumber;
}
private:
@@ -1781,9 +1771,9 @@
Expression* left_;
Expression* right_;
int pos_;
- // The short-circuit logical operations have an AST ID for their
+ // The short-circuit logical operations need an AST ID for their
// right-hand subexpression.
- int right_id_;
+ const int right_id_;
};
@@ -1834,8 +1824,8 @@
bool is_monomorphic_;
Expression* expression_;
int pos_;
- int assignment_id_;
- int count_id_;
+ const int assignment_id_;
+ const int count_id_;
SmallMapList receiver_types_;
};
@@ -1925,8 +1915,8 @@
Expression* else_expression_;
int then_expression_position_;
int else_expression_position_;
- int then_id_;
- int else_id_;
+ const int then_id_;
+ const int else_id_;
};
@@ -1980,7 +1970,6 @@
if (is_compound()) {
binary_operation_ =
factory->NewBinaryOperation(binary_op(), target_, value_, pos_ + 1);
- compound_load_id_ = GetNextId(isolate);
}
}
@@ -1990,8 +1979,8 @@
Expression* value_;
int pos_;
BinaryOperation* binary_operation_;
- int compound_load_id_;
- int assignment_id_;
+ const int compound_load_id_;
+ const int assignment_id_;
bool block_start_;
bool block_end_;
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index 726670a..c72af5c 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -42,6 +42,7 @@
#include "snapshot.h"
#include "extensions/externalize-string-extension.h"
#include "extensions/gc-extension.h"
+#include "extensions/statistics-extension.h"
namespace v8 {
namespace internal {
@@ -95,6 +96,7 @@
extensions_cache_.Initialize(create_heap_objects);
GCExtension::Register();
ExternalizeStringExtension::Register();
+ StatisticsExtension::Register();
}
@@ -253,16 +255,16 @@
Handle<Map> CreateFunctionMap(PrototypePropertyMode prototype_mode);
- Handle<DescriptorArray> ComputeFunctionInstanceDescriptor(
- PrototypePropertyMode prototypeMode);
+ void SetFunctionInstanceDescriptor(Handle<Map> map,
+ PrototypePropertyMode prototypeMode);
void MakeFunctionInstancePrototypeWritable();
Handle<Map> CreateStrictModeFunctionMap(
PrototypePropertyMode prototype_mode,
Handle<JSFunction> empty_function);
- Handle<DescriptorArray> ComputeStrictFunctionInstanceDescriptor(
- PrototypePropertyMode propertyMode);
+ void SetStrictFunctionInstanceDescriptor(Handle<Map> map,
+ PrototypePropertyMode propertyMode);
static bool CompileBuiltin(Isolate* isolate, int index);
static bool CompileExperimentalBuiltin(Isolate* isolate, int index);
@@ -381,55 +383,54 @@
}
-Handle<DescriptorArray> Genesis::ComputeFunctionInstanceDescriptor(
- PrototypePropertyMode prototypeMode) {
+void Genesis::SetFunctionInstanceDescriptor(
+ Handle<Map> map, PrototypePropertyMode prototypeMode) {
int size = (prototypeMode == DONT_ADD_PROTOTYPE) ? 4 : 5;
Handle<DescriptorArray> descriptors(factory()->NewDescriptorArray(size));
- PropertyAttributes attribs = static_cast<PropertyAttributes>(
- DONT_ENUM | DONT_DELETE | READ_ONLY);
-
DescriptorArray::WhitenessWitness witness(*descriptors);
+ Handle<Foreign> length(factory()->NewForeign(&Accessors::FunctionLength));
+ Handle<Foreign> name(factory()->NewForeign(&Accessors::FunctionName));
+ Handle<Foreign> args(factory()->NewForeign(&Accessors::FunctionArguments));
+ Handle<Foreign> caller(factory()->NewForeign(&Accessors::FunctionCaller));
+ Handle<Foreign> prototype;
+ if (prototypeMode != DONT_ADD_PROTOTYPE) {
+ prototype = factory()->NewForeign(&Accessors::FunctionPrototype);
+ }
+ PropertyAttributes attribs = static_cast<PropertyAttributes>(
+ DONT_ENUM | DONT_DELETE | READ_ONLY);
+ map->set_instance_descriptors(*descriptors);
+
{ // Add length.
- Handle<Foreign> f(factory()->NewForeign(&Accessors::FunctionLength));
- CallbacksDescriptor d(*factory()->length_symbol(), *f, attribs);
- descriptors->Append(&d, witness);
+ CallbacksDescriptor d(*factory()->length_symbol(), *length, attribs);
+ map->AppendDescriptor(&d, witness);
}
{ // Add name.
- Handle<Foreign> f(factory()->NewForeign(&Accessors::FunctionName));
- CallbacksDescriptor d(*factory()->name_symbol(), *f, attribs);
- descriptors->Append(&d, witness);
+ CallbacksDescriptor d(*factory()->name_symbol(), *name, attribs);
+ map->AppendDescriptor(&d, witness);
}
{ // Add arguments.
- Handle<Foreign> f(factory()->NewForeign(&Accessors::FunctionArguments));
- CallbacksDescriptor d(*factory()->arguments_symbol(), *f, attribs);
- descriptors->Append(&d, witness);
+ CallbacksDescriptor d(*factory()->arguments_symbol(), *args, attribs);
+ map->AppendDescriptor(&d, witness);
}
{ // Add caller.
- Handle<Foreign> f(factory()->NewForeign(&Accessors::FunctionCaller));
- CallbacksDescriptor d(*factory()->caller_symbol(), *f, attribs);
- descriptors->Append(&d, witness);
+ CallbacksDescriptor d(*factory()->caller_symbol(), *caller, attribs);
+ map->AppendDescriptor(&d, witness);
}
if (prototypeMode != DONT_ADD_PROTOTYPE) {
// Add prototype.
if (prototypeMode == ADD_WRITEABLE_PROTOTYPE) {
attribs = static_cast<PropertyAttributes>(attribs & ~READ_ONLY);
}
- Handle<Foreign> f(factory()->NewForeign(&Accessors::FunctionPrototype));
- CallbacksDescriptor d(*factory()->prototype_symbol(), *f, attribs);
- descriptors->Append(&d, witness);
+ CallbacksDescriptor d(*factory()->prototype_symbol(), *prototype, attribs);
+ map->AppendDescriptor(&d, witness);
}
-
- descriptors->Sort(witness);
- return descriptors;
}
Handle<Map> Genesis::CreateFunctionMap(PrototypePropertyMode prototype_mode) {
Handle<Map> map = factory()->NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
- Handle<DescriptorArray> descriptors =
- ComputeFunctionInstanceDescriptor(prototype_mode);
- map->set_instance_descriptors(*descriptors);
+ SetFunctionInstanceDescriptor(map, prototype_mode);
map->set_function_with_prototype(prototype_mode != DONT_ADD_PROTOTYPE);
return map;
}
@@ -485,8 +486,6 @@
global_context()->set_initial_object_prototype(*prototype);
SetPrototype(object_fun, prototype);
- object_function_map->set_instance_descriptors(
- heap->empty_descriptor_array());
}
// Allocate the empty function as the prototype for function ECMAScript
@@ -525,48 +524,48 @@
}
-Handle<DescriptorArray> Genesis::ComputeStrictFunctionInstanceDescriptor(
- PrototypePropertyMode prototypeMode) {
+void Genesis::SetStrictFunctionInstanceDescriptor(
+ Handle<Map> map, PrototypePropertyMode prototypeMode) {
int size = (prototypeMode == DONT_ADD_PROTOTYPE) ? 4 : 5;
Handle<DescriptorArray> descriptors(factory()->NewDescriptorArray(size));
- PropertyAttributes attribs = static_cast<PropertyAttributes>(
- DONT_ENUM | DONT_DELETE);
-
DescriptorArray::WhitenessWitness witness(*descriptors);
+ Handle<Foreign> length(factory()->NewForeign(&Accessors::FunctionLength));
+ Handle<Foreign> name(factory()->NewForeign(&Accessors::FunctionName));
+ Handle<AccessorPair> arguments(factory()->NewAccessorPair());
+ Handle<AccessorPair> caller(factory()->NewAccessorPair());
+ Handle<Foreign> prototype;
+ if (prototypeMode != DONT_ADD_PROTOTYPE) {
+ prototype = factory()->NewForeign(&Accessors::FunctionPrototype);
+ }
+ PropertyAttributes attribs = static_cast<PropertyAttributes>(
+ DONT_ENUM | DONT_DELETE);
+ map->set_instance_descriptors(*descriptors);
+
{ // Add length.
- Handle<Foreign> f(factory()->NewForeign(&Accessors::FunctionLength));
- CallbacksDescriptor d(*factory()->length_symbol(), *f, attribs);
- descriptors->Append(&d, witness);
+ CallbacksDescriptor d(*factory()->length_symbol(), *length, attribs);
+ map->AppendDescriptor(&d, witness);
}
{ // Add name.
- Handle<Foreign> f(factory()->NewForeign(&Accessors::FunctionName));
- CallbacksDescriptor d(*factory()->name_symbol(), *f, attribs);
- descriptors->Append(&d, witness);
+ CallbacksDescriptor d(*factory()->name_symbol(), *name, attribs);
+ map->AppendDescriptor(&d, witness);
}
{ // Add arguments.
- Handle<AccessorPair> arguments(factory()->NewAccessorPair());
CallbacksDescriptor d(*factory()->arguments_symbol(), *arguments, attribs);
- descriptors->Append(&d, witness);
+ map->AppendDescriptor(&d, witness);
}
{ // Add caller.
- Handle<AccessorPair> caller(factory()->NewAccessorPair());
CallbacksDescriptor d(*factory()->caller_symbol(), *caller, attribs);
- descriptors->Append(&d, witness);
+ map->AppendDescriptor(&d, witness);
}
-
if (prototypeMode != DONT_ADD_PROTOTYPE) {
// Add prototype.
if (prototypeMode != ADD_WRITEABLE_PROTOTYPE) {
attribs = static_cast<PropertyAttributes>(attribs | READ_ONLY);
}
- Handle<Foreign> f(factory()->NewForeign(&Accessors::FunctionPrototype));
- CallbacksDescriptor d(*factory()->prototype_symbol(), *f, attribs);
- descriptors->Append(&d, witness);
+ CallbacksDescriptor d(*factory()->prototype_symbol(), *prototype, attribs);
+ map->AppendDescriptor(&d, witness);
}
-
- descriptors->Sort(witness);
- return descriptors;
}
@@ -594,9 +593,7 @@
PrototypePropertyMode prototype_mode,
Handle<JSFunction> empty_function) {
Handle<Map> map = factory()->NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
- Handle<DescriptorArray> descriptors =
- ComputeStrictFunctionInstanceDescriptor(prototype_mode);
- map->set_instance_descriptors(*descriptors);
+ SetStrictFunctionInstanceDescriptor(map, prototype_mode);
map->set_function_with_prototype(prototype_mode != DONT_ADD_PROTOTYPE);
map->set_prototype(*empty_function);
return map;
@@ -869,19 +866,25 @@
// This seems a bit hackish, but we need to make sure Array.length
// is 1.
array_function->shared()->set_length(1);
- Handle<DescriptorArray> array_descriptors =
- factory->CopyAppendForeignDescriptor(
- factory->empty_descriptor_array(),
- factory->length_symbol(),
- factory->NewForeign(&Accessors::ArrayLength),
- static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE));
+
+ Handle<DescriptorArray> array_descriptors(factory->NewDescriptorArray(1));
+ DescriptorArray::WhitenessWitness witness(*array_descriptors);
+
+ Handle<Foreign> array_length(factory->NewForeign(&Accessors::ArrayLength));
+ PropertyAttributes attribs = static_cast<PropertyAttributes>(
+ DONT_ENUM | DONT_DELETE);
+ array_function->initial_map()->set_instance_descriptors(*array_descriptors);
+
+ { // Add length.
+ CallbacksDescriptor d(*factory->length_symbol(), *array_length, attribs);
+ array_function->initial_map()->AppendDescriptor(&d, witness);
+ }
// array_function is used internally. JS code creating array object should
// search for the 'Array' property on the global object and use that one
// as the constructor. 'Array' property on a global object can be
// overwritten by JS code.
global_context()->set_array_function(*array_function);
- array_function->initial_map()->set_instance_descriptors(*array_descriptors);
}
{ // --- N u m b e r ---
@@ -908,19 +911,22 @@
string_fun->shared()->set_construct_stub(
isolate->builtins()->builtin(Builtins::kStringConstructCode));
global_context()->set_string_function(*string_fun);
- // Add 'length' property to strings.
- Handle<DescriptorArray> string_descriptors =
- factory->CopyAppendForeignDescriptor(
- factory->empty_descriptor_array(),
- factory->length_symbol(),
- factory->NewForeign(&Accessors::StringLength),
- static_cast<PropertyAttributes>(DONT_ENUM |
- DONT_DELETE |
- READ_ONLY));
Handle<Map> string_map =
Handle<Map>(global_context()->string_function()->initial_map());
+ Handle<DescriptorArray> string_descriptors(factory->NewDescriptorArray(1));
+ DescriptorArray::WhitenessWitness witness(*string_descriptors);
+
+ Handle<Foreign> string_length(
+ factory->NewForeign(&Accessors::StringLength));
+ PropertyAttributes attribs = static_cast<PropertyAttributes>(
+ DONT_ENUM | DONT_DELETE | READ_ONLY);
string_map->set_instance_descriptors(*string_descriptors);
+
+ { // Add length.
+ CallbacksDescriptor d(*factory->length_symbol(), *string_length, attribs);
+ string_map->AppendDescriptor(&d, witness);
+ }
}
{ // --- D a t e ---
@@ -947,37 +953,39 @@
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);
+ Handle<DescriptorArray> descriptors = factory->NewDescriptorArray(5);
+ DescriptorArray::WhitenessWitness witness(*descriptors);
+ initial_map->set_instance_descriptors(*descriptors);
+
{
// ECMA-262, section 15.10.7.1.
FieldDescriptor field(heap->source_symbol(),
JSRegExp::kSourceFieldIndex,
final);
- descriptors->Append(&field, witness);
+ initial_map->AppendDescriptor(&field, witness);
}
{
// ECMA-262, section 15.10.7.2.
FieldDescriptor field(heap->global_symbol(),
JSRegExp::kGlobalFieldIndex,
final);
- descriptors->Append(&field, witness);
+ initial_map->AppendDescriptor(&field, witness);
}
{
// ECMA-262, section 15.10.7.3.
FieldDescriptor field(heap->ignore_case_symbol(),
JSRegExp::kIgnoreCaseFieldIndex,
final);
- descriptors->Append(&field, witness);
+ initial_map->AppendDescriptor(&field, witness);
}
{
// ECMA-262, section 15.10.7.4.
FieldDescriptor field(heap->multiline_symbol(),
JSRegExp::kMultilineFieldIndex,
final);
- descriptors->Append(&field, witness);
+ initial_map->AppendDescriptor(&field, witness);
}
{
// ECMA-262, section 15.10.7.5.
@@ -986,16 +994,14 @@
FieldDescriptor field(heap->last_index_symbol(),
JSRegExp::kLastIndexFieldIndex,
writable);
- descriptors->Append(&field, witness);
+ initial_map->AppendDescriptor(&field, witness);
}
- descriptors->Sort(witness);
initial_map->set_inobject_properties(5);
initial_map->set_pre_allocated_property_fields(5);
initial_map->set_unused_property_fields(0);
initial_map->set_instance_size(
initial_map->instance_size() + 5 * kPointerSize);
- initial_map->set_instance_descriptors(*descriptors);
initial_map->set_visitor_id(StaticVisitorBase::GetVisitorId(*initial_map));
// RegExp prototype object is itself a RegExp.
@@ -1129,31 +1135,31 @@
caller->set_getter(*throw_function);
caller->set_setter(*throw_function);
+ // Create the map. Allocate one in-object field for length.
+ Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE,
+ Heap::kArgumentsObjectSizeStrict);
// Create the descriptor array for the arguments object.
Handle<DescriptorArray> descriptors = factory->NewDescriptorArray(3);
DescriptorArray::WhitenessWitness witness(*descriptors);
+ map->set_instance_descriptors(*descriptors);
+
{ // length
FieldDescriptor d(*factory->length_symbol(), 0, DONT_ENUM);
- descriptors->Append(&d, witness);
+ map->AppendDescriptor(&d, witness);
}
{ // callee
CallbacksDescriptor d(*factory->callee_symbol(),
*callee,
attributes);
- descriptors->Append(&d, witness);
+ map->AppendDescriptor(&d, witness);
}
{ // caller
CallbacksDescriptor d(*factory->caller_symbol(),
*caller,
attributes);
- descriptors->Append(&d, witness);
+ map->AppendDescriptor(&d, witness);
}
- descriptors->Sort(witness);
- // Create the map. Allocate one in-object field for length.
- Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE,
- Heap::kArgumentsObjectSizeStrict);
- map->set_instance_descriptors(*descriptors);
map->set_function_with_prototype(true);
map->set_prototype(global_context()->object_function()->prototype());
map->set_pre_allocated_property_fields(1);
@@ -1472,116 +1478,132 @@
SetPrototype(script_fun, prototype);
global_context()->set_script_function(*script_fun);
- // Add 'source' and 'data' property to scripts.
- PropertyAttributes common_attributes =
- static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
- Handle<Foreign> foreign_source =
- factory()->NewForeign(&Accessors::ScriptSource);
- Handle<DescriptorArray> script_descriptors =
- factory()->CopyAppendForeignDescriptor(
- factory()->empty_descriptor_array(),
- factory()->LookupAsciiSymbol("source"),
- foreign_source,
- common_attributes);
- Handle<Foreign> foreign_name =
- factory()->NewForeign(&Accessors::ScriptName);
- script_descriptors =
- factory()->CopyAppendForeignDescriptor(
- script_descriptors,
- factory()->LookupAsciiSymbol("name"),
- foreign_name,
- common_attributes);
- Handle<Foreign> foreign_id = factory()->NewForeign(&Accessors::ScriptId);
- script_descriptors =
- factory()->CopyAppendForeignDescriptor(
- script_descriptors,
- factory()->LookupAsciiSymbol("id"),
- foreign_id,
- common_attributes);
- Handle<Foreign> foreign_line_offset =
- factory()->NewForeign(&Accessors::ScriptLineOffset);
- script_descriptors =
- factory()->CopyAppendForeignDescriptor(
- script_descriptors,
- factory()->LookupAsciiSymbol("line_offset"),
- foreign_line_offset,
- common_attributes);
- Handle<Foreign> foreign_column_offset =
- factory()->NewForeign(&Accessors::ScriptColumnOffset);
- script_descriptors =
- factory()->CopyAppendForeignDescriptor(
- script_descriptors,
- factory()->LookupAsciiSymbol("column_offset"),
- foreign_column_offset,
- common_attributes);
- Handle<Foreign> foreign_data =
- factory()->NewForeign(&Accessors::ScriptData);
- script_descriptors =
- factory()->CopyAppendForeignDescriptor(
- script_descriptors,
- factory()->LookupAsciiSymbol("data"),
- foreign_data,
- common_attributes);
- Handle<Foreign> foreign_type =
- factory()->NewForeign(&Accessors::ScriptType);
- script_descriptors =
- factory()->CopyAppendForeignDescriptor(
- script_descriptors,
- factory()->LookupAsciiSymbol("type"),
- foreign_type,
- common_attributes);
- Handle<Foreign> foreign_compilation_type =
- factory()->NewForeign(&Accessors::ScriptCompilationType);
- script_descriptors =
- factory()->CopyAppendForeignDescriptor(
- script_descriptors,
- factory()->LookupAsciiSymbol("compilation_type"),
- foreign_compilation_type,
- common_attributes);
- Handle<Foreign> foreign_line_ends =
- factory()->NewForeign(&Accessors::ScriptLineEnds);
- script_descriptors =
- factory()->CopyAppendForeignDescriptor(
- script_descriptors,
- factory()->LookupAsciiSymbol("line_ends"),
- foreign_line_ends,
- common_attributes);
- Handle<Foreign> foreign_context_data =
- factory()->NewForeign(&Accessors::ScriptContextData);
- script_descriptors =
- factory()->CopyAppendForeignDescriptor(
- script_descriptors,
- factory()->LookupAsciiSymbol("context_data"),
- foreign_context_data,
- common_attributes);
- Handle<Foreign> foreign_eval_from_script =
- factory()->NewForeign(&Accessors::ScriptEvalFromScript);
- script_descriptors =
- factory()->CopyAppendForeignDescriptor(
- script_descriptors,
- factory()->LookupAsciiSymbol("eval_from_script"),
- foreign_eval_from_script,
- common_attributes);
- Handle<Foreign> foreign_eval_from_script_position =
- factory()->NewForeign(&Accessors::ScriptEvalFromScriptPosition);
- script_descriptors =
- factory()->CopyAppendForeignDescriptor(
- script_descriptors,
- factory()->LookupAsciiSymbol("eval_from_script_position"),
- foreign_eval_from_script_position,
- common_attributes);
- Handle<Foreign> foreign_eval_from_function_name =
- factory()->NewForeign(&Accessors::ScriptEvalFromFunctionName);
- script_descriptors =
- factory()->CopyAppendForeignDescriptor(
- script_descriptors,
- factory()->LookupAsciiSymbol("eval_from_function_name"),
- foreign_eval_from_function_name,
- common_attributes);
-
Handle<Map> script_map = Handle<Map>(script_fun->initial_map());
+
+ Handle<DescriptorArray> script_descriptors(
+ factory()->NewDescriptorArray(13));
+ DescriptorArray::WhitenessWitness witness(*script_descriptors);
+
+ Handle<Foreign> script_source(
+ factory()->NewForeign(&Accessors::ScriptSource));
+ Handle<Foreign> script_name(factory()->NewForeign(&Accessors::ScriptName));
+ Handle<String> id_symbol(factory()->LookupAsciiSymbol("id"));
+ Handle<Foreign> script_id(factory()->NewForeign(&Accessors::ScriptId));
+ Handle<String> line_offset_symbol(
+ factory()->LookupAsciiSymbol("line_offset"));
+ Handle<Foreign> script_line_offset(
+ factory()->NewForeign(&Accessors::ScriptLineOffset));
+ Handle<String> column_offset_symbol(
+ factory()->LookupAsciiSymbol("column_offset"));
+ Handle<Foreign> script_column_offset(
+ factory()->NewForeign(&Accessors::ScriptColumnOffset));
+ Handle<String> data_symbol(factory()->LookupAsciiSymbol("data"));
+ Handle<Foreign> script_data(factory()->NewForeign(&Accessors::ScriptData));
+ Handle<String> type_symbol(factory()->LookupAsciiSymbol("type"));
+ Handle<Foreign> script_type(factory()->NewForeign(&Accessors::ScriptType));
+ Handle<String> compilation_type_symbol(
+ factory()->LookupAsciiSymbol("compilation_type"));
+ Handle<Foreign> script_compilation_type(
+ factory()->NewForeign(&Accessors::ScriptCompilationType));
+ Handle<String> line_ends_symbol(factory()->LookupAsciiSymbol("line_ends"));
+ Handle<Foreign> script_line_ends(
+ factory()->NewForeign(&Accessors::ScriptLineEnds));
+ Handle<String> context_data_symbol(
+ factory()->LookupAsciiSymbol("context_data"));
+ Handle<Foreign> script_context_data(
+ factory()->NewForeign(&Accessors::ScriptContextData));
+ Handle<String> eval_from_script_symbol(
+ factory()->LookupAsciiSymbol("eval_from_script"));
+ Handle<Foreign> script_eval_from_script(
+ factory()->NewForeign(&Accessors::ScriptEvalFromScript));
+ Handle<String> eval_from_script_position_symbol(
+ factory()->LookupAsciiSymbol("eval_from_script_position"));
+ Handle<Foreign> script_eval_from_script_position(
+ factory()->NewForeign(&Accessors::ScriptEvalFromScriptPosition));
+ Handle<String> eval_from_function_name_symbol(
+ factory()->LookupAsciiSymbol("eval_from_function_name"));
+ Handle<Foreign> script_eval_from_function_name(
+ factory()->NewForeign(&Accessors::ScriptEvalFromFunctionName));
+ PropertyAttributes attribs =
+ static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
script_map->set_instance_descriptors(*script_descriptors);
+ {
+ CallbacksDescriptor d(
+ *factory()->source_symbol(), *script_source, attribs);
+ script_map->AppendDescriptor(&d, witness);
+ }
+
+ {
+ CallbacksDescriptor d(*factory()->name_symbol(), *script_name, attribs);
+ script_map->AppendDescriptor(&d, witness);
+ }
+
+ {
+ CallbacksDescriptor d(*id_symbol, *script_id, attribs);
+ script_map->AppendDescriptor(&d, witness);
+ }
+
+ {
+ CallbacksDescriptor d(*line_offset_symbol, *script_line_offset, attribs);
+ script_map->AppendDescriptor(&d, witness);
+ }
+
+ {
+ CallbacksDescriptor d(
+ *column_offset_symbol, *script_column_offset, attribs);
+ script_map->AppendDescriptor(&d, witness);
+ }
+
+ {
+ CallbacksDescriptor d(*data_symbol, *script_data, attribs);
+ script_map->AppendDescriptor(&d, witness);
+ }
+
+ {
+ CallbacksDescriptor d(*type_symbol, *script_type, attribs);
+ script_map->AppendDescriptor(&d, witness);
+ }
+
+ {
+ CallbacksDescriptor d(
+ *compilation_type_symbol, *script_compilation_type, attribs);
+ script_map->AppendDescriptor(&d, witness);
+ }
+
+ {
+ CallbacksDescriptor d(*line_ends_symbol, *script_line_ends, attribs);
+ script_map->AppendDescriptor(&d, witness);
+ }
+
+ {
+ CallbacksDescriptor d(
+ *context_data_symbol, *script_context_data, attribs);
+ script_map->AppendDescriptor(&d, witness);
+ }
+
+ {
+ CallbacksDescriptor d(
+ *eval_from_script_symbol, *script_eval_from_script, attribs);
+ script_map->AppendDescriptor(&d, witness);
+ }
+
+ {
+ CallbacksDescriptor d(
+ *eval_from_script_position_symbol,
+ *script_eval_from_script_position,
+ attribs);
+ script_map->AppendDescriptor(&d, witness);
+ }
+
+ {
+ CallbacksDescriptor d(
+ *eval_from_function_name_symbol,
+ *script_eval_from_function_name,
+ attribs);
+ script_map->AppendDescriptor(&d, witness);
+ }
+
// Allocate the empty script.
Handle<Script> script = factory()->NewScript(factory()->empty_string());
script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
@@ -1637,15 +1659,20 @@
array_function->set_initial_map(new_map);
// Make "length" magic on instances.
- Handle<DescriptorArray> array_descriptors =
- factory()->CopyAppendForeignDescriptor(
- factory()->empty_descriptor_array(),
- factory()->length_symbol(),
- factory()->NewForeign(&Accessors::ArrayLength),
- static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE));
+ Handle<DescriptorArray> array_descriptors(factory()->NewDescriptorArray(1));
+ DescriptorArray::WhitenessWitness witness(*array_descriptors);
- array_function->initial_map()->set_instance_descriptors(
- *array_descriptors);
+ Handle<Foreign> array_length(factory()->NewForeign(
+ &Accessors::ArrayLength));
+ PropertyAttributes attribs = static_cast<PropertyAttributes>(
+ DONT_ENUM | DONT_DELETE);
+ array_function->initial_map()->set_instance_descriptors(*array_descriptors);
+
+ { // Add length.
+ CallbacksDescriptor d(
+ *factory()->length_symbol(), *array_length, attribs);
+ array_function->initial_map()->AppendDescriptor(&d, witness);
+ }
global_context()->set_internal_array_function(*array_function);
}
@@ -1734,34 +1761,37 @@
Handle<DescriptorArray> reresult_descriptors =
factory()->NewDescriptorArray(3);
DescriptorArray::WhitenessWitness witness(*reresult_descriptors);
+ initial_map->set_instance_descriptors(*reresult_descriptors);
- JSFunction* array_function = global_context()->array_function();
- Handle<DescriptorArray> array_descriptors(
- array_function->initial_map()->instance_descriptors());
- int old = array_descriptors->SearchWithCache(heap()->length_symbol());
- reresult_descriptors->CopyFrom(0, *array_descriptors, old, witness);
-
- reresult_descriptors->SetLastAdded(0);
-
+ {
+ JSFunction* array_function = global_context()->array_function();
+ Handle<DescriptorArray> array_descriptors(
+ array_function->initial_map()->instance_descriptors());
+ String* length = heap()->length_symbol();
+ int old = array_descriptors->SearchWithCache(length);
+ ASSERT(old != DescriptorArray::kNotFound);
+ CallbacksDescriptor desc(length,
+ array_descriptors->GetValue(old),
+ array_descriptors->GetDetails(old).attributes());
+ initial_map->AppendDescriptor(&desc, witness);
+ }
{
FieldDescriptor index_field(heap()->index_symbol(),
JSRegExpResult::kIndexIndex,
NONE);
- reresult_descriptors->Append(&index_field, witness);
+ initial_map->AppendDescriptor(&index_field, witness);
}
{
FieldDescriptor input_field(heap()->input_symbol(),
JSRegExpResult::kInputIndex,
NONE);
- reresult_descriptors->Append(&input_field, witness);
+ initial_map->AppendDescriptor(&input_field, witness);
}
- reresult_descriptors->Sort(witness);
initial_map->set_inobject_properties(2);
initial_map->set_pre_allocated_property_fields(2);
initial_map->set_unused_property_fields(0);
- initial_map->set_instance_descriptors(*reresult_descriptors);
global_context()->set_regexp_result_map(*initial_map);
}
@@ -1997,6 +2027,9 @@
if (FLAG_expose_externalize_string) {
InstallExtension("v8/externalize", &extension_states);
}
+ if (FLAG_track_gc_object_stats) {
+ InstallExtension("v8/statistics", &extension_states);
+ }
if (extensions == NULL) return true;
// Install required extensions
diff --git a/src/builtins.h b/src/builtins.h
index 3ea3393..c0a850a 100644
--- a/src/builtins.h
+++ b/src/builtins.h
@@ -66,6 +66,8 @@
#define BUILTIN_LIST_A(V) \
V(ArgumentsAdaptorTrampoline, BUILTIN, UNINITIALIZED, \
Code::kNoExtraICState) \
+ V(InRecompileQueue, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
V(JSConstructStubCountdown, BUILTIN, UNINITIALIZED, \
Code::kNoExtraICState) \
V(JSConstructStubGeneric, BUILTIN, UNINITIALIZED, \
@@ -80,6 +82,8 @@
Code::kNoExtraICState) \
V(LazyRecompile, BUILTIN, UNINITIALIZED, \
Code::kNoExtraICState) \
+ V(ParallelRecompile, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
V(NotifyDeoptimized, BUILTIN, UNINITIALIZED, \
Code::kNoExtraICState) \
V(NotifyLazyDeoptimized, BUILTIN, UNINITIALIZED, \
@@ -347,6 +351,8 @@
static void Generate_Adaptor(MacroAssembler* masm,
CFunctionId id,
BuiltinExtraArguments extra_args);
+ static void Generate_InRecompileQueue(MacroAssembler* masm);
+ static void Generate_ParallelRecompile(MacroAssembler* masm);
static void Generate_JSConstructStubCountdown(MacroAssembler* masm);
static void Generate_JSConstructStubGeneric(MacroAssembler* masm);
static void Generate_JSConstructStubApi(MacroAssembler* masm);
diff --git a/src/compiler.cc b/src/compiler.cc
index f93ce6b..998f1bc 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -207,6 +207,7 @@
}
status = compiler.OptimizeGraph();
if (status != OptimizingCompiler::SUCCEEDED) {
+ status = compiler.AbortOptimization();
return status != OptimizingCompiler::FAILED;
}
status = compiler.GenerateAndInstallCode();
@@ -340,17 +341,20 @@
}
OptimizingCompiler::Status OptimizingCompiler::OptimizeGraph() {
+ AssertNoAllocation no_gc;
+ NoHandleAllocation no_handles;
+
ASSERT(last_status() == SUCCEEDED);
Timer t(this, &time_taken_to_optimize_);
ASSERT(graph_ != NULL);
SmartArrayPointer<char> bailout_reason;
if (!graph_->Optimize(&bailout_reason)) {
if (!bailout_reason.is_empty()) graph_builder_->Bailout(*bailout_reason);
- return AbortOptimization();
+ return SetLastStatus(BAILED_OUT);
} else {
chunk_ = LChunk::NewChunk(graph_);
if (chunk_ == NULL) {
- return AbortOptimization();
+ return SetLastStatus(BAILED_OUT);
}
}
return SetLastStatus(SUCCEEDED);
@@ -658,21 +662,90 @@
}
-bool Compiler::CompileLazy(CompilationInfo* info) {
- Isolate* isolate = info->isolate();
-
- ZoneScope zone_scope(info->zone(), DELETE_ON_EXIT);
-
- // The VM is in the COMPILER state until exiting this function.
- VMState state(isolate, COMPILER);
-
- PostponeInterruptsScope postpone(isolate);
-
+static bool InstallFullCode(CompilationInfo* info) {
+ // Update the shared function info with the compiled code and the
+ // scope info. Please note, that the order of the shared function
+ // info initialization is important since set_scope_info might
+ // trigger a GC, causing the ASSERT below to be invalid if the code
+ // was flushed. By setting the code object last we avoid this.
Handle<SharedFunctionInfo> shared = info->shared_info();
- int compiled_size = shared->end_position() - shared->start_position();
- isolate->counters()->total_compile_size()->Increment(compiled_size);
+ Handle<Code> code = info->code();
+ Handle<JSFunction> function = info->closure();
+ Handle<ScopeInfo> scope_info =
+ ScopeInfo::Create(info->scope(), info->zone());
+ shared->set_scope_info(*scope_info);
+ shared->set_code(*code);
+ if (!function.is_null()) {
+ function->ReplaceCode(*code);
+ ASSERT(!function->IsOptimized());
+ }
+ // Set the expected number of properties for instances.
+ FunctionLiteral* lit = info->function();
+ int expected = lit->expected_property_count();
+ SetExpectedNofPropertiesFromEstimate(shared, expected);
+
+ // Set the optimization hints after performing lazy compilation, as
+ // these are not set when the function is set up as a lazily
+ // compiled function.
+ shared->SetThisPropertyAssignmentsInfo(
+ lit->has_only_simple_this_property_assignments(),
+ *lit->this_property_assignments());
+
+ // Check the function has compiled code.
+ ASSERT(shared->is_compiled());
+ shared->set_code_age(0);
+ shared->set_dont_optimize(lit->flags()->Contains(kDontOptimize));
+ shared->set_dont_inline(lit->flags()->Contains(kDontInline));
+ shared->set_ast_node_count(lit->ast_node_count());
+
+ if (V8::UseCrankshaft()&&
+ !function.is_null() &&
+ !shared->optimization_disabled()) {
+ // If we're asked to always optimize, we compile the optimized
+ // version of the function right away - unless the debugger is
+ // active as it makes no sense to compile optimized code then.
+ if (FLAG_always_opt &&
+ !Isolate::Current()->DebuggerHasBreakPoints()) {
+ CompilationInfoWithZone optimized(function);
+ optimized.SetOptimizing(AstNode::kNoNumber);
+ return Compiler::CompileLazy(&optimized);
+ }
+ }
+ return true;
+}
+
+
+static void InstallCodeCommon(CompilationInfo* info) {
+ Handle<SharedFunctionInfo> shared = info->shared_info();
+ Handle<Code> code = info->code();
+ ASSERT(!code.is_null());
+
+ // Set optimizable to false if this is disallowed by the shared
+ // function info, e.g., we might have flushed the code and must
+ // reset this bit when lazy compiling the code again.
+ if (shared->optimization_disabled()) code->set_optimizable(false);
+
+ Compiler::RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info, shared);
+}
+
+
+static void InsertCodeIntoOptimizedCodeMap(CompilationInfo* info) {
+ Handle<Code> code = info->code();
+ Handle<JSFunction> function = info->closure();
+ if (FLAG_cache_optimized_code && code->kind() == Code::OPTIMIZED_FUNCTION) {
+ Handle<SharedFunctionInfo> shared(function->shared());
+ Handle<FixedArray> literals(function->literals());
+ Handle<Context> global_context(function->context()->global_context());
+ SharedFunctionInfo::AddToOptimizedCodeMap(
+ shared, global_context, code, literals);
+ }
+}
+
+
+static bool InstallCodeFromOptimizedCodeMap(CompilationInfo* info) {
if (FLAG_cache_optimized_code && info->IsOptimizing()) {
+ Handle<SharedFunctionInfo> shared = info->shared_info();
Handle<JSFunction> function = info->closure();
ASSERT(!function.is_null());
Handle<Context> global_context(function->context()->global_context());
@@ -688,6 +761,25 @@
return true;
}
}
+ return false;
+}
+
+
+bool Compiler::CompileLazy(CompilationInfo* info) {
+ Isolate* isolate = info->isolate();
+
+ ZoneScope zone_scope(info->zone(), DELETE_ON_EXIT);
+
+ // The VM is in the COMPILER state until exiting this function.
+ VMState state(isolate, COMPILER);
+
+ PostponeInterruptsScope postpone(isolate);
+
+ Handle<SharedFunctionInfo> shared = info->shared_info();
+ int compiled_size = shared->end_position() - shared->start_position();
+ isolate->counters()->total_compile_size()->Increment(compiled_size);
+
+ if (InstallCodeFromOptimizedCodeMap(info)) return true;
// Generate the AST for the lazily compiled function.
if (ParserApi::Parse(info, kNoParsingFlags)) {
@@ -707,78 +799,17 @@
isolate->StackOverflow();
}
} else {
- ASSERT(!info->code().is_null());
- Handle<Code> code = info->code();
- // Set optimizable to false if this is disallowed by the shared
- // function info, e.g., we might have flushed the code and must
- // reset this bit when lazy compiling the code again.
- if (shared->optimization_disabled()) code->set_optimizable(false);
-
- Handle<JSFunction> function = info->closure();
- RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info, shared);
+ InstallCodeCommon(info);
if (info->IsOptimizing()) {
+ Handle<Code> code = info->code();
ASSERT(shared->scope_info() != ScopeInfo::Empty());
- function->ReplaceCode(*code);
- if (FLAG_cache_optimized_code &&
- code->kind() == Code::OPTIMIZED_FUNCTION) {
- Handle<SharedFunctionInfo> shared(function->shared());
- Handle<FixedArray> literals(function->literals());
- Handle<Context> global_context(function->context()->global_context());
- SharedFunctionInfo::AddToOptimizedCodeMap(
- shared, global_context, code, literals);
- }
+ info->closure()->ReplaceCode(*code);
+ InsertCodeIntoOptimizedCodeMap(info);
+ return true;
} else {
- // Update the shared function info with the compiled code and the
- // scope info. Please note, that the order of the shared function
- // info initialization is important since set_scope_info might
- // trigger a GC, causing the ASSERT below to be invalid if the code
- // was flushed. By setting the code object last we avoid this.
- Handle<ScopeInfo> scope_info =
- ScopeInfo::Create(info->scope(), info->zone());
- shared->set_scope_info(*scope_info);
- shared->set_code(*code);
- if (!function.is_null()) {
- function->ReplaceCode(*code);
- ASSERT(!function->IsOptimized());
- }
-
- // Set the expected number of properties for instances.
- FunctionLiteral* lit = info->function();
- int expected = lit->expected_property_count();
- SetExpectedNofPropertiesFromEstimate(shared, expected);
-
- // Set the optimization hints after performing lazy compilation, as
- // these are not set when the function is set up as a lazily
- // compiled function.
- shared->SetThisPropertyAssignmentsInfo(
- lit->has_only_simple_this_property_assignments(),
- *lit->this_property_assignments());
-
- // Check the function has compiled code.
- ASSERT(shared->is_compiled());
- shared->set_code_age(0);
- shared->set_dont_optimize(lit->flags()->Contains(kDontOptimize));
- shared->set_dont_inline(lit->flags()->Contains(kDontInline));
- shared->set_dont_cache(lit->flags()->Contains(kDontCache));
- shared->set_ast_node_count(lit->ast_node_count());
-
- if (V8::UseCrankshaft()&&
- !function.is_null() &&
- !shared->optimization_disabled()) {
- // If we're asked to always optimize, we compile the optimized
- // version of the function right away - unless the debugger is
- // active as it makes no sense to compile optimized code then.
- if (FLAG_always_opt &&
- !Isolate::Current()->DebuggerHasBreakPoints()) {
- CompilationInfoWithZone optimized(function);
- optimized.SetOptimizing(AstNode::kNoNumber);
- return CompileLazy(&optimized);
- }
- }
+ return InstallFullCode(info);
}
-
- return true;
}
}
@@ -787,6 +818,91 @@
}
+void Compiler::RecompileParallel(Handle<JSFunction> closure) {
+ if (closure->IsInRecompileQueue()) return;
+ ASSERT(closure->IsMarkedForParallelRecompilation());
+
+ Isolate* isolate = closure->GetIsolate();
+ if (!isolate->optimizing_compiler_thread()->IsQueueAvailable()) {
+ if (FLAG_trace_parallel_recompilation) {
+ PrintF(" ** Compilation queue, will retry opting on next run.\n");
+ }
+ return;
+ }
+
+ SmartPointer<CompilationInfo> info(new CompilationInfoWithZone(closure));
+ VMState state(isolate, PARALLEL_COMPILER_PROLOGUE);
+ PostponeInterruptsScope postpone(isolate);
+
+ Handle<SharedFunctionInfo> shared = info->shared_info();
+ int compiled_size = shared->end_position() - shared->start_position();
+ isolate->counters()->total_compile_size()->Increment(compiled_size);
+ info->SetOptimizing(AstNode::kNoNumber);
+
+ {
+ CompilationHandleScope handle_scope(*info);
+
+ if (InstallCodeFromOptimizedCodeMap(*info)) return;
+
+ if (ParserApi::Parse(*info, kNoParsingFlags)) {
+ LanguageMode language_mode = info->function()->language_mode();
+ info->SetLanguageMode(language_mode);
+ shared->set_language_mode(language_mode);
+ info->SaveHandles();
+
+ if (Rewriter::Rewrite(*info) && Scope::Analyze(*info)) {
+ OptimizingCompiler* compiler =
+ new(info->zone()) OptimizingCompiler(*info);
+ OptimizingCompiler::Status status = compiler->CreateGraph();
+ if (status == OptimizingCompiler::SUCCEEDED) {
+ isolate->optimizing_compiler_thread()->QueueForOptimization(compiler);
+ shared->code()->set_profiler_ticks(0);
+ closure->ReplaceCode(isolate->builtins()->builtin(
+ Builtins::kInRecompileQueue));
+ info.Detach();
+ } else if (status == OptimizingCompiler::BAILED_OUT) {
+ isolate->clear_pending_exception();
+ InstallFullCode(*info);
+ }
+ }
+ }
+ }
+
+ if (isolate->has_pending_exception()) {
+ isolate->clear_pending_exception();
+ }
+}
+
+
+void Compiler::InstallOptimizedCode(OptimizingCompiler* optimizing_compiler) {
+ SmartPointer<CompilationInfo> info(optimizing_compiler->info());
+ // If crankshaft succeeded, install the optimized code else install
+ // the unoptimized code.
+ OptimizingCompiler::Status status = optimizing_compiler->last_status();
+ if (status != OptimizingCompiler::SUCCEEDED) {
+ status = optimizing_compiler->AbortOptimization();
+ } else {
+ status = optimizing_compiler->GenerateAndInstallCode();
+ ASSERT(status == OptimizingCompiler::SUCCEEDED ||
+ status == OptimizingCompiler::BAILED_OUT);
+ }
+
+ InstallCodeCommon(*info);
+ if (status == OptimizingCompiler::SUCCEEDED) {
+ Handle<Code> code = info->code();
+ ASSERT(info->shared_info()->scope_info() != ScopeInfo::Empty());
+ info->closure()->ReplaceCode(*code);
+ if (info->shared_info()->SearchOptimizedCodeMap(
+ info->closure()->context()->global_context()) == -1) {
+ InsertCodeIntoOptimizedCodeMap(*info);
+ }
+ } else {
+ info->SetCode(Handle<Code>(info->shared_info()->code()));
+ InstallFullCode(*info);
+ }
+}
+
+
Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal,
Handle<Script> script) {
// Precondition: code has been parsed and scopes have been analyzed.
diff --git a/src/compiler.h b/src/compiler.h
index 6df21de..5465a2d 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -39,7 +39,7 @@
// CompilationInfo encapsulates some information known at compile time. It
// is constructed based on the resources available at compile-time.
-class CompilationInfo BASE_EMBEDDED {
+class CompilationInfo {
public:
CompilationInfo(Handle<Script> script, Zone* zone);
CompilationInfo(Handle<SharedFunctionInfo> shared_info, Zone* zone);
@@ -180,6 +180,13 @@
deferred_handles_ = deferred_handles;
}
+ void SaveHandles() {
+ SaveHandle(&closure_);
+ SaveHandle(&shared_info_);
+ SaveHandle(&calling_context_);
+ SaveHandle(&script_);
+ }
+
private:
Isolate* isolate_;
@@ -268,6 +275,14 @@
DeferredHandles* deferred_handles_;
+ template<typename T>
+ void SaveHandle(Handle<T> *object) {
+ if (!object->is_null()) {
+ Handle<T> handle(*(*object));
+ *object = handle;
+ }
+ }
+
DISALLOW_COPY_AND_ASSIGN(CompilationInfo);
};
@@ -346,6 +361,12 @@
Status last_status() const { return last_status_; }
CompilationInfo* info() const { return info_; }
+ MUST_USE_RESULT Status AbortOptimization() {
+ info_->AbortOptimization();
+ info_->shared_info()->DisableOptimization();
+ return SetLastStatus(BAILED_OUT);
+ }
+
private:
CompilationInfo* info_;
TypeFeedbackOracle* oracle_;
@@ -362,11 +383,6 @@
return last_status_;
}
void RecordOptimizationStats();
- MUST_USE_RESULT Status AbortOptimization() {
- info_->AbortOptimization();
- info_->shared_info()->DisableOptimization();
- return SetLastStatus(BAILED_OUT);
- }
struct Timer {
Timer(OptimizingCompiler* compiler, int64_t* location)
@@ -432,6 +448,8 @@
// success and false if the compilation resulted in a stack overflow.
static bool CompileLazy(CompilationInfo* info);
+ static void RecompileParallel(Handle<JSFunction> function);
+
// Compile a shared function info object (the function is possibly lazily
// compiled).
static Handle<SharedFunctionInfo> BuildFunctionInfo(FunctionLiteral* node,
@@ -443,6 +461,8 @@
bool is_toplevel,
Handle<Script> script);
+ static void InstallOptimizedCode(OptimizingCompiler* info);
+
#ifdef ENABLE_DEBUGGER_SUPPORT
static bool MakeCodeForLiveEdit(CompilationInfo* info);
#endif
diff --git a/src/conversions-inl.h b/src/conversions-inl.h
index 77b260f..a98680f 100644
--- a/src/conversions-inl.h
+++ b/src/conversions-inl.h
@@ -459,16 +459,23 @@
int insignificant_digits = 0;
bool nonzero_digit_dropped = false;
- bool negative = false;
+ enum Sign {
+ NONE,
+ NEGATIVE,
+ POSITIVE
+ };
+
+ Sign sign = NONE;
if (*current == '+') {
// Ignore leading sign.
++current;
if (current == end) return JunkStringValue();
+ sign = POSITIVE;
} else if (*current == '-') {
++current;
if (current == end) return JunkStringValue();
- negative = true;
+ sign = NEGATIVE;
}
static const char kInfinitySymbol[] = "Infinity";
@@ -483,34 +490,34 @@
}
ASSERT(buffer_pos == 0);
- return negative ? -V8_INFINITY : V8_INFINITY;
+ return (sign == NEGATIVE) ? -V8_INFINITY : V8_INFINITY;
}
bool leading_zero = false;
if (*current == '0') {
++current;
- if (current == end) return SignedZero(negative);
+ if (current == end) return SignedZero(sign == NEGATIVE);
leading_zero = true;
// It could be hexadecimal value.
if ((flags & ALLOW_HEX) && (*current == 'x' || *current == 'X')) {
++current;
- if (current == end || !isDigit(*current, 16)) {
+ if (current == end || !isDigit(*current, 16) || sign != NONE) {
return JunkStringValue(); // "0x".
}
return InternalStringToIntDouble<4>(unicode_cache,
current,
end,
- negative,
+ false,
allow_trailing_junk);
}
// Ignore leading zeros in the integer part.
while (*current == '0') {
++current;
- if (current == end) return SignedZero(negative);
+ if (current == end) return SignedZero(sign == NEGATIVE);
}
}
@@ -555,7 +562,7 @@
// leading zeros (if any).
while (*current == '0') {
++current;
- if (current == end) return SignedZero(negative);
+ if (current == end) return SignedZero(sign == NEGATIVE);
exponent--; // Move this 0 into the exponent.
}
}
@@ -647,7 +654,7 @@
return InternalStringToIntDouble<3>(unicode_cache,
buffer,
buffer + buffer_pos,
- negative,
+ sign == NEGATIVE,
allow_trailing_junk);
}
@@ -660,7 +667,7 @@
buffer[buffer_pos] = '\0';
double converted = Strtod(Vector<const char>(buffer, buffer_pos), exponent);
- return negative ? -converted : converted;
+ return (sign == NEGATIVE) ? -converted : converted;
}
} } // namespace v8::internal
diff --git a/src/d8.cc b/src/d8.cc
index 804b76c..c716c1c 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -1211,7 +1211,7 @@
// Set up counters
if (i::StrLength(i::FLAG_map_counters) != 0)
MapCounters(i::FLAG_map_counters);
- if (i::FLAG_dump_counters) {
+ if (i::FLAG_dump_counters || i::FLAG_track_gc_object_stats) {
V8::SetCounterFunction(LookupCounter);
V8::SetCreateHistogramFunction(CreateHistogram);
V8::SetAddHistogramSampleFunction(AddHistogramSample);
diff --git a/src/d8.h b/src/d8.h
index 5f356a6..9e88eca 100644
--- a/src/d8.h
+++ b/src/d8.h
@@ -31,7 +31,7 @@
#ifndef V8_SHARED
#include "allocation.h"
#include "hashmap.h"
-#include "smart-array-pointer.h"
+#include "smart-pointers.h"
#include "v8.h"
#else
#include "../include/v8.h"
diff --git a/src/execution.cc b/src/execution.cc
index 2613c20..512de4c 100644
--- a/src/execution.cc
+++ b/src/execution.cc
@@ -446,6 +446,25 @@
}
+void StackGuard::RequestCodeReadyEvent() {
+ ASSERT(FLAG_parallel_recompilation);
+ if (ExecutionAccess::TryLock(isolate_)) {
+ thread_local_.interrupt_flags_ |= CODE_READY;
+ if (thread_local_.postpone_interrupts_nesting_ == 0) {
+ thread_local_.jslimit_ = thread_local_.climit_ = kInterruptLimit;
+ isolate_->heap()->SetStackLimits();
+ }
+ ExecutionAccess::Unlock(isolate_);
+ }
+}
+
+
+bool StackGuard::IsCodeReadyEvent() {
+ ExecutionAccess access(isolate_);
+ return (thread_local_.interrupt_flags_ & CODE_READY) != 0;
+}
+
+
bool StackGuard::IsGCRequest() {
ExecutionAccess access(isolate_);
return (thread_local_.interrupt_flags_ & GC_REQUEST) != 0;
@@ -911,6 +930,17 @@
stack_guard->Continue(GC_REQUEST);
}
+ if (stack_guard->IsCodeReadyEvent()) {
+ ASSERT(FLAG_parallel_recompilation);
+ if (FLAG_trace_parallel_recompilation) {
+ PrintF(" ** CODE_READY event received.\n");
+ }
+ stack_guard->Continue(CODE_READY);
+ }
+ if (!stack_guard->IsTerminateExecution()) {
+ isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
+ }
+
isolate->counters()->stack_interrupts()->Increment();
// If FLAG_count_based_interrupts, every interrupt is a profiler interrupt.
if (FLAG_count_based_interrupts ||
diff --git a/src/execution.h b/src/execution.h
index 01e4b9d..9f5d9ff 100644
--- a/src/execution.h
+++ b/src/execution.h
@@ -42,7 +42,8 @@
PREEMPT = 1 << 3,
TERMINATE = 1 << 4,
RUNTIME_PROFILER_TICK = 1 << 5,
- GC_REQUEST = 1 << 6
+ GC_REQUEST = 1 << 6,
+ CODE_READY = 1 << 7
};
@@ -195,6 +196,8 @@
void TerminateExecution();
bool IsRuntimeProfilerTick();
void RequestRuntimeProfilerTick();
+ bool IsCodeReadyEvent();
+ void RequestCodeReadyEvent();
#ifdef ENABLE_DEBUGGER_SUPPORT
bool IsDebugBreak();
void DebugBreak();
diff --git a/src/extensions/statistics-extension.cc b/src/extensions/statistics-extension.cc
new file mode 100644
index 0000000..cb34737
--- /dev/null
+++ b/src/extensions/statistics-extension.cc
@@ -0,0 +1,110 @@
+// Copyright 2012 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.
+
+#include "statistics-extension.h"
+
+namespace v8 {
+namespace internal {
+
+const char* const StatisticsExtension::kSource =
+ "native function getV8Statistics();";
+
+
+v8::Handle<v8::FunctionTemplate> StatisticsExtension::GetNativeFunction(
+ v8::Handle<v8::String> str) {
+ ASSERT(strcmp(*v8::String::AsciiValue(str), "getV8Statistics") == 0);
+ return v8::FunctionTemplate::New(StatisticsExtension::GetCounters);
+}
+
+
+v8::Handle<v8::Value> StatisticsExtension::GetCounters(
+ const v8::Arguments& args) {
+ Isolate* isolate = Isolate::Current();
+ Heap* heap = isolate->heap();
+ if (args.Length() > 0) { // GC if first argument evaluates to true.
+ if (args[0]->IsBoolean() && args[0]->ToBoolean()->Value()) {
+ heap->CollectAllGarbage(Heap::kNoGCFlags, "counters extension");
+ }
+ }
+
+ Counters* counters = isolate->counters();
+ v8::Local<v8::Object> result = v8::Object::New();
+
+ StatsCounter* counter = NULL;
+
+#define ADD_COUNTER(name, caption) \
+ counter = counters->name(); \
+ if (counter->Enabled()) \
+ result->Set(v8::String::New(#name), \
+ v8::Number::New(*counter->GetInternalPointer()));
+
+ STATS_COUNTER_LIST_1(ADD_COUNTER)
+ STATS_COUNTER_LIST_2(ADD_COUNTER)
+#undef ADD_COUNTER
+#define ADD_COUNTER(name) \
+ counter = counters->count_of_##name(); \
+ if (counter->Enabled()) \
+ result->Set(v8::String::New("count_of_" #name), \
+ v8::Number::New(*counter->GetInternalPointer())); \
+ counter = counters->size_of_##name(); \
+ if (counter->Enabled()) \
+ result->Set(v8::String::New("size_of_" #name), \
+ v8::Number::New(*counter->GetInternalPointer()));
+
+ INSTANCE_TYPE_LIST(ADD_COUNTER)
+#undef ADD_COUNTER
+#define ADD_COUNTER(name) \
+ result->Set(v8::String::New("count_of_CODE_TYPE_" #name), \
+ v8::Number::New( \
+ *counters->count_of_CODE_TYPE_##name()->GetInternalPointer())); \
+ result->Set(v8::String::New("size_of_CODE_TYPE_" #name), \
+ v8::Number::New( \
+ *counters->size_of_CODE_TYPE_##name()->GetInternalPointer()));
+
+ CODE_KIND_LIST(ADD_COUNTER)
+#undef ADD_COUNTER
+#define ADD_COUNTER(name) \
+ result->Set(v8::String::New("count_of_FIXED_ARRAY_" #name), \
+ v8::Number::New( \
+ *counters->count_of_FIXED_ARRAY_##name()->GetInternalPointer())); \
+ result->Set(v8::String::New("size_of_FIXED_ARRAY_" #name), \
+ v8::Number::New( \
+ *counters->size_of_FIXED_ARRAY_##name()->GetInternalPointer()));
+
+ FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(ADD_COUNTER)
+#undef ADD_COUNTER
+
+ return result;
+}
+
+
+void StatisticsExtension::Register() {
+ static StatisticsExtension statistics_extension;
+ static v8::DeclareExtension declaration(&statistics_extension);
+}
+
+} } // namespace v8::internal
diff --git a/src/extensions/statistics-extension.h b/src/extensions/statistics-extension.h
new file mode 100644
index 0000000..433c4cf
--- /dev/null
+++ b/src/extensions/statistics-extension.h
@@ -0,0 +1,49 @@
+// Copyright 2010 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.
+
+#ifndef V8_EXTENSIONS_STATISTICS_EXTENSION_H_
+#define V8_EXTENSIONS_STATISTICS_EXTENSION_H_
+
+#include "v8.h"
+
+namespace v8 {
+namespace internal {
+
+class StatisticsExtension : public v8::Extension {
+ public:
+ StatisticsExtension() : v8::Extension("v8/statistics", kSource) {}
+ virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
+ v8::Handle<v8::String> name);
+ static v8::Handle<v8::Value> GetCounters(const v8::Arguments& args);
+ static void Register();
+ private:
+ static const char* const kSource;
+};
+
+} } // namespace v8::internal
+
+#endif // V8_EXTENSIONS_STATISTICS_EXTENSION_H_
diff --git a/src/factory.cc b/src/factory.cc
index 8340b46..25989ca 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -886,38 +886,15 @@
}
-MUST_USE_RESULT static inline MaybeObject* DoCopyAdd(
- DescriptorArray* array,
- String* key,
- Object* value,
- PropertyAttributes attributes) {
- CallbacksDescriptor desc(key, value, attributes);
- MaybeObject* obj = array->CopyAdd(&desc);
- return obj;
-}
-
-
-// Allocate the new array.
-Handle<DescriptorArray> Factory::CopyAppendForeignDescriptor(
- Handle<DescriptorArray> array,
- Handle<String> key,
- Handle<Object> value,
- PropertyAttributes attributes) {
- CALL_HEAP_FUNCTION(isolate(),
- DoCopyAdd(*array, *key, *value, attributes),
- DescriptorArray);
-}
-
-
Handle<String> Factory::SymbolFromString(Handle<String> value) {
CALL_HEAP_FUNCTION(isolate(),
isolate()->heap()->LookupSymbol(*value), String);
}
-Handle<DescriptorArray> Factory::CopyAppendCallbackDescriptors(
- Handle<DescriptorArray> array,
- Handle<Object> descriptors) {
+void Factory::CopyAppendCallbackDescriptors(Handle<Map> map,
+ Handle<Object> descriptors) {
+ Handle<DescriptorArray> array(map->instance_descriptors());
v8::NeanderArray callbacks(descriptors);
int nof_callbacks = callbacks.length();
int descriptor_count = array->number_of_descriptors();
@@ -929,12 +906,13 @@
// Copy the descriptors from the array.
if (0 < descriptor_count) {
- result->SetLastAdded(array->LastAdded());
for (int i = 0; i < descriptor_count; i++) {
result->CopyFrom(i, *array, i, witness);
}
}
+ map->set_instance_descriptors(*result);
+
// Fill in new callback descriptors. Process the callbacks from
// back to front so that the last callback with a given name takes
// precedence over previously added callbacks with that name.
@@ -945,19 +923,19 @@
Handle<String> key =
SymbolFromString(Handle<String>(String::cast(entry->name())));
// Check if a descriptor with this name already exists before writing.
- if (LinearSearch(*result,
- EXPECT_UNSORTED,
- *key,
- result->NumberOfSetDescriptors()) ==
+ if (LinearSearch(*result, *key, map->NumberOfSetDescriptors()) ==
DescriptorArray::kNotFound) {
CallbacksDescriptor desc(*key, *entry, entry->property_attributes());
- result->Append(&desc, witness);
+ map->AppendDescriptor(&desc, witness);
}
}
- int new_number_of_descriptors = result->NumberOfSetDescriptors();
- // Return the old descriptor array if there were no new elements.
- if (new_number_of_descriptors == descriptor_count) return array;
+ int new_number_of_descriptors = map->NumberOfSetDescriptors();
+ // Reinstall the original descriptor array if no new elements were added.
+ if (new_number_of_descriptors == descriptor_count) {
+ map->set_instance_descriptors(*array);
+ return;
+ }
// If duplicates were detected, allocate a result of the right size
// and transfer the elements.
@@ -967,12 +945,8 @@
for (int i = 0; i < new_number_of_descriptors; i++) {
new_result->CopyFrom(i, *result, i, witness);
}
- result = new_result;
+ map->set_instance_descriptors(*new_result);
}
-
- // Sort the result before returning.
- result->Sort(witness);
- return result;
}
@@ -1360,20 +1334,15 @@
result->shared()->DontAdaptArguments();
// Recursively copy parent templates' accessors, 'data' may be modified.
- Handle<DescriptorArray> array =
- Handle<DescriptorArray>(map->instance_descriptors());
while (true) {
Handle<Object> props = Handle<Object>(obj->property_accessors());
if (!props->IsUndefined()) {
- array = CopyAppendCallbackDescriptors(array, props);
+ CopyAppendCallbackDescriptors(map, props);
}
Handle<Object> parent = Handle<Object>(obj->parent_template());
if (parent->IsUndefined()) break;
obj = Handle<FunctionTemplateInfo>::cast(parent);
}
- if (!array->IsEmpty()) {
- map->set_instance_descriptors(*array);
- }
ASSERT(result->shared()->IsApiFunction());
return result;
diff --git a/src/factory.h b/src/factory.h
index 3b7ead5..6b22140 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -385,12 +385,6 @@
Handle<JSFunction> NewFunctionWithoutPrototype(Handle<String> name,
Handle<Code> code);
- Handle<DescriptorArray> CopyAppendForeignDescriptor(
- Handle<DescriptorArray> array,
- Handle<String> key,
- Handle<Object> value,
- PropertyAttributes attributes);
-
Handle<String> NumberToString(Handle<Object> number);
Handle<String> Uint32ToString(uint32_t value);
@@ -502,9 +496,8 @@
Handle<String> name,
LanguageMode language_mode);
- Handle<DescriptorArray> CopyAppendCallbackDescriptors(
- Handle<DescriptorArray> array,
- Handle<Object> descriptors);
+ void CopyAppendCallbackDescriptors(Handle<Map> map,
+ Handle<Object> descriptors);
// Create a new map cache.
Handle<MapCache> NewMapCache(int at_least_space_for);
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 4ad73ad..fdb025b 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -152,7 +152,7 @@
DEFINE_implication(harmony_modules, harmony_scoping)
// Flags for experimental implementation features.
-DEFINE_bool(packed_arrays, false, "optimizes arrays that have no holes")
+DEFINE_bool(packed_arrays, true, "optimizes arrays that have no holes")
DEFINE_bool(smi_only_arrays, true, "tracks arrays with only smi values")
DEFINE_bool(clever_optimizations,
true,
@@ -218,6 +218,12 @@
DEFINE_bool(optimize_for_in, true,
"optimize functions containing for-in loops")
+DEFINE_bool(parallel_recompilation, false,
+ "optimizing hot functions asynchronously on a separate thread")
+DEFINE_bool(trace_parallel_recompilation, false, "track parallel recompilation")
+DEFINE_int(parallel_recompilation_queue_length, 2,
+ "the length of the parallel compilation queue")
+
// Experimental profiler changes.
DEFINE_bool(experimental_profiler, true, "enable all profiler experiments")
DEFINE_bool(watch_ic_patching, false, "profiler considers IC stability")
@@ -409,6 +415,7 @@
// parser.cc
DEFINE_bool(allow_natives_syntax, false, "allow natives syntax")
+DEFINE_bool(trace_parse, false, "trace parsing and preparsing")
// simulator-arm.cc and simulator-mips.cc
DEFINE_bool(trace_sim, false, "Trace simulator execution")
diff --git a/src/flags.cc b/src/flags.cc
index 14c230a..bca0eff 100644
--- a/src/flags.cc
+++ b/src/flags.cc
@@ -31,7 +31,7 @@
#include "v8.h"
#include "platform.h"
-#include "smart-array-pointer.h"
+#include "smart-pointers.h"
#include "string-stream.h"
diff --git a/src/handles-inl.h b/src/handles-inl.h
index a5c81ce..1307986 100644
--- a/src/handles-inl.h
+++ b/src/handles-inl.h
@@ -149,25 +149,31 @@
#ifdef DEBUG
inline NoHandleAllocation::NoHandleAllocation() {
+ Isolate* isolate = Isolate::Current();
v8::ImplementationUtilities::HandleScopeData* current =
- Isolate::Current()->handle_scope_data();
+ isolate->handle_scope_data();
- // Shrink the current handle scope to make it impossible to do
- // handle allocations without an explicit handle scope.
- current->limit = current->next;
+ active_ = !isolate->optimizing_compiler_thread()->IsOptimizerThread();
+ if (active_) {
+ // Shrink the current handle scope to make it impossible to do
+ // handle allocations without an explicit handle scope.
+ current->limit = current->next;
- level_ = current->level;
- current->level = 0;
+ level_ = current->level;
+ current->level = 0;
+ }
}
inline NoHandleAllocation::~NoHandleAllocation() {
- // Restore state in current handle scope to re-enable handle
- // allocations.
- v8::ImplementationUtilities::HandleScopeData* data =
- Isolate::Current()->handle_scope_data();
- ASSERT_EQ(0, data->level);
- data->level = level_;
+ if (active_) {
+ // Restore state in current handle scope to re-enable handle
+ // allocations.
+ v8::ImplementationUtilities::HandleScopeData* data =
+ Isolate::Current()->handle_scope_data();
+ ASSERT_EQ(0, data->level);
+ data->level = level_;
+ }
}
#endif
diff --git a/src/handles.h b/src/handles.h
index 6f3044c..b35693e 100644
--- a/src/handles.h
+++ b/src/handles.h
@@ -95,6 +95,7 @@
};
+class DeferredHandles;
class HandleScopeImplementer;
@@ -159,9 +160,11 @@
// Zaps the handles in the half-open interval [start, end).
static void ZapRange(internal::Object** start, internal::Object** end);
+ friend class v8::internal::DeferredHandles;
friend class v8::HandleScope;
friend class v8::internal::HandleScopeImplementer;
friend class v8::ImplementationUtilities;
+ friend class v8::internal::Isolate;
};
@@ -324,6 +327,7 @@
inline ~NoHandleAllocation();
private:
int level_;
+ bool active_;
#endif
};
diff --git a/src/heap-inl.h b/src/heap-inl.h
index 9d79db2..958fe19 100644
--- a/src/heap-inl.h
+++ b/src/heap-inl.h
@@ -772,22 +772,30 @@
#ifdef DEBUG
AssertNoAllocation::AssertNoAllocation() {
- old_state_ = HEAP->allow_allocation(false);
+ Isolate* isolate = ISOLATE;
+ active_ = !isolate->optimizing_compiler_thread()->IsOptimizerThread();
+ if (active_) {
+ old_state_ = isolate->heap()->allow_allocation(false);
+ }
}
AssertNoAllocation::~AssertNoAllocation() {
- HEAP->allow_allocation(old_state_);
+ if (active_) HEAP->allow_allocation(old_state_);
}
DisableAssertNoAllocation::DisableAssertNoAllocation() {
- old_state_ = HEAP->allow_allocation(true);
+ Isolate* isolate = ISOLATE;
+ active_ = !isolate->optimizing_compiler_thread()->IsOptimizerThread();
+ if (active_) {
+ old_state_ = isolate->heap()->allow_allocation(true);
+ }
}
DisableAssertNoAllocation::~DisableAssertNoAllocation() {
- HEAP->allow_allocation(old_state_);
+ if (active_) HEAP->allow_allocation(old_state_);
}
#else
diff --git a/src/heap.cc b/src/heap.cc
index 15fd430..b038c77 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -155,7 +155,8 @@
scavenges_since_last_idle_round_(kIdleScavengeThreshold),
promotion_queue_(this),
configured_(false),
- chunks_queued_for_free_(NULL) {
+ chunks_queued_for_free_(NULL),
+ relocation_mutex_(NULL) {
// Allow build-time customization of the max semispace size. Building
// V8 with snapshots and a non-default max semispace size is much
// easier if you can define it as part of the build environment.
@@ -1199,6 +1200,7 @@
void Heap::Scavenge() {
+ RelocationLock relocation_lock(this);
#ifdef DEBUG
if (FLAG_verify_heap) VerifyNonPointerSpacePointers();
#endif
@@ -2044,7 +2046,8 @@
reinterpret_cast<Map*>(result)->set_unused_property_fields(0);
reinterpret_cast<Map*>(result)->set_bit_field(0);
reinterpret_cast<Map*>(result)->set_bit_field2(0);
- reinterpret_cast<Map*>(result)->set_bit_field3(0);
+ reinterpret_cast<Map*>(result)->set_bit_field3(
+ Map::LastAddedBits::encode(Map::kNoneAdded));
return result;
}
@@ -2053,9 +2056,8 @@
int instance_size,
ElementsKind elements_kind) {
Object* result;
- { MaybeObject* maybe_result = AllocateRawMap();
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
+ MaybeObject* maybe_result = AllocateRawMap();
+ if (!maybe_result->To(&result)) return maybe_result;
Map* map = reinterpret_cast<Map*>(result);
map->set_map_no_write_barrier(meta_map());
@@ -2072,7 +2074,7 @@
map->set_unused_property_fields(0);
map->set_bit_field(0);
map->set_bit_field2(1 << Map::kIsExtensible);
- map->set_bit_field3(0);
+ map->set_bit_field3(Map::LastAddedBits::encode(Map::kNoneAdded));
map->set_elements_kind(elements_kind);
// If the map object is aligned fill the padding area with Smi 0 objects.
@@ -3824,21 +3826,18 @@
// suggested by the function.
int instance_size = fun->shared()->CalculateInstanceSize();
int in_object_properties = fun->shared()->CalculateInObjectProperties();
- Object* map_obj;
- { MaybeObject* maybe_map_obj = AllocateMap(JS_OBJECT_TYPE, instance_size);
- if (!maybe_map_obj->ToObject(&map_obj)) return maybe_map_obj;
- }
+ Map* map;
+ MaybeObject* maybe_map = AllocateMap(JS_OBJECT_TYPE, instance_size);
+ if (!maybe_map->To(&map)) return maybe_map;
// Fetch or allocate prototype.
Object* prototype;
if (fun->has_instance_prototype()) {
prototype = fun->instance_prototype();
} else {
- { MaybeObject* maybe_prototype = AllocateFunctionPrototype(fun);
- if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
- }
+ MaybeObject* maybe_prototype = AllocateFunctionPrototype(fun);
+ if (!maybe_prototype->To(&prototype)) return maybe_prototype;
}
- Map* map = Map::cast(map_obj);
map->set_inobject_properties(in_object_properties);
map->set_unused_property_fields(in_object_properties);
map->set_prototype(prototype);
@@ -3857,12 +3856,10 @@
fun->shared()->ForbidInlineConstructor();
} else {
DescriptorArray* descriptors;
- { MaybeObject* maybe_descriptors_obj =
- DescriptorArray::Allocate(count, DescriptorArray::MAY_BE_SHARED);
- if (!maybe_descriptors_obj->To<DescriptorArray>(&descriptors)) {
- return maybe_descriptors_obj;
- }
- }
+ MaybeObject* maybe_descriptors =
+ DescriptorArray::Allocate(count, DescriptorArray::MAY_BE_SHARED);
+ if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
+
DescriptorArray::WhitenessWitness witness(descriptors);
for (int i = 0; i < count; i++) {
String* name = fun->shared()->GetThisPropertyAssignmentName(i);
@@ -3870,7 +3867,7 @@
FieldDescriptor field(name, i, NONE, i + 1);
descriptors->Set(i, &field, witness);
}
- descriptors->SortUnchecked(witness);
+ descriptors->Sort(witness);
// The descriptors may contain duplicates because the compiler does not
// guarantee the uniqueness of property names (it would have required
@@ -3879,7 +3876,7 @@
if (HasDuplicates(descriptors)) {
fun->shared()->ForbidInlineConstructor();
} else {
- map->set_instance_descriptors(descriptors);
+ map->InitializeDescriptors(descriptors);
map->set_pre_allocated_property_fields(count);
map->set_unused_property_fields(in_object_properties - count);
}
@@ -5698,6 +5695,7 @@
// Iterate over local handles in handle scopes.
isolate_->handle_scope_implementer()->Iterate(v);
+ isolate_->IterateDeferredHandles(v);
v->Synchronize(VisitorSynchronization::kHandleScope);
// Iterate over the builtin code objects and code stubs in the
@@ -6160,6 +6158,8 @@
store_buffer()->SetUp();
+ if (FLAG_parallel_recompilation) relocation_mutex_ = OS::CreateMutex();
+
return true;
}
@@ -6245,6 +6245,8 @@
isolate_->memory_allocator()->TearDown();
+ delete relocation_mutex_;
+
#ifdef DEBUG
delete debug_utils_;
debug_utils_ = NULL;
@@ -7222,6 +7224,18 @@
static_cast<int>(object_sizes_last_time_[index]));
CODE_KIND_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
#undef ADJUST_LAST_TIME_OBJECT_COUNT
+#define ADJUST_LAST_TIME_OBJECT_COUNT(name) \
+ index = FIRST_FIXED_ARRAY_SUB_TYPE + name; \
+ counters->count_of_FIXED_ARRAY_##name()->Increment( \
+ static_cast<int>(object_counts_[index])); \
+ counters->count_of_FIXED_ARRAY_##name()->Decrement( \
+ static_cast<int>(object_counts_last_time_[index])); \
+ counters->size_of_FIXED_ARRAY_##name()->Increment( \
+ static_cast<int>(object_sizes_[index])); \
+ counters->size_of_FIXED_ARRAY_##name()->Decrement( \
+ static_cast<int>(object_sizes_last_time_[index]));
+ FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
+#undef ADJUST_LAST_TIME_OBJECT_COUNT
memcpy(object_counts_last_time_, object_counts_, sizeof(object_counts_));
memcpy(object_sizes_last_time_, object_sizes_, sizeof(object_sizes_));
diff --git a/src/heap.h b/src/heap.h
index 64fd17d..b7caee7 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -1601,7 +1601,10 @@
// another.
enum {
FIRST_CODE_KIND_SUB_TYPE = LAST_TYPE + 1,
- OBJECT_STATS_COUNT = FIRST_CODE_KIND_SUB_TYPE + Code::LAST_CODE_KIND + 1
+ FIRST_FIXED_ARRAY_SUB_TYPE =
+ FIRST_CODE_KIND_SUB_TYPE + Code::LAST_CODE_KIND + 1,
+ OBJECT_STATS_COUNT =
+ FIRST_FIXED_ARRAY_SUB_TYPE + LAST_FIXED_ARRAY_SUB_TYPE + 1
};
void RecordObjectStats(InstanceType type, int sub_type, size_t size) {
@@ -1614,12 +1617,35 @@
ASSERT(sub_type <= Code::LAST_CODE_KIND);
object_counts_[FIRST_CODE_KIND_SUB_TYPE + sub_type]++;
object_sizes_[FIRST_CODE_KIND_SUB_TYPE + sub_type] += size;
+ } else if (type == FIXED_ARRAY_TYPE) {
+ ASSERT(sub_type <= LAST_FIXED_ARRAY_SUB_TYPE);
+ object_counts_[FIRST_FIXED_ARRAY_SUB_TYPE + sub_type]++;
+ object_sizes_[FIRST_FIXED_ARRAY_SUB_TYPE + sub_type] += size;
}
}
}
void CheckpointObjectStats();
+ // We don't use a ScopedLock here since we want to lock the heap
+ // only when FLAG_parallel_recompilation is true.
+ class RelocationLock {
+ public:
+ explicit RelocationLock(Heap* heap) : heap_(heap) {
+ if (FLAG_parallel_recompilation) {
+ heap_->relocation_mutex_->Lock();
+ }
+ }
+ ~RelocationLock() {
+ if (FLAG_parallel_recompilation) {
+ heap_->relocation_mutex_->Unlock();
+ }
+ }
+
+ private:
+ Heap* heap_;
+ };
+
private:
Heap();
@@ -2072,6 +2098,8 @@
MemoryChunk* chunks_queued_for_free_;
+ Mutex* relocation_mutex_;
+
friend class Factory;
friend class GCTracer;
friend class DisallowAllocationFailure;
@@ -2395,6 +2423,7 @@
#ifdef DEBUG
private:
bool old_state_;
+ bool active_;
#endif
};
@@ -2407,6 +2436,7 @@
#ifdef DEBUG
private:
bool old_state_;
+ bool active_;
#endif
};
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index e0caba1..3feab4a 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -1479,7 +1479,7 @@
if (has_int32_value_) {
stream->Add("%d ", int32_value_);
} else if (has_double_value_) {
- stream->Add("%lf ", FmtElm(double_value_));
+ stream->Add("%f ", FmtElm(double_value_));
} else {
handle()->ShortPrint(stream);
}
@@ -1803,7 +1803,8 @@
object()->PrintNameTo(stream);
stream->Add("[");
key()->PrintNameTo(stream);
- stream->Add("]");
+ stream->Add("] ");
+ dependency()->PrintNameTo(stream);
if (RequiresHoleCheck()) {
stream->Add(" check_hole");
}
@@ -1828,7 +1829,8 @@
elements()->PrintNameTo(stream);
stream->Add("[");
key()->PrintNameTo(stream);
- stream->Add("]");
+ stream->Add("] ");
+ dependency()->PrintNameTo(stream);
}
@@ -1857,6 +1859,7 @@
new(block()->zone()) HCheckMapValue(object(), names_cache->map());
HInstruction* index = new(block()->zone()) HLoadKeyedFastElement(
index_cache,
+ key_load->key(),
key_load->key());
map_check->InsertBefore(this);
index->InsertBefore(this);
@@ -1917,7 +1920,8 @@
}
stream->Add("[");
key()->PrintNameTo(stream);
- stream->Add("]");
+ stream->Add("] ");
+ dependency()->PrintNameTo(stream);
}
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index edd93f0..c2cb271 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -224,6 +224,16 @@
virtual Opcode opcode() const { return HValue::k##type; }
+#ifdef DEBUG
+#define ASSERT_ALLOCATION_DISABLED do { \
+ OptimizingCompilerThread* thread = \
+ ISOLATE->optimizing_compiler_thread(); \
+ ASSERT(thread->IsOptimizerThread() || !HEAP->IsAllocationAllowed()); \
+ } while (0)
+#else
+#define ASSERT_ALLOCATION_DISABLED do {} while (0)
+#endif
+
class Range: public ZoneObject {
public:
Range()
@@ -1878,6 +1888,7 @@
class HFixedArrayBaseLength: public HUnaryOperation {
public:
explicit HFixedArrayBaseLength(HValue* value) : HUnaryOperation(value) {
+ set_type(HType::Smi());
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
SetGVNFlag(kDependsOnArrayLengths);
@@ -2289,7 +2300,7 @@
virtual void PrintDataTo(StringStream* stream);
virtual intptr_t Hashcode() {
- ASSERT(!HEAP->IsAllocationAllowed());
+ ASSERT_ALLOCATION_DISABLED;
intptr_t hash = reinterpret_cast<intptr_t>(*prototype());
hash = 17 * hash + reinterpret_cast<intptr_t>(*holder());
return hash;
@@ -2535,7 +2546,7 @@
bool ToBoolean();
virtual intptr_t Hashcode() {
- ASSERT(!HEAP->allow_allocation(false));
+ ASSERT_ALLOCATION_DISABLED;
intptr_t hash;
if (has_int32_value_) {
@@ -2747,17 +2758,31 @@
};
+enum BoundsCheckKeyMode {
+ DONT_ALLOW_SMI_KEY,
+ ALLOW_SMI_KEY
+};
+
+
class HBoundsCheck: public HTemplateInstruction<2> {
public:
- HBoundsCheck(HValue* index, HValue* length) {
+ HBoundsCheck(HValue* index, HValue* length,
+ BoundsCheckKeyMode key_mode = DONT_ALLOW_SMI_KEY)
+ : key_mode_(key_mode) {
SetOperandAt(0, index);
SetOperandAt(1, length);
set_representation(Representation::Integer32());
SetFlag(kUseGVN);
}
- virtual Representation RequiredInputRepresentation(int index) {
- return Representation::Integer32();
+ virtual Representation RequiredInputRepresentation(int arg_index) {
+ if (index()->representation().IsTagged() &&
+ !index()->IsConstant() &&
+ key_mode_ == ALLOW_SMI_KEY) {
+ return Representation::Tagged();
+ } else {
+ return Representation::Integer32();
+ }
}
virtual void PrintDataTo(StringStream* stream);
@@ -2769,6 +2794,7 @@
protected:
virtual bool DataEquals(HValue* other) { return true; }
+ BoundsCheckKeyMode key_mode_;
};
@@ -3640,7 +3666,7 @@
virtual void PrintDataTo(StringStream* stream);
virtual intptr_t Hashcode() {
- ASSERT(!HEAP->allow_allocation(false));
+ ASSERT_ALLOCATION_DISABLED;
return reinterpret_cast<intptr_t>(*cell_);
}
@@ -4027,10 +4053,11 @@
};
class HLoadKeyedFastElement
- : public HTemplateInstruction<2>, public ArrayInstructionInterface {
+ : public HTemplateInstruction<3>, public ArrayInstructionInterface {
public:
HLoadKeyedFastElement(HValue* obj,
HValue* key,
+ HValue* dependency,
ElementsKind elements_kind = FAST_ELEMENTS)
: bit_field_(0) {
ASSERT(IsFastSmiOrObjectElementsKind(elements_kind));
@@ -4041,6 +4068,7 @@
}
SetOperandAt(0, obj);
SetOperandAt(1, key);
+ SetOperandAt(2, dependency);
set_representation(Representation::Tagged());
SetGVNFlag(kDependsOnArrayElements);
SetFlag(kUseGVN);
@@ -4048,6 +4076,7 @@
HValue* object() { return OperandAt(0); }
HValue* key() { return OperandAt(1); }
+ HValue* dependency() { return OperandAt(2); }
uint32_t index_offset() { return IndexOffsetField::decode(bit_field_); }
void SetIndexOffset(uint32_t index_offset) {
bit_field_ = IndexOffsetField::update(bit_field_, index_offset);
@@ -4064,9 +4093,9 @@
virtual Representation RequiredInputRepresentation(int index) {
// The key is supposed to be Integer32.
- return index == 0
- ? Representation::Tagged()
- : Representation::Integer32();
+ if (index == 0) return Representation::Tagged();
+ if (index == 1) return Representation::Integer32();
+ return Representation::None();
}
virtual void PrintDataTo(StringStream* stream);
@@ -4096,17 +4125,19 @@
class HLoadKeyedFastDoubleElement
- : public HTemplateInstruction<2>, public ArrayInstructionInterface {
+ : public HTemplateInstruction<3>, public ArrayInstructionInterface {
public:
HLoadKeyedFastDoubleElement(
HValue* elements,
HValue* key,
+ HValue* dependency,
HoleCheckMode hole_check_mode = PERFORM_HOLE_CHECK)
: index_offset_(0),
is_dehoisted_(false),
hole_check_mode_(hole_check_mode) {
SetOperandAt(0, elements);
SetOperandAt(1, key);
+ SetOperandAt(2, dependency);
set_representation(Representation::Double());
SetGVNFlag(kDependsOnDoubleArrayElements);
SetFlag(kUseGVN);
@@ -4114,6 +4145,7 @@
HValue* elements() { return OperandAt(0); }
HValue* key() { return OperandAt(1); }
+ HValue* dependency() { return OperandAt(2); }
uint32_t index_offset() { return index_offset_; }
void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; }
HValue* GetKey() { return key(); }
@@ -4123,9 +4155,9 @@
virtual Representation RequiredInputRepresentation(int index) {
// The key is supposed to be Integer32.
- return index == 0
- ? Representation::Tagged()
- : Representation::Integer32();
+ if (index == 0) return Representation::Tagged();
+ if (index == 1) return Representation::Integer32();
+ return Representation::None();
}
bool RequiresHoleCheck() {
@@ -4152,16 +4184,18 @@
class HLoadKeyedSpecializedArrayElement
- : public HTemplateInstruction<2>, public ArrayInstructionInterface {
+ : public HTemplateInstruction<3>, public ArrayInstructionInterface {
public:
HLoadKeyedSpecializedArrayElement(HValue* external_elements,
HValue* key,
+ HValue* dependency,
ElementsKind elements_kind)
: elements_kind_(elements_kind),
index_offset_(0),
is_dehoisted_(false) {
SetOperandAt(0, external_elements);
SetOperandAt(1, key);
+ SetOperandAt(2, dependency);
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
set_representation(Representation::Double());
@@ -4177,15 +4211,15 @@
virtual void PrintDataTo(StringStream* stream);
virtual Representation RequiredInputRepresentation(int index) {
- // The key is supposed to be Integer32, but the base pointer
- // for the element load is a naked pointer.
- return index == 0
- ? Representation::External()
- : Representation::Integer32();
+ // The key is supposed to be Integer32.
+ if (index == 0) return Representation::External();
+ if (index == 1) return Representation::Integer32();
+ return Representation::None();
}
HValue* external_pointer() { return OperandAt(0); }
HValue* key() { return OperandAt(1); }
+ HValue* dependency() { return OperandAt(2); }
ElementsKind elements_kind() const { return elements_kind_; }
uint32_t index_offset() { return index_offset_; }
void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; }
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 7d0e228..df4d8fc 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -1711,7 +1711,10 @@
block_side_effects_(graph->blocks()->length(), graph->zone()),
loop_side_effects_(graph->blocks()->length(), graph->zone()),
visited_on_paths_(graph->zone(), graph->blocks()->length()) {
- ASSERT(!info->isolate()->heap()->IsAllocationAllowed());
+#ifdef DEBUG
+ ASSERT(info->isolate()->optimizing_compiler_thread()->IsOptimizerThread() ||
+ !info->isolate()->heap()->IsAllocationAllowed());
+#endif
block_side_effects_.AddBlock(GVNFlagSet(), graph_->blocks()->length(),
graph_->zone());
loop_side_effects_.AddBlock(GVNFlagSet(), graph_->blocks()->length(),
@@ -3018,7 +3021,6 @@
{
HPhase phase("H_Block building");
- CompilationHandleScope handle_scope(info());
current_block_ = graph()->entry_block();
Scope* scope = info()->scope();
@@ -3079,9 +3081,6 @@
}
bool HGraph::Optimize(SmartArrayPointer<char>* bailout_reason) {
- NoHandleAllocation no_handles;
- AssertNoAllocation no_gc;
-
*bailout_reason = SmartArrayPointer<char>();
OrderBlocks();
AssignDominators();
@@ -4369,7 +4368,8 @@
HValue* key = AddInstruction(
new(zone()) HLoadKeyedFastElement(
environment()->ExpressionStackAt(2), // Enum cache.
- environment()->ExpressionStackAt(0))); // Iteration index.
+ environment()->ExpressionStackAt(0), // Iteration index.
+ environment()->ExpressionStackAt(0)));
// Check if the expected map still matches that of the enumerable.
// If not just deoptimize.
@@ -5709,6 +5709,7 @@
HValue* external_elements,
HValue* checked_key,
HValue* val,
+ HValue* dependency,
ElementsKind elements_kind,
bool is_store) {
if (is_store) {
@@ -5752,7 +5753,7 @@
} else {
ASSERT(val == NULL);
return new(zone()) HLoadKeyedSpecializedArrayElement(
- external_elements, checked_key, elements_kind);
+ external_elements, checked_key, dependency, elements_kind);
}
}
@@ -5760,6 +5761,7 @@
HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements,
HValue* checked_key,
HValue* val,
+ HValue* load_dependency,
ElementsKind elements_kind,
bool is_store) {
if (is_store) {
@@ -5788,10 +5790,11 @@
OMIT_HOLE_CHECK :
PERFORM_HOLE_CHECK;
if (IsFastDoubleElementsKind(elements_kind)) {
- return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key, mode);
+ return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key,
+ load_dependency, mode);
} else { // Smi or Object elements.
return new(zone()) HLoadKeyedFastElement(elements, checked_key,
- elements_kind);
+ load_dependency, elements_kind);
}
}
@@ -5843,12 +5846,14 @@
HInstruction* checked_key = NULL;
if (map->has_external_array_elements()) {
length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
- checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
+ checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length,
+ ALLOW_SMI_KEY));
HLoadExternalArrayPointer* external_elements =
new(zone()) HLoadExternalArrayPointer(elements);
AddInstruction(external_elements);
- return BuildExternalArrayElementAccess(external_elements, checked_key,
- val, map->elements_kind(), is_store);
+ return BuildExternalArrayElementAccess(
+ external_elements, checked_key, val, mapcheck,
+ map->elements_kind(), is_store);
}
ASSERT(fast_smi_only_elements ||
fast_elements ||
@@ -5860,7 +5865,7 @@
length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
}
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
- return BuildFastElementAccess(elements, checked_key, val,
+ return BuildFastElementAccess(elements, checked_key, val, mapcheck,
map->elements_kind(), is_store);
}
@@ -6078,9 +6083,11 @@
HInstruction* length;
length = AddInstruction(new(zone()) HJSArrayLength(object, typecheck,
HType::Smi()));
- checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
+ checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length,
+ ALLOW_SMI_KEY));
access = AddInstruction(BuildFastElementAccess(
- elements, checked_key, val, elements_kind, is_store));
+ elements, checked_key, val, elements_kind_branch,
+ elements_kind, is_store));
if (!is_store) {
Push(access);
}
@@ -6093,9 +6100,11 @@
set_current_block(if_fastobject);
length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
- checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
+ checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length,
+ ALLOW_SMI_KEY));
access = AddInstruction(BuildFastElementAccess(
- elements, checked_key, val, elements_kind, is_store));
+ elements, checked_key, val, elements_kind_branch,
+ elements_kind, is_store));
} else if (elements_kind == DICTIONARY_ELEMENTS) {
if (is_store) {
access = AddInstruction(BuildStoreKeyedGeneric(object, key, val));
@@ -6104,7 +6113,8 @@
}
} else { // External array elements.
access = AddInstruction(BuildExternalArrayElementAccess(
- external_elements, checked_key, val, elements_kind, is_store));
+ external_elements, checked_key, val, elements_kind_branch,
+ elements_kind, is_store));
}
*has_side_effects |= access->HasObservableSideEffects();
if (position != RelocInfo::kNoPosition) access->set_position(position);
@@ -6550,7 +6560,7 @@
bool HGraphBuilder::TryInline(CallKind call_kind,
Handle<JSFunction> target,
- ZoneList<Expression*>* arguments,
+ int arguments_count,
HValue* receiver,
int ast_id,
int return_id,
@@ -6712,7 +6722,7 @@
HConstant* undefined = graph()->GetConstantUndefined();
HEnvironment* inner_env =
environment()->CopyForInlining(target,
- arguments->length(),
+ arguments_count,
function,
undefined,
call_kind,
@@ -6748,7 +6758,7 @@
HEnterInlined* enter_inlined =
new(zone()) HEnterInlined(target,
- arguments->length(),
+ arguments_count,
function,
call_kind,
function_state()->is_construct(),
@@ -6851,7 +6861,7 @@
return TryInline(call_kind,
expr->target(),
- expr->arguments(),
+ expr->arguments()->length(),
NULL,
expr->id(),
expr->ReturnId(),
@@ -6862,7 +6872,7 @@
bool HGraphBuilder::TryInlineConstruct(CallNew* expr, HValue* receiver) {
return TryInline(CALL_AS_FUNCTION,
expr->target(),
- expr->arguments(),
+ expr->arguments()->length(),
receiver,
expr->id(),
expr->ReturnId(),
diff --git a/src/hydrogen.h b/src/hydrogen.h
index 2b0fc31..28f61c5 100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -874,7 +874,8 @@
void* operator new(size_t size, Zone* zone) {
return zone->New(static_cast<int>(size));
}
- void operator delete(void* ptr) { }
+ void operator delete(void* pointer, Zone* zone) { }
+ void operator delete(void* pointer) { }
private:
// Type of a member function that generates inline code for a native function.
@@ -1031,7 +1032,7 @@
int InliningAstSize(Handle<JSFunction> target);
bool TryInline(CallKind call_kind,
Handle<JSFunction> target,
- ZoneList<Expression*>* arguments,
+ int arguments_count,
HValue* receiver,
int ast_id,
int return_id,
@@ -1099,11 +1100,13 @@
HValue* external_elements,
HValue* checked_key,
HValue* val,
+ HValue* dependency,
ElementsKind elements_kind,
bool is_store);
HInstruction* BuildFastElementAccess(HValue* elements,
HValue* checked_key,
HValue* val,
+ HValue* dependency,
ElementsKind elements_kind,
bool is_store);
diff --git a/src/ia32/builtins-ia32.cc b/src/ia32/builtins-ia32.cc
index be46ff2..5c209ed 100644
--- a/src/ia32/builtins-ia32.cc
+++ b/src/ia32/builtins-ia32.cc
@@ -74,6 +74,43 @@
}
+static void GenerateTailCallToSharedCode(MacroAssembler* masm) {
+ __ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
+ __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kCodeOffset));
+ __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
+ __ jmp(eax);
+}
+
+
+void Builtins::Generate_InRecompileQueue(MacroAssembler* masm) {
+ GenerateTailCallToSharedCode(masm);
+}
+
+
+void Builtins::Generate_ParallelRecompile(MacroAssembler* masm) {
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+
+ // Push a copy of the function onto the stack.
+ __ push(edi);
+ // Push call kind information.
+ __ push(ecx);
+
+ __ push(edi); // Function is also the parameter to the runtime call.
+ __ CallRuntime(Runtime::kParallelRecompile, 1);
+
+ // Restore call kind information.
+ __ pop(ecx);
+ // Restore receiver.
+ __ pop(edi);
+
+ // Tear down internal frame.
+ }
+
+ GenerateTailCallToSharedCode(masm);
+}
+
+
static void Generate_JSConstructStubHelper(MacroAssembler* masm,
bool is_api_function,
bool count_constructions) {
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index fc49ceb..cdf965e 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -1094,7 +1094,7 @@
// We got a map in register eax. Get the enumeration cache from it.
__ bind(&use_cache);
__ LoadInstanceDescriptors(eax, ecx);
- __ mov(ecx, FieldOperand(ecx, DescriptorArray::kLastAddedOffset));
+ __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumCacheOffset));
__ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset));
// Set up the four remaining stack slots.
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index e4aaaf3..f3bcf1a 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -2650,6 +2650,7 @@
__ mov(result,
BuildFastArrayOperand(instr->elements(),
instr->key(),
+ instr->hydrogen()->key()->representation(),
FAST_ELEMENTS,
FixedArray::kHeaderSize - kHeapObjectTag,
instr->additional_index()));
@@ -2676,6 +2677,7 @@
sizeof(kHoleNanLower32);
Operand hole_check_operand = BuildFastArrayOperand(
instr->elements(), instr->key(),
+ instr->hydrogen()->key()->representation(),
FAST_DOUBLE_ELEMENTS,
offset,
instr->additional_index());
@@ -2686,6 +2688,7 @@
Operand double_load_operand = BuildFastArrayOperand(
instr->elements(),
instr->key(),
+ instr->hydrogen()->key()->representation(),
FAST_DOUBLE_ELEMENTS,
FixedDoubleArray::kHeaderSize - kHeapObjectTag,
instr->additional_index());
@@ -2696,11 +2699,15 @@
Operand LCodeGen::BuildFastArrayOperand(
LOperand* elements_pointer,
LOperand* key,
+ Representation key_representation,
ElementsKind elements_kind,
uint32_t offset,
uint32_t additional_index) {
Register elements_pointer_reg = ToRegister(elements_pointer);
int shift_size = ElementsKindToShiftSize(elements_kind);
+ if (key_representation.IsTagged() && (shift_size >= 1)) {
+ shift_size -= kSmiTagSize;
+ }
if (key->IsConstantOperand()) {
int constant_value = ToInteger32(LConstantOperand::cast(key));
if (constant_value & 0xF0000000) {
@@ -2722,11 +2729,19 @@
void LCodeGen::DoLoadKeyedSpecializedArrayElement(
LLoadKeyedSpecializedArrayElement* instr) {
ElementsKind elements_kind = instr->elements_kind();
- Operand operand(BuildFastArrayOperand(instr->external_pointer(),
- instr->key(),
- elements_kind,
- 0,
- instr->additional_index()));
+ LOperand* key = instr->key();
+ if (!key->IsConstantOperand() &&
+ ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(),
+ elements_kind)) {
+ __ SmiUntag(ToRegister(key));
+ }
+ Operand operand(BuildFastArrayOperand(
+ instr->external_pointer(),
+ key,
+ instr->hydrogen()->key()->representation(),
+ elements_kind,
+ 0,
+ instr->additional_index()));
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
XMMRegister result(ToDoubleRegister(instr->result()));
__ movss(result, operand);
@@ -3679,11 +3694,19 @@
void LCodeGen::DoStoreKeyedSpecializedArrayElement(
LStoreKeyedSpecializedArrayElement* instr) {
ElementsKind elements_kind = instr->elements_kind();
- Operand operand(BuildFastArrayOperand(instr->external_pointer(),
- instr->key(),
- elements_kind,
- 0,
- instr->additional_index()));
+ LOperand* key = instr->key();
+ if (!key->IsConstantOperand() &&
+ ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(),
+ elements_kind)) {
+ __ SmiUntag(ToRegister(key));
+ }
+ Operand operand(BuildFastArrayOperand(
+ instr->external_pointer(),
+ key,
+ instr->hydrogen()->key()->representation(),
+ elements_kind,
+ 0,
+ instr->additional_index()));
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
__ cvtsd2ss(xmm0, ToDoubleRegister(instr->value()));
__ movss(operand, xmm0);
@@ -3730,6 +3753,7 @@
Operand operand = BuildFastArrayOperand(
instr->object(),
instr->key(),
+ instr->hydrogen()->key()->representation(),
FAST_ELEMENTS,
FixedArray::kHeaderSize - kHeapObjectTag,
instr->additional_index());
@@ -3771,6 +3795,7 @@
Operand double_store_operand = BuildFastArrayOperand(
instr->elements(),
instr->key(),
+ instr->hydrogen()->key()->representation(),
FAST_DOUBLE_ELEMENTS,
FixedDoubleArray::kHeaderSize - kHeapObjectTag,
instr->additional_index());
@@ -5295,7 +5320,7 @@
Register result = ToRegister(instr->result());
__ LoadInstanceDescriptors(map, result);
__ mov(result,
- FieldOperand(result, DescriptorArray::kLastAddedOffset));
+ FieldOperand(result, DescriptorArray::kEnumCacheOffset));
__ mov(result,
FieldOperand(result, FixedArray::SizeFor(instr->idx())));
__ test(result, result);
diff --git a/src/ia32/lithium-codegen-ia32.h b/src/ia32/lithium-codegen-ia32.h
index 87b975c..42d383e 100644
--- a/src/ia32/lithium-codegen-ia32.h
+++ b/src/ia32/lithium-codegen-ia32.h
@@ -246,6 +246,7 @@
double ToDouble(LConstantOperand* op) const;
Operand BuildFastArrayOperand(LOperand* elements_pointer,
LOperand* key,
+ Representation key_representation,
ElementsKind elements_kind,
uint32_t offset,
uint32_t additional_index = 0);
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index 55b9df2..457e637 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -1900,7 +1900,8 @@
LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
HLoadKeyedFastElement* instr) {
ASSERT(instr->representation().IsTagged());
- ASSERT(instr->key()->representation().IsInteger32());
+ ASSERT(instr->key()->representation().IsInteger32() ||
+ instr->key()->representation().IsTagged());
LOperand* obj = UseRegisterAtStart(instr->object());
LOperand* key = UseRegisterOrConstantAtStart(instr->key());
LLoadKeyedFastElement* result = new(zone()) LLoadKeyedFastElement(obj, key);
@@ -1912,7 +1913,8 @@
LInstruction* LChunkBuilder::DoLoadKeyedFastDoubleElement(
HLoadKeyedFastDoubleElement* instr) {
ASSERT(instr->representation().IsDouble());
- ASSERT(instr->key()->representation().IsInteger32());
+ ASSERT(instr->key()->representation().IsInteger32() ||
+ instr->key()->representation().IsTagged());
LOperand* elements = UseRegisterAtStart(instr->elements());
LOperand* key = UseRegisterOrConstantAtStart(instr->key());
LLoadKeyedFastDoubleElement* result =
@@ -1931,11 +1933,17 @@
(instr->representation().IsDouble() &&
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
(elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
- ASSERT(instr->key()->representation().IsInteger32());
+ ASSERT(instr->key()->representation().IsInteger32() ||
+ instr->key()->representation().IsTagged());
LOperand* external_pointer = UseRegister(instr->external_pointer());
- LOperand* key = UseRegisterOrConstant(instr->key());
+ bool clobbers_key = ExternalArrayOpRequiresTemp(
+ instr->key()->representation(), elements_kind);
+ LOperand* key = clobbers_key
+ ? UseTempRegister(instr->key())
+ : UseRegisterOrConstant(instr->key());
+
LLoadKeyedSpecializedArrayElement* result =
- new(zone()) LLoadKeyedSpecializedArrayElement(external_pointer, key);
+ new(zone()) LLoadKeyedSpecializedArrayElement(external_pointer, key);
LInstruction* load_instr = DefineAsRegister(result);
// An unsigned int array load might overflow and cause a deopt, make sure it
// has an environment.
@@ -1961,7 +1969,8 @@
bool needs_write_barrier = instr->NeedsWriteBarrier();
ASSERT(instr->value()->representation().IsTagged());
ASSERT(instr->object()->representation().IsTagged());
- ASSERT(instr->key()->representation().IsInteger32());
+ ASSERT(instr->key()->representation().IsInteger32() ||
+ instr->key()->representation().IsTagged());
LOperand* obj = UseRegister(instr->object());
LOperand* val = needs_write_barrier
@@ -1978,7 +1987,8 @@
HStoreKeyedFastDoubleElement* instr) {
ASSERT(instr->value()->representation().IsDouble());
ASSERT(instr->elements()->representation().IsTagged());
- ASSERT(instr->key()->representation().IsInteger32());
+ ASSERT(instr->key()->representation().IsInteger32() ||
+ instr->key()->representation().IsTagged());
LOperand* elements = UseRegisterAtStart(instr->elements());
LOperand* val = UseTempRegister(instr->value());
@@ -1999,10 +2009,10 @@
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
(elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
ASSERT(instr->external_pointer()->representation().IsExternal());
- ASSERT(instr->key()->representation().IsInteger32());
+ ASSERT(instr->key()->representation().IsInteger32() ||
+ instr->key()->representation().IsTagged());
LOperand* external_pointer = UseRegister(instr->external_pointer());
- LOperand* key = UseRegisterOrConstant(instr->key());
LOperand* val = NULL;
if (elements_kind == EXTERNAL_BYTE_ELEMENTS ||
elements_kind == EXTERNAL_UNSIGNED_BYTE_ELEMENTS ||
@@ -2012,7 +2022,11 @@
} else {
val = UseRegister(instr->value());
}
-
+ bool clobbers_key = ExternalArrayOpRequiresTemp(
+ instr->key()->representation(), elements_kind);
+ LOperand* key = clobbers_key
+ ? UseTempRegister(instr->key())
+ : UseRegisterOrConstant(instr->key());
return new(zone()) LStoreKeyedSpecializedArrayElement(external_pointer,
key,
val);
diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h
index e05a936..ee9bf79 100644
--- a/src/ia32/lithium-ia32.h
+++ b/src/ia32/lithium-ia32.h
@@ -872,6 +872,7 @@
LOperand* length() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(BoundsCheck, "bounds-check")
+ DECLARE_HYDROGEN_ACCESSOR(BoundsCheck)
};
@@ -1277,6 +1278,19 @@
};
+inline static bool ExternalArrayOpRequiresTemp(
+ Representation key_representation,
+ ElementsKind elements_kind) {
+ // Operations that require the key to be divided by two to be converted into
+ // an index cannot fold the scale operation into a load and need an extra
+ // temp register to do the work.
+ return key_representation.IsTagged() &&
+ (elements_kind == EXTERNAL_BYTE_ELEMENTS ||
+ elements_kind == EXTERNAL_UNSIGNED_BYTE_ELEMENTS ||
+ elements_kind == EXTERNAL_PIXEL_ELEMENTS);
+}
+
+
class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
public:
LLoadKeyedSpecializedArrayElement(LOperand* external_pointer, LOperand* key) {
diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc
index 237bfd9..1fa694f 100644
--- a/src/ia32/macro-assembler-ia32.cc
+++ b/src/ia32/macro-assembler-ia32.cc
@@ -2901,7 +2901,7 @@
// Check that there is an enum cache in the non-empty instance
// descriptors (edx). This is the case if the next enumeration
// index field does not contain a smi.
- mov(edx, FieldOperand(edx, DescriptorArray::kLastAddedOffset));
+ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheOffset));
JumpIfSmi(edx, call_runtime);
// For all objects but the receiver, check that the cache is empty.
diff --git a/src/ic.cc b/src/ic.cc
index 5b71e40..0389330 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -1516,10 +1516,10 @@
case CONSTANT_FUNCTION:
return;
case TRANSITION: {
- Map* value = lookup->GetTransitionTarget();
- Handle<Map> transition(Map::cast(value));
+ Handle<Map> transition(lookup->GetTransitionTarget());
+ int descriptor = transition->LastAdded();
+
DescriptorArray* target_descriptors = transition->instance_descriptors();
- int descriptor = target_descriptors->LastAdded();
PropertyDetails details = target_descriptors->GetDetails(descriptor);
if (details.type() != FIELD || details.attributes() != NONE) return;
@@ -1980,9 +1980,9 @@
break;
case TRANSITION: {
Handle<Map> transition(lookup->GetTransitionTarget());
+ int descriptor = transition->LastAdded();
DescriptorArray* target_descriptors = transition->instance_descriptors();
- int descriptor = target_descriptors->LastAdded();
PropertyDetails details = target_descriptors->GetDetails(descriptor);
if (details.type() == FIELD && details.attributes() == NONE) {
diff --git a/src/isolate.cc b/src/isolate.cc
index cb73c26..69ffc5e 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -477,6 +477,14 @@
Iterate(v, current_t);
}
+void Isolate::IterateDeferredHandles(ObjectVisitor* visitor) {
+ for (DeferredHandles* deferred = deferred_handles_head_;
+ deferred != NULL;
+ deferred = deferred->next_) {
+ deferred->Iterate(visitor);
+ }
+}
+
void Isolate::RegisterTryCatchHandler(v8::TryCatch* that) {
// The ARM simulator has a separate JS stack. We therefore register
@@ -1484,7 +1492,9 @@
string_tracker_(NULL),
regexp_stack_(NULL),
date_cache_(NULL),
- context_exit_happened_(false) {
+ context_exit_happened_(false),
+ deferred_handles_head_(NULL),
+ optimizing_compiler_thread_(this) {
TRACE_ISOLATE(constructor);
memset(isolate_addresses_, 0,
@@ -1565,6 +1575,8 @@
if (state_ == INITIALIZED) {
TRACE_ISOLATE(deinit);
+ if (FLAG_parallel_recompilation) optimizing_compiler_thread_.Stop();
+
if (FLAG_hydrogen_stats) HStatistics::Instance()->Print();
// We must stop the logger before we tear down other components.
@@ -1906,6 +1918,7 @@
state_ = INITIALIZED;
time_millis_at_init_ = OS::TimeCurrentMillis();
+ if (FLAG_parallel_recompilation) optimizing_compiler_thread_.Start();
return true;
}
@@ -1989,6 +2002,36 @@
}
+void Isolate::LinkDeferredHandles(DeferredHandles* deferred) {
+ deferred->next_ = deferred_handles_head_;
+ if (deferred_handles_head_ != NULL) {
+ deferred_handles_head_->previous_ = deferred;
+ }
+ deferred_handles_head_ = deferred;
+}
+
+
+void Isolate::UnlinkDeferredHandles(DeferredHandles* deferred) {
+#ifdef DEBUG
+ // In debug mode assert that the linked list is well-formed.
+ DeferredHandles* deferred_iterator = deferred;
+ while (deferred_iterator->previous_ != NULL) {
+ deferred_iterator = deferred_iterator->previous_;
+ }
+ ASSERT(deferred_handles_head_ == deferred_iterator);
+#endif
+ if (deferred_handles_head_ == deferred) {
+ deferred_handles_head_ = deferred_handles_head_->next_;
+ }
+ if (deferred->next_ != NULL) {
+ deferred->next_->previous_ = deferred->previous_;
+ }
+ if (deferred->previous_ != NULL) {
+ deferred->previous_->next_ = deferred->next_;
+ }
+}
+
+
#ifdef DEBUG
#define ISOLATE_FIELD_OFFSET(type, name, ignored) \
const intptr_t Isolate::name##_debug_offset_ = OFFSET_OF(Isolate, name##_);
diff --git a/src/isolate.h b/src/isolate.h
index 8b4e12b..c0618c8 100644
--- a/src/isolate.h
+++ b/src/isolate.h
@@ -41,6 +41,7 @@
#include "handles.h"
#include "hashmap.h"
#include "heap.h"
+#include "optimizing-compiler-thread.h"
#include "regexp-stack.h"
#include "runtime-profiler.h"
#include "runtime.h"
@@ -1055,6 +1056,14 @@
date_cache_ = date_cache;
}
+ void IterateDeferredHandles(ObjectVisitor* visitor);
+ void LinkDeferredHandles(DeferredHandles* deferred_handles);
+ void UnlinkDeferredHandles(DeferredHandles* deferred_handles);
+
+ OptimizingCompilerThread* optimizing_compiler_thread() {
+ return &optimizing_compiler_thread_;
+ }
+
private:
Isolate();
@@ -1278,8 +1287,13 @@
#undef ISOLATE_FIELD_OFFSET
#endif
+ DeferredHandles* deferred_handles_head_;
+ OptimizingCompilerThread optimizing_compiler_thread_;
+
friend class ExecutionAccess;
+ friend class HandleScopeImplementer;
friend class IsolateInitializer;
+ friend class OptimizingCompilerThread;
friend class ThreadManager;
friend class Simulator;
friend class StackGuard;
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index 4bf00aa..a62196e 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -944,7 +944,15 @@
table_.GetVisitor(map)(map, obj);
}
- template<int id>
+ static void ObjectStatsVisitBase(StaticVisitorBase::VisitorId id,
+ Map* map, HeapObject* obj);
+
+ static void ObjectStatsCountFixedArray(
+ FixedArrayBase* fixed_array,
+ FixedArraySubInstanceType fast_type,
+ FixedArraySubInstanceType dictionary_type);
+
+ template<StaticMarkingVisitor::VisitorId id>
class ObjectStatsTracker {
public:
static inline void Visit(Map* map, HeapObject* obj);
@@ -1499,16 +1507,84 @@
};
-template<int id>
-void StaticMarkingVisitor::ObjectStatsTracker<id>::Visit(
- Map* map, HeapObject* obj) {
+void StaticMarkingVisitor::ObjectStatsCountFixedArray(
+ FixedArrayBase* fixed_array,
+ FixedArraySubInstanceType fast_type,
+ FixedArraySubInstanceType dictionary_type) {
+ Heap* heap = fixed_array->map()->GetHeap();
+ if (fixed_array->map() != heap->fixed_cow_array_map() &&
+ fixed_array->map() != heap->fixed_double_array_map() &&
+ fixed_array != heap->empty_fixed_array()) {
+ if (fixed_array->IsDictionary()) {
+ heap->RecordObjectStats(FIXED_ARRAY_TYPE,
+ dictionary_type,
+ fixed_array->Size());
+ } else {
+ heap->RecordObjectStats(FIXED_ARRAY_TYPE,
+ fast_type,
+ fixed_array->Size());
+ }
+ }
+}
+
+
+void StaticMarkingVisitor::ObjectStatsVisitBase(
+ StaticVisitorBase::VisitorId id, Map* map, HeapObject* obj) {
Heap* heap = map->GetHeap();
int object_size = obj->Size();
heap->RecordObjectStats(map->instance_type(), -1, object_size);
- non_count_table_.GetVisitorById(static_cast<VisitorId>(id))(map, obj);
+ non_count_table_.GetVisitorById(id)(map, obj);
+ if (obj->IsJSObject()) {
+ JSObject* object = JSObject::cast(obj);
+ ObjectStatsCountFixedArray(object->elements(),
+ DICTIONARY_ELEMENTS_SUB_TYPE,
+ FAST_ELEMENTS_SUB_TYPE);
+ ObjectStatsCountFixedArray(object->properties(),
+ DICTIONARY_PROPERTIES_SUB_TYPE,
+ FAST_PROPERTIES_SUB_TYPE);
+ }
}
+template<StaticMarkingVisitor::VisitorId id>
+void StaticMarkingVisitor::ObjectStatsTracker<id>::Visit(
+ Map* map, HeapObject* obj) {
+ ObjectStatsVisitBase(id, map, obj);
+}
+
+
+template<>
+class StaticMarkingVisitor::ObjectStatsTracker<
+ StaticMarkingVisitor::kVisitMap> {
+ public:
+ static inline void Visit(Map* map, HeapObject* obj) {
+ Heap* heap = map->GetHeap();
+ Map* map_obj = Map::cast(obj);
+ ASSERT(map->instance_type() == MAP_TYPE);
+ DescriptorArray* array = map_obj->instance_descriptors();
+ if (array != heap->empty_descriptor_array()) {
+ int fixed_array_size = array->Size();
+ heap->RecordObjectStats(FIXED_ARRAY_TYPE,
+ DESCRIPTOR_ARRAY_SUB_TYPE,
+ fixed_array_size);
+ }
+ if (map_obj->HasTransitionArray()) {
+ int fixed_array_size = map_obj->transitions()->Size();
+ heap->RecordObjectStats(FIXED_ARRAY_TYPE,
+ TRANSITION_ARRAY_SUB_TYPE,
+ fixed_array_size);
+ }
+ if (map_obj->code_cache() != heap->empty_fixed_array()) {
+ heap->RecordObjectStats(
+ FIXED_ARRAY_TYPE,
+ MAP_CODE_CACHE_SUB_TYPE,
+ FixedArray::cast(map_obj->code_cache())->Size());
+ }
+ ObjectStatsVisitBase(kVisitMap, map, obj);
+ }
+};
+
+
template<>
class StaticMarkingVisitor::ObjectStatsTracker<
StaticMarkingVisitor::kVisitCode> {
@@ -1517,10 +1593,44 @@
Heap* heap = map->GetHeap();
int object_size = obj->Size();
ASSERT(map->instance_type() == CODE_TYPE);
- heap->RecordObjectStats(CODE_TYPE, -1, object_size);
heap->RecordObjectStats(CODE_TYPE, Code::cast(obj)->kind(), object_size);
- non_count_table_.GetVisitorById(
- static_cast<VisitorId>(kVisitCode))(map, obj);
+ ObjectStatsVisitBase(kVisitCode, map, obj);
+ }
+};
+
+
+template<>
+class StaticMarkingVisitor::ObjectStatsTracker<
+ StaticMarkingVisitor::kVisitSharedFunctionInfo> {
+ public:
+ static inline void Visit(Map* map, HeapObject* obj) {
+ Heap* heap = map->GetHeap();
+ SharedFunctionInfo* sfi = SharedFunctionInfo::cast(obj);
+ if (sfi->scope_info() != heap->empty_fixed_array()) {
+ heap->RecordObjectStats(
+ FIXED_ARRAY_TYPE,
+ SCOPE_INFO_SUB_TYPE,
+ FixedArray::cast(sfi->scope_info())->Size());
+ }
+ ObjectStatsVisitBase(kVisitSharedFunctionInfo, map, obj);
+ }
+};
+
+
+template<>
+class StaticMarkingVisitor::ObjectStatsTracker<
+ StaticMarkingVisitor::kVisitFixedArray> {
+ public:
+ static inline void Visit(Map* map, HeapObject* obj) {
+ Heap* heap = map->GetHeap();
+ FixedArray* fixed_array = FixedArray::cast(obj);
+ if (fixed_array == heap->symbol_table()) {
+ heap->RecordObjectStats(
+ FIXED_ARRAY_TYPE,
+ SYMBOL_TABLE_SUB_TYPE,
+ fixed_array->Size());
+ }
+ ObjectStatsVisitBase(kVisitFixedArray, map, obj);
}
};
@@ -1974,13 +2084,6 @@
if (!base_marker()->MarkObjectWithoutPush(transitions)) return;
Object** transitions_start = transitions->data_start();
- if (transitions->HasElementsTransition()) {
- mark_compact_collector()->RecordSlot(
- transitions_start,
- transitions->GetElementsTransitionSlot(),
- transitions->elements_transition());
- }
-
if (transitions->HasPrototypeTransitions()) {
// Mark prototype transitions array but don't push it into marking stack.
// This will make references from it weak. We will clean dead prototype
@@ -2003,16 +2106,6 @@
}
-template <class T>
-void Marker<T>::MarkAccessorPairSlot(AccessorPair* accessors, int offset) {
- Object** slot = HeapObject::RawField(accessors, offset);
- HeapObject* accessor = HeapObject::cast(*slot);
- if (accessor->IsMap()) return;
- mark_compact_collector()->RecordSlot(slot, slot, accessor);
- base_marker()->MarkObjectAndPush(accessor);
-}
-
-
// Fill the marking stack with overflowed objects returned by the given
// iterator. Stop when the marking stack is filled or the end of the space
// is reached, whichever comes first.
@@ -3309,6 +3402,8 @@
void MarkCompactCollector::EvacuateNewSpaceAndCandidates() {
+ Heap::RelocationLock relocation_lock(heap());
+
bool code_slots_filtering_required;
{ GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_SWEEP_NEWSPACE);
code_slots_filtering_required = MarkInvalidatedCode();
diff --git a/src/mark-compact.h b/src/mark-compact.h
index c2a70fc..ed3def5 100644
--- a/src/mark-compact.h
+++ b/src/mark-compact.h
@@ -396,7 +396,6 @@
void MarkMapContents(Map* map);
void MarkDescriptorArray(DescriptorArray* descriptors);
void MarkTransitionArray(TransitionArray* transitions);
- void MarkAccessorPairSlot(AccessorPair* accessors, int offset);
private:
BaseMarker* base_marker() {
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index 7ae84fa..0eea32c 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -3533,23 +3533,23 @@
1,
1);
} else {
- if (!CpuFeatures::IsSupported(FPU)) UNREACHABLE();
+ ASSERT(CpuFeatures::IsSupported(FPU));
CpuFeatures::Scope scope(FPU);
Label no_update;
Label skip_cache;
// Call C function to calculate the result and update the cache.
- // Register a0 holds precalculated cache entry address; preserve
- // it on the stack and pop it into register cache_entry after the
- // call.
- __ Push(cache_entry, a2, a3);
+ // a0: precalculated cache entry address.
+ // a2 and a3: parts of the double value.
+ // Store a0, a2 and a3 on stack for later before calling C function.
+ __ Push(a3, a2, cache_entry);
GenerateCallCFunction(masm, scratch0);
__ GetCFunctionDoubleResult(f4);
// Try to update the cache. If we cannot allocate a
// heap number, we return the result without updating.
- __ Pop(cache_entry, a2, a3);
+ __ Pop(a3, a2, cache_entry);
__ LoadRoot(t1, Heap::kHeapNumberMapRootIndex);
__ AllocateHeapNumber(t2, scratch0, scratch1, t1, &no_update);
__ sdc1(f4, FieldMemOperand(t2, HeapNumber::kValueOffset));
diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc
index 55b37b4..6f4869e 100644
--- a/src/mips/full-codegen-mips.cc
+++ b/src/mips/full-codegen-mips.cc
@@ -1149,7 +1149,7 @@
// We got a map in register v0. Get the enumeration cache from it.
__ bind(&use_cache);
__ LoadInstanceDescriptors(v0, a1, a2);
- __ lw(a1, FieldMemOperand(a1, DescriptorArray::kLastAddedOffset));
+ __ lw(a1, FieldMemOperand(a1, DescriptorArray::kEnumCacheOffset));
__ lw(a2, FieldMemOperand(a1, DescriptorArray::kEnumCacheBridgeCacheOffset));
// Set up the four remaining stack slots.
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc
index 6885104..e924159 100644
--- a/src/mips/lithium-codegen-mips.cc
+++ b/src/mips/lithium-codegen-mips.cc
@@ -5170,7 +5170,7 @@
Register scratch = ToRegister(instr->scratch());
__ LoadInstanceDescriptors(map, result, scratch);
__ lw(result,
- FieldMemOperand(result, DescriptorArray::kLastAddedOffset));
+ FieldMemOperand(result, DescriptorArray::kEnumCacheOffset));
__ lw(result,
FieldMemOperand(result, FixedArray::SizeFor(instr->idx())));
DeoptimizeIf(eq, instr->environment(), result, Operand(zero_reg));
diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc
index a0fea77..a7673d1 100644
--- a/src/mips/macro-assembler-mips.cc
+++ b/src/mips/macro-assembler-mips.cc
@@ -5339,7 +5339,7 @@
// Check that there is an enum cache in the non-empty instance
// descriptors (a3). This is the case if the next enumeration
// index field does not contain a smi.
- lw(a3, FieldMemOperand(a3, DescriptorArray::kLastAddedOffset));
+ lw(a3, FieldMemOperand(a3, DescriptorArray::kEnumCacheOffset));
JumpIfSmi(a3, call_runtime);
// For all objects but the receiver, check that the cache is empty.
diff --git a/src/objects-inl.h b/src/objects-inl.h
index feca271..f4e0767 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -1952,12 +1952,12 @@
// Perform a linear search in this fixed array. len is the number of entry
// indices that are valid.
template<typename T>
-int LinearSearch(T* array, SearchMode mode, String* name, int len) {
+int LinearSearch(T* array, String* name, int len) {
uint32_t hash = name->Hash();
for (int number = 0; number < len; number++) {
String* entry = array->GetKey(number);
uint32_t current_hash = entry->Hash();
- if (mode == EXPECT_SORTED && current_hash > hash) break;
+ if (current_hash > hash) break;
if (current_hash == hash && name->Equals(entry)) return number;
}
return T::kNotFound;
@@ -1975,7 +1975,7 @@
// Fast case: do linear search for small arrays.
const int kMaxElementsForLinearSearch = 8;
if (StringShape(name).IsSymbol() && nof < kMaxElementsForLinearSearch) {
- return LinearSearch(array, EXPECT_SORTED, name, nof);
+ return LinearSearch(array, name, nof);
}
// Slow case: perform binary search.
@@ -2110,13 +2110,26 @@
}
-void DescriptorArray::Append(Descriptor* desc,
- const WhitenessWitness& witness) {
- int descriptor_number = NumberOfSetDescriptors();
+int DescriptorArray::Append(Descriptor* desc,
+ const WhitenessWitness& witness,
+ int number_of_set_descriptors) {
+ int descriptor_number = number_of_set_descriptors;
int enumeration_index = descriptor_number + 1;
desc->SetEnumerationIndex(enumeration_index);
+
+ uint32_t hash = desc->GetKey()->Hash();
+
+ for (; descriptor_number > 0; --descriptor_number) {
+ String* key = GetKey(descriptor_number - 1);
+ if (key->Hash() <= hash) break;
+ Object* value = GetValue(descriptor_number - 1);
+ PropertyDetails details = GetDetails(descriptor_number - 1);
+ Descriptor moved_descriptor(key, value, details);
+ Set(descriptor_number, &moved_descriptor, witness);
+ }
+
Set(descriptor_number, desc, witness);
- SetLastAdded(descriptor_number);
+ return descriptor_number;
}
@@ -2434,9 +2447,10 @@
}
-void SlicedString::set_parent(String* parent) {
+void SlicedString::set_parent(String* parent, WriteBarrierMode mode) {
ASSERT(parent->IsSeqString() || parent->IsExternalString());
WRITE_FIELD(this, kParentOffset, parent);
+ CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kParentOffset, parent, mode);
}
@@ -2940,16 +2954,12 @@
void Map::set_function_with_prototype(bool value) {
- if (value) {
- set_bit_field3(bit_field3() | (1 << kFunctionWithPrototype));
- } else {
- set_bit_field3(bit_field3() & ~(1 << kFunctionWithPrototype));
- }
+ set_bit_field3(FunctionWithPrototype::update(bit_field3(), value));
}
bool Map::function_with_prototype() {
- return ((1 << kFunctionWithPrototype) & bit_field3()) != 0;
+ return FunctionWithPrototype::decode(bit_field3());
}
@@ -2994,15 +3004,11 @@
void Map::set_is_shared(bool value) {
- if (value) {
- set_bit_field3(bit_field3() | (1 << kIsShared));
- } else {
- set_bit_field3(bit_field3() & ~(1 << kIsShared));
- }
+ set_bit_field3(IsShared::update(bit_field3(), value));
}
bool Map::is_shared() {
- return ((1 << kIsShared) & bit_field3()) != 0;
+ return IsShared::decode(bit_field3());
}
@@ -3488,6 +3494,40 @@
}
+void Map::InitializeDescriptors(DescriptorArray* descriptors) {
+ int len = descriptors->number_of_descriptors();
+ ASSERT(len <= DescriptorArray::kMaxNumberOfDescriptors);
+ SLOW_ASSERT(descriptors->IsSortedNoDuplicates());
+
+#ifdef DEBUG
+ bool used_indices[DescriptorArray::kMaxNumberOfDescriptors];
+ for (int i = 0; i < len; ++i) used_indices[i] = false;
+
+ // Ensure that all enumeration indexes between 1 and length occur uniquely in
+ // the descriptor array.
+ for (int i = 0; i < len; ++i) {
+ int enum_index = descriptors->GetDetails(i).index() -
+ PropertyDetails::kInitialIndex;
+ ASSERT(0 <= enum_index && enum_index < len);
+ ASSERT(!used_indices[enum_index]);
+ used_indices[enum_index] = true;
+ }
+#endif
+
+ set_instance_descriptors(descriptors);
+
+ for (int i = 0; i < len; ++i) {
+ if (descriptors->GetDetails(i).index() == len) {
+ SetLastAdded(i);
+ break;
+ }
+ }
+
+ ASSERT(len == 0 ||
+ len == descriptors->GetDetails(LastAdded()).index());
+}
+
+
SMI_ACCESSORS(Map, bit_field3, kBitField3Offset)
@@ -3507,6 +3547,14 @@
}
+void Map::AppendDescriptor(Descriptor* desc,
+ const DescriptorArray::WhitenessWitness& witness) {
+ DescriptorArray* descriptors = instance_descriptors();
+ int set_descriptors = NumberOfSetDescriptors();
+ int new_last_added = descriptors->Append(desc, witness, set_descriptors);
+ SetLastAdded(new_last_added);
+}
+
Object* Map::GetBackPointer() {
Object* object = READ_FIELD(this, kInstanceDescriptorsOrBackPointerOffset);
@@ -4202,6 +4250,18 @@
}
+bool JSFunction::IsMarkedForParallelRecompilation() {
+ return code() ==
+ GetIsolate()->builtins()->builtin(Builtins::kParallelRecompile);
+}
+
+
+bool JSFunction::IsInRecompileQueue() {
+ return code() == GetIsolate()->builtins()->builtin(
+ Builtins::kInRecompileQueue);
+}
+
+
Code* JSFunction::code() {
return Code::cast(unchecked_code());
}
diff --git a/src/objects.cc b/src/objects.cc
index 2ce1451..6511843 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -2771,9 +2771,9 @@
strict_mode);
case TRANSITION: {
Map* transition_map = result->GetTransitionTarget();
+ int descriptor = transition_map->LastAdded();
DescriptorArray* descriptors = transition_map->instance_descriptors();
- int descriptor = descriptors->LastAdded();
PropertyDetails details = descriptors->GetDetails(descriptor);
if (details.type() == FIELD) {
@@ -2892,9 +2892,9 @@
return ConvertDescriptorToField(name, value, attributes);
case TRANSITION: {
Map* transition_map = result.GetTransitionTarget();
+ int descriptor = transition_map->LastAdded();
DescriptorArray* descriptors = transition_map->instance_descriptors();
- int descriptor = descriptors->LastAdded();
PropertyDetails details = descriptors->GetDetails(descriptor);
if (details.type() == FIELD) {
@@ -3080,17 +3080,16 @@
// except for the code cache, which can contain some ics which can be
// applied to the shared map.
Object* fresh;
- { MaybeObject* maybe_fresh =
- fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
- if (maybe_fresh->ToObject(&fresh)) {
- ASSERT(memcmp(Map::cast(fresh)->address(),
- Map::cast(result)->address(),
- Map::kCodeCacheOffset) == 0);
- int offset = Map::kCodeCacheOffset + kPointerSize;
- ASSERT(memcmp(Map::cast(fresh)->address() + offset,
- Map::cast(result)->address() + offset,
- Map::kSize - offset) == 0);
- }
+ MaybeObject* maybe_fresh =
+ fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
+ if (maybe_fresh->ToObject(&fresh)) {
+ ASSERT(memcmp(Map::cast(fresh)->address(),
+ Map::cast(result)->address(),
+ Map::kCodeCacheOffset) == 0);
+ int offset = Map::kCodeCacheOffset + kPointerSize;
+ ASSERT(memcmp(Map::cast(fresh)->address() + offset,
+ Map::cast(result)->address() + offset,
+ Map::kSize - offset) == 0);
}
}
#endif
@@ -4496,7 +4495,7 @@
// If there is a transition, try to follow it.
if (result.IsFound()) {
Map* target = result.GetTransitionTarget();
- int descriptor_number = target->instance_descriptors()->LastAdded();
+ int descriptor_number = target->LastAdded();
ASSERT(target->instance_descriptors()->GetKey(descriptor_number) == name);
return TryAccessorTransition(
this, target, descriptor_number, component, accessor, attributes);
@@ -4711,14 +4710,14 @@
}
Map* result;
- { MaybeObject* maybe_result = RawCopy(new_instance_size);
- if (!maybe_result->To(&result)) return maybe_result;
- }
+ MaybeObject* maybe_result = RawCopy(new_instance_size);
+ if (!maybe_result->To(&result)) return maybe_result;
if (mode != CLEAR_INOBJECT_PROPERTIES) {
result->set_inobject_properties(inobject_properties());
}
+ result->SetLastAdded(kNoneAdded);
result->set_code_cache(code_cache());
result->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
@@ -4750,12 +4749,20 @@
MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors,
String* name,
+ int last_added,
TransitionFlag flag) {
Map* result;
MaybeObject* maybe_result = CopyDropDescriptors();
if (!maybe_result->To(&result)) return maybe_result;
- result->set_instance_descriptors(descriptors);
+ if (last_added == kNoneAdded) {
+ ASSERT(descriptors->IsEmpty());
+ } else {
+ ASSERT(descriptors->GetDetails(last_added).index() ==
+ descriptors->number_of_descriptors());
+ result->set_instance_descriptors(descriptors);
+ result->SetLastAdded(last_added);
+ }
if (flag == INSERT_TRANSITION) {
TransitionArray* transitions;
@@ -4807,32 +4814,80 @@
// array describing these properties.
ASSERT(constructor()->IsJSFunction());
JSFunction* ctor = JSFunction::cast(constructor());
+ Map* initial_map = ctor->initial_map();
+ DescriptorArray* initial_descriptors = initial_map->instance_descriptors();
DescriptorArray* descriptors;
MaybeObject* maybe_descriptors =
- ctor->initial_map()->instance_descriptors()->Copy(
- DescriptorArray::MAY_BE_SHARED);
+ initial_descriptors->Copy(DescriptorArray::MAY_BE_SHARED);
if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
- return CopyReplaceDescriptors(descriptors, NULL, OMIT_TRANSITION);
+ int last_added = initial_descriptors->IsEmpty()
+ ? kNoneAdded
+ : initial_map->LastAdded();
+
+ return CopyReplaceDescriptors(descriptors, NULL, last_added, OMIT_TRANSITION);
}
MaybeObject* Map::Copy(DescriptorArray::SharedMode shared_mode) {
+ DescriptorArray* source_descriptors = instance_descriptors();
DescriptorArray* descriptors;
- MaybeObject* maybe_descriptors = instance_descriptors()->Copy(shared_mode);
+ MaybeObject* maybe_descriptors = source_descriptors->Copy(shared_mode);
if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
- return CopyReplaceDescriptors(descriptors, NULL, OMIT_TRANSITION);
+ int last_added = source_descriptors->IsEmpty() ? kNoneAdded : LastAdded();
+
+ return CopyReplaceDescriptors(descriptors, NULL, last_added, OMIT_TRANSITION);
+}
+
+
+static bool InsertionPointFound(String* key1, String* key2) {
+ return key1->Hash() > key2->Hash() || key1 == key2;
}
MaybeObject* Map::CopyAddDescriptor(Descriptor* descriptor,
TransitionFlag flag) {
- DescriptorArray* descriptors;
- MaybeObject* maybe_descriptors = instance_descriptors()->CopyAdd(descriptor);
- if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
+ DescriptorArray* descriptors = instance_descriptors();
- return CopyReplaceDescriptors(descriptors, descriptor->GetKey(), flag);
+ // Ensure the key is a symbol.
+ MaybeObject* maybe_failure = descriptor->KeyToSymbol();
+ if (maybe_failure->IsFailure()) return maybe_failure;
+
+ String* key = descriptor->GetKey();
+ ASSERT(descriptors->Search(key) == DescriptorArray::kNotFound);
+
+ int old_size = descriptors->number_of_descriptors();
+ int new_size = old_size + 1;
+
+ DescriptorArray* new_descriptors;
+ MaybeObject* maybe_descriptors =
+ DescriptorArray::Allocate(new_size, DescriptorArray::MAY_BE_SHARED);
+ if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
+
+ FixedArray::WhitenessWitness witness(new_descriptors);
+
+ // Copy the descriptors, inserting a descriptor.
+ int insertion_index = -1;
+ int to = 0;
+ for (int from = 0; from < old_size; ++from) {
+ if (insertion_index < 0 &&
+ InsertionPointFound(descriptors->GetKey(from), key)) {
+ insertion_index = to++;
+ }
+ new_descriptors->CopyFrom(to++, descriptors, from, witness);
+ }
+ if (insertion_index < 0) insertion_index = to++;
+
+ ASSERT(to == new_size);
+ ASSERT(new_size == descriptors->NextEnumerationIndex());
+
+ descriptor->SetEnumerationIndex(new_size);
+ new_descriptors->Set(insertion_index, descriptor, witness);
+
+ SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates());
+
+ return CopyReplaceDescriptors(new_descriptors, key, insertion_index, flag);
}
@@ -4844,31 +4899,49 @@
MaybeObject* maybe_result = descriptor->KeyToSymbol();
if (maybe_result->IsFailure()) return maybe_result;
- DescriptorArray* descriptors;
- MaybeObject* maybe_descriptors;
-
// We replace the key if it is already present.
int index = old_descriptors->SearchWithCache(descriptor->GetKey());
- if (index == DescriptorArray::kNotFound) {
- maybe_descriptors = old_descriptors->CopyAdd(descriptor);
- } else {
- maybe_descriptors = old_descriptors->CopyReplace(descriptor, index);
+ if (index != DescriptorArray::kNotFound) {
+ return CopyReplaceDescriptor(descriptor, index, flag);
}
- if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
-
- return CopyReplaceDescriptors(descriptors, descriptor->GetKey(), flag);
+ return CopyAddDescriptor(descriptor, flag);
}
MaybeObject* Map::CopyReplaceDescriptor(Descriptor* descriptor,
- int index,
+ int insertion_index,
TransitionFlag flag) {
- DescriptorArray* descriptors;
- MaybeObject* maybe_descriptors =
- instance_descriptors()->CopyReplace(descriptor, index);
- if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
+ DescriptorArray* descriptors = instance_descriptors();
+ int size = descriptors->number_of_descriptors();
+ ASSERT(0 <= insertion_index && insertion_index < size);
- return CopyReplaceDescriptors(descriptors, descriptor->GetKey(), flag);
+ // Ensure the key is a symbol.
+ MaybeObject* maybe_failure = descriptor->KeyToSymbol();
+ if (maybe_failure->IsFailure()) return maybe_failure;
+
+ String* key = descriptor->GetKey();
+ ASSERT(key == descriptors->GetKey(insertion_index));
+
+ DescriptorArray* new_descriptors;
+ MaybeObject* maybe_descriptors =
+ DescriptorArray::Allocate(size, DescriptorArray::MAY_BE_SHARED);
+ if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
+
+ FixedArray::WhitenessWitness witness(new_descriptors);
+
+ // Copy the descriptors, replacing a descriptor.
+ for (int index = 0; index < size; ++index) {
+ if (index == insertion_index) continue;
+ new_descriptors->CopyFrom(index, descriptors, index, witness);
+ }
+
+ descriptor->SetEnumerationIndex(
+ descriptors->GetDetails(insertion_index).index());
+ new_descriptors->Set(insertion_index, descriptor, witness);
+
+ SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates());
+
+ return CopyReplaceDescriptors(new_descriptors, key, LastAdded(), flag);
}
@@ -5655,7 +5728,7 @@
if (!maybe_array->To(&result)) return maybe_array;
}
- result->set(kLastAddedIndex, Smi::FromInt(kNoneAdded));
+ result->set(kEnumCacheIndex, Smi::FromInt(0));
result->set(kTransitionsIndex, Smi::FromInt(0));
return result;
}
@@ -5667,9 +5740,9 @@
ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
ASSERT(new_index_cache->IsSmi() || new_index_cache->IsFixedArray());
if (HasEnumCache()) {
- FixedArray::cast(get(kLastAddedIndex))->
+ FixedArray::cast(get(kEnumCacheIndex))->
set(kEnumCacheBridgeCacheIndex, new_cache);
- FixedArray::cast(get(kLastAddedIndex))->
+ FixedArray::cast(get(kEnumCacheIndex))->
set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache);
} else {
if (IsEmpty()) return; // Do nothing for empty descriptor array.
@@ -5677,19 +5750,11 @@
set(kEnumCacheBridgeCacheIndex, new_cache);
FixedArray::cast(bridge_storage)->
set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache);
- NoWriteBarrierSet(FixedArray::cast(bridge_storage),
- kEnumCacheBridgeLastAdded,
- get(kLastAddedIndex));
- set(kLastAddedIndex, bridge_storage);
+ set(kEnumCacheIndex, bridge_storage);
}
}
-static bool InsertionPointFound(String* key1, String* key2) {
- return key1->Hash() > key2->Hash() || key1 == key2;
-}
-
-
void DescriptorArray::CopyFrom(int dst_index,
DescriptorArray* src,
int src_index,
@@ -5700,79 +5765,6 @@
Set(dst_index, &desc, witness);
}
-MaybeObject* DescriptorArray::CopyReplace(Descriptor* descriptor,
- int insertion_index) {
- ASSERT(0 <= insertion_index && insertion_index < number_of_descriptors());
-
- // Ensure the key is a symbol.
- { MaybeObject* maybe_result = descriptor->KeyToSymbol();
- if (maybe_result->IsFailure()) return maybe_result;
- }
-
- int size = number_of_descriptors();
-
- DescriptorArray* new_descriptors;
- { MaybeObject* maybe_result = Allocate(size, MAY_BE_SHARED);
- if (!maybe_result->To(&new_descriptors)) return maybe_result;
- }
-
- FixedArray::WhitenessWitness witness(new_descriptors);
-
- // Copy the descriptors, replacing a descriptor.
- for (int index = 0; index < size; ++index) {
- if (index == insertion_index) continue;
- new_descriptors->CopyFrom(index, this, index, witness);
- }
-
- descriptor->SetEnumerationIndex(GetDetails(insertion_index).index());
- new_descriptors->Set(insertion_index, descriptor, witness);
- new_descriptors->SetLastAdded(LastAdded());
-
- SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates());
-
- return new_descriptors;
-}
-
-
-MaybeObject* DescriptorArray::CopyAdd(Descriptor* descriptor) {
- // Ensure the key is a symbol.
- MaybeObject* maybe_result = descriptor->KeyToSymbol();
- if (maybe_result->IsFailure()) return maybe_result;
-
- String* key = descriptor->GetKey();
- ASSERT(Search(key) == kNotFound);
-
- int new_size = number_of_descriptors() + 1;
-
- DescriptorArray* new_descriptors;
- MaybeObject* maybe_descriptors = Allocate(new_size, MAY_BE_SHARED);
- if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
-
- FixedArray::WhitenessWitness witness(new_descriptors);
-
- // Copy the descriptors, inserting a descriptor.
- int insertion_index = -1;
- int to = 0;
- for (int from = 0; from < number_of_descriptors(); ++from) {
- if (insertion_index < 0 && InsertionPointFound(GetKey(from), key)) {
- insertion_index = to++;
- }
- new_descriptors->CopyFrom(to++, this, from, witness);
- }
- if (insertion_index < 0) insertion_index = to++;
-
- ASSERT(to == new_descriptors->number_of_descriptors());
-
- ASSERT(new_size == NextEnumerationIndex());
- descriptor->SetEnumerationIndex(new_size);
- new_descriptors->Set(insertion_index, descriptor, witness);
- new_descriptors->SetLastAdded(insertion_index);
-
- SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates());
-
- return new_descriptors;
-}
-
MaybeObject* DescriptorArray::Copy(SharedMode shared_mode) {
// Allocate the new descriptor array.
@@ -5787,25 +5779,19 @@
for (int i = 0; i < number_of_descriptors; i++) {
new_descriptors->CopyFrom(i, this, i, witness);
}
- new_descriptors->SetLastAdded(LastAdded());
}
return new_descriptors;
}
+
// We need the whiteness witness since sort will reshuffle the entries in the
// descriptor array. If the descriptor array were to be black, the shuffling
// would move a slot that was already recorded as pointing into an evacuation
// candidate. This would result in missing updates upon evacuation.
-void DescriptorArray::SortUnchecked(const WhitenessWitness& witness) {
+void DescriptorArray::Sort(const WhitenessWitness& witness) {
// In-place heap sort.
int len = number_of_descriptors();
- // Nothing to sort.
- if (len == 0) return;
-
- ASSERT(LastAdded() == kNoneAdded ||
- GetDetails(LastAdded()).index() == number_of_descriptors());
-
// Bottom-up max-heap construction.
// Index of the last node with children
const int max_parent_index = (len / 2) - 1;
@@ -5852,36 +5838,6 @@
parent_index = child_index;
}
}
-
-#ifdef DEBUG
- // Ensure that all enumeration indexes between 1 and length occur uniquely in
- // the descriptor array.
- for (int i = 1; i <= len; ++i) {
- int j;
- for (j = 0; j < len; ++j) {
- if (GetDetails(j).index() == i) break;
- }
- ASSERT(j != len);
- for (j++; j < len; ++j) {
- ASSERT(GetDetails(j).index() != i);
- }
- }
-#endif
-
- for (int i = 0; i < len; ++i) {
- if (GetDetails(i).index() == len) {
- SetLastAdded(i);
- return;
- }
- }
-
- UNREACHABLE();
-}
-
-
-void DescriptorArray::Sort(const WhitenessWitness& witness) {
- SortUnchecked(witness);
- SLOW_ASSERT(IsSortedNoDuplicates());
}
@@ -7263,8 +7219,10 @@
instance_type() == other->instance_type() &&
bit_field() == other->bit_field() &&
bit_field2() == other->bit_field2() &&
- (bit_field3() & ~(1<<Map::kIsShared)) ==
- (other->bit_field3() & ~(1<<Map::kIsShared));
+ static_cast<uint32_t>(bit_field3()) ==
+ LastAddedBits::update(
+ IsShared::update(other->bit_field3(), true),
+ kNoneAdded);
}
@@ -7285,6 +7243,18 @@
ReplaceCode(builtins->builtin(Builtins::kLazyRecompile));
}
+void JSFunction::MarkForParallelRecompilation() {
+ ASSERT(is_compiled() && !IsOptimized());
+ ASSERT(shared()->allows_lazy_compilation() || code()->optimizable());
+ Builtins* builtins = GetIsolate()->builtins();
+ ReplaceCode(builtins->builtin(Builtins::kParallelRecompile));
+
+ // Unlike MarkForLazyRecompilation, after queuing a function for
+ // recompilation on the compiler thread, we actually tail-call into
+ // the full code. We reset the profiler ticks here so that the
+ // function doesn't bother the runtime profiler too much.
+ shared()->code()->set_profiler_ticks(0);
+}
static bool CompileLazyHelper(CompilationInfo* info,
ClearExceptionFlag flag) {
@@ -12477,6 +12447,24 @@
}
}
+ int inobject_props = obj->map()->inobject_properties();
+
+ // Allocate new map.
+ Map* new_map;
+ MaybeObject* maybe_new_map = obj->map()->CopyDropDescriptors();
+ if (!maybe_new_map->To(&new_map)) return maybe_new_map;
+
+ if (instance_descriptor_length == 0) {
+ ASSERT_LE(unused_property_fields, inobject_props);
+ // Transform the object.
+ new_map->set_unused_property_fields(unused_property_fields);
+ obj->set_map(new_map);
+ obj->set_properties(heap->empty_fixed_array());
+ // Check that it really works.
+ ASSERT(obj->HasFastProperties());
+ return obj;
+ }
+
// Allocate the instance descriptor.
DescriptorArray* descriptors;
MaybeObject* maybe_descriptors =
@@ -12488,7 +12476,6 @@
FixedArray::WhitenessWitness witness(descriptors);
- int inobject_props = obj->map()->inobject_properties();
int number_of_allocated_fields =
number_of_fields + unused_property_fields - inobject_props;
if (number_of_allocated_fields < 0) {
@@ -12553,13 +12540,9 @@
ASSERT(current_offset == number_of_fields);
descriptors->Sort(witness);
- // Allocate new map.
- Map* new_map;
- MaybeObject* maybe_new_map =
- obj->map()->CopyReplaceDescriptors(descriptors, NULL, OMIT_TRANSITION);
- if (!maybe_new_map->To(&new_map)) return maybe_new_map;
new_map->set_unused_property_fields(unused_property_fields);
+ new_map->InitializeDescriptors(descriptors);
// Transform the object.
obj->set_map(new_map);
diff --git a/src/objects.h b/src/objects.h
index 6349c02..92c2bc5 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -33,7 +33,7 @@
#include "elements-kind.h"
#include "list.h"
#include "property-details.h"
-#include "smart-array-pointer.h"
+#include "smart-pointers.h"
#include "unicode-inl.h"
#if V8_TARGET_ARCH_ARM
#include "arm/constants-arm.h"
@@ -170,14 +170,6 @@
};
-// Indicates whether the search function should expect a sorted or an unsorted
-// array as input.
-enum SearchMode {
- EXPECT_SORTED,
- EXPECT_UNSORTED
-};
-
-
// Indicates whether transitions can be added to a source map or not.
enum TransitionFlag {
INSERT_TRANSITION,
@@ -662,6 +654,25 @@
STATIC_CHECK(FOREIGN_TYPE == Internals::kForeignType);
+#define FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(V) \
+ V(FAST_ELEMENTS_SUB_TYPE) \
+ V(DICTIONARY_ELEMENTS_SUB_TYPE) \
+ V(FAST_PROPERTIES_SUB_TYPE) \
+ V(DICTIONARY_PROPERTIES_SUB_TYPE) \
+ V(MAP_CODE_CACHE_SUB_TYPE) \
+ V(SCOPE_INFO_SUB_TYPE) \
+ V(SYMBOL_TABLE_SUB_TYPE) \
+ V(DESCRIPTOR_ARRAY_SUB_TYPE) \
+ V(TRANSITION_ARRAY_SUB_TYPE)
+
+enum FixedArraySubInstanceType {
+#define DEFINE_FIXED_ARRAY_SUB_INSTANCE_TYPE(name) name,
+ FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(DEFINE_FIXED_ARRAY_SUB_INSTANCE_TYPE)
+#undef DEFINE_FIXED_ARRAY_SUB_INSTANCE_TYPE
+ LAST_FIXED_ARRAY_SUB_TYPE = TRANSITION_ARRAY_SUB_TYPE
+};
+
+
enum CompareResult {
LESS = -1,
EQUAL = 0,
@@ -2480,43 +2491,20 @@
inline int number_of_entries() { return number_of_descriptors(); }
inline int NextEnumerationIndex() { return number_of_descriptors() + 1; }
- int LastAdded() {
- ASSERT(!IsEmpty());
- Object* obj = get(kLastAddedIndex);
- if (obj->IsSmi()) {
- return Smi::cast(obj)->value();
- } else {
- Object* index = FixedArray::cast(obj)->get(kEnumCacheBridgeLastAdded);
- return Smi::cast(index)->value();
- }
- }
-
- // Set index of the last added descriptor and flush any enum cache.
- void SetLastAdded(int index) {
- ASSERT(!IsEmpty() || index > 0);
- set(kLastAddedIndex, Smi::FromInt(index));
- }
-
- int NumberOfSetDescriptors() {
- ASSERT(!IsEmpty());
- if (LastAdded() == kNoneAdded) return 0;
- return GetDetails(LastAdded()).index();
- }
-
bool HasEnumCache() {
- return !IsEmpty() && !get(kLastAddedIndex)->IsSmi();
+ return !IsEmpty() && !get(kEnumCacheIndex)->IsSmi();
}
Object* GetEnumCache() {
ASSERT(HasEnumCache());
- FixedArray* bridge = FixedArray::cast(get(kLastAddedIndex));
+ FixedArray* bridge = FixedArray::cast(get(kEnumCacheIndex));
return bridge->get(kEnumCacheBridgeCacheIndex);
}
Object** GetEnumCacheSlot() {
ASSERT(HasEnumCache());
return HeapObject::RawField(reinterpret_cast<HeapObject*>(this),
- kLastAddedOffset);
+ kEnumCacheOffset);
}
Object** GetTransitionsSlot() {
@@ -2552,8 +2540,9 @@
// Append automatically sets the enumeration index. This should only be used
// to add descriptors in bulk at the end, followed by sorting the descriptor
// array.
- inline void Append(Descriptor* desc,
- const WhitenessWitness&);
+ inline int Append(Descriptor* desc,
+ const WhitenessWitness&,
+ int number_of_set_descriptors);
// Transfer a complete descriptor from the src descriptor array to this
// descriptor array.
@@ -2562,16 +2551,6 @@
int src_index,
const WhitenessWitness&);
- // Copy the descriptor array, inserting new descriptor. Its enumeration index
- // is automatically set to the size of the descriptor array to which it was
- // added first.
- MUST_USE_RESULT MaybeObject* CopyAdd(Descriptor* descriptor);
-
- // Copy the descriptor array, replacing a descriptor. Its enumeration index is
- // kept.
- MUST_USE_RESULT MaybeObject* CopyReplace(Descriptor* descriptor,
- int insertion_index);
-
// Indicates whether the search function should expect a sorted or an unsorted
// descriptor array as input.
enum SharedMode {
@@ -2584,11 +2563,6 @@
MUST_USE_RESULT MaybeObject* Copy(SharedMode shared_mode);
// Sort the instance descriptors by the hash codes of their keys.
- // Does not check for duplicates.
- void SortUnchecked(const WhitenessWitness&);
-
- // Sort the instance descriptors by the hash codes of their keys.
- // Checks the result for duplicates.
void Sort(const WhitenessWitness&);
// Search the instance descriptors for given name.
@@ -2612,31 +2586,25 @@
// Constant for denoting key was not found.
static const int kNotFound = -1;
- // Constant for denoting that the LastAdded field was not yet set.
- static const int kNoneAdded = -1;
-
static const int kBackPointerStorageIndex = 0;
- static const int kLastAddedIndex = 1;
+ static const int kEnumCacheIndex = 1;
static const int kTransitionsIndex = 2;
static const int kFirstIndex = 3;
// The length of the "bridge" to the enum cache.
- static const int kEnumCacheBridgeLength = 3;
- static const int kEnumCacheBridgeLastAdded = 0;
- static const int kEnumCacheBridgeCacheIndex = 1;
- static const int kEnumCacheBridgeIndicesCacheIndex = 2;
+ static const int kEnumCacheBridgeLength = 2;
+ static const int kEnumCacheBridgeCacheIndex = 0;
+ static const int kEnumCacheBridgeIndicesCacheIndex = 1;
// Layout description.
static const int kBackPointerStorageOffset = FixedArray::kHeaderSize;
- static const int kLastAddedOffset = kBackPointerStorageOffset +
+ static const int kEnumCacheOffset = kBackPointerStorageOffset +
kPointerSize;
- static const int kTransitionsOffset = kLastAddedOffset + kPointerSize;
+ static const int kTransitionsOffset = kEnumCacheOffset + kPointerSize;
static const int kFirstOffset = kTransitionsOffset + kPointerSize;
// Layout description for the bridge array.
- static const int kEnumCacheBridgeLastAddedOffset = FixedArray::kHeaderSize;
- static const int kEnumCacheBridgeCacheOffset =
- kEnumCacheBridgeLastAddedOffset + kPointerSize;
+ static const int kEnumCacheBridgeCacheOffset = FixedArray::kHeaderSize;
// Layout of descriptor.
static const int kDescriptorKey = 0;
@@ -2714,7 +2682,7 @@
template<typename T>
-inline int LinearSearch(T* array, SearchMode mode, String* name, int len);
+inline int LinearSearch(T* array, String* name, int len);
template<typename T>
@@ -4696,6 +4664,10 @@
inline int bit_field3();
inline void set_bit_field3(int value);
+ class IsShared: public BitField<bool, 0, 1> {};
+ class FunctionWithPrototype: public BitField<bool, 1, 1> {};
+ class LastAddedBits: public BitField<int, 2, 11> {};
+
// Tells whether the object in the prototype property will be used
// for instances created from this function. If the prototype
// property is set to a value that is not a JSObject, the prototype
@@ -4855,6 +4827,7 @@
// [instance descriptors]: describes the object.
DECL_ACCESSORS(instance_descriptors, DescriptorArray)
+ inline void InitializeDescriptors(DescriptorArray* descriptors);
// Should only be called to clear a descriptor array that was only used to
// store transitions and does not contain any live transitions anymore.
@@ -4919,11 +4892,28 @@
String* name,
LookupResult* result);
+ void SetLastAdded(int index) {
+ set_bit_field3(LastAddedBits::update(bit_field3(), index));
+ }
+
+ int LastAdded() {
+ return LastAddedBits::decode(bit_field3());
+ }
+
+ int NumberOfSetDescriptors() {
+ ASSERT(!instance_descriptors()->IsEmpty());
+ if (LastAdded() == kNoneAdded) return 0;
+ return instance_descriptors()->GetDetails(LastAdded()).index();
+ }
+
MUST_USE_RESULT MaybeObject* RawCopy(int instance_size);
MUST_USE_RESULT MaybeObject* CopyWithPreallocatedFieldDescriptors();
MUST_USE_RESULT MaybeObject* CopyDropDescriptors();
MUST_USE_RESULT MaybeObject* CopyReplaceDescriptors(
- DescriptorArray* descriptors, String* name, TransitionFlag flag);
+ DescriptorArray* descriptors,
+ String* name,
+ int last_added,
+ TransitionFlag flag);
MUST_USE_RESULT MaybeObject* CopyAddDescriptor(Descriptor* descriptor,
TransitionFlag flag);
MUST_USE_RESULT MaybeObject* CopyInsertDescriptor(Descriptor* descriptor,
@@ -4937,6 +4927,9 @@
MUST_USE_RESULT MaybeObject* CopyNormalized(PropertyNormalizationMode mode,
NormalizedMapSharingMode sharing);
+ inline void AppendDescriptor(Descriptor* desc,
+ const DescriptorArray::WhitenessWitness&);
+
// Returns a copy of the map, with all transitions dropped from the
// instance descriptors.
MUST_USE_RESULT MaybeObject* Copy(DescriptorArray::SharedMode shared_mode);
@@ -5048,6 +5041,9 @@
static const int kMaxPreAllocatedPropertyFields = 255;
+ // Constant for denoting that the LastAdded field was not yet set.
+ static const int kNoneAdded = LastAddedBits::kMax;
+
// Layout description.
static const int kInstanceSizesOffset = HeapObject::kHeaderSize;
static const int kInstanceAttributesOffset = kInstanceSizesOffset + kIntSize;
@@ -6001,6 +5997,7 @@
// Mark this function for lazy recompilation. The function will be
// recompiled the next time it is executed.
void MarkForLazyRecompilation();
+ void MarkForParallelRecompilation();
// Helpers to compile this function. Returns true on success, false on
// failure (e.g., stack overflow during compilation).
@@ -6015,6 +6012,11 @@
// Tells whether or not the function is already marked for lazy
// recompilation.
inline bool IsMarkedForLazyRecompilation();
+ inline bool IsMarkedForParallelRecompilation();
+
+ // Tells whether or not the function is on the parallel
+ // recompilation queue.
+ inline bool IsInRecompileQueue();
// Check whether or not this function is inlineable.
bool IsInlineable();
@@ -7595,7 +7597,8 @@
class SlicedString: public String {
public:
inline String* parent();
- inline void set_parent(String* parent);
+ inline void set_parent(String* parent,
+ WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
inline int offset();
inline void set_offset(int offset);
diff --git a/src/optimizing-compiler-thread.cc b/src/optimizing-compiler-thread.cc
new file mode 100644
index 0000000..06018dd
--- /dev/null
+++ b/src/optimizing-compiler-thread.cc
@@ -0,0 +1,127 @@
+// Copyright 2012 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.
+
+#include "optimizing-compiler-thread.h"
+
+#include "v8.h"
+
+#include "hydrogen.h"
+#include "isolate.h"
+#include "v8threads.h"
+
+namespace v8 {
+namespace internal {
+
+
+void OptimizingCompilerThread::Run() {
+#ifdef DEBUG
+ thread_id_ = ThreadId::Current().ToInteger();
+#endif
+ Isolate::SetIsolateThreadLocals(isolate_, NULL);
+
+ int64_t epoch = 0;
+ if (FLAG_trace_parallel_recompilation) epoch = OS::Ticks();
+
+ while (true) {
+ input_queue_semaphore_->Wait();
+ if (Acquire_Load(&stop_thread_)) {
+ stop_semaphore_->Signal();
+ if (FLAG_trace_parallel_recompilation) {
+ time_spent_total_ = OS::Ticks() - epoch;
+ }
+ return;
+ }
+
+ int64_t compiling_start = 0;
+ if (FLAG_trace_parallel_recompilation) compiling_start = OS::Ticks();
+
+ Heap::RelocationLock relocation_lock(isolate_->heap());
+ OptimizingCompiler* optimizing_compiler = NULL;
+ input_queue_.Dequeue(&optimizing_compiler);
+ Barrier_AtomicIncrement(&queue_length_, static_cast<Atomic32>(-1));
+
+ ASSERT(!optimizing_compiler->info()->closure()->IsOptimized());
+
+ OptimizingCompiler::Status status = optimizing_compiler->OptimizeGraph();
+ ASSERT(status != OptimizingCompiler::FAILED);
+ // Prevent an unused-variable error in release mode.
+ USE(status);
+
+ output_queue_.Enqueue(optimizing_compiler);
+ isolate_->stack_guard()->RequestCodeReadyEvent();
+
+ if (FLAG_trace_parallel_recompilation) {
+ time_spent_compiling_ += OS::Ticks() - compiling_start;
+ }
+ }
+}
+
+
+void OptimizingCompilerThread::Stop() {
+ Release_Store(&stop_thread_, static_cast<AtomicWord>(true));
+ input_queue_semaphore_->Signal();
+ stop_semaphore_->Wait();
+
+ if (FLAG_trace_parallel_recompilation) {
+ double compile_time = static_cast<double>(time_spent_compiling_);
+ double total_time = static_cast<double>(time_spent_total_);
+ double percentage = (compile_time * 100) / total_time;
+ PrintF(" ** Compiler thread did %.2f%% useful work\n", percentage);
+ }
+}
+
+
+void OptimizingCompilerThread::InstallOptimizedFunctions() {
+ HandleScope handle_scope(isolate_);
+ int functions_installed = 0;
+ while (!output_queue_.IsEmpty()) {
+ OptimizingCompiler* compiler = NULL;
+ output_queue_.Dequeue(&compiler);
+ Compiler::InstallOptimizedCode(compiler);
+ functions_installed++;
+ }
+ if (FLAG_trace_parallel_recompilation && functions_installed != 0) {
+ PrintF(" ** Installed %d function(s).\n", functions_installed);
+ }
+}
+
+
+void OptimizingCompilerThread::QueueForOptimization(
+ OptimizingCompiler* optimizing_compiler) {
+ input_queue_.Enqueue(optimizing_compiler);
+ input_queue_semaphore_->Signal();
+}
+
+#ifdef DEBUG
+bool OptimizingCompilerThread::IsOptimizerThread() {
+ if (!FLAG_parallel_recompilation) return false;
+ return ThreadId::Current().ToInteger() == thread_id_;
+}
+#endif
+
+
+} } // namespace v8::internal
diff --git a/src/optimizing-compiler-thread.h b/src/optimizing-compiler-thread.h
new file mode 100644
index 0000000..d562726
--- /dev/null
+++ b/src/optimizing-compiler-thread.h
@@ -0,0 +1,101 @@
+// Copyright 2012 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.
+
+#ifndef V8_OPTIMIZING_COMPILER_THREAD_H_
+#define V8_OPTIMIZING_COMPILER_THREAD_H_
+
+#include "atomicops.h"
+#include "platform.h"
+#include "flags.h"
+#include "unbound-queue.h"
+
+namespace v8 {
+namespace internal {
+
+class HGraphBuilder;
+class OptimizingCompiler;
+
+class OptimizingCompilerThread : public Thread {
+ public:
+ explicit OptimizingCompilerThread(Isolate *isolate) :
+ Thread("OptimizingCompilerThread"),
+ isolate_(isolate),
+ stop_semaphore_(OS::CreateSemaphore(0)),
+ input_queue_semaphore_(OS::CreateSemaphore(0)),
+ time_spent_compiling_(0),
+ time_spent_total_(0) {
+ NoBarrier_Store(&stop_thread_, static_cast<AtomicWord>(false));
+ NoBarrier_Store(&queue_length_, static_cast<AtomicWord>(0));
+ }
+
+ void Run();
+ void Stop();
+ void QueueForOptimization(OptimizingCompiler* optimizing_compiler);
+ void InstallOptimizedFunctions();
+
+ inline bool IsQueueAvailable() {
+ // We don't need a barrier since we have a data dependency right
+ // after.
+ Atomic32 current_length = NoBarrier_Load(&queue_length_);
+
+ // This can be queried only from the execution thread.
+ ASSERT(!IsOptimizerThread());
+ // Since only the execution thread increments queue_length_ and
+ // only one thread can run inside an Isolate at one time, a direct
+ // doesn't introduce a race -- queue_length_ may decreased in
+ // meantime, but not increased.
+ return (current_length < FLAG_parallel_recompilation_queue_length);
+ }
+
+#ifdef DEBUG
+ bool IsOptimizerThread();
+#endif
+
+ ~OptimizingCompilerThread() {
+ delete input_queue_semaphore_;
+ delete stop_semaphore_;
+ }
+
+ private:
+ Isolate* isolate_;
+ Semaphore* stop_semaphore_;
+ Semaphore* input_queue_semaphore_;
+ UnboundQueue<OptimizingCompiler*> input_queue_;
+ UnboundQueue<OptimizingCompiler*> output_queue_;
+ volatile AtomicWord stop_thread_;
+ volatile Atomic32 queue_length_;
+ int64_t time_spent_compiling_;
+ int64_t time_spent_total_;
+
+#ifdef DEBUG
+ int thread_id_;
+#endif
+};
+
+} } // namespace v8::internal
+
+#endif // V8_OPTIMIZING_COMPILER_THREAD_H_
diff --git a/src/parser.cc b/src/parser.cc
index 5ec2857..5ee217c 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -567,14 +567,15 @@
FunctionLiteral* Parser::ParseProgram() {
ZoneScope zone_scope(zone(), DONT_DELETE_ON_EXIT);
-
HistogramTimerScope timer(isolate()->counters()->parse());
Handle<String> source(String::cast(script_->source()));
isolate()->counters()->total_parse_size()->Increment(source->length());
+ int64_t start = FLAG_trace_parse ? OS::Ticks() : 0;
fni_ = new(zone()) FuncNameInferrer(isolate(), zone());
// Initialize parser state.
source->TryFlatten();
+ FunctionLiteral* result;
if (source->IsExternalTwoByteString()) {
// Notice that the stream is destroyed at the end of the branch block.
// The last line of the blocks can't be moved outside, even though they're
@@ -582,12 +583,27 @@
ExternalTwoByteStringUtf16CharacterStream stream(
Handle<ExternalTwoByteString>::cast(source), 0, source->length());
scanner_.Initialize(&stream);
- return DoParseProgram(info(), source, &zone_scope);
+ result = DoParseProgram(info(), source, &zone_scope);
} else {
GenericStringUtf16CharacterStream stream(source, 0, source->length());
scanner_.Initialize(&stream);
- return DoParseProgram(info(), source, &zone_scope);
+ result = DoParseProgram(info(), source, &zone_scope);
}
+
+ if (FLAG_trace_parse && result != NULL) {
+ double ms = static_cast<double>(OS::Ticks() - start) / 1000;
+ if (info()->is_eval()) {
+ PrintF("[parsing eval");
+ } else if (info()->script()->name()->IsString()) {
+ String* name = String::cast(info()->script()->name());
+ SmartArrayPointer<char> name_chars = name->ToCString();
+ PrintF("[parsing script: %s", *name_chars);
+ } else {
+ PrintF("[parsing script");
+ }
+ PrintF(" - took %0.3f ms]\n", ms);
+ }
+ return result;
}
@@ -668,24 +684,31 @@
HistogramTimerScope timer(isolate()->counters()->parse_lazy());
Handle<String> source(String::cast(script_->source()));
isolate()->counters()->total_parse_size()->Increment(source->length());
-
+ int64_t start = FLAG_trace_parse ? OS::Ticks() : 0;
Handle<SharedFunctionInfo> shared_info = info()->shared_info();
+
// Initialize parser state.
source->TryFlatten();
+ FunctionLiteral* result;
if (source->IsExternalTwoByteString()) {
ExternalTwoByteStringUtf16CharacterStream stream(
Handle<ExternalTwoByteString>::cast(source),
shared_info->start_position(),
shared_info->end_position());
- FunctionLiteral* result = ParseLazy(&stream, &zone_scope);
- return result;
+ result = ParseLazy(&stream, &zone_scope);
} else {
GenericStringUtf16CharacterStream stream(source,
shared_info->start_position(),
shared_info->end_position());
- FunctionLiteral* result = ParseLazy(&stream, &zone_scope);
- return result;
+ result = ParseLazy(&stream, &zone_scope);
}
+
+ if (FLAG_trace_parse && result != NULL) {
+ double ms = static_cast<double>(OS::Ticks() - start) / 1000;
+ SmartArrayPointer<char> name_chars = result->name()->ToCString();
+ PrintF("[parsing function: %s - took %0.3f ms]\n", *name_chars, ms);
+ }
+ return result;
}
diff --git a/src/profile-generator-inl.h b/src/profile-generator-inl.h
index 6c64350..02e146f 100644
--- a/src/profile-generator-inl.h
+++ b/src/profile-generator-inl.h
@@ -84,6 +84,7 @@
return gc_entry_;
case JS:
case COMPILER:
+ case PARALLEL_COMPILER_PROLOGUE:
// DOM events handlers are reported as OTHER / EXTERNAL entries.
// To avoid confusing people, let's put all these entries into
// one bucket.
diff --git a/src/runtime-profiler.cc b/src/runtime-profiler.cc
index cdbc77a..1856359 100644
--- a/src/runtime-profiler.cc
+++ b/src/runtime-profiler.cc
@@ -151,15 +151,20 @@
PrintF("]\n");
}
- // The next call to the function will trigger optimization.
- function->MarkForLazyRecompilation();
+ if (FLAG_parallel_recompilation) {
+ function->MarkForParallelRecompilation();
+ } else {
+ // The next call to the function will trigger optimization.
+ function->MarkForLazyRecompilation();
+ }
}
void RuntimeProfiler::AttemptOnStackReplacement(JSFunction* function) {
// See AlwaysFullCompiler (in compiler.cc) comment on why we need
// Debug::has_break_points().
- ASSERT(function->IsMarkedForLazyRecompilation());
+ ASSERT(function->IsMarkedForLazyRecompilation() ||
+ function->IsMarkedForParallelRecompilation());
if (!FLAG_use_osr ||
isolate_->DebuggerHasBreakPoints() ||
function->IsBuiltin()) {
@@ -278,7 +283,8 @@
if (shared_code->kind() != Code::FUNCTION) continue;
- if (function->IsMarkedForLazyRecompilation()) {
+ if (function->IsMarkedForLazyRecompilation() ||
+ function->IsMarkedForParallelRecompilation()) {
int nesting = shared_code->allow_osr_at_loop_nesting_level();
if (nesting == 0) AttemptOnStackReplacement(function);
int new_nesting = Min(nesting + 1, Code::kMaxLoopNestingMarker);
diff --git a/src/runtime.cc b/src/runtime.cc
index 54bb61a..f7bd0e4 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -54,7 +54,7 @@
#include "runtime-profiler.h"
#include "runtime.h"
#include "scopeinfo.h"
-#include "smart-array-pointer.h"
+#include "smart-pointers.h"
#include "string-search.h"
#include "stub-cache.h"
#include "v8threads.h"
@@ -2160,10 +2160,7 @@
RUNTIME_ASSERT(args.length() == 1);
CONVERT_ARG_CHECKED(JSFunction, function, 0);
- MaybeObject* maybe_name =
- isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
- String* name;
- if (!maybe_name->To(&name)) return maybe_name;
+ String* name = isolate->heap()->prototype_symbol();
if (function->HasFastProperties()) {
// Construct a new field descriptor with updated attributes.
@@ -8292,6 +8289,14 @@
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_ParallelRecompile) {
+ HandleScope handle_scope(isolate);
+ ASSERT(FLAG_parallel_recompilation);
+ Compiler::RecompileParallel(args.at<JSFunction>(0));
+ return *isolate->factory()->undefined_value();
+}
+
+
class ActivationsFinder : public ThreadVisitor {
public:
explicit ActivationsFinder(JSFunction* function)
@@ -8486,6 +8491,11 @@
return Smi::FromInt(4); // 4 == "never".
}
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
+ if (FLAG_parallel_recompilation) {
+ if (function->IsMarkedForLazyRecompilation()) {
+ return Smi::FromInt(5);
+ }
+ }
if (FLAG_always_opt) {
// We may have always opt, but that is more best-effort than a real
// promise, so we still say "no" if it is not optimized.
diff --git a/src/runtime.h b/src/runtime.h
index c5c8bcb..da78c26 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -86,6 +86,7 @@
F(NewStrictArgumentsFast, 3, 1) \
F(LazyCompile, 1, 1) \
F(LazyRecompile, 1, 1) \
+ F(ParallelRecompile, 1, 1) \
F(NotifyDeoptimized, 1, 1) \
F(NotifyOSR, 0, 1) \
F(DeoptimizeFunction, 1, 1) \
diff --git a/src/smart-array-pointer.h b/src/smart-pointers.h
similarity index 67%
rename from src/smart-array-pointer.h
rename to src/smart-pointers.h
index 00721c1..345c4d4 100644
--- a/src/smart-array-pointer.h
+++ b/src/smart-pointers.h
@@ -25,34 +25,33 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#ifndef V8_SMART_ARRAY_POINTER_H_
-#define V8_SMART_ARRAY_POINTER_H_
+#ifndef V8_SMART_POINTERS_H_
+#define V8_SMART_POINTERS_H_
namespace v8 {
namespace internal {
-// A 'scoped array pointer' that calls DeleteArray on its pointer when the
-// destructor is called.
-template<typename T>
-class SmartArrayPointer {
+template<typename Deallocator, typename T>
+class SmartPointerBase {
public:
// Default constructor. Constructs an empty scoped pointer.
- inline SmartArrayPointer() : p_(NULL) {}
+ inline SmartPointerBase() : p_(NULL) {}
// Constructs a scoped pointer from a plain one.
- explicit inline SmartArrayPointer(T* ptr) : p_(ptr) {}
+ explicit inline SmartPointerBase(T* ptr) : p_(ptr) {}
// Copy constructor removes the pointer from the original to avoid double
// freeing.
- inline SmartArrayPointer(const SmartArrayPointer<T>& rhs) : p_(rhs.p_) {
- const_cast<SmartArrayPointer<T>&>(rhs).p_ = NULL;
+ inline SmartPointerBase(const SmartPointerBase<Deallocator, T>& rhs)
+ : p_(rhs.p_) {
+ const_cast<SmartPointerBase<Deallocator, T>&>(rhs).p_ = NULL;
}
// When the destructor of the scoped pointer is executed the plain pointer
// is deleted using DeleteArray. This implies that you must allocate with
// NewArray.
- inline ~SmartArrayPointer() { if (p_) DeleteArray(p_); }
+ inline ~SmartPointerBase() { if (p_) Deallocator::Delete(p_); }
inline T* operator->() const { return p_; }
@@ -81,10 +80,11 @@
// Assignment requires an empty (NULL) SmartArrayPointer as the receiver. Like
// the copy constructor it removes the pointer in the original to avoid
// double freeing.
- inline SmartArrayPointer& operator=(const SmartArrayPointer<T>& rhs) {
+ inline SmartPointerBase<Deallocator, T>& operator=(
+ const SmartPointerBase<Deallocator, T>& rhs) {
ASSERT(is_empty());
T* tmp = rhs.p_; // swap to handle self-assignment
- const_cast<SmartArrayPointer<T>&>(rhs).p_ = NULL;
+ const_cast<SmartPointerBase<Deallocator, T>&>(rhs).p_ = NULL;
p_ = tmp;
return *this;
}
@@ -95,6 +95,45 @@
T* p_;
};
+// A 'scoped array pointer' that calls DeleteArray on its pointer when the
+// destructor is called.
+
+template<typename T>
+struct ArrayDeallocator {
+ static void Delete(T* array) {
+ DeleteArray(array);
+ }
+};
+
+
+template<typename T>
+class SmartArrayPointer: public SmartPointerBase<ArrayDeallocator<T>, T> {
+ public:
+ inline SmartArrayPointer() { }
+ explicit inline SmartArrayPointer(T* ptr)
+ : SmartPointerBase<ArrayDeallocator<T>, T>(ptr) { }
+ inline SmartArrayPointer(const SmartArrayPointer<T>& rhs)
+ : SmartPointerBase<ArrayDeallocator<T>, T>(rhs) { }
+};
+
+
+template<typename T>
+struct ObjectDeallocator {
+ static void Delete(T* array) {
+ Malloced::Delete(array);
+ }
+};
+
+template<typename T>
+class SmartPointer: public SmartPointerBase<ObjectDeallocator<T>, T> {
+ public:
+ inline SmartPointer() { }
+ explicit inline SmartPointer(T* ptr)
+ : SmartPointerBase<ObjectDeallocator<T>, T>(ptr) { }
+ inline SmartPointer(const SmartPointer<T>& rhs)
+ : SmartPointerBase<ObjectDeallocator<T>, T>(rhs) { }
+};
+
} } // namespace v8::internal
-#endif // V8_SMART_ARRAY_POINTER_H_
+#endif // V8_SMART_POINTERS_H_
diff --git a/src/transitions-inl.h b/src/transitions-inl.h
index 0de9854..24ff8c2 100644
--- a/src/transitions-inl.h
+++ b/src/transitions-inl.h
@@ -161,18 +161,12 @@
PropertyDetails TransitionArray::GetTargetDetails(int transition_number) {
Map* map = GetTarget(transition_number);
DescriptorArray* descriptors = map->instance_descriptors();
- int descriptor = descriptors->LastAdded();
- ASSERT(descriptor != DescriptorArray::kNotFound);
+ int descriptor = map->LastAdded();
+ ASSERT(descriptor != Map::kNoneAdded);
return descriptors->GetDetails(descriptor);
}
-Object** TransitionArray::GetElementsTransitionSlot() {
- return HeapObject::RawField(reinterpret_cast<HeapObject*>(this),
- kElementsTransitionOffset);
-}
-
-
int TransitionArray::Search(String* name) {
return internal::Search(this, name);
}
diff --git a/src/transitions.cc b/src/transitions.cc
index f2e49ec..5dda18e 100644
--- a/src/transitions.cc
+++ b/src/transitions.cc
@@ -69,10 +69,8 @@
MaybeObject* TransitionArray::NewWith(String* name, Map* target) {
TransitionArray* result;
- { MaybeObject* maybe_array;
- maybe_array = TransitionArray::Allocate(1);
- if (!maybe_array->To(&result)) return maybe_array;
- }
+ MaybeObject* maybe_array = TransitionArray::Allocate(1);
+ if (!maybe_array->To(&result)) return maybe_array;
FixedArray::WhitenessWitness witness(result);
diff --git a/src/transitions.h b/src/transitions.h
index 7acb88f..bc661ac 100644
--- a/src/transitions.h
+++ b/src/transitions.h
@@ -61,7 +61,6 @@
inline void set_elements_transition(
Map* target,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
- inline Object** GetElementsTransitionSlot();
inline bool HasElementsTransition();
inline void ClearElementsTransition();
diff --git a/src/v8-counters.cc b/src/v8-counters.cc
index f17aacc..b5a40b5 100644
--- a/src/v8-counters.cc
+++ b/src/v8-counters.cc
@@ -71,6 +71,16 @@
CODE_KIND_LIST(SC)
#undef SC
+#define SC(name) \
+ StatsCounter count_of_FIXED_ARRAY_##name = { \
+ "c:" "V8.CountOf_FIXED_ARRAY-" #name, NULL, false }; \
+ count_of_FIXED_ARRAY_##name##_ = count_of_FIXED_ARRAY_##name; \
+ StatsCounter size_of_FIXED_ARRAY_##name = { \
+ "c:" "V8.SizeOf_FIXED_ARRAY-" #name, NULL, false }; \
+ size_of_FIXED_ARRAY_##name##_ = size_of_FIXED_ARRAY_##name;
+ FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(SC)
+#undef SC
+
StatsCounter state_counters[] = {
#define COUNTER_NAME(name) \
{ "c:V8.State" #name, NULL, false },
diff --git a/src/v8-counters.h b/src/v8-counters.h
index cb789af..e230613 100644
--- a/src/v8-counters.h
+++ b/src/v8-counters.h
@@ -323,6 +323,14 @@
CODE_KIND_LIST(SC)
#undef SC
+#define SC(name) \
+ StatsCounter* count_of_FIXED_ARRAY_##name() \
+ { return &count_of_FIXED_ARRAY_##name##_; } \
+ StatsCounter* size_of_FIXED_ARRAY_##name() \
+ { return &size_of_FIXED_ARRAY_##name##_; }
+ FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(SC)
+#undef SC
+
enum Id {
#define RATE_ID(name, caption) k_##name,
HISTOGRAM_TIMER_LIST(RATE_ID)
@@ -341,6 +349,10 @@
kSizeOfCODE_TYPE_##name,
CODE_KIND_LIST(COUNTER_ID)
#undef COUNTER_ID
+#define COUNTER_ID(name) kCountOfFIXED_ARRAY__##name, \
+ kSizeOfFIXED_ARRAY__##name,
+ FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(COUNTER_ID)
+#undef COUNTER_ID
#define COUNTER_ID(name) k_##name,
STATE_TAG_LIST(COUNTER_ID)
#undef COUNTER_ID
@@ -380,6 +392,12 @@
CODE_KIND_LIST(SC)
#undef SC
+#define SC(name) \
+ StatsCounter size_of_FIXED_ARRAY_##name##_; \
+ StatsCounter count_of_FIXED_ARRAY_##name##_;
+ FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(SC)
+#undef SC
+
enum {
#define COUNTER_ID(name) __##name,
STATE_TAG_LIST(COUNTER_ID)
diff --git a/src/v8.cc b/src/v8.cc
index 2910a07..eaff43c 100644
--- a/src/v8.cc
+++ b/src/v8.cc
@@ -106,13 +106,16 @@
if (!has_been_set_up_ || has_been_disposed_) return;
+ // The isolate has to be torn down before clearing the LOperand
+ // caches so that the optimizing compiler thread (if running)
+ // doesn't see an inconsistent view of the lithium instructions.
+ isolate->TearDown();
+ delete isolate;
+
ElementsAccessor::TearDown();
LOperand::TearDownCaches();
RegisteredExtension::UnregisterAll();
- isolate->TearDown();
- delete isolate;
-
is_running_ = false;
has_been_disposed_ = true;
diff --git a/src/v8globals.h b/src/v8globals.h
index a295f8b..a95672d 100644
--- a/src/v8globals.h
+++ b/src/v8globals.h
@@ -359,11 +359,12 @@
// VMState object leaves a state by popping the current state from the
// stack.
-#define STATE_TAG_LIST(V) \
- V(JS) \
- V(GC) \
- V(COMPILER) \
- V(OTHER) \
+#define STATE_TAG_LIST(V) \
+ V(JS) \
+ V(GC) \
+ V(COMPILER) \
+ V(PARALLEL_COMPILER_PROLOGUE) \
+ V(OTHER) \
V(EXTERNAL)
enum StateTag {
diff --git a/src/version.cc b/src/version.cc
index 83fd1c1..03c020b 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,7 +34,7 @@
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 3
#define MINOR_VERSION 12
-#define BUILD_NUMBER 14
+#define BUILD_NUMBER 15
#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
diff --git a/src/vm-state-inl.h b/src/vm-state-inl.h
index c647e56..384940d 100644
--- a/src/vm-state-inl.h
+++ b/src/vm-state-inl.h
@@ -47,6 +47,8 @@
return "GC";
case COMPILER:
return "COMPILER";
+ case PARALLEL_COMPILER_PROLOGUE:
+ return "PARALLEL_COMPILER_PROLOGUE";
case OTHER:
return "OTHER";
case EXTERNAL:
diff --git a/src/x64/assembler-x64.cc b/src/x64/assembler-x64.cc
index 89b9710..b3aa936 100644
--- a/src/x64/assembler-x64.cc
+++ b/src/x64/assembler-x64.cc
@@ -75,6 +75,7 @@
// Save old rsp, since we are going to modify the stack.
__ push(rbp);
__ pushfq();
+ __ push(rdi);
__ push(rcx);
__ push(rbx);
__ movq(rbp, rsp);
@@ -128,6 +129,7 @@
__ movq(rsp, rbp);
__ pop(rbx);
__ pop(rcx);
+ __ pop(rdi);
__ popfq();
__ pop(rbp);
__ ret(0);
diff --git a/src/x64/builtins-x64.cc b/src/x64/builtins-x64.cc
index 0af0a43..b19a3d0 100644
--- a/src/x64/builtins-x64.cc
+++ b/src/x64/builtins-x64.cc
@@ -73,6 +73,45 @@
}
+static void GenerateTailCallToSharedCode(MacroAssembler* masm) {
+ __ movq(kScratchRegister,
+ FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
+ __ movq(kScratchRegister,
+ FieldOperand(kScratchRegister, SharedFunctionInfo::kCodeOffset));
+ __ lea(kScratchRegister, FieldOperand(kScratchRegister, Code::kHeaderSize));
+ __ jmp(kScratchRegister);
+}
+
+
+void Builtins::Generate_InRecompileQueue(MacroAssembler* masm) {
+ GenerateTailCallToSharedCode(masm);
+}
+
+
+void Builtins::Generate_ParallelRecompile(MacroAssembler* masm) {
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+
+ // Push a copy of the function onto the stack.
+ __ push(rdi);
+ // Push call kind information.
+ __ push(rcx);
+
+ __ push(rdi); // Function is also the parameter to the runtime call.
+ __ CallRuntime(Runtime::kParallelRecompile, 1);
+
+ // Restore call kind information.
+ __ pop(rcx);
+ // Restore receiver.
+ __ pop(rdi);
+
+ // Tear down internal frame.
+ }
+
+ GenerateTailCallToSharedCode(masm);
+}
+
+
static void Generate_JSConstructStubHelper(MacroAssembler* masm,
bool is_api_function,
bool count_constructions) {
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index 2a752f2..3eb6493 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -1111,7 +1111,7 @@
// We got a map in register rax. Get the enumeration cache from it.
__ bind(&use_cache);
__ LoadInstanceDescriptors(rax, rcx);
- __ movq(rcx, FieldOperand(rcx, DescriptorArray::kLastAddedOffset));
+ __ movq(rcx, FieldOperand(rcx, DescriptorArray::kEnumCacheOffset));
__ movq(rdx, FieldOperand(rcx, DescriptorArray::kEnumCacheBridgeCacheOffset));
// Set up the four remaining stack slots.
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index 461b632..3e688df 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -2503,18 +2503,22 @@
void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
Register result = ToRegister(instr->result());
-
- if (instr->hydrogen()->IsDehoisted() && !instr->key()->IsConstantOperand()) {
- // Sign extend key because it could be a 32 bit negative value
- // and the dehoisted address computation happens in 64 bits.
- Register key_reg = ToRegister(instr->key());
- __ movsxlq(key_reg, key_reg);
+ LOperand* key = instr->key();
+ if (!key->IsConstantOperand()) {
+ Register key_reg = ToRegister(key);
+ if (instr->hydrogen()->key()->representation().IsTagged()) {
+ __ SmiToInteger64(key_reg, key_reg);
+ } else if (instr->hydrogen()->IsDehoisted()) {
+ // Sign extend key because it could be a 32 bit negative value
+ // and the dehoisted address computation happens in 64 bits
+ __ movsxlq(key_reg, key_reg);
+ }
}
// Load the result.
__ movq(result,
BuildFastArrayOperand(instr->elements(),
- instr->key(),
+ key,
FAST_ELEMENTS,
FixedArray::kHeaderSize - kHeapObjectTag,
instr->additional_index()));
@@ -2535,12 +2539,16 @@
void LCodeGen::DoLoadKeyedFastDoubleElement(
LLoadKeyedFastDoubleElement* instr) {
XMMRegister result(ToDoubleRegister(instr->result()));
-
- if (instr->hydrogen()->IsDehoisted() && !instr->key()->IsConstantOperand()) {
- // Sign extend key because it could be a 32 bit negative value
- // and the dehoisted address computation happens in 64 bits
- Register key_reg = ToRegister(instr->key());
- __ movsxlq(key_reg, key_reg);
+ LOperand* key = instr->key();
+ if (!key->IsConstantOperand()) {
+ Register key_reg = ToRegister(key);
+ if (instr->hydrogen()->key()->representation().IsTagged()) {
+ __ SmiToInteger64(key_reg, key_reg);
+ } else if (instr->hydrogen()->IsDehoisted()) {
+ // Sign extend key because it could be a 32 bit negative value
+ // and the dehoisted address computation happens in 64 bits
+ __ movsxlq(key_reg, key_reg);
+ }
}
if (instr->hydrogen()->RequiresHoleCheck()) {
@@ -2548,7 +2556,7 @@
sizeof(kHoleNanLower32);
Operand hole_check_operand = BuildFastArrayOperand(
instr->elements(),
- instr->key(),
+ key,
FAST_DOUBLE_ELEMENTS,
offset,
instr->additional_index());
@@ -2558,7 +2566,7 @@
Operand double_load_operand = BuildFastArrayOperand(
instr->elements(),
- instr->key(),
+ key,
FAST_DOUBLE_ELEMENTS,
FixedDoubleArray::kHeaderSize - kHeapObjectTag,
instr->additional_index());
@@ -2595,17 +2603,23 @@
void LCodeGen::DoLoadKeyedSpecializedArrayElement(
LLoadKeyedSpecializedArrayElement* instr) {
ElementsKind elements_kind = instr->elements_kind();
- Operand operand(BuildFastArrayOperand(instr->external_pointer(),
- instr->key(),
- elements_kind,
- 0,
- instr->additional_index()));
- if (instr->hydrogen()->IsDehoisted() && !instr->key()->IsConstantOperand()) {
- // Sign extend key because it could be a 32 bit negative value
- // and the dehoisted address computation happens in 64 bits
- Register key_reg = ToRegister(instr->key());
- __ movsxlq(key_reg, key_reg);
+ LOperand* key = instr->key();
+ if (!key->IsConstantOperand()) {
+ Register key_reg = ToRegister(key);
+ if (instr->hydrogen()->key()->representation().IsTagged()) {
+ __ SmiToInteger64(key_reg, key_reg);
+ } else if (instr->hydrogen()->IsDehoisted()) {
+ // Sign extend key because it could be a 32 bit negative value
+ // and the dehoisted address computation happens in 64 bits
+ __ movsxlq(key_reg, key_reg);
+ }
}
+ Operand operand(BuildFastArrayOperand(
+ instr->external_pointer(),
+ key,
+ elements_kind,
+ 0,
+ instr->additional_index()));
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
XMMRegister result(ToDoubleRegister(instr->result()));
@@ -3538,18 +3552,23 @@
void LCodeGen::DoStoreKeyedSpecializedArrayElement(
LStoreKeyedSpecializedArrayElement* instr) {
ElementsKind elements_kind = instr->elements_kind();
- Operand operand(BuildFastArrayOperand(instr->external_pointer(),
- instr->key(),
- elements_kind,
- 0,
- instr->additional_index()));
-
- if (instr->hydrogen()->IsDehoisted() && !instr->key()->IsConstantOperand()) {
- // Sign extend key because it could be a 32 bit negative value
- // and the dehoisted address computation happens in 64 bits
- Register key_reg = ToRegister(instr->key());
- __ movsxlq(key_reg, key_reg);
+ LOperand* key = instr->key();
+ if (!key->IsConstantOperand()) {
+ Register key_reg = ToRegister(key);
+ if (instr->hydrogen()->key()->representation().IsTagged()) {
+ __ SmiToInteger64(key_reg, key_reg);
+ } else if (instr->hydrogen()->IsDehoisted()) {
+ // Sign extend key because it could be a 32 bit negative value
+ // and the dehoisted address computation happens in 64 bits
+ __ movsxlq(key_reg, key_reg);
+ }
}
+ Operand operand(BuildFastArrayOperand(
+ instr->external_pointer(),
+ key,
+ elements_kind,
+ 0,
+ instr->additional_index()));
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
XMMRegister value(ToDoubleRegister(instr->value()));
@@ -3593,7 +3612,8 @@
void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
if (instr->length()->IsRegister()) {
Register reg = ToRegister(instr->length());
- if (FLAG_debug_code) {
+ if (FLAG_debug_code &&
+ !instr->hydrogen()->index()->representation().IsTagged()) {
__ AbortIfNotZeroExtended(reg);
}
if (instr->index()->IsConstantOperand()) {
@@ -3601,7 +3621,8 @@
Immediate(ToInteger32(LConstantOperand::cast(instr->index()))));
} else {
Register reg2 = ToRegister(instr->index());
- if (FLAG_debug_code) {
+ if (FLAG_debug_code &&
+ !instr->hydrogen()->index()->representation().IsTagged()) {
__ AbortIfNotZeroExtended(reg2);
}
__ cmpq(reg, reg2);
@@ -3621,37 +3642,42 @@
void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
Register value = ToRegister(instr->value());
Register elements = ToRegister(instr->object());
- Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
+ LOperand* key = instr->key();
+ if (!key->IsConstantOperand()) {
+ Register key_reg = ToRegister(key);
+ if (instr->hydrogen()->key()->representation().IsTagged()) {
+ __ SmiToInteger64(key_reg, key_reg);
+ } else if (instr->hydrogen()->IsDehoisted()) {
+ // Sign extend key because it could be a 32 bit negative value
+ // and the dehoisted address computation happens in 64 bits
+ __ movsxlq(key_reg, key_reg);
+ }
+ }
Operand operand =
BuildFastArrayOperand(instr->object(),
- instr->key(),
+ key,
FAST_ELEMENTS,
FixedArray::kHeaderSize - kHeapObjectTag,
instr->additional_index());
- if (instr->hydrogen()->IsDehoisted() && !instr->key()->IsConstantOperand()) {
- // Sign extend key because it could be a 32 bit negative value
- // and the dehoisted address computation happens in 64 bits
- Register key_reg = ToRegister(instr->key());
- __ movsxlq(key_reg, key_reg);
- }
-
- __ movq(operand, value);
-
if (instr->hydrogen()->NeedsWriteBarrier()) {
ASSERT(!instr->key()->IsConstantOperand());
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, operand);
+ Register key_reg(ToRegister(key));
+ __ lea(key_reg, operand);
+ __ movq(Operand(key_reg, 0), value);
__ RecordWrite(elements,
- key,
+ key_reg,
value,
kSaveFPRegs,
EMIT_REMEMBERED_SET,
check_needed);
+ } else {
+ __ movq(operand, value);
}
}
@@ -3659,6 +3685,17 @@
void LCodeGen::DoStoreKeyedFastDoubleElement(
LStoreKeyedFastDoubleElement* instr) {
XMMRegister value = ToDoubleRegister(instr->value());
+ LOperand* key = instr->key();
+ if (!key->IsConstantOperand()) {
+ Register key_reg = ToRegister(key);
+ if (instr->hydrogen()->key()->representation().IsTagged()) {
+ __ SmiToInteger64(key_reg, key_reg);
+ } else if (instr->hydrogen()->IsDehoisted()) {
+ // Sign extend key because it could be a 32 bit negative value
+ // and the dehoisted address computation happens in 64 bits
+ __ movsxlq(key_reg, key_reg);
+ }
+ }
if (instr->NeedsCanonicalization()) {
Label have_value;
@@ -3675,18 +3712,11 @@
Operand double_store_operand = BuildFastArrayOperand(
instr->elements(),
- instr->key(),
+ key,
FAST_DOUBLE_ELEMENTS,
FixedDoubleArray::kHeaderSize - kHeapObjectTag,
instr->additional_index());
- if (instr->hydrogen()->IsDehoisted() && !instr->key()->IsConstantOperand()) {
- // Sign extend key because it could be a 32 bit negative value
- // and the dehoisted address computation happens in 64 bits
- Register key_reg = ToRegister(instr->key());
- __ movsxlq(key_reg, key_reg);
- }
-
__ movsd(double_store_operand, value);
}
@@ -5007,7 +5037,7 @@
Register result = ToRegister(instr->result());
__ LoadInstanceDescriptors(map, result);
__ movq(result,
- FieldOperand(result, DescriptorArray::kLastAddedOffset));
+ FieldOperand(result, DescriptorArray::kEnumCacheOffset));
__ movq(result,
FieldOperand(result, FixedArray::SizeFor(instr->idx())));
Condition cc = masm()->CheckSmi(result);
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index ecacac0..24b991e 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -1815,10 +1815,15 @@
LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
HLoadKeyedFastElement* instr) {
ASSERT(instr->representation().IsTagged());
- ASSERT(instr->key()->representation().IsInteger32());
+ ASSERT(instr->key()->representation().IsInteger32() ||
+ instr->key()->representation().IsTagged());
LOperand* obj = UseRegisterAtStart(instr->object());
- LOperand* key = UseRegisterOrConstantAtStart(instr->key());
- LLoadKeyedFastElement* result = new(zone()) LLoadKeyedFastElement(obj, key);
+ bool clobbers_key = instr->key()->representation().IsTagged();
+ LOperand* key = clobbers_key
+ ? UseTempRegister(instr->key())
+ : UseRegisterOrConstantAtStart(instr->key());
+ LLoadKeyedFastElement* result =
+ new(zone()) LLoadKeyedFastElement(obj, key);
if (instr->RequiresHoleCheck()) AssignEnvironment(result);
return DefineAsRegister(result);
}
@@ -1827,9 +1832,13 @@
LInstruction* LChunkBuilder::DoLoadKeyedFastDoubleElement(
HLoadKeyedFastDoubleElement* instr) {
ASSERT(instr->representation().IsDouble());
- ASSERT(instr->key()->representation().IsInteger32());
+ ASSERT(instr->key()->representation().IsInteger32() ||
+ instr->key()->representation().IsTagged());
LOperand* elements = UseRegisterAtStart(instr->elements());
- LOperand* key = UseRegisterOrConstantAtStart(instr->key());
+ bool clobbers_key = instr->key()->representation().IsTagged();
+ LOperand* key = clobbers_key
+ ? UseTempRegister(instr->key())
+ : UseRegisterOrConstantAtStart(instr->key());
LLoadKeyedFastDoubleElement* result =
new(zone()) LLoadKeyedFastDoubleElement(elements, key);
return AssignEnvironment(DefineAsRegister(result));
@@ -1846,9 +1855,13 @@
(instr->representation().IsDouble() &&
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
(elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
- ASSERT(instr->key()->representation().IsInteger32());
+ ASSERT(instr->key()->representation().IsInteger32() ||
+ instr->key()->representation().IsTagged());
LOperand* external_pointer = UseRegister(instr->external_pointer());
- LOperand* key = UseRegisterOrConstant(instr->key());
+ bool clobbers_key = instr->key()->representation().IsTagged();
+ LOperand* key = clobbers_key
+ ? UseTempRegister(instr->key())
+ : UseRegisterOrConstantAtStart(instr->key());
LLoadKeyedSpecializedArrayElement* result =
new(zone()) LLoadKeyedSpecializedArrayElement(external_pointer, key);
LInstruction* load_instr = DefineAsRegister(result);
@@ -1873,13 +1886,16 @@
bool needs_write_barrier = instr->NeedsWriteBarrier();
ASSERT(instr->value()->representation().IsTagged());
ASSERT(instr->object()->representation().IsTagged());
- ASSERT(instr->key()->representation().IsInteger32());
+ ASSERT(instr->key()->representation().IsInteger32() ||
+ instr->key()->representation().IsTagged());
LOperand* obj = UseTempRegister(instr->object());
LOperand* val = needs_write_barrier
? UseTempRegister(instr->value())
: UseRegisterAtStart(instr->value());
- LOperand* key = needs_write_barrier
+ bool clobbers_key = needs_write_barrier ||
+ instr->key()->representation().IsTagged();
+ LOperand* key = clobbers_key
? UseTempRegister(instr->key())
: UseRegisterOrConstantAtStart(instr->key());
return new(zone()) LStoreKeyedFastElement(obj, key, val);
@@ -1890,12 +1906,15 @@
HStoreKeyedFastDoubleElement* instr) {
ASSERT(instr->value()->representation().IsDouble());
ASSERT(instr->elements()->representation().IsTagged());
- ASSERT(instr->key()->representation().IsInteger32());
+ ASSERT(instr->key()->representation().IsInteger32() ||
+ instr->key()->representation().IsTagged());
LOperand* elements = UseRegisterAtStart(instr->elements());
LOperand* val = UseTempRegister(instr->value());
- LOperand* key = UseRegisterOrConstantAtStart(instr->key());
-
+ bool clobbers_key = instr->key()->representation().IsTagged();
+ LOperand* key = clobbers_key
+ ? UseTempRegister(instr->key())
+ : UseRegisterOrConstantAtStart(instr->key());
return new(zone()) LStoreKeyedFastDoubleElement(elements, key, val);
}
@@ -1911,7 +1930,8 @@
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
(elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
ASSERT(instr->external_pointer()->representation().IsExternal());
- ASSERT(instr->key()->representation().IsInteger32());
+ ASSERT(instr->key()->representation().IsInteger32() ||
+ instr->key()->representation().IsTagged());
LOperand* external_pointer = UseRegister(instr->external_pointer());
bool val_is_temp_register =
@@ -1920,11 +1940,12 @@
LOperand* val = val_is_temp_register
? UseTempRegister(instr->value())
: UseRegister(instr->value());
- LOperand* key = UseRegisterOrConstant(instr->key());
-
+ bool clobbers_key = instr->key()->representation().IsTagged();
+ LOperand* key = clobbers_key
+ ? UseTempRegister(instr->key())
+ : UseRegisterOrConstantAtStart(instr->key());
return new(zone()) LStoreKeyedSpecializedArrayElement(external_pointer,
- key,
- val);
+ key, val);
}
diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h
index e7a0a08..a7ae588 100644
--- a/src/x64/lithium-x64.h
+++ b/src/x64/lithium-x64.h
@@ -857,6 +857,7 @@
LOperand* length() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(BoundsCheck, "bounds-check")
+ DECLARE_HYDROGEN_ACCESSOR(BoundsCheck)
};
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc
index 4b8ca8f..e3c9a92 100644
--- a/src/x64/macro-assembler-x64.cc
+++ b/src/x64/macro-assembler-x64.cc
@@ -4473,7 +4473,7 @@
// Check that there is an enum cache in the non-empty instance
// descriptors (rdx). This is the case if the next enumeration
// index field does not contain a smi.
- movq(rdx, FieldOperand(rdx, DescriptorArray::kLastAddedOffset));
+ movq(rdx, FieldOperand(rdx, DescriptorArray::kEnumCacheOffset));
JumpIfSmi(rdx, call_runtime);
// For all objects but the receiver, check that the cache is empty.
diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status
index a2fa0aa..f529adb 100644
--- a/test/cctest/cctest.status
+++ b/test/cctest/cctest.status
@@ -54,7 +54,7 @@
test-weakmaps/Shrinking: FAIL
##############################################################################
-[ $arch == arm || $arch == android ]
+[ $arch == arm ]
# We cannot assume that we can throw OutOfMemory exceptions in all situations.
# Apparently our ARM box is in such a state. Skip the test as it also runs for
@@ -65,7 +65,7 @@
# BUG(355): Test crashes on ARM.
test-log/ProfLazyMode: SKIP
-# BUG(945): Socket connect fails on ARM
+# BUG(945): Tests using Socket cannot be run in parallel.
test-debug/DebuggerAgent: SKIP
test-debug/DebuggerAgentProtocolOverflowHeader: SKIP
test-sockets/Socket: SKIP
@@ -76,3 +76,18 @@
test-serialize/DeserializeAndRunScript2: SKIP
test-serialize/DeserializeFromSecondSerialization: SKIP
+##############################################################################
+[ $arch == android_arm || $arch == android_ia32 ]
+
+# Tests crash as there is no /tmp directory in Android.
+test-log/LogAccessorCallbacks: SKIP
+test-log/LogCallbacks: SKIP
+test-log/ProfLazyMode: SKIP
+
+# platform-tls.h does not contain an ANDROID-related header.
+test-platform-tls/FastTLS: SKIP
+
+# BUG(945): Tests using Socket cannot be run in parallel.
+test-debug/DebuggerAgent: SKIP
+test-debug/DebuggerAgentProtocolOverflowHeader: SKIP
+test-sockets/Socket: SKIP
diff --git a/test/cctest/test-alloc.cc b/test/cctest/test-alloc.cc
index a8e504f..f64ed1a 100644
--- a/test/cctest/test-alloc.cc
+++ b/test/cctest/test-alloc.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 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:
@@ -151,12 +151,21 @@
Handle<Map> map(function->initial_map());
Handle<DescriptorArray> instance_descriptors(map->instance_descriptors());
Handle<Foreign> foreign = FACTORY->NewForeign(&kDescriptor);
- instance_descriptors = FACTORY->CopyAppendForeignDescriptor(
- instance_descriptors,
- FACTORY->NewStringFromAscii(Vector<const char>("get", 3)),
- foreign,
- static_cast<PropertyAttributes>(0));
- map->set_instance_descriptors(*instance_descriptors);
+ Handle<String> name =
+ FACTORY->NewStringFromAscii(Vector<const char>("get", 3));
+ ASSERT(instance_descriptors->IsEmpty());
+
+ Handle<DescriptorArray> new_descriptors = FACTORY->NewDescriptorArray(1);
+
+ v8::internal::DescriptorArray::WhitenessWitness witness(*new_descriptors);
+ map->set_instance_descriptors(*new_descriptors);
+
+ CallbacksDescriptor d(*name,
+ *foreign,
+ static_cast<PropertyAttributes>(0),
+ v8::internal::PropertyDetails::kInitialIndex);
+ map->AppendDescriptor(&d, witness);
+
// Add the Foo constructor the global object.
env->Global()->Set(v8::String::New("Foo"), v8::Utils::ToLocal(function));
// Call the accessor through JavaScript.
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 9832c98..26483e0 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -3057,6 +3057,32 @@
}
+static void check_custom_error_message(
+ v8::Handle<v8::Message> message,
+ v8::Handle<v8::Value> data) {
+ const char* uncaught_error = "Uncaught MyError toString";
+ CHECK(message->Get()->Equals(v8_str(uncaught_error)));
+}
+
+
+TEST(CustomErrorToString) {
+ v8::HandleScope scope;
+ v8::V8::AddMessageListener(check_custom_error_message);
+ LocalContext context;
+ CompileRun(
+ "function MyError(name, message) { "
+ " this.name = name; "
+ " this.message = message; "
+ "} "
+ "MyError.prototype = Object.create(Error.prototype); "
+ "MyError.prototype.toString = function() { "
+ " return 'MyError toString'; "
+ "}; "
+ "throw new MyError('my name', 'my message'); ");
+ v8::V8::RemoveMessageListeners(check_custom_error_message);
+}
+
+
static void receive_message(v8::Handle<v8::Message> message,
v8::Handle<v8::Value> data) {
message->Get();
@@ -5544,6 +5570,7 @@
v8::Handle<String> str = v8_str("abcde");
// abc<Icelandic eth><Unicode snowman>.
v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
+ v8::Handle<String> str3 = v8::String::New("abc\0def", 7);
const int kStride = 4; // Must match stride in for loops in JS below.
CompileRun(
"var left = '';"
@@ -5754,6 +5781,28 @@
CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
utf8buf[8] = '\0';
CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
+
+ memset(utf8buf, 0x1, sizeof(utf8buf));
+ utf8buf[5] = 'X';
+ len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
+ String::NO_NULL_TERMINATION);
+ CHECK_EQ(5, len);
+ CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
+ CHECK_EQ(5, charlen);
+ utf8buf[5] = '\0';
+ CHECK_EQ(0, strcmp(utf8buf, "abcde"));
+
+ memset(buf, 0x1, sizeof(buf));
+ len = str3->WriteAscii(buf);
+ CHECK_EQ(7, len);
+ CHECK_EQ(0, strcmp("abc def", buf));
+
+ memset(buf, 0x1, sizeof(buf));
+ len = str3->WriteAscii(buf, 0, -1, String::PRESERVE_ASCII_NULL);
+ CHECK_EQ(7, len);
+ CHECK_EQ(0, strcmp("abc", buf));
+ CHECK_EQ(0, buf[3]);
+ CHECK_EQ(0, strcmp("def", buf + 4));
}
diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc
index a7deeeb..9229a97 100644
--- a/test/cctest/test-heap.cc
+++ b/test/cctest/test-heap.cc
@@ -1932,3 +1932,37 @@
HEAP->CollectAllAvailableGarbage("triggered really hard");
CHECK_EQ(1, old_pointer_space->CountTotalPages());
}
+
+
+TEST(Regress2237) {
+ InitializeVM();
+ v8::HandleScope scope;
+ Handle<String> slice(HEAP->empty_string());
+
+ {
+ // Generate a parent that lives in new-space.
+ v8::HandleScope inner_scope;
+ const char* c = "This text is long enough to trigger sliced strings.";
+ Handle<String> s = FACTORY->NewStringFromAscii(CStrVector(c));
+ CHECK(s->IsSeqAsciiString());
+ CHECK(HEAP->InNewSpace(*s));
+
+ // Generate a sliced string that is based on the above parent and
+ // lives in old-space.
+ FillUpNewSpace(HEAP->new_space());
+ AlwaysAllocateScope always_allocate;
+ Handle<String> t;
+ // TODO(mstarzinger): Unfortunately FillUpNewSpace() still leaves
+ // some slack, so we need to allocate a few sliced strings.
+ for (int i = 0; i < 16; i++) {
+ t = FACTORY->NewProperSubString(s, 5, 35);
+ }
+ CHECK(t->IsSlicedString());
+ CHECK(!HEAP->InNewSpace(*t));
+ *slice.location() = *t.location();
+ }
+
+ CHECK(SlicedString::cast(*slice)->parent()->IsSeqAsciiString());
+ HEAP->CollectAllGarbage(Heap::kNoGCFlags);
+ CHECK(SlicedString::cast(*slice)->parent()->IsSeqAsciiString());
+}
diff --git a/test/cctest/test-mark-compact.cc b/test/cctest/test-mark-compact.cc
index 2712370..f09a3ce 100644
--- a/test/cctest/test-mark-compact.cc
+++ b/test/cctest/test-mark-compact.cc
@@ -526,7 +526,10 @@
TEST(BootUpMemoryUse) {
intptr_t initial_memory = MemoryInUse();
- FLAG_crankshaft = false; // Avoid flakiness.
+ // Avoid flakiness.
+ FLAG_crankshaft = false;
+ FLAG_parallel_recompilation = false;
+
// Only Linux has the proc filesystem and only if it is mapped. If it's not
// there we just skip the test.
if (initial_memory >= 0) {
diff --git a/test/message/testcfg.py b/test/message/testcfg.py
index af467e6..de46cd6 100644
--- a/test/message/testcfg.py
+++ b/test/message/testcfg.py
@@ -41,9 +41,10 @@
self.config = config
def IgnoreLine(self, str):
- """Ignore empty lines and valgrind output."""
+ """Ignore empty lines, valgrind output and Android output."""
if not str: return True
- else: return str.startswith('==') or str.startswith('**')
+ return (str.startswith('==') or str.startswith('**') or
+ str.startswith('ANDROID'))
def IsFailureOutput(self, output):
f = file(self.expected)
@@ -62,7 +63,7 @@
pattern = '^%s$' % pattern
patterns.append(pattern)
# Compare actual output with the expected
- raw_lines = output.stdout.split('\n')
+ raw_lines = output.stdout.splitlines()
outlines = [ s for s in raw_lines if not self.IgnoreLine(s) ]
if len(outlines) != len(patterns):
return True
diff --git a/test/mjsunit/array-literal-transitions.js b/test/mjsunit/array-literal-transitions.js
index a96719d..e9062ac 100644
--- a/test/mjsunit/array-literal-transitions.js
+++ b/test/mjsunit/array-literal-transitions.js
@@ -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: --allow-natives-syntax --smi-only-arrays --expose-gc
+// Flags: --allow-natives-syntax --smi-only-arrays --expose-gc --noparallel-recompilation
// 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
diff --git a/test/mjsunit/assert-opt-and-deopt.js b/test/mjsunit/assert-opt-and-deopt.js
index 51cb99a..c79d923 100644
--- a/test/mjsunit/assert-opt-and-deopt.js
+++ b/test/mjsunit/assert-opt-and-deopt.js
@@ -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: --allow-natives-syntax
+// Flags: --allow-natives-syntax --noparallel-recompilation
/**
* This class shows how to use %GetOptimizationCount() and
diff --git a/test/mjsunit/count-based-osr.js b/test/mjsunit/count-based-osr.js
index 125c4e2..59ce9ac 100644
--- a/test/mjsunit/count-based-osr.js
+++ b/test/mjsunit/count-based-osr.js
@@ -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: --count-based-interrupts --interrupt-budget=10 --weighted-back-edges --allow-natives-syntax
+// Flags: --count-based-interrupts --interrupt-budget=10 --weighted-back-edges --allow-natives-syntax --noparallel-recompilation
// Test that OSR works properly when using count-based interrupting/profiling.
diff --git a/test/mjsunit/debug-break-inline.js b/test/mjsunit/debug-break-inline.js
index 4418fa8..0229358 100644
--- a/test/mjsunit/debug-break-inline.js
+++ b/test/mjsunit/debug-break-inline.js
@@ -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 --allow-natives-syntax
+// Flags: --expose-debug-as debug --allow-natives-syntax --noparallel-recompilation
// This test tests that deoptimization due to debug breaks works for
// inlined functions where the full-code is generated before the
diff --git a/test/mjsunit/debug-script.js b/test/mjsunit/debug-script.js
index 9767888..d7ffb56 100644
--- a/test/mjsunit/debug-script.js
+++ b/test/mjsunit/debug-script.js
@@ -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 --expose-gc
+// Flags: --expose-debug-as debug --expose-gc --noparallel-recompilation
// Get the Debug object exposed from the debug context global object.
Debug = debug.Debug
diff --git a/test/mjsunit/elements-transition-hoisting.js b/test/mjsunit/elements-transition-hoisting.js
index 9ffb67e..2d86151 100644
--- a/test/mjsunit/elements-transition-hoisting.js
+++ b/test/mjsunit/elements-transition-hoisting.js
@@ -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: --allow-natives-syntax --smi-only-arrays --expose-gc
+// Flags: --allow-natives-syntax --smi-only-arrays --expose-gc --noparallel-recompilation
// Ensure that ElementsKind transitions in various situations are hoisted (or
// not hoisted) correctly, don't change the semantics programs and don't trigger
diff --git a/test/mjsunit/external-array.js b/test/mjsunit/external-array.js
index 09d36df..85a8cc5 100644
--- a/test/mjsunit/external-array.js
+++ b/test/mjsunit/external-array.js
@@ -663,3 +663,54 @@
var b3 = b0.slice(2, 4)
assertEquals(2, b3.byteLength)
assertArrayPrefix([3, 4], Int8Array(b3))
+
+function goo(a, i) {
+ return a[i];
+}
+
+function boo(a, i, v) {
+ return a[i] = v;
+}
+
+function do_tagged_index_external_array_test(constructor) {
+ var t_array = new constructor([1, 2, 3, 4, 5, 6]);
+ assertEquals(1, goo(t_array, 0));
+ assertEquals(1, goo(t_array, 0));
+ boo(t_array, 0, 13);
+ assertEquals(13, goo(t_array, 0));
+ %OptimizeFunctionOnNextCall(goo);
+ %OptimizeFunctionOnNextCall(boo);
+ boo(t_array, 0, 15);
+ assertEquals(15, goo(t_array, 0));
+ %ClearFunctionTypeFeedback(goo);
+ %ClearFunctionTypeFeedback(boo);
+}
+
+do_tagged_index_external_array_test(Int8Array);
+do_tagged_index_external_array_test(Uint8Array);
+do_tagged_index_external_array_test(Int16Array);
+do_tagged_index_external_array_test(Uint16Array);
+do_tagged_index_external_array_test(Int32Array);
+do_tagged_index_external_array_test(Uint32Array);
+do_tagged_index_external_array_test(Float32Array);
+do_tagged_index_external_array_test(Float64Array);
+
+var built_in_array = new Array(1, 2, 3, 4, 5, 6);
+assertEquals(1, goo(built_in_array, 0));
+assertEquals(1, goo(built_in_array, 0));
+%OptimizeFunctionOnNextCall(goo);
+%OptimizeFunctionOnNextCall(boo);
+boo(built_in_array, 0, 11);
+assertEquals(11, goo(built_in_array, 0));
+%ClearFunctionTypeFeedback(goo);
+%ClearFunctionTypeFeedback(boo);
+
+built_in_array = new Array(1.5, 2, 3, 4, 5, 6);
+assertEquals(1.5, goo(built_in_array, 0));
+assertEquals(1.5, goo(built_in_array, 0));
+%OptimizeFunctionOnNextCall(goo);
+%OptimizeFunctionOnNextCall(boo);
+boo(built_in_array, 0, 2.5);
+assertEquals(2.5, goo(built_in_array, 0));
+%ClearFunctionTypeFeedback(goo);
+%ClearFunctionTypeFeedback(boo);
diff --git a/test/mjsunit/fuzz-natives.js b/test/mjsunit/fuzz-natives.js
index 2965e74..225a44d 100644
--- a/test/mjsunit/fuzz-natives.js
+++ b/test/mjsunit/fuzz-natives.js
@@ -149,6 +149,7 @@
"PushBlockContext": true,
"LazyCompile": true,
"LazyRecompile": true,
+ "ParallelRecompile": true,
"NotifyDeoptimized": true,
"NotifyOSR": true,
"CreateObjectLiteralBoilerplate": true,
diff --git a/test/mjsunit/harmony/block-let-crankshaft.js b/test/mjsunit/harmony/block-let-crankshaft.js
index 1db1792..d01e5c0 100644
--- a/test/mjsunit/harmony/block-let-crankshaft.js
+++ b/test/mjsunit/harmony/block-let-crankshaft.js
@@ -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: --harmony-scoping --allow-natives-syntax
+// Flags: --harmony-scoping --allow-natives-syntax --noparallel-recompilation
// TODO(ES6): properly activate extended mode
"use strict";
diff --git a/test/mjsunit/math-floor-of-div-minus-zero.js b/test/mjsunit/math-floor-of-div-minus-zero.js
index 9fbe9a9..2743490 100644
--- a/test/mjsunit/math-floor-of-div-minus-zero.js
+++ b/test/mjsunit/math-floor-of-div-minus-zero.js
@@ -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: --allow-natives-syntax --nouse_inlining
+// Flags: --allow-natives-syntax --nouse_inlining --noparallel-recompilation
// Test for negative zero that doesn't need bail out
diff --git a/test/mjsunit/mjsunit.status b/test/mjsunit/mjsunit.status
index 1e11a96..dda2db5 100644
--- a/test/mjsunit/mjsunit.status
+++ b/test/mjsunit/mjsunit.status
@@ -49,15 +49,15 @@
##############################################################################
# This one uses a built-in that's only present in debug mode. It takes
# too long to run in debug mode on ARM and MIPS.
-fuzz-natives: PASS, SKIP if ($mode == release || $arch == arm || $arch == android || $arch == mipsel)
+fuzz-natives: PASS, SKIP if ($mode == release || $arch == arm || $arch == android_arm || $arch == mipsel)
-big-object-literal: PASS, SKIP if ($arch == arm || $arch == android)
+big-object-literal: PASS, SKIP if ($arch == arm || $arch == android_arm)
# Issue 488: this test sometimes times out.
array-constructor: PASS || TIMEOUT
# Very slow on ARM and MIPS, contains no architecture dependent code.
-unicode-case-overoptimization: PASS, TIMEOUT if ($arch == arm || $arch == android || $arch == mipsel)
+unicode-case-overoptimization: PASS, TIMEOUT if ($arch == arm || $arch == android_arm || $arch == mipsel)
# Test Crankshaft compilation time. Expected to take too long in debug mode.
regress/regress-1969: PASS, SKIP if $mode == debug
@@ -66,10 +66,11 @@
# This test sets the umask on a per-process basis and hence cannot be
# used in multi-threaded runs.
# On android there is no /tmp directory.
-d8-os: PASS, SKIP if ($isolates || $arch == android)
+d8-os: PASS, SKIP if ($isolates || $arch == android_arm || $arch == android_ia32)
+tools/tickprocessor: PASS, SKIP if ($arch == android_arm || $arch == android_ia32)
##############################################################################
-[ $arch == arm || $arch == android ]
+[ $arch == arm || $arch == android_arm ]
# Slow tests which times out in debug mode.
try: PASS, SKIP if $mode == debug
diff --git a/test/mjsunit/regress/regress-1118.js b/test/mjsunit/regress/regress-1118.js
index 7e0461d..3e3920f 100644
--- a/test/mjsunit/regress/regress-1118.js
+++ b/test/mjsunit/regress/regress-1118.js
@@ -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: --allow-natives-syntax
+// Flags: --allow-natives-syntax --noparallel-recompilation
// An exception thrown in a function optimized by on-stack replacement (OSR)
// should be able to construct a receiver from all optimized stack frames.
diff --git a/test/mjsunit/regress/regress-137768.js b/test/mjsunit/regress/regress-137768.js
new file mode 100644
index 0000000..9fbd7f3
--- /dev/null
+++ b/test/mjsunit/regress/regress-137768.js
@@ -0,0 +1,73 @@
+// Copyright 2012 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
+
+// Create elements in a constructor function to ensure map sharing.
+function TestConstructor() {
+ this[0] = 1;
+ this[1] = 2;
+ this[2] = 3;
+}
+
+function bad_func(o,a) {
+ var s = 0;
+ for (var i = 0; i < 1; ++i) {
+ o.newFileToChangeMap = undefined;
+ var x = a[0];
+ s += x;
+ }
+ return s;
+}
+
+o = new Object();
+a = new TestConstructor();
+bad_func(o, a);
+
+// Make sure that we're out of pre-monomorphic state for the member add of
+// 'newFileToChangeMap' which causes a map transition.
+o = new Object();
+a = new TestConstructor();
+bad_func(o, a);
+
+// Optimize, before the fix, the element load and subsequent tagged-to-i were
+// hoisted above the map check, which can't be hoisted due to the map-changing
+// store.
+o = new Object();
+a = new TestConstructor();
+%OptimizeFunctionOnNextCall(bad_func);
+bad_func(o, a);
+
+// Pass in a array of doubles. Before the fix, the optimized load and
+// tagged-to-i will treat part of a double value as a pointer and de-ref it
+// before the map check was executed that should have deopt.
+o = new Object();
+// Pass in an elements buffer where the bit representation of the double numbers
+// are two adjacent small 32-bit values with the lowest bit set to one, causing
+// tagged-to-i to SIGSEGV.
+a = [2.122e-314, 2.122e-314, 2.122e-314];
+bad_func(o, a);
diff --git a/test/mjsunit/regress/regress-2249.js b/test/mjsunit/regress/regress-2249.js
new file mode 100644
index 0000000..07d687d
--- /dev/null
+++ b/test/mjsunit/regress/regress-2249.js
@@ -0,0 +1,33 @@
+// Copyright 2012 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: --gc-interval=10 --stress-compaction
+
+var o = {};
+o[Math.pow(2,30)-1] = 0;
+o[Math.pow(2,31)-1] = 0;
+o[1] = 0;
diff --git a/test/mjsunit/str-to-num.js b/test/mjsunit/str-to-num.js
index bbfa7d3..cbec87f 100644
--- a/test/mjsunit/str-to-num.js
+++ b/test/mjsunit/str-to-num.js
@@ -147,7 +147,6 @@
assertEquals(15, toNumber("0XF"));
assertEquals(0, toNumber("0x000"));
-assertEquals(-Infinity, 1 / toNumber("-0x000"));
assertEquals(0, toNumber("0x000" + repeat('0', 1000)));
assertEquals(9, toNumber("0x009"));
assertEquals(10, toNumber("0x00a"));
@@ -157,7 +156,6 @@
assertEquals(15, toNumber("0x00F "));
assertEquals(Infinity, toNumber("0x" + repeat('0', 1000) + '1'
+ repeat('0', 1000)));
-assertEquals(-Infinity, toNumber("-0x1" + repeat('0', 1000)));
assertEquals(0x1000000 * 0x10000000, toNumber("0x10000000000000"));
assertEquals(0x1000000 * 0x10000000 + 1, toNumber("0x10000000000001"));
@@ -207,3 +205,10 @@
for (var i = 1; i < 12; i++) {
assertEquals(toNumber('1' + repeat('0', i)), Math.pow(10.0, i));
}
+
+assertTrue(isNaN(toNumber("+0x0")));
+assertTrue(isNaN(toNumber("+0xFF")));
+assertTrue(isNaN(toNumber("+0x012")));
+assertTrue(isNaN(toNumber("-0x0")));
+assertTrue(isNaN(toNumber("-0xFF")));
+assertTrue(isNaN(toNumber("-0x012")));
\ No newline at end of file
diff --git a/test/mjsunit/unbox-double-arrays.js b/test/mjsunit/unbox-double-arrays.js
index ac03993..0c7730f 100644
--- a/test/mjsunit/unbox-double-arrays.js
+++ b/test/mjsunit/unbox-double-arrays.js
@@ -27,7 +27,7 @@
// Test dictionary -> double elements -> dictionary elements round trip
-// Flags: --allow-natives-syntax --unbox-double-arrays --expose-gc
+// Flags: --allow-natives-syntax --unbox-double-arrays --expose-gc --noparallel-recompilation
var large_array_size = 100000;
var approx_dict_to_elements_threshold = 70000;
diff --git a/test/mozilla/mozilla.status b/test/mozilla/mozilla.status
index fb5c441..32065c5 100644
--- a/test/mozilla/mozilla.status
+++ b/test/mozilla/mozilla.status
@@ -603,6 +603,10 @@
ecma_2/RegExp/properties-001: FAIL_OK
+# Negative hexadecimal literals are parsed as NaN. This test is outdated.
+ecma/TypeConversion/9.3.1-3: FAIL_OK
+
+
##################### FAILING TESTS #####################
# This section is for tests that fail in V8 and pass in JSC.
diff --git a/tools/android-build.sh b/tools/android-build.sh
new file mode 100644
index 0000000..e5af590
--- /dev/null
+++ b/tools/android-build.sh
@@ -0,0 +1,97 @@
+#!/bin/bash
+# Copyright 2012 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.
+
+if [ ${#@} -lt 4 ] ; then
+ echo "$0: Error: needs 4 arguments."
+ exit 1
+fi
+
+ARCH=$1
+MODE=$2
+OUTDIR=$3
+GYPFLAGS=$4
+
+host_os=$(uname -s | sed -e 's/Linux/linux/;s/Darwin/mac/')
+
+case "${host_os}" in
+ "linux")
+ toolchain_dir="linux-x86"
+ ;;
+ "mac")
+ toolchain_dir="darwin-x86"
+ ;;
+ *)
+ echo "$0: Host platform ${host_os} is not supported" >& 2
+ exit 1
+esac
+
+case "${ARCH}" in
+ "android_arm")
+ DEFINES=" target_arch=arm v8_target_arch=arm android_target_arch=arm"
+ DEFINES+=" arm_neon=0 armv7=1"
+ toolchain_arch="arm-linux-androideabi-4.4.3"
+ ;;
+ "android_ia32")
+ DEFINES=" target_arch=ia32 v8_target_arch=ia32 android_target_arch=x86"
+ toolchain_arch="x86-4.4.3"
+ ;;
+ *)
+ echo "$0: Target architecture ${ARCH} is not supported." >& 2
+ echo "$0: Current supported architectures: android_arm|android_ia32." >& 2
+ exit 1
+esac
+
+toolchain_path="${ANDROID_NDK_ROOT}/toolchains/${toolchain_arch}/prebuilt/"
+ANDROID_TOOLCHAIN="${toolchain_path}/${toolchain_dir}/bin"
+if [ ! -d "${ANDROID_TOOLCHAIN}" ]; then
+ echo "$0: Cannot find Android toolchain in ${ANDROID_TOOLCHAIN}." >& 2
+ echo "$0: The NDK version might be wrong." >& 2
+ exit 1
+fi
+
+# For mksnapshot host generation.
+DEFINES+=" host_os=${host_os}"
+
+# The set of GYP_DEFINES to pass to gyp.
+export GYP_DEFINES="${DEFINES}"
+
+# Use the "android" flavor of the Makefile generator for both Linux and OS X.
+export GYP_GENERATORS=make-android
+export CC=${ANDROID_TOOLCHAIN}/*-gcc
+export CXX=${ANDROID_TOOLCHAIN}/*-g++
+build/gyp/gyp --generator-output="${OUTDIR}" build/all.gyp \
+ -Ibuild/standalone.gypi --depth=. -Ibuild/android.gypi \
+ -S.${ARCH} ${GYPFLAGS}
+
+export AR=${ANDROID_TOOLCHAIN}/*-ar
+export RANLIB=${ANDROID_TOOLCHAIN}/*-ranlib
+export LD=${ANDROID_TOOLCHAIN}/*-ld
+export LINK=${ANDROID_TOOLCHAIN}/*-g++
+export BUILDTYPE=$(echo ${MODE} | python -c "print raw_input().capitalize()")
+export builddir=${PWD}/${OUTDIR}/${ARCH}.${MODE}
+make -C "${OUTDIR}" -f Makefile.${ARCH}
diff --git a/tools/android-run.py b/tools/android-run.py
index d3969a2..1693c5b 100644
--- a/tools/android-run.py
+++ b/tools/android-run.py
@@ -42,7 +42,7 @@
import tempfile
def Check(output, errors):
- failed = any([s.startswith('/system/bin/sh:') or s.startswith('Error')
+ failed = any([s.startswith('/system/bin/sh:') or s.startswith('ANDROID')
for s in output.split('\n')])
return 1 if failed else 0
@@ -92,8 +92,8 @@
args = [Escape(arg) for arg in sys.argv[1:]]
script = (" ".join(args) + "\n"
"case $? in\n"
- " 0) break;;\n"
- " *) echo \"Error returned by test\";;\n"
+ " 0) ;;\n"
+ " *) echo \"ANDROID: Error returned by test\";;\n"
"esac\n")
script = script.replace(workspace, android_workspace)
script_file = WriteToTemporaryFile(script)
diff --git a/tools/android-sync.sh b/tools/android-sync.sh
index 90fa318..5d4ef2e 100644
--- a/tools/android-sync.sh
+++ b/tools/android-sync.sh
@@ -33,7 +33,7 @@
# The fourth argument is the absolute path to the V8 directory on the device.
if [ ${#@} -lt 4 ] ; then
- echo "Error: need 4 arguments"
+ echo "$0: Error: need 4 arguments"
exit 1
fi
@@ -42,11 +42,34 @@
HOST_V8=$3
ANDROID_V8=$4
+function LINUX_MD5 {
+ local HASH=$(md5sum $1)
+ echo ${HASH%% *}
+}
+
+function DARWIN_MD5 {
+ local HASH=$(md5 $1)
+ echo ${HASH} | cut -f2 -d "=" | cut -f2 -d " "
+}
+
+host_os=$(uname -s)
+case "${host_os}" in
+ "Linux")
+ MD5=LINUX_MD5
+ ;;
+ "Darwin")
+ MD5=DARWIN_MD5
+ ;;
+ *)
+ echo "$0: Host platform ${host_os} is not supported" >& 2
+ exit 1
+esac
+
function sync_file {
local FILE=$1
local ANDROID_HASH=$(adb shell "md5 \"$ANDROID_V8/$FILE\"")
- local HOST_HASH=$(md5sum "$HOST_V8/$FILE")
- if [ "${ANDROID_HASH%% *}" != "${HOST_HASH%% *}" ]; then
+ local HOST_HASH=$($MD5 "$HOST_V8/$FILE")
+ if [ "${ANDROID_HASH%% *}" != "${HOST_HASH}" ]; then
adb push "$HOST_V8/$FILE" "$ANDROID_V8/$FILE" &> /dev/null
fi
echo -n "."
@@ -55,7 +78,7 @@
function sync_dir {
local DIR=$1
echo -n "sync to $ANDROID_V8/$DIR"
- for FILE in $(find "$HOST_V8/$DIR" -type f); do
+ for FILE in $(find "$HOST_V8/$DIR" -not -path "*.svn*" -type f); do
local RELATIVE_FILE=${FILE:${#HOST_V8}}
sync_file "$RELATIVE_FILE"
done
@@ -73,6 +96,9 @@
sync_file tools/csvparser.js
sync_file tools/profile.js
sync_file tools/splaytree.js
+sync_file tools/profile_view.js
+sync_file tools/logreader.js
+sync_file tools/tickprocessor.js
echo ""
sync_dir test/message
sync_dir test/mjsunit
diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp
index 8b5d115..b646567 100644
--- a/tools/gyp/v8.gyp
+++ b/tools/gyp/v8.gyp
@@ -303,6 +303,8 @@
'../../src/extensions/externalize-string-extension.h',
'../../src/extensions/gc-extension.cc',
'../../src/extensions/gc-extension.h',
+ '../../src/extensions/statistics-extension.cc',
+ '../../src/extensions/statistics-extension.h',
'../../src/factory.cc',
'../../src/factory.h',
'../../src/fast-dtoa.cc',
@@ -384,6 +386,8 @@
'../../src/objects.h',
'../../src/once.cc',
'../../src/once.h',
+ '../../src/optimizing-compiler-thread.h',
+ '../../src/optimizing-compiler-thread.cc',
'../../src/parser.cc',
'../../src/parser.h',
'../../src/platform-posix.h',
@@ -432,7 +436,7 @@
'../../src/serialize.cc',
'../../src/serialize.h',
'../../src/small-pointer-list.h',
- '../../src/smart-array-pointer.h',
+ '../../src/smart-pointers.h',
'../../src/snapshot-common.cc',
'../../src/snapshot.h',
'../../src/spaces-inl.h',
diff --git a/tools/test-wrapper-gypbuild.py b/tools/test-wrapper-gypbuild.py
index 8429a03..4dd6338 100755
--- a/tools/test-wrapper-gypbuild.py
+++ b/tools/test-wrapper-gypbuild.py
@@ -95,11 +95,14 @@
default=1, type="int")
result.add_option("--time", help="Print timing information after running",
default=False, action="store_true")
- result.add_option("--suppress-dialogs", help="Suppress Windows dialogs for crashing tests",
- dest="suppress_dialogs", default=True, action="store_true")
- result.add_option("--no-suppress-dialogs", help="Display Windows dialogs for crashing tests",
- dest="suppress_dialogs", action="store_false")
- result.add_option("--isolates", help="Whether to test isolates", default=False, action="store_true")
+ result.add_option("--suppress-dialogs",
+ help="Suppress Windows dialogs for crashing tests",
+ dest="suppress_dialogs", default=True, action="store_true")
+ result.add_option("--no-suppress-dialogs",
+ help="Display Windows dialogs for crashing tests",
+ dest="suppress_dialogs", action="store_false")
+ result.add_option("--isolates", help="Whether to test isolates",
+ default=False, action="store_true")
result.add_option("--store-unexpected-output",
help="Store the temporary JS files from tests that fails",
dest="store_unexpected_output", default=True, action="store_true")
@@ -148,7 +151,8 @@
print "Unknown mode %s" % mode
return False
for arch in options.arch:
- if not arch in ['ia32', 'x64', 'arm', 'mipsel', 'android']:
+ if not arch in ['ia32', 'x64', 'arm', 'mipsel', 'android_arm',
+ 'android_ia32']:
print "Unknown architecture %s" % arch
return False
if options.buildbot: