Version 3.17.16
Stack trace API: poison stack frames below the first strict mode frame. (issue 2564)
Made Isolate::GetHeapStatistics robust against half-initialized isolates (Chromium issue 2591).
Finished implementation of ES6 symbols aka. private names (issue 2158).
Performance and stability improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@14137 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/api.cc b/src/api.cc
index 64c0022..65663ba 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -477,14 +477,6 @@
}
-#ifdef DEBUG
-void ImplementationUtilities::ZapHandleRange(i::Object** begin,
- i::Object** end) {
- i::HandleScope::ZapRange(begin, end);
-}
-#endif
-
-
void V8::SetFlagsFromString(const char* str, int length) {
i::FlagList::SetFlagsFromString(str, length);
}
@@ -706,7 +698,7 @@
i::HandleScope::DeleteExtensions(isolate_);
}
-#ifdef DEBUG
+#ifdef ENABLE_EXTRA_CHECKS
i::HandleScope::ZapRange(prev_next_, prev_limit_);
#endif
}
@@ -3197,7 +3189,7 @@
i::Handle<i::Object> name(self->class_name(), isolate);
// Native implementation of Object.prototype.toString (v8natives.js):
- // var c = %ClassOf(this);
+ // var c = %_ClassOf(this);
// if (c === 'Arguments') c = 'Object';
// return "[object " + c + "]";
@@ -5807,6 +5799,20 @@
}
+HeapProfiler* Isolate::GetHeapProfiler() {
+ i::HeapProfiler* heap_profiler =
+ reinterpret_cast<i::Isolate*>(this)->heap_profiler();
+ return reinterpret_cast<HeapProfiler*>(heap_profiler);
+}
+
+
+CpuProfiler* Isolate::GetCpuProfiler() {
+ i::CpuProfiler* cpu_profiler =
+ reinterpret_cast<i::Isolate*>(this)->cpu_profiler();
+ return reinterpret_cast<CpuProfiler*>(cpu_profiler);
+}
+
+
void V8::SetGlobalGCPrologueCallback(GCCallback callback) {
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::V8::SetGlobalGCPrologueCallback()")) return;
@@ -5979,6 +5985,14 @@
void Isolate::GetHeapStatistics(HeapStatistics* heap_statistics) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+ if (!isolate->IsInitialized()) {
+ heap_statistics->total_heap_size_ = 0;
+ heap_statistics->total_heap_size_executable_ = 0;
+ heap_statistics->total_physical_size_ = 0;
+ heap_statistics->used_heap_size_ = 0;
+ heap_statistics->heap_size_limit_ = 0;
+ return;
+ }
i::Heap* heap = isolate->heap();
heap_statistics->total_heap_size_ = heap->CommittedMemory();
heap_statistics->total_heap_size_executable_ =
@@ -6454,6 +6468,11 @@
}
+unsigned CpuProfileNode::GetNodeId() const {
+ return reinterpret_cast<const i::ProfileNode*>(this)->id();
+}
+
+
int CpuProfileNode::GetChildrenCount() const {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::CpuProfileNode::GetChildrenCount");
@@ -6473,11 +6492,12 @@
void CpuProfile::Delete() {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::CpuProfile::Delete");
- i::CpuProfiler::DeleteProfile(reinterpret_cast<i::CpuProfile*>(this));
- if (i::CpuProfiler::GetProfilesCount() == 0 &&
- !i::CpuProfiler::HasDetachedProfiles()) {
+ i::CpuProfiler* profiler = isolate->cpu_profiler();
+ ASSERT(profiler != NULL);
+ profiler->DeleteProfile(reinterpret_cast<i::CpuProfile*>(this));
+ if (profiler->GetProfilesCount() == 0 && !profiler->HasDetachedProfiles()) {
// If this was the last profile, clean up all accessory data as well.
- i::CpuProfiler::DeleteAllProfiles();
+ profiler->DeleteAllProfiles();
}
}
@@ -6506,10 +6526,28 @@
}
+const CpuProfileNode* CpuProfile::GetSample(int index) const {
+ const i::CpuProfile* profile = reinterpret_cast<const i::CpuProfile*>(this);
+ return reinterpret_cast<const CpuProfileNode*>(profile->sample(index));
+}
+
+
+int CpuProfile::GetSamplesCount() const {
+ return reinterpret_cast<const i::CpuProfile*>(this)->samples_count();
+}
+
+
int CpuProfiler::GetProfilesCount() {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::CpuProfiler::GetProfilesCount");
- return i::CpuProfiler::GetProfilesCount();
+ i::CpuProfiler* profiler = isolate->cpu_profiler();
+ ASSERT(profiler != NULL);
+ return profiler->GetProfilesCount();
+}
+
+
+int CpuProfiler::GetProfileCount() {
+ return reinterpret_cast<i::CpuProfiler*>(this)->GetProfilesCount();
}
@@ -6517,8 +6555,19 @@
Handle<Value> security_token) {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::CpuProfiler::GetProfile");
+ i::CpuProfiler* profiler = isolate->cpu_profiler();
+ ASSERT(profiler != NULL);
return reinterpret_cast<const CpuProfile*>(
- i::CpuProfiler::GetProfile(
+ profiler->GetProfile(
+ security_token.IsEmpty() ? NULL : *Utils::OpenHandle(*security_token),
+ index));
+}
+
+
+const CpuProfile* CpuProfiler::GetCpuProfile(int index,
+ Handle<Value> security_token) {
+ return reinterpret_cast<const CpuProfile*>(
+ reinterpret_cast<i::CpuProfiler*>(this)->GetProfile(
security_token.IsEmpty() ? NULL : *Utils::OpenHandle(*security_token),
index));
}
@@ -6528,17 +6577,36 @@
Handle<Value> security_token) {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::CpuProfiler::FindProfile");
+ i::CpuProfiler* profiler = isolate->cpu_profiler();
+ ASSERT(profiler != NULL);
return reinterpret_cast<const CpuProfile*>(
- i::CpuProfiler::FindProfile(
+ profiler->FindProfile(
security_token.IsEmpty() ? NULL : *Utils::OpenHandle(*security_token),
uid));
}
-void CpuProfiler::StartProfiling(Handle<String> title) {
+const CpuProfile* CpuProfiler::FindCpuProfile(unsigned uid,
+ Handle<Value> security_token) {
+ return reinterpret_cast<const CpuProfile*>(
+ reinterpret_cast<i::CpuProfiler*>(this)->FindProfile(
+ security_token.IsEmpty() ? NULL : *Utils::OpenHandle(*security_token),
+ uid));
+}
+
+
+void CpuProfiler::StartProfiling(Handle<String> title, bool record_samples) {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::CpuProfiler::StartProfiling");
- i::CpuProfiler::StartProfiling(*Utils::OpenHandle(*title));
+ i::CpuProfiler* profiler = isolate->cpu_profiler();
+ ASSERT(profiler != NULL);
+ profiler->StartProfiling(*Utils::OpenHandle(*title), record_samples);
+}
+
+
+void CpuProfiler::StartCpuProfiling(Handle<String> title, bool record_samples) {
+ reinterpret_cast<i::CpuProfiler*>(this)->StartProfiling(
+ *Utils::OpenHandle(*title), record_samples);
}
@@ -6546,8 +6614,19 @@
Handle<Value> security_token) {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::CpuProfiler::StopProfiling");
+ i::CpuProfiler* profiler = isolate->cpu_profiler();
+ ASSERT(profiler != NULL);
return reinterpret_cast<const CpuProfile*>(
- i::CpuProfiler::StopProfiling(
+ profiler->StopProfiling(
+ security_token.IsEmpty() ? NULL : *Utils::OpenHandle(*security_token),
+ *Utils::OpenHandle(*title)));
+}
+
+
+const CpuProfile* CpuProfiler::StopCpuProfiling(Handle<String> title,
+ Handle<Value> security_token) {
+ return reinterpret_cast<const CpuProfile*>(
+ reinterpret_cast<i::CpuProfiler*>(this)->StopProfiling(
security_token.IsEmpty() ? NULL : *Utils::OpenHandle(*security_token),
*Utils::OpenHandle(*title)));
}
@@ -6556,7 +6635,14 @@
void CpuProfiler::DeleteAllProfiles() {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::CpuProfiler::DeleteAllProfiles");
- i::CpuProfiler::DeleteAllProfiles();
+ i::CpuProfiler* profiler = isolate->cpu_profiler();
+ ASSERT(profiler != NULL);
+ profiler->DeleteAllProfiles();
+}
+
+
+void CpuProfiler::DeleteAllCpuProfiles() {
+ reinterpret_cast<i::CpuProfiler*>(this)->DeleteAllProfiles();
}
@@ -6679,11 +6765,11 @@
void HeapSnapshot::Delete() {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::HeapSnapshot::Delete");
- if (i::HeapProfiler::GetSnapshotsCount() > 1) {
+ if (isolate->heap_profiler()->GetSnapshotsCount() > 1) {
ToInternal(this)->Delete();
} else {
// If this is the last snapshot, clean up all accessory data as well.
- i::HeapProfiler::DeleteAllSnapshots();
+ isolate->heap_profiler()->DeleteAllSnapshots();
}
}
@@ -6691,7 +6777,7 @@
HeapSnapshot::Type HeapSnapshot::GetType() const {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::HeapSnapshot::GetType");
- return static_cast<HeapSnapshot::Type>(ToInternal(this)->type());
+ return kFull;
}
@@ -6768,7 +6854,12 @@
int HeapProfiler::GetSnapshotsCount() {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::HeapProfiler::GetSnapshotsCount");
- return i::HeapProfiler::GetSnapshotsCount();
+ return isolate->heap_profiler()->GetSnapshotsCount();
+}
+
+
+int HeapProfiler::GetSnapshotCount() {
+ return reinterpret_cast<i::HeapProfiler*>(this)->GetSnapshotsCount();
}
@@ -6776,7 +6867,13 @@
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::HeapProfiler::GetSnapshot");
return reinterpret_cast<const HeapSnapshot*>(
- i::HeapProfiler::GetSnapshot(index));
+ isolate->heap_profiler()->GetSnapshot(index));
+}
+
+
+const HeapSnapshot* HeapProfiler::GetHeapSnapshot(int index) {
+ return reinterpret_cast<const HeapSnapshot*>(
+ reinterpret_cast<i::HeapProfiler*>(this)->GetSnapshot(index));
}
@@ -6784,7 +6881,13 @@
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::HeapProfiler::FindSnapshot");
return reinterpret_cast<const HeapSnapshot*>(
- i::HeapProfiler::FindSnapshot(uid));
+ isolate->heap_profiler()->FindSnapshot(uid));
+}
+
+
+const HeapSnapshot* HeapProfiler::FindHeapSnapshot(unsigned uid) {
+ return reinterpret_cast<const HeapSnapshot*>(
+ reinterpret_cast<i::HeapProfiler*>(this)->FindSnapshot(uid));
}
@@ -6792,7 +6895,13 @@
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::HeapProfiler::GetSnapshotObjectId");
i::Handle<i::Object> obj = Utils::OpenHandle(*value);
- return i::HeapProfiler::GetSnapshotObjectId(obj);
+ return isolate->heap_profiler()->GetSnapshotObjectId(obj);
+}
+
+
+SnapshotObjectId HeapProfiler::GetObjectId(Handle<Value> value) {
+ i::Handle<i::Object> obj = Utils::OpenHandle(*value);
+ return reinterpret_cast<i::HeapProfiler*>(this)->GetSnapshotObjectId(obj);
}
@@ -6802,45 +6911,67 @@
ObjectNameResolver* resolver) {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::HeapProfiler::TakeSnapshot");
- i::HeapSnapshot::Type internal_type = i::HeapSnapshot::kFull;
- switch (type) {
- case HeapSnapshot::kFull:
- internal_type = i::HeapSnapshot::kFull;
- break;
- default:
- UNREACHABLE();
- }
return reinterpret_cast<const HeapSnapshot*>(
- i::HeapProfiler::TakeSnapshot(
- *Utils::OpenHandle(*title), internal_type, control, resolver));
+ isolate->heap_profiler()->TakeSnapshot(
+ *Utils::OpenHandle(*title), control, resolver));
+}
+
+
+const HeapSnapshot* HeapProfiler::TakeHeapSnapshot(
+ Handle<String> title,
+ ActivityControl* control,
+ ObjectNameResolver* resolver) {
+ return reinterpret_cast<const HeapSnapshot*>(
+ reinterpret_cast<i::HeapProfiler*>(this)->TakeSnapshot(
+ *Utils::OpenHandle(*title), control, resolver));
}
void HeapProfiler::StartHeapObjectsTracking() {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::HeapProfiler::StartHeapObjectsTracking");
- i::HeapProfiler::StartHeapObjectsTracking();
+ isolate->heap_profiler()->StartHeapObjectsTracking();
+}
+
+
+void HeapProfiler::StartTrackingHeapObjects() {
+ reinterpret_cast<i::HeapProfiler*>(this)->StartHeapObjectsTracking();
}
void HeapProfiler::StopHeapObjectsTracking() {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::HeapProfiler::StopHeapObjectsTracking");
- i::HeapProfiler::StopHeapObjectsTracking();
+ isolate->heap_profiler()->StopHeapObjectsTracking();
+}
+
+
+void HeapProfiler::StopTrackingHeapObjects() {
+ reinterpret_cast<i::HeapProfiler*>(this)->StopHeapObjectsTracking();
}
SnapshotObjectId HeapProfiler::PushHeapObjectsStats(OutputStream* stream) {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::HeapProfiler::PushHeapObjectsStats");
- return i::HeapProfiler::PushHeapObjectsStats(stream);
+ return isolate->heap_profiler()->PushHeapObjectsStats(stream);
+}
+
+
+SnapshotObjectId HeapProfiler::GetHeapStats(OutputStream* stream) {
+ return reinterpret_cast<i::HeapProfiler*>(this)->PushHeapObjectsStats(stream);
}
void HeapProfiler::DeleteAllSnapshots() {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::HeapProfiler::DeleteAllSnapshots");
- i::HeapProfiler::DeleteAllSnapshots();
+ isolate->heap_profiler()->DeleteAllSnapshots();
+}
+
+
+void HeapProfiler::DeleteAllHeapSnapshots() {
+ reinterpret_cast<i::HeapProfiler*>(this)->DeleteAllSnapshots();
}
@@ -6851,6 +6982,13 @@
}
+void HeapProfiler::SetWrapperClassInfoProvider(uint16_t class_id,
+ WrapperInfoCallback callback) {
+ reinterpret_cast<i::HeapProfiler*>(this)->DefineWrapperClass(class_id,
+ callback);
+}
+
+
int HeapProfiler::GetPersistentHandleCount() {
i::Isolate* isolate = i::Isolate::Current();
return isolate->global_handles()->NumberOfGlobalHandles();
@@ -6858,7 +6996,13 @@
size_t HeapProfiler::GetMemorySizeUsedByProfiler() {
- return i::HeapProfiler::GetMemorySizeUsedByProfiler();
+ return i::Isolate::Current()->heap_profiler()->GetMemorySizeUsedByProfiler();
+}
+
+
+size_t HeapProfiler::GetProfilerMemorySize() {
+ return reinterpret_cast<i::HeapProfiler*>(this)->
+ GetMemorySizeUsedByProfiler();
}
@@ -7053,7 +7197,7 @@
isolate_->UnlinkDeferredHandles(this);
for (int i = 0; i < blocks_.length(); i++) {
-#ifdef DEBUG
+#ifdef ENABLE_EXTRA_CHECKS
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 8628b2a..d73646d 100644
--- a/src/api.h
+++ b/src/api.h
@@ -572,8 +572,8 @@
#endif
blocks_.RemoveLast();
-#ifdef DEBUG
- v8::ImplementationUtilities::ZapHandleRange(block_start, block_limit);
+#ifdef ENABLE_EXTRA_CHECKS
+ internal::HandleScope::ZapRange(block_start, block_limit);
#endif
if (spare_ != NULL) {
DeleteArray(spare_);
diff --git a/src/apiutils.h b/src/apiutils.h
index 71c0e1c..9831f08 100644
--- a/src/apiutils.h
+++ b/src/apiutils.h
@@ -67,10 +67,6 @@
// Introduce an alias for the handle scope data to allow non-friends
// to access the HandleScope data.
typedef v8::HandleScope::Data HandleScopeData;
-
-#ifdef DEBUG
- static void ZapHandleRange(internal::Object** begin, internal::Object** end);
-#endif
};
} // namespace v8
diff --git a/src/arm/builtins-arm.cc b/src/arm/builtins-arm.cc
index 2946b35..ebb9e12 100644
--- a/src/arm/builtins-arm.cc
+++ b/src/arm/builtins-arm.cc
@@ -221,13 +221,12 @@
__ add(elements_array_end,
elements_array_end,
Operand(array_size, ASR, kSmiTagSize));
- __ AllocateInNewSpace(
- elements_array_end,
- result,
- scratch1,
- scratch2,
- gc_required,
- static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS));
+ __ Allocate(elements_array_end,
+ result,
+ scratch1,
+ scratch2,
+ gc_required,
+ static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS));
// Allocated the JSArray. Now initialize the fields except for the elements
// array.
@@ -874,7 +873,7 @@
// r1: constructor function
// r2: initial map
__ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset));
- __ AllocateInNewSpace(r3, r4, r5, r6, &rt_call, SIZE_IN_WORDS);
+ __ Allocate(r3, r4, r5, r6, &rt_call, SIZE_IN_WORDS);
// Allocated the JSObject, now initialize the fields. Map is set to
// initial map and properties and elements are set to empty fixed array.
@@ -949,7 +948,7 @@
// r4: JSObject
// r5: start of next object
__ add(r0, r3, Operand(FixedArray::kHeaderSize / kPointerSize));
- __ AllocateInNewSpace(
+ __ Allocate(
r0,
r5,
r6,
@@ -1105,10 +1104,6 @@
__ CompareObjectType(r0, r1, r3, FIRST_SPEC_OBJECT_TYPE);
__ b(ge, &exit);
- // Symbols are "objects".
- __ CompareInstanceType(r1, r3, SYMBOL_TYPE);
- __ b(eq, &exit);
-
// Throw away the result of the constructor invocation and use the
// on-stack receiver as the result.
__ bind(&use_receiver);
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index b2b8d4b..d982f27 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -95,7 +95,7 @@
// stack param count needs (constructor pointer, and single argument)
descriptor->stack_parameter_count_ = &r0;
descriptor->register_params_ = registers;
- descriptor->extra_expression_stack_count_ = 1;
+ descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
descriptor->deoptimization_handler_ =
FUNCTION_ADDR(ArrayConstructor_StubFailure);
}
@@ -2634,8 +2634,8 @@
OverwriteMode mode) {
Register left = r1;
Register right = r0;
- Register scratch1 = r7;
- Register scratch2 = r9;
+ Register scratch1 = r6;
+ Register scratch2 = r7;
Register scratch3 = r4;
ASSERT(smi_operands || (not_numbers != NULL));
@@ -2650,7 +2650,7 @@
__ JumpIfNotSmi(right, miss);
}
- Register heap_number_map = r6;
+ Register heap_number_map = r9;
__ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
switch (op) {
@@ -4488,35 +4488,6 @@
}
-void ArrayLengthStub::Generate(MacroAssembler* masm) {
- Label miss;
- Register receiver;
- if (kind() == Code::KEYED_LOAD_IC) {
- // ----------- S t a t e -------------
- // -- lr : return address
- // -- r0 : key
- // -- r1 : receiver
- // -----------------------------------
- __ cmp(r0, Operand(masm->isolate()->factory()->length_string()));
- __ b(ne, &miss);
- receiver = r1;
- } else {
- ASSERT(kind() == Code::LOAD_IC);
- // ----------- S t a t e -------------
- // -- r2 : name
- // -- lr : return address
- // -- r0 : receiver
- // -- sp[0] : receiver
- // -----------------------------------
- receiver = r0;
- }
-
- StubCompiler::GenerateLoadArrayLength(masm, receiver, r3, &miss);
- __ bind(&miss);
- StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind()));
-}
-
-
void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
Label miss;
Register receiver;
@@ -4791,7 +4762,7 @@
__ add(r9, r9, Operand(Heap::kArgumentsObjectSize));
// Do the allocation of all three objects in one go.
- __ AllocateInNewSpace(r9, r0, r3, r4, &runtime, TAG_OBJECT);
+ __ Allocate(r9, r0, r3, r4, &runtime, TAG_OBJECT);
// r0 = address of new object(s) (tagged)
// r2 = argument count (tagged)
@@ -4967,13 +4938,8 @@
__ add(r1, r1, Operand(Heap::kArgumentsObjectSizeStrict / kPointerSize));
// Do the allocation of both objects in one go.
- __ AllocateInNewSpace(r1,
- r0,
- r2,
- r3,
- &runtime,
- static_cast<AllocationFlags>(TAG_OBJECT |
- SIZE_IN_WORDS));
+ __ Allocate(r1, r0, r2, r3, &runtime,
+ static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS));
// Get the arguments boilerplate from the current native context.
__ ldr(r4, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
@@ -5477,7 +5443,7 @@
(JSRegExpResult::kSize + FixedArray::kHeaderSize) / kPointerSize;
__ mov(r5, Operand(r1, LSR, kSmiTagSize + kSmiShiftSize));
__ add(r2, r5, Operand(objects_size));
- __ AllocateInNewSpace(
+ __ Allocate(
r2, // In: Size, in words.
r0, // Out: Start of allocation (tagged).
r3, // Scratch register.
@@ -7996,6 +7962,9 @@
int parameter_count_offset =
StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
__ ldr(r1, MemOperand(fp, parameter_count_offset));
+ if (function_mode_ == JS_FUNCTION_STUB_MODE) {
+ __ add(r1, r1, Operand(1));
+ }
masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE);
__ mov(r1, Operand(r1, LSL, kPointerSizeLog2));
__ add(sp, sp, r1);
diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc
index b8f8f6d..1c82946 100644
--- a/src/arm/codegen-arm.cc
+++ b/src/arm/codegen-arm.cc
@@ -207,7 +207,7 @@
// Use lr as a temporary register.
__ mov(lr, Operand(r5, LSL, 2));
__ add(lr, lr, Operand(FixedDoubleArray::kHeaderSize));
- __ AllocateInNewSpace(lr, r6, r7, r9, &gc_required, DOUBLE_ALIGNMENT);
+ __ Allocate(lr, r6, r7, r9, &gc_required, DOUBLE_ALIGNMENT);
// r6: destination FixedDoubleArray, not tagged as heap object.
// Set destination FixedDoubleArray's length and map.
@@ -348,7 +348,7 @@
// Allocate new FixedArray.
__ mov(r0, Operand(FixedDoubleArray::kHeaderSize));
__ add(r0, r0, Operand(r5, LSL, 1));
- __ AllocateInNewSpace(r0, r6, r7, r9, &gc_required, NO_ALLOCATION_FLAGS);
+ __ Allocate(r0, r6, r7, r9, &gc_required, NO_ALLOCATION_FLAGS);
// r6: destination FixedArray, not tagged as heap object
// Set destination FixedDoubleArray's length and map.
__ LoadRoot(r9, Heap::kFixedArrayMapRootIndex);
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index 1df1649..6086645 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -2764,28 +2764,6 @@
}
-void FullCodeGenerator::EmitIsSymbol(CallRuntime* expr) {
- ZoneList<Expression*>* args = expr->arguments();
- ASSERT(args->length() == 1);
-
- VisitForAccumulatorValue(args->at(0));
-
- Label materialize_true, materialize_false;
- Label* if_true = NULL;
- Label* if_false = NULL;
- Label* fall_through = NULL;
- context()->PrepareTest(&materialize_true, &materialize_false,
- &if_true, &if_false, &fall_through);
-
- __ JumpIfSmi(r0, if_false);
- __ CompareObjectType(r0, r1, r2, SYMBOL_TYPE);
- PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
- Split(eq, if_true, if_false, fall_through);
-
- context()->Plug(if_true, if_false);
-}
-
-
void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
ASSERT(args->length() == 1);
@@ -4292,6 +4270,10 @@
__ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset));
__ tst(r1, Operand(1 << Map::kIsUndetectable));
Split(eq, if_true, if_false, fall_through);
+ } else if (check->Equals(isolate()->heap()->symbol_string())) {
+ __ JumpIfSmi(r0, if_false);
+ __ CompareObjectType(r0, r0, r1, SYMBOL_TYPE);
+ Split(eq, if_true, if_false, fall_through);
} else if (check->Equals(isolate()->heap()->boolean_string())) {
__ CompareRoot(r0, Heap::kTrueValueRootIndex);
__ b(eq, if_true);
@@ -4324,10 +4306,6 @@
__ CompareRoot(r0, Heap::kNullValueRootIndex);
__ b(eq, if_true);
}
- if (FLAG_harmony_symbols) {
- __ CompareObjectType(r0, r0, r1, SYMBOL_TYPE);
- __ b(eq, if_true);
- }
// Check for JS objects => true.
__ CompareObjectType(r0, r0, r1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
__ b(lt, if_false);
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index 38884ce..f2b65ef 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -871,6 +871,35 @@
LInstruction* instr = current->CompileToLithium(this);
if (instr != NULL) {
+#if DEBUG
+ // Make sure that the lithium instruction has either no fixed register
+ // constraints in temps or the result OR no uses that are only used at
+ // start. If this invariant doesn't hold, the register allocator can decide
+ // to insert a split of a range immediately before the instruction due to an
+ // already allocated register needing to be used for the instruction's fixed
+ // register constraint. In this case, The register allocator won't see an
+ // interference between the split child and the use-at-start (it would if
+ // the it was just a plain use), so it is free to move the split child into
+ // the same register that is used for the use-at-start.
+ // See https://code.google.com/p/chromium/issues/detail?id=201590
+ if (!(instr->ClobbersRegisters() && instr->ClobbersDoubleRegisters())) {
+ int fixed = 0;
+ int used_at_start = 0;
+ for (UseIterator it(instr); !it.Done(); it.Advance()) {
+ LUnallocated* operand = LUnallocated::cast(it.Current());
+ if (operand->IsUsedAtStart()) ++used_at_start;
+ }
+ if (instr->Output() != NULL) {
+ if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed;
+ }
+ for (TempIterator it(instr); !it.Done(); it.Advance()) {
+ LUnallocated* operand = LUnallocated::cast(it.Current());
+ if (operand->HasFixedPolicy()) ++fixed;
+ }
+ ASSERT(fixed == 0 || used_at_start == 0);
+ }
+#endif
+
if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
instr = AssignPointerMap(instr);
}
@@ -1115,7 +1144,7 @@
LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, temp);
return DefineFixedDouble(result, d2);
} else {
- LOperand* input = UseRegisterAtStart(instr->value());
+ LOperand* input = UseRegister(instr->value());
LOperand* temp = (op == kMathRound) ? FixedTemp(d3) : NULL;
LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, temp);
@@ -1711,12 +1740,6 @@
}
-LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
- LOperand* array = UseRegisterAtStart(instr->value());
- return DefineAsRegister(new(zone()) LJSArrayLength(array));
-}
-
-
LInstruction* LChunkBuilder::DoFixedArrayBaseLength(
HFixedArrayBaseLength* instr) {
LOperand* array = UseRegisterAtStart(instr->value());
@@ -1823,11 +1846,13 @@
return AssignEnvironment(DefineAsRegister(res));
} else {
ASSERT(to.IsInteger32());
- LOperand* value = UseRegisterAtStart(instr->value());
+ LOperand* value = NULL;
LInstruction* res = NULL;
if (instr->value()->type().IsSmi()) {
+ value = UseRegisterAtStart(instr->value());
res = DefineAsRegister(new(zone()) LSmiUntag(value, false));
} else {
+ value = UseRegister(instr->value());
LOperand* temp1 = TempRegister();
LOperand* temp2 = instr->CanTruncateToInt32() ? TempRegister()
: NULL;
@@ -2205,7 +2230,7 @@
LOperand* new_map_reg = TempRegister();
LTransitionElementsKind* result =
new(zone()) LTransitionElementsKind(object, new_map_reg, NULL);
- return DefineSameAsFirst(result);
+ return result;
} else if (FLAG_compiled_transitions) {
LTransitionElementsKind* result =
new(zone()) LTransitionElementsKind(object, NULL, NULL);
diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h
index f49e8ce..207faf4 100644
--- a/src/arm/lithium-arm.h
+++ b/src/arm/lithium-arm.h
@@ -120,7 +120,6 @@
V(IsStringAndBranch) \
V(IsSmiAndBranch) \
V(IsUndetectableAndBranch) \
- V(JSArrayLength) \
V(Label) \
V(LazyBailout) \
V(LoadContextSlot) \
@@ -1165,19 +1164,6 @@
};
-class LJSArrayLength: public LTemplateInstruction<1, 1, 0> {
- public:
- explicit LJSArrayLength(LOperand* value) {
- inputs_[0] = value;
- }
-
- LOperand* value() { return inputs_[0]; }
-
- DECLARE_CONCRETE_INSTRUCTION(JSArrayLength, "js-array-length")
- DECLARE_HYDROGEN_ACCESSOR(JSArrayLength)
-};
-
-
class LFixedArrayBaseLength: public LTemplateInstruction<1, 1, 0> {
public:
explicit LFixedArrayBaseLength(LOperand* value) {
@@ -2114,7 +2100,7 @@
};
-class LTransitionElementsKind: public LTemplateInstruction<1, 1, 2> {
+class LTransitionElementsKind: public LTemplateInstruction<0, 1, 2> {
public:
LTransitionElementsKind(LOperand* object,
LOperand* new_map_temp,
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index 8040791..7bb3535 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -1918,13 +1918,6 @@
}
-void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
- Register result = ToRegister(instr->result());
- Register array = ToRegister(instr->value());
- __ ldr(result, FieldMemOperand(array, JSArray::kLengthOffset));
-}
-
-
void LCodeGen::DoFixedArrayBaseLength(LFixedArrayBaseLength* instr) {
Register result = ToRegister(instr->result());
Register array = ToRegister(instr->value());
@@ -2301,6 +2294,12 @@
__ bind(¬_string);
}
+ if (expected.Contains(ToBooleanStub::SYMBOL)) {
+ // Symbol value -> true.
+ __ CompareInstanceType(map, ip, SYMBOL_TYPE);
+ __ b(eq, true_label);
+ }
+
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
CpuFeatureScope scope(masm(), VFP2);
// heap number -> false iff +0, -0, or NaN.
@@ -4897,10 +4896,11 @@
// Convert unsigned integer with specified number of leading zeroes in binary
// representation to IEEE 754 double.
-// Integer to convert is passed in register hiword.
+// Integer to convert is passed in register src.
// Resulting double is returned in registers hiword:loword.
// This functions does not work correctly for 0.
static void GenerateUInt2Double(MacroAssembler* masm,
+ Register src,
Register hiword,
Register loword,
Register scratch,
@@ -4914,13 +4914,13 @@
kBitsPerInt - mantissa_shift_for_hi_word;
masm->mov(scratch, Operand(biased_exponent << HeapNumber::kExponentShift));
if (mantissa_shift_for_hi_word > 0) {
- masm->mov(loword, Operand(hiword, LSL, mantissa_shift_for_lo_word));
+ masm->mov(loword, Operand(src, LSL, mantissa_shift_for_lo_word));
masm->orr(hiword, scratch,
- Operand(hiword, LSR, mantissa_shift_for_hi_word));
+ Operand(src, LSR, mantissa_shift_for_hi_word));
} else {
masm->mov(loword, Operand::Zero());
masm->orr(hiword, scratch,
- Operand(hiword, LSL, -mantissa_shift_for_hi_word));
+ Operand(src, LSL, -mantissa_shift_for_hi_word));
}
// If least significant bit of biased exponent was not 1 it was corrupted
@@ -4969,17 +4969,17 @@
__ vmov(flt_scratch, src);
__ vcvt_f64_u32(dbl_scratch, flt_scratch);
} else {
- Label no_leading_zero, done;
+ Label no_leading_zero, convert_done;
__ tst(src, Operand(0x80000000));
__ b(ne, &no_leading_zero);
// Integer has one leading zeros.
- GenerateUInt2Double(masm(), sfpd_hi, sfpd_lo, r9, 1);
- __ b(&done);
+ GenerateUInt2Double(masm(), src, sfpd_hi, sfpd_lo, r9, 1);
+ __ b(&convert_done);
__ bind(&no_leading_zero);
- GenerateUInt2Double(masm(), sfpd_hi, sfpd_lo, r9, 0);
- __ b(&done);
+ GenerateUInt2Double(masm(), src, sfpd_hi, sfpd_lo, r9, 0);
+ __ bind(&convert_done);
}
}
@@ -4996,10 +4996,18 @@
// TODO(3095996): Put a valid pointer value in the stack slot where the result
// register is stored, as this register is in the pointer map, but contains an
// integer value.
+ if (!CpuFeatures::IsSupported(VFP2)) {
+ // Preserve sfpd_lo.
+ __ mov(r9, sfpd_lo);
+ }
__ mov(ip, Operand::Zero());
__ StoreToSafepointRegisterSlot(ip, dst);
CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
__ Move(dst, r0);
+ if (!CpuFeatures::IsSupported(VFP2)) {
+ // Restore sfpd_lo.
+ __ mov(sfpd_lo, r9);
+ }
__ sub(dst, dst, Operand(kHeapObjectTag));
// Done. Put the value in dbl_scratch into the value of the allocated heap
@@ -5671,12 +5679,12 @@
__ Allocate(size, result, scratch, scratch2, deferred->entry(), flags);
} else {
Register size = ToRegister(instr->size());
- __ AllocateInNewSpace(size,
- result,
- scratch,
- scratch2,
- deferred->entry(),
- flags);
+ __ Allocate(size,
+ result,
+ scratch,
+ scratch2,
+ deferred->entry(),
+ flags);
}
__ bind(deferred->exit());
@@ -6074,6 +6082,11 @@
__ tst(ip, Operand(1 << Map::kIsUndetectable));
final_branch_condition = eq;
+ } else if (type_name->Equals(heap()->symbol_string())) {
+ __ JumpIfSmi(input, false_label);
+ __ CompareObjectType(input, input, scratch, SYMBOL_TYPE);
+ final_branch_condition = eq;
+
} else if (type_name->Equals(heap()->boolean_string())) {
__ CompareRoot(input, Heap::kTrueValueRootIndex);
__ b(eq, true_label);
@@ -6108,15 +6121,8 @@
__ CompareRoot(input, Heap::kNullValueRootIndex);
__ b(eq, true_label);
}
- if (FLAG_harmony_symbols) {
- __ CompareObjectType(input, input, scratch, SYMBOL_TYPE);
- __ b(eq, true_label);
- __ CompareInstanceType(input, scratch,
- FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
- } else {
- __ CompareObjectType(input, input, scratch,
- FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
- }
+ __ CompareObjectType(input, input, scratch,
+ FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
__ b(lt, false_label);
__ CompareInstanceType(input, scratch, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
__ b(gt, false_label);
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index e0e77cf..bacf570 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -708,15 +708,14 @@
const MemOperand& src, Condition cond) {
ASSERT(src.rm().is(no_reg));
ASSERT(!dst1.is(lr)); // r14.
- ASSERT_EQ(0, dst1.code() % 2);
- ASSERT_EQ(dst1.code() + 1, dst2.code());
// V8 does not use this addressing mode, so the fallback code
// below doesn't support it yet.
ASSERT((src.am() != PreIndex) && (src.am() != NegPreIndex));
// Generate two ldr instructions if ldrd is not available.
- if (CpuFeatures::IsSupported(ARMv7) && !predictable_code_size()) {
+ if (CpuFeatures::IsSupported(ARMv7) && !predictable_code_size() &&
+ (dst1.code() % 2 == 0) && (dst1.code() + 1 == dst2.code())) {
CpuFeatureScope scope(this, ARMv7);
ldrd(dst1, dst2, src, cond);
} else {
@@ -750,15 +749,14 @@
const MemOperand& dst, Condition cond) {
ASSERT(dst.rm().is(no_reg));
ASSERT(!src1.is(lr)); // r14.
- ASSERT_EQ(0, src1.code() % 2);
- ASSERT_EQ(src1.code() + 1, src2.code());
// V8 does not use this addressing mode, so the fallback code
// below doesn't support it yet.
ASSERT((dst.am() != PreIndex) && (dst.am() != NegPreIndex));
// Generate two str instructions if strd is not available.
- if (CpuFeatures::IsSupported(ARMv7) && !predictable_code_size()) {
+ if (CpuFeatures::IsSupported(ARMv7) && !predictable_code_size() &&
+ (src1.code() % 2 == 0) && (src1.code() + 1 == src2.code())) {
CpuFeatureScope scope(this, ARMv7);
strd(src1, src2, dst, cond);
} else {
@@ -1671,13 +1669,12 @@
}
-void MacroAssembler::AllocateInNewSpace(Register object_size,
- Register result,
- Register scratch1,
- Register scratch2,
- Label* gc_required,
- AllocationFlags flags) {
- ASSERT((flags & PRETENURE_OLD_POINTER_SPACE) == 0);
+void MacroAssembler::Allocate(Register object_size,
+ Register result,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required,
+ AllocationFlags flags) {
if (!FLAG_inline_new) {
if (emit_debug_code()) {
// Trash the registers to simulate an allocation failure.
@@ -1703,20 +1700,20 @@
// The values must be adjacent in memory to allow the use of LDM.
// Also, assert that the registers are numbered such that the values
// are loaded in the correct order.
- ExternalReference new_space_allocation_top =
- ExternalReference::new_space_allocation_top_address(isolate());
- ExternalReference new_space_allocation_limit =
- ExternalReference::new_space_allocation_limit_address(isolate());
+ ExternalReference allocation_top =
+ AllocationUtils::GetAllocationTopReference(isolate(), flags);
+ ExternalReference allocation_limit =
+ AllocationUtils::GetAllocationLimitReference(isolate(), flags);
intptr_t top =
- reinterpret_cast<intptr_t>(new_space_allocation_top.address());
+ reinterpret_cast<intptr_t>(allocation_top.address());
intptr_t limit =
- reinterpret_cast<intptr_t>(new_space_allocation_limit.address());
+ reinterpret_cast<intptr_t>(allocation_limit.address());
ASSERT((limit - top) == kPointerSize);
ASSERT(result.code() < ip.code());
// Set up allocation top address.
Register topaddr = scratch1;
- mov(topaddr, Operand(new_space_allocation_top));
+ mov(topaddr, Operand(allocation_top));
// This code stores a temporary value in ip. This is OK, as the code below
// does not need ip for implicit literal generation.
@@ -1739,6 +1736,7 @@
if ((flags & DOUBLE_ALIGNMENT) != 0) {
// Align the next allocation. Storing the filler map without checking top is
// always safe because the limit of the heap is always aligned.
+ ASSERT((flags & PRETENURE_OLD_POINTER_SPACE) == 0);
ASSERT(kPointerAlignment * 2 == kDoubleAlignment);
and_(scratch2, result, Operand(kDoubleAlignmentMask), SetCC);
Label aligned;
@@ -1809,12 +1807,12 @@
and_(scratch1, scratch1, Operand(~kObjectAlignmentMask));
// Allocate two-byte string in new space.
- AllocateInNewSpace(scratch1,
- result,
- scratch2,
- scratch3,
- gc_required,
- TAG_OBJECT);
+ Allocate(scratch1,
+ result,
+ scratch2,
+ scratch3,
+ gc_required,
+ TAG_OBJECT);
// Set the map, length and hash field.
InitializeNewString(result,
@@ -1840,12 +1838,12 @@
and_(scratch1, scratch1, Operand(~kObjectAlignmentMask));
// Allocate ASCII string in new space.
- AllocateInNewSpace(scratch1,
- result,
- scratch2,
- scratch3,
- gc_required,
- TAG_OBJECT);
+ Allocate(scratch1,
+ result,
+ scratch2,
+ scratch3,
+ gc_required,
+ TAG_OBJECT);
// Set the map, length and hash field.
InitializeNewString(result,
@@ -2499,9 +2497,9 @@
void MacroAssembler::ECMAConvertNumberToInt32(Register source,
Register result,
- Register scratch,
- Register input_high,
Register input_low,
+ Register input_high,
+ Register scratch,
DwVfpRegister double_scratch1,
DwVfpRegister double_scratch2) {
if (CpuFeatures::IsSupported(VFP2)) {
@@ -2578,24 +2576,26 @@
Ubfx(scratch, input_high,
HeapNumber::kExponentShift, HeapNumber::kExponentBits);
- // Load scratch with exponent - 1. This is faster than loading
- // with exponent because Bias + 1 = 1024 which is an *ARM* immediate value.
- sub(scratch, scratch, Operand(HeapNumber::kExponentBias + 1));
+ // Load scratch with exponent.
+ sub(scratch, scratch, Operand(HeapNumber::kExponentBias));
// If exponent is negative, 0 < input < 1, the result is 0.
// If exponent is greater than or equal to 84, the 32 less significant
// bits are 0s (2^84 = 1, 52 significant bits, 32 uncoded bits),
// the result is 0.
// This test also catch Nan and infinities which also return 0.
- // Compare exponent with 84 (compare exponent - 1 with 83).
- cmp(scratch, Operand(83));
+ cmp(scratch, Operand(84));
// We do an unsigned comparison so negative numbers are treated as big
// positive number and the two tests above are done in one test.
b(hs, &out_of_range);
- // Load scratch with 20 - exponent (load with 19 - (exponent - 1)).
- rsb(scratch, scratch, Operand(19), SetCC);
+ // Load scratch with 20 - exponent.
+ rsb(scratch, scratch, Operand(20), SetCC);
b(mi, &both);
+ // Test 0 and -0.
+ bic(result, input_high, Operand(HeapNumber::kSignMask));
+ orr(result, result, Operand(input_low), SetCC);
+ b(eq, &done);
// 0 <= exponent <= 20, shift only input_high.
// Scratch contains: 20 - exponent.
Ubfx(result, input_high,
diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h
index 5cbe995..958fcac 100644
--- a/src/arm/macro-assembler-arm.h
+++ b/src/arm/macro-assembler-arm.h
@@ -679,12 +679,12 @@
Label* gc_required,
AllocationFlags flags);
- void AllocateInNewSpace(Register object_size,
- Register result,
- Register scratch1,
- Register scratch2,
- Label* gc_required,
- AllocationFlags flags);
+ void Allocate(Register object_size,
+ Register result,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required,
+ AllocationFlags flags);
// Undo allocation in new space. The object passed and objects allocated after
// it will no longer be allocated. The caller must make sure that no pointers
@@ -960,9 +960,9 @@
// Exits with 'result' holding the answer.
void ECMAConvertNumberToInt32(Register source,
Register result,
- Register scratch,
- Register input_high,
Register input_low,
+ Register input_high,
+ Register scratch,
DwVfpRegister double_scratch1,
DwVfpRegister double_scratch2);
diff --git a/src/arm/simulator-arm.cc b/src/arm/simulator-arm.cc
index b7bc839..2551e14 100644
--- a/src/arm/simulator-arm.cc
+++ b/src/arm/simulator-arm.cc
@@ -112,8 +112,8 @@
ASSERT(msg != NULL);
// Update this stop description.
- if (isWatchedStop(code) && !watched_stops[code].desc) {
- watched_stops[code].desc = msg;
+ if (isWatchedStop(code) && !watched_stops_[code].desc) {
+ watched_stops_[code].desc = msg;
}
if (strlen(msg) > 0) {
@@ -141,8 +141,8 @@
char* msg = *reinterpret_cast<char**>(sim_->get_pc()
+ Instruction::kInstrSize);
// Update this stop description.
- if (sim_->isWatchedStop(code) && !sim_->watched_stops[code].desc) {
- sim_->watched_stops[code].desc = msg;
+ if (sim_->isWatchedStop(code) && !sim_->watched_stops_[code].desc) {
+ sim_->watched_stops_[code].desc = msg;
}
// Print the stop message and code if it is not the default code.
if (code != kMaxStopCode) {
@@ -1880,14 +1880,14 @@
ASSERT(code <= kMaxStopCode);
// Unwatched stops are always enabled.
return !isWatchedStop(code) ||
- !(watched_stops[code].count & kStopDisabledBit);
+ !(watched_stops_[code].count & kStopDisabledBit);
}
void Simulator::EnableStop(uint32_t code) {
ASSERT(isWatchedStop(code));
if (!isEnabledStop(code)) {
- watched_stops[code].count &= ~kStopDisabledBit;
+ watched_stops_[code].count &= ~kStopDisabledBit;
}
}
@@ -1895,7 +1895,7 @@
void Simulator::DisableStop(uint32_t code) {
ASSERT(isWatchedStop(code));
if (isEnabledStop(code)) {
- watched_stops[code].count |= kStopDisabledBit;
+ watched_stops_[code].count |= kStopDisabledBit;
}
}
@@ -1903,13 +1903,13 @@
void Simulator::IncreaseStopCounter(uint32_t code) {
ASSERT(code <= kMaxStopCode);
ASSERT(isWatchedStop(code));
- if ((watched_stops[code].count & ~(1 << 31)) == 0x7fffffff) {
+ if ((watched_stops_[code].count & ~(1 << 31)) == 0x7fffffff) {
PrintF("Stop counter for code %i has overflowed.\n"
"Enabling this code and reseting the counter to 0.\n", code);
- watched_stops[code].count = 0;
+ watched_stops_[code].count = 0;
EnableStop(code);
} else {
- watched_stops[code].count++;
+ watched_stops_[code].count++;
}
}
@@ -1921,12 +1921,12 @@
PrintF("Stop not watched.");
} else {
const char* state = isEnabledStop(code) ? "Enabled" : "Disabled";
- int32_t count = watched_stops[code].count & ~kStopDisabledBit;
+ int32_t count = watched_stops_[code].count & ~kStopDisabledBit;
// Don't print the state of unused breakpoints.
if (count != 0) {
- if (watched_stops[code].desc) {
+ if (watched_stops_[code].desc) {
PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n",
- code, code, state, count, watched_stops[code].desc);
+ code, code, state, count, watched_stops_[code].desc);
} else {
PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n",
code, code, state, count);
diff --git a/src/arm/simulator-arm.h b/src/arm/simulator-arm.h
index 907a590..b918ecf 100644
--- a/src/arm/simulator-arm.h
+++ b/src/arm/simulator-arm.h
@@ -414,14 +414,14 @@
static const uint32_t kStopDisabledBit = 1 << 31;
// A stop is enabled, meaning the simulator will stop when meeting the
- // instruction, if bit 31 of watched_stops[code].count is unset.
- // The value watched_stops[code].count & ~(1 << 31) indicates how many times
+ // instruction, if bit 31 of watched_stops_[code].count is unset.
+ // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
// the breakpoint was hit or gone through.
struct StopCountAndDesc {
uint32_t count;
char* desc;
};
- StopCountAndDesc watched_stops[kNumOfWatchedStops];
+ StopCountAndDesc watched_stops_[kNumOfWatchedStops];
};
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index 3350c56..f2d45e1 100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -423,7 +423,7 @@
// registers have their original values.
void StubCompiler::GenerateStoreField(MacroAssembler* masm,
Handle<JSObject> object,
- int index,
+ LookupResult* lookup,
Handle<Map> transition,
Handle<Name> name,
Register receiver_reg,
@@ -436,16 +436,6 @@
// r0 : value
Label exit;
- LookupResult lookup(masm->isolate());
- object->Lookup(*name, &lookup);
- if (lookup.IsFound() && (lookup.IsReadOnly() || !lookup.IsCacheable())) {
- // In sloppy mode, we could just return the value and be done. However, we
- // might be in strict mode, where we have to throw. Since we cannot tell,
- // go into slow case unconditionally.
- __ jmp(miss_label);
- return;
- }
-
// Check that the map of the object hasn't changed.
CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
: REQUIRE_EXACT_MAP;
@@ -460,8 +450,9 @@
// Check that we are allowed to write this.
if (!transition.is_null() && object->GetPrototype()->IsJSObject()) {
JSObject* holder;
- if (lookup.IsFound()) {
- holder = lookup.holder();
+ // holder == object indicates that no property was found.
+ if (lookup->holder() != *object) {
+ holder = lookup->holder();
} else {
// Find the top object.
holder = *object;
@@ -469,8 +460,19 @@
holder = JSObject::cast(holder->GetPrototype());
} while (holder->GetPrototype()->IsJSObject());
}
- CheckPrototypes(object, receiver_reg, Handle<JSObject>(holder), name_reg,
- scratch1, scratch2, name, miss_restore_name);
+ Register holder_reg = CheckPrototypes(
+ object, receiver_reg, Handle<JSObject>(holder), name_reg,
+ scratch1, scratch2, name, miss_restore_name);
+ // If no property was found, and the holder (the last object in the
+ // prototype chain) is in slow mode, we need to do a negative lookup on the
+ // holder.
+ if (lookup->holder() == *object &&
+ !holder->HasFastProperties() &&
+ !holder->IsJSGlobalProxy() &&
+ !holder->IsJSGlobalObject()) {
+ GenerateDictionaryNegativeLookup(
+ masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
+ }
}
// Stub never generated for non-global objects that require access
@@ -492,6 +494,7 @@
return;
}
+ int index;
if (!transition.is_null()) {
// Update the map of the object.
__ mov(scratch1, Operand(transition));
@@ -507,6 +510,10 @@
kDontSaveFPRegs,
OMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
+ index = transition->instance_descriptors()->GetFieldIndex(
+ transition->LastAdded());
+ } else {
+ index = lookup->GetFieldIndex().field_index();
}
// Adjust for the number of properties stored in the object. Even in the
@@ -2391,6 +2398,12 @@
// Check that the object is a symbol.
__ CompareObjectType(r1, r1, r3, SYMBOL_TYPE);
__ b(ne, &miss);
+ // Check that the maps starting from the prototype haven't changed.
+ GenerateDirectLoadGlobalFunctionPrototype(
+ masm(), Context::SYMBOL_FUNCTION_INDEX, r0, &miss);
+ CheckPrototypes(
+ Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
+ r0, holder, r3, r1, r4, name, &miss);
break;
case NUMBER_CHECK: {
@@ -2982,7 +2995,7 @@
__ cmp(r3, Operand(instance_size >> kPointerSizeLog2));
__ Check(eq, "Instance size of initial map changed.");
#endif
- __ AllocateInNewSpace(r3, r4, r5, r6, &generic_stub_call, SIZE_IN_WORDS);
+ __ Allocate(r3, r4, r5, r6, &generic_stub_call, SIZE_IN_WORDS);
// Allocated the JSObject, now initialize the fields. Map is set to initial
// map and properties and elements are set to empty fixed array.
diff --git a/src/array.js b/src/array.js
index 7cf744b..936d008 100644
--- a/src/array.js
+++ b/src/array.js
@@ -38,22 +38,21 @@
// Gets a sorted array of array keys. Useful for operations on sparse
// arrays. Dupes have not been removed.
-function GetSortedArrayKeys(array, intervals) {
- var length = intervals.length;
- var keys = [];
- for (var k = 0; k < length; k++) {
- var key = intervals[k];
- if (key < 0) {
- var j = -1 - key;
- var limit = j + intervals[++k];
- for (; j < limit; j++) {
- var e = array[j];
- if (!IS_UNDEFINED(e) || j in array) {
- keys.push(j);
- }
+function GetSortedArrayKeys(array, indices) {
+ var keys = new InternalArray();
+ if (IS_NUMBER(indices)) {
+ // It's an interval
+ var limit = indices;
+ for (var i = 0; i < limit; ++i) {
+ var e = array[i];
+ if (!IS_UNDEFINED(e) || i in array) {
+ keys.push(i);
}
- } else {
- // The case where key is undefined also ends here.
+ }
+ } else {
+ var length = indices.length;
+ for (var k = 0; k < length; ++k) {
+ var key = indices[k];
if (!IS_UNDEFINED(key)) {
var e = array[key];
if (!IS_UNDEFINED(e) || key in array) {
@@ -61,8 +60,8 @@
}
}
}
+ %_CallFunction(keys, function(a, b) { return a - b; }, ArraySort);
}
- %_CallFunction(keys, function(a, b) { return a - b; }, ArraySort);
return keys;
}
@@ -217,34 +216,21 @@
// special array operations to handle sparse arrays in a sensible fashion.
function SmartSlice(array, start_i, del_count, len, deleted_elements) {
// Move deleted elements to a new array (the return value from splice).
- // Intervals array can contain keys and intervals. See comment in Concat.
- var intervals = %GetArrayKeys(array, start_i + del_count);
- var length = intervals.length;
- for (var k = 0; k < length; k++) {
- var key = intervals[k];
- if (key < 0) {
- var j = -1 - key;
- var interval_limit = j + intervals[++k];
- if (j < start_i) {
- j = start_i;
+ var indices = %GetArrayKeys(array, start_i + del_count);
+ if (IS_NUMBER(indices)) {
+ var limit = indices;
+ for (var i = start_i; i < limit; ++i) {
+ var current = array[i];
+ if (!IS_UNDEFINED(current) || i in array) {
+ deleted_elements[i - start_i] = current;
}
- for (; j < interval_limit; j++) {
- // ECMA-262 15.4.4.12 line 10. The spec could also be
- // interpreted such that %HasLocalProperty would be the
- // appropriate test. We follow KJS in consulting the
- // prototype.
- var current = array[j];
- if (!IS_UNDEFINED(current) || j in array) {
- deleted_elements[j - start_i] = current;
- }
- }
- } else {
+ }
+ } else {
+ var length = indices.length;
+ for (var k = 0; k < length; ++k) {
+ var key = indices[k];
if (!IS_UNDEFINED(key)) {
if (key >= start_i) {
- // ECMA-262 15.4.4.12 line 10. The spec could also be
- // interpreted such that %HasLocalProperty would be the
- // appropriate test. We follow KJS in consulting the
- // prototype.
var current = array[key];
if (!IS_UNDEFINED(current) || key in array) {
deleted_elements[key - start_i] = current;
@@ -261,50 +247,32 @@
function SmartMove(array, start_i, del_count, len, num_additional_args) {
// Move data to new array.
var new_array = new InternalArray(len - del_count + num_additional_args);
- var intervals = %GetArrayKeys(array, len);
- var length = intervals.length;
- for (var k = 0; k < length; k++) {
- var key = intervals[k];
- if (key < 0) {
- var j = -1 - key;
- var interval_limit = j + intervals[++k];
- while (j < start_i && j < interval_limit) {
- // The spec could also be interpreted such that
- // %HasLocalProperty would be the appropriate test. We follow
- // KJS in consulting the prototype.
- var current = array[j];
- if (!IS_UNDEFINED(current) || j in array) {
- new_array[j] = current;
- }
- j++;
+ var indices = %GetArrayKeys(array, len);
+ if (IS_NUMBER(indices)) {
+ var limit = indices;
+ for (var i = 0; i < start_i && i < limit; ++i) {
+ var current = array[i];
+ if (!IS_UNDEFINED(current) || i in array) {
+ new_array[i] = current;
}
- j = start_i + del_count;
- while (j < interval_limit) {
- // ECMA-262 15.4.4.12 lines 24 and 41. The spec could also be
- // interpreted such that %HasLocalProperty would be the
- // appropriate test. We follow KJS in consulting the
- // prototype.
- var current = array[j];
- if (!IS_UNDEFINED(current) || j in array) {
- new_array[j - del_count + num_additional_args] = current;
- }
- j++;
+ }
+ for (var i = start_i + del_count; i < limit; ++i) {
+ var current = array[i];
+ if (!IS_UNDEFINED(current) || i in array) {
+ new_array[i - del_count + num_additional_args] = current;
}
- } else {
+ }
+ } else {
+ var length = indices.length;
+ for (var k = 0; k < length; ++k) {
+ var key = indices[k];
if (!IS_UNDEFINED(key)) {
if (key < start_i) {
- // The spec could also be interpreted such that
- // %HasLocalProperty would be the appropriate test. We follow
- // KJS in consulting the prototype.
var current = array[key];
if (!IS_UNDEFINED(current) || key in array) {
new_array[key] = current;
}
} else if (key >= start_i + del_count) {
- // ECMA-262 15.4.4.12 lines 24 and 41. The spec could also
- // be interpreted such that %HasLocalProperty would be the
- // appropriate test. We follow KJS in consulting the
- // prototype.
var current = array[key];
if (!IS_UNDEFINED(current) || key in array) {
new_array[key - del_count + num_additional_args] = current;
@@ -887,24 +855,22 @@
var max = 0;
for (var proto = %GetPrototype(obj); proto; proto = %GetPrototype(proto)) {
var indices = %GetArrayKeys(proto, length);
- if (indices.length > 0) {
- if (indices[0] == -1) {
- // It's an interval.
- var proto_length = indices[1];
- for (var i = 0; i < proto_length; i++) {
- if (!obj.hasOwnProperty(i) && proto.hasOwnProperty(i)) {
- obj[i] = proto[i];
- if (i >= max) { max = i + 1; }
- }
+ if (IS_NUMBER(indices)) {
+ // It's an interval.
+ var proto_length = indices;
+ for (var i = 0; i < proto_length; i++) {
+ if (!obj.hasOwnProperty(i) && proto.hasOwnProperty(i)) {
+ obj[i] = proto[i];
+ if (i >= max) { max = i + 1; }
}
- } else {
- for (var i = 0; i < indices.length; i++) {
- var index = indices[i];
- if (!IS_UNDEFINED(index) &&
- !obj.hasOwnProperty(index) && proto.hasOwnProperty(index)) {
- obj[index] = proto[index];
- if (index >= max) { max = index + 1; }
- }
+ }
+ } else {
+ for (var i = 0; i < indices.length; i++) {
+ var index = indices[i];
+ if (!IS_UNDEFINED(index) &&
+ !obj.hasOwnProperty(index) && proto.hasOwnProperty(index)) {
+ obj[index] = proto[index];
+ if (index >= max) { max = index + 1; }
}
}
}
@@ -918,22 +884,20 @@
var ShadowPrototypeElements = function(obj, from, to) {
for (var proto = %GetPrototype(obj); proto; proto = %GetPrototype(proto)) {
var indices = %GetArrayKeys(proto, to);
- if (indices.length > 0) {
- if (indices[0] == -1) {
- // It's an interval.
- var proto_length = indices[1];
- for (var i = from; i < proto_length; i++) {
- if (proto.hasOwnProperty(i)) {
- obj[i] = void 0;
- }
+ if (IS_NUMBER(indices)) {
+ // It's an interval.
+ var proto_length = indices;
+ for (var i = from; i < proto_length; i++) {
+ if (proto.hasOwnProperty(i)) {
+ obj[i] = void 0;
}
- } else {
- for (var i = 0; i < indices.length; i++) {
- var index = indices[i];
- if (!IS_UNDEFINED(index) && from <= index &&
- proto.hasOwnProperty(index)) {
- obj[index] = void 0;
- }
+ }
+ } else {
+ for (var i = 0; i < indices.length; i++) {
+ var index = indices[i];
+ if (!IS_UNDEFINED(index) && from <= index &&
+ proto.hasOwnProperty(index)) {
+ obj[index] = void 0;
}
}
}
@@ -1284,18 +1248,15 @@
var min = index;
var max = length;
if (UseSparseVariant(this, length, IS_ARRAY(this))) {
- var intervals = %GetArrayKeys(this, length);
- if (intervals.length == 2 && intervals[0] < 0) {
- // A single interval.
- var intervalMin = -(intervals[0] + 1);
- var intervalMax = intervalMin + intervals[1];
- if (min < intervalMin) min = intervalMin;
- max = intervalMax; // Capped by length already.
+ var indices = %GetArrayKeys(this, length);
+ if (IS_NUMBER(indices)) {
+ // It's an interval.
+ max = indices; // Capped by length already.
// Fall through to loop below.
} else {
- if (intervals.length == 0) return -1;
+ if (indices.length == 0) return -1;
// Get all the keys in sorted order.
- var sortedKeys = GetSortedArrayKeys(this, intervals);
+ var sortedKeys = GetSortedArrayKeys(this, indices);
var n = sortedKeys.length;
var i = 0;
while (i < n && sortedKeys[i] < index) i++;
@@ -1345,18 +1306,15 @@
var min = 0;
var max = index;
if (UseSparseVariant(this, length, IS_ARRAY(this))) {
- var intervals = %GetArrayKeys(this, index + 1);
- if (intervals.length == 2 && intervals[0] < 0) {
- // A single interval.
- var intervalMin = -(intervals[0] + 1);
- var intervalMax = intervalMin + intervals[1];
- if (min < intervalMin) min = intervalMin;
- max = intervalMax; // Capped by index already.
+ var indices = %GetArrayKeys(this, index + 1);
+ if (IS_NUMBER(indices)) {
+ // It's an interval.
+ max = indices; // Capped by index already.
// Fall through to loop below.
} else {
- if (intervals.length == 0) return -1;
+ if (indices.length == 0) return -1;
// Get all the keys in sorted order.
- var sortedKeys = GetSortedArrayKeys(this, intervals);
+ var sortedKeys = GetSortedArrayKeys(this, indices);
var i = sortedKeys.length - 1;
while (i >= 0) {
var key = sortedKeys[i];
diff --git a/src/ast.cc b/src/ast.cc
index a6984dd..7d7a5b2 100644
--- a/src/ast.cc
+++ b/src/ast.cc
@@ -414,12 +414,9 @@
is_monomorphic_ = oracle->LoadIsMonomorphicNormal(this);
receiver_types_.Clear();
if (key()->IsPropertyName()) {
- ArrayLengthStub array_stub(Code::LOAD_IC);
FunctionPrototypeStub proto_stub(Code::LOAD_IC);
StringLengthStub string_stub(Code::LOAD_IC, false);
- if (oracle->LoadIsStub(this, &array_stub)) {
- is_array_length_ = true;
- } else if (oracle->LoadIsStub(this, &string_stub)) {
+ if (oracle->LoadIsStub(this, &string_stub)) {
is_string_length_ = true;
} else if (oracle->LoadIsStub(this, &proto_stub)) {
is_function_prototype_ = true;
@@ -1065,6 +1062,7 @@
DONT_OPTIMIZE_NODE(ModulePath)
DONT_OPTIMIZE_NODE(ModuleUrl)
DONT_OPTIMIZE_NODE(ModuleStatement)
+DONT_OPTIMIZE_NODE(Yield)
DONT_OPTIMIZE_NODE(WithStatement)
DONT_OPTIMIZE_NODE(TryCatchStatement)
DONT_OPTIMIZE_NODE(TryFinallyStatement)
diff --git a/src/ast.h b/src/ast.h
index 88cd696..dddfc83 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -102,6 +102,7 @@
V(ObjectLiteral) \
V(ArrayLiteral) \
V(Assignment) \
+ V(Yield) \
V(Throw) \
V(Property) \
V(Call) \
@@ -119,6 +120,10 @@
STATEMENT_NODE_LIST(V) \
EXPRESSION_NODE_LIST(V)
+#ifdef WIN32
+#undef Yield
+#endif
+
// Forward declarations
class AstConstructionVisitor;
template<class> class AstNodeFactory;
@@ -1488,7 +1493,6 @@
virtual KeyedAccessStoreMode GetStoreMode() {
return STANDARD_STORE;
}
- bool IsArrayLength() { return is_array_length_; }
bool IsUninitialized() { return is_uninitialized_; }
TypeFeedbackId PropertyFeedbackId() { return reuse(id()); }
@@ -1504,7 +1508,6 @@
load_id_(GetNextId(isolate)),
is_monomorphic_(false),
is_uninitialized_(false),
- is_array_length_(false),
is_string_length_(false),
is_string_access_(false),
is_function_prototype_(false) { }
@@ -1518,7 +1521,6 @@
SmallMapList receiver_types_;
bool is_monomorphic_ : 1;
bool is_uninitialized_ : 1;
- bool is_array_length_ : 1;
bool is_string_length_ : 1;
bool is_string_access_ : 1;
bool is_function_prototype_ : 1;
@@ -1956,6 +1958,31 @@
};
+class Yield: public Expression {
+ public:
+ DECLARE_NODE_TYPE(Yield)
+
+ Expression* expression() const { return expression_; }
+ bool is_delegating_yield() const { return is_delegating_yield_; }
+ virtual int position() const { return pos_; }
+
+ protected:
+ Yield(Isolate* isolate,
+ Expression* expression,
+ bool is_delegating_yield,
+ int pos)
+ : Expression(isolate),
+ expression_(expression),
+ is_delegating_yield_(is_delegating_yield),
+ pos_(pos) { }
+
+ private:
+ Expression* expression_;
+ bool is_delegating_yield_;
+ int pos_;
+};
+
+
class Throw: public Expression {
public:
DECLARE_NODE_TYPE(Throw)
@@ -1996,6 +2023,11 @@
kNotParenthesized
};
+ enum IsGeneratorFlag {
+ kIsGenerator,
+ kNotGenerator
+ };
+
DECLARE_NODE_TYPE(FunctionLiteral)
Handle<String> name() const { return name_; }
@@ -2056,6 +2088,10 @@
bitfield_ = IsParenthesized::update(bitfield_, kIsParenthesized);
}
+ bool is_generator() {
+ return IsGenerator::decode(bitfield_) == kIsGenerator;
+ }
+
int ast_node_count() { return ast_properties_.node_count(); }
AstProperties::Flags* flags() { return ast_properties_.flags(); }
void set_ast_properties(AstProperties* ast_properties) {
@@ -2076,7 +2112,8 @@
Type type,
ParameterFlag has_duplicate_parameters,
IsFunctionFlag is_function,
- IsParenthesizedFlag is_parenthesized)
+ IsParenthesizedFlag is_parenthesized,
+ IsGeneratorFlag is_generator)
: Expression(isolate),
name_(name),
scope_(scope),
@@ -2096,7 +2133,8 @@
Pretenure::encode(false) |
HasDuplicateParameters::encode(has_duplicate_parameters) |
IsFunction::encode(is_function) |
- IsParenthesized::encode(is_parenthesized);
+ IsParenthesized::encode(is_parenthesized) |
+ IsGenerator::encode(is_generator);
}
private:
@@ -2121,6 +2159,7 @@
class HasDuplicateParameters: public BitField<ParameterFlag, 4, 1> {};
class IsFunction: public BitField<IsFunctionFlag, 5, 1> {};
class IsParenthesized: public BitField<IsParenthesizedFlag, 6, 1> {};
+ class IsGenerator: public BitField<IsGeneratorFlag, 7, 1> {};
};
@@ -2919,6 +2958,12 @@
VISIT_AND_RETURN(Assignment, assign)
}
+ Yield* NewYield(Expression* expression, bool is_delegating_yield, int pos) {
+ Yield* yield =
+ new(zone_) Yield(isolate_, expression, is_delegating_yield, pos);
+ VISIT_AND_RETURN(Yield, yield)
+ }
+
Throw* NewThrow(Expression* exception, int pos) {
Throw* t = new(zone_) Throw(isolate_, exception, pos);
VISIT_AND_RETURN(Throw, t)
@@ -2937,13 +2982,14 @@
FunctionLiteral::ParameterFlag has_duplicate_parameters,
FunctionLiteral::Type type,
FunctionLiteral::IsFunctionFlag is_function,
- FunctionLiteral::IsParenthesizedFlag is_parenthesized) {
+ FunctionLiteral::IsParenthesizedFlag is_parenthesized,
+ FunctionLiteral::IsGeneratorFlag is_generator) {
FunctionLiteral* lit = new(zone_) FunctionLiteral(
isolate_, name, scope, body,
materialized_literal_count, expected_property_count, handler_count,
has_only_simple_this_property_assignments, this_property_assignments,
parameter_count, type, has_duplicate_parameters, is_function,
- is_parenthesized);
+ is_parenthesized, is_generator);
// Top-level literal doesn't count for the AST's properties.
if (is_function == FunctionLiteral::kIsFunction) {
visitor_.VisitFunctionLiteral(lit);
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index ce58a86..f57a1f6 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -1280,7 +1280,17 @@
Handle<JSObject> global = Handle<JSObject>(native_context()->global_object());
// TODO(mstarzinger): Move this into Genesis::InitializeGlobal once we no
- // longer need to live behind a flag, so functions get added to the snapshot.
+ // longer need to live behind flags, so functions get added to the snapshot.
+
+ if (FLAG_harmony_symbols) {
+ // --- S y m b o l ---
+ Handle<JSFunction> symbol_fun =
+ InstallFunction(global, "Symbol", JS_VALUE_TYPE, JSValue::kSize,
+ isolate()->initial_object_prototype(),
+ Builtins::kIllegal, true);
+ native_context()->set_symbol_function(*symbol_fun);
+ }
+
if (FLAG_harmony_collections) {
{ // -- S e t
Handle<JSObject> prototype =
@@ -1301,6 +1311,16 @@
prototype, Builtins::kIllegal, true);
}
}
+
+ if (FLAG_harmony_typed_arrays) {
+ { // -- A r r a y B u f f e r
+ Handle<JSObject> prototype =
+ factory()->NewJSObject(isolate()->object_function(), TENURED);
+ InstallFunction(global, "__ArrayBuffer", JS_ARRAY_BUFFER_TYPE,
+ JSArrayBuffer::kSize, prototype,
+ Builtins::kIllegal, true);
+ }
+ }
}
@@ -1436,9 +1456,6 @@
}
void Genesis::InstallExperimentalNativeFunctions() {
- if (FLAG_harmony_symbols) {
- INSTALL_NATIVE(JSObject, "SymbolDelegate", symbol_delegate);
- }
if (FLAG_harmony_proxies) {
INSTALL_NATIVE(JSFunction, "DerivedHasTrap", derived_has_trap);
INSTALL_NATIVE(JSFunction, "DerivedGetTrap", derived_get_trap);
@@ -1911,6 +1928,11 @@
"native object-observe.js") == 0) {
if (!CompileExperimentalBuiltin(isolate(), i)) return false;
}
+ if (FLAG_harmony_typed_arrays &&
+ strcmp(ExperimentalNatives::GetScriptName(i).start(),
+ "native typedarray.js") == 0) {
+ if (!CompileExperimentalBuiltin(isolate(), i)) return false;
+ }
}
InstallExperimentalNativeFunctions();
diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc
index 0a8b9d5..ee903ae 100644
--- a/src/code-stubs-hydrogen.cc
+++ b/src/code-stubs-hydrogen.cc
@@ -129,7 +129,8 @@
if (descriptor_->stack_parameter_count_ != NULL) {
ASSERT(descriptor_->environment_length() == (param_count + 1));
stack_parameter_count = new(zone) HParameter(param_count,
- HParameter::REGISTER_PARAMETER);
+ HParameter::REGISTER_PARAMETER,
+ Representation::Integer32());
// it's essential to bind this value to the environment in case of deopt
start_environment->Bind(param_count, stack_parameter_count);
AddInstruction(stack_parameter_count);
@@ -147,13 +148,26 @@
AddSimulate(BailoutId::StubEntry());
HValue* return_value = BuildCodeStub();
+
+ // We might have extra expressions to pop from the stack in addition to the
+ // arguments above
+ HInstruction* stack_pop_count = stack_parameter_count;
+ if (descriptor_->function_mode_ == JS_FUNCTION_STUB_MODE) {
+ HInstruction* amount = graph()->GetConstant1();
+ stack_pop_count = AddInstruction(
+ HAdd::New(zone, context_, stack_parameter_count, amount));
+ stack_pop_count->ChangeRepresentation(Representation::Integer32());
+ stack_pop_count->ClearFlag(HValue::kCanOverflow);
+ }
+
HReturn* hreturn_instruction = new(zone) HReturn(return_value,
context_,
- stack_parameter_count);
+ stack_pop_count);
current_block()->Finish(hreturn_instruction);
return true;
}
+
template <class Stub>
class CodeStubGraphBuilder: public CodeStubGraphBuilderBase {
public:
@@ -273,9 +287,8 @@
AddInstruction(new(zone) HTrapAllocationMemento(js_array));
HInstruction* array_length =
- AddInstruction(new(zone) HJSArrayLength(js_array,
- js_array,
- HType::Smi()));
+ AddInstruction(HLoadNamedField::NewArrayLength(
+ zone, js_array, js_array, HType::Smi()));
ElementsKind to_kind = casted_stub()->to_kind();
BuildNewSpaceArrayCheck(array_length, to_kind);
diff --git a/src/code-stubs.cc b/src/code-stubs.cc
index 95bc1e9..eff0f7f 100644
--- a/src/code-stubs.cc
+++ b/src/code-stubs.cc
@@ -510,6 +510,7 @@
if (Contains(SMI)) stream->Add("Smi");
if (Contains(SPEC_OBJECT)) stream->Add("SpecObject");
if (Contains(STRING)) stream->Add("String");
+ if (Contains(SYMBOL)) stream->Add("Symbol");
if (Contains(HEAP_NUMBER)) stream->Add("HeapNumber");
}
@@ -549,6 +550,9 @@
Add(STRING);
return !object->IsUndetectableObject() &&
String::cast(*object)->length() != 0;
+ } else if (object->IsSymbol()) {
+ Add(SYMBOL);
+ return true;
} else if (object->IsHeapNumber()) {
ASSERT(!object->IsUndetectableObject());
Add(HEAP_NUMBER);
@@ -565,6 +569,7 @@
bool ToBooleanStub::Types::NeedsMap() const {
return Contains(ToBooleanStub::SPEC_OBJECT)
|| Contains(ToBooleanStub::STRING)
+ || Contains(ToBooleanStub::SYMBOL)
|| Contains(ToBooleanStub::HEAP_NUMBER);
}
@@ -614,10 +619,8 @@
void StubFailureTrampolineStub::GenerateAheadOfTime(Isolate* isolate) {
- int i = 0;
- for (; i <= StubFailureTrampolineStub::kMaxExtraExpressionStackCount; ++i) {
- StubFailureTrampolineStub(i).GetCode(isolate);
- }
+ StubFailureTrampolineStub(NOT_JS_FUNCTION_STUB_MODE).GetCode(isolate);
+ StubFailureTrampolineStub(JS_FUNCTION_STUB_MODE).GetCode(isolate);
}
diff --git a/src/code-stubs.h b/src/code-stubs.h
index 6e95780..99ff515 100644
--- a/src/code-stubs.h
+++ b/src/code-stubs.h
@@ -47,7 +47,6 @@
V(Compare) \
V(CompareIC) \
V(MathPow) \
- V(ArrayLength) \
V(StringLength) \
V(FunctionPrototype) \
V(StoreArrayLength) \
@@ -259,15 +258,17 @@
};
+enum StubFunctionMode { NOT_JS_FUNCTION_STUB_MODE, JS_FUNCTION_STUB_MODE };
+
struct CodeStubInterfaceDescriptor {
CodeStubInterfaceDescriptor()
: register_param_count_(-1),
stack_parameter_count_(NULL),
- extra_expression_stack_count_(0),
+ function_mode_(NOT_JS_FUNCTION_STUB_MODE),
register_params_(NULL) { }
int register_param_count_;
const Register* stack_parameter_count_;
- int extra_expression_stack_count_;
+ StubFunctionMode function_mode_;
Register* register_params_;
Address deoptimization_handler_;
@@ -597,16 +598,6 @@
};
-class ArrayLengthStub: public ICStub {
- public:
- explicit ArrayLengthStub(Code::Kind kind) : ICStub(kind) { }
- virtual void Generate(MacroAssembler* masm);
-
- private:
- virtual CodeStub::Major MajorKey() { return ArrayLength; }
-};
-
-
class FunctionPrototypeStub: public ICStub {
public:
explicit FunctionPrototypeStub(Code::Kind kind) : ICStub(kind) { }
@@ -1488,6 +1479,7 @@
SMI,
SPEC_OBJECT,
STRING,
+ SYMBOL,
HEAP_NUMBER,
NUMBER_OF_TYPES
};
@@ -1611,10 +1603,8 @@
class StubFailureTrampolineStub : public PlatformCodeStub {
public:
- static const int kMaxExtraExpressionStackCount = 1;
-
- explicit StubFailureTrampolineStub(int extra_expression_stack_count)
- : extra_expression_stack_count_(extra_expression_stack_count) {}
+ explicit StubFailureTrampolineStub(StubFunctionMode function_mode)
+ : function_mode_(function_mode) {}
virtual bool IsPregenerated() { return true; }
@@ -1622,11 +1612,11 @@
private:
Major MajorKey() { return StubFailureTrampoline; }
- int MinorKey() { return extra_expression_stack_count_; }
+ int MinorKey() { return static_cast<int>(function_mode_); }
void Generate(MacroAssembler* masm);
- int extra_expression_stack_count_;
+ StubFunctionMode function_mode_;
DISALLOW_COPY_AND_ASSIGN(StubFailureTrampolineStub);
};
diff --git a/src/codegen.cc b/src/codegen.cc
index 508e221..90ab2b5 100644
--- a/src/codegen.cc
+++ b/src/codegen.cc
@@ -171,7 +171,8 @@
bool CodeGenerator::ShouldGenerateLog(Expression* type) {
ASSERT(type != NULL);
Isolate* isolate = Isolate::Current();
- if (!isolate->logger()->is_logging() && !CpuProfiler::is_profiling(isolate)) {
+ if (!isolate->logger()->is_logging() &&
+ !isolate->cpu_profiler()->is_profiling()) {
return false;
}
Handle<String> name = Handle<String>::cast(type->AsLiteral()->handle());
diff --git a/src/compiler.cc b/src/compiler.cc
index 21ea25f..6f9b901 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -1121,6 +1121,7 @@
function_info->set_dont_optimize(lit->flags()->Contains(kDontOptimize));
function_info->set_dont_inline(lit->flags()->Contains(kDontInline));
function_info->set_dont_cache(lit->flags()->Contains(kDontCache));
+ function_info->set_is_generator(lit->is_generator());
}
@@ -1134,7 +1135,7 @@
// script name and line number. Check explicitly whether logging is
// enabled as finding the line number is not free.
if (info->isolate()->logger()->is_logging_code_events() ||
- CpuProfiler::is_profiling(info->isolate())) {
+ info->isolate()->cpu_profiler()->is_profiling()) {
Handle<Script> script = info->script();
Handle<Code> code = info->code();
if (*code == info->isolate()->builtins()->builtin(Builtins::kLazyCompile))
diff --git a/src/contexts.h b/src/contexts.h
index cd7ed6a..a0ba2f7 100644
--- a/src/contexts.h
+++ b/src/contexts.h
@@ -103,6 +103,7 @@
V(NUMBER_FUNCTION_INDEX, JSFunction, number_function) \
V(STRING_FUNCTION_INDEX, JSFunction, string_function) \
V(STRING_FUNCTION_PROTOTYPE_MAP_INDEX, Map, string_function_prototype_map) \
+ V(SYMBOL_FUNCTION_INDEX, JSFunction, symbol_function) \
V(OBJECT_FUNCTION_INDEX, JSFunction, object_function) \
V(INTERNAL_ARRAY_FUNCTION_INDEX, JSFunction, internal_array_function) \
V(ARRAY_FUNCTION_INDEX, JSFunction, array_function) \
@@ -156,7 +157,6 @@
V(ALLOW_CODE_GEN_FROM_STRINGS_INDEX, Object, allow_code_gen_from_strings) \
V(ERROR_MESSAGE_FOR_CODE_GEN_FROM_STRINGS_INDEX, Object, \
error_message_for_code_gen_from_strings) \
- V(SYMBOL_DELEGATE_INDEX, JSObject, symbol_delegate) \
V(TO_COMPLETE_PROPERTY_DESCRIPTOR_INDEX, JSFunction, \
to_complete_property_descriptor) \
V(DERIVED_HAS_TRAP_INDEX, JSFunction, derived_has_trap) \
@@ -251,6 +251,7 @@
NUMBER_FUNCTION_INDEX,
STRING_FUNCTION_INDEX,
STRING_FUNCTION_PROTOTYPE_MAP_INDEX,
+ SYMBOL_FUNCTION_INDEX,
OBJECT_FUNCTION_INDEX,
INTERNAL_ARRAY_FUNCTION_INDEX,
ARRAY_FUNCTION_INDEX,
@@ -287,7 +288,6 @@
EMBEDDER_DATA_INDEX,
ALLOW_CODE_GEN_FROM_STRINGS_INDEX,
ERROR_MESSAGE_FOR_CODE_GEN_FROM_STRINGS_INDEX,
- SYMBOL_DELEGATE_INDEX,
TO_COMPLETE_PROPERTY_DESCRIPTOR_INDEX,
DERIVED_HAS_TRAP_INDEX,
DERIVED_GET_TRAP_INDEX,
diff --git a/src/cpu-profiler.cc b/src/cpu-profiler.cc
index 15edc1e..7979eb4 100644
--- a/src/cpu-profiler.cc
+++ b/src/cpu-profiler.cc
@@ -258,109 +258,66 @@
}
-void CpuProfiler::StartProfiling(const char* title) {
- ASSERT(Isolate::Current()->cpu_profiler() != NULL);
- Isolate::Current()->cpu_profiler()->StartCollectingProfile(title);
-}
-
-
-void CpuProfiler::StartProfiling(String* title) {
- ASSERT(Isolate::Current()->cpu_profiler() != NULL);
- Isolate::Current()->cpu_profiler()->StartCollectingProfile(title);
-}
-
-
-CpuProfile* CpuProfiler::StopProfiling(const char* title) {
- Isolate* isolate = Isolate::Current();
- return is_profiling(isolate) ?
- isolate->cpu_profiler()->StopCollectingProfile(title) : NULL;
-}
-
-
-CpuProfile* CpuProfiler::StopProfiling(Object* security_token, String* title) {
- Isolate* isolate = Isolate::Current();
- return is_profiling(isolate) ?
- isolate->cpu_profiler()->StopCollectingProfile(
- security_token, title) : NULL;
-}
-
-
int CpuProfiler::GetProfilesCount() {
- ASSERT(Isolate::Current()->cpu_profiler() != NULL);
// The count of profiles doesn't depend on a security token.
- return Isolate::Current()->cpu_profiler()->profiles_->Profiles(
- TokenEnumerator::kNoSecurityToken)->length();
+ return profiles_->Profiles(TokenEnumerator::kNoSecurityToken)->length();
}
CpuProfile* CpuProfiler::GetProfile(Object* security_token, int index) {
- ASSERT(Isolate::Current()->cpu_profiler() != NULL);
- CpuProfiler* profiler = Isolate::Current()->cpu_profiler();
- const int token = profiler->token_enumerator_->GetTokenId(security_token);
- return profiler->profiles_->Profiles(token)->at(index);
+ const int token = token_enumerator_->GetTokenId(security_token);
+ return profiles_->Profiles(token)->at(index);
}
CpuProfile* CpuProfiler::FindProfile(Object* security_token, unsigned uid) {
- ASSERT(Isolate::Current()->cpu_profiler() != NULL);
- CpuProfiler* profiler = Isolate::Current()->cpu_profiler();
- const int token = profiler->token_enumerator_->GetTokenId(security_token);
- return profiler->profiles_->GetProfile(token, uid);
+ const int token = token_enumerator_->GetTokenId(security_token);
+ return profiles_->GetProfile(token, uid);
}
-TickSample* CpuProfiler::TickSampleEvent(Isolate* isolate) {
- if (CpuProfiler::is_profiling(isolate)) {
- return isolate->cpu_profiler()->processor_->TickSampleEvent();
- } else {
- return NULL;
- }
+TickSample* CpuProfiler::TickSampleEvent() {
+ if (is_profiling_) return processor_->TickSampleEvent();
+ return NULL;
}
void CpuProfiler::DeleteAllProfiles() {
- Isolate* isolate = Isolate::Current();
- ASSERT(isolate->cpu_profiler() != NULL);
- if (is_profiling(isolate)) {
- isolate->cpu_profiler()->StopProcessor();
- }
- isolate->cpu_profiler()->ResetProfiles();
+ if (is_profiling_) StopProcessor();
+ ResetProfiles();
}
void CpuProfiler::DeleteProfile(CpuProfile* profile) {
- ASSERT(Isolate::Current()->cpu_profiler() != NULL);
- Isolate::Current()->cpu_profiler()->profiles_->RemoveProfile(profile);
+ profiles_->RemoveProfile(profile);
delete profile;
}
bool CpuProfiler::HasDetachedProfiles() {
- ASSERT(Isolate::Current()->cpu_profiler() != NULL);
- return Isolate::Current()->cpu_profiler()->profiles_->HasDetachedProfiles();
+ return profiles_->HasDetachedProfiles();
}
void CpuProfiler::CallbackEvent(Name* name, Address entry_point) {
- Isolate::Current()->cpu_profiler()->processor_->CallbackCreateEvent(
+ processor_->CallbackCreateEvent(
Logger::CALLBACK_TAG, CodeEntry::kEmptyNamePrefix, name, entry_point);
}
void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
Code* code, const char* comment) {
- Isolate::Current()->cpu_profiler()->processor_->CodeCreateEvent(
+ processor_->CodeCreateEvent(
tag, comment, code->address(), code->ExecutableSize());
}
void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
Code* code, Name* name) {
- Isolate* isolate = Isolate::Current();
- isolate->cpu_profiler()->processor_->CodeCreateEvent(
+ processor_->CodeCreateEvent(
tag,
name,
- isolate->heap()->empty_string(),
+ isolate_->heap()->empty_string(),
v8::CpuProfileNode::kNoLineNumberInfo,
code->address(),
code->ExecutableSize(),
@@ -372,11 +329,10 @@
Code* code,
SharedFunctionInfo* shared,
Name* name) {
- Isolate* isolate = Isolate::Current();
- isolate->cpu_profiler()->processor_->CodeCreateEvent(
+ processor_->CodeCreateEvent(
tag,
name,
- isolate->heap()->empty_string(),
+ isolate_->heap()->empty_string(),
v8::CpuProfileNode::kNoLineNumberInfo,
code->address(),
code->ExecutableSize(),
@@ -388,7 +344,7 @@
Code* code,
SharedFunctionInfo* shared,
String* source, int line) {
- Isolate::Current()->cpu_profiler()->processor_->CodeCreateEvent(
+ processor_->CodeCreateEvent(
tag,
shared->DebugName(),
source,
@@ -401,7 +357,7 @@
void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
Code* code, int args_count) {
- Isolate::Current()->cpu_profiler()->processor_->CodeCreateEvent(
+ processor_->CodeCreateEvent(
tag,
args_count,
code->address(),
@@ -410,7 +366,7 @@
void CpuProfiler::CodeMoveEvent(Address from, Address to) {
- Isolate::Current()->cpu_profiler()->processor_->CodeMoveEvent(from, to);
+ processor_->CodeMoveEvent(from, to);
}
@@ -419,19 +375,18 @@
void CpuProfiler::SharedFunctionInfoMoveEvent(Address from, Address to) {
- CpuProfiler* profiler = Isolate::Current()->cpu_profiler();
- profiler->processor_->SharedFunctionInfoMoveEvent(from, to);
+ processor_->SharedFunctionInfoMoveEvent(from, to);
}
void CpuProfiler::GetterCallbackEvent(Name* name, Address entry_point) {
- Isolate::Current()->cpu_profiler()->processor_->CallbackCreateEvent(
+ processor_->CallbackCreateEvent(
Logger::CALLBACK_TAG, "get ", name, entry_point);
}
void CpuProfiler::RegExpCodeCreateEvent(Code* code, String* source) {
- Isolate::Current()->cpu_profiler()->processor_->RegExpCodeCreateEvent(
+ processor_->RegExpCodeCreateEvent(
Logger::REG_EXP_TAG,
"RegExp: ",
source,
@@ -441,13 +396,14 @@
void CpuProfiler::SetterCallbackEvent(Name* name, Address entry_point) {
- Isolate::Current()->cpu_profiler()->processor_->CallbackCreateEvent(
+ processor_->CallbackCreateEvent(
Logger::CALLBACK_TAG, "set ", name, entry_point);
}
-CpuProfiler::CpuProfiler()
- : profiles_(new CpuProfilesCollection()),
+CpuProfiler::CpuProfiler(Isolate* isolate)
+ : isolate_(isolate),
+ profiles_(new CpuProfilesCollection()),
next_profile_uid_(1),
token_enumerator_(new TokenEnumerator()),
generator_(NULL),
@@ -468,43 +424,41 @@
profiles_ = new CpuProfilesCollection();
}
-void CpuProfiler::StartCollectingProfile(const char* title) {
- if (profiles_->StartProfiling(title, next_profile_uid_++)) {
+void CpuProfiler::StartProfiling(const char* title, bool record_samples) {
+ if (profiles_->StartProfiling(title, next_profile_uid_++, record_samples)) {
StartProcessorIfNotStarted();
}
processor_->AddCurrentStack();
}
-void CpuProfiler::StartCollectingProfile(String* title) {
- StartCollectingProfile(profiles_->GetName(title));
+void CpuProfiler::StartProfiling(String* title, bool record_samples) {
+ StartProfiling(profiles_->GetName(title), record_samples);
}
void CpuProfiler::StartProcessorIfNotStarted() {
if (processor_ == NULL) {
- Isolate* isolate = Isolate::Current();
-
// Disable logging when using the new implementation.
- saved_logging_nesting_ = isolate->logger()->logging_nesting_;
- isolate->logger()->logging_nesting_ = 0;
+ saved_logging_nesting_ = isolate_->logger()->logging_nesting_;
+ isolate_->logger()->logging_nesting_ = 0;
generator_ = new ProfileGenerator(profiles_);
processor_ = new ProfilerEventsProcessor(generator_);
is_profiling_ = true;
processor_->Start();
// Enumerate stuff we already have in the heap.
- if (isolate->heap()->HasBeenSetUp()) {
+ if (isolate_->heap()->HasBeenSetUp()) {
if (!FLAG_prof_browser_mode) {
bool saved_log_code_flag = FLAG_log_code;
FLAG_log_code = true;
- isolate->logger()->LogCodeObjects();
+ isolate_->logger()->LogCodeObjects();
FLAG_log_code = saved_log_code_flag;
}
- isolate->logger()->LogCompiledFunctions();
- isolate->logger()->LogAccessorCallbacks();
+ isolate_->logger()->LogCompiledFunctions();
+ isolate_->logger()->LogAccessorCallbacks();
}
// Enable stack sampling.
- Sampler* sampler = reinterpret_cast<Sampler*>(isolate->logger()->ticker_);
+ Sampler* sampler = reinterpret_cast<Sampler*>(isolate_->logger()->ticker_);
if (!sampler->IsActive()) {
sampler->Start();
need_to_stop_sampler_ = true;
@@ -514,7 +468,8 @@
}
-CpuProfile* CpuProfiler::StopCollectingProfile(const char* title) {
+CpuProfile* CpuProfiler::StopProfiling(const char* title) {
+ if (!is_profiling_) return NULL;
const double actual_sampling_rate = generator_->actual_sampling_rate();
StopProcessorIfLastProfile(title);
CpuProfile* result =
@@ -528,8 +483,8 @@
}
-CpuProfile* CpuProfiler::StopCollectingProfile(Object* security_token,
- String* title) {
+CpuProfile* CpuProfiler::StopProfiling(Object* security_token, String* title) {
+ if (!is_profiling_) return NULL;
const double actual_sampling_rate = generator_->actual_sampling_rate();
const char* profile_title = profiles_->GetName(title);
StopProcessorIfLastProfile(profile_title);
@@ -544,7 +499,7 @@
void CpuProfiler::StopProcessor() {
- Logger* logger = Isolate::Current()->logger();
+ Logger* logger = isolate_->logger();
Sampler* sampler = reinterpret_cast<Sampler*>(logger->ticker_);
sampler->DecreaseProfilingDepth();
if (need_to_stop_sampler_) {
@@ -562,20 +517,4 @@
}
-void CpuProfiler::SetUp() {
- Isolate* isolate = Isolate::Current();
- if (isolate->cpu_profiler() == NULL) {
- isolate->set_cpu_profiler(new CpuProfiler());
- }
-}
-
-
-void CpuProfiler::TearDown() {
- Isolate* isolate = Isolate::Current();
- if (isolate->cpu_profiler() != NULL) {
- delete isolate->cpu_profiler();
- }
- isolate->set_cpu_profiler(NULL);
-}
-
} } // namespace v8::internal
diff --git a/src/cpu-profiler.h b/src/cpu-profiler.h
index 3dc766b..89d9c81 100644
--- a/src/cpu-profiler.h
+++ b/src/cpu-profiler.h
@@ -184,84 +184,71 @@
unsigned enqueue_order_;
};
-} } // namespace v8::internal
-
-#define PROFILE(isolate, Call) \
- LOG_CODE_EVENT(isolate, Call); \
- do { \
- if (v8::internal::CpuProfiler::is_profiling(isolate)) { \
- v8::internal::CpuProfiler::Call; \
- } \
+#define PROFILE(IsolateGetter, Call) \
+ do { \
+ Isolate* cpu_profiler_isolate = (IsolateGetter); \
+ LOG_CODE_EVENT(cpu_profiler_isolate, Call); \
+ CpuProfiler* cpu_profiler = cpu_profiler_isolate->cpu_profiler(); \
+ if (cpu_profiler->is_profiling()) { \
+ cpu_profiler->Call; \
+ } \
} while (false)
-namespace v8 {
-namespace internal {
-
-
-// TODO(isolates): isolatify this class.
class CpuProfiler {
public:
- static void SetUp();
- static void TearDown();
+ explicit CpuProfiler(Isolate* isolate);
+ ~CpuProfiler();
- static void StartProfiling(const char* title);
- static void StartProfiling(String* title);
- static CpuProfile* StopProfiling(const char* title);
- static CpuProfile* StopProfiling(Object* security_token, String* title);
- static int GetProfilesCount();
- static CpuProfile* GetProfile(Object* security_token, int index);
- static CpuProfile* FindProfile(Object* security_token, unsigned uid);
- static void DeleteAllProfiles();
- static void DeleteProfile(CpuProfile* profile);
- static bool HasDetachedProfiles();
+ void StartProfiling(const char* title, bool record_samples = false);
+ void StartProfiling(String* title, bool record_samples);
+ CpuProfile* StopProfiling(const char* title);
+ CpuProfile* StopProfiling(Object* security_token, String* title);
+ int GetProfilesCount();
+ CpuProfile* GetProfile(Object* security_token, int index);
+ CpuProfile* FindProfile(Object* security_token, unsigned uid);
+ void DeleteAllProfiles();
+ void DeleteProfile(CpuProfile* profile);
+ bool HasDetachedProfiles();
// Invoked from stack sampler (thread or signal handler.)
- static TickSample* TickSampleEvent(Isolate* isolate);
+ TickSample* TickSampleEvent();
// Must be called via PROFILE macro, otherwise will crash when
// profiling is not enabled.
- static void CallbackEvent(Name* name, Address entry_point);
- static void CodeCreateEvent(Logger::LogEventsAndTags tag,
- Code* code, const char* comment);
- static void CodeCreateEvent(Logger::LogEventsAndTags tag,
- Code* code, Name* name);
- static void CodeCreateEvent(Logger::LogEventsAndTags tag,
- Code* code,
+ void CallbackEvent(Name* name, Address entry_point);
+ void CodeCreateEvent(Logger::LogEventsAndTags tag,
+ Code* code, const char* comment);
+ void CodeCreateEvent(Logger::LogEventsAndTags tag,
+ Code* code, Name* name);
+ void CodeCreateEvent(Logger::LogEventsAndTags tag,
+ Code* code,
SharedFunctionInfo* shared,
Name* name);
- static void CodeCreateEvent(Logger::LogEventsAndTags tag,
- Code* code,
- SharedFunctionInfo* shared,
- String* source, int line);
- static void CodeCreateEvent(Logger::LogEventsAndTags tag,
- Code* code, int args_count);
- static void CodeMovingGCEvent() {}
- static void CodeMoveEvent(Address from, Address to);
- static void CodeDeleteEvent(Address from);
- static void GetterCallbackEvent(Name* name, Address entry_point);
- static void RegExpCodeCreateEvent(Code* code, String* source);
- static void SetterCallbackEvent(Name* name, Address entry_point);
- static void SharedFunctionInfoMoveEvent(Address from, Address to);
+ void CodeCreateEvent(Logger::LogEventsAndTags tag,
+ Code* code,
+ SharedFunctionInfo* shared,
+ String* source, int line);
+ void CodeCreateEvent(Logger::LogEventsAndTags tag,
+ Code* code, int args_count);
+ void CodeMovingGCEvent() {}
+ void CodeMoveEvent(Address from, Address to);
+ void CodeDeleteEvent(Address from);
+ void GetterCallbackEvent(Name* name, Address entry_point);
+ void RegExpCodeCreateEvent(Code* code, String* source);
+ void SetterCallbackEvent(Name* name, Address entry_point);
+ void SharedFunctionInfoMoveEvent(Address from, Address to);
- static INLINE(bool is_profiling(Isolate* isolate)) {
- CpuProfiler* profiler = isolate->cpu_profiler();
- return profiler != NULL && profiler->is_profiling_;
- }
+ INLINE(bool is_profiling() const) { return is_profiling_; }
private:
- CpuProfiler();
- ~CpuProfiler();
- void StartCollectingProfile(const char* title);
- void StartCollectingProfile(String* title);
void StartProcessorIfNotStarted();
- CpuProfile* StopCollectingProfile(const char* title);
- CpuProfile* StopCollectingProfile(Object* security_token, String* title);
void StopProcessorIfLastProfile(const char* title);
void StopProcessor();
void ResetProfiles();
+ Isolate* isolate_;
CpuProfilesCollection* profiles_;
unsigned next_profile_uid_;
TokenEnumerator* token_enumerator_;
diff --git a/src/d8.cc b/src/d8.cc
index 805a0cf..b57e390 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -227,11 +227,13 @@
}
#if !defined(V8_SHARED)
} else {
+ v8::TryCatch try_catch;
Context::Scope context_scope(utility_context_);
Handle<Object> global = utility_context_->Global();
Handle<Value> fun = global->Get(String::New("Stringify"));
Handle<Value> argv[1] = { result };
Handle<Value> s = Handle<Function>::Cast(fun)->Call(global, 1, argv);
+ if (try_catch.HasCaught()) return true;
v8::String::Utf8Value str(s);
fwrite(*str, sizeof(**str), str.length(), stdout);
printf("\n");
@@ -905,12 +907,6 @@
}
-Handle<Value> Shell::Yield(const Arguments& args) {
- v8::Unlocker unlocker(args.GetIsolate());
- return Undefined(args.GetIsolate());
-}
-
-
Handle<Value> Shell::Quit(const Arguments& args) {
int exit_code = args[0]->Int32Value();
OnExit();
diff --git a/src/d8.h b/src/d8.h
index 621ac74..2789c07 100644
--- a/src/d8.h
+++ b/src/d8.h
@@ -298,13 +298,8 @@
#endif // ENABLE_DEBUGGER_SUPPORT
#endif // V8_SHARED
-#ifdef WIN32
-#undef Yield
-#endif
-
static Handle<Value> Print(const Arguments& args);
static Handle<Value> Write(const Arguments& args);
- static Handle<Value> Yield(const Arguments& args);
static Handle<Value> Quit(const Arguments& args);
static Handle<Value> Version(const Arguments& args);
static Handle<Value> EnableProfiler(const Arguments& args);
diff --git a/src/d8.js b/src/d8.js
index 1ff0ce8..df10461 100644
--- a/src/d8.js
+++ b/src/d8.js
@@ -2214,7 +2214,8 @@
return x.toString();
case "string":
return "\"" + x.toString() + "\"";
- // TODO(rossberg): add symbol case
+ case "symbol":
+ return "Symbol(" + (x.name ? Stringify(x.name, depth) : "") + ")"
case "object":
if (x === null) return "null";
if (x.constructor && x.constructor.name === "Array") {
diff --git a/src/debug.cc b/src/debug.cc
index 7a876e7..91af9cc 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -3761,8 +3761,8 @@
MessageDispatchHelperThread::MessageDispatchHelperThread(Isolate* isolate)
: Thread("v8:MsgDispHelpr"),
- sem_(OS::CreateSemaphore(0)), mutex_(OS::CreateMutex()),
- already_signalled_(false) {
+ isolate_(isolate), sem_(OS::CreateSemaphore(0)),
+ mutex_(OS::CreateMutex()), already_signalled_(false) {
}
@@ -3785,7 +3785,6 @@
void MessageDispatchHelperThread::Run() {
- Isolate* isolate = Isolate::Current();
while (true) {
sem_->Wait();
{
@@ -3793,8 +3792,8 @@
already_signalled_ = false;
}
{
- Locker locker(reinterpret_cast<v8::Isolate*>(isolate));
- isolate->debugger()->CallMessageDispatchHandler();
+ Locker locker(reinterpret_cast<v8::Isolate*>(isolate_));
+ isolate_->debugger()->CallMessageDispatchHandler();
}
}
}
diff --git a/src/debug.h b/src/debug.h
index c7f0681..459073f 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -1041,6 +1041,7 @@
private:
void Run();
+ Isolate* isolate_;
Semaphore* const sem_;
Mutex* const mutex_;
bool already_signalled_;
diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc
index 8a07afe..601faf7 100644
--- a/src/deoptimizer.cc
+++ b/src/deoptimizer.cc
@@ -1280,29 +1280,37 @@
}
intptr_t caller_arg_count = 0;
- if (descriptor->stack_parameter_count_ != NULL) {
- caller_arg_count =
- input_->GetRegister(descriptor->stack_parameter_count_->code());
- }
+ bool arg_count_known = descriptor->stack_parameter_count_ == NULL;
// Build the Arguments object for the caller's parameters and a pointer to it.
output_frame_offset -= kPointerSize;
- value = frame_ptr + StandardFrameConstants::kCallerSPOffset +
- (caller_arg_count - 1) * kPointerSize;
- output_frame->SetFrameSlot(output_frame_offset, value);
+ int args_arguments_offset = output_frame_offset;
+ intptr_t the_hole = reinterpret_cast<intptr_t>(
+ isolate_->heap()->the_hole_value());
+ if (arg_count_known) {
+ value = frame_ptr + StandardFrameConstants::kCallerSPOffset +
+ (caller_arg_count - 1) * kPointerSize;
+ } else {
+ value = the_hole;
+ }
+
+ output_frame->SetFrameSlot(args_arguments_offset, value);
if (trace_) {
PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
- V8PRIxPTR " ; args.arguments\n",
- top_address + output_frame_offset, output_frame_offset, value);
+ V8PRIxPTR " ; args.arguments %s\n",
+ top_address + args_arguments_offset, args_arguments_offset, value,
+ arg_count_known ? "" : "(the hole)");
}
output_frame_offset -= kPointerSize;
- value = caller_arg_count;
- output_frame->SetFrameSlot(output_frame_offset, value);
+ int length_frame_offset = output_frame_offset;
+ value = arg_count_known ? caller_arg_count : the_hole;
+ output_frame->SetFrameSlot(length_frame_offset, value);
if (trace_) {
PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
- V8PRIxPTR " ; args.length\n",
- top_address + output_frame_offset, output_frame_offset, value);
+ V8PRIxPTR " ; args.length %s\n",
+ top_address + length_frame_offset, length_frame_offset, value,
+ arg_count_known ? "" : "(the hole)");
}
output_frame_offset -= kPointerSize;
@@ -1321,6 +1329,20 @@
DoTranslateCommand(iterator, 0, output_frame_offset);
}
+ if (!arg_count_known) {
+ DoTranslateCommand(iterator, 0, length_frame_offset,
+ TRANSLATED_VALUE_IS_NATIVE);
+ caller_arg_count = output_frame->GetFrameSlot(length_frame_offset);
+ value = frame_ptr + StandardFrameConstants::kCallerSPOffset +
+ (caller_arg_count - 1) * kPointerSize;
+ output_frame->SetFrameSlot(args_arguments_offset, value);
+ if (trace_) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ V8PRIxPTR " ; args.arguments\n",
+ top_address + args_arguments_offset, args_arguments_offset, value);
+ }
+ }
+
ASSERT(0 == output_frame_offset);
// Copy the double registers from the input into the output frame.
@@ -1331,8 +1353,9 @@
// Compute this frame's PC, state, and continuation.
Code* trampoline = NULL;
- int extra = descriptor->extra_expression_stack_count_;
- StubFailureTrampolineStub(extra).FindCodeInCache(&trampoline, isolate_);
+ StubFunctionMode function_mode = descriptor->function_mode_;
+ StubFailureTrampolineStub(function_mode).FindCodeInCache(&trampoline,
+ isolate_);
ASSERT(trampoline != NULL);
output_frame->SetPc(reinterpret_cast<intptr_t>(
trampoline->instruction_start()));
@@ -1476,12 +1499,25 @@
#endif
+static const char* TraceValueType(bool is_smi, bool is_native) {
+ if (is_native) {
+ return "native";
+ } else if (is_smi) {
+ return "smi";
+ }
+
+ return "heap number";
+}
+
+
void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
- int frame_index,
- unsigned output_offset) {
+ int frame_index,
+ unsigned output_offset,
+ DeoptimizerTranslatedValueType value_type) {
disasm::NameConverter converter;
// A GC-safe temporary placeholder that we can put in the output frame.
const intptr_t kPlaceholder = reinterpret_cast<intptr_t>(Smi::FromInt(0));
+ bool is_native = value_type == TRANSLATED_VALUE_IS_NATIVE;
// Ignore commands marked as duplicate and act on the first non-duplicate.
Translation::Opcode opcode =
@@ -1524,7 +1560,9 @@
case Translation::INT32_REGISTER: {
int input_reg = iterator->Next();
intptr_t value = input_->GetRegister(input_reg);
- bool is_smi = Smi::IsValid(value);
+ bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) &&
+ Smi::IsValid(value);
+
if (trace_) {
PrintF(
" 0x%08" V8PRIxPTR ": [top + %d] <- %" V8PRIdPTR " ; %s (%s)\n",
@@ -1532,15 +1570,18 @@
output_offset,
value,
converter.NameOfCPURegister(input_reg),
- is_smi ? "smi" : "heap number");
+ TraceValueType(is_smi, is_native));
}
if (is_smi) {
intptr_t tagged_value =
reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
+ } else if (value_type == TRANSLATED_VALUE_IS_NATIVE) {
+ output_[frame_index]->SetFrameSlot(output_offset, value);
} else {
// We save the untagged value on the side and store a GC-safe
// temporary placeholder in the frame.
+ ASSERT(value_type == TRANSLATED_VALUE_IS_TAGGED);
AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
static_cast<double>(static_cast<int32_t>(value)));
output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
@@ -1551,7 +1592,8 @@
case Translation::UINT32_REGISTER: {
int input_reg = iterator->Next();
uintptr_t value = static_cast<uintptr_t>(input_->GetRegister(input_reg));
- bool is_smi = (value <= static_cast<uintptr_t>(Smi::kMaxValue));
+ bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) &&
+ (value <= static_cast<uintptr_t>(Smi::kMaxValue));
if (trace_) {
PrintF(
" 0x%08" V8PRIxPTR ": [top + %d] <- %" V8PRIuPTR
@@ -1560,15 +1602,18 @@
output_offset,
value,
converter.NameOfCPURegister(input_reg),
- is_smi ? "smi" : "heap number");
+ TraceValueType(is_smi, is_native));
}
if (is_smi) {
intptr_t tagged_value =
reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
+ } else if (value_type == TRANSLATED_VALUE_IS_NATIVE) {
+ output_[frame_index]->SetFrameSlot(output_offset, value);
} else {
// We save the untagged value on the side and store a GC-safe
// temporary placeholder in the frame.
+ ASSERT(value_type == TRANSLATED_VALUE_IS_TAGGED);
AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
static_cast<double>(static_cast<uint32_t>(value)));
output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
@@ -1617,7 +1662,8 @@
unsigned input_offset =
input_->GetOffsetFromSlotIndex(input_slot_index);
intptr_t value = input_->GetFrameSlot(input_offset);
- bool is_smi = Smi::IsValid(value);
+ bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) &&
+ Smi::IsValid(value);
if (trace_) {
PrintF(" 0x%08" V8PRIxPTR ": ",
output_[frame_index]->GetTop() + output_offset);
@@ -1625,15 +1671,18 @@
output_offset,
value,
input_offset,
- is_smi ? "smi" : "heap number");
+ TraceValueType(is_smi, is_native));
}
if (is_smi) {
intptr_t tagged_value =
reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
+ } else if (value_type == TRANSLATED_VALUE_IS_NATIVE) {
+ output_[frame_index]->SetFrameSlot(output_offset, value);
} else {
// We save the untagged value on the side and store a GC-safe
// temporary placeholder in the frame.
+ ASSERT(value_type == TRANSLATED_VALUE_IS_TAGGED);
AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
static_cast<double>(static_cast<int32_t>(value)));
output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
@@ -1647,7 +1696,8 @@
input_->GetOffsetFromSlotIndex(input_slot_index);
uintptr_t value =
static_cast<uintptr_t>(input_->GetFrameSlot(input_offset));
- bool is_smi = (value <= static_cast<uintptr_t>(Smi::kMaxValue));
+ bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) &&
+ (value <= static_cast<uintptr_t>(Smi::kMaxValue));
if (trace_) {
PrintF(" 0x%08" V8PRIxPTR ": ",
output_[frame_index]->GetTop() + output_offset);
@@ -1655,15 +1705,18 @@
output_offset,
value,
input_offset,
- is_smi ? "smi" : "heap number");
+ TraceValueType(is_smi, is_native));
}
if (is_smi) {
intptr_t tagged_value =
reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
+ } else if (value_type == TRANSLATED_VALUE_IS_NATIVE) {
+ output_[frame_index]->SetFrameSlot(output_offset, value);
} else {
// We save the untagged value on the side and store a GC-safe
// temporary placeholder in the frame.
+ ASSERT(value_type == TRANSLATED_VALUE_IS_TAGGED);
AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
static_cast<double>(static_cast<uint32_t>(value)));
output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
@@ -2130,7 +2183,8 @@
ASSERT(static_cast<int>(Deoptimizer::GetMaxDeoptTableSize()) >=
desc.instr_size);
chunk->CommitArea(desc.instr_size);
- CopyBytes(chunk->area_start(), desc.buffer, desc.instr_size);
+ CopyBytes(chunk->area_start(), desc.buffer,
+ static_cast<size_t>(desc.instr_size));
CPU::FlushICache(chunk->area_start(), desc.instr_size);
if (type == EAGER) {
diff --git a/src/deoptimizer.h b/src/deoptimizer.h
index db0cc0b..895ed66 100644
--- a/src/deoptimizer.h
+++ b/src/deoptimizer.h
@@ -356,9 +356,17 @@
bool is_setter_stub_frame);
void DoComputeCompiledStubFrame(TranslationIterator* iterator,
int frame_index);
+
+ enum DeoptimizerTranslatedValueType {
+ TRANSLATED_VALUE_IS_NATIVE,
+ TRANSLATED_VALUE_IS_TAGGED
+ };
+
void DoTranslateCommand(TranslationIterator* iterator,
- int frame_index,
- unsigned output_offset);
+ int frame_index,
+ unsigned output_offset,
+ DeoptimizerTranslatedValueType value_type = TRANSLATED_VALUE_IS_TAGGED);
+
// Translate a command for OSR. Updates the input offset to be used for
// the next command. Returns false if translation of the command failed
// (e.g., a number conversion failed) and may or may not have updated the
diff --git a/src/elements-kind.h b/src/elements-kind.h
index cb3bb9c..da15192 100644
--- a/src/elements-kind.h
+++ b/src/elements-kind.h
@@ -110,10 +110,15 @@
}
+inline bool IsExternalFloatOrDoubleElementsKind(ElementsKind kind) {
+ return kind == EXTERNAL_DOUBLE_ELEMENTS ||
+ kind == EXTERNAL_FLOAT_ELEMENTS;
+}
+
+
inline bool IsDoubleOrFloatElementsKind(ElementsKind kind) {
return IsFastDoubleElementsKind(kind) ||
- kind == EXTERNAL_DOUBLE_ELEMENTS ||
- kind == EXTERNAL_FLOAT_ELEMENTS;
+ IsExternalFloatOrDoubleElementsKind(kind);
}
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 06d114f..ea72168 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -148,6 +148,9 @@
"enable harmony collections (sets, maps, and weak maps)")
DEFINE_bool(harmony_observation, false,
"enable harmony object observation (implies harmony collections")
+DEFINE_bool(harmony_typed_arrays, false,
+ "enable harmony typed arrays")
+DEFINE_bool(harmony_generators, false, "enable harmony generators")
DEFINE_bool(harmony, false, "enable all harmony features (except typeof)")
DEFINE_implication(harmony, harmony_scoping)
DEFINE_implication(harmony, harmony_modules)
@@ -155,8 +158,10 @@
DEFINE_implication(harmony, harmony_proxies)
DEFINE_implication(harmony, harmony_collections)
DEFINE_implication(harmony, harmony_observation)
+DEFINE_implication(harmony, harmony_generators)
DEFINE_implication(harmony_modules, harmony_scoping)
DEFINE_implication(harmony_observation, harmony_collections)
+DEFINE_implication(harmony, harmony_typed_arrays)
// Flags for experimental implementation features.
DEFINE_bool(packed_arrays, true, "optimizes arrays that have no holes")
diff --git a/src/frames.cc b/src/frames.cc
index ed407e7..aaf8c79 100644
--- a/src/frames.cc
+++ b/src/frames.cc
@@ -1311,18 +1311,19 @@
Code* StubFailureTrampolineFrame::unchecked_code() const {
- int i = 0;
- for (; i <= StubFailureTrampolineStub::kMaxExtraExpressionStackCount; ++i) {
- Code* trampoline;
- StubFailureTrampolineStub(i).FindCodeInCache(&trampoline, isolate());
- ASSERT(trampoline != NULL);
- Address current_pc = pc();
- Address code_start = trampoline->instruction_start();
- Address code_end = code_start + trampoline->instruction_size();
- if (code_start <= current_pc && current_pc < code_end) {
- return trampoline;
- }
+ Code* trampoline;
+ StubFailureTrampolineStub(NOT_JS_FUNCTION_STUB_MODE).
+ FindCodeInCache(&trampoline, isolate());
+ if (trampoline->contains(pc())) {
+ return trampoline;
}
+
+ StubFailureTrampolineStub(JS_FUNCTION_STUB_MODE).
+ FindCodeInCache(&trampoline, isolate());
+ if (trampoline->contains(pc())) {
+ return trampoline;
+ }
+
UNREACHABLE();
return NULL;
}
diff --git a/src/full-codegen.cc b/src/full-codegen.cc
index cb6f228..1c6a0b9 100644
--- a/src/full-codegen.cc
+++ b/src/full-codegen.cc
@@ -232,6 +232,12 @@
}
+void BreakableStatementChecker::VisitYield(Yield* expr) {
+ // Yield is breakable if the expression is.
+ Visit(expr->expression());
+}
+
+
void BreakableStatementChecker::VisitThrow(Throw* expr) {
// Throw is breakable if the expression is.
Visit(expr->exception());
@@ -1538,6 +1544,28 @@
}
+void FullCodeGenerator::VisitYield(Yield* expr) {
+ if (expr->is_delegating_yield())
+ UNIMPLEMENTED();
+
+ Comment cmnt(masm_, "[ Yield");
+ VisitForAccumulatorValue(expr->expression());
+ // TODO(wingo): Assert that the operand stack depth is 0, at least while
+ // general yield expressions are unimplemented.
+
+ // TODO(wingo): What follows is as in VisitReturnStatement. Replace it with a
+ // call to a builtin that will resume the generator.
+ NestedStatement* current = nesting_stack_;
+ int stack_depth = 0;
+ int context_length = 0;
+ while (current != NULL) {
+ current = current->Exit(&stack_depth, &context_length);
+ }
+ __ Drop(stack_depth);
+ EmitReturnSequence();
+}
+
+
void FullCodeGenerator::VisitThrow(Throw* expr) {
Comment cmnt(masm_, "[ Throw");
VisitForStackValue(expr->exception());
diff --git a/src/handles-inl.h b/src/handles-inl.h
index fd60a35..b763c86 100644
--- a/src/handles-inl.h
+++ b/src/handles-inl.h
@@ -107,7 +107,7 @@
current->limit = prev_limit_;
DeleteExtensions(isolate_);
}
-#ifdef DEBUG
+#ifdef ENABLE_EXTRA_CHECKS
ZapRange(prev_next_, prev_limit_);
#endif
}
diff --git a/src/handles.cc b/src/handles.cc
index 2958d2c..b24a4cd 100644
--- a/src/handles.cc
+++ b/src/handles.cc
@@ -101,12 +101,14 @@
}
+#ifdef ENABLE_EXTRA_CHECKS
void HandleScope::ZapRange(Object** start, Object** end) {
ASSERT(end - start <= kHandleBlockSize);
for (Object** p = start; p != end; p++) {
*reinterpret_cast<Address*>(p) = v8::internal::kHandleZapValue;
}
}
+#endif
Address HandleScope::current_level_address(Isolate* isolate) {
@@ -259,20 +261,6 @@
}
-Handle<Object> SetPropertyWithInterceptor(Handle<JSObject> object,
- Handle<Name> key,
- Handle<Object> value,
- PropertyAttributes attributes,
- StrictModeFlag strict_mode) {
- CALL_HEAP_FUNCTION(object->GetIsolate(),
- object->SetPropertyWithInterceptor(*key,
- *value,
- attributes,
- strict_mode),
- Object);
-}
-
-
Handle<Object> GetProperty(Handle<JSReceiver> obj,
const char* name) {
Isolate* isolate = obj->GetIsolate();
@@ -289,19 +277,6 @@
}
-Handle<Object> GetPropertyWithInterceptor(Handle<JSObject> receiver,
- Handle<JSObject> holder,
- Handle<Name> name,
- PropertyAttributes* attributes) {
- Isolate* isolate = receiver->GetIsolate();
- CALL_HEAP_FUNCTION(isolate,
- holder->GetPropertyWithInterceptor(*receiver,
- *name,
- attributes),
- Object);
-}
-
-
Handle<Object> SetPrototype(Handle<JSObject> obj, Handle<Object> value) {
const bool skip_hidden_prototypes = false;
CALL_HEAP_FUNCTION(obj->GetIsolate(),
diff --git a/src/handles.h b/src/handles.h
index 3e408b7..c69713e 100644
--- a/src/handles.h
+++ b/src/handles.h
@@ -160,13 +160,14 @@
// Extend the handle scope making room for more handles.
static internal::Object** Extend(Isolate* isolate);
+#ifdef ENABLE_EXTRA_CHECKS
// Zaps the handles in the half-open interval [start, end).
static void ZapRange(internal::Object** start, internal::Object** end);
+#endif
- friend class v8::internal::DeferredHandles;
friend class v8::HandleScope;
+ friend class v8::internal::DeferredHandles;
friend class v8::internal::HandleScopeImplementer;
- friend class v8::ImplementationUtilities;
friend class v8::internal::Isolate;
};
@@ -232,11 +233,6 @@
Handle<Object> obj,
Handle<Object> key);
-Handle<Object> GetPropertyWithInterceptor(Handle<JSObject> receiver,
- Handle<JSObject> holder,
- Handle<String> name,
- PropertyAttributes* attributes);
-
Handle<Object> SetPrototype(Handle<JSObject> obj, Handle<Object> value);
Handle<Object> LookupSingleCharacterStringFromCode(Isolate* isolate,
diff --git a/src/heap-inl.h b/src/heap-inl.h
index 9ed65d8..a15b8ef 100644
--- a/src/heap-inl.h
+++ b/src/heap-inl.h
@@ -399,7 +399,9 @@
ASSERT(type != ODDBALL_TYPE);
ASSERT(type != JS_GLOBAL_PROPERTY_CELL_TYPE);
- if (type < FIRST_NONSTRING_TYPE) {
+ if (type <= LAST_NAME_TYPE) {
+ if (type == SYMBOL_TYPE) return OLD_POINTER_SPACE;
+ ASSERT(type < FIRST_NONSTRING_TYPE);
// There are four string representations: sequential strings, external
// strings, cons strings, and sliced strings.
// Only the latter two contain non-map-word pointers to heap objects.
diff --git a/src/heap-profiler.cc b/src/heap-profiler.cc
index c9f1d50..5c1badf 100644
--- a/src/heap-profiler.cc
+++ b/src/heap-profiler.cc
@@ -44,72 +44,13 @@
}
-void HeapProfiler::ResetSnapshots() {
+void HeapProfiler::DeleteAllSnapshots() {
Heap* the_heap = heap();
delete snapshots_;
snapshots_ = new HeapSnapshotsCollection(the_heap);
}
-void HeapProfiler::SetUp() {
- Isolate* isolate = Isolate::Current();
- if (isolate->heap_profiler() == NULL) {
- isolate->set_heap_profiler(new HeapProfiler(isolate->heap()));
- }
-}
-
-
-void HeapProfiler::TearDown() {
- Isolate* isolate = Isolate::Current();
- delete isolate->heap_profiler();
- isolate->set_heap_profiler(NULL);
-}
-
-
-HeapSnapshot* HeapProfiler::TakeSnapshot(
- const char* name,
- int type,
- v8::ActivityControl* control,
- v8::HeapProfiler::ObjectNameResolver* resolver) {
- ASSERT(Isolate::Current()->heap_profiler() != NULL);
- return Isolate::Current()->heap_profiler()->TakeSnapshotImpl(name,
- type,
- control,
- resolver);
-}
-
-
-HeapSnapshot* HeapProfiler::TakeSnapshot(
- String* name,
- int type,
- v8::ActivityControl* control,
- v8::HeapProfiler::ObjectNameResolver* resolver) {
- ASSERT(Isolate::Current()->heap_profiler() != NULL);
- return Isolate::Current()->heap_profiler()->TakeSnapshotImpl(name,
- type,
- control,
- resolver);
-}
-
-
-void HeapProfiler::StartHeapObjectsTracking() {
- ASSERT(Isolate::Current()->heap_profiler() != NULL);
- Isolate::Current()->heap_profiler()->StartHeapObjectsTrackingImpl();
-}
-
-
-void HeapProfiler::StopHeapObjectsTracking() {
- ASSERT(Isolate::Current()->heap_profiler() != NULL);
- Isolate::Current()->heap_profiler()->StopHeapObjectsTrackingImpl();
-}
-
-
-SnapshotObjectId HeapProfiler::PushHeapObjectsStats(v8::OutputStream* stream) {
- ASSERT(Isolate::Current()->heap_profiler() != NULL);
- return Isolate::Current()->heap_profiler()->PushHeapObjectsStatsImpl(stream);
-}
-
-
void HeapProfiler::DefineWrapperClass(
uint16_t class_id, v8::HeapProfiler::WrapperInfoCallback callback) {
ASSERT(class_id != v8::HeapProfiler::kPersistentHandleNoClassId);
@@ -129,99 +70,69 @@
}
-HeapSnapshot* HeapProfiler::TakeSnapshotImpl(
+HeapSnapshot* HeapProfiler::TakeSnapshot(
const char* name,
- int type,
v8::ActivityControl* control,
v8::HeapProfiler::ObjectNameResolver* resolver) {
- HeapSnapshot::Type s_type = static_cast<HeapSnapshot::Type>(type);
- HeapSnapshot* result =
- snapshots_->NewSnapshot(s_type, name, next_snapshot_uid_++);
- bool generation_completed = true;
- switch (s_type) {
- case HeapSnapshot::kFull: {
- HeapSnapshotGenerator generator(result, control, resolver, heap());
- generation_completed = generator.GenerateSnapshot();
- break;
+ HeapSnapshot* result = snapshots_->NewSnapshot(name, next_snapshot_uid_++);
+ {
+ HeapSnapshotGenerator generator(result, control, resolver, heap());
+ if (!generator.GenerateSnapshot()) {
+ delete result;
+ result = NULL;
}
- default:
- UNREACHABLE();
- }
- if (!generation_completed) {
- delete result;
- result = NULL;
}
snapshots_->SnapshotGenerationFinished(result);
return result;
}
-HeapSnapshot* HeapProfiler::TakeSnapshotImpl(
+HeapSnapshot* HeapProfiler::TakeSnapshot(
String* name,
- int type,
v8::ActivityControl* control,
v8::HeapProfiler::ObjectNameResolver* resolver) {
- return TakeSnapshotImpl(snapshots_->names()->GetName(name), type, control,
- resolver);
+ return TakeSnapshot(snapshots_->names()->GetName(name), control, resolver);
}
-void HeapProfiler::StartHeapObjectsTrackingImpl() {
+void HeapProfiler::StartHeapObjectsTracking() {
snapshots_->StartHeapObjectsTracking();
}
-SnapshotObjectId HeapProfiler::PushHeapObjectsStatsImpl(OutputStream* stream) {
+SnapshotObjectId HeapProfiler::PushHeapObjectsStats(OutputStream* stream) {
return snapshots_->PushHeapObjectsStats(stream);
}
-void HeapProfiler::StopHeapObjectsTrackingImpl() {
+void HeapProfiler::StopHeapObjectsTracking() {
snapshots_->StopHeapObjectsTracking();
}
size_t HeapProfiler::GetMemorySizeUsedByProfiler() {
- HeapProfiler* profiler = Isolate::Current()->heap_profiler();
- ASSERT(profiler != NULL);
- size_t size = profiler->snapshots_->GetUsedMemorySize();
- return size;
+ return snapshots_->GetUsedMemorySize();
}
int HeapProfiler::GetSnapshotsCount() {
- HeapProfiler* profiler = Isolate::Current()->heap_profiler();
- ASSERT(profiler != NULL);
- return profiler->snapshots_->snapshots()->length();
+ return snapshots_->snapshots()->length();
}
HeapSnapshot* HeapProfiler::GetSnapshot(int index) {
- HeapProfiler* profiler = Isolate::Current()->heap_profiler();
- ASSERT(profiler != NULL);
- return profiler->snapshots_->snapshots()->at(index);
+ return snapshots_->snapshots()->at(index);
}
HeapSnapshot* HeapProfiler::FindSnapshot(unsigned uid) {
- HeapProfiler* profiler = Isolate::Current()->heap_profiler();
- ASSERT(profiler != NULL);
- return profiler->snapshots_->GetSnapshot(uid);
+ return snapshots_->GetSnapshot(uid);
}
SnapshotObjectId HeapProfiler::GetSnapshotObjectId(Handle<Object> obj) {
if (!obj->IsHeapObject())
return v8::HeapProfiler::kUnknownObjectId;
- HeapProfiler* profiler = Isolate::Current()->heap_profiler();
- ASSERT(profiler != NULL);
- return profiler->snapshots_->FindObjectId(HeapObject::cast(*obj)->address());
-}
-
-
-void HeapProfiler::DeleteAllSnapshots() {
- HeapProfiler* profiler = Isolate::Current()->heap_profiler();
- ASSERT(profiler != NULL);
- profiler->ResetSnapshots();
+ return snapshots_->FindObjectId(HeapObject::cast(*obj)->address());
}
diff --git a/src/heap-profiler.h b/src/heap-profiler.h
index c8c94f5..3f3138d 100644
--- a/src/heap-profiler.h
+++ b/src/heap-profiler.h
@@ -46,30 +46,28 @@
class HeapProfiler {
public:
- static void SetUp();
- static void TearDown();
+ explicit HeapProfiler(Heap* heap);
+ ~HeapProfiler();
- static size_t GetMemorySizeUsedByProfiler();
+ size_t GetMemorySizeUsedByProfiler();
- static HeapSnapshot* TakeSnapshot(
+ HeapSnapshot* TakeSnapshot(
const char* name,
- int type,
v8::ActivityControl* control,
v8::HeapProfiler::ObjectNameResolver* resolver);
- static HeapSnapshot* TakeSnapshot(
+ HeapSnapshot* TakeSnapshot(
String* name,
- int type,
v8::ActivityControl* control,
v8::HeapProfiler::ObjectNameResolver* resolver);
- static void StartHeapObjectsTracking();
- static void StopHeapObjectsTracking();
- static SnapshotObjectId PushHeapObjectsStats(OutputStream* stream);
- static int GetSnapshotsCount();
- static HeapSnapshot* GetSnapshot(int index);
- static HeapSnapshot* FindSnapshot(unsigned uid);
- static SnapshotObjectId GetSnapshotObjectId(Handle<Object> obj);
- static void DeleteAllSnapshots();
+ void StartHeapObjectsTracking();
+ void StopHeapObjectsTracking();
+ SnapshotObjectId PushHeapObjectsStats(OutputStream* stream);
+ int GetSnapshotsCount();
+ HeapSnapshot* GetSnapshot(int index);
+ HeapSnapshot* FindSnapshot(unsigned uid);
+ SnapshotObjectId GetSnapshotObjectId(Handle<Object> obj);
+ void DeleteAllSnapshots();
void ObjectMoveEvent(Address from, Address to);
@@ -83,24 +81,6 @@
}
private:
- explicit HeapProfiler(Heap* heap);
- ~HeapProfiler();
- HeapSnapshot* TakeSnapshotImpl(
- const char* name,
- int type,
- v8::ActivityControl* control,
- v8::HeapProfiler::ObjectNameResolver* resolver);
- HeapSnapshot* TakeSnapshotImpl(
- String* name,
- int type,
- v8::ActivityControl* control,
- v8::HeapProfiler::ObjectNameResolver* resolver);
- void ResetSnapshots();
-
- void StartHeapObjectsTrackingImpl();
- void StopHeapObjectsTrackingImpl();
- SnapshotObjectId PushHeapObjectsStatsImpl(OutputStream* stream);
-
Heap* heap() const { return snapshots_->heap(); }
HeapSnapshotsCollection* snapshots_;
diff --git a/src/heap-snapshot-generator.cc b/src/heap-snapshot-generator.cc
index 824e507..fb239aa 100644
--- a/src/heap-snapshot-generator.cc
+++ b/src/heap-snapshot-generator.cc
@@ -189,7 +189,7 @@
static const int kExpectedHeapGraphEdgeSize = 12;
static const int kExpectedHeapEntrySize = 24;
static const int kExpectedHeapSnapshotsCollectionSize = 100;
- static const int kExpectedHeapSnapshotSize = 136;
+ static const int kExpectedHeapSnapshotSize = 132;
static const size_t kMaxSerializableSnapshotRawSize = 256 * MB;
};
@@ -197,7 +197,7 @@
static const int kExpectedHeapGraphEdgeSize = 24;
static const int kExpectedHeapEntrySize = 32;
static const int kExpectedHeapSnapshotsCollectionSize = 152;
- static const int kExpectedHeapSnapshotSize = 168;
+ static const int kExpectedHeapSnapshotSize = 160;
static const uint64_t kMaxSerializableSnapshotRawSize =
static_cast<uint64_t>(6000) * MB;
};
@@ -205,11 +205,9 @@
} // namespace
HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection,
- HeapSnapshot::Type type,
const char* title,
unsigned uid)
: collection_(collection),
- type_(type),
title_(title),
uid_(uid),
root_index_(HeapEntry::kNoEntry),
@@ -599,11 +597,10 @@
}
-HeapSnapshot* HeapSnapshotsCollection::NewSnapshot(HeapSnapshot::Type type,
- const char* name,
+HeapSnapshot* HeapSnapshotsCollection::NewSnapshot(const char* name,
unsigned uid) {
is_tracking_objects_ = true; // Start watching for heap objects moves.
- return new HeapSnapshot(this, type, name, uid);
+ return new HeapSnapshot(this, name, uid);
}
@@ -2410,7 +2407,6 @@
HeapSnapshot* HeapSnapshotJSONSerializer::CreateFakeSnapshot() {
HeapSnapshot* result = new HeapSnapshot(snapshot_->collection(),
- HeapSnapshot::kFull,
snapshot_->title(),
snapshot_->uid());
result->AddRootEntry();
diff --git a/src/heap-snapshot-generator.h b/src/heap-snapshot-generator.h
index 08c2fe7..a4fcef7 100644
--- a/src/heap-snapshot-generator.h
+++ b/src/heap-snapshot-generator.h
@@ -157,18 +157,12 @@
// HeapSnapshotGenerator fills in a HeapSnapshot.
class HeapSnapshot {
public:
- enum Type {
- kFull = v8::HeapSnapshot::kFull
- };
-
HeapSnapshot(HeapSnapshotsCollection* collection,
- Type type,
const char* title,
unsigned uid);
void Delete();
HeapSnapshotsCollection* collection() { return collection_; }
- Type type() { return type_; }
const char* title() { return title_; }
unsigned uid() { return uid_; }
size_t RawSnapshotSize() const;
@@ -203,7 +197,6 @@
private:
HeapSnapshotsCollection* collection_;
- Type type_;
const char* title_;
unsigned uid_;
int root_index_;
@@ -305,8 +298,7 @@
void StartHeapObjectsTracking() { is_tracking_objects_ = true; }
void StopHeapObjectsTracking() { ids_.StopHeapObjectsTracking(); }
- HeapSnapshot* NewSnapshot(
- HeapSnapshot::Type type, const char* name, unsigned uid);
+ HeapSnapshot* NewSnapshot(const char* name, unsigned uid);
void SnapshotGenerationFinished(HeapSnapshot* snapshot);
List<HeapSnapshot*>* snapshots() { return &snapshots_; }
HeapSnapshot* GetSnapshot(unsigned uid);
diff --git a/src/heap.cc b/src/heap.cc
index 949661d..fafcb64 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -1779,6 +1779,10 @@
&ObjectEvacuationStrategy<POINTER_OBJECT>::
template VisitSpecialized<SlicedString::kSize>);
+ table_.Register(kVisitSymbol,
+ &ObjectEvacuationStrategy<POINTER_OBJECT>::
+ template VisitSpecialized<Symbol::kSize>);
+
table_.Register(kVisitSharedFunctionInfo,
&ObjectEvacuationStrategy<POINTER_OBJECT>::
template VisitSpecialized<SharedFunctionInfo::kSize>);
@@ -1854,7 +1858,7 @@
HEAP_PROFILE(heap, ObjectMoveEvent(source->address(), target->address()));
Isolate* isolate = heap->isolate();
if (isolate->logger()->is_logging_code_events() ||
- CpuProfiler::is_profiling(isolate)) {
+ isolate->cpu_profiler()->is_profiling()) {
if (target->IsSharedFunctionInfo()) {
PROFILE(isolate, SharedFunctionInfoMoveEvent(
source->address(), target->address()));
@@ -2110,7 +2114,7 @@
void Heap::SelectScavengingVisitorsTable() {
bool logging_and_profiling =
isolate()->logger()->is_logging() ||
- CpuProfiler::is_profiling(isolate()) ||
+ isolate()->cpu_profiler()->is_profiling() ||
(isolate()->heap_profiler() != NULL &&
isolate()->heap_profiler()->is_profiling());
@@ -3880,7 +3884,7 @@
Address new_addr = reinterpret_cast<HeapObject*>(result)->address();
// Copy header and instructions.
- CopyBytes(new_addr, old_addr, static_cast<int>(relocation_offset));
+ CopyBytes(new_addr, old_addr, relocation_offset);
Code* new_code = Code::cast(result);
new_code->set_relocation_info(ByteArray::cast(reloc_info_array));
@@ -3888,7 +3892,7 @@
// Copy patched rinfo.
CopyBytes(new_code->relocation_start(),
reloc_info.start(),
- reloc_info.length());
+ static_cast<size_t>(reloc_info.length()));
// Relocate the copy.
ASSERT(!isolate_->code_range()->exists() ||
@@ -5424,13 +5428,13 @@
}
-MaybeObject* Heap::AllocateSymbol(PretenureFlag pretenure) {
+MaybeObject* Heap::AllocateSymbol() {
// Statically ensure that it is safe to allocate symbols in paged spaces.
STATIC_ASSERT(Symbol::kSize <= Page::kNonCodeObjectAreaSize);
- AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
Object* result;
- MaybeObject* maybe = AllocateRaw(Symbol::kSize, space, OLD_DATA_SPACE);
+ MaybeObject* maybe =
+ AllocateRaw(Symbol::kSize, OLD_POINTER_SPACE, OLD_POINTER_SPACE);
if (!maybe->ToObject(&result)) return maybe;
HeapObject::cast(result)->set_map_no_write_barrier(symbol_map());
@@ -5446,6 +5450,7 @@
Symbol::cast(result)->set_hash_field(
Name::kIsNotArrayIndexMask | (hash << Name::kHashShift));
+ Symbol::cast(result)->set_name(undefined_value());
ASSERT(result->IsSymbol());
return result;
@@ -7465,6 +7470,9 @@
}
name = internalized_string;
}
+ // This cache is cleared only between mark compact passes, so we expect the
+ // cache to only contain old space names.
+ ASSERT(!HEAP->InNewSpace(name));
int index = (Hash(map, name) & kHashMask);
// After a GC there will be free slots, so we use them in order (this may
diff --git a/src/heap.h b/src/heap.h
index 90f2e60..8992e31 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -213,6 +213,8 @@
V(prototype_string, "prototype") \
V(string_string, "string") \
V(String_string, "String") \
+ V(symbol_string, "symbol") \
+ V(Symbol_string, "Symbol") \
V(Date_string, "Date") \
V(this_string, "this") \
V(to_string_string, "toString") \
@@ -220,6 +222,7 @@
V(undefined_string, "undefined") \
V(value_of_string, "valueOf") \
V(stack_string, "stack") \
+ V(toJSON_string, "toJSON") \
V(InitializeVarGlobal_string, "InitializeVarGlobal") \
V(InitializeConstGlobal_string, "InitializeConstGlobal") \
V(KeyedLoadElementMonomorphic_string, \
@@ -879,12 +882,11 @@
void* external_pointer,
PretenureFlag pretenure);
- // Allocate a symbol.
+ // Allocate a symbol in old space.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
- MUST_USE_RESULT MaybeObject* AllocateSymbol(
- PretenureFlag pretenure = NOT_TENURED);
+ MUST_USE_RESULT MaybeObject* AllocateSymbol();
// Allocate a tenured JS global property cell.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index fc80748..edbffc2 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -1277,7 +1277,8 @@
ToBooleanStub::UNDEFINED |
ToBooleanStub::NULL_TYPE |
ToBooleanStub::SPEC_OBJECT |
- ToBooleanStub::STRING);
+ ToBooleanStub::STRING |
+ ToBooleanStub::SYMBOL);
if (expected_input_types_.ContainsAnyOf(tagged_types)) {
return Representation::Tagged();
} else if (expected_input_types_.Contains(ToBooleanStub::HEAP_NUMBER)) {
@@ -1467,15 +1468,6 @@
}
-void HJSArrayLength::PrintDataTo(StringStream* stream) {
- value()->PrintNameTo(stream);
- if (HasTypeCheck()) {
- stream->Add(" ");
- typecheck()->PrintNameTo(stream);
- }
-}
-
-
HValue* HUnaryMathOperation::Canonicalize() {
if (op() == kMathFloor) {
// If the input is integer32 then we replace the floor instruction
@@ -2415,6 +2407,10 @@
void HLoadNamedField::PrintDataTo(StringStream* stream) {
object()->PrintNameTo(stream);
stream->Add(" @%d%s", offset(), is_in_object() ? "[in-object]" : "");
+ if (HasTypeCheck()) {
+ stream->Add(" ");
+ typecheck()->PrintNameTo(stream);
+ }
}
@@ -2589,6 +2585,10 @@
return false;
}
+ if (IsExternalArrayElementsKind(elements_kind())) {
+ return false;
+ }
+
if (hole_mode() == ALLOW_RETURN_HOLE) return true;
if (IsFastDoubleElementsKind(elements_kind())) {
@@ -2611,6 +2611,10 @@
return false;
}
+ if (IsExternalArrayElementsKind(elements_kind())) {
+ return false;
+ }
+
return !UsesMustHandleHole();
}
@@ -3036,10 +3040,19 @@
// If value is an integer or smi or comes from the result of a keyed load or
// constant then it is either be a non-hole value or in the case of a constant
// the hole is only being stored explicitly: no need for canonicalization.
- if (value()->IsLoadKeyed() || value()->IsConstant()) {
+ //
+ // The exception to that is keyed loads from external float or double arrays:
+ // these can load arbitrary representation of NaN.
+
+ if (value()->IsConstant()) {
return false;
}
+ if (value()->IsLoadKeyed()) {
+ return IsExternalFloatOrDoubleElementsKind(
+ HLoadKeyed::cast(value())->elements_kind());
+ }
+
if (value()->IsChange()) {
if (HChange::cast(value())->from().IsInteger32()) {
return false;
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index f741f29..ad03687 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -134,7 +134,6 @@
V(IsStringAndBranch) \
V(IsSmiAndBranch) \
V(IsUndetectableAndBranch) \
- V(JSArrayLength) \
V(LeaveInlined) \
V(LoadContextSlot) \
V(LoadElements) \
@@ -2392,45 +2391,6 @@
};
-class HJSArrayLength: public HTemplateInstruction<2> {
- public:
- HJSArrayLength(HValue* value, HValue* typecheck,
- HType type = HType::Tagged()) {
- set_type(type);
- // The length of an array is stored as a tagged value in the array
- // object. It is guaranteed to be 32 bit integer, but it can be
- // represented as either a smi or heap number.
- SetOperandAt(0, value);
- SetOperandAt(1, typecheck != NULL ? typecheck : value);
- set_representation(Representation::Tagged());
- SetFlag(kUseGVN);
- SetGVNFlag(kDependsOnArrayLengths);
- SetGVNFlag(kDependsOnMaps);
- }
-
- virtual Representation RequiredInputRepresentation(int index) {
- return Representation::Tagged();
- }
-
- virtual void PrintDataTo(StringStream* stream);
-
- HValue* value() { return OperandAt(0); }
- HValue* typecheck() {
- ASSERT(HasTypeCheck());
- return OperandAt(1);
- }
- bool HasTypeCheck() const { return OperandAt(0) != OperandAt(1); }
-
- DECLARE_CONCRETE_INSTRUCTION(JSArrayLength)
-
- protected:
- virtual bool DataEquals(HValue* other_raw) { return true; }
-
- private:
- virtual bool IsDeletable() const { return true; }
-};
-
-
class HFixedArrayBaseLength: public HUnaryOperation {
public:
explicit HFixedArrayBaseLength(HValue* value) : HUnaryOperation(value) {
@@ -4693,6 +4653,14 @@
set_representation(Representation::Tagged());
}
+ explicit HParameter(unsigned index,
+ ParameterKind kind,
+ Representation r)
+ : index_(index),
+ kind_(kind) {
+ set_representation(r);
+ }
+
unsigned index() const { return index_; }
ParameterKind kind() const { return kind_; }
@@ -5184,12 +5152,16 @@
};
-class HLoadNamedField: public HUnaryOperation {
+class HLoadNamedField: public HTemplateInstruction<2> {
public:
- HLoadNamedField(HValue* object, bool is_in_object, int offset)
- : HUnaryOperation(object),
- is_in_object_(is_in_object),
+ HLoadNamedField(HValue* object, bool is_in_object, int offset,
+ HValue* typecheck = NULL)
+ : is_in_object_(is_in_object),
offset_(offset) {
+ ASSERT(object != NULL);
+ SetOperandAt(0, object);
+ SetOperandAt(1, typecheck != NULL ? typecheck : object);
+
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
SetGVNFlag(kDependsOnMaps);
@@ -5200,7 +5172,24 @@
}
}
+ static HLoadNamedField* NewArrayLength(Zone* zone, HValue* object,
+ HValue* typecheck,
+ HType type = HType::Tagged()) {
+ HLoadNamedField* result = new(zone) HLoadNamedField(
+ object, true, JSArray::kLengthOffset, typecheck);
+ result->set_type(type);
+ result->SetGVNFlag(kDependsOnArrayLengths);
+ result->ClearGVNFlag(kDependsOnInobjectFields);
+ return result;
+ }
+
HValue* object() { return OperandAt(0); }
+ HValue* typecheck() {
+ ASSERT(HasTypeCheck());
+ return OperandAt(1);
+ }
+
+ bool HasTypeCheck() const { return OperandAt(0) != OperandAt(1); }
bool is_in_object() const { return is_in_object_; }
int offset() const { return offset_; }
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 8dbb5dd..abff7b7 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -1165,8 +1165,8 @@
}
HInstruction* length = NULL;
if (is_js_array) {
- length = AddInstruction(new(zone) HJSArrayLength(object, mapcheck,
- HType::Smi()));
+ length = AddInstruction(
+ HLoadNamedField::NewArrayLength(zone, object, mapcheck, HType::Smi()));
} else {
length = AddInstruction(new(zone) HFixedArrayBaseLength(elements));
}
@@ -4115,6 +4115,10 @@
bool HOptimizedGraphBuilder::BuildGraph() {
+ if (info()->function()->is_generator()) {
+ Bailout("function is a generator");
+ return false;
+ }
Scope* scope = info()->scope();
if (scope->HasIllegalRedeclaration()) {
Bailout("function with illegal redeclaration");
@@ -5083,19 +5087,7 @@
typecheck->SetSuccessorAt(1, not_spec_object);
current_block()->Finish(typecheck);
if_spec_object->AddLeaveInlined(return_value, state);
- if (!FLAG_harmony_symbols) {
- not_spec_object->AddLeaveInlined(receiver, state);
- } else {
- HHasInstanceTypeAndBranch* symbolcheck =
- new(zone()) HHasInstanceTypeAndBranch(return_value, SYMBOL_TYPE);
- HBasicBlock* is_symbol = graph()->CreateBasicBlock();
- HBasicBlock* not_symbol = graph()->CreateBasicBlock();
- symbolcheck->SetSuccessorAt(0, is_symbol);
- symbolcheck->SetSuccessorAt(1, not_symbol);
- not_spec_object->Finish(symbolcheck);
- is_symbol->AddLeaveInlined(return_value, state);
- not_symbol->AddLeaveInlined(receiver, state);
- }
+ not_spec_object->AddLeaveInlined(receiver, state);
}
} else if (state->inlining_kind() == SETTER_CALL_RETURN) {
// Return from an inlined setter call. The returned value is never used, the
@@ -6299,6 +6291,12 @@
}
+void HOptimizedGraphBuilder::AddCheckMap(HValue* object, Handle<Map> map) {
+ AddInstruction(new(zone()) HCheckNonSmi(object));
+ AddInstruction(new(zone()) HCheckMaps(object, map, zone()));
+}
+
+
void HOptimizedGraphBuilder::AddCheckMapsWithTransitions(HValue* object,
Handle<Map> map) {
AddInstruction(new(zone()) HCheckNonSmi(object));
@@ -6410,15 +6408,40 @@
}
-void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(
+bool HOptimizedGraphBuilder::HandlePolymorphicArrayLengthLoad(
Property* expr,
HValue* object,
SmallMapList* types,
Handle<String> name) {
+ if (!name->Equals(isolate()->heap()->length_string())) return false;
+
+ for (int i = 0; i < types->length(); i++) {
+ if (types->at(i)->instance_type() != JS_ARRAY_TYPE) return false;
+ }
+
+ AddInstruction(new(zone()) HCheckNonSmi(object));
+ HInstruction* typecheck =
+ AddInstruction(HCheckInstanceType::NewIsJSArray(object, zone()));
+ HInstruction* instr =
+ HLoadNamedField::NewArrayLength(zone(), object, typecheck);
+ instr->set_position(expr->position());
+ ast_context()->ReturnInstruction(instr, expr->id());
+ return true;
+}
+
+
+void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr,
+ HValue* object,
+ SmallMapList* types,
+ Handle<String> name) {
int count = 0;
int previous_field_offset = 0;
bool previous_field_is_in_object = false;
bool is_monomorphic_field = true;
+
+ if (HandlePolymorphicArrayLengthLoad(expr, object, types, name))
+ return;
+
Handle<Map> map;
LookupResult lookup(isolate());
for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) {
@@ -6985,6 +7008,12 @@
}
+void HOptimizedGraphBuilder::VisitYield(Yield* expr) {
+ // Generators are not optimized, so we should never get here.
+ UNREACHABLE();
+}
+
+
void HOptimizedGraphBuilder::VisitThrow(Throw* expr) {
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
@@ -7054,16 +7083,25 @@
Handle<Map> map) {
// Handle a load from a known field.
ASSERT(!map->is_dictionary_map());
+
+ // Handle access to various length properties
+ if (name->Equals(isolate()->heap()->length_string())) {
+ if (map->instance_type() == JS_ARRAY_TYPE) {
+ AddCheckMapsWithTransitions(object, map);
+ return HLoadNamedField::NewArrayLength(zone(), object, object);
+ }
+ }
+
LookupResult lookup(isolate());
map->LookupDescriptor(NULL, *name, &lookup);
if (lookup.IsField()) {
- AddCheckMapsWithTransitions(object, map);
+ AddCheckMap(object, map);
return BuildLoadNamedField(object, map, &lookup);
}
// Handle a load of a constant known function.
if (lookup.IsConstantFunction()) {
- AddCheckMapsWithTransitions(object, map);
+ AddCheckMap(object, map);
Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*map));
return new(zone()) HConstant(function, Representation::Tagged());
}
@@ -7074,7 +7112,7 @@
Handle<JSObject> prototype(JSObject::cast(map->prototype()));
Handle<JSObject> holder(lookup.holder());
Handle<Map> holder_map(holder->map());
- AddCheckMapsWithTransitions(object, map);
+ AddCheckMap(object, map);
HInstruction* holder_value = AddInstruction(
new(zone()) HCheckPrototypeMaps(prototype, holder, zone()));
return BuildLoadNamedField(holder_value, holder_map, &lookup);
@@ -7085,7 +7123,7 @@
Handle<JSObject> prototype(JSObject::cast(map->prototype()));
Handle<JSObject> holder(lookup.holder());
Handle<Map> holder_map(holder->map());
- AddCheckMapsWithTransitions(object, map);
+ AddCheckMap(object, map);
AddInstruction(new(zone()) HCheckPrototypeMaps(prototype, holder, zone()));
Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*holder_map));
return new(zone()) HConstant(function, Representation::Tagged());
@@ -7343,8 +7381,9 @@
set_current_block(if_jsarray);
HInstruction* length;
- length = AddInstruction(new(zone()) HJSArrayLength(object, typecheck,
- HType::Smi()));
+ length = AddInstruction(
+ HLoadNamedField::NewArrayLength(zone(), object, typecheck,
+ HType::Smi()));
checked_key = AddBoundsCheck(key, length, ALLOW_SMI_KEY);
access = AddInstruction(BuildFastElementAccess(
elements, checked_key, val, elements_kind_branch,
@@ -7545,13 +7584,7 @@
CHECK_ALIVE(VisitForValue(expr->obj()));
HInstruction* instr = NULL;
- if (expr->AsProperty()->IsArrayLength()) {
- HValue* array = Pop();
- AddInstruction(new(zone()) HCheckNonSmi(array));
- HInstruction* mapcheck =
- AddInstruction(HCheckInstanceType::NewIsJSArray(array, zone()));
- instr = new(zone()) HJSArrayLength(array, mapcheck);
- } else if (expr->IsStringLength()) {
+ if (expr->IsStringLength()) {
HValue* string = Pop();
AddInstruction(new(zone()) HCheckNonSmi(string));
AddInstruction(HCheckInstanceType::NewIsString(string, zone()));
@@ -10080,16 +10113,6 @@
}
-void HOptimizedGraphBuilder::GenerateIsSymbol(CallRuntime* call) {
- ASSERT(call->arguments()->length() == 1);
- CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
- HValue* value = Pop();
- HHasInstanceTypeAndBranch* result =
- new(zone()) HHasInstanceTypeAndBranch(value, SYMBOL_TYPE);
- return ast_context()->ReturnControl(result, call->id());
-}
-
-
void HOptimizedGraphBuilder::GenerateIsFunction(CallRuntime* call) {
ASSERT(call->arguments()->length() == 1);
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
diff --git a/src/hydrogen.h b/src/hydrogen.h
index 6dea1a6..ef3679e 100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -1351,6 +1351,10 @@
HValue* object,
SmallMapList* types,
Handle<String> name);
+ bool HandlePolymorphicArrayLengthLoad(Property* expr,
+ HValue* object,
+ SmallMapList* types,
+ Handle<String> name);
void HandlePolymorphicStoreNamedField(Assignment* expr,
HValue* object,
HValue* value,
@@ -1425,6 +1429,8 @@
Property* expr,
Handle<Map> map);
+ void AddCheckMap(HValue* object, Handle<Map> map);
+
void AddCheckMapsWithTransitions(HValue* object,
Handle<Map> map);
diff --git a/src/ia32/builtins-ia32.cc b/src/ia32/builtins-ia32.cc
index afb1c03..e861db3 100644
--- a/src/ia32/builtins-ia32.cc
+++ b/src/ia32/builtins-ia32.cc
@@ -216,8 +216,7 @@
// eax: initial map
__ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset));
__ shl(edi, kPointerSizeLog2);
- __ AllocateInNewSpace(
- edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS);
+ __ Allocate(edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS);
// Allocated the JSObject, now initialize the fields.
// eax: initial map
// ebx: JSObject
@@ -280,15 +279,15 @@
// ebx: JSObject
// edi: start of next object (will be start of FixedArray)
// edx: number of elements in properties array
- __ AllocateInNewSpace(FixedArray::kHeaderSize,
- times_pointer_size,
- edx,
- REGISTER_VALUE_IS_INT32,
- edi,
- ecx,
- no_reg,
- &undo_allocation,
- RESULT_CONTAINS_TOP);
+ __ Allocate(FixedArray::kHeaderSize,
+ times_pointer_size,
+ edx,
+ REGISTER_VALUE_IS_INT32,
+ edi,
+ ecx,
+ no_reg,
+ &undo_allocation,
+ RESULT_CONTAINS_TOP);
// Initialize the FixedArray.
// ebx: JSObject
@@ -409,10 +408,6 @@
__ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
__ j(above_equal, &exit);
- // Symbols are "objects".
- __ CmpInstanceType(ecx, SYMBOL_TYPE);
- __ j(equal, &exit);
-
// Throw away the result of the constructor invocation and use the
// on-stack receiver as the result.
__ bind(&use_receiver);
@@ -1129,15 +1124,15 @@
// Allocate the JSArray object together with space for a FixedArray with the
// requested elements.
STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
- __ AllocateInNewSpace(JSArray::kSize + FixedArray::kHeaderSize,
- times_pointer_size,
- array_size,
- REGISTER_VALUE_IS_SMI,
- result,
- elements_array_end,
- scratch,
- gc_required,
- TAG_OBJECT);
+ __ Allocate(JSArray::kSize + FixedArray::kHeaderSize,
+ times_pointer_size,
+ array_size,
+ REGISTER_VALUE_IS_SMI,
+ result,
+ elements_array_end,
+ scratch,
+ gc_required,
+ TAG_OBJECT);
// Allocated the JSArray. Now initialize the fields except for the elements
// array.
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index b30d519..9b77c50 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -100,7 +100,7 @@
// stack param count needs (constructor pointer, and single argument)
descriptor->stack_parameter_count_ = &eax;
descriptor->register_params_ = registers;
- descriptor->extra_expression_stack_count_ = 1;
+ descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
descriptor->deoptimization_handler_ =
FUNCTION_ADDR(ArrayConstructor_StubFailure);
}
@@ -632,6 +632,14 @@
__ bind(¬_string);
}
+ if (types_.Contains(SYMBOL)) {
+ // Symbol value -> true.
+ Label not_symbol;
+ __ CmpInstanceType(map, SYMBOL_TYPE);
+ __ j(not_equal, ¬_symbol, Label::kNear);
+ __ bind(¬_symbol);
+ }
+
if (types_.Contains(HEAP_NUMBER)) {
// heap number -> false iff +0, -0, or NaN.
Label not_heap_number, false_result;
@@ -3296,25 +3304,6 @@
}
-void ArrayLengthStub::Generate(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- ecx : name
- // -- edx : receiver
- // -- esp[0] : return address
- // -----------------------------------
- Label miss;
-
- if (kind() == Code::KEYED_LOAD_IC) {
- __ cmp(ecx, Immediate(masm->isolate()->factory()->length_string()));
- __ j(not_equal, &miss);
- }
-
- StubCompiler::GenerateLoadArrayLength(masm, edx, eax, &miss);
- __ bind(&miss);
- StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind()));
-}
-
-
void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- ecx : name
@@ -3569,7 +3558,7 @@
__ add(ebx, Immediate(Heap::kArgumentsObjectSize));
// Do the allocation of all three objects in one go.
- __ AllocateInNewSpace(ebx, eax, edx, edi, &runtime, TAG_OBJECT);
+ __ Allocate(ebx, eax, edx, edi, &runtime, TAG_OBJECT);
// eax = address of new object(s) (tagged)
// ecx = argument count (tagged)
@@ -3767,7 +3756,7 @@
__ add(ecx, Immediate(Heap::kArgumentsObjectSizeStrict));
// Do the allocation of both objects in one go.
- __ AllocateInNewSpace(ecx, eax, edx, ebx, &runtime, TAG_OBJECT);
+ __ Allocate(ecx, eax, edx, ebx, &runtime, TAG_OBJECT);
// Get the arguments boilerplate from the current native context.
__ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
@@ -4291,15 +4280,15 @@
// Allocate RegExpResult followed by FixedArray with size in ebx.
// JSArray: [Map][empty properties][Elements][Length-smi][index][input]
// Elements: [Map][Length][..elements..]
- __ AllocateInNewSpace(JSRegExpResult::kSize + FixedArray::kHeaderSize,
- times_pointer_size,
- ebx, // In: Number of elements as a smi
- REGISTER_VALUE_IS_SMI,
- eax, // Out: Start of allocation (tagged).
- ecx, // Out: End of allocation.
- edx, // Scratch register
- &slowcase,
- TAG_OBJECT);
+ __ Allocate(JSRegExpResult::kSize + FixedArray::kHeaderSize,
+ times_pointer_size,
+ ebx, // In: Number of elements as a smi
+ REGISTER_VALUE_IS_SMI,
+ eax, // Out: Start of allocation (tagged).
+ ecx, // Out: End of allocation.
+ edx, // Scratch register
+ &slowcase,
+ TAG_OBJECT);
// eax: Start of allocated area, object-tagged.
// Set JSArray map to global.regexp_result_map().
@@ -4536,6 +4525,7 @@
// Identical objects can be compared fast, but there are some tricky cases
// for NaN and undefined.
+ Label generic_heap_number_comparison;
{
Label not_identical;
__ cmp(eax, edx);
@@ -4552,12 +4542,11 @@
__ bind(&check_for_nan);
}
- // Test for NaN. Sadly, we can't just compare to factory->nan_value(),
- // so we do the second best thing - test it ourselves.
- Label heap_number;
+ // Test for NaN. Compare heap numbers in a general way,
+ // to hanlde NaNs correctly.
__ cmp(FieldOperand(edx, HeapObject::kMapOffset),
Immediate(masm->isolate()->factory()->heap_number_map()));
- __ j(equal, &heap_number, Label::kNear);
+ __ j(equal, &generic_heap_number_comparison, Label::kNear);
if (cc != equal) {
// Call runtime on identical JSObjects. Otherwise return equal.
__ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
@@ -4566,37 +4555,6 @@
__ Set(eax, Immediate(Smi::FromInt(EQUAL)));
__ ret(0);
- __ bind(&heap_number);
- // It is a heap number, so return non-equal if it's NaN and equal if
- // it's not NaN.
- // The representation of NaN values has all exponent bits (52..62) set,
- // and not all mantissa bits (0..51) clear.
- // We only accept QNaNs, which have bit 51 set.
- // Read top bits of double representation (second word of value).
-
- // Value is a QNaN if value & kQuietNaNMask == kQuietNaNMask, i.e.,
- // all bits in the mask are set. We only need to check the word
- // that contains the exponent and high bit of the mantissa.
- STATIC_ASSERT(((kQuietNaNHighBitsMask << 1) & 0x80000000u) != 0);
- __ mov(edx, FieldOperand(edx, HeapNumber::kExponentOffset));
- __ Set(eax, Immediate(0));
- // Shift value and mask so kQuietNaNHighBitsMask applies to topmost
- // bits.
- __ add(edx, edx);
- __ cmp(edx, kQuietNaNHighBitsMask << 1);
- if (cc == equal) {
- STATIC_ASSERT(EQUAL != 1);
- __ setcc(above_equal, eax);
- __ ret(0);
- } else {
- Label nan;
- __ j(above_equal, &nan, Label::kNear);
- __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
- __ ret(0);
- __ bind(&nan);
- __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc))));
- __ ret(0);
- }
__ bind(¬_identical);
}
@@ -4676,6 +4634,7 @@
// Generate the number comparison code.
Label non_number_comparison;
Label unordered;
+ __ bind(&generic_heap_number_comparison);
if (CpuFeatures::IsSupported(SSE2)) {
CpuFeatureScope use_sse2(masm, SSE2);
CpuFeatureScope use_cmov(masm, CMOV);
@@ -7836,8 +7795,10 @@
__ mov(ebx, MemOperand(ebp, parameter_count_offset));
masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE);
__ pop(ecx);
- __ lea(esp, MemOperand(esp, ebx, times_pointer_size,
- extra_expression_stack_count_ * kPointerSize));
+ int additional_offset = function_mode_ == JS_FUNCTION_STUB_MODE
+ ? kPointerSize
+ : 0;
+ __ lea(esp, MemOperand(esp, ebx, times_pointer_size, additional_offset));
__ jmp(ecx); // Return to IC Miss stub, continuation still on stack.
}
diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc
index 586ffef..550c83d 100644
--- a/src/ia32/codegen-ia32.cc
+++ b/src/ia32/codegen-ia32.cc
@@ -450,9 +450,8 @@
// edi: length of source FixedArray (smi-tagged)
AllocationFlags flags =
static_cast<AllocationFlags>(TAG_OBJECT | DOUBLE_ALIGNMENT);
- __ AllocateInNewSpace(FixedDoubleArray::kHeaderSize, times_8,
- edi, REGISTER_VALUE_IS_SMI,
- eax, ebx, no_reg, &gc_required, flags);
+ __ Allocate(FixedDoubleArray::kHeaderSize, times_8, edi,
+ REGISTER_VALUE_IS_SMI, eax, ebx, no_reg, &gc_required, flags);
// eax: destination FixedDoubleArray
// edi: number of elements
@@ -589,7 +588,7 @@
// Allocate new FixedArray.
// ebx: length of source FixedDoubleArray (smi-tagged)
__ lea(edi, Operand(ebx, times_2, FixedArray::kHeaderSize));
- __ AllocateInNewSpace(edi, eax, esi, no_reg, &gc_required, TAG_OBJECT);
+ __ Allocate(edi, eax, esi, no_reg, &gc_required, TAG_OBJECT);
// eax: destination FixedArray
// ebx: number of elements
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index ebc3a2b..efbdf13 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -2567,7 +2567,6 @@
void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
- // TODO(rossberg): incorporate symbols.
ZoneList<Expression*>* args = expr->arguments();
ASSERT(args->length() == 1);
@@ -2703,28 +2702,6 @@
}
-void FullCodeGenerator::EmitIsSymbol(CallRuntime* expr) {
- ZoneList<Expression*>* args = expr->arguments();
- ASSERT(args->length() == 1);
-
- VisitForAccumulatorValue(args->at(0));
-
- Label materialize_true, materialize_false;
- Label* if_true = NULL;
- Label* if_false = NULL;
- Label* fall_through = NULL;
- context()->PrepareTest(&materialize_true, &materialize_false,
- &if_true, &if_false, &fall_through);
-
- __ JumpIfSmi(eax, if_false);
- __ CmpObjectType(eax, SYMBOL_TYPE, ebx);
- PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
- Split(equal, if_true, if_false, fall_through);
-
- context()->Plug(if_true, if_false);
-}
-
-
void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
ASSERT(args->length() == 1);
@@ -4275,6 +4252,10 @@
__ test_b(FieldOperand(edx, Map::kBitFieldOffset),
1 << Map::kIsUndetectable);
Split(zero, if_true, if_false, fall_through);
+ } else if (check->Equals(isolate()->heap()->symbol_string())) {
+ __ JumpIfSmi(eax, if_false);
+ __ CmpObjectType(eax, SYMBOL_TYPE, edx);
+ Split(equal, if_true, if_false, fall_through);
} else if (check->Equals(isolate()->heap()->boolean_string())) {
__ cmp(eax, isolate()->factory()->true_value());
__ j(equal, if_true);
@@ -4306,10 +4287,6 @@
__ cmp(eax, isolate()->factory()->null_value());
__ j(equal, if_true);
}
- if (FLAG_harmony_symbols) {
- __ CmpObjectType(eax, SYMBOL_TYPE, edx);
- __ j(equal, if_true);
- }
__ CmpObjectType(eax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, edx);
__ j(below, if_false);
__ CmpInstanceType(edx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 205781b..4d23aef 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -1740,13 +1740,6 @@
}
-void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
- Register result = ToRegister(instr->result());
- Register array = ToRegister(instr->value());
- __ mov(result, FieldOperand(array, JSArray::kLengthOffset));
-}
-
-
void LCodeGen::DoFixedArrayBaseLength(
LFixedArrayBaseLength* instr) {
Register result = ToRegister(instr->result());
@@ -2116,6 +2109,12 @@
__ bind(¬_string);
}
+ if (expected.Contains(ToBooleanStub::SYMBOL)) {
+ // Symbol value -> true.
+ __ CmpInstanceType(map, SYMBOL_TYPE);
+ __ j(equal, true_label);
+ }
+
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
// heap number -> false iff +0, -0, or NaN.
Label not_heap_number;
@@ -5566,7 +5565,7 @@
__ Allocate(size, result, temp, no_reg, deferred->entry(), flags);
} else {
Register size = ToRegister(instr->size());
- __ AllocateInNewSpace(size, result, temp, no_reg, deferred->entry(), flags);
+ __ Allocate(size, result, temp, no_reg, deferred->entry(), flags);
}
__ bind(deferred->exit());
@@ -5979,6 +5978,11 @@
1 << Map::kIsUndetectable);
final_branch_condition = zero;
+ } else if (type_name->Equals(heap()->symbol_string())) {
+ __ JumpIfSmi(input, false_label);
+ __ CmpObjectType(input, SYMBOL_TYPE, input);
+ final_branch_condition = equal;
+
} else if (type_name->Equals(heap()->boolean_string())) {
__ cmp(input, factory()->true_value());
__ j(equal, true_label);
@@ -6013,13 +6017,7 @@
__ cmp(input, factory()->null_value());
__ j(equal, true_label);
}
- if (FLAG_harmony_symbols) {
- __ CmpObjectType(input, SYMBOL_TYPE, input);
- __ j(equal, true_label);
- __ CmpInstanceType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
- } else {
- __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
- }
+ __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
__ j(below, false_label);
__ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
__ j(above, false_label);
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index f2aec99..102515a 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -923,6 +923,35 @@
LInstruction* instr = current->CompileToLithium(this);
if (instr != NULL) {
+#if DEBUG
+ // Make sure that the lithium instruction has either no fixed register
+ // constraints in temps or the result OR no uses that are only used at
+ // start. If this invariant doesn't hold, the register allocator can decide
+ // to insert a split of a range immediately before the instruction due to an
+ // already allocated register needing to be used for the instruction's fixed
+ // register constraint. In this case, The register allocator won't see an
+ // interference between the split child and the use-at-start (it would if
+ // the it was just a plain use), so it is free to move the split child into
+ // the same register that is used for the use-at-start.
+ // See https://code.google.com/p/chromium/issues/detail?id=201590
+ if (!(instr->ClobbersRegisters() && instr->ClobbersDoubleRegisters())) {
+ int fixed = 0;
+ int used_at_start = 0;
+ for (UseIterator it(instr); !it.Done(); it.Advance()) {
+ LUnallocated* operand = LUnallocated::cast(it.Current());
+ if (operand->IsUsedAtStart()) ++used_at_start;
+ }
+ if (instr->Output() != NULL) {
+ if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed;
+ }
+ for (TempIterator it(instr); !it.Done(); it.Advance()) {
+ LUnallocated* operand = LUnallocated::cast(it.Current());
+ if (operand->HasFixedPolicy()) ++fixed;
+ }
+ ASSERT(fixed == 0 || used_at_start == 0);
+ }
+#endif
+
if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
instr = AssignPointerMap(instr);
}
@@ -1182,16 +1211,20 @@
input);
return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
} else {
- LOperand* input = UseRegisterAtStart(instr->value());
LOperand* context = UseAny(instr->context()); // Deferred use by MathAbs.
+ LOperand* input = NULL;
if (op == kMathPowHalf) {
+ input = UseRegisterAtStart(instr->value());
LOperand* temp = TempRegister();
LMathPowHalf* result = new(zone()) LMathPowHalf(context, input, temp);
return DefineSameAsFirst(result);
} else if (op == kMathRound) {
+ input = UseRegister(instr->value());
LOperand* temp = FixedTemp(xmm4);
LMathRound* result = new(zone()) LMathRound(context, input, temp);
return AssignEnvironment(DefineAsRegister(result));
+ } else {
+ input = UseRegisterAtStart(instr->value());
}
LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(context,
input);
@@ -1716,12 +1749,6 @@
}
-LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
- LOperand* array = UseRegisterAtStart(instr->value());
- return DefineAsRegister(new(zone()) LJSArrayLength(array));
-}
-
-
LInstruction* LChunkBuilder::DoFixedArrayBaseLength(
HFixedArrayBaseLength* instr) {
LOperand* array = UseRegisterAtStart(instr->value());
diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h
index 0e36474..1c490bb 100644
--- a/src/ia32/lithium-ia32.h
+++ b/src/ia32/lithium-ia32.h
@@ -114,7 +114,6 @@
V(IsStringAndBranch) \
V(IsSmiAndBranch) \
V(IsUndetectableAndBranch) \
- V(JSArrayLength) \
V(Label) \
V(LazyBailout) \
V(LoadContextSlot) \
@@ -1147,19 +1146,6 @@
};
-class LJSArrayLength: public LTemplateInstruction<1, 1, 0> {
- public:
- explicit LJSArrayLength(LOperand* value) {
- inputs_[0] = value;
- }
-
- LOperand* value() { return inputs_[0]; }
-
- DECLARE_CONCRETE_INSTRUCTION(JSArrayLength, "js-array-length")
- DECLARE_HYDROGEN_ACCESSOR(JSArrayLength)
-};
-
-
class LFixedArrayBaseLength: public LTemplateInstruction<1, 1, 0> {
public:
explicit LFixedArrayBaseLength(LOperand* value) {
diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc
index debf64a..3d3dabc 100644
--- a/src/ia32/macro-assembler-ia32.cc
+++ b/src/ia32/macro-assembler-ia32.cc
@@ -1332,18 +1332,16 @@
}
-void MacroAssembler::AllocateInNewSpace(
- int header_size,
- ScaleFactor element_size,
- Register element_count,
- RegisterValueType element_count_type,
- Register result,
- Register result_end,
- Register scratch,
- Label* gc_required,
- AllocationFlags flags) {
+void MacroAssembler::Allocate(int header_size,
+ ScaleFactor element_size,
+ Register element_count,
+ RegisterValueType element_count_type,
+ Register result,
+ Register result_end,
+ Register scratch,
+ Label* gc_required,
+ AllocationFlags flags) {
ASSERT((flags & SIZE_IN_WORDS) == 0);
- ASSERT((flags & PRETENURE_OLD_POINTER_SPACE) == 0);
if (!FLAG_inline_new) {
if (emit_debug_code()) {
// Trash the registers to simulate an allocation failure.
@@ -1365,6 +1363,7 @@
// Align the next allocation. Storing the filler map without checking top is
// always safe because the limit of the heap is always aligned.
if ((flags & DOUBLE_ALIGNMENT) != 0) {
+ ASSERT((flags & PRETENURE_OLD_POINTER_SPACE) == 0);
ASSERT(kPointerAlignment * 2 == kDoubleAlignment);
Label aligned;
test(result, Immediate(kDoubleAlignmentMask));
@@ -1375,9 +1374,9 @@
bind(&aligned);
}
- // Calculate new top and bail out if new space is exhausted.
- ExternalReference new_space_allocation_limit =
- ExternalReference::new_space_allocation_limit_address(isolate());
+ // Calculate new top and bail out if space is exhausted.
+ ExternalReference allocation_limit =
+ AllocationUtils::GetAllocationLimitReference(isolate(), flags);
// We assume that element_count*element_size + header_size does not
// overflow.
@@ -1394,7 +1393,7 @@
lea(result_end, Operand(element_count, element_size, header_size));
add(result_end, result);
j(carry, gc_required);
- cmp(result_end, Operand::StaticVariable(new_space_allocation_limit));
+ cmp(result_end, Operand::StaticVariable(allocation_limit));
j(above, gc_required);
if ((flags & TAG_OBJECT) != 0) {
@@ -1407,14 +1406,13 @@
}
-void MacroAssembler::AllocateInNewSpace(Register object_size,
- Register result,
- Register result_end,
- Register scratch,
- Label* gc_required,
- AllocationFlags flags) {
+void MacroAssembler::Allocate(Register object_size,
+ Register result,
+ Register result_end,
+ Register scratch,
+ Label* gc_required,
+ AllocationFlags flags) {
ASSERT((flags & (RESULT_CONTAINS_TOP | SIZE_IN_WORDS)) == 0);
- ASSERT((flags & PRETENURE_OLD_POINTER_SPACE) == 0);
if (!FLAG_inline_new) {
if (emit_debug_code()) {
// Trash the registers to simulate an allocation failure.
@@ -1436,6 +1434,7 @@
// Align the next allocation. Storing the filler map without checking top is
// always safe because the limit of the heap is always aligned.
if ((flags & DOUBLE_ALIGNMENT) != 0) {
+ ASSERT((flags & PRETENURE_OLD_POINTER_SPACE) == 0);
ASSERT(kPointerAlignment * 2 == kDoubleAlignment);
Label aligned;
test(result, Immediate(kDoubleAlignmentMask));
@@ -1446,15 +1445,16 @@
bind(&aligned);
}
- // Calculate new top and bail out if new space is exhausted.
- ExternalReference new_space_allocation_limit =
- ExternalReference::new_space_allocation_limit_address(isolate());
+ // Calculate new top and bail out if space is exhausted.
+ ExternalReference allocation_limit =
+ AllocationUtils::GetAllocationLimitReference(isolate(), flags);
+
if (!object_size.is(result_end)) {
mov(result_end, object_size);
}
add(result_end, result);
j(carry, gc_required);
- cmp(result_end, Operand::StaticVariable(new_space_allocation_limit));
+ cmp(result_end, Operand::StaticVariable(allocation_limit));
j(above, gc_required);
// Tag result if requested.
@@ -1511,15 +1511,15 @@
and_(scratch1, Immediate(~kObjectAlignmentMask));
// Allocate two byte string in new space.
- AllocateInNewSpace(SeqTwoByteString::kHeaderSize,
- times_1,
- scratch1,
- REGISTER_VALUE_IS_INT32,
- result,
- scratch2,
- scratch3,
- gc_required,
- TAG_OBJECT);
+ Allocate(SeqTwoByteString::kHeaderSize,
+ times_1,
+ scratch1,
+ REGISTER_VALUE_IS_INT32,
+ result,
+ scratch2,
+ scratch3,
+ gc_required,
+ TAG_OBJECT);
// Set the map, length and hash field.
mov(FieldOperand(result, HeapObject::kMapOffset),
@@ -1547,15 +1547,15 @@
and_(scratch1, Immediate(~kObjectAlignmentMask));
// Allocate ASCII string in new space.
- AllocateInNewSpace(SeqOneByteString::kHeaderSize,
- times_1,
- scratch1,
- REGISTER_VALUE_IS_INT32,
- result,
- scratch2,
- scratch3,
- gc_required,
- TAG_OBJECT);
+ Allocate(SeqOneByteString::kHeaderSize,
+ times_1,
+ scratch1,
+ REGISTER_VALUE_IS_INT32,
+ result,
+ scratch2,
+ scratch3,
+ gc_required,
+ TAG_OBJECT);
// Set the map, length and hash field.
mov(FieldOperand(result, HeapObject::kMapOffset),
diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h
index 8dd4120..b3dae73 100644
--- a/src/ia32/macro-assembler-ia32.h
+++ b/src/ia32/macro-assembler-ia32.h
@@ -582,22 +582,22 @@
Label* gc_required,
AllocationFlags flags);
- void AllocateInNewSpace(int header_size,
- ScaleFactor element_size,
- Register element_count,
- RegisterValueType element_count_type,
- Register result,
- Register result_end,
- Register scratch,
- Label* gc_required,
- AllocationFlags flags);
+ void Allocate(int header_size,
+ ScaleFactor element_size,
+ Register element_count,
+ RegisterValueType element_count_type,
+ Register result,
+ Register result_end,
+ Register scratch,
+ Label* gc_required,
+ AllocationFlags flags);
- void AllocateInNewSpace(Register object_size,
- Register result,
- Register result_end,
- Register scratch,
- Label* gc_required,
- AllocationFlags flags);
+ void Allocate(Register object_size,
+ Register result,
+ Register result_end,
+ Register scratch,
+ Label* gc_required,
+ AllocationFlags flags);
// Undo allocation in new space. The object passed and objects allocated after
// it will no longer be allocated. Make sure that no pointers are left to the
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
index f7e795e..cb4b4a7 100644
--- a/src/ia32/stub-cache-ia32.cc
+++ b/src/ia32/stub-cache-ia32.cc
@@ -730,7 +730,7 @@
// but may be destroyed if store is successful.
void StubCompiler::GenerateStoreField(MacroAssembler* masm,
Handle<JSObject> object,
- int index,
+ LookupResult* lookup,
Handle<Map> transition,
Handle<Name> name,
Register receiver_reg,
@@ -740,16 +740,6 @@
Register scratch2,
Label* miss_label,
Label* miss_restore_name) {
- LookupResult lookup(masm->isolate());
- object->Lookup(*name, &lookup);
- if (lookup.IsFound() && (lookup.IsReadOnly() || !lookup.IsCacheable())) {
- // In sloppy mode, we could just return the value and be done. However, we
- // might be in strict mode, where we have to throw. Since we cannot tell,
- // go into slow case unconditionally.
- __ jmp(miss_label);
- return;
- }
-
// Check that the map of the object hasn't changed.
CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
: REQUIRE_EXACT_MAP;
@@ -764,8 +754,9 @@
// Check that we are allowed to write this.
if (!transition.is_null() && object->GetPrototype()->IsJSObject()) {
JSObject* holder;
- if (lookup.IsFound()) {
- holder = lookup.holder();
+ // holder == object indicates that no property was found.
+ if (lookup->holder() != *object) {
+ holder = lookup->holder();
} else {
// Find the top object.
holder = *object;
@@ -774,8 +765,19 @@
} while (holder->GetPrototype()->IsJSObject());
}
// We need an extra register, push
- CheckPrototypes(object, receiver_reg, Handle<JSObject>(holder), name_reg,
- scratch1, scratch2, name, miss_restore_name);
+ Register holder_reg = CheckPrototypes(
+ object, receiver_reg, Handle<JSObject>(holder), name_reg,
+ scratch1, scratch2, name, miss_restore_name);
+ // If no property was found, and the holder (the last object in the
+ // prototype chain) is in slow mode, we need to do a negative lookup on the
+ // holder.
+ if (lookup->holder() == *object &&
+ !holder->HasFastProperties() &&
+ !holder->IsJSGlobalProxy() &&
+ !holder->IsJSGlobalObject()) {
+ GenerateDictionaryNegativeLookup(
+ masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
+ }
}
// Stub never generated for non-global objects that require access
@@ -799,6 +801,7 @@
return;
}
+ int index;
if (!transition.is_null()) {
// Update the map of the object.
__ mov(scratch1, Immediate(transition));
@@ -813,8 +816,13 @@
kDontSaveFPRegs,
OMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
+ index = transition->instance_descriptors()->GetFieldIndex(
+ transition->LastAdded());
+ } else {
+ index = lookup->GetFieldIndex().field_index();
}
+
// Adjust for the number of properties stored in the object. Even in the
// face of a transition we can use the old map here because the size of the
// object and the number of in-object properties is not going to change.
@@ -2350,6 +2358,12 @@
// Check that the object is a symbol.
__ CmpObjectType(edx, SYMBOL_TYPE, eax);
__ j(not_equal, &miss);
+ // Check that the maps starting from the prototype haven't changed.
+ GenerateDirectLoadGlobalFunctionPrototype(
+ masm(), Context::SYMBOL_FUNCTION_INDEX, eax, &miss);
+ CheckPrototypes(
+ Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
+ eax, holder, ebx, edx, edi, name, &miss);
break;
case NUMBER_CHECK: {
diff --git a/src/ic-inl.h b/src/ic-inl.h
index 9439792..ca02183 100644
--- a/src/ic-inl.h
+++ b/src/ic-inl.h
@@ -109,7 +109,7 @@
// If the object is a value, we use the prototype map for the cache.
ASSERT(object->IsString() || object->IsSymbol() ||
object->IsNumber() || object->IsBoolean());
- return DELEGATE_MAP;
+ return PROTOTYPE_MAP;
}
@@ -124,7 +124,7 @@
!object->HasFastProperties() &&
!object->IsJSGlobalProxy() &&
!object->IsJSGlobalObject()) {
- return DELEGATE_MAP;
+ return PROTOTYPE_MAP;
}
return OWN_MAP;
}
@@ -133,7 +133,8 @@
JSObject* IC::GetCodeCacheHolder(Isolate* isolate,
Object* object,
InlineCacheHolderFlag holder) {
- Object* map_owner = holder == OWN_MAP ? object : object->GetDelegate(isolate);
+ Object* map_owner =
+ holder == OWN_MAP ? object : object->GetPrototype(isolate);
ASSERT(map_owner->IsJSObject());
return JSObject::cast(map_owner);
}
diff --git a/src/ic.cc b/src/ic.cc
index 71f2c30..515c6f7 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -190,7 +190,7 @@
// The stub was generated for JSObject but called for non-JSObject.
// IC::GetCodeCacheHolder is not applicable.
return false;
- } else if (cache_holder == DELEGATE_MAP &&
+ } else if (cache_holder == PROTOTYPE_MAP &&
receiver->GetPrototype(isolate)->IsNull()) {
// IC::GetCodeCacheHolder is not applicable.
return false;
@@ -857,28 +857,6 @@
return Smi::FromInt(String::cast(*string)->length());
}
- // Use specialized code for getting the length of arrays.
- if (object->IsJSArray() &&
- name->Equals(isolate()->heap()->length_string())) {
- Handle<Code> stub;
- if (state == UNINITIALIZED) {
- stub = pre_monomorphic_stub();
- } else if (state == PREMONOMORPHIC) {
- ArrayLengthStub array_length_stub(kind());
- stub = array_length_stub.GetCode(isolate());
- } else if (state != MEGAMORPHIC) {
- ASSERT(state != GENERIC);
- stub = megamorphic_stub();
- }
- if (!stub.is_null()) {
- set_target(*stub);
-#ifdef DEBUG
- if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n");
-#endif
- }
- return JSArray::cast(*object)->length();
- }
-
// Use specialized code for getting prototype of functions.
if (object->IsJSFunction() &&
name->Equals(isolate()->heap()->prototype_string()) &&
@@ -1037,6 +1015,22 @@
}
+bool IC::IsTransitionedMapOfMonomorphicTarget(Map* receiver_map) {
+ AssertNoAllocation no_allocation;
+
+ Map* current_map = target()->FindFirstMap();
+ ElementsKind receiver_elements_kind = receiver_map->elements_kind();
+ bool more_general_transition =
+ IsMoreGeneralElementsKindTransition(
+ current_map->elements_kind(), receiver_elements_kind);
+ Map* transitioned_map = more_general_transition
+ ? current_map->LookupElementsTransitionMap(receiver_elements_kind)
+ : NULL;
+
+ return transitioned_map == receiver_map;
+}
+
+
// Since GC may have been invoked, by the time PatchCache is called, |state| is
// not necessarily equal to target()->state().
void IC::PatchCache(State state,
@@ -1054,6 +1048,17 @@
// Only move to megamorphic if the target changes.
if (target() != *code) {
if (target()->is_load_stub()) {
+ bool is_same_handler = false;
+ {
+ AssertNoAllocation no_allocation;
+ Code* old_handler = target()->FindFirstCode();
+ is_same_handler = old_handler == *code;
+ }
+ if (is_same_handler
+ && IsTransitionedMapOfMonomorphicTarget(receiver->map())) {
+ UpdateMonomorphicIC(receiver, code, name);
+ break;
+ }
if (UpdatePolymorphicIC(state, strict_mode, receiver, name, code)) {
break;
}
@@ -1226,6 +1231,12 @@
if (!holder->HasFastProperties()) break;
return isolate()->stub_cache()->ComputeLoadViaGetter(
name, receiver, holder, Handle<JSFunction>::cast(getter));
+ } else if (receiver->IsJSArray() &&
+ name->Equals(isolate()->heap()->length_string())) {
+ PropertyIndex lengthIndex =
+ PropertyIndex::NewHeaderIndex(JSArray::kLengthOffset / kPointerSize);
+ return isolate()->stub_cache()->ComputeLoadField(
+ name, receiver, holder, lengthIndex);
}
// TODO(dcarney): Handle correctly.
if (callback->IsDeclaredAccessorInfo()) break;
@@ -1418,41 +1429,42 @@
}
-static bool StoreICableLookup(LookupResult* lookup) {
- // Bail out if we didn't find a result.
- if (!lookup->IsFound()) return false;
-
- // Bail out if inline caching is not allowed.
- if (!lookup->IsCacheable()) return false;
-
- // If the property is read-only, we leave the IC in its current state.
- if (lookup->IsTransition()) {
- return !lookup->GetTransitionDetails().IsReadOnly();
- }
- return !lookup->IsReadOnly();
-}
-
-
static bool LookupForWrite(Handle<JSObject> receiver,
Handle<String> name,
LookupResult* lookup) {
- receiver->LocalLookup(*name, lookup);
- if (!lookup->IsFound()) {
- receiver->map()->LookupTransition(*receiver, *name, lookup);
- }
- if (!StoreICableLookup(lookup)) {
- // 2nd chance: There can be accessors somewhere in the prototype chain.
- receiver->Lookup(*name, lookup);
- return lookup->IsPropertyCallbacks() && StoreICableLookup(lookup);
+ Handle<JSObject> holder = receiver;
+ receiver->Lookup(*name, lookup);
+ if (lookup->IsFound()) {
+ if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false;
+
+ if (lookup->holder() == *receiver) {
+ if (lookup->IsInterceptor() &&
+ receiver->GetNamedInterceptor()->setter()->IsUndefined()) {
+ receiver->LocalLookupRealNamedProperty(*name, lookup);
+ return lookup->IsFound() &&
+ !lookup->IsReadOnly() &&
+ lookup->IsCacheable();
+ }
+ return true;
+ }
+
+ if (lookup->IsPropertyCallbacks()) return true;
+
+ // Currently normal holders in the prototype chain are not supported. They
+ // would require a runtime positive lookup and verification that the details
+ // have not changed.
+ if (lookup->IsInterceptor() || lookup->IsNormal()) return false;
+ holder = Handle<JSObject>(lookup->holder(), lookup->isolate());
}
- if (lookup->IsInterceptor() &&
- receiver->GetNamedInterceptor()->setter()->IsUndefined()) {
- receiver->LocalLookupRealNamedProperty(*name, lookup);
- return StoreICableLookup(lookup);
- }
-
- return true;
+ // While normally LookupTransition gets passed the receiver, in this case we
+ // pass the holder of the property that we overwrite. This keeps the holder in
+ // the LookupResult intact so we can later use it to generate a prototype
+ // chain check. This avoids a double lookup, but requires us to pass in the
+ // receiver when trying to fetch extra information from the transition.
+ receiver->map()->LookupTransition(*holder, *name, lookup);
+ return lookup->IsTransition() &&
+ !lookup->GetTransitionDetails(receiver->map()).IsReadOnly();
}
@@ -1552,7 +1564,6 @@
Handle<String> name,
Handle<Object> value) {
ASSERT(!receiver->IsJSGlobalProxy());
- ASSERT(StoreICableLookup(lookup));
ASSERT(lookup->IsFound());
// These are not cacheable, so we never see such LookupResults here.
@@ -1575,8 +1586,7 @@
switch (lookup->type()) {
case FIELD:
return isolate()->stub_cache()->ComputeStoreField(
- name, receiver, lookup->GetFieldIndex().field_index(),
- Handle<Map>::null(), strict_mode);
+ name, receiver, lookup, Handle<Map>::null(), strict_mode);
case NORMAL:
if (receiver->IsGlobalObject()) {
// The stub generated for the global object picks the value directly
@@ -1588,7 +1598,7 @@
return isolate()->stub_cache()->ComputeStoreGlobal(
name, global, cell, strict_mode);
}
- if (!holder.is_identical_to(receiver)) break;
+ ASSERT(holder.is_identical_to(receiver));
return isolate()->stub_cache()->ComputeStoreNormal(strict_mode);
case CALLBACKS: {
Handle<Object> callback(lookup->GetCallbackObject(), isolate());
@@ -1623,7 +1633,10 @@
case CONSTANT_FUNCTION:
break;
case TRANSITION: {
- Handle<Map> transition(lookup->GetTransitionTarget(), isolate());
+ // Explicitly pass in the receiver map since LookupForWrite may have
+ // stored something else than the receiver in the holder.
+ Handle<Map> transition(
+ lookup->GetTransitionTarget(receiver->map()), isolate());
int descriptor = transition->LastAdded();
DescriptorArray* target_descriptors = transition->instance_descriptors();
@@ -1631,9 +1644,8 @@
if (details.type() != FIELD || details.attributes() != NONE) break;
- int field_index = target_descriptors->GetFieldIndex(descriptor);
return isolate()->stub_cache()->ComputeStoreField(
- name, receiver, field_index, transition, strict_mode);
+ name, receiver, lookup, transition, strict_mode);
}
case NONEXISTENT:
case HANDLER:
@@ -1704,16 +1716,7 @@
transitioned_receiver_map =
ComputeTransitionedMap(receiver, store_mode);
}
- ElementsKind transitioned_kind =
- transitioned_receiver_map->elements_kind();
- bool more_general_transition =
- IsMoreGeneralElementsKindTransition(
- previous_receiver_map->elements_kind(),
- transitioned_kind);
- Map* transitioned_previous_map = more_general_transition
- ? previous_receiver_map->LookupElementsTransitionMap(transitioned_kind)
- : NULL;
- if (transitioned_previous_map == *transitioned_receiver_map) {
+ if (IsTransitionedMapOfMonomorphicTarget(*transitioned_receiver_map)) {
// Element family is the same, use the "worst" case map.
store_mode = GetNonTransitioningStoreMode(store_mode);
return isolate()->stub_cache()->ComputeKeyedStoreElement(
@@ -1984,19 +1987,20 @@
switch (lookup->type()) {
case FIELD:
return isolate()->stub_cache()->ComputeKeyedStoreField(
- name, receiver, lookup->GetFieldIndex().field_index(),
- Handle<Map>::null(), strict_mode);
+ name, receiver, lookup, Handle<Map>::null(), strict_mode);
case TRANSITION: {
- Handle<Map> transition(lookup->GetTransitionTarget(), isolate());
+ // Explicitly pass in the receiver map since LookupForWrite may have
+ // stored something else than the receiver in the holder.
+ Handle<Map> transition(
+ lookup->GetTransitionTarget(receiver->map()), isolate());
int descriptor = transition->LastAdded();
DescriptorArray* target_descriptors = transition->instance_descriptors();
PropertyDetails details = target_descriptors->GetDetails(descriptor);
if (details.type() == FIELD && details.attributes() == NONE) {
- int field_index = target_descriptors->GetFieldIndex(descriptor);
return isolate()->stub_cache()->ComputeKeyedStoreField(
- name, receiver, field_index, transition, strict_mode);
+ name, receiver, lookup, transition, strict_mode);
}
// fall through.
}
diff --git a/src/ic.h b/src/ic.h
index 2b8f378..55b5661 100644
--- a/src/ic.h
+++ b/src/ic.h
@@ -176,6 +176,7 @@
Handle<String> name,
Handle<Code> code);
void CopyICToMegamorphicCache(Handle<String> name);
+ bool IsTransitionedMapOfMonomorphicTarget(Map* receiver_map);
void PatchCache(State state,
StrictModeFlag strict_mode,
Handle<JSObject> receiver,
diff --git a/src/interpreter-irregexp.cc b/src/interpreter-irregexp.cc
index 5abeb5a..e678e6c 100644
--- a/src/interpreter-irregexp.cc
+++ b/src/interpreter-irregexp.cc
@@ -73,9 +73,15 @@
unsigned int old_char = subject[from++];
unsigned int new_char = subject[current++];
if (old_char == new_char) continue;
- if (old_char - 'A' <= 'Z' - 'A') old_char |= 0x20;
- if (new_char - 'A' <= 'Z' - 'A') new_char |= 0x20;
+ // Convert both characters to lower case.
+ old_char |= 0x20;
+ new_char |= 0x20;
if (old_char != new_char) return false;
+ // Not letters in the ASCII range and Latin-1 range.
+ if (!(old_char - 'a' <= 'z' - 'a') &&
+ !(old_char - 224 <= 254 - 224 && old_char != 247)) {
+ return false;
+ }
}
return true;
}
diff --git a/src/isolate.cc b/src/isolate.cc
index 632ecdc..0415519 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -612,13 +612,16 @@
limit = Max(limit, 0); // Ensure that limit is not negative.
int initial_size = Min(limit, 10);
Handle<FixedArray> elements =
- factory()->NewFixedArrayWithHoles(initial_size * 4);
+ factory()->NewFixedArrayWithHoles(initial_size * 4 + 1);
// If the caller parameter is a function we skip frames until we're
// under it before starting to collect.
bool seen_caller = !caller->IsJSFunction();
- int cursor = 0;
+ // First element is reserved to store the number of non-strict frames.
+ int cursor = 1;
int frames_seen = 0;
+ int non_strict_frames = 0;
+ bool encountered_strict_function = false;
for (StackFrameIterator iter(this);
!iter.done() && frames_seen < limit;
iter.Advance()) {
@@ -646,6 +649,17 @@
Handle<JSFunction> fun = frames[i].function();
Handle<Code> code = frames[i].code();
Handle<Smi> offset(Smi::FromInt(frames[i].offset()), this);
+ // The stack trace API should not expose receivers and function
+ // objects on frames deeper than the top-most one with a strict
+ // mode function. The number of non-strict frames is stored as
+ // first element in the result array.
+ if (!encountered_strict_function) {
+ if (!fun->shared()->is_classic_mode()) {
+ encountered_strict_function = true;
+ } else {
+ non_strict_frames++;
+ }
+ }
elements->set(cursor++, *recv);
elements->set(cursor++, *fun);
elements->set(cursor++, *code);
@@ -653,6 +667,7 @@
}
}
}
+ elements->set(0, Smi::FromInt(non_strict_frames));
Handle<JSArray> result = factory()->NewJSArrayWithElements(elements);
result->set_length(Smi::FromInt(cursor));
return result;
@@ -1678,6 +1693,8 @@
date_cache_(NULL),
code_stub_interface_descriptors_(NULL),
context_exit_happened_(false),
+ cpu_profiler_(NULL),
+ heap_profiler_(NULL),
deferred_handles_head_(NULL),
optimizing_compiler_thread_(this),
marking_thread_(NULL),
@@ -1809,8 +1826,11 @@
preallocated_message_space_ = NULL;
PreallocatedMemoryThreadStop();
- HeapProfiler::TearDown();
- CpuProfiler::TearDown();
+ delete heap_profiler_;
+ heap_profiler_ = NULL;
+ delete cpu_profiler_;
+ cpu_profiler_ = NULL;
+
if (runtime_profiler_ != NULL) {
runtime_profiler_->TearDown();
delete runtime_profiler_;
@@ -2039,8 +2059,8 @@
// Enable logging before setting up the heap
logger_->SetUp();
- CpuProfiler::SetUp();
- HeapProfiler::SetUp();
+ cpu_profiler_ = new CpuProfiler(this);
+ heap_profiler_ = new HeapProfiler(heap());
// Initialize other runtime facilities
#if defined(USE_SIMULATOR)
diff --git a/src/isolate.h b/src/isolate.h
index d6770cc..f7a81d3 100644
--- a/src/isolate.h
+++ b/src/isolate.h
@@ -357,9 +357,6 @@
V(FunctionInfoListener*, active_function_info_listener, NULL) \
/* State for Relocatable. */ \
V(Relocatable*, relocatable_top, NULL) \
- /* State for CodeEntry in profile-generator. */ \
- V(CodeGenerator*, current_code_generator, NULL) \
- V(bool, jump_target_compiling_deferred_code, false) \
V(DebugObjectCache*, string_stream_debug_object_cache, NULL) \
V(Object*, string_stream_current_security_token, NULL) \
/* TODO(isolates): Release this on destruction? */ \
@@ -371,8 +368,6 @@
V(unsigned, ast_node_count, 0) \
/* SafeStackFrameIterator activations count. */ \
V(int, safe_stack_iterator_counter, 0) \
- V(CpuProfiler*, cpu_profiler, NULL) \
- V(HeapProfiler*, heap_profiler, NULL) \
V(bool, observer_delivery_pending, false) \
V(HStatistics*, hstatistics, NULL) \
V(HTracer*, htracer, NULL) \
@@ -979,6 +974,9 @@
inline bool IsDebuggerActive();
inline bool DebuggerHasBreakPoints();
+ CpuProfiler* cpu_profiler() const { return cpu_profiler_; }
+ HeapProfiler* heap_profiler() const { return heap_profiler_; }
+
#ifdef DEBUG
HistogramInfo* heap_histograms() { return heap_histograms_; }
@@ -1314,6 +1312,8 @@
Debugger* debugger_;
Debug* debug_;
#endif
+ CpuProfiler* cpu_profiler_;
+ HeapProfiler* heap_profiler_;
#define GLOBAL_BACKING_STORE(type, name, initialvalue) \
type name##_;
diff --git a/src/json-parser.h b/src/json-parser.h
index 28ef8b3..ac34c59 100644
--- a/src/json-parser.h
+++ b/src/json-parser.h
@@ -291,6 +291,7 @@
// Parse a JSON object. Position must be right at '{'.
template <bool seq_ascii>
Handle<Object> JsonParser<seq_ascii>::ParseJsonObject() {
+ HandleScope scope(isolate());
Handle<JSObject> json_object =
factory()->NewJSObject(object_constructor(), pretenure_);
ASSERT_EQ(c0_, '{');
@@ -358,12 +359,13 @@
}
}
AdvanceSkipWhitespace();
- return json_object;
+ return scope.CloseAndEscape(json_object);
}
// Parse a JSON array. Position must be right at '['.
template <bool seq_ascii>
Handle<Object> JsonParser<seq_ascii>::ParseJsonArray() {
+ HandleScope scope(isolate());
ZoneScope zone_scope(zone(), DELETE_ON_EXIT);
ZoneList<Handle<Object> > elements(4, zone());
ASSERT_EQ(c0_, '[');
@@ -386,8 +388,9 @@
for (int i = 0, n = elements.length(); i < n; i++) {
fast_elements->set(i, *elements[i]);
}
- return factory()->NewJSArrayWithElements(
+ Handle<Object> json_array = factory()->NewJSArrayWithElements(
fast_elements, FAST_ELEMENTS, pretenure_);
+ return scope.CloseAndEscape(json_array);
}
@@ -501,10 +504,10 @@
int count = end - start;
int max_length = count + source_length_ - position_;
int length = Min(max_length, Max(kInitialSpecialStringLength, 2 * count));
- Handle<StringType> seq_str =
+ Handle<StringType> seq_string =
NewRawString<StringType>(factory(), length, pretenure_);
// Copy prefix into seq_str.
- SinkChar* dest = seq_str->GetChars();
+ SinkChar* dest = seq_string->GetChars();
String::WriteToFlat(*prefix, dest, start, end);
while (c0_ != '"') {
@@ -512,7 +515,7 @@
if (c0_ < 0x20) return Handle<String>::null();
if (count >= length) {
// We need to create a longer sequential string for the result.
- return SlowScanJsonString<StringType, SinkChar>(seq_str, 0, count);
+ return SlowScanJsonString<StringType, SinkChar>(seq_string, 0, count);
}
if (c0_ != '\\') {
// If the sink can contain UC16 characters, or source_ contains only
@@ -522,11 +525,11 @@
if (sizeof(SinkChar) == kUC16Size ||
seq_ascii ||
c0_ <= String::kMaxOneByteCharCode) {
- SeqStringSet(seq_str, count++, c0_);
+ SeqStringSet(seq_string, count++, c0_);
Advance();
} else {
// StringType is SeqOneByteString and we just read a non-ASCII char.
- return SlowScanJsonString<SeqTwoByteString, uc16>(seq_str, 0, count);
+ return SlowScanJsonString<SeqTwoByteString, uc16>(seq_string, 0, count);
}
} else {
Advance(); // Advance past the \.
@@ -534,22 +537,22 @@
case '"':
case '\\':
case '/':
- SeqStringSet(seq_str, count++, c0_);
+ SeqStringSet(seq_string, count++, c0_);
break;
case 'b':
- SeqStringSet(seq_str, count++, '\x08');
+ SeqStringSet(seq_string, count++, '\x08');
break;
case 'f':
- SeqStringSet(seq_str, count++, '\x0c');
+ SeqStringSet(seq_string, count++, '\x0c');
break;
case 'n':
- SeqStringSet(seq_str, count++, '\x0a');
+ SeqStringSet(seq_string, count++, '\x0a');
break;
case 'r':
- SeqStringSet(seq_str, count++, '\x0d');
+ SeqStringSet(seq_string, count++, '\x0d');
break;
case 't':
- SeqStringSet(seq_str, count++, '\x09');
+ SeqStringSet(seq_string, count++, '\x09');
break;
case 'u': {
uc32 value = 0;
@@ -563,13 +566,13 @@
}
if (sizeof(SinkChar) == kUC16Size ||
value <= String::kMaxOneByteCharCode) {
- SeqStringSet(seq_str, count++, value);
+ SeqStringSet(seq_string, count++, value);
break;
} else {
// StringType is SeqOneByteString and we just read a non-ASCII char.
position_ -= 6; // Rewind position_ to \ in \uxxxx.
Advance();
- return SlowScanJsonString<SeqTwoByteString, uc16>(seq_str,
+ return SlowScanJsonString<SeqTwoByteString, uc16>(seq_string,
0,
count);
}
@@ -580,23 +583,13 @@
Advance();
}
}
- // Shrink seq_string length to count.
- if (isolate()->heap()->InNewSpace(*seq_str)) {
- isolate()->heap()->new_space()->
- template ShrinkStringAtAllocationBoundary<StringType>(
- *seq_str, count);
- } else {
- int string_size = StringType::SizeFor(count);
- int allocated_string_size = StringType::SizeFor(length);
- int delta = allocated_string_size - string_size;
- Address start_filler_object = seq_str->address() + string_size;
- seq_str->set_length(count);
- isolate()->heap()->CreateFillerObjectAt(start_filler_object, delta);
- }
+
ASSERT_EQ('"', c0_);
// Advance past the last '"'.
AdvanceSkipWhitespace();
- return seq_str;
+
+ // Shrink seq_string length to count and return.
+ return SeqString::Truncate(seq_string, count);
}
@@ -623,8 +616,8 @@
int beg_pos = position_;
position_ = position;
return SlowScanJsonString<SeqOneByteString, uint8_t>(source_,
- beg_pos,
- position_);
+ beg_pos,
+ position_);
}
if (c0 < 0x20) return Handle<String>::null();
if (static_cast<uint32_t>(c0) >
diff --git a/src/json-stringifier.h b/src/json-stringifier.h
index ad9ef3d..bcdd64c 100644
--- a/src/json-stringifier.h
+++ b/src/json-stringifier.h
@@ -41,6 +41,9 @@
MaybeObject* Stringify(Handle<Object> object);
+ INLINE(static MaybeObject* StringifyString(Isolate* isolate,
+ Handle<String> object));
+
private:
static const int kInitialPartLength = 32;
static const int kMaxPartLength = 16 * 1024;
@@ -52,7 +55,7 @@
void ChangeEncoding();
- void ShrinkCurrentPart();
+ INLINE(void ShrinkCurrentPart());
template <bool is_ascii, typename Char>
INLINE(void Append_(Char c));
@@ -84,6 +87,11 @@
bool deferred_comma,
bool deferred_key);
+ template <typename ResultType, typename Char>
+ INLINE(static MaybeObject* StringifyString_(Isolate* isolate,
+ Vector<Char> vector,
+ Handle<String> result));
+
// Entry point to serialize the object.
INLINE(Result SerializeObject(Handle<Object> obj)) {
return Serialize_<false>(obj, false, factory_->empty_string());
@@ -135,18 +143,18 @@
void SerializeString(Handle<String> object);
template <typename SrcChar, typename DestChar>
- INLINE(void SerializeStringUnchecked_(const SrcChar* src,
- DestChar* dest,
- int length));
+ INLINE(static int SerializeStringUnchecked_(const SrcChar* src,
+ DestChar* dest,
+ int length));
template <bool is_ascii, typename Char>
INLINE(void SerializeString_(Handle<String> string));
template <typename Char>
- INLINE(bool DoNotEscape(Char c));
+ INLINE(static bool DoNotEscape(Char c));
template <typename Char>
- INLINE(Vector<const Char> GetCharVector(Handle<String> string));
+ INLINE(static Vector<const Char> GetCharVector(Handle<String> string));
Result StackPush(Handle<Object> object);
void StackPop();
@@ -244,15 +252,15 @@
"\370\0 \371\0 \372\0 \373\0 "
"\374\0 \375\0 \376\0 \377\0 ";
+
BasicJsonStringifier::BasicJsonStringifier(Isolate* isolate)
: isolate_(isolate), current_index_(0), is_ascii_(true) {
factory_ = isolate_->factory();
accumulator_store_ = Handle<JSValue>::cast(
factory_->ToObject(factory_->empty_string()));
part_length_ = kInitialPartLength;
- current_part_ = factory_->NewRawOneByteString(kInitialPartLength);
- tojson_string_ =
- factory_->InternalizeOneByteString(STATIC_ASCII_VECTOR("toJSON"));
+ current_part_ = factory_->NewRawOneByteString(part_length_);
+ tojson_string_ = factory_->toJSON_string();
stack_ = factory_->NewJSArray(8);
}
@@ -275,6 +283,51 @@
}
+MaybeObject* BasicJsonStringifier::StringifyString(Isolate* isolate,
+ Handle<String> object) {
+ static const int kJsonQuoteWorstCaseBlowup = 6;
+ static const int kSpaceForQuotes = 2;
+ int worst_case_length =
+ object->length() * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
+
+ if (worst_case_length > 32 * KB) { // Slow path if too large.
+ BasicJsonStringifier stringifier(isolate);
+ return stringifier.Stringify(object);
+ }
+
+ FlattenString(object);
+ String::FlatContent flat = object->GetFlatContent();
+ if (flat.IsAscii()) {
+ return StringifyString_<SeqOneByteString>(
+ isolate,
+ flat.ToOneByteVector(),
+ isolate->factory()->NewRawOneByteString(worst_case_length));
+ } else {
+ ASSERT(flat.IsTwoByte());
+ return StringifyString_<SeqTwoByteString>(
+ isolate,
+ flat.ToUC16Vector(),
+ isolate->factory()->NewRawTwoByteString(worst_case_length));
+ }
+}
+
+
+template <typename ResultType, typename Char>
+MaybeObject* BasicJsonStringifier::StringifyString_(Isolate* isolate,
+ Vector<Char> vector,
+ Handle<String> result) {
+ AssertNoAllocation no_allocation;
+ int final_size = 0;
+ ResultType* dest = ResultType::cast(*result);
+ dest->Set(final_size++, '\"');
+ final_size += SerializeStringUnchecked_(vector.start(),
+ dest->GetChars() + 1,
+ vector.length());
+ dest->Set(final_size++, '\"');
+ return *SeqString::Truncate(Handle<SeqString>::cast(result), final_size);
+}
+
+
template <bool is_ascii, typename Char>
void BasicJsonStringifier::Append_(Char c) {
if (is_ascii) {
@@ -638,8 +691,8 @@
void BasicJsonStringifier::ShrinkCurrentPart() {
ASSERT(current_index_ < part_length_);
- current_part_ = Handle<String>(
- SeqString::cast(*current_part_)->Truncate(current_index_), isolate_);
+ current_part_ = SeqString::Truncate(Handle<SeqString>::cast(current_part_),
+ current_index_);
}
@@ -667,10 +720,9 @@
template <typename SrcChar, typename DestChar>
-void BasicJsonStringifier::SerializeStringUnchecked_(const SrcChar* src,
- DestChar* dest,
- int length) {
- dest += current_index_;
+int BasicJsonStringifier::SerializeStringUnchecked_(const SrcChar* src,
+ DestChar* dest,
+ int length) {
DestChar* dest_start = dest;
// Assert that uc16 character is not truncated down to 8 bit.
@@ -688,7 +740,7 @@
}
}
- current_index_ += static_cast<int>(dest - dest_start);
+ return static_cast<int>(dest - dest_start);
}
@@ -705,14 +757,14 @@
AssertNoAllocation no_allocation;
Vector<const Char> vector = GetCharVector<Char>(string);
if (is_ascii) {
- SerializeStringUnchecked_(
+ current_index_ += SerializeStringUnchecked_(
vector.start(),
- SeqOneByteString::cast(*current_part_)->GetChars(),
+ SeqOneByteString::cast(*current_part_)->GetChars() + current_index_,
length);
} else {
- SerializeStringUnchecked_(
+ current_index_ += SerializeStringUnchecked_(
vector.start(),
- SeqTwoByteString::cast(*current_part_)->GetChars(),
+ SeqTwoByteString::cast(*current_part_)->GetChars() + current_index_,
length);
}
} else {
diff --git a/src/log.cc b/src/log.cc
index 4ec981c..9438537 100644
--- a/src/log.cc
+++ b/src/log.cc
@@ -644,7 +644,17 @@
String::cast(key)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
ApiEvent("api,check-security,\"%s\"\n", *str);
} else if (key->IsSymbol()) {
- ApiEvent("api,check-security,symbol(hash %x)\n", Symbol::cast(key)->Hash());
+ Symbol* symbol = Symbol::cast(key);
+ if (symbol->name()->IsUndefined()) {
+ ApiEvent("api,check-security,symbol(hash %x)\n",
+ Symbol::cast(key)->Hash());
+ } else {
+ SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
+ DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+ ApiEvent("api,check-security,symbol(\"%s\" hash %x)\n",
+ *str,
+ Symbol::cast(key)->Hash());
+ }
} else if (key->IsUndefined()) {
ApiEvent("api,check-security,undefined\n");
} else {
@@ -833,8 +843,16 @@
String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
ApiEvent("api,%s,\"%s\",\"%s\"\n", tag, *class_name, *property_name);
} else {
- uint32_t hash = Symbol::cast(name)->Hash();
- ApiEvent("api,%s,\"%s\",symbol(hash %x)\n", tag, *class_name, hash);
+ Symbol* symbol = Symbol::cast(name);
+ uint32_t hash = symbol->Hash();
+ if (symbol->name()->IsUndefined()) {
+ ApiEvent("api,%s,\"%s\",symbol(hash %x)\n", tag, *class_name, hash);
+ } else {
+ SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
+ DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+ ApiEvent("api,%s,\"%s\",symbol(\"%s\" hash %x)\n",
+ tag, *class_name, *str, hash);
+ }
}
}
@@ -902,7 +920,14 @@
String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
msg.Append(",1,\"%s%s\"", prefix, *str);
} else {
- msg.Append(",1,symbol(hash %x)", prefix, Name::cast(name)->Hash());
+ Symbol* symbol = Symbol::cast(name);
+ if (symbol->name()->IsUndefined()) {
+ msg.Append(",1,symbol(hash %x)", prefix, symbol->Hash());
+ } else {
+ SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
+ DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+ msg.Append(",1,symbol(\"%s\" hash %x)", prefix, *str, symbol->Hash());
+ }
}
msg.Append('\n');
msg.WriteToLogFile();
@@ -978,8 +1003,15 @@
if (name->IsString()) {
name_buffer_->AppendString(String::cast(name));
} else {
- name_buffer_->AppendBytes("symbol(hash ");
- name_buffer_->AppendHex(Name::cast(name)->Hash());
+ Symbol* symbol = Symbol::cast(name);
+ name_buffer_->AppendBytes("symbol(");
+ if (!symbol->name()->IsUndefined()) {
+ name_buffer_->AppendBytes("\"");
+ name_buffer_->AppendString(String::cast(symbol->name()));
+ name_buffer_->AppendBytes("\" ");
+ }
+ name_buffer_->AppendBytes("hash ");
+ name_buffer_->AppendHex(symbol->Hash());
name_buffer_->AppendByte(')');
}
}
@@ -1006,7 +1038,14 @@
msg.AppendDetailed(String::cast(name), false);
msg.Append('"');
} else {
- msg.Append("symbol(hash %x)", Name::cast(name)->Hash());
+ Symbol* symbol = Symbol::cast(name);
+ msg.Append("symbol(");
+ if (!symbol->name()->IsUndefined()) {
+ msg.Append("\"");
+ msg.AppendDetailed(String::cast(symbol->name()), false);
+ msg.Append("\" ");
+ }
+ msg.Append("hash %x)", symbol->Hash());
}
msg.Append('\n');
msg.WriteToLogFile();
@@ -1036,8 +1075,15 @@
if (name->IsString()) {
name_buffer_->AppendString(String::cast(name));
} else {
- name_buffer_->AppendBytes("symbol(hash ");
- name_buffer_->AppendHex(Name::cast(name)->Hash());
+ Symbol* symbol = Symbol::cast(name);
+ name_buffer_->AppendBytes("symbol(");
+ if (!symbol->name()->IsUndefined()) {
+ name_buffer_->AppendBytes("\"");
+ name_buffer_->AppendString(String::cast(symbol->name()));
+ name_buffer_->AppendBytes("\" ");
+ }
+ name_buffer_->AppendBytes("hash ");
+ name_buffer_->AppendHex(symbol->Hash());
name_buffer_->AppendByte(')');
}
}
@@ -1073,7 +1119,14 @@
String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
msg.Append("\"%s\"", *str);
} else {
- msg.Append("symbol(hash %x)", Name::cast(name)->Hash());
+ Symbol* symbol = Symbol::cast(name);
+ msg.Append("symbol(");
+ if (!symbol->name()->IsUndefined()) {
+ msg.Append("\"");
+ msg.AppendDetailed(String::cast(symbol->name()), false);
+ msg.Append("\" ");
+ }
+ msg.Append("hash %x)", symbol->Hash());
}
msg.Append(',');
msg.AppendAddress(shared->address());
@@ -1138,7 +1191,14 @@
String::cast(source)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
msg.Append("%s", *sourcestr);
} else {
- msg.Append("symbol(hash %x)", Name::cast(source)->Hash());
+ Symbol* symbol = Symbol::cast(source);
+ msg.Append("symbol(");
+ if (!symbol->name()->IsUndefined()) {
+ msg.Append("\"");
+ msg.AppendDetailed(String::cast(symbol->name()), false);
+ msg.Append("\" ");
+ }
+ msg.Append("hash %x)", symbol->Hash());
}
msg.Append(":%d\",", line);
msg.AppendAddress(shared->address());
@@ -1358,7 +1418,14 @@
msg.Append(String::cast(name));
msg.Append('"');
} else {
- msg.Append("symbol(hash %x)", Name::cast(name)->Hash());
+ Symbol* symbol = Symbol::cast(name);
+ msg.Append("symbol(");
+ if (!symbol->name()->IsUndefined()) {
+ msg.Append("\"");
+ msg.AppendDetailed(String::cast(symbol->name()), false);
+ msg.Append("\" ");
+ }
+ msg.Append("hash %x)", symbol->Hash());
}
msg.Append('\n');
msg.WriteToLogFile();
@@ -1615,7 +1682,7 @@
tag = Logger::KEYED_CALL_IC_TAG;
break;
}
- PROFILE(ISOLATE, CodeCreateEvent(tag, code_object, description));
+ PROFILE(isolate_, CodeCreateEvent(tag, code_object, description));
}
}
@@ -1719,20 +1786,20 @@
Handle<String> script_name(String::cast(script->name()));
int line_num = GetScriptLineNumber(script, shared->start_position());
if (line_num > 0) {
- PROFILE(ISOLATE,
+ PROFILE(isolate_,
CodeCreateEvent(
Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
*code, *shared,
*script_name, line_num + 1));
} else {
// Can't distinguish eval and script here, so always use Script.
- PROFILE(ISOLATE,
+ PROFILE(isolate_,
CodeCreateEvent(
Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
*code, *shared, *script_name));
}
} else {
- PROFILE(ISOLATE,
+ PROFILE(isolate_,
CodeCreateEvent(
Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
*code, *shared, *func_name));
@@ -1745,10 +1812,10 @@
CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
Object* callback_obj = call_data->callback();
Address entry_point = v8::ToCData<Address>(callback_obj);
- PROFILE(ISOLATE, CallbackEvent(*func_name, entry_point));
+ PROFILE(isolate_, CallbackEvent(*func_name, entry_point));
}
} else {
- PROFILE(ISOLATE,
+ PROFILE(isolate_,
CodeCreateEvent(
Logger::LAZY_COMPILE_TAG, *code, *shared, *func_name));
}
@@ -1789,11 +1856,11 @@
Address getter_entry = v8::ToCData<Address>(ai->getter());
Name* name = Name::cast(ai->name());
if (getter_entry != 0) {
- PROFILE(ISOLATE, GetterCallbackEvent(name, getter_entry));
+ PROFILE(isolate_, GetterCallbackEvent(name, getter_entry));
}
Address setter_entry = v8::ToCData<Address>(ai->setter());
if (setter_entry != 0) {
- PROFILE(ISOLATE, SetterCallbackEvent(name, setter_entry));
+ PROFILE(isolate_, SetterCallbackEvent(name, setter_entry));
}
}
}
diff --git a/src/log.h b/src/log.h
index 5c121bc..a5eddc7 100644
--- a/src/log.h
+++ b/src/log.h
@@ -77,6 +77,7 @@
class Ticker;
class Isolate;
class PositionsRecorder;
+class CpuProfiler;
#undef LOG
#define LOG(isolate, Call) \
diff --git a/src/macros.py b/src/macros.py
index 291a898..92ed437 100644
--- a/src/macros.py
+++ b/src/macros.py
@@ -99,7 +99,7 @@
macro IS_NUMBER(arg) = (typeof(arg) === 'number');
macro IS_STRING(arg) = (typeof(arg) === 'string');
macro IS_BOOLEAN(arg) = (typeof(arg) === 'boolean');
-macro IS_SYMBOL(arg) = (%_IsSymbol(arg));
+macro IS_SYMBOL(arg) = (typeof(arg) === 'symbol');
macro IS_OBJECT(arg) = (%_IsObject(arg));
macro IS_ARRAY(arg) = (%_IsArray(arg));
macro IS_FUNCTION(arg) = (%_IsFunction(arg));
@@ -110,11 +110,13 @@
macro IS_DATE(arg) = (%_ClassOf(arg) === 'Date');
macro IS_NUMBER_WRAPPER(arg) = (%_ClassOf(arg) === 'Number');
macro IS_STRING_WRAPPER(arg) = (%_ClassOf(arg) === 'String');
+macro IS_SYMBOL_WRAPPER(arg) = (%_ClassOf(arg) === 'Symbol');
macro IS_BOOLEAN_WRAPPER(arg) = (%_ClassOf(arg) === 'Boolean');
macro IS_ERROR(arg) = (%_ClassOf(arg) === 'Error');
macro IS_SCRIPT(arg) = (%_ClassOf(arg) === 'Script');
macro IS_ARGUMENTS(arg) = (%_ClassOf(arg) === 'Arguments');
macro IS_GLOBAL(arg) = (%_ClassOf(arg) === 'global');
+macro IS_ARRAYBUFFER(arg) = (%_ClassOf(arg) === '__ArrayBuffer');
macro IS_UNDETECTABLE(arg) = (%_IsUndetectableObject(arg));
macro FLOOR(arg) = $floor(arg);
@@ -141,6 +143,7 @@
macro NUMBER_IS_NAN(arg) = (!%_IsSmi(%IS_VAR(arg)) && !(arg == arg));
macro NUMBER_IS_FINITE(arg) = (%_IsSmi(%IS_VAR(arg)) || ((arg == arg) && (arg != 1/0) && (arg != -1/0)));
macro TO_INTEGER(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : %NumberToInteger(ToNumber(arg)));
+macro TO_POSITIVE_INTEGER(arg) = (%_IsSmi(%IS_VAR(arg)) ? (arg > 0 ? arg : 0) : %NumberToPositiveInteger(ToNumber(arg)));
macro TO_INTEGER_MAP_MINUS_ZERO(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : %NumberToIntegerMapMinusZero(ToNumber(arg)));
macro TO_INT32(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : (arg >> 0));
macro TO_UINT32(arg) = (arg >>> 0);
diff --git a/src/messages.js b/src/messages.js
index 7353444..d51d384 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -100,6 +100,7 @@
observe_notify_non_notifier: ["notify called on non-notifier object"],
// RangeError
invalid_array_length: ["Invalid array length"],
+ invalid_array_buffer_length: ["Invalid array buffer length"],
stack_overflow: ["Maximum call stack size exceeded"],
invalid_time_value: ["Invalid time value"],
// SyntaxError
@@ -150,6 +151,7 @@
cant_prevent_ext_external_array_elements: ["Cannot prevent extension of an object with external array elements"],
redef_external_array_element: ["Cannot redefine a property of an object with external array elements"],
harmony_const_assign: ["Assignment to constant variable."],
+ symbol_to_string: ["Conversion from symbol to string"],
invalid_module_path: ["Module does not export '", "%0", "', or export is not itself a module"],
module_type_error: ["Module '", "%0", "' used improperly"],
module_export_undefined: ["Export '", "%0", "' is not defined in module"],
@@ -745,64 +747,70 @@
function GetStackTraceLine(recv, fun, pos, isGlobal) {
- return new CallSite(recv, fun, pos).toString();
+ return new CallSite(recv, fun, pos, false).toString();
}
// ----------------------------------------------------------------------------
// Error implementation
-function CallSite(receiver, fun, pos) {
- this.receiver = receiver;
- this.fun = fun;
- this.pos = pos;
+var CallSiteReceiverKey = %CreateSymbol("receiver");
+var CallSiteFunctionKey = %CreateSymbol("function");
+var CallSitePositionKey = %CreateSymbol("position");
+var CallSiteStrictModeKey = %CreateSymbol("strict mode");
+
+function CallSite(receiver, fun, pos, strict_mode) {
+ this[CallSiteReceiverKey] = receiver;
+ this[CallSiteFunctionKey] = fun;
+ this[CallSitePositionKey] = pos;
+ this[CallSiteStrictModeKey] = strict_mode;
}
function CallSiteGetThis() {
- return this.receiver;
+ return this[CallSiteStrictModeKey] ? void 0 : this[CallSiteReceiverKey];
}
function CallSiteGetTypeName() {
- return GetTypeName(this, false);
+ return GetTypeName(this[CallSiteReceiverKey], false);
}
function CallSiteIsToplevel() {
- if (this.receiver == null) {
+ if (this[CallSiteReceiverKey] == null) {
return true;
}
- return IS_GLOBAL(this.receiver);
+ return IS_GLOBAL(this[CallSiteReceiverKey]);
}
function CallSiteIsEval() {
- var script = %FunctionGetScript(this.fun);
+ var script = %FunctionGetScript(this[CallSiteFunctionKey]);
return script && script.compilation_type == COMPILATION_TYPE_EVAL;
}
function CallSiteGetEvalOrigin() {
- var script = %FunctionGetScript(this.fun);
+ var script = %FunctionGetScript(this[CallSiteFunctionKey]);
return FormatEvalOrigin(script);
}
function CallSiteGetScriptNameOrSourceURL() {
- var script = %FunctionGetScript(this.fun);
+ var script = %FunctionGetScript(this[CallSiteFunctionKey]);
return script ? script.nameOrSourceURL() : null;
}
function CallSiteGetFunction() {
- return this.fun;
+ return this[CallSiteStrictModeKey] ? void 0 : this[CallSiteFunctionKey];
}
function CallSiteGetFunctionName() {
// See if the function knows its own name
- var name = this.fun.name;
+ var name = this[CallSiteFunctionKey].name;
if (name) {
return name;
}
- name = %FunctionGetInferredName(this.fun);
+ name = %FunctionGetInferredName(this[CallSiteFunctionKey]);
if (name) {
return name;
}
// Maybe this is an evaluation?
- var script = %FunctionGetScript(this.fun);
+ var script = %FunctionGetScript(this[CallSiteFunctionKey]);
if (script && script.compilation_type == COMPILATION_TYPE_EVAL) {
return "eval";
}
@@ -812,26 +820,22 @@
function CallSiteGetMethodName() {
// See if we can find a unique property on the receiver that holds
// this function.
- var ownName = this.fun.name;
- if (ownName && this.receiver &&
- (%_CallFunction(this.receiver,
- ownName,
- ObjectLookupGetter) === this.fun ||
- %_CallFunction(this.receiver,
- ownName,
- ObjectLookupSetter) === this.fun ||
- (IS_OBJECT(this.receiver) &&
- %GetDataProperty(this.receiver, ownName) === this.fun))) {
+ var receiver = this[CallSiteReceiverKey];
+ var fun = this[CallSiteFunctionKey];
+ var ownName = fun.name;
+ if (ownName && receiver &&
+ (%_CallFunction(receiver, ownName, ObjectLookupGetter) === fun ||
+ %_CallFunction(receiver, ownName, ObjectLookupSetter) === fun ||
+ (IS_OBJECT(receiver) && %GetDataProperty(receiver, ownName) === fun))) {
// To handle DontEnum properties we guess that the method has
// the same name as the function.
return ownName;
}
var name = null;
- for (var prop in this.receiver) {
- if (%_CallFunction(this.receiver, prop, ObjectLookupGetter) === this.fun ||
- %_CallFunction(this.receiver, prop, ObjectLookupSetter) === this.fun ||
- (IS_OBJECT(this.receiver) &&
- %GetDataProperty(this.receiver, prop) === this.fun)) {
+ for (var prop in receiver) {
+ if (%_CallFunction(receiver, prop, ObjectLookupGetter) === fun ||
+ %_CallFunction(receiver, prop, ObjectLookupSetter) === fun ||
+ (IS_OBJECT(receiver) && %GetDataProperty(receiver, prop) === fun)) {
// If we find more than one match bail out to avoid confusion.
if (name) {
return null;
@@ -846,49 +850,49 @@
}
function CallSiteGetFileName() {
- var script = %FunctionGetScript(this.fun);
+ var script = %FunctionGetScript(this[CallSiteFunctionKey]);
return script ? script.name : null;
}
function CallSiteGetLineNumber() {
- if (this.pos == -1) {
+ if (this[CallSitePositionKey] == -1) {
return null;
}
- var script = %FunctionGetScript(this.fun);
+ var script = %FunctionGetScript(this[CallSiteFunctionKey]);
var location = null;
if (script) {
- location = script.locationFromPosition(this.pos, true);
+ location = script.locationFromPosition(this[CallSitePositionKey], true);
}
return location ? location.line + 1 : null;
}
function CallSiteGetColumnNumber() {
- if (this.pos == -1) {
+ if (this[CallSitePositionKey] == -1) {
return null;
}
- var script = %FunctionGetScript(this.fun);
+ var script = %FunctionGetScript(this[CallSiteFunctionKey]);
var location = null;
if (script) {
- location = script.locationFromPosition(this.pos, true);
+ location = script.locationFromPosition(this[CallSitePositionKey], true);
}
return location ? location.column + 1: null;
}
function CallSiteIsNative() {
- var script = %FunctionGetScript(this.fun);
+ var script = %FunctionGetScript(this[CallSiteFunctionKey]);
return script ? (script.type == TYPE_NATIVE) : false;
}
function CallSiteGetPosition() {
- return this.pos;
+ return this[CallSitePositionKey];
}
function CallSiteIsConstructor() {
- var receiver = this.receiver;
+ var receiver = this[CallSiteReceiverKey];
var constructor =
IS_OBJECT(receiver) ? %GetDataProperty(receiver, "constructor") : null;
if (!constructor) return false;
- return this.fun === constructor;
+ return this[CallSiteFunctionKey] === constructor;
}
function CallSiteToString() {
@@ -931,7 +935,7 @@
var isConstructor = this.isConstructor();
var isMethodCall = !(this.isToplevel() || isConstructor);
if (isMethodCall) {
- var typeName = GetTypeName(this, true);
+ var typeName = GetTypeName(this[CallSiteReceiverKey], true);
var methodName = this.getMethodName();
if (functionName) {
if (typeName &&
@@ -1035,13 +1039,15 @@
function GetStackFrames(raw_stack) {
var frames = new InternalArray();
- for (var i = 0; i < raw_stack.length; i += 4) {
+ var non_strict_frames = raw_stack[0];
+ for (var i = 1; i < raw_stack.length; i += 4) {
var recv = raw_stack[i];
var fun = raw_stack[i + 1];
var code = raw_stack[i + 2];
var pc = raw_stack[i + 3];
var pos = %FunctionGetPositionForOffset(code, pc);
- frames.push(new CallSite(recv, fun, pos));
+ non_strict_frames--;
+ frames.push(new CallSite(recv, fun, pos, (non_strict_frames < 0)));
}
return frames;
}
@@ -1069,16 +1075,16 @@
}
-function GetTypeName(obj, requireConstructor) {
- var constructor = obj.receiver.constructor;
+function GetTypeName(receiver, requireConstructor) {
+ var constructor = receiver.constructor;
if (!constructor) {
return requireConstructor ? null :
- %_CallFunction(obj.receiver, ObjectToString);
+ %_CallFunction(receiver, ObjectToString);
}
var constructorName = constructor.name;
if (!constructorName) {
return requireConstructor ? null :
- %_CallFunction(obj.receiver, ObjectToString);
+ %_CallFunction(receiver, ObjectToString);
}
return constructorName;
}
diff --git a/src/mips/builtins-mips.cc b/src/mips/builtins-mips.cc
index 54efd94..1901f9c 100644
--- a/src/mips/builtins-mips.cc
+++ b/src/mips/builtins-mips.cc
@@ -227,13 +227,12 @@
(JSArray::kSize + FixedArray::kHeaderSize) / kPointerSize);
__ sra(scratch1, array_size, kSmiTagSize);
__ Addu(elements_array_end, elements_array_end, scratch1);
- __ AllocateInNewSpace(
- elements_array_end,
- result,
- scratch1,
- scratch2,
- gc_required,
- static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS));
+ __ Allocate(elements_array_end,
+ result,
+ scratch1,
+ scratch2,
+ gc_required,
+ static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS));
// Allocated the JSArray. Now initialize the fields except for the elements
// array.
@@ -895,7 +894,7 @@
// a1: constructor function
// a2: initial map
__ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
- __ AllocateInNewSpace(a3, t4, t5, t6, &rt_call, SIZE_IN_WORDS);
+ __ Allocate(a3, t4, t5, t6, &rt_call, SIZE_IN_WORDS);
// Allocated the JSObject, now initialize the fields. Map is set to
// initial map and properties and elements are set to empty fixed array.
@@ -974,7 +973,7 @@
// t4: JSObject
// t5: start of next object
__ Addu(a0, a3, Operand(FixedArray::kHeaderSize / kPointerSize));
- __ AllocateInNewSpace(
+ __ Allocate(
a0,
t5,
t6,
@@ -1130,10 +1129,6 @@
__ GetObjectType(v0, a1, a3);
__ Branch(&exit, greater_equal, a3, Operand(FIRST_SPEC_OBJECT_TYPE));
- // Symbols are "objects".
- __ lbu(a3, FieldMemOperand(a1, Map::kInstanceTypeOffset));
- __ Branch(&exit, eq, a3, Operand(SYMBOL_TYPE));
-
// Throw away the result of the constructor invocation and use the
// on-stack receiver as the result.
__ bind(&use_receiver);
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index a13cb93..37d7720 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -96,7 +96,7 @@
// stack param count needs (constructor pointer, and single argument)
descriptor->stack_parameter_count_ = &a0;
descriptor->register_params_ = registers;
- descriptor->extra_expression_stack_count_ = 1;
+ descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
descriptor->deoptimization_handler_ =
FUNCTION_ADDR(ArrayConstructor_StubFailure);
}
@@ -684,6 +684,8 @@
Register scratch1,
Register scratch2,
Label* not_number) {
+ ASSERT(!object.is(dst1) && !object.is(dst2));
+
__ AssertRootValue(heap_number_map,
Heap::kHeapNumberMapRootIndex,
"HeapNumberMap register clobbered.");
@@ -878,6 +880,10 @@
ASSERT(!heap_number_map.is(object) &&
!heap_number_map.is(scratch1) &&
!heap_number_map.is(scratch2));
+ // ARM uses pop/push and Ldlr to save dst_* and probably object registers in
+ // softfloat path. On MIPS there is no ldlr, 1st lw instruction may overwrite
+ // object register making the 2nd lw invalid.
+ ASSERT(!object.is(dst_mantissa) && !object.is(dst_exponent));
Label done, obj_is_not_smi;
@@ -914,49 +920,24 @@
if (destination == kCoreRegisters) {
__ Move(dst_mantissa, dst_exponent, double_dst);
}
-
} else {
- ASSERT(!scratch1.is(object) && !scratch2.is(object));
// Load the double value in the destination registers.
- bool save_registers = object.is(dst_mantissa) || object.is(dst_exponent);
- if (save_registers) {
- // Save both output registers, because the other one probably holds
- // an important value too.
- __ Push(dst_exponent, dst_mantissa);
- }
__ lw(dst_exponent, FieldMemOperand(object, HeapNumber::kExponentOffset));
__ lw(dst_mantissa, FieldMemOperand(object, HeapNumber::kMantissaOffset));
// Check for 0 and -0.
- Label zero;
__ And(scratch1, dst_exponent, Operand(~HeapNumber::kSignMask));
__ Or(scratch1, scratch1, Operand(dst_mantissa));
- __ Branch(&zero, eq, scratch1, Operand(zero_reg));
+ __ Branch(&done, eq, scratch1, Operand(zero_reg));
// Check that the value can be exactly represented by a 32-bit integer.
// Jump to not_int32 if that's not the case.
- Label restore_input_and_miss;
DoubleIs32BitInteger(masm, dst_exponent, dst_mantissa, scratch1, scratch2,
- &restore_input_and_miss);
+ not_int32);
// dst_* were trashed. Reload the double value.
- if (save_registers) {
- __ Pop(dst_exponent, dst_mantissa);
- }
__ lw(dst_exponent, FieldMemOperand(object, HeapNumber::kExponentOffset));
__ lw(dst_mantissa, FieldMemOperand(object, HeapNumber::kMantissaOffset));
- __ Branch(&done);
-
- __ bind(&restore_input_and_miss);
- if (save_registers) {
- __ Pop(dst_exponent, dst_mantissa);
- }
- __ Branch(not_int32);
-
- __ bind(&zero);
- if (save_registers) {
- __ Drop(2);
- }
}
__ bind(&done);
@@ -2707,16 +2688,20 @@
masm, destination, right, f14, a2, a3, heap_number_map,
scratch1, scratch2, fail);
}
+ // Use scratch3 as left in LoadNumber functions to avoid overwriting of
+ // left (a0) register.
+ __ mov(scratch3, left);
+
// Load left operand to f12 or a0/a1. This keeps a0/a1 intact if it
// jumps to |miss|.
if (left_type == BinaryOpIC::INT32) {
FloatingPointHelper::LoadNumberAsInt32Double(
- masm, left, destination, f12, f16, a0, a1, heap_number_map,
+ masm, scratch3, destination, f12, f16, a0, a1, heap_number_map,
scratch1, scratch2, f2, miss);
} else {
Label* fail = (left_type == BinaryOpIC::NUMBER) ? miss : not_numbers;
FloatingPointHelper::LoadNumber(
- masm, destination, left, f12, a0, a1, heap_number_map,
+ masm, destination, scratch3, f12, a0, a1, heap_number_map,
scratch1, scratch2, fail);
}
}
@@ -4555,35 +4540,6 @@
}
-void ArrayLengthStub::Generate(MacroAssembler* masm) {
- Label miss;
- Register receiver;
- if (kind() == Code::KEYED_LOAD_IC) {
- // ----------- S t a t e -------------
- // -- ra : return address
- // -- a0 : key
- // -- a1 : receiver
- // -----------------------------------
- __ Branch(&miss, ne, a0,
- Operand(masm->isolate()->factory()->length_string()));
- receiver = a1;
- } else {
- ASSERT(kind() == Code::LOAD_IC);
- // ----------- S t a t e -------------
- // -- a2 : name
- // -- ra : return address
- // -- a0 : receiver
- // -- sp[0] : receiver
- // -----------------------------------
- receiver = a0;
- }
-
- StubCompiler::GenerateLoadArrayLength(masm, receiver, a3, &miss);
- __ bind(&miss);
- StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind()));
-}
-
-
void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
Label miss;
Register receiver;
@@ -4872,7 +4828,7 @@
__ Addu(t5, t5, Operand(Heap::kArgumentsObjectSize));
// Do the allocation of all three objects in one go.
- __ AllocateInNewSpace(t5, v0, a3, t0, &runtime, TAG_OBJECT);
+ __ Allocate(t5, v0, a3, t0, &runtime, TAG_OBJECT);
// v0 = address of new object(s) (tagged)
// a2 = argument count (tagged)
@@ -5063,13 +5019,8 @@
__ Addu(a1, a1, Operand(Heap::kArgumentsObjectSizeStrict / kPointerSize));
// Do the allocation of both objects in one go.
- __ AllocateInNewSpace(a1,
- v0,
- a2,
- a3,
- &runtime,
- static_cast<AllocationFlags>(TAG_OBJECT |
- SIZE_IN_WORDS));
+ __ Allocate(a1, v0, a2, a3, &runtime,
+ static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS));
// Get the arguments boilerplate from the current native context.
__ lw(t0, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
@@ -5589,7 +5540,7 @@
(JSRegExpResult::kSize + FixedArray::kHeaderSize) / kPointerSize;
__ srl(t1, a1, kSmiTagSize + kSmiShiftSize);
__ Addu(a2, t1, Operand(objects_size));
- __ AllocateInNewSpace(
+ __ Allocate(
a2, // In: Size, in words.
v0, // Out: Start of allocation (tagged).
a3, // Scratch register.
@@ -8136,6 +8087,9 @@
int parameter_count_offset =
StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
__ lw(a1, MemOperand(fp, parameter_count_offset));
+ if (function_mode_ == JS_FUNCTION_STUB_MODE) {
+ __ Addu(a1, a1, Operand(1));
+ }
masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE);
__ sll(a1, a1, kPointerSizeLog2);
__ Addu(sp, sp, a1);
diff --git a/src/mips/codegen-mips.cc b/src/mips/codegen-mips.cc
index 967bb5b..bd403ce 100644
--- a/src/mips/codegen-mips.cc
+++ b/src/mips/codegen-mips.cc
@@ -206,8 +206,9 @@
// Allocate new FixedDoubleArray.
__ sll(scratch, t1, 2);
__ Addu(scratch, scratch, FixedDoubleArray::kHeaderSize);
- __ AllocateInNewSpace(scratch, t2, t3, t5, &gc_required, NO_ALLOCATION_FLAGS);
+ __ Allocate(scratch, t2, t3, t5, &gc_required, NO_ALLOCATION_FLAGS);
// t2: destination FixedDoubleArray, not tagged as heap object
+
// Set destination FixedDoubleArray's length and map.
__ LoadRoot(t5, Heap::kFixedDoubleArrayMapRootIndex);
__ sw(t1, MemOperand(t2, FixedDoubleArray::kLengthOffset));
@@ -351,7 +352,7 @@
// Allocate new FixedArray.
__ sll(a0, t1, 1);
__ Addu(a0, a0, FixedDoubleArray::kHeaderSize);
- __ AllocateInNewSpace(a0, t2, t3, t5, &gc_required, NO_ALLOCATION_FLAGS);
+ __ Allocate(a0, t2, t3, t5, &gc_required, NO_ALLOCATION_FLAGS);
// t2: destination FixedArray, not tagged as heap object
// Set destination FixedDoubleArray's length and map.
__ LoadRoot(t5, Heap::kFixedArrayMapRootIndex);
diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc
index bacec10..3e7c8da 100644
--- a/src/mips/full-codegen-mips.cc
+++ b/src/mips/full-codegen-mips.cc
@@ -2780,28 +2780,6 @@
}
-void FullCodeGenerator::EmitIsSymbol(CallRuntime* expr) {
- ZoneList<Expression*>* args = expr->arguments();
- ASSERT(args->length() == 1);
-
- VisitForAccumulatorValue(args->at(0));
-
- Label materialize_true, materialize_false;
- Label* if_true = NULL;
- Label* if_false = NULL;
- Label* fall_through = NULL;
- context()->PrepareTest(&materialize_true, &materialize_false,
- &if_true, &if_false, &fall_through);
-
- __ JumpIfSmi(v0, if_false);
- __ GetObjectType(v0, a1, a2);
- PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
- Split(eq, a2, Operand(SYMBOL_TYPE), if_true, if_false, fall_through);
-
- context()->Plug(if_true, if_false);
-}
-
-
void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
ASSERT(args->length() == 1);
@@ -4320,6 +4298,10 @@
__ And(a1, a1, Operand(1 << Map::kIsUndetectable));
Split(eq, a1, Operand(zero_reg),
if_true, if_false, fall_through);
+ } else if (check->Equals(isolate()->heap()->symbol_string())) {
+ __ JumpIfSmi(v0, if_false);
+ __ GetObjectType(v0, v0, a1);
+ Split(eq, a1, Operand(SYMBOL_TYPE), if_true, if_false, fall_through);
} else if (check->Equals(isolate()->heap()->boolean_string())) {
__ LoadRoot(at, Heap::kTrueValueRootIndex);
__ Branch(if_true, eq, v0, Operand(at));
@@ -4351,10 +4333,6 @@
__ LoadRoot(at, Heap::kNullValueRootIndex);
__ Branch(if_true, eq, v0, Operand(at));
}
- if (FLAG_harmony_symbols) {
- __ GetObjectType(v0, v0, a1);
- __ Branch(if_true, eq, a1, Operand(SYMBOL_TYPE));
- }
// Check for JS objects => true.
__ GetObjectType(v0, v0, a1);
__ Branch(if_false, lt, a1, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc
index c32be4f..b5d6c45 100644
--- a/src/mips/lithium-codegen-mips.cc
+++ b/src/mips/lithium-codegen-mips.cc
@@ -1492,13 +1492,6 @@
}
-void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
- Register result = ToRegister(instr->result());
- Register array = ToRegister(instr->value());
- __ lw(result, FieldMemOperand(array, JSArray::kLengthOffset));
-}
-
-
void LCodeGen::DoFixedArrayBaseLength(LFixedArrayBaseLength* instr) {
Register result = ToRegister(instr->result());
Register array = ToRegister(instr->value());
@@ -1901,6 +1894,13 @@
__ bind(¬_string);
}
+ if (expected.Contains(ToBooleanStub::SYMBOL)) {
+ // Symbol value -> true.
+ const Register scratch = scratch1();
+ __ lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
+ __ Branch(true_label, eq, scratch, Operand(SYMBOL_TYPE));
+ }
+
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
CpuFeatureScope scope(masm(), FPU);
// heap number -> false iff +0, -0, or NaN.
@@ -4571,10 +4571,11 @@
// Convert unsigned integer with specified number of leading zeroes in binary
// representation to IEEE 754 double.
-// Integer to convert is passed in register hiword.
+// Integer to convert is passed in register src.
// Resulting double is returned in registers hiword:loword.
// This functions does not work correctly for 0.
static void GenerateUInt2Double(MacroAssembler* masm,
+ Register src,
Register hiword,
Register loword,
Register scratch,
@@ -4588,12 +4589,12 @@
kBitsPerInt - mantissa_shift_for_hi_word;
masm->li(scratch, Operand(biased_exponent << HeapNumber::kExponentShift));
if (mantissa_shift_for_hi_word > 0) {
- masm->sll(loword, hiword, mantissa_shift_for_lo_word);
- masm->srl(hiword, hiword, mantissa_shift_for_hi_word);
+ masm->sll(loword, src, mantissa_shift_for_lo_word);
+ masm->srl(hiword, src, mantissa_shift_for_hi_word);
masm->Or(hiword, scratch, hiword);
} else {
masm->mov(loword, zero_reg);
- masm->sll(hiword, hiword, mantissa_shift_for_hi_word);
+ masm->sll(hiword, src, mantissa_shift_for_hi_word);
masm->Or(hiword, scratch, hiword);
}
@@ -4644,17 +4645,17 @@
__ mtc1(src, dbl_scratch);
__ Cvt_d_uw(dbl_scratch, dbl_scratch, f22);
} else {
- Label no_leading_zero, done;
+ Label no_leading_zero, convert_done;
__ And(at, src, Operand(0x80000000));
__ Branch(&no_leading_zero, ne, at, Operand(zero_reg));
// Integer has one leading zeros.
- GenerateUInt2Double(masm(), sfpd_hi, sfpd_lo, t0, 1);
- __ Branch(&done);
+ GenerateUInt2Double(masm(), src, sfpd_hi, sfpd_lo, t0, 1);
+ __ Branch(&convert_done);
__ bind(&no_leading_zero);
- GenerateUInt2Double(masm(), sfpd_hi, sfpd_lo, t0, 0);
- __ Branch(&done);
+ GenerateUInt2Double(masm(), src, sfpd_hi, sfpd_lo, t0, 0);
+ __ bind(&convert_done);
}
}
@@ -5344,12 +5345,12 @@
__ Allocate(size, result, scratch, scratch2, deferred->entry(), flags);
} else {
Register size = ToRegister(instr->size());
- __ AllocateInNewSpace(size,
- result,
- scratch,
- scratch2,
- deferred->entry(),
- flags);
+ __ Allocate(size,
+ result,
+ scratch,
+ scratch2,
+ deferred->entry(),
+ flags);
}
__ bind(deferred->exit());
@@ -5771,6 +5772,13 @@
cmp2 = Operand(zero_reg);
final_branch_condition = eq;
+ } else if (type_name->Equals(heap()->symbol_string())) {
+ __ JumpIfSmi(input, false_label);
+ __ GetObjectType(input, input, scratch);
+ cmp1 = scratch;
+ cmp2 = Operand(SYMBOL_TYPE);
+ final_branch_condition = eq;
+
} else if (type_name->Equals(heap()->boolean_string())) {
__ LoadRoot(at, Heap::kTrueValueRootIndex);
__ Branch(USE_DELAY_SLOT, true_label, eq, at, Operand(input));
@@ -5814,27 +5822,15 @@
__ LoadRoot(at, Heap::kNullValueRootIndex);
__ Branch(USE_DELAY_SLOT, true_label, eq, at, Operand(input));
}
- if (FLAG_harmony_symbols) {
- // input is an object, it is safe to use GetObjectType in the delay slot.
- __ GetObjectType(input, input, scratch);
- __ Branch(USE_DELAY_SLOT, true_label, eq, scratch, Operand(SYMBOL_TYPE));
- // Still an object, so the InstanceType can be loaded.
- __ lbu(scratch, FieldMemOperand(input, Map::kInstanceTypeOffset));
- __ Branch(USE_DELAY_SLOT, false_label,
- lt, scratch, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
- } else {
- // input is an object, it is safe to use GetObjectType in the delay slot.
- __ GetObjectType(input, input, scratch);
- __ Branch(USE_DELAY_SLOT, false_label,
- lt, scratch, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
- }
- // Still an object, so the InstanceType can be loaded.
- __ lbu(scratch, FieldMemOperand(input, Map::kInstanceTypeOffset));
+ Register map = input;
+ __ GetObjectType(input, map, scratch);
+ __ Branch(false_label,
+ lt, scratch, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
__ Branch(USE_DELAY_SLOT, false_label,
gt, scratch, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
- // Still an object, so the BitField can be loaded.
+ // map is still valid, so the BitField can be loaded in delay slot.
// Check for undetectable objects => false.
- __ lbu(at, FieldMemOperand(input, Map::kBitFieldOffset));
+ __ lbu(at, FieldMemOperand(map, Map::kBitFieldOffset));
__ And(at, at, 1 << Map::kIsUndetectable);
cmp1 = at;
cmp2 = Operand(zero_reg);
diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc
index 8848032..652c7ca 100644
--- a/src/mips/lithium-mips.cc
+++ b/src/mips/lithium-mips.cc
@@ -871,6 +871,35 @@
LInstruction* instr = current->CompileToLithium(this);
if (instr != NULL) {
+#if DEBUG
+ // Make sure that the lithium instruction has either no fixed register
+ // constraints in temps or the result OR no uses that are only used at
+ // start. If this invariant doesn't hold, the register allocator can decide
+ // to insert a split of a range immediately before the instruction due to an
+ // already allocated register needing to be used for the instruction's fixed
+ // register constraint. In this case, The register allocator won't see an
+ // interference between the split child and the use-at-start (it would if
+ // the it was just a plain use), so it is free to move the split child into
+ // the same register that is used for the use-at-start.
+ // See https://code.google.com/p/chromium/issues/detail?id=201590
+ if (!(instr->ClobbersRegisters() && instr->ClobbersDoubleRegisters())) {
+ int fixed = 0;
+ int used_at_start = 0;
+ for (UseIterator it(instr); !it.Done(); it.Advance()) {
+ LUnallocated* operand = LUnallocated::cast(it.Current());
+ if (operand->IsUsedAtStart()) ++used_at_start;
+ }
+ if (instr->Output() != NULL) {
+ if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed;
+ }
+ for (TempIterator it(instr); !it.Done(); it.Advance()) {
+ LUnallocated* operand = LUnallocated::cast(it.Current());
+ if (operand->HasFixedPolicy()) ++fixed;
+ }
+ ASSERT(fixed == 0 || used_at_start == 0);
+ }
+#endif
+
if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
instr = AssignPointerMap(instr);
}
@@ -1116,7 +1145,7 @@
LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, temp);
return DefineFixedDouble(result, f4);
} else {
- LOperand* input = UseRegisterAtStart(instr->value());
+ LOperand* input = UseRegister(instr->value());
LOperand* temp = (op == kMathRound) ? FixedTemp(f6) :
(op == kMathFloor) ? TempRegister() : NULL;
@@ -1585,12 +1614,6 @@
}
-LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
- LOperand* array = UseRegisterAtStart(instr->value());
- return DefineAsRegister(new(zone()) LJSArrayLength(array));
-}
-
-
LInstruction* LChunkBuilder::DoFixedArrayBaseLength(
HFixedArrayBaseLength* instr) {
LOperand* array = UseRegisterAtStart(instr->value());
@@ -1697,11 +1720,13 @@
return AssignEnvironment(DefineAsRegister(res));
} else {
ASSERT(to.IsInteger32());
- LOperand* value = UseRegisterAtStart(instr->value());
+ LOperand* value = NULL;
LInstruction* res = NULL;
if (instr->value()->type().IsSmi()) {
+ value = UseRegisterAtStart(instr->value());
res = DefineAsRegister(new(zone()) LSmiUntag(value, false));
} else {
+ value = UseRegister(instr->value());
LOperand* temp1 = TempRegister();
LOperand* temp2 = instr->CanTruncateToInt32() ? TempRegister()
: NULL;
@@ -2081,7 +2106,7 @@
LOperand* new_map_reg = TempRegister();
LTransitionElementsKind* result =
new(zone()) LTransitionElementsKind(object, new_map_reg, NULL);
- return DefineSameAsFirst(result);
+ return result;
} else if (FLAG_compiled_transitions) {
LTransitionElementsKind* result =
new(zone()) LTransitionElementsKind(object, NULL, NULL);
diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h
index 80635c3..e995905 100644
--- a/src/mips/lithium-mips.h
+++ b/src/mips/lithium-mips.h
@@ -120,7 +120,6 @@
V(IsStringAndBranch) \
V(IsSmiAndBranch) \
V(IsUndetectableAndBranch) \
- V(JSArrayLength) \
V(Label) \
V(LazyBailout) \
V(LoadContextSlot) \
@@ -291,7 +290,6 @@
SetOncePointer<LPointerMap> pointer_map_;
HValue* hydrogen_value_;
bool is_call_;
- bool is_save_doubles_;
};
@@ -1111,19 +1109,6 @@
};
-class LJSArrayLength: public LTemplateInstruction<1, 1, 0> {
- public:
- explicit LJSArrayLength(LOperand* value) {
- inputs_[0] = value;
- }
-
- LOperand* value() { return inputs_[0]; }
-
- DECLARE_CONCRETE_INSTRUCTION(JSArrayLength, "js-array-length")
- DECLARE_HYDROGEN_ACCESSOR(JSArrayLength)
-};
-
-
class LFixedArrayBaseLength: public LTemplateInstruction<1, 1, 0> {
public:
explicit LFixedArrayBaseLength(LOperand* value) {
@@ -2060,7 +2045,7 @@
};
-class LTransitionElementsKind: public LTemplateInstruction<1, 1, 2> {
+class LTransitionElementsKind: public LTemplateInstruction<0, 1, 2> {
public:
LTransitionElementsKind(LOperand* object,
LOperand* new_map_temp,
diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc
index 33ff9ab..12e1025 100644
--- a/src/mips/macro-assembler-mips.cc
+++ b/src/mips/macro-assembler-mips.cc
@@ -1928,7 +1928,7 @@
BranchDelaySlot bdslot) {
BRANCH_ARGS_CHECK(cond, rs, rt);
- int32_t offset;
+ int32_t offset = 0;
Register r2 = no_reg;
Register scratch = at;
if (rt.is_reg()) {
@@ -2361,7 +2361,7 @@
BranchDelaySlot bdslot) {
BRANCH_ARGS_CHECK(cond, rs, rt);
- int32_t offset;
+ int32_t offset = 0;
Register r2 = no_reg;
Register scratch = at;
if (rt.is_reg()) {
@@ -3002,13 +3002,12 @@
}
-void MacroAssembler::AllocateInNewSpace(Register object_size,
- Register result,
- Register scratch1,
- Register scratch2,
- Label* gc_required,
- AllocationFlags flags) {
- ASSERT((flags & PRETENURE_OLD_POINTER_SPACE) == 0);
+void MacroAssembler::Allocate(Register object_size,
+ Register result,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required,
+ AllocationFlags flags) {
if (!FLAG_inline_new) {
if (emit_debug_code()) {
// Trash the registers to simulate an allocation failure.
@@ -3029,19 +3028,19 @@
// Check relative positions of allocation top and limit addresses.
// ARM adds additional checks to make sure the ldm instruction can be
// used. On MIPS we don't have ldm so we don't need additional checks either.
- ExternalReference new_space_allocation_top =
- ExternalReference::new_space_allocation_top_address(isolate());
- ExternalReference new_space_allocation_limit =
- ExternalReference::new_space_allocation_limit_address(isolate());
+ ExternalReference allocation_top =
+ AllocationUtils::GetAllocationTopReference(isolate(), flags);
+ ExternalReference allocation_limit =
+ AllocationUtils::GetAllocationLimitReference(isolate(), flags);
intptr_t top =
- reinterpret_cast<intptr_t>(new_space_allocation_top.address());
+ reinterpret_cast<intptr_t>(allocation_top.address());
intptr_t limit =
- reinterpret_cast<intptr_t>(new_space_allocation_limit.address());
+ reinterpret_cast<intptr_t>(allocation_limit.address());
ASSERT((limit - top) == kPointerSize);
// Set up allocation top address and object size registers.
Register topaddr = scratch1;
- li(topaddr, Operand(new_space_allocation_top));
+ li(topaddr, Operand(allocation_top));
// This code stores a temporary value in t9.
if ((flags & RESULT_CONTAINS_TOP) == 0) {
@@ -3120,12 +3119,12 @@
And(scratch1, scratch1, Operand(~kObjectAlignmentMask));
// Allocate two-byte string in new space.
- AllocateInNewSpace(scratch1,
- result,
- scratch2,
- scratch3,
- gc_required,
- TAG_OBJECT);
+ Allocate(scratch1,
+ result,
+ scratch2,
+ scratch3,
+ gc_required,
+ TAG_OBJECT);
// Set the map, length and hash field.
InitializeNewString(result,
@@ -3150,12 +3149,12 @@
And(scratch1, scratch1, Operand(~kObjectAlignmentMask));
// Allocate ASCII string in new space.
- AllocateInNewSpace(scratch1,
- result,
- scratch2,
- scratch3,
- gc_required,
- TAG_OBJECT);
+ Allocate(scratch1,
+ result,
+ scratch2,
+ scratch3,
+ gc_required,
+ TAG_OBJECT);
// Set the map, length and hash field.
InitializeNewString(result,
@@ -5515,7 +5514,6 @@
CodePatcher::CodePatcher(byte* address, int instructions)
: address_(address),
- instructions_(instructions),
size_(instructions * Assembler::kInstrSize),
masm_(NULL, address, size_ + Assembler::kGap) {
// Create a new macro assembler pointing to the address of the code to patch.
diff --git a/src/mips/macro-assembler-mips.h b/src/mips/macro-assembler-mips.h
index e4cf3bc..125cc8a 100644
--- a/src/mips/macro-assembler-mips.h
+++ b/src/mips/macro-assembler-mips.h
@@ -491,12 +491,12 @@
Label* gc_required,
AllocationFlags flags);
- void AllocateInNewSpace(Register object_size,
- Register result,
- Register scratch1,
- Register scratch2,
- Label* gc_required,
- AllocationFlags flags);
+ void Allocate(Register object_size,
+ Register result,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required,
+ AllocationFlags flags);
// Undo allocation in new space. The object passed and objects allocated after
// it will no longer be allocated. The caller must make sure that no pointers
@@ -1565,7 +1565,6 @@
private:
byte* address_; // The address of the code being patched.
- int instructions_; // Number of instructions of the expected patch size.
int size_; // Number of bytes of the expected patch size.
MacroAssembler masm_; // Macro assembler used to generate the code.
};
diff --git a/src/mips/simulator-mips.cc b/src/mips/simulator-mips.cc
index be9f369..5eb79eb 100644
--- a/src/mips/simulator-mips.cc
+++ b/src/mips/simulator-mips.cc
@@ -132,8 +132,8 @@
ASSERT(msg != NULL);
// Update this stop description.
- if (!watched_stops[code].desc) {
- watched_stops[code].desc = msg;
+ if (!watched_stops_[code].desc) {
+ watched_stops_[code].desc = msg;
}
if (strlen(msg) > 0) {
@@ -163,8 +163,8 @@
char* msg = *reinterpret_cast<char**>(sim_->get_pc() +
Instruction::kInstrSize);
// Update this stop description.
- if (!sim_->watched_stops[code].desc) {
- sim_->watched_stops[code].desc = msg;
+ if (!sim_->watched_stops_[code].desc) {
+ sim_->watched_stops_[code].desc = msg;
}
PrintF("Simulator hit %s (%u)\n", msg, code);
sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstrSize);
@@ -513,7 +513,7 @@
int32_t words;
if (argc == next_arg) {
words = 10;
- } else if (argc == next_arg + 1) {
+ } else {
if (!GetValue(argv[next_arg], &words)) {
words = 10;
}
@@ -1636,33 +1636,33 @@
bool Simulator::IsEnabledStop(uint32_t code) {
ASSERT(code <= kMaxStopCode);
ASSERT(code > kMaxWatchpointCode);
- return !(watched_stops[code].count & kStopDisabledBit);
+ return !(watched_stops_[code].count & kStopDisabledBit);
}
void Simulator::EnableStop(uint32_t code) {
if (!IsEnabledStop(code)) {
- watched_stops[code].count &= ~kStopDisabledBit;
+ watched_stops_[code].count &= ~kStopDisabledBit;
}
}
void Simulator::DisableStop(uint32_t code) {
if (IsEnabledStop(code)) {
- watched_stops[code].count |= kStopDisabledBit;
+ watched_stops_[code].count |= kStopDisabledBit;
}
}
void Simulator::IncreaseStopCounter(uint32_t code) {
ASSERT(code <= kMaxStopCode);
- if ((watched_stops[code].count & ~(1 << 31)) == 0x7fffffff) {
+ if ((watched_stops_[code].count & ~(1 << 31)) == 0x7fffffff) {
PrintF("Stop counter for code %i has overflowed.\n"
"Enabling this code and reseting the counter to 0.\n", code);
- watched_stops[code].count = 0;
+ watched_stops_[code].count = 0;
EnableStop(code);
} else {
- watched_stops[code].count++;
+ watched_stops_[code].count++;
}
}
@@ -1677,12 +1677,12 @@
return;
}
const char* state = IsEnabledStop(code) ? "Enabled" : "Disabled";
- int32_t count = watched_stops[code].count & ~kStopDisabledBit;
+ int32_t count = watched_stops_[code].count & ~kStopDisabledBit;
// Don't print the state of unused breakpoints.
if (count != 0) {
- if (watched_stops[code].desc) {
+ if (watched_stops_[code].desc) {
PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n",
- code, code, state, count, watched_stops[code].desc);
+ code, code, state, count, watched_stops_[code].desc);
} else {
PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n",
code, code, state, count);
diff --git a/src/mips/simulator-mips.h b/src/mips/simulator-mips.h
index 67f5953..ed63443 100644
--- a/src/mips/simulator-mips.h
+++ b/src/mips/simulator-mips.h
@@ -391,14 +391,14 @@
static const uint32_t kStopDisabledBit = 1 << 31;
// A stop is enabled, meaning the simulator will stop when meeting the
- // instruction, if bit 31 of watched_stops[code].count is unset.
- // The value watched_stops[code].count & ~(1 << 31) indicates how many times
+ // instruction, if bit 31 of watched_stops_[code].count is unset.
+ // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
// the breakpoint was hit or gone through.
struct StopCountAndDesc {
uint32_t count;
char* desc;
};
- StopCountAndDesc watched_stops[kMaxStopCode + 1];
+ StopCountAndDesc watched_stops_[kMaxStopCode + 1];
};
diff --git a/src/mips/stub-cache-mips.cc b/src/mips/stub-cache-mips.cc
index d5cf6de..da6770a 100644
--- a/src/mips/stub-cache-mips.cc
+++ b/src/mips/stub-cache-mips.cc
@@ -415,7 +415,7 @@
// may be clobbered.
void StubCompiler::GenerateStoreField(MacroAssembler* masm,
Handle<JSObject> object,
- int index,
+ LookupResult* lookup,
Handle<Map> transition,
Handle<Name> name,
Register receiver_reg,
@@ -428,16 +428,6 @@
// a0 : value.
Label exit;
- LookupResult lookup(masm->isolate());
- object->Lookup(*name, &lookup);
- if (lookup.IsFound() && (lookup.IsReadOnly() || !lookup.IsCacheable())) {
- // In sloppy mode, we could just return the value and be done. However, we
- // might be in strict mode, where we have to throw. Since we cannot tell,
- // go into slow case unconditionally.
- __ jmp(miss_label);
- return;
- }
-
// Check that the map of the object hasn't changed.
CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
: REQUIRE_EXACT_MAP;
@@ -452,8 +442,9 @@
// Check that we are allowed to write this.
if (!transition.is_null() && object->GetPrototype()->IsJSObject()) {
JSObject* holder;
- if (lookup.IsFound()) {
- holder = lookup.holder();
+ // holder == object indicates that no property was found.
+ if (lookup->holder() != *object) {
+ holder = lookup->holder();
} else {
// Find the top object.
holder = *object;
@@ -461,8 +452,19 @@
holder = JSObject::cast(holder->GetPrototype());
} while (holder->GetPrototype()->IsJSObject());
}
- CheckPrototypes(object, receiver_reg, Handle<JSObject>(holder), name_reg,
- scratch1, scratch2, name, miss_restore_name);
+ Register holder_reg = CheckPrototypes(
+ object, receiver_reg, Handle<JSObject>(holder), name_reg,
+ scratch1, scratch2, name, miss_restore_name);
+ // If no property was found, and the holder (the last object in the
+ // prototype chain) is in slow mode, we need to do a negative lookup on the
+ // holder.
+ if (lookup->holder() == *object &&
+ !holder->HasFastProperties() &&
+ !holder->IsJSGlobalProxy() &&
+ !holder->IsJSGlobalObject()) {
+ GenerateDictionaryNegativeLookup(
+ masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
+ }
}
// Stub never generated for non-global objects that require access
@@ -483,6 +485,7 @@
return;
}
+ int index;
if (!transition.is_null()) {
// Update the map of the object.
__ li(scratch1, Operand(transition));
@@ -498,6 +501,10 @@
kDontSaveFPRegs,
OMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
+ index = transition->instance_descriptors()->GetFieldIndex(
+ transition->LastAdded());
+ } else {
+ index = lookup->GetFieldIndex().field_index();
}
// Adjust for the number of properties stored in the object. Even in the
@@ -2424,6 +2431,12 @@
// Check that the object is a symbol.
__ GetObjectType(a1, a1, a3);
__ Branch(&miss, ne, a3, Operand(SYMBOL_TYPE));
+ // Check that the maps starting from the prototype haven't changed.
+ GenerateDirectLoadGlobalFunctionPrototype(
+ masm(), Context::SYMBOL_FUNCTION_INDEX, a0, &miss);
+ CheckPrototypes(
+ Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
+ a0, holder, a3, a1, t0, name, &miss);
break;
case NUMBER_CHECK: {
@@ -3010,7 +3023,7 @@
__ Check(eq, "Instance size of initial map changed.",
a3, Operand(instance_size >> kPointerSizeLog2));
#endif
- __ AllocateInNewSpace(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS);
+ __ Allocate(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS);
// Allocated the JSObject, now initialize the fields. Map is set to initial
// map and properties and elements are set to empty fixed array.
diff --git a/src/mirror-debugger.js b/src/mirror-debugger.js
index 7f1a05a..e1fd872 100644
--- a/src/mirror-debugger.js
+++ b/src/mirror-debugger.js
@@ -638,7 +638,7 @@
// Find all the named properties.
if (kind & PropertyKind.Named) {
// Get the local property names.
- propertyNames = %GetLocalPropertyNames(this.value_);
+ propertyNames = %GetLocalPropertyNames(this.value_, true);
total += propertyNames.length;
// Get names for named interceptor properties if any.
diff --git a/src/object-observe.js b/src/object-observe.js
index b35f547..bfb4a65 100644
--- a/src/object-observe.js
+++ b/src/object-observe.js
@@ -117,6 +117,9 @@
}
function EnqueueChangeRecord(changeRecord, observers) {
+ // TODO(rossberg): adjust once there is a story for symbols vs proxies.
+ if (IS_SYMBOL(changeRecord.name)) return;
+
for (var i = 0; i < observers.length; i++) {
var observer = observers[i];
var observerInfo = observerInfoMap.get(observer);
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index 82a71a5..44cab53 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -195,6 +195,9 @@
case JS_MESSAGE_OBJECT_TYPE:
JSMessageObject::cast(this)->JSMessageObjectVerify();
break;
+ case JS_ARRAY_BUFFER_TYPE:
+ JSArrayBuffer::cast(this)->JSArrayBufferVerify();
+ break;
#define MAKE_STRUCT_CASE(NAME, Name, name) \
case NAME##_TYPE: \
@@ -220,6 +223,7 @@
CHECK(IsSymbol());
CHECK(HasHashCode());
CHECK_GT(Hash(), 0);
+ CHECK(name()->IsUndefined() || name()->IsString());
}
@@ -711,6 +715,14 @@
VerifyPointer(construct_trap());
}
+void JSArrayBuffer::JSArrayBufferVerify() {
+ CHECK(IsJSArrayBuffer());
+ JSObjectVerify();
+ VerifyPointer(byte_length());
+ CHECK(byte_length()->IsSmi() || byte_length()->IsHeapNumber()
+ || byte_length()->IsUndefined());
+}
+
void Foreign::ForeignVerify() {
CHECK(IsForeign());
diff --git a/src/objects-inl.h b/src/objects-inl.h
index ba0a7f8..ec03405 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -674,6 +674,7 @@
TYPE_CHECKER(JSArray, JS_ARRAY_TYPE)
+TYPE_CHECKER(JSArrayBuffer, JS_ARRAY_BUFFER_TYPE)
TYPE_CHECKER(JSRegExp, JS_REGEXP_TYPE)
@@ -1490,13 +1491,17 @@
bool JSObject::TryTransitionToField(Handle<JSObject> object,
Handle<Name> key) {
if (!object->map()->HasTransitionArray()) return false;
- TransitionArray* transitions = object->map()->transitions();
- int transition = transitions->Search(*key);
- if (transition == TransitionArray::kNotFound) return false;
- PropertyDetails target_details = transitions->GetTargetDetails(transition);
- if (target_details.type() != FIELD) return false;
- if (target_details.attributes() != NONE) return false;
- Handle<Map> target(transitions->GetTarget(transition));
+ Handle<Map> target;
+ {
+ AssertNoAllocation no_allocation;
+ TransitionArray* transitions = object->map()->transitions();
+ int transition = transitions->Search(*key);
+ if (transition == TransitionArray::kNotFound) return false;
+ PropertyDetails target_details = transitions->GetTargetDetails(transition);
+ if (target_details.type() != FIELD) return false;
+ if (target_details.attributes() != NONE) return false;
+ target = Handle<Map>(transitions->GetTarget(transition));
+ }
JSObject::AddFastPropertyUsingMap(object, target);
return true;
}
@@ -1558,6 +1563,8 @@
return JSDate::kSize;
case JS_ARRAY_TYPE:
return JSArray::kSize;
+ case JS_ARRAY_BUFFER_TYPE:
+ return JSArrayBuffer::kSize;
case JS_SET_TYPE:
return JSSet::kSize;
case JS_MAP_TYPE:
@@ -2444,6 +2451,7 @@
CAST_ACCESSOR(JSBuiltinsObject)
CAST_ACCESSOR(Code)
CAST_ACCESSOR(JSArray)
+CAST_ACCESSOR(JSArrayBuffer)
CAST_ACCESSOR(JSRegExp)
CAST_ACCESSOR(JSProxy)
CAST_ACCESSOR(JSFunctionProxy)
@@ -2500,11 +2508,17 @@
bool Name::Equals(Name* other) {
if (other == this) return true;
- if (this->IsUniqueName() && other->IsUniqueName()) return false;
+ if (this->IsSymbol() || other->IsSymbol() ||
+ (this->IsInternalizedString() && other->IsInternalizedString())) {
+ return false;
+ }
return String::cast(this)->SlowEquals(String::cast(other));
}
+ACCESSORS(Symbol, name, Object, kNameOffset)
+
+
bool String::Equals(String* other) {
if (other == this) return true;
if (this->IsInternalizedString() && other->IsInternalizedString()) {
@@ -4508,6 +4522,7 @@
kDontOptimize)
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, dont_inline, kDontInline)
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, dont_cache, kDontCache)
+BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_generator, kIsGenerator)
void SharedFunctionInfo::BeforeVisitingPointers() {
if (IsInobjectSlackTrackingInProgress()) DetachInitialMap();
@@ -5124,6 +5139,21 @@
ACCESSORS(JSArray, length, Object, kLengthOffset)
+void* JSArrayBuffer::backing_store() {
+ intptr_t ptr = READ_INTPTR_FIELD(this, kBackingStoreOffset);
+ return reinterpret_cast<void*>(ptr);
+}
+
+
+void JSArrayBuffer::set_backing_store(void* value, WriteBarrierMode mode) {
+ intptr_t ptr = reinterpret_cast<intptr_t>(value);
+ WRITE_INTPTR_FIELD(this, kBackingStoreOffset, ptr);
+}
+
+
+ACCESSORS(JSArrayBuffer, byte_length, Object, kByteLengthOffset)
+
+
ACCESSORS(JSRegExp, data, Object, kDataOffset)
diff --git a/src/objects-printer.cc b/src/objects-printer.cc
index 4522ee4..8342232 100644
--- a/src/objects-printer.cc
+++ b/src/objects-printer.cc
@@ -184,6 +184,8 @@
case JS_GLOBAL_PROPERTY_CELL_TYPE:
JSGlobalPropertyCell::cast(this)->JSGlobalPropertyCellPrint(out);
break;
+ case JS_ARRAY_BUFFER_TYPE:
+ JSArrayBuffer::cast(this)->JSArrayBufferPrint(out);
#define MAKE_STRUCT_CASE(NAME, Name, name) \
case NAME##_TYPE: \
Name::cast(this)->Name##Print(out); \
@@ -552,6 +554,9 @@
void Symbol::SymbolPrint(FILE* out) {
HeapObject::PrintHeader(out, "Symbol");
PrintF(out, " - hash: %d\n", Hash());
+ PrintF(out, " - name: ");
+ name()->ShortPrint();
+ PrintF(out, "\n");
}
@@ -792,6 +797,16 @@
}
+void JSArrayBuffer::JSArrayBufferPrint(FILE* out) {
+ HeapObject::PrintHeader(out, "JSArrayBuffer");
+ PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
+ PrintF(out, " - backing_store = -0x%p\n", backing_store());
+ PrintF(out, " - byte_length = ");
+ byte_length()->ShortPrint(out);
+ PrintF(out, "\n");
+}
+
+
void JSFunction::JSFunctionPrint(FILE* out) {
HeapObject::PrintHeader(out, "Function");
PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
diff --git a/src/objects-visiting-inl.h b/src/objects-visiting-inl.h
index 2b7fcf3..6a64cbf 100644
--- a/src/objects-visiting-inl.h
+++ b/src/objects-visiting-inl.h
@@ -49,6 +49,11 @@
SlicedString::BodyDescriptor,
int>::Visit);
+ table_.Register(kVisitSymbol,
+ &FixedBodyVisitor<StaticVisitor,
+ Symbol::BodyDescriptor,
+ int>::Visit);
+
table_.Register(kVisitFixedArray,
&FlexibleBodyVisitor<StaticVisitor,
FixedArray::BodyDescriptor,
@@ -110,6 +115,11 @@
SlicedString::BodyDescriptor,
void>::Visit);
+ table_.Register(kVisitSymbol,
+ &FixedBodyVisitor<StaticVisitor,
+ Symbol::BodyDescriptor,
+ void>::Visit);
+
table_.Register(kVisitFixedArray, &FixedArrayVisitor::Visit);
table_.Register(kVisitFixedDoubleArray, &DataObjectVisitor::Visit);
diff --git a/src/objects-visiting.cc b/src/objects-visiting.cc
index 088f5eb..fa53562 100644
--- a/src/objects-visiting.cc
+++ b/src/objects-visiting.cc
@@ -129,9 +129,7 @@
Foreign::kSize);
case SYMBOL_TYPE:
- return GetVisitorIdForSize(kVisitDataObject,
- kVisitDataObjectGeneric,
- Symbol::kSize);
+ return kVisitSymbol;
case FILLER_TYPE:
return kVisitDataObjectGeneric;
@@ -146,6 +144,7 @@
case JS_GLOBAL_OBJECT_TYPE:
case JS_BUILTINS_OBJECT_TYPE:
case JS_MESSAGE_OBJECT_TYPE:
+ case JS_ARRAY_BUFFER_TYPE:
return GetVisitorIdForSize(kVisitJSObject,
kVisitJSObjectGeneric,
instance_size);
diff --git a/src/objects-visiting.h b/src/objects-visiting.h
index 9b2422c..d4a2ed2 100644
--- a/src/objects-visiting.h
+++ b/src/objects-visiting.h
@@ -84,6 +84,7 @@
V(StructGeneric) \
V(ConsString) \
V(SlicedString) \
+ V(Symbol) \
V(Oddball) \
V(Code) \
V(Map) \
diff --git a/src/objects.cc b/src/objects.cc
index dbbec58..8f03b10 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -98,6 +98,10 @@
Isolate* isolate = HeapObject::cast(this)->GetIsolate();
Context* native_context = isolate->context()->native_context();
return CreateJSValue(native_context->string_function(), this);
+ } else if (IsSymbol()) {
+ Isolate* isolate = HeapObject::cast(this)->GetIsolate();
+ Context* native_context = isolate->context()->native_context();
+ return CreateJSValue(native_context->symbol_function(), this);
}
// Throw a type error.
@@ -126,10 +130,10 @@
holder = native_context->number_function()->instance_prototype();
} else if (IsString()) {
holder = native_context->string_function()->instance_prototype();
+ } else if (IsSymbol()) {
+ holder = native_context->symbol_function()->instance_prototype();
} else if (IsBoolean()) {
holder = native_context->boolean_function()->instance_prototype();
- } else if (IsSymbol()) {
- holder = native_context->symbol_delegate();
} else {
Isolate::Current()->PushStackTraceAndDie(
0xDEAD0000, this, JSReceiver::cast(this)->map(), 0xDEAD0001);
@@ -375,6 +379,9 @@
Handle<Object> receiver(receiver_raw, isolate);
Handle<Object> name(name_raw, isolate);
+ // TODO(rossberg): adjust once there is a story for symbols vs proxies.
+ if (name->IsSymbol()) return isolate->heap()->undefined_value();
+
Handle<Object> args[] = { receiver, name };
Handle<Object> result = CallTrap(
"get", isolate->derived_get_trap(), ARRAY_SIZE(args), args);
@@ -756,7 +763,7 @@
// holder in the prototype chain.
// Proxy handlers do not use the proxy's prototype, so we can skip this.
if (!result->IsHandler()) {
- Object* last = result->IsProperty() && !receiver->IsSymbol()
+ Object* last = result->IsProperty()
? result->holder()
: Object::cast(heap->null_value());
ASSERT(this != this->GetPrototype(isolate));
@@ -837,10 +844,10 @@
holder = native_context->number_function()->instance_prototype();
} else if (holder->IsString()) {
holder = native_context->string_function()->instance_prototype();
+ } else if (holder->IsSymbol()) {
+ holder = native_context->symbol_function()->instance_prototype();
} else if (holder->IsBoolean()) {
holder = native_context->boolean_function()->instance_prototype();
- } else if (holder->IsSymbol()) {
- holder = native_context->symbol_delegate();
} else if (holder->IsJSProxy()) {
return JSProxy::cast(holder)->GetElementWithHandler(receiver, index);
} else {
@@ -900,6 +907,9 @@
if (heap_object->IsString()) {
return context->string_function()->instance_prototype();
}
+ if (heap_object->IsSymbol()) {
+ return context->symbol_function()->instance_prototype();
+ }
if (heap_object->IsBoolean()) {
return context->boolean_function()->instance_prototype();
} else {
@@ -908,16 +918,6 @@
}
-Object* Object::GetDelegate(Isolate* isolate) {
- if (IsSymbol()) {
- Heap* heap = Symbol::cast(this)->GetHeap();
- Context* context = heap->isolate()->context()->native_context();
- return context->symbol_delegate();
- }
- return GetPrototype(isolate);
-}
-
-
MaybeObject* Object::GetHash(CreationFlag flag) {
// The object is either a number, a name, an odd-ball,
// a real JS object, or a Harmony proxy.
@@ -1467,9 +1467,16 @@
accumulator->Add("<Odd Oddball>");
break;
}
- case SYMBOL_TYPE:
- accumulator->Add("<Symbol: %d>", Symbol::cast(this)->Hash());
+ case SYMBOL_TYPE: {
+ Symbol* symbol = Symbol::cast(this);
+ accumulator->Add("<Symbol: %d", symbol->Hash());
+ if (!symbol->name()->IsUndefined()) {
+ accumulator->Add(" ");
+ String::cast(symbol->name())->StringShortPrint(accumulator);
+ }
+ accumulator->Add(">");
break;
+ }
case HEAP_NUMBER_TYPE:
accumulator->Add("<Number: ");
HeapNumber::cast(this)->HeapNumberPrint(accumulator);
@@ -1543,6 +1550,7 @@
case JS_VALUE_TYPE:
case JS_DATE_TYPE:
case JS_ARRAY_TYPE:
+ case JS_ARRAY_BUFFER_TYPE:
case JS_SET_TYPE:
case JS_MAP_TYPE:
case JS_WEAK_MAP_TYPE:
@@ -1579,6 +1587,8 @@
JSGlobalPropertyCell::BodyDescriptor::IterateBody(this, v);
break;
case SYMBOL_TYPE:
+ Symbol::BodyDescriptor::IterateBody(this, v);
+ break;
case HEAP_NUMBER_TYPE:
case FILLER_TYPE:
case BYTE_ARRAY_TYPE:
@@ -1728,7 +1738,7 @@
// hidden strings) and is not a real identifier.
// Normalize the object if it will have too many fast properties.
Isolate* isolate = GetHeap()->isolate();
- if ((!IsIdentifier(isolate->unicode_cache(), name)
+ if ((!name->IsSymbol() && !IsIdentifier(isolate->unicode_cache(), name)
&& name != isolate->heap()->hidden_string()) ||
(map()->unused_property_fields() == 0 &&
TooManyFastProperties(properties()->length(), store_mode))) {
@@ -2755,6 +2765,9 @@
Handle<Object> receiver(this, isolate);
Handle<Object> name(name_raw, isolate);
+ // TODO(rossberg): adjust once there is a story for symbols vs proxies.
+ if (name->IsSymbol()) return false;
+
Handle<Object> args[] = { name };
Handle<Object> result = CallTrap(
"has", isolate->derived_has_trap(), ARRAY_SIZE(args), args);
@@ -2776,6 +2789,9 @@
Handle<Object> name(name_raw, isolate);
Handle<Object> value(value_raw, isolate);
+ // TODO(rossberg): adjust once there is a story for symbols vs proxies.
+ if (name->IsSymbol()) return *value;
+
Handle<Object> args[] = { receiver, name, value };
CallTrap("set", isolate->derived_set_trap(), ARRAY_SIZE(args), args);
if (isolate->has_pending_exception()) return Failure::Exception();
@@ -2798,6 +2814,12 @@
Handle<Object> value(value_raw, isolate);
Handle<Object> handler(this->handler(), isolate); // Trap might morph proxy.
+ // TODO(rossberg): adjust once there is a story for symbols vs proxies.
+ if (name->IsSymbol()) {
+ *done = false;
+ return isolate->heap()->the_hole_value();
+ }
+
*done = true; // except where redefined...
Handle<Object> args[] = { name };
Handle<Object> result = proxy->CallTrap(
@@ -2806,7 +2828,7 @@
if (result->IsUndefined()) {
*done = false;
- return GetHeap()->the_hole_value();
+ return isolate->heap()->the_hole_value();
}
// Emulate [[GetProperty]] semantics for proxies.
@@ -2887,6 +2909,9 @@
Handle<JSProxy> receiver(this);
Handle<Object> name(name_raw, isolate);
+ // TODO(rossberg): adjust once there is a story for symbols vs proxies.
+ if (name->IsSymbol()) return isolate->heap()->false_value();
+
Handle<Object> args[] = { name };
Handle<Object> result = CallTrap(
"delete", Handle<Object>(), ARRAY_SIZE(args), args);
@@ -2927,6 +2952,9 @@
Handle<JSReceiver> receiver(receiver_raw);
Handle<Object> name(name_raw, isolate);
+ // TODO(rossberg): adjust once there is a story for symbols vs proxies.
+ if (name->IsSymbol()) return ABSENT;
+
Handle<Object> args[] = { name };
Handle<Object> result = CallTrap(
"getPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args);
@@ -4665,6 +4693,145 @@
}
+MUST_USE_RESULT MaybeObject* JSObject::DeepCopy(Isolate* isolate) {
+ StackLimitCheck check(isolate);
+ if (check.HasOverflowed()) return isolate->StackOverflow();
+
+ Heap* heap = isolate->heap();
+ Object* result;
+ { MaybeObject* maybe_result = heap->CopyJSObject(this);
+ if (!maybe_result->ToObject(&result)) return maybe_result;
+ }
+ JSObject* copy = JSObject::cast(result);
+
+ // Deep copy local properties.
+ if (copy->HasFastProperties()) {
+ FixedArray* properties = copy->properties();
+ for (int i = 0; i < properties->length(); i++) {
+ Object* value = properties->get(i);
+ if (value->IsJSObject()) {
+ JSObject* js_object = JSObject::cast(value);
+ { MaybeObject* maybe_result = js_object->DeepCopy(isolate);
+ if (!maybe_result->ToObject(&result)) return maybe_result;
+ }
+ properties->set(i, result);
+ }
+ }
+ int nof = copy->map()->inobject_properties();
+ for (int i = 0; i < nof; i++) {
+ Object* value = copy->InObjectPropertyAt(i);
+ if (value->IsJSObject()) {
+ JSObject* js_object = JSObject::cast(value);
+ { MaybeObject* maybe_result = js_object->DeepCopy(isolate);
+ if (!maybe_result->ToObject(&result)) return maybe_result;
+ }
+ copy->InObjectPropertyAtPut(i, result);
+ }
+ }
+ } else {
+ { MaybeObject* maybe_result =
+ heap->AllocateFixedArray(copy->NumberOfLocalProperties());
+ if (!maybe_result->ToObject(&result)) return maybe_result;
+ }
+ FixedArray* names = FixedArray::cast(result);
+ copy->GetLocalPropertyNames(names, 0);
+ for (int i = 0; i < names->length(); i++) {
+ ASSERT(names->get(i)->IsString());
+ String* key_string = String::cast(names->get(i));
+ PropertyAttributes attributes =
+ copy->GetLocalPropertyAttribute(key_string);
+ // Only deep copy fields from the object literal expression.
+ // In particular, don't try to copy the length attribute of
+ // an array.
+ if (attributes != NONE) continue;
+ Object* value =
+ copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
+ if (value->IsJSObject()) {
+ JSObject* js_object = JSObject::cast(value);
+ { MaybeObject* maybe_result = js_object->DeepCopy(isolate);
+ if (!maybe_result->ToObject(&result)) return maybe_result;
+ }
+ { MaybeObject* maybe_result =
+ // Creating object copy for literals. No strict mode needed.
+ copy->SetProperty(key_string, result, NONE, kNonStrictMode);
+ if (!maybe_result->ToObject(&result)) return maybe_result;
+ }
+ }
+ }
+ }
+
+ // Deep copy local elements.
+ // Pixel elements cannot be created using an object literal.
+ ASSERT(!copy->HasExternalArrayElements());
+ switch (copy->GetElementsKind()) {
+ case FAST_SMI_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS: {
+ FixedArray* elements = FixedArray::cast(copy->elements());
+ if (elements->map() == heap->fixed_cow_array_map()) {
+ isolate->counters()->cow_arrays_created_runtime()->Increment();
+#ifdef DEBUG
+ for (int i = 0; i < elements->length(); i++) {
+ ASSERT(!elements->get(i)->IsJSObject());
+ }
+#endif
+ } else {
+ for (int i = 0; i < elements->length(); i++) {
+ Object* value = elements->get(i);
+ ASSERT(value->IsSmi() ||
+ value->IsTheHole() ||
+ (IsFastObjectElementsKind(copy->GetElementsKind())));
+ if (value->IsJSObject()) {
+ JSObject* js_object = JSObject::cast(value);
+ { MaybeObject* maybe_result = js_object->DeepCopy(isolate);
+ if (!maybe_result->ToObject(&result)) return maybe_result;
+ }
+ elements->set(i, result);
+ }
+ }
+ }
+ break;
+ }
+ case DICTIONARY_ELEMENTS: {
+ SeededNumberDictionary* element_dictionary = copy->element_dictionary();
+ int capacity = element_dictionary->Capacity();
+ for (int i = 0; i < capacity; i++) {
+ Object* k = element_dictionary->KeyAt(i);
+ if (element_dictionary->IsKey(k)) {
+ Object* value = element_dictionary->ValueAt(i);
+ if (value->IsJSObject()) {
+ JSObject* js_object = JSObject::cast(value);
+ { MaybeObject* maybe_result = js_object->DeepCopy(isolate);
+ if (!maybe_result->ToObject(&result)) return maybe_result;
+ }
+ element_dictionary->ValueAtPut(i, result);
+ }
+ }
+ }
+ break;
+ }
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
+ UNIMPLEMENTED();
+ break;
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
+ // No contained objects, nothing to do.
+ break;
+ }
+ return copy;
+}
+
+
// Tests for the fast common case for property enumeration:
// - This object and all prototypes has an enum cache (which means that
// it is no proxy, has no interceptors and needs no access checks).
@@ -7626,33 +7793,45 @@
}
-String* SeqString::Truncate(int new_length) {
- Heap* heap = GetHeap();
- if (new_length <= 0) return heap->empty_string();
+Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) {
+ int new_size, old_size;
+ int old_length = string->length();
+ if (old_length <= new_length) return string;
- int string_size, allocated_string_size;
- int old_length = length();
- if (old_length <= new_length) return this;
-
- if (IsSeqOneByteString()) {
- allocated_string_size = SeqOneByteString::SizeFor(old_length);
- string_size = SeqOneByteString::SizeFor(new_length);
+ if (string->IsSeqOneByteString()) {
+ old_size = SeqOneByteString::SizeFor(old_length);
+ new_size = SeqOneByteString::SizeFor(new_length);
} else {
- allocated_string_size = SeqTwoByteString::SizeFor(old_length);
- string_size = SeqTwoByteString::SizeFor(new_length);
+ ASSERT(string->IsSeqTwoByteString());
+ old_size = SeqTwoByteString::SizeFor(old_length);
+ new_size = SeqTwoByteString::SizeFor(new_length);
}
- int delta = allocated_string_size - string_size;
- set_length(new_length);
+ int delta = old_size - new_size;
+ string->set_length(new_length);
- // String sizes are pointer size aligned, so that we can use filler objects
- // that are a multiple of pointer size.
- Address end_of_string = address() + string_size;
- heap->CreateFillerObjectAt(end_of_string, delta);
- if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
- MemoryChunk::IncrementLiveBytesFromMutator(address(), -delta);
+ Address start_of_string = string->address();
+ ASSERT_OBJECT_ALIGNED(start_of_string);
+ ASSERT_OBJECT_ALIGNED(start_of_string + new_size);
+
+ Heap* heap = string->GetHeap();
+ NewSpace* newspace = heap->new_space();
+ if (newspace->Contains(start_of_string) &&
+ newspace->top() == start_of_string + old_size) {
+ // Last allocated object in new space. Simply lower allocation top.
+ *(newspace->allocation_top_address()) = start_of_string + new_size;
+ } else {
+ // Sizes are pointer size aligned, so that we can use filler objects
+ // that are a multiple of pointer size.
+ heap->CreateFillerObjectAt(start_of_string + new_size, delta);
}
- return this;
+ if (Marking::IsBlack(Marking::MarkBitFrom(start_of_string))) {
+ MemoryChunk::IncrementLiveBytesFromMutator(start_of_string, -delta);
+ }
+
+
+ if (new_length == 0) return heap->isolate()->factory()->empty_string();
+ return string;
}
@@ -8813,12 +8992,13 @@
ASSERT(Marking::Color(this) == Marking::WHITE_OBJECT);
// copy code
- CopyBytes(instruction_start(), desc.buffer, desc.instr_size);
+ CopyBytes(instruction_start(), desc.buffer,
+ static_cast<size_t>(desc.instr_size));
// copy reloc info
CopyBytes(relocation_start(),
desc.buffer + desc.buffer_size - desc.reloc_size,
- desc.reloc_size);
+ static_cast<size_t>(desc.reloc_size));
// unbox handles and relocate
intptr_t delta = instruction_start() - desc.buffer;
@@ -9751,9 +9931,14 @@
void Map::ZapTransitions() {
TransitionArray* transition_array = transitions();
- MemsetPointer(transition_array->data_start(),
- GetHeap()->the_hole_value(),
- transition_array->length());
+ // TODO(mstarzinger): Temporarily use a slower version instead of the faster
+ // MemsetPointer to investigate a crasher. Switch back to MemsetPointer.
+ Object** data = transition_array->data_start();
+ Object* the_hole = GetHeap()->the_hole_value();
+ int length = transition_array->length();
+ for (int i = 0; i < length; i++) {
+ data[i] = the_hole;
+ }
}
@@ -11586,18 +11771,22 @@
// Fill in the names of local properties into the supplied storage. The main
// purpose of this function is to provide reflection information for the object
// mirrors.
-void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) {
- ASSERT(storage->length() >= (NumberOfLocalProperties() - index));
+void JSObject::GetLocalPropertyNames(
+ FixedArray* storage, int index, PropertyAttributes filter) {
+ ASSERT(storage->length() >= (NumberOfLocalProperties(filter) - index));
if (HasFastProperties()) {
int real_size = map()->NumberOfOwnDescriptors();
DescriptorArray* descs = map()->instance_descriptors();
- ASSERT(storage->length() >= index + real_size);
for (int i = 0; i < real_size; i++) {
- storage->set(index + i, descs->GetKey(i));
+ if ((descs->GetDetails(i).attributes() & filter) == 0 &&
+ ((filter & SYMBOLIC) == 0 || !descs->GetKey(i)->IsSymbol())) {
+ storage->set(index++, descs->GetKey(i));
+ }
}
} else {
property_dictionary()->CopyKeysTo(storage,
index,
+ filter,
NameDictionary::UNSORTED);
}
}
@@ -12348,6 +12537,7 @@
template void Dictionary<NameDictionaryShape, Name*>::CopyKeysTo(
FixedArray*,
int,
+ PropertyAttributes,
Dictionary<NameDictionaryShape, Name*>::SortMode);
template int
@@ -13590,6 +13780,7 @@
void Dictionary<Shape, Key>::CopyKeysTo(
FixedArray* storage,
int index,
+ PropertyAttributes filter,
typename Dictionary<Shape, Key>::SortMode sort_mode) {
ASSERT(storage->length() >= NumberOfElementsFilterAttributes(
static_cast<PropertyAttributes>(NONE)));
@@ -13599,7 +13790,8 @@
if (HashTable<Shape, Key>::IsKey(k)) {
PropertyDetails details = DetailsAt(i);
if (details.IsDeleted()) continue;
- storage->set(index++, k);
+ PropertyAttributes attr = details.attributes();
+ if ((attr & filter) == 0) storage->set(index++, k);
}
}
if (sort_mode == Dictionary<Shape, Key>::SORTED) {
diff --git a/src/objects.h b/src/objects.h
index 933a075..37be25f 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -56,6 +56,7 @@
// - JSReceiver (suitable for property access)
// - JSObject
// - JSArray
+// - JSArrayBuffer
// - JSSet
// - JSMap
// - JSWeakMap
@@ -399,6 +400,7 @@
V(JS_BUILTINS_OBJECT_TYPE) \
V(JS_GLOBAL_PROXY_TYPE) \
V(JS_ARRAY_TYPE) \
+ V(JS_ARRAY_BUFFER_TYPE) \
V(JS_PROXY_TYPE) \
V(JS_WEAK_MAP_TYPE) \
V(JS_REGEXP_TYPE) \
@@ -729,6 +731,7 @@
JS_BUILTINS_OBJECT_TYPE,
JS_GLOBAL_PROXY_TYPE,
JS_ARRAY_TYPE,
+ JS_ARRAY_BUFFER_TYPE,
JS_SET_TYPE,
JS_MAP_TYPE,
JS_WEAK_MAP_TYPE,
@@ -974,6 +977,7 @@
V(Foreign) \
V(Boolean) \
V(JSArray) \
+ V(JSArrayBuffer) \
V(JSProxy) \
V(JSFunctionProxy) \
V(JSSet) \
@@ -1102,9 +1106,6 @@
// Return the object's prototype (might be Heap::null_value()).
Object* GetPrototype(Isolate* isolate);
- // Return the prototype, or the method holder for a value-like object.
- Object* GetDelegate(Isolate* isolate);
-
// Returns the permanent hash code associated with this object depending on
// the actual object type. Might return a failure in case no hash was
// created yet or GC was caused by creation.
@@ -2060,7 +2061,8 @@
int NumberOfLocalProperties(PropertyAttributes filter = NONE);
// Fill in details for properties into storage starting at the specified
// index.
- void GetLocalPropertyNames(FixedArray* storage, int index);
+ void GetLocalPropertyNames(
+ FixedArray* storage, int index, PropertyAttributes filter = NONE);
// Returns the number of properties on this object filtering out properties
// with the specified attributes (ignoring interceptors).
@@ -2216,6 +2218,8 @@
static Handle<Object> PreventExtensions(Handle<JSObject> object);
MUST_USE_RESULT MaybeObject* PreventExtensions();
+ // Copy object
+ MUST_USE_RESULT MaybeObject* DeepCopy(Isolate* isolate);
// Dispatched behavior.
void JSObjectShortPrint(StringStream* accumulator);
@@ -3258,7 +3262,10 @@
PropertyAttributes filter,
SortMode sort_mode);
// Fill in details for properties into storage.
- void CopyKeysTo(FixedArray* storage, int index, SortMode sort_mode);
+ void CopyKeysTo(FixedArray* storage,
+ int index,
+ PropertyAttributes filter,
+ SortMode sort_mode);
// Accessors for next enumeration index.
void SetNextEnumerationIndex(int index) {
@@ -4347,6 +4354,11 @@
NONEXISTENT
};
+ enum StubHolder {
+ OWN_STUB,
+ PROTOTYPE_STUB
+ };
+
enum {
NUMBER_OF_KINDS = LAST_IC_KIND + 1
};
@@ -4542,6 +4554,8 @@
class ExtraICStateKeyedAccessStoreMode:
public BitField<KeyedAccessStoreMode, 1, 4> {}; // NOLINT
+ class ExtraICStateStubHolder: public BitField<StubHolder, 0, 1> {};
+
static inline StrictModeFlag GetStrictMode(ExtraICState extra_ic_state) {
return ExtraICStateStrictMode::decode(extra_ic_state);
}
@@ -4558,6 +4572,10 @@
ExtraICStateStrictMode::encode(strict_mode);
}
+ static inline ExtraICState ComputeExtraICState(StubHolder stub_holder) {
+ return ExtraICStateStubHolder::encode(stub_holder);
+ }
+
// Flags operations.
static inline Flags ComputeFlags(
Kind kind,
@@ -5943,6 +5961,9 @@
// Indicates that code for this function cannot be cached.
DECL_BOOLEAN_ACCESSORS(dont_cache)
+ // Indicates that this function is a generator.
+ DECL_BOOLEAN_ACCESSORS(is_generator)
+
// Indicates whether or not the code in the shared function support
// deoptimization.
inline bool has_deoptimization_support();
@@ -6169,6 +6190,7 @@
kDontOptimize,
kDontInline,
kDontCache,
+ kIsGenerator,
kCompilerHintsCount // Pseudo entry
};
@@ -7401,6 +7423,9 @@
// ES6 symbols.
class Symbol: public Name {
public:
+ // [name]: the print name of a symbol, or undefined if none.
+ DECL_ACCESSORS(name, Object)
+
// Casting.
static inline Symbol* cast(Object* obj);
@@ -7409,7 +7434,11 @@
DECLARE_VERIFIER(Symbol)
// Layout description.
- static const int kSize = Name::kSize;
+ static const int kNameOffset = Name::kSize;
+ static const int kSize = kNameOffset + kPointerSize;
+
+ typedef FixedBodyDescriptor<kNameOffset, kNameOffset + kPointerSize, kSize>
+ BodyDescriptor;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(Symbol);
@@ -7754,8 +7783,8 @@
// Truncate the string in-place if possible and return the result.
// In case of new_length == 0, the empty string is returned without
// truncating the original string.
- MUST_USE_RESULT String* Truncate(int new_length);
-
+ MUST_USE_RESULT static Handle<String> Truncate(Handle<SeqString> string,
+ int new_length);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(SeqString);
};
@@ -8464,6 +8493,30 @@
};
+class JSArrayBuffer: public JSObject {
+ public:
+ // [backing_store]: backing memory for thsi array
+ DECL_ACCESSORS(backing_store, void)
+
+ // [byte_length]: length in bytes
+ DECL_ACCESSORS(byte_length, Object)
+
+ // Casting.
+ static inline JSArrayBuffer* cast(Object* obj);
+
+ // Dispatched behavior.
+ DECLARE_PRINTER(JSArrayBuffer)
+ DECLARE_VERIFIER(JSArrayBuffer)
+
+ static const int kBackingStoreOffset = JSObject::kHeaderSize;
+ static const int kByteLengthOffset = kBackingStoreOffset + kPointerSize;
+ static const int kSize = kByteLengthOffset + kPointerSize;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSArrayBuffer);
+};
+
+
// Foreign describes objects pointing from JavaScript to C structures.
// Since they cannot contain references to JS HeapObjects they can be
// placed in old_data_space.
diff --git a/src/parser.cc b/src/parser.cc
index cdc0adb..d1228d2 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -486,10 +486,12 @@
Parser::FunctionState::FunctionState(Parser* parser,
Scope* scope,
+ bool is_generator,
Isolate* isolate)
: next_materialized_literal_index_(JSFunction::kLiteralsPrefixSize),
next_handler_index_(0),
expected_property_count_(0),
+ is_generator_(is_generator),
only_simple_this_property_assignments_(false),
this_property_assignments_(isolate->factory()->empty_fixed_array()),
parser_(parser),
@@ -642,7 +644,10 @@
}
ParsingModeScope parsing_mode(this, mode);
- FunctionState function_state(this, scope, isolate()); // Enters 'scope'.
+ bool is_generator = false;
+ // Enters 'scope'.
+ FunctionState function_state(this, scope, is_generator, isolate());
+
top_scope_->SetLanguageMode(info->language_mode());
ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16, zone());
bool ok = true;
@@ -680,7 +685,8 @@
FunctionLiteral::kNoDuplicateParameters,
FunctionLiteral::ANONYMOUS_EXPRESSION,
FunctionLiteral::kGlobalOrEval,
- FunctionLiteral::kNotParenthesized);
+ FunctionLiteral::kNotParenthesized,
+ FunctionLiteral::kNotGenerator);
result->set_ast_properties(factory()->visitor()->ast_properties());
} else if (stack_overflow_) {
isolate()->StackOverflow();
@@ -754,7 +760,8 @@
scope = Scope::DeserializeScopeChain(info()->closure()->context(), scope,
zone());
}
- FunctionState function_state(this, scope, isolate());
+ bool is_generator = false; // Top scope is not a generator.
+ FunctionState function_state(this, scope, is_generator, isolate());
ASSERT(scope->language_mode() != STRICT_MODE || !info()->is_classic_mode());
ASSERT(scope->language_mode() != EXTENDED_MODE ||
info()->is_extended_mode());
@@ -768,6 +775,7 @@
bool ok = true;
result = ParseFunctionLiteral(name,
false, // Strict mode name already checked.
+ shared_info->is_generator(),
RelocInfo::kNoPosition,
type,
&ok);
@@ -1132,6 +1140,7 @@
// ModuleDeclaration
// ImportDeclaration
// ExportDeclaration
+ // GeneratorDeclaration
switch (peek()) {
case Token::FUNCTION:
@@ -1430,6 +1439,7 @@
// 'export' Identifier (',' Identifier)* ';'
// 'export' VariableDeclaration
// 'export' FunctionDeclaration
+ // 'export' GeneratorDeclaration
// 'export' ModuleDeclaration
//
// TODO(ES6): implement structuring ExportSpecifiers
@@ -1509,6 +1519,7 @@
// BlockElement (aka SourceElement):
// LetDeclaration
// ConstDeclaration
+ // GeneratorDeclaration
switch (peek()) {
case Token::FUNCTION:
@@ -1628,6 +1639,10 @@
// FunctionDeclaration
// Common language extension is to allow function declaration in place
// of any statement. This language extension is disabled in strict mode.
+ //
+ // In Harmony mode, this case also handles the extension:
+ // Statement:
+ // GeneratorDeclaration
if (!top_scope_->is_classic_mode()) {
ReportMessageAt(scanner().peek_location(), "strict_function",
Vector<const char*>::empty());
@@ -1890,13 +1905,18 @@
Statement* Parser::ParseFunctionDeclaration(ZoneStringList* names, bool* ok) {
// FunctionDeclaration ::
// 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
+ // GeneratorDeclaration ::
+ // 'function' '*' Identifier '(' FormalParameterListopt ')'
+ // '{' FunctionBody '}'
Expect(Token::FUNCTION, CHECK_OK);
int function_token_position = scanner().location().beg_pos;
+ bool is_generator = FLAG_harmony_generators && Check(Token::MUL);
bool is_strict_reserved = false;
Handle<String> name = ParseIdentifierOrStrictReservedWord(
&is_strict_reserved, CHECK_OK);
FunctionLiteral* fun = ParseFunctionLiteral(name,
is_strict_reserved,
+ is_generator,
function_token_position,
FunctionLiteral::DECLARATION,
CHECK_OK);
@@ -3004,8 +3024,13 @@
Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) {
// AssignmentExpression ::
// ConditionalExpression
+ // YieldExpression
// LeftHandSideExpression AssignmentOperator AssignmentExpression
+ if (peek() == Token::YIELD && is_generator()) {
+ return ParseYieldExpression(ok);
+ }
+
if (fni_ != NULL) fni_->Enter();
Expression* expression = ParseConditionalExpression(accept_IN, CHECK_OK);
@@ -3074,6 +3099,17 @@
}
+Expression* Parser::ParseYieldExpression(bool* ok) {
+ // YieldExpression ::
+ // 'yield' '*'? AssignmentExpression
+ int position = scanner().peek_location().beg_pos;
+ Expect(Token::YIELD, CHECK_OK);
+ bool is_yield_star = Check(Token::MUL);
+ Expression* expression = ParseAssignmentExpression(false, CHECK_OK);
+ return factory()->NewYield(expression, is_yield_star, position);
+}
+
+
// Precedence = 3
Expression* Parser::ParseConditionalExpression(bool accept_IN, bool* ok) {
// ConditionalExpression ::
@@ -3450,6 +3486,7 @@
if (peek() == Token::FUNCTION) {
Expect(Token::FUNCTION, CHECK_OK);
int function_token_position = scanner().location().beg_pos;
+ bool is_generator = FLAG_harmony_generators && Check(Token::MUL);
Handle<String> name;
bool is_strict_reserved_name = false;
if (peek_any_identifier()) {
@@ -3461,6 +3498,7 @@
: FunctionLiteral::NAMED_EXPRESSION;
result = ParseFunctionLiteral(name,
is_strict_reserved_name,
+ is_generator,
function_token_position,
type,
CHECK_OK);
@@ -3544,6 +3582,7 @@
case Token::FUTURE_RESERVED_WORD:
return ReportMessage("unexpected_reserved",
Vector<const char*>::empty());
+ case Token::YIELD:
case Token::FUTURE_STRICT_RESERVED_WORD:
return ReportMessage(top_scope_->is_classic_mode() ?
"unexpected_token_identifier" :
@@ -3604,6 +3643,7 @@
break;
case Token::IDENTIFIER:
+ case Token::YIELD:
case Token::FUTURE_STRICT_RESERVED_WORD: {
Handle<String> name = ParseIdentifier(CHECK_OK);
if (fni_ != NULL) fni_->PushVariableName(name);
@@ -4009,6 +4049,7 @@
FunctionLiteral* value =
ParseFunctionLiteral(name,
false, // reserved words are allowed here
+ false, // not a generator
RelocInfo::kNoPosition,
FunctionLiteral::ANONYMOUS_EXPRESSION,
CHECK_OK);
@@ -4310,6 +4351,7 @@
FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
bool name_is_strict_reserved,
+ bool is_generator,
int function_token_position,
FunctionLiteral::Type type,
bool* ok) {
@@ -4344,9 +4386,12 @@
FunctionLiteral::IsParenthesizedFlag parenthesized = parenthesized_function_
? FunctionLiteral::kIsParenthesized
: FunctionLiteral::kNotParenthesized;
+ FunctionLiteral::IsGeneratorFlag generator = is_generator
+ ? FunctionLiteral::kIsGenerator
+ : FunctionLiteral::kNotGenerator;
AstProperties ast_properties;
// Parse function body.
- { FunctionState function_state(this, scope, isolate());
+ { FunctionState function_state(this, scope, is_generator, isolate());
top_scope_->SetScopeName(function_name);
// FormalParameterList ::
@@ -4584,7 +4629,8 @@
duplicate_parameters,
type,
FunctionLiteral::kIsFunction,
- parenthesized);
+ parenthesized,
+ generator);
function_literal->set_function_token_position(function_token_position);
function_literal->set_ast_properties(&ast_properties);
@@ -4606,10 +4652,12 @@
stack_limit,
do_allow_lazy,
allow_natives_syntax_,
- allow_modules_);
+ allow_modules_,
+ FLAG_harmony_generators);
}
preparser::PreParser::PreParseResult result =
reusable_preparser_->PreParseLazyFunction(top_scope_->language_mode(),
+ is_generator(),
logger);
return result;
}
@@ -4672,7 +4720,8 @@
Token::Value next = peek();
return next == Token::IDENTIFIER ||
next == Token::FUTURE_RESERVED_WORD ||
- next == Token::FUTURE_STRICT_RESERVED_WORD;
+ next == Token::FUTURE_STRICT_RESERVED_WORD ||
+ next == Token::YIELD;
}
@@ -4744,13 +4793,17 @@
// Parses an identifier that is valid for the current scope, in particular it
// fails on strict mode future reserved keywords in a strict scope.
Handle<String> Parser::ParseIdentifier(bool* ok) {
- if (!top_scope_->is_classic_mode()) {
- Expect(Token::IDENTIFIER, ok);
- } else if (!Check(Token::IDENTIFIER)) {
- Expect(Token::FUTURE_STRICT_RESERVED_WORD, ok);
+ Token::Value next = Next();
+ if (next == Token::IDENTIFIER ||
+ (top_scope_->is_classic_mode() &&
+ (next == Token::FUTURE_STRICT_RESERVED_WORD ||
+ (next == Token::YIELD && !is_generator())))) {
+ return GetSymbol(ok);
+ } else {
+ ReportUnexpectedToken(next);
+ *ok = false;
+ return Handle<String>();
}
- if (!*ok) return Handle<String>();
- return GetSymbol(ok);
}
@@ -4758,12 +4811,17 @@
// whether it is strict mode future reserved.
Handle<String> Parser::ParseIdentifierOrStrictReservedWord(
bool* is_strict_reserved, bool* ok) {
- *is_strict_reserved = false;
- if (!Check(Token::IDENTIFIER)) {
- Expect(Token::FUTURE_STRICT_RESERVED_WORD, ok);
+ Token::Value next = Next();
+ if (next == Token::IDENTIFIER) {
+ *is_strict_reserved = false;
+ } else if (next == Token::FUTURE_STRICT_RESERVED_WORD ||
+ (next == Token::YIELD && !is_generator())) {
*is_strict_reserved = true;
+ } else {
+ ReportUnexpectedToken(next);
+ *ok = false;
+ return Handle<String>();
}
- if (!*ok) return Handle<String>();
return GetSymbol(ok);
}
@@ -5875,6 +5933,9 @@
if (FLAG_lazy && (extension == NULL)) {
flags |= kAllowLazy;
}
+ if (FLAG_harmony_generators) {
+ flags |= kAllowGenerators;
+ }
CompleteParserRecorder recorder;
return DoPreParse(source, flags, &recorder);
}
diff --git a/src/parser.h b/src/parser.h
index 6dcf7f1..fc4aba2 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -474,6 +474,7 @@
public:
FunctionState(Parser* parser,
Scope* scope,
+ bool is_generator,
Isolate* isolate);
~FunctionState();
@@ -504,6 +505,8 @@
void AddProperty() { expected_property_count_++; }
int expected_property_count() { return expected_property_count_; }
+ bool is_generator() const { return is_generator_; }
+
AstNodeFactory<AstConstructionVisitor>* factory() { return &factory_; }
private:
@@ -518,6 +521,9 @@
// Properties count estimation.
int expected_property_count_;
+ // Indicates that this function is a generator.
+ bool is_generator_;
+
// Keeps track of assignments to properties of this. Used for
// optimizing constructors.
bool only_simple_this_property_assignments_;
@@ -631,6 +637,7 @@
Expression* ParseExpression(bool accept_IN, bool* ok);
Expression* ParseAssignmentExpression(bool accept_IN, bool* ok);
+ Expression* ParseYieldExpression(bool* ok);
Expression* ParseConditionalExpression(bool accept_IN, bool* ok);
Expression* ParseBinaryExpression(int prec, bool accept_IN, bool* ok);
Expression* ParseUnaryExpression(bool* ok);
@@ -674,6 +681,7 @@
ZoneList<Expression*>* ParseArguments(bool* ok);
FunctionLiteral* ParseFunctionLiteral(Handle<String> var_name,
bool name_is_reserved,
+ bool is_generator,
int function_token_position,
FunctionLiteral::Type type,
bool* ok);
@@ -703,6 +711,8 @@
return scanner().Next();
}
+ bool is_generator() const { return current_function_state_->is_generator(); }
+
bool peek_any_identifier();
INLINE(void Consume(Token::Value token));
diff --git a/src/platform-cygwin.cc b/src/platform-cygwin.cc
index 8914d63..67c389e 100644
--- a/src/platform-cygwin.cc
+++ b/src/platform-cygwin.cc
@@ -687,13 +687,14 @@
CONTEXT context;
memset(&context, 0, sizeof(context));
+ Isolate* isolate = sampler->isolate();
TickSample sample_obj;
- TickSample* sample = CpuProfiler::TickSampleEvent(sampler->isolate());
+ TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
if (sample == NULL) sample = &sample_obj;
static const DWORD kSuspendFailed = static_cast<DWORD>(-1);
if (SuspendThread(profiled_thread) == kSuspendFailed) return;
- sample->state = sampler->isolate()->current_vm_state();
+ sample->state = isolate->current_vm_state();
context.ContextFlags = CONTEXT_FULL;
if (GetThreadContext(profiled_thread, &context) != 0) {
diff --git a/src/platform-freebsd.cc b/src/platform-freebsd.cc
index 986c5af..14f7171 100644
--- a/src/platform-freebsd.cc
+++ b/src/platform-freebsd.cc
@@ -715,7 +715,7 @@
if (sampler == NULL || !sampler->IsActive()) return;
TickSample sample_obj;
- TickSample* sample = CpuProfiler::TickSampleEvent(isolate);
+ TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
if (sample == NULL) sample = &sample_obj;
// Extracting the sample from the context is extremely machine dependent.
diff --git a/src/platform-linux.cc b/src/platform-linux.cc
index 0359b2d..1f9cde1 100644
--- a/src/platform-linux.cc
+++ b/src/platform-linux.cc
@@ -111,8 +111,10 @@
FILE* f = NULL;
const char* what = search_string;
- if (NULL == (f = fopen(file_name, "r")))
+ if (NULL == (f = fopen(file_name, "r"))) {
+ OS::PrintError("Failed to open /proc/cpuinfo\n");
return false;
+ }
int k;
while (EOF != (k = fgetc(f))) {
@@ -1088,7 +1090,7 @@
if (sampler == NULL || !sampler->IsActive()) return;
TickSample sample_obj;
- TickSample* sample = CpuProfiler::TickSampleEvent(isolate);
+ TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
if (sample == NULL) sample = &sample_obj;
// Extracting the sample from the context is extremely machine dependent.
diff --git a/src/platform-macos.cc b/src/platform-macos.cc
index fde5217..30e2b89 100644
--- a/src/platform-macos.cc
+++ b/src/platform-macos.cc
@@ -818,8 +818,9 @@
void SampleContext(Sampler* sampler) {
thread_act_t profiled_thread = sampler->platform_data()->profiled_thread();
+ Isolate* isolate = sampler->isolate();
TickSample sample_obj;
- TickSample* sample = CpuProfiler::TickSampleEvent(sampler->isolate());
+ TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
if (sample == NULL) sample = &sample_obj;
if (KERN_SUCCESS != thread_suspend(profiled_thread)) return;
@@ -850,7 +851,7 @@
flavor,
reinterpret_cast<natural_t*>(&state),
&count) == KERN_SUCCESS) {
- sample->state = sampler->isolate()->current_vm_state();
+ sample->state = isolate->current_vm_state();
sample->pc = reinterpret_cast<Address>(state.REGISTER_FIELD(ip));
sample->sp = reinterpret_cast<Address>(state.REGISTER_FIELD(sp));
sample->fp = reinterpret_cast<Address>(state.REGISTER_FIELD(bp));
diff --git a/src/platform-openbsd.cc b/src/platform-openbsd.cc
index 66eac22..e48d4cb 100644
--- a/src/platform-openbsd.cc
+++ b/src/platform-openbsd.cc
@@ -748,7 +748,7 @@
if (sampler == NULL || !sampler->IsActive()) return;
TickSample sample_obj;
- TickSample* sample = CpuProfiler::TickSampleEvent(isolate);
+ TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
if (sample == NULL) sample = &sample_obj;
// Extracting the sample from the context is extremely machine dependent.
diff --git a/src/platform-solaris.cc b/src/platform-solaris.cc
index 85ba95f..0e616d1 100644
--- a/src/platform-solaris.cc
+++ b/src/platform-solaris.cc
@@ -682,7 +682,7 @@
if (sampler == NULL || !sampler->IsActive()) return;
TickSample sample_obj;
- TickSample* sample = CpuProfiler::TickSampleEvent(isolate);
+ TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
if (sample == NULL) sample = &sample_obj;
// Extracting the sample from the context is extremely machine dependent.
diff --git a/src/platform-win32.cc b/src/platform-win32.cc
index 66dbade..c1bae93 100644
--- a/src/platform-win32.cc
+++ b/src/platform-win32.cc
@@ -2064,13 +2064,14 @@
CONTEXT context;
memset(&context, 0, sizeof(context));
+ Isolate* isolate = sampler->isolate();
TickSample sample_obj;
- TickSample* sample = CpuProfiler::TickSampleEvent(sampler->isolate());
+ TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
if (sample == NULL) sample = &sample_obj;
static const DWORD kSuspendFailed = static_cast<DWORD>(-1);
if (SuspendThread(profiled_thread) == kSuspendFailed) return;
- sample->state = sampler->isolate()->current_vm_state();
+ sample->state = isolate->current_vm_state();
context.ContextFlags = CONTEXT_FULL;
if (GetThreadContext(profiled_thread, &context) != 0) {
diff --git a/src/preparser.cc b/src/preparser.cc
index c461d8a..c61a08d 100644
--- a/src/preparser.cc
+++ b/src/preparser.cc
@@ -53,12 +53,13 @@
namespace preparser {
PreParser::PreParseResult PreParser::PreParseLazyFunction(
- i::LanguageMode mode, i::ParserRecorder* log) {
+ i::LanguageMode mode, bool is_generator, i::ParserRecorder* log) {
log_ = log;
// Lazy functions always have trivial outer scopes (no with/catch scopes).
Scope top_scope(&scope_, kTopLevelScope);
set_language_mode(mode);
Scope function_scope(&scope_, kFunctionScope);
+ function_scope.set_is_generator(is_generator);
ASSERT_EQ(i::Token::LBRACE, scanner_->current_token());
bool ok = true;
int start_position = scanner_->peek_location().beg_pos;
@@ -154,6 +155,7 @@
// SourceElement:
// LetDeclaration
// ConstDeclaration
+ // GeneratorDeclaration
switch (peek()) {
case i::Token::FUNCTION:
@@ -294,19 +296,23 @@
PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) {
// FunctionDeclaration ::
// 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
+ // GeneratorDeclaration ::
+ // 'function' '*' Identifier '(' FormalParameterListopt ')'
+ // '{' FunctionBody '}'
Expect(i::Token::FUNCTION, CHECK_OK);
+ bool is_generator = allow_generators_ && Check(i::Token::MUL);
Identifier identifier = ParseIdentifier(CHECK_OK);
i::Scanner::Location location = scanner_->location();
- Expression function_value = ParseFunctionLiteral(CHECK_OK);
+ Expression function_value = ParseFunctionLiteral(is_generator, CHECK_OK);
if (function_value.IsStrictFunction() &&
!identifier.IsValidStrictVariable()) {
// Strict mode violation, using either reserved word or eval/arguments
// as name of strict function.
const char* type = "strict_function_name";
- if (identifier.IsFutureStrictReserved()) {
+ if (identifier.IsFutureStrictReserved() || identifier.IsYield()) {
type = "strict_reserved_word";
}
ReportMessageAt(location, type, NULL);
@@ -475,7 +481,9 @@
Expression expr = ParseExpression(true, CHECK_OK);
if (expr.IsRawIdentifier()) {
ASSERT(!expr.AsIdentifier().IsFutureReserved());
- ASSERT(is_classic_mode() || !expr.AsIdentifier().IsFutureStrictReserved());
+ ASSERT(is_classic_mode() ||
+ (!expr.AsIdentifier().IsFutureStrictReserved() &&
+ !expr.AsIdentifier().IsYield()));
if (peek() == i::Token::COLON) {
Consume(i::Token::COLON);
return ParseStatement(ok);
@@ -810,8 +818,13 @@
bool* ok) {
// AssignmentExpression ::
// ConditionalExpression
+ // YieldExpression
// LeftHandSideExpression AssignmentOperator AssignmentExpression
+ if (scope_->is_generator() && peek() == i::Token::YIELD) {
+ return ParseYieldExpression(ok);
+ }
+
i::Scanner::Location before = scanner_->peek_location();
Expression expression = ParseConditionalExpression(accept_IN, CHECK_OK);
@@ -842,6 +855,19 @@
// Precedence = 3
+PreParser::Expression PreParser::ParseYieldExpression(bool* ok) {
+ // YieldExpression ::
+ // 'yield' '*'? AssignmentExpression
+ Consume(i::Token::YIELD);
+ Check(i::Token::MUL);
+
+ ParseAssignmentExpression(false, CHECK_OK);
+
+ return Expression::Default();
+}
+
+
+// Precedence = 3
PreParser::Expression PreParser::ParseConditionalExpression(bool accept_IN,
bool* ok) {
// ConditionalExpression ::
@@ -1034,11 +1060,13 @@
Expression result = Expression::Default();
if (peek() == i::Token::FUNCTION) {
Consume(i::Token::FUNCTION);
+
+ bool is_generator = allow_generators_ && Check(i::Token::MUL);
Identifier identifier = Identifier::Default();
if (peek_any_identifier()) {
identifier = ParseIdentifier(CHECK_OK);
}
- result = ParseFunctionLiteral(CHECK_OK);
+ result = ParseFunctionLiteral(is_generator, CHECK_OK);
if (result.IsStrictFunction() && !identifier.IsValidStrictVariable()) {
StrictModeIdentifierViolation(scanner_->location(),
"strict_function_name",
@@ -1112,6 +1140,7 @@
case i::Token::FUTURE_RESERVED_WORD:
case i::Token::FUTURE_STRICT_RESERVED_WORD:
+ case i::Token::YIELD:
case i::Token::IDENTIFIER: {
Identifier id = ParseIdentifier(CHECK_OK);
result = Expression::FromIdentifier(id);
@@ -1257,7 +1286,7 @@
}
PropertyType type = is_getter ? kGetterProperty : kSetterProperty;
CheckDuplicate(&duplicate_finder, name, type, CHECK_OK);
- ParseFunctionLiteral(CHECK_OK);
+ ParseFunctionLiteral(false, CHECK_OK);
if (peek() != i::Token::RBRACE) {
Expect(i::Token::COMMA, CHECK_OK);
}
@@ -1344,7 +1373,8 @@
}
-PreParser::Expression PreParser::ParseFunctionLiteral(bool* ok) {
+PreParser::Expression PreParser::ParseFunctionLiteral(bool is_generator,
+ bool* ok) {
// Function ::
// '(' FormalParameterList? ')' '{' FunctionBody '}'
@@ -1352,6 +1382,7 @@
ScopeType outer_scope_type = scope_->type();
bool inside_with = scope_->IsInsideWith();
Scope function_scope(&scope_, kFunctionScope);
+ function_scope.set_is_generator(is_generator);
// FormalParameterList ::
// '(' (Identifier)*[','] ')'
Expect(i::Token::LPAREN, CHECK_OK);
@@ -1497,6 +1528,8 @@
} else if (scanner_->current_token() ==
i::Token::FUTURE_STRICT_RESERVED_WORD) {
return Identifier::FutureStrictReserved();
+ } else if (scanner_->current_token() == i::Token::YIELD) {
+ return Identifier::Yield();
}
if (scanner_->is_literal_ascii()) {
// Detect strict-mode poison words.
@@ -1523,6 +1556,14 @@
*ok = false;
return GetIdentifierSymbol();
}
+ case i::Token::YIELD:
+ if (scope_->is_generator()) {
+ // 'yield' in a generator is only valid as part of a YieldExpression.
+ ReportMessageAt(scanner_->location(), "unexpected_token", "yield");
+ *ok = false;
+ return Identifier::Yield();
+ }
+ // FALLTHROUGH
case i::Token::FUTURE_STRICT_RESERVED_WORD:
if (!is_classic_mode()) {
i::Scanner::Location location = scanner_->location();
@@ -1580,7 +1621,7 @@
const char* type = eval_args_type;
if (identifier.IsFutureReserved()) {
type = "reserved_word";
- } else if (identifier.IsFutureStrictReserved()) {
+ } else if (identifier.IsFutureStrictReserved() || identifier.IsYield()) {
type = "strict_reserved_word";
}
if (!is_classic_mode()) {
@@ -1634,7 +1675,8 @@
i::Token::Value next = peek();
return next == i::Token::IDENTIFIER ||
next == i::Token::FUTURE_RESERVED_WORD ||
- next == i::Token::FUTURE_STRICT_RESERVED_WORD;
+ next == i::Token::FUTURE_STRICT_RESERVED_WORD ||
+ next == i::Token::YIELD;
}
diff --git a/src/preparser.h b/src/preparser.h
index ad52d74..ce9aa75 100644
--- a/src/preparser.h
+++ b/src/preparser.h
@@ -104,6 +104,11 @@
};
+#ifdef WIN32
+#undef Yield
+#endif
+
+
class PreParser {
public:
enum PreParseResult {
@@ -117,7 +122,8 @@
uintptr_t stack_limit,
bool allow_lazy,
bool allow_natives_syntax,
- bool allow_modules)
+ bool allow_modules,
+ bool allow_generators)
: scanner_(scanner),
log_(log),
scope_(NULL),
@@ -128,6 +134,7 @@
allow_lazy_(allow_lazy),
allow_modules_(allow_modules),
allow_natives_syntax_(allow_natives_syntax),
+ allow_generators_(allow_generators),
parenthesized_function_(false),
harmony_scoping_(scanner->HarmonyScoping()) { }
@@ -144,19 +151,22 @@
bool allow_lazy = (flags & i::kAllowLazy) != 0;
bool allow_natives_syntax = (flags & i::kAllowNativesSyntax) != 0;
bool allow_modules = (flags & i::kAllowModules) != 0;
+ bool allow_generators = (flags & i::kAllowGenerators) != 0;
return PreParser(scanner, log, stack_limit, allow_lazy,
- allow_natives_syntax, allow_modules).PreParse();
+ allow_natives_syntax, allow_modules,
+ allow_generators).PreParse();
}
// Parses a single function literal, from the opening parentheses before
// parameters to the closing brace after the body.
// Returns a FunctionEntry describing the body of the function in enough
// detail that it can be lazily compiled.
- // The scanner is expected to have matched the "function" keyword and
- // parameters, and have consumed the initial '{'.
+ // The scanner is expected to have matched the "function" or "function*"
+ // keyword and parameters, and have consumed the initial '{'.
// At return, unless an error occurred, the scanner is positioned before the
// the final '}'.
PreParseResult PreParseLazyFunction(i::LanguageMode mode,
+ bool is_generator,
i::ParserRecorder* log);
private:
@@ -240,9 +250,13 @@
static Identifier FutureStrictReserved() {
return Identifier(kFutureStrictReservedIdentifier);
}
+ static Identifier Yield() {
+ return Identifier(kYieldIdentifier);
+ }
bool IsEval() { return type_ == kEvalIdentifier; }
bool IsArguments() { return type_ == kArgumentsIdentifier; }
bool IsEvalOrArguments() { return type_ >= kEvalIdentifier; }
+ bool IsYield() { return type_ == kYieldIdentifier; }
bool IsFutureReserved() { return type_ == kFutureReservedIdentifier; }
bool IsFutureStrictReserved() {
return type_ == kFutureStrictReservedIdentifier;
@@ -254,6 +268,7 @@
kUnknownIdentifier,
kFutureReservedIdentifier,
kFutureStrictReservedIdentifier,
+ kYieldIdentifier,
kEvalIdentifier,
kArgumentsIdentifier
};
@@ -347,7 +362,7 @@
// Identifiers and string literals can be parenthesized.
// They no longer work as labels or directive prologues,
// but are still recognized in other contexts.
- return Expression(code_ | kParentesizedExpressionFlag);
+ return Expression(code_ | kParenthesizedExpressionFlag);
}
// For other types of expressions, it's not important to remember
// the parentheses.
@@ -373,7 +388,8 @@
kUseStrictString = kStringLiteralFlag | 8,
kStringLiteralMask = kUseStrictString,
- kParentesizedExpressionFlag = 4, // Only if identifier or string literal.
+ // Only if identifier or string literal.
+ kParenthesizedExpressionFlag = 4,
// Below here applies if neither identifier nor string literal.
kThisExpression = 4,
@@ -451,7 +467,8 @@
expected_properties_(0),
with_nesting_count_(0),
language_mode_(
- (prev_ != NULL) ? prev_->language_mode() : i::CLASSIC_MODE) {
+ (prev_ != NULL) ? prev_->language_mode() : i::CLASSIC_MODE),
+ is_generator_(false) {
*variable = this;
}
~Scope() { *variable_ = prev_; }
@@ -461,6 +478,8 @@
int expected_properties() { return expected_properties_; }
int materialized_literal_count() { return materialized_literal_count_; }
bool IsInsideWith() { return with_nesting_count_ != 0; }
+ bool is_generator() { return is_generator_; }
+ void set_is_generator(bool is_generator) { is_generator_ = is_generator; }
bool is_classic_mode() {
return language_mode_ == i::CLASSIC_MODE;
}
@@ -492,6 +511,7 @@
int expected_properties_;
int with_nesting_count_;
i::LanguageMode language_mode_;
+ bool is_generator_;
};
// Preparse the program. Only called in PreParseProgram after creating
@@ -557,6 +577,7 @@
Expression ParseExpression(bool accept_IN, bool* ok);
Expression ParseAssignmentExpression(bool accept_IN, bool* ok);
+ Expression ParseYieldExpression(bool* ok);
Expression ParseConditionalExpression(bool accept_IN, bool* ok);
Expression ParseBinaryExpression(int prec, bool accept_IN, bool* ok);
Expression ParseUnaryExpression(bool* ok);
@@ -572,7 +593,7 @@
Expression ParseV8Intrinsic(bool* ok);
Arguments ParseArguments(bool* ok);
- Expression ParseFunctionLiteral(bool* ok);
+ Expression ParseFunctionLiteral(bool is_generator, bool* ok);
void ParseLazyFunctionLiteralBody(bool* ok);
Identifier ParseIdentifier(bool* ok);
@@ -664,6 +685,7 @@
bool allow_lazy_;
bool allow_modules_;
bool allow_natives_syntax_;
+ bool allow_generators_;
bool parenthesized_function_;
bool harmony_scoping_;
};
diff --git a/src/prettyprinter.cc b/src/prettyprinter.cc
index df6183a..50a71ce 100644
--- a/src/prettyprinter.cc
+++ b/src/prettyprinter.cc
@@ -353,6 +353,12 @@
}
+void PrettyPrinter::VisitYield(Yield* node) {
+ Print("yield ");
+ Visit(node->expression());
+}
+
+
void PrettyPrinter::VisitThrow(Throw* node) {
Print("throw ");
Visit(node->exception());
@@ -1059,6 +1065,11 @@
}
+void AstPrinter::VisitYield(Yield* node) {
+ PrintIndentedVisit("YIELD", node->expression());
+}
+
+
void AstPrinter::VisitThrow(Throw* node) {
PrintIndentedVisit("THROW", node->exception());
}
diff --git a/src/profile-generator-inl.h b/src/profile-generator-inl.h
index 6e7f499..4e6302c 100644
--- a/src/profile-generator-inl.h
+++ b/src/profile-generator-inl.h
@@ -74,7 +74,8 @@
entry_(entry),
total_ticks_(0),
self_ticks_(0),
- children_(CodeEntriesMatch) {
+ children_(CodeEntriesMatch),
+ id_(tree->next_node_id()) {
}
diff --git a/src/profile-generator.cc b/src/profile-generator.cc
index 2bf1724..ce07213 100644
--- a/src/profile-generator.cc
+++ b/src/profile-generator.cc
@@ -296,6 +296,7 @@
"",
0,
TokenEnumerator::kNoSecurityToken),
+ next_node_id_(1),
root_(new ProfileNode(this, &root_entry_)) {
}
@@ -306,7 +307,7 @@
}
-void ProfileTree::AddPathFromEnd(const Vector<CodeEntry*>& path) {
+ProfileNode* ProfileTree::AddPathFromEnd(const Vector<CodeEntry*>& path) {
ProfileNode* node = root_;
for (CodeEntry** entry = path.start() + path.length() - 1;
entry != path.start() - 1;
@@ -316,6 +317,7 @@
}
}
node->IncrementSelfTicks();
+ return node;
}
@@ -467,7 +469,8 @@
void CpuProfile::AddPath(const Vector<CodeEntry*>& path) {
- top_down_.AddPathFromEnd(path);
+ ProfileNode* top_frame_node = top_down_.AddPathFromEnd(path);
+ if (record_samples_) samples_.Add(top_frame_node);
}
@@ -483,7 +486,7 @@
CpuProfile* CpuProfile::FilteredClone(int security_token_id) {
ASSERT(security_token_id != TokenEnumerator::kNoSecurityToken);
- CpuProfile* clone = new CpuProfile(title_, uid_);
+ CpuProfile* clone = new CpuProfile(title_, uid_, false);
clone->top_down_.FilteredClone(&top_down_, security_token_id);
return clone;
}
@@ -609,7 +612,8 @@
}
-bool CpuProfilesCollection::StartProfiling(const char* title, unsigned uid) {
+bool CpuProfilesCollection::StartProfiling(const char* title, unsigned uid,
+ bool record_samples) {
ASSERT(uid > 0);
current_profiles_semaphore_->Wait();
if (current_profiles_.length() >= kMaxSimultaneousProfiles) {
@@ -623,17 +627,12 @@
return false;
}
}
- current_profiles_.Add(new CpuProfile(title, uid));
+ current_profiles_.Add(new CpuProfile(title, uid, record_samples));
current_profiles_semaphore_->Signal();
return true;
}
-bool CpuProfilesCollection::StartProfiling(String* title, unsigned uid) {
- return StartProfiling(GetName(title), uid);
-}
-
-
CpuProfile* CpuProfilesCollection::StopProfiling(int security_token_id,
const char* title,
double actual_sampling_rate) {
diff --git a/src/profile-generator.h b/src/profile-generator.h
index b128dad..4ddb753 100644
--- a/src/profile-generator.h
+++ b/src/profile-generator.h
@@ -150,6 +150,7 @@
INLINE(const List<ProfileNode*>* children() const) { return &children_list_; }
double GetSelfMillis() const;
double GetTotalMillis() const;
+ unsigned id() const { return id_; }
void Print(int indent);
@@ -170,6 +171,7 @@
// Mapping from CodeEntry* to ProfileNode*
HashMap children_;
List<ProfileNode*> children_list_;
+ unsigned id_;
DISALLOW_COPY_AND_ASSIGN(ProfileNode);
};
@@ -180,7 +182,7 @@
ProfileTree();
~ProfileTree();
- void AddPathFromEnd(const Vector<CodeEntry*>& path);
+ ProfileNode* AddPathFromEnd(const Vector<CodeEntry*>& path);
void AddPathFromStart(const Vector<CodeEntry*>& path);
void CalculateTotalTicks();
void FilteredClone(ProfileTree* src, int security_token_id);
@@ -191,6 +193,8 @@
ProfileNode* root() const { return root_; }
void SetTickRatePerMs(double ticks_per_ms);
+ unsigned next_node_id() { return next_node_id_++; }
+
void ShortPrint();
void Print() {
root_->Print(0);
@@ -201,6 +205,7 @@
void TraverseDepthFirst(Callback* callback);
CodeEntry root_entry_;
+ unsigned next_node_id_;
ProfileNode* root_;
double ms_to_ticks_scale_;
@@ -210,8 +215,8 @@
class CpuProfile {
public:
- CpuProfile(const char* title, unsigned uid)
- : title_(title), uid_(uid) { }
+ CpuProfile(const char* title, unsigned uid, bool record_samples)
+ : title_(title), uid_(uid), record_samples_(record_samples) { }
// Add pc -> ... -> main() call path to the profile.
void AddPath(const Vector<CodeEntry*>& path);
@@ -223,6 +228,9 @@
INLINE(unsigned uid() const) { return uid_; }
INLINE(const ProfileTree* top_down() const) { return &top_down_; }
+ INLINE(int samples_count() const) { return samples_.length(); }
+ INLINE(ProfileNode* sample(int index) const) { return samples_.at(index); }
+
void UpdateTicksScale();
void ShortPrint();
@@ -231,6 +239,8 @@
private:
const char* title_;
unsigned uid_;
+ bool record_samples_;
+ List<ProfileNode*> samples_;
ProfileTree top_down_;
DISALLOW_COPY_AND_ASSIGN(CpuProfile);
@@ -288,8 +298,7 @@
CpuProfilesCollection();
~CpuProfilesCollection();
- bool StartProfiling(const char* title, unsigned uid);
- bool StartProfiling(String* title, unsigned uid);
+ bool StartProfiling(const char* title, unsigned uid, bool record_samples);
CpuProfile* StopProfiling(int security_token_id,
const char* title,
double actual_sampling_rate);
diff --git a/src/property.h b/src/property.h
index 546967a..bbba8ae 100644
--- a/src/property.h
+++ b/src/property.h
@@ -362,12 +362,16 @@
return NULL;
}
- Map* GetTransitionTarget() {
+ Map* GetTransitionTarget(Map* map) {
ASSERT(IsTransition());
- TransitionArray* transitions = holder()->map()->transitions();
+ TransitionArray* transitions = map->transitions();
return transitions->GetTarget(number_);
}
+ Map* GetTransitionTarget() {
+ return GetTransitionTarget(holder()->map());
+ }
+
PropertyDetails GetTransitionDetails(Map* map) {
ASSERT(IsTransition());
TransitionArray* transitions = map->transitions();
diff --git a/src/runtime.cc b/src/runtime.cc
index 58f2a51..78efc8d 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -26,6 +26,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdlib.h>
+#include <limits>
#include "v8.h"
@@ -138,148 +139,6 @@
static_cast<LanguageMode>(args.smi_at(index));
-MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
- JSObject* boilerplate) {
- StackLimitCheck check(isolate);
- if (check.HasOverflowed()) return isolate->StackOverflow();
-
- Heap* heap = isolate->heap();
- Object* result;
- { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- JSObject* copy = JSObject::cast(result);
-
- // Deep copy local properties.
- if (copy->HasFastProperties()) {
- FixedArray* properties = copy->properties();
- for (int i = 0; i < properties->length(); i++) {
- Object* value = properties->get(i);
- if (value->IsJSObject()) {
- JSObject* js_object = JSObject::cast(value);
- { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- properties->set(i, result);
- }
- }
- int nof = copy->map()->inobject_properties();
- for (int i = 0; i < nof; i++) {
- Object* value = copy->InObjectPropertyAt(i);
- if (value->IsJSObject()) {
- JSObject* js_object = JSObject::cast(value);
- { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- copy->InObjectPropertyAtPut(i, result);
- }
- }
- } else {
- { MaybeObject* maybe_result =
- heap->AllocateFixedArray(copy->NumberOfLocalProperties());
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- FixedArray* names = FixedArray::cast(result);
- copy->GetLocalPropertyNames(names, 0);
- for (int i = 0; i < names->length(); i++) {
- ASSERT(names->get(i)->IsString());
- String* key_string = String::cast(names->get(i));
- PropertyAttributes attributes =
- copy->GetLocalPropertyAttribute(key_string);
- // Only deep copy fields from the object literal expression.
- // In particular, don't try to copy the length attribute of
- // an array.
- if (attributes != NONE) continue;
- Object* value =
- copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
- if (value->IsJSObject()) {
- JSObject* js_object = JSObject::cast(value);
- { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- { MaybeObject* maybe_result =
- // Creating object copy for literals. No strict mode needed.
- copy->SetProperty(key_string, result, NONE, kNonStrictMode);
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- }
- }
- }
-
- // Deep copy local elements.
- // Pixel elements cannot be created using an object literal.
- ASSERT(!copy->HasExternalArrayElements());
- switch (copy->GetElementsKind()) {
- case FAST_SMI_ELEMENTS:
- case FAST_ELEMENTS:
- case FAST_HOLEY_SMI_ELEMENTS:
- case FAST_HOLEY_ELEMENTS: {
- FixedArray* elements = FixedArray::cast(copy->elements());
- if (elements->map() == heap->fixed_cow_array_map()) {
- isolate->counters()->cow_arrays_created_runtime()->Increment();
-#ifdef DEBUG
- for (int i = 0; i < elements->length(); i++) {
- ASSERT(!elements->get(i)->IsJSObject());
- }
-#endif
- } else {
- for (int i = 0; i < elements->length(); i++) {
- Object* value = elements->get(i);
- ASSERT(value->IsSmi() ||
- value->IsTheHole() ||
- (IsFastObjectElementsKind(copy->GetElementsKind())));
- if (value->IsJSObject()) {
- JSObject* js_object = JSObject::cast(value);
- { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
- js_object);
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- elements->set(i, result);
- }
- }
- }
- break;
- }
- case DICTIONARY_ELEMENTS: {
- SeededNumberDictionary* element_dictionary = copy->element_dictionary();
- int capacity = element_dictionary->Capacity();
- for (int i = 0; i < capacity; i++) {
- Object* k = element_dictionary->KeyAt(i);
- if (element_dictionary->IsKey(k)) {
- Object* value = element_dictionary->ValueAt(i);
- if (value->IsJSObject()) {
- JSObject* js_object = JSObject::cast(value);
- { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
- js_object);
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- element_dictionary->ValueAtPut(i, result);
- }
- }
- }
- break;
- }
- case NON_STRICT_ARGUMENTS_ELEMENTS:
- UNIMPLEMENTED();
- break;
- case EXTERNAL_PIXEL_ELEMENTS:
- case EXTERNAL_BYTE_ELEMENTS:
- case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case EXTERNAL_SHORT_ELEMENTS:
- case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- case EXTERNAL_INT_ELEMENTS:
- case EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case EXTERNAL_FLOAT_ELEMENTS:
- case EXTERNAL_DOUBLE_ELEMENTS:
- case FAST_DOUBLE_ELEMENTS:
- case FAST_HOLEY_DOUBLE_ELEMENTS:
- // No contained objects, nothing to do.
- break;
- }
- return copy;
-}
-
-
static Handle<Map> ComputeObjectLiteralMap(
Handle<Context> context,
Handle<FixedArray> constant_properties,
@@ -598,7 +457,7 @@
// Update the functions literal and return the boilerplate.
literals->set(literals_index, *boilerplate);
}
- return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
+ return JSObject::cast(*boilerplate)->DeepCopy(isolate);
}
@@ -645,7 +504,7 @@
// Update the functions literal and return the boilerplate.
literals->set(literals_index, *boilerplate);
}
- return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
+ return JSObject::cast(*boilerplate)->DeepCopy(isolate);
}
@@ -683,9 +542,23 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateSymbol) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 1);
+ Handle<Object> name(args[0], isolate);
+ RUNTIME_ASSERT(name->IsString() || name->IsUndefined());
+ Symbol* symbol;
+ MaybeObject* maybe = isolate->heap()->AllocateSymbol();
+ if (!maybe->To(&symbol)) return maybe;
+ if (name->IsString()) symbol->set_name(*name);
+ return symbol;
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_SymbolName) {
NoHandleAllocation ha(isolate);
- ASSERT(args.length() == 0);
- return isolate->heap()->AllocateSymbol();
+ ASSERT(args.length() == 1);
+ CONVERT_ARG_CHECKED(Symbol, symbol, 0);
+ return symbol->name();
}
@@ -764,6 +637,125 @@
}
+static size_t ArrayBufferAllocatedLength(Isolate* isolate,
+ JSArrayBuffer* buffer) {
+ NoHandleAllocation hc(isolate);
+ Object* byte_length = buffer->byte_length();
+ if (byte_length->IsSmi()) {
+ return Smi::cast(byte_length)->value();
+ } else {
+ double value = HeapNumber::cast(byte_length)->value();
+ return static_cast<size_t>(value);
+ }
+}
+
+
+static void ArrayBufferWeakCallback(v8::Isolate* external_isolate,
+ Persistent<Value> object,
+ void* data) {
+ Isolate* isolate = reinterpret_cast<Isolate*>(external_isolate);
+ HandleScope scope(isolate);
+ Handle<Object> internal_object = Utils::OpenHandle(*object);
+
+ size_t allocated_length = ArrayBufferAllocatedLength(
+ isolate, JSArrayBuffer::cast(*internal_object));
+ isolate->heap()->AdjustAmountOfExternalAllocatedMemory(
+ -static_cast<intptr_t>(allocated_length));
+ if (data != NULL)
+ free(data);
+ object.Dispose(external_isolate);
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferInitialize) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 2);
+ CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0);
+ CONVERT_ARG_HANDLE_CHECKED(Object, byteLength, 1);
+ size_t allocated_length;
+ if (byteLength->IsSmi()) {
+ allocated_length = Smi::cast(*byteLength)->value();
+ } else {
+ ASSERT(byteLength->IsHeapNumber());
+ double value = HeapNumber::cast(*byteLength)->value();
+
+ ASSERT(value >= 0);
+
+ if (value > std::numeric_limits<size_t>::max()) {
+ return isolate->Throw(
+ *isolate->factory()->NewRangeError("invalid_array_buffer_length",
+ HandleVector<Object>(NULL, 0)));
+ }
+
+ allocated_length = static_cast<size_t>(value);
+ }
+
+ void* data;
+ if (allocated_length != 0) {
+ data = malloc(allocated_length);
+
+ if (data == NULL) {
+ return isolate->Throw(*isolate->factory()->
+ NewRangeError("invalid_array_buffer_length",
+ HandleVector<Object>(NULL, 0)));
+ }
+
+ memset(data, 0, allocated_length);
+ } else {
+ data = NULL;
+ }
+ holder->set_backing_store(data);
+
+ Object* byte_length;
+ {
+ MaybeObject* maybe_byte_length =
+ isolate->heap()->NumberFromDouble(
+ static_cast<double>(allocated_length));
+ if (!maybe_byte_length->ToObject(&byte_length)) return maybe_byte_length;
+ }
+ CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber());
+ holder->set_byte_length(byte_length);
+
+ v8::Isolate* external_isolate = reinterpret_cast<v8::Isolate*>(isolate);
+ v8::Handle<Object> external_holder(*holder);
+ Persistent<Object> weak_handle = Persistent<Object>::New(
+ external_isolate, external_holder);
+ weak_handle.MakeWeak(external_isolate, data, ArrayBufferWeakCallback);
+ weak_handle.MarkIndependent(external_isolate);
+ isolate->heap()->AdjustAmountOfExternalAllocatedMemory(allocated_length);
+
+ return *holder;
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferGetByteLength) {
+ NoHandleAllocation ha(isolate);
+ ASSERT(args.length() == 1);
+ CONVERT_ARG_CHECKED(JSArrayBuffer, holder, 0);
+ return holder->byte_length();
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferSliceImpl) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 3);
+ CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, source, 0);
+ CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, target, 1);
+ CONVERT_DOUBLE_ARG_CHECKED(first, 2);
+ size_t start = static_cast<size_t>(first);
+ size_t target_length = ArrayBufferAllocatedLength(isolate, *target);
+
+ if (target_length == 0)
+ return isolate->heap()->undefined_value();
+
+ ASSERT(ArrayBufferAllocatedLength(isolate, *source) - target_length >= start);
+ uint8_t* source_data = reinterpret_cast<uint8_t*>(source->backing_store());
+ uint8_t* target_data = reinterpret_cast<uint8_t*>(target->backing_store());
+ CopyBytes(target_data, source_data + start, target_length);
+ return isolate->heap()->undefined_value();
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
HandleScope scope(isolate);
ASSERT(args.length() == 1);
@@ -2231,7 +2223,7 @@
target->set_literals(*literals);
if (isolate->logger()->is_logging_code_events() ||
- CpuProfiler::is_profiling(isolate)) {
+ isolate->cpu_profiler()->is_profiling()) {
isolate->logger()->LogExistingFunction(
source_shared, Handle<Code>(source_shared->code()));
}
@@ -4731,11 +4723,13 @@
// args[0]: object
RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
HandleScope scope(isolate);
- ASSERT(args.length() == 1);
+ ASSERT(args.length() == 2);
if (!args[0]->IsJSObject()) {
return isolate->heap()->undefined_value();
}
CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
+ CONVERT_BOOLEAN_ARG_CHECKED(include_symbols, 1);
+ PropertyAttributes filter = include_symbols ? NONE : SYMBOLIC;
// Skip the global proxy as it has no properties and always delegates to the
// real global object.
@@ -4768,7 +4762,7 @@
return *isolate->factory()->NewJSArray(0);
}
int n;
- n = jsproto->NumberOfLocalProperties();
+ n = jsproto->NumberOfLocalProperties(filter);
local_property_count[i] = n;
total_property_count += n;
if (i < length - 1) {
@@ -4785,7 +4779,7 @@
int proto_with_hidden_properties = 0;
int next_copy_index = 0;
for (int i = 0; i < length; i++) {
- jsproto->GetLocalPropertyNames(*names, next_copy_index);
+ jsproto->GetLocalPropertyNames(*names, next_copy_index, filter);
next_copy_index += local_property_count[i];
if (jsproto->HasHiddenProperties()) {
proto_with_hidden_properties++;
@@ -4795,7 +4789,7 @@
}
}
- // Filter out name of hidden propeties object.
+ // Filter out name of hidden properties object.
if (proto_with_hidden_properties > 0) {
Handle<FixedArray> old_names = names;
names = isolate->factory()->NewFixedArray(
@@ -5035,6 +5029,8 @@
}
ASSERT(heap_obj->IsUndefined());
return isolate->heap()->undefined_string();
+ case SYMBOL_TYPE:
+ return isolate->heap()->symbol_string();
case JS_FUNCTION_TYPE:
case JS_FUNCTION_PROXY_TYPE:
return isolate->heap()->function_string();
@@ -5137,10 +5133,10 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_TruncateString) {
- NoHandleAllocation ha(isolate);
- CONVERT_ARG_CHECKED(SeqString, string, 0);
+ HandleScope scope(isolate);
+ CONVERT_ARG_HANDLE_CHECKED(SeqString, string, 0);
CONVERT_SMI_ARG_CHECKED(new_length, 1);
- return string->Truncate(new_length);
+ return *SeqString::Truncate(string, new_length);
}
@@ -5171,365 +5167,11 @@
}
-static const unsigned int kQuoteTableLength = 128u;
-
-static const int kJsonQuotesCharactersPerEntry = 8;
-static const char* const JsonQuotes =
- "\\u0000 \\u0001 \\u0002 \\u0003 "
- "\\u0004 \\u0005 \\u0006 \\u0007 "
- "\\b \\t \\n \\u000b "
- "\\f \\r \\u000e \\u000f "
- "\\u0010 \\u0011 \\u0012 \\u0013 "
- "\\u0014 \\u0015 \\u0016 \\u0017 "
- "\\u0018 \\u0019 \\u001a \\u001b "
- "\\u001c \\u001d \\u001e \\u001f "
- " ! \\\" # "
- "$ % & ' "
- "( ) * + "
- ", - . / "
- "0 1 2 3 "
- "4 5 6 7 "
- "8 9 : ; "
- "< = > ? "
- "@ A B C "
- "D E F G "
- "H I J K "
- "L M N O "
- "P Q R S "
- "T U V W "
- "X Y Z [ "
- "\\\\ ] ^ _ "
- "` a b c "
- "d e f g "
- "h i j k "
- "l m n o "
- "p q r s "
- "t u v w "
- "x y z { "
- "| } ~ \177 ";
-
-
-// For a string that is less than 32k characters it should always be
-// possible to allocate it in new space.
-static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
-
-
-// Doing JSON quoting cannot make the string more than this many times larger.
-static const int kJsonQuoteWorstCaseBlowup = 6;
-
-static const int kSpaceForQuotesAndComma = 3;
-static const int kSpaceForBrackets = 2;
-
-// Covers the entire ASCII range (all other characters are unchanged by JSON
-// quoting).
-static const byte JsonQuoteLengths[kQuoteTableLength] = {
- 6, 6, 6, 6, 6, 6, 6, 6,
- 2, 2, 2, 6, 2, 2, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6,
- 1, 1, 2, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 2, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
-};
-
-
-template <typename StringType>
-MaybeObject* AllocateRawString(Isolate* isolate, int length);
-
-
-template <>
-MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
- return isolate->heap()->AllocateRawTwoByteString(length);
-}
-
-
-template <>
-MaybeObject* AllocateRawString<SeqOneByteString>(Isolate* isolate, int length) {
- return isolate->heap()->AllocateRawOneByteString(length);
-}
-
-
-template <typename Char, typename StringType, bool comma>
-static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
- Vector<const Char> characters) {
- int length = characters.length();
- const Char* read_cursor = characters.start();
- const Char* end = read_cursor + length;
- const int kSpaceForQuotes = 2 + (comma ? 1 :0);
- int quoted_length = kSpaceForQuotes;
- while (read_cursor < end) {
- Char c = *(read_cursor++);
- if (static_cast<unsigned>(c) >= kQuoteTableLength) {
- quoted_length++;
- } else {
- quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
- }
- }
- MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
- quoted_length);
- Object* new_object;
- if (!new_alloc->ToObject(&new_object)) {
- return new_alloc;
- }
- StringType* new_string = StringType::cast(new_object);
-
- Char* write_cursor = reinterpret_cast<Char*>(
- new_string->address() + SeqString::kHeaderSize);
- if (comma) *(write_cursor++) = ',';
- *(write_cursor++) = '"';
-
- read_cursor = characters.start();
- while (read_cursor < end) {
- Char c = *(read_cursor++);
- if (static_cast<unsigned>(c) >= kQuoteTableLength) {
- *(write_cursor++) = c;
- } else {
- int len = JsonQuoteLengths[static_cast<unsigned>(c)];
- const char* replacement = JsonQuotes +
- static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
- for (int i = 0; i < len; i++) {
- *write_cursor++ = *replacement++;
- }
- }
- }
- *(write_cursor++) = '"';
- return new_string;
-}
-
-
-template <typename SinkChar, typename SourceChar>
-static inline SinkChar* WriteQuoteJsonString(
- Isolate* isolate,
- SinkChar* write_cursor,
- Vector<const SourceChar> characters) {
- // SinkChar is only char if SourceChar is guaranteed to be char.
- ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
- const SourceChar* read_cursor = characters.start();
- const SourceChar* end = read_cursor + characters.length();
- *(write_cursor++) = '"';
- while (read_cursor < end) {
- SourceChar c = *(read_cursor++);
- if (static_cast<unsigned>(c) >= kQuoteTableLength) {
- *(write_cursor++) = static_cast<SinkChar>(c);
- } else {
- int len = JsonQuoteLengths[static_cast<unsigned>(c)];
- const char* replacement = JsonQuotes +
- static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
- write_cursor[0] = replacement[0];
- if (len > 1) {
- write_cursor[1] = replacement[1];
- if (len > 2) {
- ASSERT(len == 6);
- write_cursor[2] = replacement[2];
- write_cursor[3] = replacement[3];
- write_cursor[4] = replacement[4];
- write_cursor[5] = replacement[5];
- }
- }
- write_cursor += len;
- }
- }
- *(write_cursor++) = '"';
- return write_cursor;
-}
-
-
-template <typename Char, typename StringType, bool comma>
-static MaybeObject* QuoteJsonString(Isolate* isolate,
- Vector<const Char> characters) {
- int length = characters.length();
- isolate->counters()->quote_json_char_count()->Increment(length);
- int worst_case_length =
- length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
- if (worst_case_length > kMaxGuaranteedNewSpaceString) {
- return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
- }
-
- MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
- worst_case_length);
- Object* new_object;
- if (!new_alloc->ToObject(&new_object)) {
- return new_alloc;
- }
- if (!isolate->heap()->new_space()->Contains(new_object)) {
- // Even if our string is small enough to fit in new space we still have to
- // handle it being allocated in old space as may happen in the third
- // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
- // CEntryStub::GenerateCore.
- return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
- }
- StringType* new_string = StringType::cast(new_object);
- ASSERT(isolate->heap()->new_space()->Contains(new_string));
-
- Char* write_cursor = reinterpret_cast<Char*>(
- new_string->address() + SeqString::kHeaderSize);
- if (comma) *(write_cursor++) = ',';
- write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
- write_cursor,
- characters);
- int final_length = static_cast<int>(
- write_cursor - reinterpret_cast<Char*>(
- new_string->address() + SeqString::kHeaderSize));
- isolate->heap()->new_space()->
- template ShrinkStringAtAllocationBoundary<StringType>(
- new_string, final_length);
- return new_string;
-}
-
-
RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
- NoHandleAllocation ha(isolate);
- CONVERT_ARG_CHECKED(String, str, 0);
- if (!str->IsFlat()) {
- MaybeObject* try_flatten = str->TryFlatten();
- Object* flat;
- if (!try_flatten->ToObject(&flat)) {
- return try_flatten;
- }
- str = String::cast(flat);
- ASSERT(str->IsFlat());
- }
- String::FlatContent flat = str->GetFlatContent();
- ASSERT(flat.IsFlat());
- if (flat.IsTwoByte()) {
- return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
- flat.ToUC16Vector());
- } else {
- return QuoteJsonString<uint8_t, SeqOneByteString, false>(
- isolate,
- flat.ToOneByteVector());
- }
-}
-
-
-RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
- NoHandleAllocation ha(isolate);
- CONVERT_ARG_CHECKED(String, str, 0);
- if (!str->IsFlat()) {
- MaybeObject* try_flatten = str->TryFlatten();
- Object* flat;
- if (!try_flatten->ToObject(&flat)) {
- return try_flatten;
- }
- str = String::cast(flat);
- ASSERT(str->IsFlat());
- }
- String::FlatContent flat = str->GetFlatContent();
- if (flat.IsTwoByte()) {
- return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
- flat.ToUC16Vector());
- } else {
- return QuoteJsonString<uint8_t, SeqOneByteString, true>(
- isolate,
- flat.ToOneByteVector());
- }
-}
-
-
-template <typename Char, typename StringType>
-static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
- FixedArray* array,
- int worst_case_length) {
- int length = array->length();
-
- MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
- worst_case_length);
- Object* new_object;
- if (!new_alloc->ToObject(&new_object)) {
- return new_alloc;
- }
- if (!isolate->heap()->new_space()->Contains(new_object)) {
- // Even if our string is small enough to fit in new space we still have to
- // handle it being allocated in old space as may happen in the third
- // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
- // CEntryStub::GenerateCore.
- return isolate->heap()->undefined_value();
- }
- AssertNoAllocation no_gc;
- StringType* new_string = StringType::cast(new_object);
- ASSERT(isolate->heap()->new_space()->Contains(new_string));
-
- Char* write_cursor = reinterpret_cast<Char*>(
- new_string->address() + SeqString::kHeaderSize);
- *(write_cursor++) = '[';
- for (int i = 0; i < length; i++) {
- if (i != 0) *(write_cursor++) = ',';
- String* str = String::cast(array->get(i));
- String::FlatContent content = str->GetFlatContent();
- ASSERT(content.IsFlat());
- if (content.IsTwoByte()) {
- write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
- write_cursor,
- content.ToUC16Vector());
- } else {
- write_cursor =
- WriteQuoteJsonString<Char, uint8_t>(isolate,
- write_cursor,
- content.ToOneByteVector());
- }
- }
- *(write_cursor++) = ']';
-
- int final_length = static_cast<int>(
- write_cursor - reinterpret_cast<Char*>(
- new_string->address() + SeqString::kHeaderSize));
- isolate->heap()->new_space()->
- template ShrinkStringAtAllocationBoundary<StringType>(
- new_string, final_length);
- return new_string;
-}
-
-
-RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
- NoHandleAllocation ha(isolate);
+ HandleScope scope(isolate);
+ CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
ASSERT(args.length() == 1);
- CONVERT_ARG_CHECKED(JSArray, array, 0);
-
- if (!array->HasFastObjectElements()) {
- return isolate->heap()->undefined_value();
- }
- FixedArray* elements = FixedArray::cast(array->elements());
- int n = elements->length();
- bool ascii = true;
- int total_length = 0;
-
- for (int i = 0; i < n; i++) {
- Object* elt = elements->get(i);
- if (!elt->IsString()) return isolate->heap()->undefined_value();
- String* element = String::cast(elt);
- if (!element->IsFlat()) return isolate->heap()->undefined_value();
- total_length += element->length();
- if (ascii && element->IsTwoByteRepresentation()) {
- ascii = false;
- }
- }
-
- int worst_case_length =
- kSpaceForBrackets + n * kSpaceForQuotesAndComma
- + total_length * kJsonQuoteWorstCaseBlowup;
-
- if (worst_case_length > kMaxGuaranteedNewSpaceString) {
- return isolate->heap()->undefined_value();
- }
-
- if (ascii) {
- return QuoteJsonStringArray<char, SeqOneByteString>(isolate,
- elements,
- worst_case_length);
- } else {
- return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
- elements,
- worst_case_length);
- }
+ return BasicJsonStringifier::StringifyString(isolate, string);
}
@@ -6134,6 +5776,24 @@
}
+// ES6 draft 9.1.11
+RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPositiveInteger) {
+ NoHandleAllocation ha(isolate);
+ ASSERT(args.length() == 1);
+
+ CONVERT_DOUBLE_ARG_CHECKED(number, 0);
+
+ // We do not include 0 so that we don't have to treat +0 / -0 cases.
+ if (number > 0 && number <= Smi::kMaxValue) {
+ return Smi::FromInt(static_cast<int>(number));
+ }
+ if (number <= 0) {
+ return Smi::FromInt(0);
+ }
+ return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
NoHandleAllocation ha(isolate);
ASSERT(args.length() == 1);
@@ -9895,9 +9555,9 @@
// Returns an array that tells you where in the [0, length) interval an array
-// might have elements. Can either return keys (positive integers) or
-// intervals (pair of a negative integer (-start-1) followed by a
-// positive (length)) or undefined values.
+// might have elements. Can either return an array of keys (positive integers
+// or undefined) or a number representing the positive length of an interval
+// starting at index 0.
// Intervals can span over some keys that are not in the object.
RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
HandleScope scope(isolate);
@@ -9905,37 +9565,34 @@
CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
if (array->elements()->IsDictionary()) {
- // Create an array and get all the keys into it, then remove all the
- // keys that are not integers in the range 0 to length-1.
- bool threw = false;
- Handle<FixedArray> keys =
- GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
- if (threw) return Failure::Exception();
-
- int keys_length = keys->length();
- for (int i = 0; i < keys_length; i++) {
- Object* key = keys->get(i);
- uint32_t index = 0;
- if (!key->ToArrayIndex(&index) || index >= length) {
- // Zap invalid keys.
- keys->set_undefined(i);
+ Handle<FixedArray> keys = isolate->factory()->empty_fixed_array();
+ for (Handle<Object> p = array;
+ !p->IsNull();
+ p = Handle<Object>(p->GetPrototype(isolate), isolate)) {
+ if (p->IsJSProxy() || JSObject::cast(*p)->HasIndexedInterceptor()) {
+ // Bail out if we find a proxy or interceptor, likely not worth
+ // collecting keys in that case.
+ return *isolate->factory()->NewNumberFromUint(length);
}
+ Handle<JSObject> current = Handle<JSObject>::cast(p);
+ Handle<FixedArray> current_keys =
+ isolate->factory()->NewFixedArray(
+ current->NumberOfLocalElements(NONE));
+ current->GetLocalElementKeys(*current_keys, NONE);
+ keys = UnionOfKeys(keys, current_keys);
+ }
+ // Erase any keys >= length.
+ // TODO(adamk): Remove this step when the contract of %GetArrayKeys
+ // is changed to let this happen on the JS side.
+ for (int i = 0; i < keys->length(); i++) {
+ if (NumberToUint32(keys->get(i)) >= length) keys->set_undefined(i);
}
return *isolate->factory()->NewJSArrayWithElements(keys);
} else {
ASSERT(array->HasFastSmiOrObjectElements() ||
array->HasFastDoubleElements());
- Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
- // -1 means start of array.
- single_interval->set(0, Smi::FromInt(-1));
- FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
- uint32_t actual_length =
- static_cast<uint32_t>(elements->length());
- uint32_t min_length = actual_length < length ? actual_length : length;
- Handle<Object> length_object =
- isolate->factory()->NewNumber(static_cast<double>(min_length));
- single_interval->set(1, *length_object);
- return *isolate->factory()->NewJSArrayWithElements(single_interval);
+ uint32_t actual_length = static_cast<uint32_t>(array->elements()->length());
+ return *isolate->factory()->NewNumberFromUint(Min(actual_length, length));
}
}
@@ -11810,6 +11467,13 @@
}
+static bool IsBlockOrCatchOrWithScope(ScopeIterator::ScopeType type) {
+ return type == ScopeIterator::ScopeTypeBlock ||
+ type == ScopeIterator::ScopeTypeCatch ||
+ type == ScopeIterator::ScopeTypeWith;
+}
+
+
// Creates a copy of the with context chain. The copy of the context chain is
// is linked to the function context supplied.
static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
@@ -11824,8 +11488,7 @@
ScopeIterator it(isolate, frame, inlined_jsframe_index);
if (it.Failed()) return Handle<Context>::null();
- for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
- it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
+ for ( ; IsBlockOrCatchOrWithScope(it.Type()); it.Next()) {
ASSERT(!it.Done());
scope_chain.Add(it.CurrentScopeInfo());
context_chain.Add(it.CurrentContext());
@@ -11841,6 +11504,7 @@
ASSERT(!(scope_info->HasContext() & current.is_null()));
if (scope_info->Type() == CATCH_SCOPE) {
+ ASSERT(current->IsCatchContext());
Handle<String> name(String::cast(current->extension()));
Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX),
isolate);
@@ -11851,6 +11515,7 @@
thrown_object);
} else if (scope_info->Type() == BLOCK_SCOPE) {
// Materialize the contents of the block scope into a JSObject.
+ ASSERT(current->IsBlockContext());
Handle<JSObject> block_scope_object =
MaterializeBlockScope(isolate, current);
CHECK(!block_scope_object.is_null());
@@ -11903,19 +11568,10 @@
}
}
- Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
- int length = frame_inspector->GetParametersCount();
- Handle<JSObject> arguments =
- isolate->factory()->NewArgumentsObject(function, length);
- Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
-
- AssertNoAllocation no_gc;
- WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
- for (int i = 0; i < length; i++) {
- array->set(i, frame_inspector->GetParameter(i), mode);
- }
- arguments->set_elements(*array);
- return arguments;
+ // FunctionGetArguments can't return a non-Object.
+ return Handle<JSObject>(JSObject::cast(
+ Accessors::FunctionGetArguments(frame_inspector->GetFunction(),
+ NULL)->ToObjectUnchecked()), isolate);
}
@@ -12026,23 +11682,26 @@
isolate, frame, &frame_inspector);
RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
- Handle<Context> frame_context(Context::cast(frame->context()));
- Handle<Context> function_context;
- Handle<ScopeInfo> scope_info(function->shared()->scope_info());
- if (scope_info->HasContext()) {
- function_context = Handle<Context>(frame_context->declaration_context());
+ // Do not materialize the arguments object for eval or top-level code.
+ if (function->shared()->is_function()) {
+ Handle<Context> frame_context(Context::cast(frame->context()));
+ Handle<Context> function_context;
+ Handle<ScopeInfo> scope_info(function->shared()->scope_info());
+ if (scope_info->HasContext()) {
+ function_context = Handle<Context>(frame_context->declaration_context());
+ }
+ Handle<Object> arguments = GetArgumentsObject(isolate,
+ frame,
+ &frame_inspector,
+ scope_info,
+ function_context);
+ SetProperty(isolate,
+ local_scope,
+ isolate->factory()->arguments_string(),
+ arguments,
+ ::NONE,
+ kNonStrictMode);
}
- Handle<Object> arguments = GetArgumentsObject(isolate,
- frame,
- &frame_inspector,
- scope_info,
- function_context);
- SetProperty(isolate,
- local_scope,
- isolate->factory()->arguments_string(),
- arguments,
- ::NONE,
- kNonStrictMode);
// Allocate a new context for the debug evaluation and set the extension
// object build.
@@ -13181,7 +12840,7 @@
CONVERT_ARG_CHECKED(JSReceiver, obj, 0);
if (obj->IsJSGlobalProxy()) {
Object* proto = obj->GetPrototype();
- if (obj->IsNull()) return isolate->heap()->false_value();
+ if (proto->IsNull()) return isolate->heap()->false_value();
ASSERT(proto->IsJSGlobalObject());
obj = JSReceiver::cast(proto);
}
@@ -13196,7 +12855,7 @@
CONVERT_BOOLEAN_ARG_CHECKED(is_observed, 1);
if (obj->IsJSGlobalProxy()) {
Object* proto = obj->GetPrototype();
- if (obj->IsNull()) return isolate->heap()->undefined_value();
+ if (proto->IsNull()) return isolate->heap()->undefined_value();
ASSERT(proto->IsJSGlobalObject());
obj = JSReceiver::cast(proto);
}
diff --git a/src/runtime.h b/src/runtime.h
index 2959fed..b16acd1 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -55,7 +55,7 @@
F(IsPropertyEnumerable, 2, 1) \
F(GetPropertyNames, 1, 1) \
F(GetPropertyNamesFast, 1, 1) \
- F(GetLocalPropertyNames, 1, 1) \
+ F(GetLocalPropertyNames, 2, 1) \
F(GetLocalElementNames, 1, 1) \
F(GetInterceptorInfo, 1, 1) \
F(GetNamedInterceptorPropertyNames, 1, 1) \
@@ -129,6 +129,7 @@
F(NumberToString, 1, 1) \
F(NumberToStringSkipCache, 1, 1) \
F(NumberToInteger, 1, 1) \
+ F(NumberToPositiveInteger, 1, 1) \
F(NumberToIntegerMapMinusZero, 1, 1) \
F(NumberToJSUint32, 1, 1) \
F(NumberToJSInt32, 1, 1) \
@@ -195,8 +196,6 @@
F(ParseJson, 1, 1) \
F(BasicJSONStringify, 1, 1) \
F(QuoteJSONString, 1, 1) \
- F(QuoteJSONStringComma, 1, 1) \
- F(QuoteJSONStringArray, 1, 1) \
\
/* Strings */ \
F(StringCharCodeAt, 2, 1) \
@@ -299,7 +298,8 @@
F(IsJSModule, 1, 1) \
\
/* Harmony symbols */ \
- F(CreateSymbol, 0, 1) \
+ F(CreateSymbol, 1, 1) \
+ F(SymbolName, 1, 1) \
\
/* Harmony proxies */ \
F(CreateJSProxy, 2, 1) \
@@ -341,6 +341,11 @@
F(ObservationWeakMapCreate, 0, 1) \
F(UnwrapGlobalProxy, 1, 1) \
\
+ /* Harmony typed arrays */ \
+ F(ArrayBufferInitialize, 2, 1)\
+ F(ArrayBufferGetByteLength, 1, 1)\
+ F(ArrayBufferSliceImpl, 3, 1) \
+ \
/* Statements */ \
F(NewClosure, 3, 1) \
F(NewObject, 1, 1) \
@@ -514,7 +519,6 @@
#define INLINE_FUNCTION_LIST(F) \
F(IsSmi, 1, 1) \
F(IsNonNegativeSmi, 1, 1) \
- F(IsSymbol, 1, 1) \
F(IsArray, 1, 1) \
F(IsRegExp, 1, 1) \
F(IsConstructCall, 0, 1) \
diff --git a/src/runtime.js b/src/runtime.js
index 09b39ff..22f888d 100644
--- a/src/runtime.js
+++ b/src/runtime.js
@@ -69,16 +69,24 @@
} else if (IS_STRING(x)) {
while (true) {
if (IS_STRING(y)) return %StringEquals(x, y);
+ if (IS_SYMBOL(y)) return 1; // not equal
if (IS_NUMBER(y)) return %NumberEquals(%ToNumber(x), y);
if (IS_BOOLEAN(y)) return %NumberEquals(%ToNumber(x), %ToNumber(y));
if (IS_NULL_OR_UNDEFINED(y)) return 1; // not equal
y = %ToPrimitive(y, NO_HINT);
}
+ } else if (IS_SYMBOL(x)) {
+ while (true) {
+ if (IS_SYMBOL(y)) return %_ObjectEquals(x, y) ? 0 : 1;
+ if (!IS_SPEC_OBJECT(y)) return 1; // not equal
+ y = %ToPrimitive(y, NO_HINT);
+ }
} else if (IS_BOOLEAN(x)) {
if (IS_BOOLEAN(y)) return %_ObjectEquals(x, y) ? 0 : 1;
if (IS_NULL_OR_UNDEFINED(y)) return 1;
if (IS_NUMBER(y)) return %NumberEquals(%ToNumber(x), y);
if (IS_STRING(y)) return %NumberEquals(%ToNumber(x), %ToNumber(y));
+ if (IS_SYMBOL(y)) return 1; // not equal
// y is object.
x = %ToNumber(x);
y = %ToPrimitive(y, NO_HINT);
@@ -508,6 +516,7 @@
if (IS_STRING(x)) return x;
// Normal behavior.
if (!IS_SPEC_OBJECT(x)) return x;
+ if (IS_SYMBOL_WRAPPER(x)) return %_ValueOf(x);
if (hint == NO_HINT) hint = (IS_DATE(x)) ? STRING_HINT : NUMBER_HINT;
return (hint == NUMBER_HINT) ? %DefaultNumber(x) : %DefaultString(x);
}
@@ -532,6 +541,7 @@
}
if (IS_BOOLEAN(x)) return x ? 1 : 0;
if (IS_UNDEFINED(x)) return $NaN;
+ if (IS_SYMBOL(x)) return $NaN;
return (IS_NULL(x)) ? 0 : ToNumber(%DefaultNumber(x));
}
@@ -542,6 +552,7 @@
}
if (IS_BOOLEAN(x)) return x ? 1 : 0;
if (IS_UNDEFINED(x)) return $NaN;
+ if (IS_SYMBOL(x)) return $NaN;
return (IS_NULL(x)) ? 0 : ToNumber(%DefaultNumber(x));
}
@@ -572,6 +583,7 @@
// ECMA-262, section 9.9, page 36.
function ToObject(x) {
if (IS_STRING(x)) return new $String(x);
+ if (IS_SYMBOL(x)) return new $Symbol(x);
if (IS_NUMBER(x)) return new $Number(x);
if (IS_BOOLEAN(x)) return new $Boolean(x);
if (IS_NULL_OR_UNDEFINED(x) && !IS_UNDETECTABLE(x)) {
diff --git a/src/scanner.cc b/src/scanner.cc
index bd2db58..ef2dc2c 100755
--- a/src/scanner.cc
+++ b/src/scanner.cc
@@ -877,7 +877,7 @@
KEYWORD("while", Token::WHILE) \
KEYWORD("with", Token::WITH) \
KEYWORD_GROUP('y') \
- KEYWORD("yield", Token::FUTURE_STRICT_RESERVED_WORD)
+ KEYWORD("yield", Token::YIELD)
static Token::Value KeywordOrIdentifierToken(const char* input,
diff --git a/src/scanner.h b/src/scanner.h
index a454750..dd1bfb8 100644
--- a/src/scanner.h
+++ b/src/scanner.h
@@ -53,7 +53,8 @@
kLanguageModeMask = 0x03,
kAllowLazy = 0x04,
kAllowNativesSyntax = 0x08,
- kAllowModules = 0x10
+ kAllowModules = 0x10,
+ kAllowGenerators = 0x20
};
STATIC_ASSERT((kLanguageModeMask & CLASSIC_MODE) == CLASSIC_MODE);
diff --git a/src/spaces-inl.h b/src/spaces-inl.h
index aeac570..77117b8 100644
--- a/src/spaces-inl.h
+++ b/src/spaces-inl.h
@@ -351,23 +351,6 @@
}
-template <typename StringType>
-void NewSpace::ShrinkStringAtAllocationBoundary(String* string, int length) {
- ASSERT(length <= string->length());
- ASSERT(string->IsSeqString());
- ASSERT(string->address() + StringType::SizeFor(string->length()) ==
- allocation_info_.top);
- Address old_top = allocation_info_.top;
- allocation_info_.top =
- string->address() + StringType::SizeFor(length);
- string->set_length(length);
- if (Marking::IsBlack(Marking::MarkBitFrom(string))) {
- int delta = static_cast<int>(old_top - allocation_info_.top);
- MemoryChunk::IncrementLiveBytesFromMutator(string->address(), -delta);
- }
-}
-
-
bool FreeListNode::IsFreeListNode(HeapObject* object) {
Map* map = object->map();
Heap* heap = object->GetHeap();
diff --git a/src/spaces.cc b/src/spaces.cc
index 2952fd5..f8e6a1e 100644
--- a/src/spaces.cc
+++ b/src/spaces.cc
@@ -1030,10 +1030,10 @@
size = 16 * kPointerSize * KB;
break;
case CODE_SPACE:
- if (kPointerSize == 8) {
- // On x64 we allocate code pages in a special way (from the reserved
- // 2Byte area). That part of the code is not yet upgraded to handle
- // small pages.
+ if (heap()->isolate()->code_range()->exists()) {
+ // When code range exists, code pages are allocated in a special way
+ // (from the reserved code range). That part of the code is not yet
+ // upgraded to handle small pages.
size = AreaSize();
} else {
size = 384 * KB;
diff --git a/src/spaces.h b/src/spaces.h
index 39c19a4..65eefd0 100644
--- a/src/spaces.h
+++ b/src/spaces.h
@@ -2419,11 +2419,6 @@
virtual bool ReserveSpace(int bytes);
- // Resizes a sequential string which must be the most recent thing that was
- // allocated in new space.
- template <typename StringType>
- inline void ShrinkStringAtAllocationBoundary(String* string, int len);
-
#ifdef VERIFY_HEAP
// Verify the active semispace.
virtual void Verify();
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index c104d80..553c6f5 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -123,10 +123,13 @@
Handle<Code> StubCache::FindHandler(Handle<Name> name,
+ Handle<JSObject> receiver,
Handle<JSObject> stub_holder,
Code::Kind kind,
- Code::StubType type,
- Code::ExtraICState extra_ic_state) {
+ Code::StubType type) {
+ Code::ExtraICState extra_ic_state = Code::ComputeExtraICState(
+ receiver.is_identical_to(stub_holder) ? Code::OWN_STUB
+ : Code::PROTOTYPE_STUB);
ASSERT(type != Code::NORMAL);
Code::Flags flags = Code::ComputeMonomorphicFlags(
Code::STUB, extra_ic_state, type, kind);
@@ -194,7 +197,7 @@
// Compile the stub that is either shared for all names or
// name specific if there are global objects involved.
Handle<Code> handler = FindHandler(
- cache_name, receiver, Code::LOAD_IC, Code::NONEXISTENT);
+ cache_name, receiver, receiver, Code::LOAD_IC, Code::NONEXISTENT);
if (!handler.is_null()) return handler;
LoadStubCompiler compiler(isolate_);
@@ -218,7 +221,7 @@
Handle<JSObject> stub_holder = StubHolder(receiver, holder);
Handle<Code> stub = FindHandler(
- name, stub_holder, Code::LOAD_IC, Code::FIELD);
+ name, receiver, stub_holder, Code::LOAD_IC, Code::FIELD);
if (!stub.is_null()) return stub;
LoadStubCompiler compiler(isolate_);
@@ -237,7 +240,7 @@
ASSERT(v8::ToCData<Address>(callback->getter()) != 0);
Handle<JSObject> stub_holder = StubHolder(receiver, holder);
Handle<Code> stub = FindHandler(
- name, stub_holder, Code::LOAD_IC, Code::CALLBACKS);
+ name, receiver, stub_holder, Code::LOAD_IC, Code::CALLBACKS);
if (!stub.is_null()) return stub;
LoadStubCompiler compiler(isolate_);
@@ -254,7 +257,7 @@
Handle<JSFunction> getter) {
Handle<JSObject> stub_holder = StubHolder(receiver, holder);
Handle<Code> stub = FindHandler(
- name, stub_holder, Code::LOAD_IC, Code::CALLBACKS);
+ name, receiver, stub_holder, Code::LOAD_IC, Code::CALLBACKS);
if (!stub.is_null()) return stub;
LoadStubCompiler compiler(isolate_);
@@ -271,7 +274,7 @@
Handle<JSFunction> value) {
Handle<JSObject> stub_holder = StubHolder(receiver, holder);
Handle<Code> handler = FindHandler(
- name, stub_holder, Code::LOAD_IC, Code::CONSTANT_FUNCTION);
+ name, receiver, stub_holder, Code::LOAD_IC, Code::CONSTANT_FUNCTION);
if (!handler.is_null()) return handler;
LoadStubCompiler compiler(isolate_);
@@ -287,7 +290,7 @@
Handle<JSObject> holder) {
Handle<JSObject> stub_holder = StubHolder(receiver, holder);
Handle<Code> stub = FindHandler(
- name, stub_holder, Code::LOAD_IC, Code::INTERCEPTOR);
+ name, receiver, stub_holder, Code::LOAD_IC, Code::INTERCEPTOR);
if (!stub.is_null()) return stub;
LoadStubCompiler compiler(isolate_);
@@ -334,7 +337,7 @@
Handle<JSObject> stub_holder = StubHolder(receiver, holder);
Handle<Code> stub = FindHandler(
- name, stub_holder, Code::KEYED_LOAD_IC, Code::FIELD);
+ name, receiver, stub_holder, Code::KEYED_LOAD_IC, Code::FIELD);
if (!stub.is_null()) return stub;
KeyedLoadStubCompiler compiler(isolate_);
@@ -351,7 +354,8 @@
Handle<JSFunction> value) {
Handle<JSObject> stub_holder = StubHolder(receiver, holder);
Handle<Code> handler = FindHandler(
- name, stub_holder, Code::KEYED_LOAD_IC, Code::CONSTANT_FUNCTION);
+ name, receiver, stub_holder, Code::KEYED_LOAD_IC,
+ Code::CONSTANT_FUNCTION);
if (!handler.is_null()) return handler;
KeyedLoadStubCompiler compiler(isolate_);
@@ -366,7 +370,7 @@
Handle<JSObject> holder) {
Handle<JSObject> stub_holder = StubHolder(receiver, holder);
Handle<Code> stub = FindHandler(
- name, stub_holder, Code::KEYED_LOAD_IC, Code::INTERCEPTOR);
+ name, receiver, stub_holder, Code::KEYED_LOAD_IC, Code::INTERCEPTOR);
if (!stub.is_null()) return stub;
KeyedLoadStubCompiler compiler(isolate_);
@@ -384,7 +388,7 @@
Handle<ExecutableAccessorInfo> callback) {
Handle<JSObject> stub_holder = StubHolder(receiver, holder);
Handle<Code> stub = FindHandler(
- name, stub_holder, Code::KEYED_LOAD_IC, Code::CALLBACKS);
+ name, receiver, stub_holder, Code::KEYED_LOAD_IC, Code::CALLBACKS);
if (!stub.is_null()) return stub;
KeyedLoadStubCompiler compiler(isolate_);
@@ -397,7 +401,7 @@
Handle<Code> StubCache::ComputeStoreField(Handle<Name> name,
Handle<JSObject> receiver,
- int field_index,
+ LookupResult* lookup,
Handle<Map> transition,
StrictModeFlag strict_mode) {
Code::StubType type =
@@ -409,7 +413,7 @@
StoreStubCompiler compiler(isolate_, strict_mode);
Handle<Code> code =
- compiler.CompileStoreField(receiver, field_index, transition, name);
+ compiler.CompileStoreField(receiver, lookup, transition, name);
JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
@@ -532,7 +536,7 @@
Handle<Code> StubCache::ComputeKeyedStoreField(Handle<Name> name,
Handle<JSObject> receiver,
- int field_index,
+ LookupResult* lookup,
Handle<Map> transition,
StrictModeFlag strict_mode) {
Code::StubType type =
@@ -543,7 +547,7 @@
KeyedStoreStubCompiler compiler(isolate(), strict_mode, STANDARD_STORE);
Handle<Code> code =
- compiler.CompileStoreField(receiver, field_index, transition, name);
+ compiler.CompileStoreField(receiver, lookup, transition, name);
JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
@@ -1584,7 +1588,7 @@
Handle<Code> BaseStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
- int index,
+ LookupResult* lookup,
Handle<Map> transition,
Handle<Name> name) {
Label miss, miss_restore_name;
@@ -1594,7 +1598,7 @@
// Generate store field code.
GenerateStoreField(masm(),
object,
- index,
+ lookup,
transition,
name,
receiver(), this->name(), value(), scratch1(), scratch2(),
diff --git a/src/stub-cache.h b/src/stub-cache.h
index 7c45566..bca3b7b 100644
--- a/src/stub-cache.h
+++ b/src/stub-cache.h
@@ -85,10 +85,10 @@
Handle<Code> FindHandler(
Handle<Name> name,
+ Handle<JSObject> receiver,
Handle<JSObject> stub_holder,
Code::Kind kind,
- Code::StubType type,
- Code::ExtraICState extra_state = Code::kNoExtraICState);
+ Code::StubType type);
Handle<Code> ComputeMonomorphicIC(Handle<JSObject> receiver,
Handle<Code> handler,
@@ -161,7 +161,7 @@
Handle<Code> ComputeStoreField(Handle<Name> name,
Handle<JSObject> object,
- int field_index,
+ LookupResult* lookup,
Handle<Map> transition,
StrictModeFlag strict_mode);
@@ -192,7 +192,7 @@
Handle<Code> ComputeKeyedStoreField(Handle<Name> name,
Handle<JSObject> object,
- int field_index,
+ LookupResult* lookup,
Handle<Map> transition,
StrictModeFlag strict_mode);
@@ -511,7 +511,7 @@
void GenerateStoreField(MacroAssembler* masm,
Handle<JSObject> object,
- int index,
+ LookupResult* lookup,
Handle<Map> transition,
Handle<Name> name,
Register receiver_reg,
@@ -782,7 +782,7 @@
virtual ~BaseStoreStubCompiler() { }
Handle<Code> CompileStoreField(Handle<JSObject> object,
- int index,
+ LookupResult* lookup,
Handle<Map> transition,
Handle<Name> name);
diff --git a/src/symbol.js b/src/symbol.js
index b7f9dc9..fb7476f 100644
--- a/src/symbol.js
+++ b/src/symbol.js
@@ -27,13 +27,55 @@
"use strict";
-var $Symbol = function() { return %CreateSymbol() }
-global.Symbol = $Symbol
+var $Symbol = global.Symbol;
-// Symbols only have a toString method and no prototype.
-var SymbolDelegate = {
- __proto__: null,
- toString: $Object.prototype.toString
+function SymbolConstructor(x) {
+ var value =
+ IS_SYMBOL(x) ? x : %CreateSymbol(IS_UNDEFINED(x) ? x : ToString(x));
+ if (%_IsConstructCall()) {
+ %_SetValueOf(this, value);
+ } else {
+ return value;
+ }
}
-$Object.freeze(SymbolDelegate)
+function SymbolGetName() {
+ var symbol = IS_SYMBOL_WRAPPER(this) ? %_ValueOf(this) : this;
+ if (!IS_SYMBOL(symbol)) {
+ throw MakeTypeError(
+ 'incompatible_method_receiver', ["Symbol.prototype.name", this]);
+ }
+ return %SymbolName(symbol);
+}
+
+function SymbolToString() {
+ throw MakeTypeError('symbol_to_string');
+}
+
+function SymbolValueOf() {
+ // NOTE: Both Symbol objects and values can enter here as
+ // 'this'. This is not as dictated by ECMA-262.
+ if (!IS_SYMBOL(this) && !IS_SYMBOL_WRAPPER(this)) {
+ throw MakeTypeError(
+ 'incompatible_method_receiver', ["Symbol.prototype.valueOf", this]);
+ }
+ return %_ValueOf(this);
+}
+
+//-------------------------------------------------------------------
+
+function SetUpSymbol() {
+ %CheckIsBootstrapping();
+
+ %SetCode($Symbol, SymbolConstructor);
+ %FunctionSetPrototype($Symbol, new $Symbol());
+ %SetProperty($Symbol.prototype, "constructor", $Symbol, DONT_ENUM);
+
+ InstallGetter($Symbol.prototype, "name", SymbolGetName);
+ InstallFunctions($Symbol.prototype, DONT_ENUM, $Array(
+ "toString", SymbolToString,
+ "valueOf", SymbolValueOf
+ ));
+}
+
+SetUpSymbol();
diff --git a/src/token.h b/src/token.h
index 4078a15..04d7f76 100644
--- a/src/token.h
+++ b/src/token.h
@@ -174,6 +174,7 @@
K(EXPORT, "export", 0) \
K(IMPORT, "import", 0) \
K(LET, "let", 0) \
+ K(YIELD, "yield", 0) \
\
/* Illegal token - not able to scan. */ \
T(ILLEGAL, "ILLEGAL", 0) \
diff --git a/src/type-info.cc b/src/type-info.cc
index f31edb7..39a01f5 100644
--- a/src/type-info.cc
+++ b/src/type-info.cc
@@ -283,11 +283,12 @@
case RECEIVER_MAP_CHECK:
UNREACHABLE();
break;
- case SYMBOL_CHECK:
- return Handle<JSObject>(native_context_->symbol_delegate());
case STRING_CHECK:
function = native_context_->string_function();
break;
+ case SYMBOL_CHECK:
+ function = native_context_->symbol_function();
+ break;
case NUMBER_CHECK:
function = native_context_->number_function();
break;
diff --git a/src/typedarray.js b/src/typedarray.js
new file mode 100644
index 0000000..c3e3ebd
--- /dev/null
+++ b/src/typedarray.js
@@ -0,0 +1,98 @@
+// Copyright 2013 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.
+
+"use strict";
+
+var $ArrayBuffer = global.__ArrayBuffer;
+
+function ArrayBufferConstructor(byteLength) { // length = 1
+ if (%_IsConstructCall()) {
+ var l = TO_POSITIVE_INTEGER(byteLength);
+ %ArrayBufferInitialize(this, l);
+ } else {
+ return new $ArrayBuffer(byteLength);
+ }
+}
+
+function ArrayBufferGetByteLength() {
+ if (!IS_ARRAYBUFFER(this)) {
+ throw MakeTypeError('incompatible_method_receiver',
+ ['ArrayBuffer.prototype.byteLength', this]);
+ }
+ return %ArrayBufferGetByteLength(this);
+}
+
+// ES6 Draft 15.13.5.5.3
+function ArrayBufferSlice(start, end) {
+ if (!IS_ARRAYBUFFER(this)) {
+ throw MakeTypeError('incompatible_method_receiver',
+ ['ArrayBuffer.prototype.slice', this]);
+ }
+
+ var relativeStart = TO_INTEGER(start);
+ var first;
+ if (relativeStart < 0) {
+ first = MathMax(this.byteLength + relativeStart, 0);
+ } else {
+ first = MathMin(relativeStart, this.byteLength);
+ }
+ var relativeEnd = IS_UNDEFINED(end) ? this.byteLength : TO_INTEGER(end);
+ var fin;
+ if (relativeEnd < 0) {
+ fin = MathMax(this.byteLength + relativeEnd, 0);
+ } else {
+ fin = MathMin(relativeEnd, this.byteLength);
+ }
+
+ var newLen = fin - first;
+ // TODO(dslomov): implement inheritance
+ var result = new $ArrayBuffer(newLen);
+
+ %ArrayBufferSliceImpl(this, result, first);
+ return result;
+}
+
+
+
+// -------------------------------------------------------------------
+
+(function () {
+ %CheckIsBootstrapping();
+
+ // Set up the Uint16Array constructor function.
+ %SetCode($ArrayBuffer, ArrayBufferConstructor);
+
+ // Set up the constructor property on the ArrayBuffer prototype object.
+ %SetProperty($ArrayBuffer.prototype, "constructor", $ArrayBuffer, DONT_ENUM);
+
+ InstallGetter($ArrayBuffer.prototype, "byteLength", ArrayBufferGetByteLength);
+
+ InstallFunctions($ArrayBuffer.prototype, DONT_ENUM, $Array(
+ "slice", ArrayBufferSlice
+ ));
+
+})();
diff --git a/src/v8globals.h b/src/v8globals.h
index 8874cfb..4b4d312 100644
--- a/src/v8globals.h
+++ b/src/v8globals.h
@@ -296,7 +296,7 @@
enum InlineCacheHolderFlag {
OWN_MAP, // For fast properties objects.
- DELEGATE_MAP // For slow properties objects (except GlobalObjects).
+ PROTOTYPE_MAP // For slow properties objects (except GlobalObjects).
};
diff --git a/src/v8natives.js b/src/v8natives.js
index 24ad22d..d9dc096 100644
--- a/src/v8natives.js
+++ b/src/v8natives.js
@@ -233,7 +233,6 @@
function ObjectToString() {
if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) return "[object Undefined]";
if (IS_NULL(this)) return "[object Null]";
- if (IS_SYMBOL(this)) return "[object Symbol]";
return "[object " + %_ClassOf(ToObject(this)) + "]";
}
@@ -257,6 +256,9 @@
// ECMA-262 - 15.2.4.5
function ObjectHasOwnProperty(V) {
if (%IsJSProxy(this)) {
+ // TODO(rossberg): adjust once there is a story for symbols vs proxies.
+ if (IS_SYMBOL(V)) return false;
+
var handler = %GetHandler(this);
return CallTrap1(handler, "hasOwn", DerivedHasOwnTrap, ToName(V));
}
@@ -279,6 +281,9 @@
function ObjectPropertyIsEnumerable(V) {
var P = ToName(V);
if (%IsJSProxy(this)) {
+ // TODO(rossberg): adjust once there is a story for symbols vs proxies.
+ if (IS_SYMBOL(V)) return false;
+
var desc = GetOwnProperty(this, P);
return IS_UNDEFINED(desc) ? false : desc.isEnumerable();
}
@@ -646,6 +651,9 @@
function GetOwnProperty(obj, v) {
var p = ToName(v);
if (%IsJSProxy(obj)) {
+ // TODO(rossberg): adjust once there is a story for symbols vs proxies.
+ if (IS_SYMBOL(v)) return void 0;
+
var handler = %GetHandler(obj);
var descriptor = CallTrap1(handler, "getOwnPropertyDescriptor", void 0, p);
if (IS_UNDEFINED(descriptor)) return descriptor;
@@ -686,6 +694,9 @@
// Harmony proxies.
function DefineProxyProperty(obj, p, attributes, should_throw) {
+ // TODO(rossberg): adjust once there is a story for symbols vs proxies.
+ if (IS_SYMBOL(p)) return false;
+
var handler = %GetHandler(obj);
var result = CallTrap2(handler, "defineProperty", void 0, p, attributes);
if (!ToBoolean(result)) {
@@ -865,7 +876,7 @@
// DefineObjectProperty() to modify its value.
// Step 3 - Special handling for length property.
- if (p == "length") {
+ if (p === "length") {
var length = obj.length;
if (!desc.hasValue()) {
return DefineObjectProperty(obj, "length", desc, should_throw);
@@ -951,6 +962,9 @@
// ES5 section 8.12.9, ES5 section 15.4.5.1 and Harmony proxies.
function DefineOwnProperty(obj, p, desc, should_throw) {
if (%IsJSProxy(obj)) {
+ // TODO(rossberg): adjust once there is a story for symbols vs proxies.
+ if (IS_SYMBOL(p)) return false;
+
var attributes = FromGenericPropertyDescriptor(desc);
return DefineProxyProperty(obj, p, attributes, should_throw);
} else if (IS_ARRAY(obj)) {
@@ -988,16 +1002,20 @@
}
var n = ToUint32(obj.length);
var array = new $Array(n);
+ var realLength = 0;
var names = { __proto__: null }; // TODO(rossberg): use sets once ready.
for (var index = 0; index < n; index++) {
var s = ToName(obj[index]);
+ // TODO(rossberg): adjust once there is a story for symbols vs proxies.
if (IS_SYMBOL(s) && !includeSymbols) continue;
if (%HasLocalProperty(names, s)) {
throw MakeTypeError("proxy_repeated_prop_name", [obj, trap, s]);
}
array[index] = s;
+ ++realLength;
names[s] = 0;
}
+ array.length = realLength;
return array;
}
@@ -1011,7 +1029,7 @@
if (%IsJSProxy(obj)) {
var handler = %GetHandler(obj);
var names = CallTrap0(handler, "getOwnPropertyNames", void 0);
- return ToNameArray(names, "getOwnPropertyNames", true);
+ return ToNameArray(names, "getOwnPropertyNames", false);
}
var nameArrays = new InternalArray();
@@ -1037,7 +1055,7 @@
// Find all the named properties.
// Get the local property names.
- nameArrays.push(%GetLocalPropertyNames(obj));
+ nameArrays.push(%GetLocalPropertyNames(obj, false));
// Get names for named interceptor properties if any.
if ((interceptorInfo & 2) != 0) {
@@ -1057,7 +1075,8 @@
var propertySet = { __proto__: null };
var j = 0;
for (var i = 0; i < propertyNames.length; ++i) {
- var name = ToName(propertyNames[i]);
+ if (IS_SYMBOL(propertyNames[i])) continue;
+ var name = ToString(propertyNames[i]);
// We need to check for the exact property value since for intrinsic
// properties like toString if(propertySet["toString"]) will always
// succeed.
diff --git a/src/v8utils.h b/src/v8utils.h
index 606d8e7..b5c8f08 100644
--- a/src/v8utils.h
+++ b/src/v8utils.h
@@ -151,20 +151,19 @@
// Copies data from |src| to |dst|. The data spans must not overlap.
template <typename T>
-inline void CopyBytes(T* dst, T* src, int num_bytes) {
+inline void CopyBytes(T* dst, T* src, size_t num_bytes) {
STATIC_ASSERT(sizeof(T) == 1);
ASSERT(Min(dst, src) + num_bytes <= Max(dst, src));
- ASSERT(num_bytes >= 0);
if (num_bytes == 0) return;
// Use block copying OS::MemCopy if the segment we're copying is
// enough to justify the extra call/setup overhead.
static const int kBlockCopyLimit = OS::kMinComplexMemCopy;
- if (num_bytes >= kBlockCopyLimit) {
+ if (num_bytes >= static_cast<size_t>(kBlockCopyLimit)) {
OS::MemCopy(dst, src, num_bytes);
} else {
- int remaining = num_bytes;
+ size_t remaining = num_bytes;
do {
remaining--;
*dst++ = *src++;
diff --git a/src/version.cc b/src/version.cc
index 0ecf596..64ed98d 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,8 +34,8 @@
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 3
#define MINOR_VERSION 17
-#define BUILD_NUMBER 15
-#define PATCH_LEVEL 6
+#define BUILD_NUMBER 16
+#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
#define IS_CANDIDATE_VERSION 0
diff --git a/src/x64/builtins-x64.cc b/src/x64/builtins-x64.cc
index 0b70c1a..2da3de2 100644
--- a/src/x64/builtins-x64.cc
+++ b/src/x64/builtins-x64.cc
@@ -220,12 +220,12 @@
__ movzxbq(rdi, FieldOperand(rax, Map::kInstanceSizeOffset));
__ shl(rdi, Immediate(kPointerSizeLog2));
// rdi: size of new object
- __ AllocateInNewSpace(rdi,
- rbx,
- rdi,
- no_reg,
- &rt_call,
- NO_ALLOCATION_FLAGS);
+ __ Allocate(rdi,
+ rbx,
+ rdi,
+ no_reg,
+ &rt_call,
+ NO_ALLOCATION_FLAGS);
// Allocated the JSObject, now initialize the fields.
// rax: initial map
// rbx: JSObject (not HeapObject tagged - the actual address).
@@ -287,14 +287,14 @@
// rbx: JSObject
// rdi: start of next object (will be start of FixedArray)
// rdx: number of elements in properties array
- __ AllocateInNewSpace(FixedArray::kHeaderSize,
- times_pointer_size,
- rdx,
- rdi,
- rax,
- no_reg,
- &undo_allocation,
- RESULT_CONTAINS_TOP);
+ __ Allocate(FixedArray::kHeaderSize,
+ times_pointer_size,
+ rdx,
+ rdi,
+ rax,
+ no_reg,
+ &undo_allocation,
+ RESULT_CONTAINS_TOP);
// Initialize the FixedArray.
// rbx: JSObject
@@ -416,10 +416,6 @@
__ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx);
__ j(above_equal, &exit);
- // Symbols are "objects".
- __ CmpInstanceType(rcx, SYMBOL_TYPE);
- __ j(equal, &exit);
-
// Throw away the result of the constructor invocation and use the
// on-stack receiver as the result.
__ bind(&use_receiver);
@@ -1216,14 +1212,14 @@
// requested elements.
SmiIndex index =
masm->SmiToIndex(kScratchRegister, array_size, kPointerSizeLog2);
- __ AllocateInNewSpace(JSArray::kSize + FixedArray::kHeaderSize,
- index.scale,
- index.reg,
- result,
- elements_array_end,
- scratch,
- gc_required,
- TAG_OBJECT);
+ __ Allocate(JSArray::kSize + FixedArray::kHeaderSize,
+ index.scale,
+ index.reg,
+ result,
+ elements_array_end,
+ scratch,
+ gc_required,
+ TAG_OBJECT);
// Allocated the JSArray. Now initialize the fields except for the elements
// array.
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index 4ff1635..fffd37f 100644
--- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc
@@ -95,7 +95,7 @@
// stack param count needs (constructor pointer, and single argument)
descriptor->stack_parameter_count_ = &rax;
descriptor->register_params_ = registers;
- descriptor->extra_expression_stack_count_ = 1;
+ descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
descriptor->deoptimization_handler_ =
FUNCTION_ADDR(ArrayConstructor_StubFailure);
}
@@ -2386,34 +2386,6 @@
}
-void ArrayLengthStub::Generate(MacroAssembler* masm) {
- Label miss;
- Register receiver;
- if (kind() == Code::KEYED_LOAD_IC) {
- // ----------- S t a t e -------------
- // -- rax : key
- // -- rdx : receiver
- // -- rsp[0] : return address
- // -----------------------------------
- __ Cmp(rax, masm->isolate()->factory()->length_string());
- __ j(not_equal, &miss);
- receiver = rdx;
- } else {
- ASSERT(kind() == Code::LOAD_IC);
- // ----------- S t a t e -------------
- // -- rax : receiver
- // -- rcx : name
- // -- rsp[0] : return address
- // -----------------------------------
- receiver = rax;
- }
-
- StubCompiler::GenerateLoadArrayLength(masm, receiver, r8, &miss);
- __ bind(&miss);
- StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind()));
-}
-
-
void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
Label miss;
Register receiver;
@@ -2663,7 +2635,7 @@
__ addq(r8, Immediate(Heap::kArgumentsObjectSize));
// Do the allocation of all three objects in one go.
- __ AllocateInNewSpace(r8, rax, rdx, rdi, &runtime, TAG_OBJECT);
+ __ Allocate(r8, rax, rdx, rdi, &runtime, TAG_OBJECT);
// rax = address of new object(s) (tagged)
// rcx = argument count (untagged)
@@ -2881,7 +2853,7 @@
__ addq(rcx, Immediate(Heap::kArgumentsObjectSizeStrict));
// Do the allocation of both objects in one go.
- __ AllocateInNewSpace(rcx, rax, rdx, rbx, &runtime, TAG_OBJECT);
+ __ Allocate(rcx, rax, rdx, rbx, &runtime, TAG_OBJECT);
// Get the arguments boilerplate from the current native context.
__ movq(rdi, Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
@@ -3414,14 +3386,14 @@
// Allocate RegExpResult followed by FixedArray with size in rbx.
// JSArray: [Map][empty properties][Elements][Length-smi][index][input]
// Elements: [Map][Length][..elements..]
- __ AllocateInNewSpace(JSRegExpResult::kSize + FixedArray::kHeaderSize,
- times_pointer_size,
- rbx, // In: Number of elements.
- rax, // Out: Start of allocation (tagged).
- rcx, // Out: End of allocation.
- rdx, // Scratch register
- &slowcase,
- TAG_OBJECT);
+ __ Allocate(JSRegExpResult::kSize + FixedArray::kHeaderSize,
+ times_pointer_size,
+ rbx, // In: Number of elements.
+ rax, // Out: Start of allocation (tagged).
+ rcx, // Out: End of allocation.
+ rdx, // Scratch register
+ &slowcase,
+ TAG_OBJECT);
// rax: Start of allocated area, object-tagged.
// rbx: Number of array elements as int32.
// r8: Number of array elements as smi.
@@ -6811,8 +6783,10 @@
__ movq(rbx, MemOperand(rbp, parameter_count_offset));
masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE);
__ pop(rcx);
- __ lea(rsp, MemOperand(rsp, rbx, times_pointer_size,
- extra_expression_stack_count_ * kPointerSize));
+ int additional_offset = function_mode_ == JS_FUNCTION_STUB_MODE
+ ? kPointerSize
+ : 0;
+ __ lea(rsp, MemOperand(rsp, rbx, times_pointer_size, additional_offset));
__ jmp(rcx); // Return to IC Miss stub, continuation still on stack.
}
diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc
index ec66127..6f32f7c 100644
--- a/src/x64/codegen-x64.cc
+++ b/src/x64/codegen-x64.cc
@@ -347,7 +347,7 @@
// Allocate new backing store.
__ bind(&new_backing_store);
__ lea(rdi, Operand(r9, times_pointer_size, FixedArray::kHeaderSize));
- __ AllocateInNewSpace(rdi, r14, r11, r15, fail, TAG_OBJECT);
+ __ Allocate(rdi, r14, r11, r15, fail, TAG_OBJECT);
// Set backing store's map
__ LoadRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex);
__ movq(FieldOperand(r14, HeapObject::kMapOffset), rdi);
@@ -435,7 +435,7 @@
// r8 : source FixedDoubleArray
// r9 : number of elements
__ lea(rdi, Operand(r9, times_pointer_size, FixedArray::kHeaderSize));
- __ AllocateInNewSpace(rdi, r11, r14, r15, &gc_required, TAG_OBJECT);
+ __ Allocate(rdi, r11, r14, r15, &gc_required, TAG_OBJECT);
// r11: destination FixedArray
__ LoadRoot(rdi, Heap::kFixedArrayMapRootIndex);
__ movq(FieldOperand(r11, HeapObject::kMapOffset), rdi);
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index 8ff12df..322479d 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -2678,28 +2678,6 @@
}
-void FullCodeGenerator::EmitIsSymbol(CallRuntime* expr) {
- ZoneList<Expression*>* args = expr->arguments();
- ASSERT(args->length() == 1);
-
- VisitForAccumulatorValue(args->at(0));
-
- Label materialize_true, materialize_false;
- Label* if_true = NULL;
- Label* if_false = NULL;
- Label* fall_through = NULL;
- context()->PrepareTest(&materialize_true, &materialize_false,
- &if_true, &if_false, &fall_through);
-
- __ JumpIfSmi(rax, if_false);
- __ CmpObjectType(rax, SYMBOL_TYPE, rbx);
- PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
- Split(equal, if_true, if_false, fall_through);
-
- context()->Plug(if_true, if_false);
-}
-
-
void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
ASSERT(args->length() == 1);
@@ -4271,6 +4249,10 @@
__ testb(FieldOperand(rdx, Map::kBitFieldOffset),
Immediate(1 << Map::kIsUndetectable));
Split(zero, if_true, if_false, fall_through);
+ } else if (check->Equals(isolate()->heap()->symbol_string())) {
+ __ JumpIfSmi(rax, if_false);
+ __ CmpObjectType(rax, SYMBOL_TYPE, rdx);
+ Split(equal, if_true, if_false, fall_through);
} else if (check->Equals(isolate()->heap()->boolean_string())) {
__ CompareRoot(rax, Heap::kTrueValueRootIndex);
__ j(equal, if_true);
@@ -4302,10 +4284,6 @@
__ CompareRoot(rax, Heap::kNullValueRootIndex);
__ j(equal, if_true);
}
- if (FLAG_harmony_symbols) {
- __ CmpObjectType(rax, SYMBOL_TYPE, rdx);
- __ j(equal, if_true);
- }
__ CmpObjectType(rax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, rdx);
__ j(below, if_false);
__ CmpInstanceType(rdx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index b9bd30b..817a9d3 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -1574,13 +1574,6 @@
}
-void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
- Register result = ToRegister(instr->result());
- Register array = ToRegister(instr->value());
- __ movq(result, FieldOperand(array, JSArray::kLengthOffset));
-}
-
-
void LCodeGen::DoFixedArrayBaseLength(LFixedArrayBaseLength* instr) {
Register result = ToRegister(instr->result());
Register array = ToRegister(instr->value());
@@ -5129,7 +5122,7 @@
__ Allocate(size, result, temp, no_reg, deferred->entry(), flags);
} else {
Register size = ToRegister(instr->size());
- __ AllocateInNewSpace(size, result, temp, no_reg, deferred->entry(), flags);
+ __ Allocate(size, result, temp, no_reg, deferred->entry(), flags);
}
__ bind(deferred->exit());
@@ -5538,6 +5531,11 @@
Immediate(1 << Map::kIsUndetectable));
final_branch_condition = zero;
+ } else if (type_name->Equals(heap()->symbol_string())) {
+ __ JumpIfSmi(input, false_label);
+ __ CmpObjectType(input, SYMBOL_TYPE, input);
+ final_branch_condition = equal;
+
} else if (type_name->Equals(heap()->boolean_string())) {
__ CompareRoot(input, Heap::kTrueValueRootIndex);
__ j(equal, true_label);
@@ -5572,13 +5570,7 @@
__ CompareRoot(input, Heap::kNullValueRootIndex);
__ j(equal, true_label);
}
- if (FLAG_harmony_symbols) {
- __ CmpObjectType(input, SYMBOL_TYPE, input);
- __ j(equal, true_label);
- __ CmpInstanceType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
- } else {
- __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
- }
+ __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
__ j(below, false_label);
__ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
__ j(above, false_label);
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index 16248ee..9a3166e 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -879,6 +879,35 @@
LInstruction* instr = current->CompileToLithium(this);
if (instr != NULL) {
+#if DEBUG
+ // Make sure that the lithium instruction has either no fixed register
+ // constraints in temps or the result OR no uses that are only used at
+ // start. If this invariant doesn't hold, the register allocator can decide
+ // to insert a split of a range immediately before the instruction due to an
+ // already allocated register needing to be used for the instruction's fixed
+ // register constraint. In this case, The register allocator won't see an
+ // interference between the split child and the use-at-start (it would if
+ // the it was just a plain use), so it is free to move the split child into
+ // the same register that is used for the use-at-start.
+ // See https://code.google.com/p/chromium/issues/detail?id=201590
+ if (!(instr->ClobbersRegisters() && instr->ClobbersDoubleRegisters())) {
+ int fixed = 0;
+ int used_at_start = 0;
+ for (UseIterator it(instr); !it.Done(); it.Advance()) {
+ LUnallocated* operand = LUnallocated::cast(it.Current());
+ if (operand->IsUsedAtStart()) ++used_at_start;
+ }
+ if (instr->Output() != NULL) {
+ if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed;
+ }
+ for (TempIterator it(instr); !it.Done(); it.Advance()) {
+ LUnallocated* operand = LUnallocated::cast(it.Current());
+ if (operand->HasFixedPolicy()) ++fixed;
+ }
+ ASSERT(fixed == 0 || used_at_start == 0);
+ }
+#endif
+
if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
instr = AssignPointerMap(instr);
}
@@ -1632,12 +1661,6 @@
}
-LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
- LOperand* array = UseRegisterAtStart(instr->value());
- return DefineAsRegister(new(zone()) LJSArrayLength(array));
-}
-
-
LInstruction* LChunkBuilder::DoFixedArrayBaseLength(
HFixedArrayBaseLength* instr) {
LOperand* array = UseRegisterAtStart(instr->value());
diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h
index 9e3e836..051f9a4 100644
--- a/src/x64/lithium-x64.h
+++ b/src/x64/lithium-x64.h
@@ -121,7 +121,6 @@
V(IsStringAndBranch) \
V(IsSmiAndBranch) \
V(IsUndetectableAndBranch) \
- V(JSArrayLength) \
V(Label) \
V(LazyBailout) \
V(LoadContextSlot) \
@@ -1109,19 +1108,6 @@
};
-class LJSArrayLength: public LTemplateInstruction<1, 1, 0> {
- public:
- explicit LJSArrayLength(LOperand* value) {
- inputs_[0] = value;
- }
-
- LOperand* value() { return inputs_[0]; }
-
- DECLARE_CONCRETE_INSTRUCTION(JSArrayLength, "js-array-length")
- DECLARE_HYDROGEN_ACCESSOR(JSArrayLength)
-};
-
-
class LFixedArrayBaseLength: public LTemplateInstruction<1, 1, 0> {
public:
explicit LFixedArrayBaseLength(LOperand* value) {
@@ -2034,7 +2020,7 @@
};
-class LTransitionElementsKind: public LTemplateInstruction<1, 1, 2> {
+class LTransitionElementsKind: public LTemplateInstruction<0, 1, 2> {
public:
LTransitionElementsKind(LOperand* object,
LOperand* new_map_temp,
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc
index 9ecf66c..6c1c19d 100644
--- a/src/x64/macro-assembler-x64.cc
+++ b/src/x64/macro-assembler-x64.cc
@@ -3830,16 +3830,15 @@
}
-void MacroAssembler::AllocateInNewSpace(int header_size,
- ScaleFactor element_size,
- Register element_count,
- Register result,
- Register result_end,
- Register scratch,
- Label* gc_required,
- AllocationFlags flags) {
+void MacroAssembler::Allocate(int header_size,
+ ScaleFactor element_size,
+ Register element_count,
+ Register result,
+ Register result_end,
+ Register scratch,
+ Label* gc_required,
+ AllocationFlags flags) {
ASSERT((flags & SIZE_IN_WORDS) == 0);
- ASSERT((flags & PRETENURE_OLD_POINTER_SPACE) == 0);
if (!FLAG_inline_new) {
if (emit_debug_code()) {
// Trash the registers to simulate an allocation failure.
@@ -3866,15 +3865,15 @@
}
// Calculate new top and bail out if new space is exhausted.
- ExternalReference new_space_allocation_limit =
- ExternalReference::new_space_allocation_limit_address(isolate());
+ ExternalReference allocation_limit =
+ AllocationUtils::GetAllocationLimitReference(isolate(), flags);
// We assume that element_count*element_size + header_size does not
// overflow.
lea(result_end, Operand(element_count, element_size, header_size));
addq(result_end, result);
j(carry, gc_required);
- Operand limit_operand = ExternalOperand(new_space_allocation_limit);
+ Operand limit_operand = ExternalOperand(allocation_limit);
cmpq(result_end, limit_operand);
j(above, gc_required);
@@ -3889,14 +3888,13 @@
}
-void MacroAssembler::AllocateInNewSpace(Register object_size,
- Register result,
- Register result_end,
- Register scratch,
- Label* gc_required,
- AllocationFlags flags) {
+void MacroAssembler::Allocate(Register object_size,
+ Register result,
+ Register result_end,
+ Register scratch,
+ Label* gc_required,
+ AllocationFlags flags) {
ASSERT((flags & (RESULT_CONTAINS_TOP | SIZE_IN_WORDS)) == 0);
- ASSERT((flags & PRETENURE_OLD_POINTER_SPACE) == 0);
if (!FLAG_inline_new) {
if (emit_debug_code()) {
// Trash the registers to simulate an allocation failure.
@@ -3916,14 +3914,14 @@
LoadAllocationTopHelper(result, scratch, flags);
// Calculate new top and bail out if new space is exhausted.
- ExternalReference new_space_allocation_limit =
- ExternalReference::new_space_allocation_limit_address(isolate());
+ ExternalReference allocation_limit =
+ AllocationUtils::GetAllocationLimitReference(isolate(), flags);
if (!object_size.is(result_end)) {
movq(result_end, object_size);
}
addq(result_end, result);
j(carry, gc_required);
- Operand limit_operand = ExternalOperand(new_space_allocation_limit);
+ Operand limit_operand = ExternalOperand(allocation_limit);
cmpq(result_end, limit_operand);
j(above, gc_required);
@@ -3991,14 +3989,14 @@
}
// Allocate two byte string in new space.
- AllocateInNewSpace(SeqTwoByteString::kHeaderSize,
- times_1,
- scratch1,
- result,
- scratch2,
- scratch3,
- gc_required,
- TAG_OBJECT);
+ Allocate(SeqTwoByteString::kHeaderSize,
+ times_1,
+ scratch1,
+ result,
+ scratch2,
+ scratch3,
+ gc_required,
+ TAG_OBJECT);
// Set the map, length and hash field.
LoadRoot(kScratchRegister, Heap::kStringMapRootIndex);
@@ -4029,14 +4027,14 @@
}
// Allocate ASCII string in new space.
- AllocateInNewSpace(SeqOneByteString::kHeaderSize,
- times_1,
- scratch1,
- result,
- scratch2,
- scratch3,
- gc_required,
- TAG_OBJECT);
+ Allocate(SeqOneByteString::kHeaderSize,
+ times_1,
+ scratch1,
+ result,
+ scratch2,
+ scratch3,
+ gc_required,
+ TAG_OBJECT);
// Set the map, length and hash field.
LoadRoot(kScratchRegister, Heap::kAsciiStringMapRootIndex);
diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h
index df52159..3381a5b 100644
--- a/src/x64/macro-assembler-x64.h
+++ b/src/x64/macro-assembler-x64.h
@@ -1042,21 +1042,21 @@
Label* gc_required,
AllocationFlags flags);
- void AllocateInNewSpace(int header_size,
- ScaleFactor element_size,
- Register element_count,
- Register result,
- Register result_end,
- Register scratch,
- Label* gc_required,
- AllocationFlags flags);
+ void Allocate(int header_size,
+ ScaleFactor element_size,
+ Register element_count,
+ Register result,
+ Register result_end,
+ Register scratch,
+ Label* gc_required,
+ AllocationFlags flags);
- void AllocateInNewSpace(Register object_size,
- Register result,
- Register result_end,
- Register scratch,
- Label* gc_required,
- AllocationFlags flags);
+ void Allocate(Register object_size,
+ Register result,
+ Register result_end,
+ Register scratch,
+ Label* gc_required,
+ AllocationFlags flags);
// Undo allocation in new space. The object passed and objects allocated after
// it will no longer be allocated. Make sure that no pointers are left to the
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
index 69d7a91..7e900db 100644
--- a/src/x64/stub-cache-x64.cc
+++ b/src/x64/stub-cache-x64.cc
@@ -716,7 +716,7 @@
// but may be destroyed if store is successful.
void StubCompiler::GenerateStoreField(MacroAssembler* masm,
Handle<JSObject> object,
- int index,
+ LookupResult* lookup,
Handle<Map> transition,
Handle<Name> name,
Register receiver_reg,
@@ -726,16 +726,6 @@
Register scratch2,
Label* miss_label,
Label* miss_restore_name) {
- LookupResult lookup(masm->isolate());
- object->Lookup(*name, &lookup);
- if (lookup.IsFound() && (lookup.IsReadOnly() || !lookup.IsCacheable())) {
- // In sloppy mode, we could just return the value and be done. However, we
- // might be in strict mode, where we have to throw. Since we cannot tell,
- // go into slow case unconditionally.
- __ jmp(miss_label);
- return;
- }
-
// Check that the map of the object hasn't changed.
CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
: REQUIRE_EXACT_MAP;
@@ -750,8 +740,9 @@
// Check that we are allowed to write this.
if (!transition.is_null() && object->GetPrototype()->IsJSObject()) {
JSObject* holder;
- if (lookup.IsFound()) {
- holder = lookup.holder();
+ // holder == object indicates that no property was found.
+ if (lookup->holder() != *object) {
+ holder = lookup->holder();
} else {
// Find the top object.
holder = *object;
@@ -759,8 +750,19 @@
holder = JSObject::cast(holder->GetPrototype());
} while (holder->GetPrototype()->IsJSObject());
}
- CheckPrototypes(object, receiver_reg, Handle<JSObject>(holder), name_reg,
- scratch1, scratch2, name, miss_restore_name);
+ Register holder_reg = CheckPrototypes(
+ object, receiver_reg, Handle<JSObject>(holder), name_reg,
+ scratch1, scratch2, name, miss_restore_name);
+ // If no property was found, and the holder (the last object in the
+ // prototype chain) is in slow mode, we need to do a negative lookup on the
+ // holder.
+ if (lookup->holder() == *object &&
+ !holder->HasFastProperties() &&
+ !holder->IsJSGlobalProxy() &&
+ !holder->IsJSGlobalObject()) {
+ GenerateDictionaryNegativeLookup(
+ masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
+ }
}
// Stub never generated for non-global objects that require access
@@ -784,6 +786,7 @@
return;
}
+ int index;
if (!transition.is_null()) {
// Update the map of the object.
__ Move(scratch1, transition);
@@ -798,6 +801,10 @@
kDontSaveFPRegs,
OMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
+ index = transition->instance_descriptors()->GetFieldIndex(
+ transition->LastAdded());
+ } else {
+ index = lookup->GetFieldIndex().field_index();
}
// Adjust for the number of properties stored in the object. Even in the
@@ -2174,6 +2181,12 @@
// Check that the object is a symbol.
__ CmpObjectType(rdx, SYMBOL_TYPE, rax);
__ j(not_equal, &miss);
+ // Check that the maps starting from the prototype haven't changed.
+ GenerateDirectLoadGlobalFunctionPrototype(
+ masm(), Context::SYMBOL_FUNCTION_INDEX, rax, &miss);
+ CheckPrototypes(
+ Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
+ rax, holder, rbx, rdx, rdi, name, &miss);
break;
case NUMBER_CHECK: {