Version 3.28.21 (based on bleeding_edge revision r22338)
Make `let` usable as an identifier in ES6 sloppy mode (issue 2198).
Support ES6 Map and Set in heap profiler (issue 3368).
Performance and stability improvements on all platforms.
git-svn-id: https://v8.googlecode.com/svn/trunk@22341 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index 6d6e18c..5be394c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2014-07-11: Version 3.28.21
+
+ Make `let` usable as an identifier in ES6 sloppy mode (issue 2198).
+
+ Support ES6 Map and Set in heap profiler (issue 3368).
+
+ Performance and stability improvements on all platforms.
+
+
2014-07-10: Version 3.28.20
Remove deprecate counter/histogram methods.
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index b55acca..4b52aeb 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -176,5 +176,6 @@
'v8_linux_layout_dbg': set(['defaulttests']),
'v8_mac_rel': set(['defaulttests']),
'v8_win_rel': set(['defaulttests']),
+ 'v8_win64_rel': set(['defaulttests']),
},
}
diff --git a/include/v8.h b/include/v8.h
index 11bf598..82d5784 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -1087,6 +1087,12 @@
/**
* Compiles the specified script (context-independent).
+ * Cached data as part of the source object can be optionally produced to be
+ * consumed later to speed up compilation of identical source scripts.
+ *
+ * Note that when producing cached data, the source must point to NULL for
+ * cached data. When consuming cached data, the cached data must have been
+ * produced by the same version of V8.
*
* \param source Script source code.
* \return Compiled script object (context independent; for running it must be
diff --git a/src/api.cc b/src/api.cc
index d01d826..106c1fd 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -1699,43 +1699,19 @@
Isolate* v8_isolate,
Source* source,
CompileOptions options) {
- i::ScriptData* script_data_impl = NULL;
+ i::ScriptData* script_data = NULL;
i::CachedDataMode cached_data_mode = i::NO_CACHED_DATA;
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ON_BAILOUT(isolate, "v8::ScriptCompiler::CompileUnbound()",
return Local<UnboundScript>());
if (options & kProduceDataToCache) {
cached_data_mode = i::PRODUCE_CACHED_DATA;
- ASSERT(source->cached_data == NULL);
- if (source->cached_data) {
- // Asked to produce cached data even though there is some already -> not
- // good. Fail the compilation.
- EXCEPTION_PREAMBLE(isolate);
- i::Handle<i::Object> result = isolate->factory()->NewSyntaxError(
- "invalid_cached_data", isolate->factory()->NewJSArray(0));
- isolate->Throw(*result);
- isolate->ReportPendingMessages();
- has_pending_exception = true;
- EXCEPTION_BAILOUT_CHECK(isolate, Local<UnboundScript>());
- }
+ CHECK(source->cached_data == NULL);
} else if (source->cached_data) {
cached_data_mode = i::CONSUME_CACHED_DATA;
- // ScriptData takes care of aligning, in case the data is not aligned
- // correctly.
- script_data_impl = i::ScriptData::New(
- reinterpret_cast<const char*>(source->cached_data->data),
- source->cached_data->length);
- // If the cached data is not valid, fail the compilation.
- if (script_data_impl == NULL || !script_data_impl->SanityCheck()) {
- EXCEPTION_PREAMBLE(isolate);
- i::Handle<i::Object> result = isolate->factory()->NewSyntaxError(
- "invalid_cached_data", isolate->factory()->NewJSArray(0));
- isolate->Throw(*result);
- isolate->ReportPendingMessages();
- delete script_data_impl;
- has_pending_exception = true;
- EXCEPTION_BAILOUT_CHECK(isolate, Local<UnboundScript>());
- }
+ // ScriptData takes care of pointer-aligning the data.
+ script_data = new i::ScriptData(source->cached_data->data,
+ source->cached_data->length);
}
i::Handle<i::String> str = Utils::OpenHandle(*(source->source_string));
@@ -1763,36 +1739,28 @@
source->resource_is_shared_cross_origin == v8::True(v8_isolate);
}
EXCEPTION_PREAMBLE(isolate);
- i::Handle<i::SharedFunctionInfo> result =
- i::Compiler::CompileScript(str,
- name_obj,
- line_offset,
- column_offset,
- is_shared_cross_origin,
- isolate->global_context(),
- NULL,
- &script_data_impl,
- cached_data_mode,
- i::NOT_NATIVES_CODE);
+ i::Handle<i::SharedFunctionInfo> result = i::Compiler::CompileScript(
+ str, name_obj, line_offset, column_offset, is_shared_cross_origin,
+ isolate->global_context(), NULL, &script_data, cached_data_mode,
+ i::NOT_NATIVES_CODE);
has_pending_exception = result.is_null();
if (has_pending_exception && cached_data_mode == i::CONSUME_CACHED_DATA) {
// This case won't happen during normal operation; we have compiled
// successfully and produced cached data, and but the second compilation
// of the same source code fails.
- delete script_data_impl;
- script_data_impl = NULL;
+ delete script_data;
+ script_data = NULL;
}
EXCEPTION_BAILOUT_CHECK(isolate, Local<UnboundScript>());
raw_result = *result;
- if ((options & kProduceDataToCache) && script_data_impl != NULL) {
+ if ((options & kProduceDataToCache) && script_data != NULL) {
// script_data_impl now contains the data that was generated. source will
// take the ownership.
source->cached_data = new CachedData(
- reinterpret_cast<const uint8_t*>(script_data_impl->Data()),
- script_data_impl->Length(), CachedData::BufferOwned);
- script_data_impl->owns_store_ = false;
+ script_data->data(), script_data->length(), CachedData::BufferOwned);
+ script_data->ReleaseDataOwnership();
}
- delete script_data_impl;
+ delete script_data;
}
i::Handle<i::SharedFunctionInfo> result(raw_result, isolate);
return ToApiHandle<UnboundScript>(result);
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index 526bc55..5e0e69e 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -87,15 +87,6 @@
}
-void KeyedStoreFastElementStub::InitializeInterfaceDescriptor(
- CodeStubInterfaceDescriptor* descriptor) {
- Register registers[] = { r2, r1, r0 };
- descriptor->Initialize(
- ARRAY_SIZE(registers), registers,
- FUNCTION_ADDR(KeyedStoreIC_MissFromStubFailure));
-}
-
-
void TransitionElementsKindStub::InitializeInterfaceDescriptor(
CodeStubInterfaceDescriptor* descriptor) {
Register registers[] = { r0, r1 };
@@ -230,14 +221,6 @@
}
-void StoreGlobalStub::InitializeInterfaceDescriptor(
- CodeStubInterfaceDescriptor* descriptor) {
- Register registers[] = { r1, r2, r0 };
- descriptor->Initialize(ARRAY_SIZE(registers), registers,
- FUNCTION_ADDR(StoreIC_MissFromStubFailure));
-}
-
-
void ElementsTransitionAndStoreStub::InitializeInterfaceDescriptor(
CodeStubInterfaceDescriptor* descriptor) {
Register registers[] = { r0, r3, r1, r2 };
diff --git a/src/arm/debug-arm.cc b/src/arm/debug-arm.cc
index 8526dd0..310ddb5 100644
--- a/src/arm/debug-arm.cc
+++ b/src/arm/debug-arm.cc
@@ -184,15 +184,11 @@
void DebugCodegen::GenerateStoreICDebugBreak(MacroAssembler* masm) {
// Calling convention for IC store (from ic-arm.cc).
- // ----------- S t a t e -------------
- // -- r0 : value
- // -- r1 : receiver
- // -- r2 : name
- // -- lr : return address
- // -----------------------------------
- // Registers r0, r1, and r2 contain objects that need to be pushed on the
- // expression stack of the fake JS frame.
- Generate_DebugBreakCallHelper(masm, r0.bit() | r1.bit() | r2.bit(), 0);
+ Register receiver = StoreIC::ReceiverRegister();
+ Register name = StoreIC::NameRegister();
+ Register value = StoreIC::ValueRegister();
+ Generate_DebugBreakCallHelper(
+ masm, receiver.bit() | name.bit() | value.bit(), 0);
}
@@ -203,12 +199,12 @@
void DebugCodegen::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
- // ---------- S t a t e --------------
- // -- r0 : value
- // -- r1 : key
- // -- r2 : receiver
- // -- lr : return address
- Generate_DebugBreakCallHelper(masm, r0.bit() | r1.bit() | r2.bit(), 0);
+ // Calling convention for IC keyed store call (from ic-arm.cc).
+ Register receiver = KeyedStoreIC::ReceiverRegister();
+ Register name = KeyedStoreIC::NameRegister();
+ Register value = KeyedStoreIC::ValueRegister();
+ Generate_DebugBreakCallHelper(
+ masm, receiver.bit() | name.bit() | value.bit(), 0);
}
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index 4255d66..bb9fe95 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -1693,8 +1693,9 @@
if (key->value()->IsInternalizedString()) {
if (property->emit_store()) {
VisitForAccumulatorValue(value);
- __ mov(r2, Operand(key->value()));
- __ ldr(r1, MemOperand(sp));
+ ASSERT(StoreIC::ValueRegister().is(r0));
+ __ mov(StoreIC::NameRegister(), Operand(key->value()));
+ __ ldr(StoreIC::ReceiverRegister(), MemOperand(sp));
CallStoreIC(key->LiteralFeedbackId());
PrepareForBailoutForId(key->id(), NO_REGISTERS);
} else {
@@ -2420,9 +2421,10 @@
case NAMED_PROPERTY: {
__ push(r0); // Preserve value.
VisitForAccumulatorValue(prop->obj());
- __ mov(r1, r0);
- __ pop(r0); // Restore value.
- __ mov(r2, Operand(prop->key()->AsLiteral()->value()));
+ __ Move(StoreIC::ReceiverRegister(), r0);
+ __ pop(StoreIC::ValueRegister()); // Restore value.
+ __ mov(StoreIC::NameRegister(),
+ Operand(prop->key()->AsLiteral()->value()));
CallStoreIC();
break;
}
@@ -2430,8 +2432,8 @@
__ push(r0); // Preserve value.
VisitForStackValue(prop->obj());
VisitForAccumulatorValue(prop->key());
- __ mov(r1, r0);
- __ Pop(r0, r2); // r0 = restored value.
+ __ Move(KeyedStoreIC::NameRegister(), r0);
+ __ Pop(KeyedStoreIC::ValueRegister(), KeyedStoreIC::ReceiverRegister());
Handle<Code> ic = strict_mode() == SLOPPY
? isolate()->builtins()->KeyedStoreIC_Initialize()
: isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
@@ -2469,8 +2471,8 @@
void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op) {
if (var->IsUnallocated()) {
// Global var, const, or let.
- __ mov(r2, Operand(var->name()));
- __ ldr(r1, GlobalObjectOperand());
+ __ mov(StoreIC::NameRegister(), Operand(var->name()));
+ __ ldr(StoreIC::ReceiverRegister(), GlobalObjectOperand());
CallStoreIC();
} else if (op == Token::INIT_CONST_LEGACY) {
@@ -2540,9 +2542,8 @@
// Record source code position before IC call.
SetSourcePosition(expr->position());
- __ mov(r2, Operand(prop->key()->AsLiteral()->value()));
- __ pop(r1);
-
+ __ mov(StoreIC::NameRegister(), Operand(prop->key()->AsLiteral()->value()));
+ __ pop(StoreIC::ReceiverRegister());
CallStoreIC(expr->AssignmentFeedbackId());
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
@@ -2555,7 +2556,8 @@
// Record source code position before IC call.
SetSourcePosition(expr->position());
- __ Pop(r2, r1); // r1 = key.
+ __ Pop(KeyedStoreIC::ReceiverRegister(), KeyedStoreIC::NameRegister());
+ ASSERT(KeyedStoreIC::ValueRegister().is(r0));
Handle<Code> ic = strict_mode() == SLOPPY
? isolate()->builtins()->KeyedStoreIC_Initialize()
@@ -4354,8 +4356,9 @@
}
break;
case NAMED_PROPERTY: {
- __ mov(r2, Operand(prop->key()->AsLiteral()->value()));
- __ pop(r1);
+ __ mov(StoreIC::NameRegister(),
+ Operand(prop->key()->AsLiteral()->value()));
+ __ pop(StoreIC::ReceiverRegister());
CallStoreIC(expr->CountStoreFeedbackId());
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
if (expr->is_postfix()) {
@@ -4368,7 +4371,7 @@
break;
}
case KEYED_PROPERTY: {
- __ Pop(r2, r1); // r1 = key. r2 = receiver.
+ __ Pop(KeyedStoreIC::ReceiverRegister(), KeyedStoreIC::NameRegister());
Handle<Code> ic = strict_mode() == SLOPPY
? isolate()->builtins()->KeyedStoreIC_Initialize()
: isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc
index fc32a48..c49b161 100644
--- a/src/arm/ic-arm.cc
+++ b/src/arm/ic-arm.cc
@@ -497,27 +497,28 @@
void KeyedStoreIC::GenerateSloppyArguments(MacroAssembler* masm) {
- // ---------- S t a t e --------------
- // -- r0 : value
- // -- r1 : key
- // -- r2 : receiver
- // -- lr : return address
- // -----------------------------------
+ Register receiver = ReceiverRegister();
+ Register key = NameRegister();
+ Register value = ValueRegister();
+ ASSERT(receiver.is(r2));
+ ASSERT(key.is(r1));
+ ASSERT(value.is(r0));
+
Label slow, notin;
- MemOperand mapped_location =
- GenerateMappedArgumentsLookup(masm, r2, r1, r3, r4, r5, ¬in, &slow);
- __ str(r0, mapped_location);
+ MemOperand mapped_location = GenerateMappedArgumentsLookup(
+ masm, receiver, key, r3, r4, r5, ¬in, &slow);
+ __ str(value, mapped_location);
__ add(r6, r3, r5);
- __ mov(r9, r0);
+ __ mov(r9, value);
__ RecordWrite(r3, r6, r9, kLRHasNotBeenSaved, kDontSaveFPRegs);
__ Ret();
__ bind(¬in);
// The unmapped lookup expects that the parameter map is in r3.
MemOperand unmapped_location =
- GenerateUnmappedArgumentsLookup(masm, r1, r3, r4, &slow);
- __ str(r0, unmapped_location);
+ GenerateUnmappedArgumentsLookup(masm, key, r3, r4, &slow);
+ __ str(value, unmapped_location);
__ add(r6, r3, r4);
- __ mov(r9, r0);
+ __ mov(r9, value);
__ RecordWrite(r3, r6, r9, kLRHasNotBeenSaved, kDontSaveFPRegs);
__ Ret();
__ bind(&slow);
@@ -546,6 +547,16 @@
const Register LoadIC::NameRegister() { return r2; }
+const Register StoreIC::ReceiverRegister() { return r1; }
+const Register StoreIC::NameRegister() { return r2; }
+const Register StoreIC::ValueRegister() { return r0; }
+
+
+const Register KeyedStoreIC::ReceiverRegister() { return r2; }
+const Register KeyedStoreIC::NameRegister() { return r1; }
+const Register KeyedStoreIC::ValueRegister() { return r0; }
+
+
void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
// The return address is in lr.
@@ -792,15 +803,8 @@
void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
- // ---------- S t a t e --------------
- // -- r0 : value
- // -- r1 : key
- // -- r2 : receiver
- // -- lr : return address
- // -----------------------------------
-
// Push receiver, key and value for runtime call.
- __ Push(r2, r1, r0);
+ __ Push(ReceiverRegister(), NameRegister(), ValueRegister());
ExternalReference ref =
ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
@@ -809,15 +813,8 @@
void StoreIC::GenerateSlow(MacroAssembler* masm) {
- // ---------- S t a t e --------------
- // -- r0 : value
- // -- r2 : key
- // -- r1 : receiver
- // -- lr : return address
- // -----------------------------------
-
// Push receiver, key and value for runtime call.
- __ Push(r1, r2, r0);
+ __ Push(ReceiverRegister(), NameRegister(), ValueRegister());
// The slow case calls into the runtime to complete the store without causing
// an IC miss that would otherwise cause a transition to the generic stub.
@@ -828,15 +825,8 @@
void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
- // ---------- S t a t e --------------
- // -- r0 : value
- // -- r1 : key
- // -- r2 : receiver
- // -- lr : return address
- // -----------------------------------
-
// Push receiver, key and value for runtime call.
- __ Push(r2, r1, r0);
+ __ Push(ReceiverRegister(), NameRegister(), ValueRegister());
// The slow case calls into the runtime to complete the store without causing
// an IC miss that would otherwise cause a transition to the generic stub.
@@ -848,15 +838,8 @@
void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
StrictMode strict_mode) {
- // ---------- S t a t e --------------
- // -- r0 : value
- // -- r1 : key
- // -- r2 : receiver
- // -- lr : return address
- // -----------------------------------
-
// Push receiver, key and value for runtime call.
- __ Push(r2, r1, r0);
+ __ Push(ReceiverRegister(), NameRegister(), ValueRegister());
__ mov(r0, Operand(Smi::FromInt(strict_mode))); // Strict mode.
__ Push(r0);
@@ -1042,9 +1025,12 @@
Label array, extra, check_if_double_array;
// Register usage.
- Register value = r0;
- Register key = r1;
- Register receiver = r2;
+ Register value = ValueRegister();
+ Register key = NameRegister();
+ Register receiver = ReceiverRegister();
+ ASSERT(receiver.is(r2));
+ ASSERT(key.is(r1));
+ ASSERT(value.is(r0));
Register receiver_map = r3;
Register elements_map = r6;
Register elements = r9; // Elements array of the receiver.
@@ -1130,18 +1116,17 @@
void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- r0 : value
- // -- r1 : receiver
- // -- r2 : name
- // -- lr : return address
- // -----------------------------------
+ Register receiver = ReceiverRegister();
+ Register name = NameRegister();
+ ASSERT(receiver.is(r1));
+ ASSERT(name.is(r2));
+ ASSERT(ValueRegister().is(r0));
// Get the receiver from the stack and probe the stub cache.
Code::Flags flags = Code::ComputeHandlerFlags(Code::STORE_IC);
masm->isolate()->stub_cache()->GenerateProbe(
- masm, flags, r1, r2, r3, r4, r5, r6);
+ masm, flags, receiver, name, r3, r4, r5, r6);
// Cache miss: Jump to runtime.
GenerateMiss(masm);
@@ -1149,14 +1134,7 @@
void StoreIC::GenerateMiss(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- r0 : value
- // -- r1 : receiver
- // -- r2 : name
- // -- lr : return address
- // -----------------------------------
-
- __ Push(r1, r2, r0);
+ __ Push(ReceiverRegister(), NameRegister(), ValueRegister());
// Perform tail call to the entry.
ExternalReference ref =
@@ -1166,17 +1144,17 @@
void StoreIC::GenerateNormal(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- r0 : value
- // -- r1 : receiver
- // -- r2 : name
- // -- lr : return address
- // -----------------------------------
Label miss;
+ Register receiver = ReceiverRegister();
+ Register name = NameRegister();
+ Register value = ValueRegister();
+ ASSERT(receiver.is(r1));
+ ASSERT(name.is(r2));
+ ASSERT(value.is(r0));
- GenerateNameDictionaryReceiverCheck(masm, r1, r3, r4, r5, &miss);
+ GenerateNameDictionaryReceiverCheck(masm, receiver, r3, r4, r5, &miss);
- GenerateDictionaryStore(masm, &miss, r3, r2, r0, r4, r5);
+ GenerateDictionaryStore(masm, &miss, r3, name, value, r4, r5);
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->store_normal_hit(),
1, r4, r5);
@@ -1190,14 +1168,7 @@
void StoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
StrictMode strict_mode) {
- // ----------- S t a t e -------------
- // -- r0 : value
- // -- r1 : receiver
- // -- r2 : name
- // -- lr : return address
- // -----------------------------------
-
- __ Push(r1, r2, r0);
+ __ Push(ReceiverRegister(), NameRegister(), ValueRegister());
__ mov(r0, Operand(Smi::FromInt(strict_mode)));
__ Push(r0);
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index 21fd783..90ff023 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -2255,9 +2255,9 @@
LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
LOperand* context = UseFixed(instr->context(), cp);
- LOperand* obj = UseFixed(instr->object(), r2);
- LOperand* key = UseFixed(instr->key(), r1);
- LOperand* val = UseFixed(instr->value(), r0);
+ LOperand* obj = UseFixed(instr->object(), KeyedStoreIC::ReceiverRegister());
+ LOperand* key = UseFixed(instr->key(), KeyedStoreIC::NameRegister());
+ LOperand* val = UseFixed(instr->value(), KeyedStoreIC::ValueRegister());
ASSERT(instr->object()->representation().IsTagged());
ASSERT(instr->key()->representation().IsTagged());
@@ -2331,8 +2331,8 @@
LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
LOperand* context = UseFixed(instr->context(), cp);
- LOperand* obj = UseFixed(instr->object(), r1);
- LOperand* val = UseFixed(instr->value(), r0);
+ LOperand* obj = UseFixed(instr->object(), StoreIC::ReceiverRegister());
+ LOperand* val = UseFixed(instr->value(), StoreIC::ValueRegister());
LInstruction* result = new(zone()) LStoreNamedGeneric(context, obj, val);
return MarkAsCall(result, instr);
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index 34a23e1..13dd7b7 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -4191,11 +4191,10 @@
void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
ASSERT(ToRegister(instr->context()).is(cp));
- ASSERT(ToRegister(instr->object()).is(r1));
- ASSERT(ToRegister(instr->value()).is(r0));
+ ASSERT(ToRegister(instr->object()).is(StoreIC::ReceiverRegister()));
+ ASSERT(ToRegister(instr->value()).is(StoreIC::ValueRegister()));
- // Name is always in r2.
- __ mov(r2, Operand(instr->name()));
+ __ mov(StoreIC::NameRegister(), Operand(instr->name()));
Handle<Code> ic = StoreIC::initialize_stub(isolate(), instr->strict_mode());
CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS);
}
@@ -4413,9 +4412,9 @@
void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
ASSERT(ToRegister(instr->context()).is(cp));
- ASSERT(ToRegister(instr->object()).is(r2));
- ASSERT(ToRegister(instr->key()).is(r1));
- ASSERT(ToRegister(instr->value()).is(r0));
+ ASSERT(ToRegister(instr->object()).is(KeyedStoreIC::ReceiverRegister()));
+ ASSERT(ToRegister(instr->key()).is(KeyedStoreIC::NameRegister()));
+ ASSERT(ToRegister(instr->value()).is(KeyedStoreIC::ValueRegister()));
Handle<Code> ic = instr->strict_mode() == STRICT
? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index 1f7c152..98002dc 100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -1280,20 +1280,24 @@
Register StoreStubCompiler::value() {
- return r0;
+ return StoreIC::ValueRegister();
}
Register* StoreStubCompiler::registers() {
// receiver, name, scratch1, scratch2, scratch3.
- static Register registers[] = { r1, r2, r3, r4, r5 };
+ Register receiver = StoreIC::ReceiverRegister();
+ Register name = StoreIC::NameRegister();
+ static Register registers[] = { receiver, name, r3, r4, r5 };
return registers;
}
Register* KeyedStoreStubCompiler::registers() {
// receiver, name, scratch1, scratch2, scratch3.
- static Register registers[] = { r2, r1, r3, r4, r5 };
+ Register receiver = KeyedStoreIC::ReceiverRegister();
+ Register name = KeyedStoreIC::NameRegister();
+ static Register registers[] = { receiver, name, r3, r4, r5 };
return registers;
}
diff --git a/src/arm64/code-stubs-arm64.cc b/src/arm64/code-stubs-arm64.cc
index e24c7bd..5b76f1a 100644
--- a/src/arm64/code-stubs-arm64.cc
+++ b/src/arm64/code-stubs-arm64.cc
@@ -102,18 +102,6 @@
}
-void KeyedStoreFastElementStub::InitializeInterfaceDescriptor(
- CodeStubInterfaceDescriptor* descriptor) {
- // x2: receiver
- // x1: key
- // x0: value
- Register registers[] = { x2, x1, x0 };
- descriptor->Initialize(
- ARRAY_SIZE(registers), registers,
- FUNCTION_ADDR(KeyedStoreIC_MissFromStubFailure));
-}
-
-
void TransitionElementsKindStub::InitializeInterfaceDescriptor(
CodeStubInterfaceDescriptor* descriptor) {
// x0: value (js_array)
@@ -250,17 +238,6 @@
}
-void StoreGlobalStub::InitializeInterfaceDescriptor(
- CodeStubInterfaceDescriptor* descriptor) {
- // x1: receiver
- // x2: key (unused)
- // x0: value
- Register registers[] = { x1, x2, x0 };
- descriptor->Initialize(ARRAY_SIZE(registers), registers,
- FUNCTION_ADDR(StoreIC_MissFromStubFailure));
-}
-
-
void ElementsTransitionAndStoreStub::InitializeInterfaceDescriptor(
CodeStubInterfaceDescriptor* descriptor) {
// x0: value
diff --git a/src/arm64/debug-arm64.cc b/src/arm64/debug-arm64.cc
index 1578452..5d88903 100644
--- a/src/arm64/debug-arm64.cc
+++ b/src/arm64/debug-arm64.cc
@@ -243,16 +243,12 @@
void DebugCodegen::GenerateStoreICDebugBreak(MacroAssembler* masm) {
- // Calling convention for IC store (from ic-arm.cc).
- // ----------- S t a t e -------------
- // -- x0 : value
- // -- x1 : receiver
- // -- x2 : name
- // -- lr : return address
- // -----------------------------------
- // Registers x0, x1, and x2 contain objects that need to be pushed on the
- // expression stack of the fake JS frame.
- Generate_DebugBreakCallHelper(masm, x0.Bit() | x1.Bit() | x2.Bit(), 0, x10);
+ // Calling convention for IC store (from ic-arm64.cc).
+ Register receiver = StoreIC::ReceiverRegister();
+ Register name = StoreIC::NameRegister();
+ Register value = StoreIC::ValueRegister();
+ Generate_DebugBreakCallHelper(
+ masm, receiver.Bit() | name.Bit() | value.Bit(), 0, x10);
}
@@ -263,12 +259,12 @@
void DebugCodegen::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
- // ---------- S t a t e --------------
- // -- x0 : value
- // -- x1 : key
- // -- x2 : receiver
- // -- lr : return address
- Generate_DebugBreakCallHelper(masm, x0.Bit() | x1.Bit() | x2.Bit(), 0, x10);
+ // Calling convention for IC keyed store call (from ic-arm64.cc).
+ Register receiver = KeyedStoreIC::ReceiverRegister();
+ Register name = KeyedStoreIC::NameRegister();
+ Register value = KeyedStoreIC::ValueRegister();
+ Generate_DebugBreakCallHelper(
+ masm, receiver.Bit() | name.Bit() | value.Bit(), 0, x10);
}
diff --git a/src/arm64/full-codegen-arm64.cc b/src/arm64/full-codegen-arm64.cc
index f027dc6..f7103f2 100644
--- a/src/arm64/full-codegen-arm64.cc
+++ b/src/arm64/full-codegen-arm64.cc
@@ -1682,8 +1682,9 @@
if (key->value()->IsInternalizedString()) {
if (property->emit_store()) {
VisitForAccumulatorValue(value);
- __ Mov(x2, Operand(key->value()));
- __ Peek(x1, 0);
+ ASSERT(StoreIC::ValueRegister().is(x0));
+ __ Mov(StoreIC::NameRegister(), Operand(key->value()));
+ __ Peek(StoreIC::ReceiverRegister(), 0);
CallStoreIC(key->LiteralFeedbackId());
PrepareForBailoutForId(key->id(), NO_REGISTERS);
} else {
@@ -2104,9 +2105,10 @@
VisitForAccumulatorValue(prop->obj());
// TODO(all): We could introduce a VisitForRegValue(reg, expr) to avoid
// this copy.
- __ Mov(x1, x0);
- __ Pop(x0); // Restore value.
- __ Mov(x2, Operand(prop->key()->AsLiteral()->value()));
+ __ Mov(StoreIC::ReceiverRegister(), x0);
+ __ Pop(StoreIC::ValueRegister()); // Restore value.
+ __ Mov(StoreIC::NameRegister(),
+ Operand(prop->key()->AsLiteral()->value()));
CallStoreIC();
break;
}
@@ -2114,8 +2116,8 @@
__ Push(x0); // Preserve value.
VisitForStackValue(prop->obj());
VisitForAccumulatorValue(prop->key());
- __ Mov(x1, x0);
- __ Pop(x2, x0);
+ __ Mov(KeyedStoreIC::NameRegister(), x0);
+ __ Pop(KeyedStoreIC::ReceiverRegister(), KeyedStoreIC::ValueRegister());
Handle<Code> ic = strict_mode() == SLOPPY
? isolate()->builtins()->KeyedStoreIC_Initialize()
: isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
@@ -2158,8 +2160,8 @@
ASM_LOCATION("FullCodeGenerator::EmitVariableAssignment");
if (var->IsUnallocated()) {
// Global var, const, or let.
- __ Mov(x2, Operand(var->name()));
- __ Ldr(x1, GlobalObjectMemOperand());
+ __ Mov(StoreIC::NameRegister(), Operand(var->name()));
+ __ Ldr(StoreIC::ReceiverRegister(), GlobalObjectMemOperand());
CallStoreIC();
} else if (op == Token::INIT_CONST_LEGACY) {
@@ -2226,9 +2228,8 @@
// Record source code position before IC call.
SetSourcePosition(expr->position());
- __ Mov(x2, Operand(prop->key()->AsLiteral()->value()));
- __ Pop(x1);
-
+ __ Mov(StoreIC::NameRegister(), Operand(prop->key()->AsLiteral()->value()));
+ __ Pop(StoreIC::ReceiverRegister());
CallStoreIC(expr->AssignmentFeedbackId());
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
@@ -2243,7 +2244,8 @@
// Record source code position before IC call.
SetSourcePosition(expr->position());
// TODO(all): Could we pass this in registers rather than on the stack?
- __ Pop(x1, x2); // Key and object holding the property.
+ __ Pop(KeyedStoreIC::NameRegister(), KeyedStoreIC::ReceiverRegister());
+ ASSERT(KeyedStoreIC::ValueRegister().is(x0));
Handle<Code> ic = strict_mode() == SLOPPY
? isolate()->builtins()->KeyedStoreIC_Initialize()
@@ -4043,8 +4045,9 @@
}
break;
case NAMED_PROPERTY: {
- __ Mov(x2, Operand(prop->key()->AsLiteral()->value()));
- __ Pop(x1);
+ __ Mov(StoreIC::NameRegister(),
+ Operand(prop->key()->AsLiteral()->value()));
+ __ Pop(StoreIC::ReceiverRegister());
CallStoreIC(expr->CountStoreFeedbackId());
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
if (expr->is_postfix()) {
@@ -4057,8 +4060,8 @@
break;
}
case KEYED_PROPERTY: {
- __ Pop(x1); // Key.
- __ Pop(x2); // Receiver.
+ __ Pop(KeyedStoreIC::NameRegister());
+ __ Pop(KeyedStoreIC::ReceiverRegister());
Handle<Code> ic = strict_mode() == SLOPPY
? isolate()->builtins()->KeyedStoreIC_Initialize()
: isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
diff --git a/src/arm64/ic-arm64.cc b/src/arm64/ic-arm64.cc
index 6e6e8ce..5a2dde5 100644
--- a/src/arm64/ic-arm64.cc
+++ b/src/arm64/ic-arm64.cc
@@ -502,17 +502,14 @@
void KeyedStoreIC::GenerateSloppyArguments(MacroAssembler* masm) {
ASM_LOCATION("KeyedStoreIC::GenerateSloppyArguments");
- // ---------- S t a t e --------------
- // -- lr : return address
- // -- x0 : value
- // -- x1 : key
- // -- x2 : receiver
- // -----------------------------------
Label slow, notin;
+ Register value = ValueRegister();
+ Register key = NameRegister();
+ Register receiver = ReceiverRegister();
+ ASSERT(receiver.is(x2));
+ ASSERT(key.is(x1));
+ ASSERT(value.is(x0));
- Register value = x0;
- Register key = x1;
- Register receiver = x2;
Register map = x3;
// These registers are used by GenerateMappedArgumentsLookup to build a
@@ -572,6 +569,16 @@
const Register LoadIC::NameRegister() { return x2; }
+const Register StoreIC::ReceiverRegister() { return x1; }
+const Register StoreIC::NameRegister() { return x2; }
+const Register StoreIC::ValueRegister() { return x0; }
+
+
+const Register KeyedStoreIC::ReceiverRegister() { return x2; }
+const Register KeyedStoreIC::NameRegister() { return x1; }
+const Register KeyedStoreIC::ValueRegister() { return x0; }
+
+
void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
// The return address is in lr.
__ Push(ReceiverRegister(), NameRegister());
@@ -847,15 +854,9 @@
void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
ASM_LOCATION("KeyedStoreIC::GenerateMiss");
- // ---------- S t a t e --------------
- // -- x0 : value
- // -- x1 : key
- // -- x2 : receiver
- // -- lr : return address
- // -----------------------------------
// Push receiver, key and value for runtime call.
- __ Push(x2, x1, x0);
+ __ Push(ReceiverRegister(), NameRegister(), ValueRegister());
ExternalReference ref =
ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
@@ -865,15 +866,9 @@
void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
ASM_LOCATION("KeyedStoreIC::GenerateSlow");
- // ---------- S t a t e --------------
- // -- lr : return address
- // -- x0 : value
- // -- x1 : key
- // -- x2 : receiver
- // -----------------------------------
// Push receiver, key and value for runtime call.
- __ Push(x2, x1, x0);
+ __ Push(ReceiverRegister(), NameRegister(), ValueRegister());
// The slow case calls into the runtime to complete the store without causing
// an IC miss that would otherwise cause a transition to the generic stub.
@@ -886,15 +881,9 @@
void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
StrictMode strict_mode) {
ASM_LOCATION("KeyedStoreIC::GenerateRuntimeSetProperty");
- // ---------- S t a t e --------------
- // -- x0 : value
- // -- x1 : key
- // -- x2 : receiver
- // -- lr : return address
- // -----------------------------------
// Push receiver, key and value for runtime call.
- __ Push(x2, x1, x0);
+ __ Push(ReceiverRegister(), NameRegister(), ValueRegister());
// Push strict_mode for runtime call.
__ Mov(x10, Smi::FromInt(strict_mode));
@@ -1067,12 +1056,6 @@
void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
StrictMode strict_mode) {
ASM_LOCATION("KeyedStoreIC::GenerateGeneric");
- // ---------- S t a t e --------------
- // -- x0 : value
- // -- x1 : key
- // -- x2 : receiver
- // -- lr : return address
- // -----------------------------------
Label slow;
Label array;
Label fast_object;
@@ -1081,9 +1064,13 @@
Label fast_double_grow;
Label fast_double;
- Register value = x0;
- Register key = x1;
- Register receiver = x2;
+ Register value = ValueRegister();
+ Register key = NameRegister();
+ Register receiver = ReceiverRegister();
+ ASSERT(receiver.is(x2));
+ ASSERT(key.is(x1));
+ ASSERT(value.is(x0));
+
Register receiver_map = x3;
Register elements = x4;
Register elements_map = x5;
@@ -1168,17 +1155,14 @@
void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- x0 : value
- // -- x1 : receiver
- // -- x2 : name
- // -- lr : return address
- // -----------------------------------
+ Register receiver = ReceiverRegister();
+ Register name = NameRegister();
+ ASSERT(!AreAliased(receiver, name, ValueRegister(), x3, x4, x5, x6));
// Probe the stub cache.
Code::Flags flags = Code::ComputeHandlerFlags(Code::STORE_IC);
masm->isolate()->stub_cache()->GenerateProbe(
- masm, flags, x1, x2, x3, x4, x5, x6);
+ masm, flags, receiver, name, x3, x4, x5, x6);
// Cache miss: Jump to runtime.
GenerateMiss(masm);
@@ -1186,14 +1170,7 @@
void StoreIC::GenerateMiss(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- x0 : value
- // -- x1 : receiver
- // -- x2 : name
- // -- lr : return address
- // -----------------------------------
-
- __ Push(x1, x2, x0);
+ __ Push(ReceiverRegister(), NameRegister(), ValueRegister());
// Tail call to the entry.
ExternalReference ref =
@@ -1203,17 +1180,12 @@
void StoreIC::GenerateNormal(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- x0 : value
- // -- x1 : receiver
- // -- x2 : name
- // -- lr : return address
- // -----------------------------------
Label miss;
- Register value = x0;
- Register receiver = x1;
- Register name = x2;
+ Register value = ValueRegister();
+ Register receiver = ReceiverRegister();
+ Register name = NameRegister();
Register dictionary = x3;
+ ASSERT(!AreAliased(value, receiver, name, x3, x4, x5));
GenerateNameDictionaryReceiverCheck(
masm, receiver, dictionary, x4, x5, &miss);
@@ -1233,14 +1205,8 @@
void StoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
StrictMode strict_mode) {
ASM_LOCATION("StoreIC::GenerateRuntimeSetProperty");
- // ----------- S t a t e -------------
- // -- x0 : value
- // -- x1 : receiver
- // -- x2 : name
- // -- lr : return address
- // -----------------------------------
- __ Push(x1, x2, x0);
+ __ Push(ReceiverRegister(), NameRegister(), ValueRegister());
__ Mov(x10, Smi::FromInt(strict_mode));
__ Push(x10);
@@ -1259,7 +1225,7 @@
// -----------------------------------
// Push receiver, name and value for runtime call.
- __ Push(x1, x2, x0);
+ __ Push(ReceiverRegister(), NameRegister(), ValueRegister());
// The slow case calls into the runtime to complete the store without causing
// an IC miss that would otherwise cause a transition to the generic stub.
diff --git a/src/arm64/lithium-arm64.cc b/src/arm64/lithium-arm64.cc
index acae6b0..3431116 100644
--- a/src/arm64/lithium-arm64.cc
+++ b/src/arm64/lithium-arm64.cc
@@ -2358,9 +2358,10 @@
LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
LOperand* context = UseFixed(instr->context(), cp);
- LOperand* object = UseFixed(instr->object(), x2);
- LOperand* key = UseFixed(instr->key(), x1);
- LOperand* value = UseFixed(instr->value(), x0);
+ LOperand* object = UseFixed(instr->object(),
+ KeyedStoreIC::ReceiverRegister());
+ LOperand* key = UseFixed(instr->key(), KeyedStoreIC::NameRegister());
+ LOperand* value = UseFixed(instr->value(), KeyedStoreIC::ValueRegister());
ASSERT(instr->object()->representation().IsTagged());
ASSERT(instr->key()->representation().IsTagged());
@@ -2402,8 +2403,9 @@
LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
LOperand* context = UseFixed(instr->context(), cp);
- LOperand* object = UseFixed(instr->object(), x1);
- LOperand* value = UseFixed(instr->value(), x0);
+ LOperand* object = UseFixed(instr->object(), StoreIC::ReceiverRegister());
+ LOperand* value = UseFixed(instr->value(), StoreIC::ValueRegister());
+
LInstruction* result = new(zone()) LStoreNamedGeneric(context, object, value);
return MarkAsCall(result, instr);
}
diff --git a/src/arm64/lithium-codegen-arm64.cc b/src/arm64/lithium-codegen-arm64.cc
index dd24b9c..46d88e5 100644
--- a/src/arm64/lithium-codegen-arm64.cc
+++ b/src/arm64/lithium-codegen-arm64.cc
@@ -5322,9 +5322,9 @@
void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
ASSERT(ToRegister(instr->context()).is(cp));
- ASSERT(ToRegister(instr->object()).Is(x2));
- ASSERT(ToRegister(instr->key()).Is(x1));
- ASSERT(ToRegister(instr->value()).Is(x0));
+ ASSERT(ToRegister(instr->object()).is(KeyedStoreIC::ReceiverRegister()));
+ ASSERT(ToRegister(instr->key()).is(KeyedStoreIC::NameRegister()));
+ ASSERT(ToRegister(instr->value()).is(KeyedStoreIC::ValueRegister()));
Handle<Code> ic = instr->strict_mode() == STRICT
? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
@@ -5429,11 +5429,10 @@
void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
ASSERT(ToRegister(instr->context()).is(cp));
- ASSERT(ToRegister(instr->value()).is(x0));
- ASSERT(ToRegister(instr->object()).is(x1));
+ ASSERT(ToRegister(instr->object()).is(StoreIC::ReceiverRegister()));
+ ASSERT(ToRegister(instr->value()).is(StoreIC::ValueRegister()));
- // Name must be in x2.
- __ Mov(x2, Operand(instr->name()));
+ __ Mov(StoreIC::NameRegister(), Operand(instr->name()));
Handle<Code> ic = StoreIC::initialize_stub(isolate(), instr->strict_mode());
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
diff --git a/src/arm64/stub-cache-arm64.cc b/src/arm64/stub-cache-arm64.cc
index 85774d9..d52493e 100644
--- a/src/arm64/stub-cache-arm64.cc
+++ b/src/arm64/stub-cache-arm64.cc
@@ -1262,20 +1262,24 @@
Register StoreStubCompiler::value() {
- return x0;
+ return StoreIC::ValueRegister();
}
Register* StoreStubCompiler::registers() {
// receiver, value, scratch1, scratch2, scratch3.
- static Register registers[] = { x1, x2, x3, x4, x5 };
+ Register receiver = StoreIC::ReceiverRegister();
+ Register name = StoreIC::NameRegister();
+ static Register registers[] = { receiver, name, x3, x4, x5 };
return registers;
}
Register* KeyedStoreStubCompiler::registers() {
// receiver, name, scratch1, scratch2, scratch3.
- static Register registers[] = { x2, x1, x3, x4, x5 };
+ Register receiver = KeyedStoreIC::ReceiverRegister();
+ Register name = KeyedStoreIC::NameRegister();
+ static Register registers[] = { receiver, name, x3, x4, x5 };
return registers;
}
diff --git a/src/assembler.cc b/src/assembler.cc
index 2e5e828..a98ff1e 100644
--- a/src/assembler.cc
+++ b/src/assembler.cc
@@ -1572,11 +1572,6 @@
ASSERT(pos != RelocInfo::kNoPosition);
ASSERT(pos >= 0);
state_.current_position = pos;
-#ifdef ENABLE_GDB_JIT_INTERFACE
- if (gdbjit_lineinfo_ != NULL) {
- gdbjit_lineinfo_->SetPosition(assembler_->pc_offset(), pos, false);
- }
-#endif
LOG_CODE_EVENT(assembler_->isolate(),
CodeLinePosInfoAddPositionEvent(jit_handler_data_,
assembler_->pc_offset(),
@@ -1588,11 +1583,6 @@
ASSERT(pos != RelocInfo::kNoPosition);
ASSERT(pos >= 0);
state_.current_statement_position = pos;
-#ifdef ENABLE_GDB_JIT_INTERFACE
- if (gdbjit_lineinfo_ != NULL) {
- gdbjit_lineinfo_->SetPosition(assembler_->pc_offset(), pos, true);
- }
-#endif
LOG_CODE_EVENT(assembler_->isolate(),
CodeLinePosInfoAddStatementPositionEvent(
jit_handler_data_,
diff --git a/src/assembler.h b/src/assembler.h
index 0ef7f5e..c92ef1e 100644
--- a/src/assembler.h
+++ b/src/assembler.h
@@ -1022,29 +1022,9 @@
public:
explicit PositionsRecorder(Assembler* assembler)
: assembler_(assembler) {
-#ifdef ENABLE_GDB_JIT_INTERFACE
- gdbjit_lineinfo_ = NULL;
-#endif
jit_handler_data_ = NULL;
}
-#ifdef ENABLE_GDB_JIT_INTERFACE
- ~PositionsRecorder() {
- delete gdbjit_lineinfo_;
- }
-
- void StartGDBJITLineInfoRecording() {
- if (FLAG_gdbjit) {
- gdbjit_lineinfo_ = new GDBJITLineInfo();
- }
- }
-
- GDBJITLineInfo* DetachGDBJITLineInfo() {
- GDBJITLineInfo* lineinfo = gdbjit_lineinfo_;
- gdbjit_lineinfo_ = NULL; // To prevent deallocation in destructor.
- return lineinfo;
- }
-#endif
void AttachJITHandlerData(void* user_data) {
jit_handler_data_ = user_data;
}
@@ -1072,9 +1052,6 @@
private:
Assembler* assembler_;
PositionState state_;
-#ifdef ENABLE_GDB_JIT_INTERFACE
- GDBJITLineInfo* gdbjit_lineinfo_;
-#endif
// Currently jit_handler_data_ is used to store JITHandler-specific data
// over the lifetime of a PositionsRecorder
diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc
index c6705c3..bdd168b 100644
--- a/src/code-stubs-hydrogen.cc
+++ b/src/code-stubs-hydrogen.cc
@@ -603,7 +603,9 @@
template <>
HValue* CodeStubGraphBuilder<KeyedStoreFastElementStub>::BuildCodeStub() {
BuildUncheckedMonomorphicElementAccess(
- GetParameter(0), GetParameter(1), GetParameter(2),
+ GetParameter(StoreIC::kReceiverIndex),
+ GetParameter(StoreIC::kNameIndex),
+ GetParameter(StoreIC::kValueIndex),
casted_stub()->is_js_array(), casted_stub()->elements_kind(),
STORE, NEVER_RETURN_HOLE, casted_stub()->store_mode());
@@ -1028,7 +1030,7 @@
Handle<PropertyCell> placeholder_cell =
isolate()->factory()->NewPropertyCell(placeholer_value);
- HParameter* value = GetParameter(2);
+ HParameter* value = GetParameter(StoreIC::kValueIndex);
if (stub->check_global()) {
// Check that the map of the global has not changed: use a placeholder map
diff --git a/src/code-stubs.cc b/src/code-stubs.cc
index 507d6f5..79eccef 100644
--- a/src/code-stubs.cc
+++ b/src/code-stubs.cc
@@ -634,6 +634,27 @@
}
+void KeyedStoreFastElementStub::InitializeInterfaceDescriptor(
+ CodeStubInterfaceDescriptor* descriptor) {
+ Register registers[] = { KeyedStoreIC::ReceiverRegister(),
+ KeyedStoreIC::NameRegister(),
+ KeyedStoreIC::ValueRegister() };
+ descriptor->Initialize(
+ ARRAY_SIZE(registers), registers,
+ FUNCTION_ADDR(KeyedStoreIC_MissFromStubFailure));
+}
+
+
+void StoreGlobalStub::InitializeInterfaceDescriptor(
+ CodeStubInterfaceDescriptor* descriptor) {
+ Register registers[] = { StoreIC::ReceiverRegister(),
+ StoreIC::NameRegister(),
+ StoreIC::ValueRegister() };
+ descriptor->Initialize(ARRAY_SIZE(registers), registers,
+ FUNCTION_ADDR(StoreIC_MissFromStubFailure));
+}
+
+
void KeyedLoadDictionaryElementPlatformStub::Generate(
MacroAssembler* masm) {
KeyedLoadStubCompiler::GenerateLoadDictionaryElement(masm);
diff --git a/src/compiler.cc b/src/compiler.cc
index 59c6a36..4dc5f30 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -31,6 +31,19 @@
namespace internal {
+ScriptData::ScriptData(const byte* data, int length)
+ : owns_data_(false), data_(data), length_(length) {
+ if (!IsAligned(reinterpret_cast<intptr_t>(data), kPointerAlignment)) {
+ byte* copy = NewArray<byte>(length);
+ // TODO(yangguo): find out why this is not always the case.
+ // ASSERT(IsAligned(reinterpret_cast<intptr_t>(data_), kPointerAlignment));
+ CopyBytes(copy, data, length);
+ data_ = copy;
+ AcquireDataOwnership();
+ }
+}
+
+
CompilationInfo::CompilationInfo(Handle<Script> script,
Zone* zone)
: flags_(StrictModeField::encode(SLOPPY)),
diff --git a/src/compiler.h b/src/compiler.h
index b0c4e11..58fb164 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -13,7 +13,6 @@
namespace internal {
class AstValueFactory;
-class ScriptData;
class HydrogenCodeStub;
// ParseRestriction is used to restrict the set of valid statements in a
@@ -35,6 +34,36 @@
int to;
};
+
+class ScriptData {
+ public:
+ ScriptData(const byte* data, int length);
+ ~ScriptData() {
+ if (owns_data_) DeleteArray(data_);
+ }
+
+ const byte* data() const { return data_; }
+ int length() const { return length_; }
+
+ void AcquireDataOwnership() {
+ ASSERT(!owns_data_);
+ owns_data_ = true;
+ }
+
+ void ReleaseDataOwnership() {
+ ASSERT(owns_data_);
+ owns_data_ = false;
+ }
+
+ private:
+ bool owns_data_;
+ const byte* data_;
+ int length_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScriptData);
+};
+
+
// CompilationInfo encapsulates some information known at compile time. It
// is constructed based on the resources available at compile-time.
class CompilationInfo {
@@ -722,7 +751,6 @@
DISALLOW_COPY_AND_ASSIGN(CompilationPhase);
};
-
} } // namespace v8::internal
#endif // V8_COMPILER_H_
diff --git a/src/d8.cc b/src/d8.cc
index 4e0d86f..35732b1 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -29,6 +29,10 @@
#include "include/v8-testing.h"
#endif // V8_SHARED
+#if !defined(V8_SHARED) && defined(ENABLE_GDB_JIT_INTERFACE)
+#include "src/gdb-jit.h"
+#endif
+
#ifdef ENABLE_VTUNE_JIT_INTERFACE
#include "src/third_party/vtune/v8-vtune.h"
#endif
@@ -1577,6 +1581,12 @@
{
Isolate::Scope scope(isolate);
Initialize(isolate);
+#if !defined(V8_SHARED) && defined(ENABLE_GDB_JIT_INTERFACE)
+ if (i::FLAG_gdbjit) {
+ v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault,
+ i::GDBJITInterface::EventHandler);
+ }
+#endif
#ifdef ENABLE_VTUNE_JIT_INTERFACE
vTune::InitializeVtuneForV8();
#endif
diff --git a/src/full-codegen.cc b/src/full-codegen.cc
index de7faa3..9b9b40d 100644
--- a/src/full-codegen.cc
+++ b/src/full-codegen.cc
@@ -303,9 +303,6 @@
MacroAssembler masm(info->isolate(), NULL, kInitialBufferSize);
if (info->will_serialize()) masm.enable_serializer();
-#ifdef ENABLE_GDB_JIT_INTERFACE
- masm.positions_recorder()->StartGDBJITLineInfoRecording();
-#endif
LOG_CODE_EVENT(isolate,
CodeStartLinePosInfoRecordEvent(masm.positions_recorder()));
@@ -332,13 +329,6 @@
code->set_back_edge_table_offset(table_offset);
CodeGenerator::PrintCode(code, info);
info->SetCode(code);
-#ifdef ENABLE_GDB_JIT_INTERFACE
- if (FLAG_gdbjit) {
- GDBJITLineInfo* lineinfo =
- masm.positions_recorder()->DetachGDBJITLineInfo();
- GDBJIT(RegisterDetailedLineInfo(*code, lineinfo));
- }
-#endif
void* line_info = masm.positions_recorder()->DetachJITHandlerData();
LOG_CODE_EVENT(isolate, CodeEndLinePosInfoRecordEvent(*code, line_info));
return true;
diff --git a/src/gdb-jit.cc b/src/gdb-jit.cc
index 51895f0..5ca6dfd 100644
--- a/src/gdb-jit.cc
+++ b/src/gdb-jit.cc
@@ -899,6 +899,32 @@
#endif // defined(__ELF)
+class LineInfo : public Malloced {
+ public:
+ LineInfo() : pc_info_(10) {}
+
+ void SetPosition(intptr_t pc, int pos, bool is_statement) {
+ AddPCInfo(PCInfo(pc, pos, is_statement));
+ }
+
+ struct PCInfo {
+ PCInfo(intptr_t pc, int pos, bool is_statement)
+ : pc_(pc), pos_(pos), is_statement_(is_statement) {}
+
+ intptr_t pc_;
+ int pos_;
+ bool is_statement_;
+ };
+
+ List<PCInfo>* pc_info() { return &pc_info_; }
+
+ private:
+ void AddPCInfo(const PCInfo& pc_info) { pc_info_.Add(pc_info); }
+
+ List<PCInfo> pc_info_;
+};
+
+
class CodeDescription BASE_EMBEDDED {
public:
#if V8_TARGET_ARCH_X64
@@ -910,27 +936,21 @@
};
#endif
- CodeDescription(const char* name,
- Code* code,
- Handle<Script> script,
- GDBJITLineInfo* lineinfo,
- GDBJITInterface::CodeTag tag,
+ CodeDescription(const char* name, Code* code, Handle<Script> script,
+ LineInfo* lineinfo, GDBJITInterface::CodeTag tag,
CompilationInfo* info)
: name_(name),
code_(code),
script_(script),
lineinfo_(lineinfo),
tag_(tag),
- info_(info) {
- }
+ info_(info) {}
const char* name() const {
return name_;
}
- GDBJITLineInfo* lineinfo() const {
- return lineinfo_;
- }
+ LineInfo* lineinfo() const { return lineinfo_; }
GDBJITInterface::CodeTag tag() const {
return tag_;
@@ -989,7 +1009,7 @@
const char* name_;
Code* code_;
Handle<Script> script_;
- GDBJITLineInfo* lineinfo_;
+ LineInfo* lineinfo_;
GDBJITInterface::CodeTag tag_;
CompilationInfo* info_;
#if V8_TARGET_ARCH_X64
@@ -1451,12 +1471,12 @@
intptr_t line = 1;
bool is_statement = true;
- List<GDBJITLineInfo::PCInfo>* pc_info = desc_->lineinfo()->pc_info();
+ List<LineInfo::PCInfo>* pc_info = desc_->lineinfo()->pc_info();
pc_info->Sort(&ComparePCInfo);
int pc_info_length = pc_info->length();
for (int i = 0; i < pc_info_length; i++) {
- GDBJITLineInfo::PCInfo* info = &pc_info->at(i);
+ LineInfo::PCInfo* info = &pc_info->at(i);
ASSERT(info->pc_ >= pc);
// Reduce bloating in the debug line table by removing duplicate line
@@ -1527,8 +1547,8 @@
w->Write<uint8_t>(op);
}
- static int ComparePCInfo(const GDBJITLineInfo::PCInfo* a,
- const GDBJITLineInfo::PCInfo* b) {
+ static int ComparePCInfo(const LineInfo::PCInfo* a,
+ const LineInfo::PCInfo* b) {
if (a->pc_ == b->pc_) {
if (a->is_statement_ != b->is_statement_) {
return b->is_statement_ ? +1 : -1;
@@ -1967,15 +1987,15 @@
}
-static void* TagLineInfo(GDBJITLineInfo* ptr) {
+static void* TagLineInfo(LineInfo* ptr) {
return reinterpret_cast<void*>(
reinterpret_cast<intptr_t>(ptr) | kLineInfoTag);
}
-static GDBJITLineInfo* UntagLineInfo(void* ptr) {
- return reinterpret_cast<GDBJITLineInfo*>(
- reinterpret_cast<intptr_t>(ptr) & ~kLineInfoTag);
+static LineInfo* UntagLineInfo(void* ptr) {
+ return reinterpret_cast<LineInfo*>(reinterpret_cast<intptr_t>(ptr) &
+ ~kLineInfoTag);
}
@@ -2051,7 +2071,7 @@
HashMap::Entry* e = GetEntries()->Lookup(code, HashForCodeObject(code), true);
if (e->value != NULL && !IsLineInfoTagged(e->value)) return;
- GDBJITLineInfo* lineinfo = UntagLineInfo(e->value);
+ LineInfo* lineinfo = UntagLineInfo(e->value);
CodeDescription code_desc(name,
code,
script != NULL ? Handle<Script>(script)
@@ -2167,8 +2187,7 @@
}
-void GDBJITInterface::RegisterDetailedLineInfo(Code* code,
- GDBJITLineInfo* line_info) {
+static void RegisterDetailedLineInfo(Code* code, LineInfo* line_info) {
base::LockGuard<base::Mutex> lock_guard(mutex.Pointer());
ASSERT(!IsLineInfoTagged(line_info));
HashMap::Entry* e = GetEntries()->Lookup(code, HashForCodeObject(code), true);
@@ -2177,5 +2196,36 @@
}
+void GDBJITInterface::EventHandler(const v8::JitCodeEvent* event) {
+ if (!FLAG_gdbjit) return;
+ switch (event->type) {
+ case v8::JitCodeEvent::CODE_ADDED:
+ case v8::JitCodeEvent::CODE_MOVED:
+ case v8::JitCodeEvent::CODE_REMOVED:
+ break;
+ case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
+ LineInfo* line_info = reinterpret_cast<LineInfo*>(event->user_data);
+ line_info->SetPosition(static_cast<intptr_t>(event->line_info.offset),
+ static_cast<int>(event->line_info.pos),
+ event->line_info.position_type ==
+ v8::JitCodeEvent::STATEMENT_POSITION);
+ break;
+ }
+ case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
+ v8::JitCodeEvent* mutable_event = const_cast<v8::JitCodeEvent*>(event);
+ mutable_event->user_data = new LineInfo();
+ break;
+ }
+ case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
+ LineInfo* line_info = reinterpret_cast<LineInfo*>(event->user_data);
+ Code* code = Code::GetCodeFromTargetAddress(
+ reinterpret_cast<Address>(event->code_start));
+ RegisterDetailedLineInfo(code, line_info);
+ break;
+ }
+ }
+}
+
+
} } // namespace v8::internal
#endif
diff --git a/src/gdb-jit.h b/src/gdb-jit.h
index db9c0f2..323038a 100644
--- a/src/gdb-jit.h
+++ b/src/gdb-jit.h
@@ -34,37 +34,6 @@
V(EVAL) \
V(FUNCTION)
-class GDBJITLineInfo : public Malloced {
- public:
- GDBJITLineInfo()
- : pc_info_(10) { }
-
- void SetPosition(intptr_t pc, int pos, bool is_statement) {
- AddPCInfo(PCInfo(pc, pos, is_statement));
- }
-
- struct PCInfo {
- PCInfo(intptr_t pc, int pos, bool is_statement)
- : pc_(pc), pos_(pos), is_statement_(is_statement) { }
-
- intptr_t pc_;
- int pos_;
- bool is_statement_;
- };
-
- List<PCInfo>* pc_info() {
- return &pc_info_;
- }
-
- private:
- void AddPCInfo(const PCInfo& pc_info) {
- pc_info_.Add(pc_info);
- }
-
- List<PCInfo> pc_info_;
-};
-
-
class GDBJITInterface: public AllStatic {
public:
enum CodeTag {
@@ -84,6 +53,9 @@
}
}
+ // Main entry point into GDB JIT realized as a JitCodeEventHandler.
+ static void EventHandler(const v8::JitCodeEvent* event);
+
static void AddCode(const char* name,
Code* code,
CodeTag tag,
@@ -104,8 +76,6 @@
static void RemoveCode(Code* code);
static void RemoveCodeRange(Address start, Address end);
-
- static void RegisterDetailedLineInfo(Code* code, GDBJITLineInfo* line_info);
};
#define GDBJIT(action) GDBJITInterface::action
diff --git a/src/heap-snapshot-generator.cc b/src/heap-snapshot-generator.cc
index f39ac1d..6229386 100644
--- a/src/heap-snapshot-generator.cc
+++ b/src/heap-snapshot-generator.cc
@@ -1097,11 +1097,16 @@
ExtractJSGlobalProxyReferences(entry, JSGlobalProxy::cast(obj));
} else if (obj->IsJSArrayBuffer()) {
ExtractJSArrayBufferReferences(entry, JSArrayBuffer::cast(obj));
- } else if (obj->IsJSWeakSet()) {
- ExtractJSWeakCollectionReferences(entry, JSWeakSet::cast(obj));
- } else if (obj->IsJSWeakMap()) {
- ExtractJSWeakCollectionReferences(entry, JSWeakMap::cast(obj));
} else if (obj->IsJSObject()) {
+ if (obj->IsJSWeakSet()) {
+ ExtractJSWeakCollectionReferences(entry, JSWeakSet::cast(obj));
+ } else if (obj->IsJSWeakMap()) {
+ ExtractJSWeakCollectionReferences(entry, JSWeakMap::cast(obj));
+ } else if (obj->IsJSSet()) {
+ ExtractJSCollectionReferences(entry, JSSet::cast(obj));
+ } else if (obj->IsJSMap()) {
+ ExtractJSCollectionReferences(entry, JSMap::cast(obj));
+ }
ExtractJSObjectReferences(entry, JSObject::cast(obj));
} else if (obj->IsString()) {
ExtractStringReferences(entry, String::cast(obj));
@@ -1260,6 +1265,13 @@
}
+void V8HeapExplorer::ExtractJSCollectionReferences(int entry,
+ JSCollection* collection) {
+ SetInternalReference(collection, entry, "table", collection->table(),
+ JSCollection::kTableOffset);
+}
+
+
void V8HeapExplorer::ExtractJSWeakCollectionReferences(
int entry, JSWeakCollection* collection) {
MarkAsWeakContainer(collection->table());
diff --git a/src/heap-snapshot-generator.h b/src/heap-snapshot-generator.h
index e18d70a..329570f 100644
--- a/src/heap-snapshot-generator.h
+++ b/src/heap-snapshot-generator.h
@@ -370,6 +370,7 @@
void ExtractJSObjectReferences(int entry, JSObject* js_obj);
void ExtractStringReferences(int entry, String* obj);
void ExtractSymbolReferences(int entry, Symbol* symbol);
+ void ExtractJSCollectionReferences(int entry, JSCollection* collection);
void ExtractJSWeakCollectionReferences(int entry,
JSWeakCollection* collection);
void ExtractContextReferences(int entry, Context* context);
diff --git a/src/heap.cc b/src/heap.cc
index 8560aa3..d172ceb 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -408,7 +408,7 @@
}
-void Heap::GarbageCollectionPrologue(GarbageCollector collector) {
+void Heap::GarbageCollectionPrologue() {
{ AllowHeapAllocation for_the_first_part_of_prologue;
ClearJSFunctionResultCaches();
gc_count_++;
@@ -439,7 +439,7 @@
ReportStatisticsBeforeGC();
#endif // DEBUG
- store_buffer()->GCPrologue(collector == MARK_COMPACTOR);
+ store_buffer()->GCPrologue();
if (isolate()->concurrent_osr_enabled()) {
isolate()->optimizing_compiler_thread()->AgeBufferedOsrJobs();
@@ -837,7 +837,7 @@
{ GCTracer tracer(this, gc_reason, collector_reason);
ASSERT(AllowHeapAllocation::IsAllowed());
DisallowHeapAllocation no_allocation_during_gc;
- GarbageCollectionPrologue(collector);
+ GarbageCollectionPrologue();
// The GC count was incremented in the prologue. Tell the tracer about
// it.
tracer.set_gc_count(gc_count_);
diff --git a/src/heap.h b/src/heap.h
index 66f7ce6..a6a14f6 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -1698,7 +1698,7 @@
// Code that should be run before and after each GC. Includes some
// reporting/verification activities when compiled with DEBUG set.
- void GarbageCollectionPrologue(GarbageCollector collector);
+ void GarbageCollectionPrologue();
void GarbageCollectionEpilogue();
// Pretenuring decisions are made based on feedback collected during new
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index e3f1aa6..1dfd62f 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -92,15 +92,6 @@
}
-void KeyedStoreFastElementStub::InitializeInterfaceDescriptor(
- CodeStubInterfaceDescriptor* descriptor) {
- Register registers[] = { edx, ecx, eax };
- descriptor->Initialize(
- ARRAY_SIZE(registers), registers,
- FUNCTION_ADDR(KeyedStoreIC_MissFromStubFailure));
-}
-
-
void TransitionElementsKindStub::InitializeInterfaceDescriptor(
CodeStubInterfaceDescriptor* descriptor) {
Register registers[] = { eax, ebx };
@@ -234,14 +225,6 @@
}
-void StoreGlobalStub::InitializeInterfaceDescriptor(
- CodeStubInterfaceDescriptor* descriptor) {
- Register registers[] = { edx, ecx, eax };
- descriptor->Initialize(ARRAY_SIZE(registers), registers,
- FUNCTION_ADDR(StoreIC_MissFromStubFailure));
-}
-
-
void ElementsTransitionAndStoreStub::InitializeInterfaceDescriptor(
CodeStubInterfaceDescriptor* descriptor) {
Register registers[] = { eax, ebx, ecx, edx };
diff --git a/src/ia32/debug-ia32.cc b/src/ia32/debug-ia32.cc
index 68cf0dd..763c548 100644
--- a/src/ia32/debug-ia32.cc
+++ b/src/ia32/debug-ia32.cc
@@ -188,13 +188,11 @@
void DebugCodegen::GenerateStoreICDebugBreak(MacroAssembler* masm) {
// Register state for IC store call (from ic-ia32.cc).
- // ----------- S t a t e -------------
- // -- eax : value
- // -- ecx : name
- // -- edx : receiver
- // -----------------------------------
+ Register receiver = StoreIC::ReceiverRegister();
+ Register name = StoreIC::NameRegister();
+ Register value = StoreIC::ValueRegister();
Generate_DebugBreakCallHelper(
- masm, eax.bit() | ecx.bit() | edx.bit(), 0, false);
+ masm, receiver.bit() | name.bit() | value.bit(), 0, false);
}
@@ -205,14 +203,12 @@
void DebugCodegen::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
- // Register state for keyed IC load call (from ic-ia32.cc).
- // ----------- S t a t e -------------
- // -- eax : value
- // -- ecx : key
- // -- edx : receiver
- // -----------------------------------
+ // Register state for keyed IC store call (from ic-ia32.cc).
+ Register receiver = KeyedStoreIC::ReceiverRegister();
+ Register name = KeyedStoreIC::NameRegister();
+ Register value = KeyedStoreIC::ValueRegister();
Generate_DebugBreakCallHelper(
- masm, eax.bit() | ecx.bit() | edx.bit(), 0, false);
+ masm, receiver.bit() | name.bit() | value.bit(), 0, false);
}
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index e9f13c1..e3669cf 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -1633,8 +1633,9 @@
if (key->value()->IsInternalizedString()) {
if (property->emit_store()) {
VisitForAccumulatorValue(value);
- __ mov(ecx, Immediate(key->value()));
- __ mov(edx, Operand(esp, 0));
+ ASSERT(StoreIC::ValueRegister().is(eax));
+ __ mov(StoreIC::NameRegister(), Immediate(key->value()));
+ __ mov(StoreIC::ReceiverRegister(), Operand(esp, 0));
CallStoreIC(key->LiteralFeedbackId());
PrepareForBailoutForId(key->id(), NO_REGISTERS);
} else {
@@ -2349,9 +2350,9 @@
case NAMED_PROPERTY: {
__ push(eax); // Preserve value.
VisitForAccumulatorValue(prop->obj());
- __ mov(edx, eax);
- __ pop(eax); // Restore value.
- __ mov(ecx, prop->key()->AsLiteral()->value());
+ __ Move(StoreIC::ReceiverRegister(), eax);
+ __ pop(StoreIC::ValueRegister()); // Restore value.
+ __ mov(StoreIC::NameRegister(), prop->key()->AsLiteral()->value());
CallStoreIC();
break;
}
@@ -2359,9 +2360,9 @@
__ push(eax); // Preserve value.
VisitForStackValue(prop->obj());
VisitForAccumulatorValue(prop->key());
- __ mov(ecx, eax);
- __ pop(edx); // Receiver.
- __ pop(eax); // Restore value.
+ __ Move(KeyedStoreIC::NameRegister(), eax);
+ __ pop(KeyedStoreIC::ReceiverRegister()); // Receiver.
+ __ pop(KeyedStoreIC::ValueRegister()); // Restore value.
Handle<Code> ic = strict_mode() == SLOPPY
? isolate()->builtins()->KeyedStoreIC_Initialize()
: isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
@@ -2398,8 +2399,8 @@
Token::Value op) {
if (var->IsUnallocated()) {
// Global var, const, or let.
- __ mov(ecx, var->name());
- __ mov(edx, GlobalObjectOperand());
+ __ mov(StoreIC::NameRegister(), var->name());
+ __ mov(StoreIC::ReceiverRegister(), GlobalObjectOperand());
CallStoreIC();
} else if (op == Token::INIT_CONST_LEGACY) {
@@ -2470,8 +2471,8 @@
// Record source code position before IC call.
SetSourcePosition(expr->position());
- __ mov(ecx, prop->key()->AsLiteral()->value());
- __ pop(edx);
+ __ mov(StoreIC::NameRegister(), prop->key()->AsLiteral()->value());
+ __ pop(StoreIC::ReceiverRegister());
CallStoreIC(expr->AssignmentFeedbackId());
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
context()->Plug(eax);
@@ -2484,8 +2485,9 @@
// esp[0] : key
// esp[kPointerSize] : receiver
- __ pop(ecx); // Key.
- __ pop(edx);
+ __ pop(KeyedStoreIC::NameRegister()); // Key.
+ __ pop(KeyedStoreIC::ReceiverRegister());
+ ASSERT(KeyedStoreIC::ValueRegister().is(eax));
// Record source code position before IC call.
SetSourcePosition(expr->position());
Handle<Code> ic = strict_mode() == SLOPPY
@@ -4332,8 +4334,8 @@
}
break;
case NAMED_PROPERTY: {
- __ mov(ecx, prop->key()->AsLiteral()->value());
- __ pop(edx);
+ __ mov(StoreIC::NameRegister(), prop->key()->AsLiteral()->value());
+ __ pop(StoreIC::ReceiverRegister());
CallStoreIC(expr->CountStoreFeedbackId());
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
if (expr->is_postfix()) {
@@ -4346,8 +4348,8 @@
break;
}
case KEYED_PROPERTY: {
- __ pop(ecx);
- __ pop(edx);
+ __ pop(KeyedStoreIC::NameRegister());
+ __ pop(KeyedStoreIC::ReceiverRegister());
Handle<Code> ic = strict_mode() == SLOPPY
? isolate()->builtins()->KeyedStoreIC_Initialize()
: isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc
index 4536103..379ed0f 100644
--- a/src/ia32/ic-ia32.cc
+++ b/src/ia32/ic-ia32.cc
@@ -555,23 +555,14 @@
}
-// A register that isn't one of the parameters to the load ic.
-static const Register LoadIC_TempRegister() { return ebx; }
-
-
-// A register that isn't one of the parameters to the load ic.
-static const Register KeyedLoadIC_TempRegister() {
- return LoadIC_TempRegister();
-}
-
-
void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
// Return address is on the stack.
Label miss;
Register receiver = ReceiverRegister();
Register index = NameRegister();
- Register scratch = KeyedLoadIC_TempRegister();
+ Register scratch = ebx;
+ ASSERT(!scratch.is(receiver) && !scratch.is(index));
Register result = eax;
ASSERT(!result.is(scratch));
@@ -665,27 +656,30 @@
void KeyedStoreIC::GenerateSloppyArguments(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- eax : value
- // -- ecx : key
- // -- edx : receiver
- // -- esp[0] : return address
- // -----------------------------------
+ // Return address is on the stack.
Label slow, notin;
+ Register receiver = ReceiverRegister();
+ Register name = NameRegister();
+ Register value = ValueRegister();
+ ASSERT(receiver.is(edx));
+ ASSERT(name.is(ecx));
+ ASSERT(value.is(eax));
+
Operand mapped_location =
- GenerateMappedArgumentsLookup(masm, edx, ecx, ebx, edi, ¬in, &slow);
- __ mov(mapped_location, eax);
+ GenerateMappedArgumentsLookup(masm, receiver, name, ebx, edi, ¬in,
+ &slow);
+ __ mov(mapped_location, value);
__ lea(ecx, mapped_location);
- __ mov(edx, eax);
+ __ mov(edx, value);
__ RecordWrite(ebx, ecx, edx, kDontSaveFPRegs);
__ Ret();
__ bind(¬in);
// The unmapped lookup expects that the parameter map is in ebx.
Operand unmapped_location =
- GenerateUnmappedArgumentsLookup(masm, ecx, ebx, edi, &slow);
- __ mov(unmapped_location, eax);
+ GenerateUnmappedArgumentsLookup(masm, name, ebx, edi, &slow);
+ __ mov(unmapped_location, value);
__ lea(edi, unmapped_location);
- __ mov(edx, eax);
+ __ mov(edx, value);
__ RecordWrite(ebx, edi, edx, kDontSaveFPRegs);
__ Ret();
__ bind(&slow);
@@ -703,9 +697,13 @@
Label transition_smi_elements;
Label finish_object_store, non_double_value, transition_double_elements;
Label fast_double_without_map_check;
- // eax: value
- // ecx: key (a smi)
- // edx: receiver
+ Register receiver = KeyedStoreIC::ReceiverRegister();
+ Register key = KeyedStoreIC::NameRegister();
+ Register value = KeyedStoreIC::ValueRegister();
+ ASSERT(receiver.is(edx));
+ ASSERT(key.is(ecx));
+ ASSERT(value.is(eax));
+ // key is a smi.
// ebx: FixedArray receiver->elements
// edi: receiver map
// Fast case: Do the store, could either Object or double.
@@ -720,43 +718,43 @@
// We have to go to the runtime if the current value is the hole because
// there may be a callback on the element
Label holecheck_passed1;
- __ cmp(FixedArrayElementOperand(ebx, ecx),
+ __ cmp(FixedArrayElementOperand(ebx, key),
masm->isolate()->factory()->the_hole_value());
__ j(not_equal, &holecheck_passed1);
- __ JumpIfDictionaryInPrototypeChain(edx, ebx, edi, slow);
- __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
+ __ JumpIfDictionaryInPrototypeChain(receiver, ebx, edi, slow);
+ __ mov(ebx, FieldOperand(receiver, JSObject::kElementsOffset));
__ bind(&holecheck_passed1);
// Smi stores don't require further checks.
Label non_smi_value;
- __ JumpIfNotSmi(eax, &non_smi_value);
+ __ JumpIfNotSmi(value, &non_smi_value);
if (increment_length == kIncrementLength) {
// Add 1 to receiver->length.
- __ add(FieldOperand(edx, JSArray::kLengthOffset),
+ __ add(FieldOperand(receiver, JSArray::kLengthOffset),
Immediate(Smi::FromInt(1)));
}
// It's irrelevant whether array is smi-only or not when writing a smi.
- __ mov(FixedArrayElementOperand(ebx, ecx), eax);
+ __ mov(FixedArrayElementOperand(ebx, key), value);
__ ret(0);
__ bind(&non_smi_value);
// Escape to elements kind transition case.
- __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
+ __ mov(edi, FieldOperand(receiver, HeapObject::kMapOffset));
__ CheckFastObjectElements(edi, &transition_smi_elements);
// Fast elements array, store the value to the elements backing store.
__ bind(&finish_object_store);
if (increment_length == kIncrementLength) {
// Add 1 to receiver->length.
- __ add(FieldOperand(edx, JSArray::kLengthOffset),
+ __ add(FieldOperand(receiver, JSArray::kLengthOffset),
Immediate(Smi::FromInt(1)));
}
- __ mov(FixedArrayElementOperand(ebx, ecx), eax);
+ __ mov(FixedArrayElementOperand(ebx, key), value);
// Update write barrier for the elements array address.
- __ mov(edx, eax); // Preserve the value which is returned.
+ __ mov(edx, value); // Preserve the value which is returned.
__ RecordWriteArray(
- ebx, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
+ ebx, edx, key, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
__ ret(0);
__ bind(fast_double);
@@ -773,26 +771,26 @@
// We have to see if the double version of the hole is present. If so
// go to the runtime.
uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
- __ cmp(FieldOperand(ebx, ecx, times_4, offset), Immediate(kHoleNanUpper32));
+ __ cmp(FieldOperand(ebx, key, times_4, offset), Immediate(kHoleNanUpper32));
__ j(not_equal, &fast_double_without_map_check);
- __ JumpIfDictionaryInPrototypeChain(edx, ebx, edi, slow);
- __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
+ __ JumpIfDictionaryInPrototypeChain(receiver, ebx, edi, slow);
+ __ mov(ebx, FieldOperand(receiver, JSObject::kElementsOffset));
__ bind(&fast_double_without_map_check);
- __ StoreNumberToDoubleElements(eax, ebx, ecx, edi, xmm0,
+ __ StoreNumberToDoubleElements(value, ebx, key, edi, xmm0,
&transition_double_elements);
if (increment_length == kIncrementLength) {
// Add 1 to receiver->length.
- __ add(FieldOperand(edx, JSArray::kLengthOffset),
+ __ add(FieldOperand(receiver, JSArray::kLengthOffset),
Immediate(Smi::FromInt(1)));
}
__ ret(0);
__ bind(&transition_smi_elements);
- __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
+ __ mov(ebx, FieldOperand(receiver, HeapObject::kMapOffset));
// Transition the array appropriately depending on the value type.
- __ CheckMap(eax,
+ __ CheckMap(value,
masm->isolate()->factory()->heap_number_map(),
&non_double_value,
DONT_DO_SMI_CHECK);
@@ -807,7 +805,7 @@
AllocationSiteMode mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS,
FAST_DOUBLE_ELEMENTS);
ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, slow);
- __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
+ __ mov(ebx, FieldOperand(receiver, JSObject::kElementsOffset));
__ jmp(&fast_double_without_map_check);
__ bind(&non_double_value);
@@ -820,14 +818,14 @@
mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm, mode,
slow);
- __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
+ __ mov(ebx, FieldOperand(receiver, JSObject::kElementsOffset));
__ jmp(&finish_object_store);
__ bind(&transition_double_elements);
// Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
// HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
// transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
- __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
+ __ mov(ebx, FieldOperand(receiver, HeapObject::kMapOffset));
__ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
FAST_ELEMENTS,
ebx,
@@ -835,34 +833,33 @@
slow);
mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, slow);
- __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
+ __ mov(ebx, FieldOperand(receiver, JSObject::kElementsOffset));
__ jmp(&finish_object_store);
}
void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
StrictMode strict_mode) {
- // ----------- S t a t e -------------
- // -- eax : value
- // -- ecx : key
- // -- edx : receiver
- // -- esp[0] : return address
- // -----------------------------------
+ // Return address is on the stack.
Label slow, fast_object, fast_object_grow;
Label fast_double, fast_double_grow;
Label array, extra, check_if_double_array;
+ Register receiver = ReceiverRegister();
+ Register key = NameRegister();
+ ASSERT(receiver.is(edx));
+ ASSERT(key.is(ecx));
// Check that the object isn't a smi.
- __ JumpIfSmi(edx, &slow);
+ __ JumpIfSmi(receiver, &slow);
// Get the map from the receiver.
- __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
+ __ mov(edi, FieldOperand(receiver, HeapObject::kMapOffset));
// Check that the receiver does not require access checks and is not observed.
// The generic stub does not perform map checks or handle observed objects.
__ test_b(FieldOperand(edi, Map::kBitFieldOffset),
1 << Map::kIsAccessCheckNeeded | 1 << Map::kIsObserved);
__ j(not_zero, &slow);
// Check that the key is a smi.
- __ JumpIfNotSmi(ecx, &slow);
+ __ JumpIfNotSmi(key, &slow);
__ CmpInstanceType(edi, JS_ARRAY_TYPE);
__ j(equal, &array);
// Check that the object is some kind of JSObject.
@@ -870,13 +867,11 @@
__ j(below, &slow);
// Object case: Check key against length in the elements array.
- // eax: value
- // edx: JSObject
- // ecx: key (a smi)
+ // Key is a smi.
// edi: receiver map
- __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
+ __ mov(ebx, FieldOperand(receiver, JSObject::kElementsOffset));
// Check array bounds. Both the key and the length of FixedArray are smis.
- __ cmp(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
+ __ cmp(key, FieldOperand(ebx, FixedArray::kLengthOffset));
__ j(below, &fast_object);
// Slow case: call runtime.
@@ -887,15 +882,14 @@
// perform the store and update the length. Used for adding one
// element to the array by writing to array[array.length].
__ bind(&extra);
- // eax: value
- // edx: receiver, a JSArray
- // ecx: key, a smi.
+ // receiver is a JSArray.
+ // key is a smi.
// ebx: receiver->elements, a FixedArray
// edi: receiver map
- // flags: compare (ecx, edx.length())
+ // flags: compare (key, receiver.length())
// do not leave holes in the array:
__ j(not_equal, &slow);
- __ cmp(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
+ __ cmp(key, FieldOperand(ebx, FixedArray::kLengthOffset));
__ j(above_equal, &slow);
__ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset));
__ cmp(edi, masm->isolate()->factory()->fixed_array_map());
@@ -911,15 +905,14 @@
// array. Check that the array is in fast mode (and writable); if it
// is the length is always a smi.
__ bind(&array);
- // eax: value
- // edx: receiver, a JSArray
- // ecx: key, a smi.
+ // receiver is a JSArray.
+ // key is a smi.
// edi: receiver map
- __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
+ __ mov(ebx, FieldOperand(receiver, JSObject::kElementsOffset));
// Check the key against the length in the array and fall through to the
// common store code.
- __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // Compare smis.
+ __ cmp(key, FieldOperand(receiver, JSArray::kLengthOffset)); // Compare smis.
__ j(above_equal, &extra);
KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double,
@@ -974,14 +967,23 @@
}
+static void LoadIC_PushArgs(MacroAssembler* masm) {
+ Register receiver = LoadIC::ReceiverRegister();
+ Register name = LoadIC::NameRegister();
+ ASSERT(!ebx.is(receiver) && !ebx.is(name));
+
+ __ pop(ebx);
+ __ push(receiver);
+ __ push(name);
+ __ push(ebx);
+}
+
+
void LoadIC::GenerateMiss(MacroAssembler* masm) {
// Return address is on the stack.
__ IncrementCounter(masm->isolate()->counters()->load_miss(), 1);
- __ pop(LoadIC_TempRegister());
- __ push(ReceiverRegister()); // receiver
- __ push(NameRegister()); // name
- __ push(LoadIC_TempRegister()); // return address
+ LoadIC_PushArgs(masm);
// Perform tail call to the entry.
ExternalReference ref =
@@ -992,10 +994,7 @@
void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
// Return address is on the stack.
- __ pop(LoadIC_TempRegister());
- __ push(ReceiverRegister()); // receiver
- __ push(NameRegister()); // name
- __ push(LoadIC_TempRegister()); // return address
+ LoadIC_PushArgs(masm);
// Perform tail call to the entry.
__ TailCallRuntime(Runtime::kGetProperty, 2, 1);
@@ -1006,10 +1005,7 @@
// Return address is on the stack.
__ IncrementCounter(masm->isolate()->counters()->keyed_load_miss(), 1);
- __ pop(KeyedLoadIC_TempRegister());
- __ push(ReceiverRegister()); // receiver
- __ push(NameRegister()); // name
- __ push(KeyedLoadIC_TempRegister()); // return address
+ LoadIC_PushArgs(masm);
// Perform tail call to the entry.
ExternalReference ref =
@@ -1023,12 +1019,29 @@
const Register LoadIC::NameRegister() { return ecx; }
+const Register StoreIC::ReceiverRegister() { return edx; }
+const Register StoreIC::NameRegister() { return ecx; }
+const Register StoreIC::ValueRegister() { return eax; }
+
+
+const Register KeyedStoreIC::ReceiverRegister() {
+ return StoreIC::ReceiverRegister();
+}
+
+
+const Register KeyedStoreIC::NameRegister() {
+ return StoreIC::NameRegister();
+}
+
+
+const Register KeyedStoreIC::ValueRegister() {
+ return StoreIC::ValueRegister();
+}
+
+
void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
// Return address is on the stack.
- __ pop(KeyedLoadIC_TempRegister());
- __ push(ReceiverRegister()); // receiver
- __ push(NameRegister()); // name
- __ push(KeyedLoadIC_TempRegister()); // return address
+ LoadIC_PushArgs(masm);
// Perform tail call to the entry.
__ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
@@ -1036,34 +1049,35 @@
void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- eax : value
- // -- ecx : name
- // -- edx : receiver
- // -- esp[0] : return address
- // -----------------------------------
+ // Return address is on the stack.
Code::Flags flags = Code::ComputeHandlerFlags(Code::STORE_IC);
masm->isolate()->stub_cache()->GenerateProbe(
- masm, flags, edx, ecx, ebx, no_reg);
+ masm, flags, ReceiverRegister(), NameRegister(),
+ ebx, no_reg);
// Cache miss: Jump to runtime.
GenerateMiss(masm);
}
-void StoreIC::GenerateMiss(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- eax : value
- // -- ecx : name
- // -- edx : receiver
- // -- esp[0] : return address
- // -----------------------------------
+static void StoreIC_PushArgs(MacroAssembler* masm) {
+ Register receiver = StoreIC::ReceiverRegister();
+ Register name = StoreIC::NameRegister();
+ Register value = StoreIC::ValueRegister();
+
+ ASSERT(!ebx.is(receiver) && !ebx.is(name) && !ebx.is(value));
__ pop(ebx);
- __ push(edx);
- __ push(ecx);
- __ push(eax);
+ __ push(receiver);
+ __ push(name);
+ __ push(value);
__ push(ebx);
+}
+
+
+void StoreIC::GenerateMiss(MacroAssembler* masm) {
+ // Return address is on the stack.
+ StoreIC_PushArgs(masm);
// Perform tail call to the entry.
ExternalReference ref =
@@ -1073,29 +1087,26 @@
void StoreIC::GenerateNormal(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- eax : value
- // -- ecx : name
- // -- edx : receiver
- // -- esp[0] : return address
- // -----------------------------------
-
+ // Return address is on the stack.
Label miss, restore_miss;
+ Register receiver = ReceiverRegister();
+ Register name = NameRegister();
+ Register value = ValueRegister();
- GenerateNameDictionaryReceiverCheck(masm, edx, ebx, edi, &miss);
+ GenerateNameDictionaryReceiverCheck(masm, receiver, ebx, edi, &miss);
// A lot of registers are needed for storing to slow case
// objects. Push and restore receiver but rely on
// GenerateDictionaryStore preserving the value and name.
- __ push(edx);
- GenerateDictionaryStore(masm, &restore_miss, ebx, ecx, eax, edx, edi);
+ __ push(receiver);
+ GenerateDictionaryStore(masm, &restore_miss, ebx, name, value, receiver, edi);
__ Drop(1);
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->store_normal_hit(), 1);
__ ret(0);
__ bind(&restore_miss);
- __ pop(edx);
+ __ pop(receiver);
__ bind(&miss);
__ IncrementCounter(counters->store_normal_miss(), 1);
@@ -1105,16 +1116,13 @@
void StoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
StrictMode strict_mode) {
- // ----------- S t a t e -------------
- // -- eax : value
- // -- ecx : name
- // -- edx : receiver
- // -- esp[0] : return address
- // -----------------------------------
+ // Return address is on the stack.
+ ASSERT(!ebx.is(ReceiverRegister()) && !ebx.is(NameRegister()) &&
+ !ebx.is(ValueRegister()));
__ pop(ebx);
- __ push(edx);
- __ push(ecx);
- __ push(eax);
+ __ push(ReceiverRegister());
+ __ push(NameRegister());
+ __ push(ValueRegister());
__ push(Immediate(Smi::FromInt(strict_mode)));
__ push(ebx); // return address
@@ -1125,19 +1133,15 @@
void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
StrictMode strict_mode) {
- // ----------- S t a t e -------------
- // -- eax : value
- // -- ecx : key
- // -- edx : receiver
- // -- esp[0] : return address
- // -----------------------------------
-
+ // Return address is on the stack.
+ ASSERT(!ebx.is(ReceiverRegister()) && !ebx.is(NameRegister()) &&
+ !ebx.is(ValueRegister()));
__ pop(ebx);
- __ push(edx);
- __ push(ecx);
- __ push(eax);
- __ push(Immediate(Smi::FromInt(strict_mode))); // Strict mode.
- __ push(ebx); // return address
+ __ push(ReceiverRegister());
+ __ push(NameRegister());
+ __ push(ValueRegister());
+ __ push(Immediate(Smi::FromInt(strict_mode)));
+ __ push(ebx); // return address
// Do tail-call to runtime routine.
__ TailCallRuntime(Runtime::kSetProperty, 4, 1);
@@ -1145,18 +1149,8 @@
void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- eax : value
- // -- ecx : key
- // -- edx : receiver
- // -- esp[0] : return address
- // -----------------------------------
-
- __ pop(ebx);
- __ push(edx);
- __ push(ecx);
- __ push(eax);
- __ push(ebx);
+ // Return address is on the stack.
+ StoreIC_PushArgs(masm);
// Do tail-call to runtime routine.
ExternalReference ref =
@@ -1166,18 +1160,8 @@
void StoreIC::GenerateSlow(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- eax : value
- // -- ecx : key
- // -- edx : receiver
- // -- esp[0] : return address
- // -----------------------------------
-
- __ pop(ebx);
- __ push(edx);
- __ push(ecx);
- __ push(eax);
- __ push(ebx); // return address
+ // Return address is on the stack.
+ StoreIC_PushArgs(masm);
// Do tail-call to runtime routine.
ExternalReference ref(IC_Utility(kStoreIC_Slow), masm->isolate());
@@ -1186,18 +1170,8 @@
void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- eax : value
- // -- ecx : key
- // -- edx : receiver
- // -- esp[0] : return address
- // -----------------------------------
-
- __ pop(ebx);
- __ push(edx);
- __ push(ecx);
- __ push(eax);
- __ push(ebx); // return address
+ // Return address is on the stack.
+ StoreIC_PushArgs(masm);
// Do tail-call to runtime routine.
ExternalReference ref(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index f43b0a7..0cd5c36 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -4054,10 +4054,10 @@
void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
ASSERT(ToRegister(instr->context()).is(esi));
- ASSERT(ToRegister(instr->object()).is(edx));
- ASSERT(ToRegister(instr->value()).is(eax));
+ ASSERT(ToRegister(instr->object()).is(StoreIC::ReceiverRegister()));
+ ASSERT(ToRegister(instr->value()).is(StoreIC::ValueRegister()));
- __ mov(ecx, instr->name());
+ __ mov(StoreIC::NameRegister(), instr->name());
Handle<Code> ic = StoreIC::initialize_stub(isolate(), instr->strict_mode());
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
@@ -4236,9 +4236,9 @@
void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
ASSERT(ToRegister(instr->context()).is(esi));
- ASSERT(ToRegister(instr->object()).is(edx));
- ASSERT(ToRegister(instr->key()).is(ecx));
- ASSERT(ToRegister(instr->value()).is(eax));
+ ASSERT(ToRegister(instr->object()).is(KeyedStoreIC::ReceiverRegister()));
+ ASSERT(ToRegister(instr->key()).is(KeyedStoreIC::NameRegister()));
+ ASSERT(ToRegister(instr->value()).is(KeyedStoreIC::ValueRegister()));
Handle<Code> ic = instr->strict_mode() == STRICT
? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index a528fe4..c408288 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -2287,9 +2287,10 @@
LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
LOperand* context = UseFixed(instr->context(), esi);
- LOperand* object = UseFixed(instr->object(), edx);
- LOperand* key = UseFixed(instr->key(), ecx);
- LOperand* value = UseFixed(instr->value(), eax);
+ LOperand* object = UseFixed(instr->object(),
+ KeyedStoreIC::ReceiverRegister());
+ LOperand* key = UseFixed(instr->key(), KeyedStoreIC::NameRegister());
+ LOperand* value = UseFixed(instr->value(), KeyedStoreIC::ValueRegister());
ASSERT(instr->object()->representation().IsTagged());
ASSERT(instr->key()->representation().IsTagged());
@@ -2391,8 +2392,8 @@
LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
LOperand* context = UseFixed(instr->context(), esi);
- LOperand* object = UseFixed(instr->object(), edx);
- LOperand* value = UseFixed(instr->value(), eax);
+ LOperand* object = UseFixed(instr->object(), StoreIC::ReceiverRegister());
+ LOperand* value = UseFixed(instr->value(), StoreIC::ValueRegister());
LStoreNamedGeneric* result =
new(zone()) LStoreNamedGeneric(context, object, value);
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
index 4878001..7350319 100644
--- a/src/ia32/stub-cache-ia32.cc
+++ b/src/ia32/stub-cache-ia32.cc
@@ -1300,20 +1300,24 @@
Register StoreStubCompiler::value() {
- return eax;
+ return StoreIC::ValueRegister();
}
Register* StoreStubCompiler::registers() {
// receiver, name, scratch1, scratch2, scratch3.
- static Register registers[] = { edx, ecx, ebx, edi, no_reg };
+ Register receiver = StoreIC::ReceiverRegister();
+ Register name = StoreIC::NameRegister();
+ static Register registers[] = { receiver, name, ebx, edi, no_reg };
return registers;
}
Register* KeyedStoreStubCompiler::registers() {
// receiver, name, scratch1, scratch2, scratch3.
- static Register registers[] = { edx, ecx, ebx, edi, no_reg };
+ Register receiver = KeyedStoreIC::ReceiverRegister();
+ Register name = KeyedStoreIC::NameRegister();
+ static Register registers[] = { receiver, name, ebx, edi, no_reg };
return registers;
}
diff --git a/src/ic.h b/src/ic.h
index 9ce2ae1..47ffd6e 100644
--- a/src/ic.h
+++ b/src/ic.h
@@ -583,6 +583,16 @@
static const ExtraICState kStrictModeState =
1 << StrictModeState::kShift;
+ enum RegisterInfo {
+ kReceiverIndex,
+ kNameIndex,
+ kValueIndex,
+ kRegisterArgumentCount
+ };
+ static const Register ReceiverRegister();
+ static const Register NameRegister();
+ static const Register ValueRegister();
+
StoreIC(FrameDepth depth, Isolate* isolate)
: IC(depth, isolate) {
ASSERT(IsStoreStub());
@@ -691,6 +701,10 @@
return ExtraICStateKeyedAccessStoreMode::decode(extra_state);
}
+ static const Register ReceiverRegister();
+ static const Register NameRegister();
+ static const Register ValueRegister();
+
KeyedStoreIC(FrameDepth depth, Isolate* isolate)
: StoreIC(depth, isolate) {
ASSERT(target()->is_keyed_store_stub());
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index 9192c58..0df3adc 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -559,7 +559,7 @@
private:
// v8::Task overrides.
virtual void Run() V8_OVERRIDE {
- heap_->mark_compact_collector()->SweepInParallel(space_);
+ heap_->mark_compact_collector()->SweepInParallel(space_, 0);
heap_->mark_compact_collector()->pending_sweeper_jobs_semaphore_.Signal();
}
@@ -3544,7 +3544,7 @@
switch (space->identity()) {
case OLD_DATA_SPACE:
- SweepConservatively<SWEEP_SEQUENTIALLY>(space, NULL, p);
+ SweepConservatively<SWEEP_ON_MAIN_THREAD>(space, NULL, p);
break;
case OLD_POINTER_SPACE:
SweepPrecisely<SWEEP_AND_VISIT_LIVE_OBJECTS,
@@ -3939,7 +3939,7 @@
FreeList* free_list,
Address start,
int size) {
- if (mode == MarkCompactCollector::SWEEP_SEQUENTIALLY) {
+ if (mode == MarkCompactCollector::SWEEP_ON_MAIN_THREAD) {
return space->Free(start, size);
} else {
return size - free_list->Free(start, size);
@@ -3948,9 +3948,9 @@
// Force instantiation of templatized SweepConservatively method for
-// SWEEP_SEQUENTIALLY mode.
+// SWEEP_ON_MAIN_THREAD mode.
template intptr_t MarkCompactCollector::
- SweepConservatively<MarkCompactCollector::SWEEP_SEQUENTIALLY>(
+ SweepConservatively<MarkCompactCollector::SWEEP_ON_MAIN_THREAD>(
PagedSpace*, FreeList*, Page*);
@@ -3975,16 +3975,19 @@
ASSERT(!p->IsEvacuationCandidate() && !p->WasSwept());
ASSERT((mode == MarkCompactCollector::SWEEP_IN_PARALLEL &&
free_list != NULL) ||
- (mode == MarkCompactCollector::SWEEP_SEQUENTIALLY &&
+ (mode == MarkCompactCollector::SWEEP_ON_MAIN_THREAD &&
free_list == NULL));
// When parallel sweeping is active, the page will be marked after
// sweeping by the main thread.
- if (mode != MarkCompactCollector::SWEEP_IN_PARALLEL) {
+ if (mode == MarkCompactCollector::SWEEP_IN_PARALLEL) {
+ p->set_parallel_sweeping(MemoryChunk::PARALLEL_SWEEPING_FINALIZE);
+ } else {
p->MarkSweptConservatively();
}
intptr_t freed_bytes = 0;
+ intptr_t max_freed_bytes = 0;
size_t size = 0;
// Skip over all the dead objects at the start of the page and mark them free.
@@ -3999,8 +4002,9 @@
if (it.Done()) {
size = p->area_end() - p->area_start();
- freed_bytes += Free<mode>(space, free_list, p->area_start(),
- static_cast<int>(size));
+ freed_bytes = Free<mode>(space, free_list, p->area_start(),
+ static_cast<int>(size));
+ max_freed_bytes = Max(freed_bytes, max_freed_bytes);
ASSERT_EQ(0, p->LiveBytes());
return freed_bytes;
}
@@ -4010,8 +4014,9 @@
Address free_end = StartOfLiveObject(cell_base, *cell);
// Free the first free space.
size = free_end - p->area_start();
- freed_bytes += Free<mode>(space, free_list, p->area_start(),
- static_cast<int>(size));
+ freed_bytes = Free<mode>(space, free_list, p->area_start(),
+ static_cast<int>(size));
+ max_freed_bytes = Max(freed_bytes, max_freed_bytes);
// The start of the current free area is represented in undigested form by
// the address of the last 32-word section that contained a live object and
@@ -4036,8 +4041,9 @@
// so now we need to find the start of the first live object at the
// end of the free space.
free_end = StartOfLiveObject(cell_base, *cell);
- freed_bytes += Free<mode>(space, free_list, free_start,
- static_cast<int>(free_end - free_start));
+ freed_bytes = Free<mode>(space, free_list, free_start,
+ static_cast<int>(free_end - free_start));
+ max_freed_bytes = Max(freed_bytes, max_freed_bytes);
}
}
// Update our undigested record of where the current free area started.
@@ -4051,31 +4057,41 @@
// Handle the free space at the end of the page.
if (cell_base - free_start > 32 * kPointerSize) {
free_start = DigestFreeStart(free_start, free_start_cell);
- freed_bytes += Free<mode>(space, free_list, free_start,
- static_cast<int>(p->area_end() - free_start));
+ freed_bytes = Free<mode>(space, free_list, free_start,
+ static_cast<int>(p->area_end() - free_start));
+ max_freed_bytes = Max(freed_bytes, max_freed_bytes);
}
p->ResetLiveBytes();
- return freed_bytes;
+ return max_freed_bytes;
}
-void MarkCompactCollector::SweepInParallel(PagedSpace* space) {
+int MarkCompactCollector::SweepInParallel(PagedSpace* space,
+ int required_freed_bytes) {
PageIterator it(space);
FreeList* free_list = space == heap()->old_pointer_space()
? free_list_old_pointer_space_.get()
: free_list_old_data_space_.get();
FreeList private_free_list(space);
+ int max_freed = 0;
+ int max_freed_overall = 0;
while (it.has_next()) {
Page* p = it.next();
if (p->TryParallelSweeping()) {
- SweepConservatively<SWEEP_IN_PARALLEL>(space, &private_free_list, p);
+ max_freed = static_cast<int>(SweepConservatively<SWEEP_IN_PARALLEL>(
+ space, &private_free_list, p));
+ ASSERT(max_freed >= 0);
free_list->Concatenate(&private_free_list);
- p->set_parallel_sweeping(MemoryChunk::PARALLEL_SWEEPING_FINALIZE);
+ if (required_freed_bytes > 0 && max_freed >= required_freed_bytes) {
+ return max_freed;
+ }
+ max_freed_overall = Max(max_freed, max_freed_overall);
}
if (p == space->end_of_unswept_pages()) break;
}
+ return max_freed_overall;
}
@@ -4131,7 +4147,7 @@
PrintF("Sweeping 0x%" V8PRIxPTR " conservatively.\n",
reinterpret_cast<intptr_t>(p));
}
- SweepConservatively<SWEEP_SEQUENTIALLY>(space, NULL, p);
+ SweepConservatively<SWEEP_ON_MAIN_THREAD>(space, NULL, p);
pages_swept++;
break;
}
@@ -4142,27 +4158,16 @@
PrintF("Sweeping 0x%" V8PRIxPTR " conservatively.\n",
reinterpret_cast<intptr_t>(p));
}
- SweepConservatively<SWEEP_SEQUENTIALLY>(space, NULL, p);
+ SweepConservatively<SWEEP_ON_MAIN_THREAD>(space, NULL, p);
pages_swept++;
parallel_sweeping_active = true;
} else {
- if (p->scan_on_scavenge()) {
- SweepPrecisely<SWEEP_ONLY, IGNORE_SKIP_LIST, IGNORE_FREE_SPACE>(
- space, p, NULL);
- pages_swept++;
- if (FLAG_gc_verbose) {
- PrintF("Sweeping 0x%" V8PRIxPTR
- " scan on scavenge page precisely.\n",
- reinterpret_cast<intptr_t>(p));
- }
- } else {
- if (FLAG_gc_verbose) {
- PrintF("Sweeping 0x%" V8PRIxPTR " conservatively in parallel.\n",
- reinterpret_cast<intptr_t>(p));
- }
- p->set_parallel_sweeping(MemoryChunk::PARALLEL_SWEEPING_PENDING);
- space->IncreaseUnsweptFreeBytes(p);
+ if (FLAG_gc_verbose) {
+ PrintF("Sweeping 0x%" V8PRIxPTR " conservatively in parallel.\n",
+ reinterpret_cast<intptr_t>(p));
}
+ p->set_parallel_sweeping(MemoryChunk::PARALLEL_SWEEPING_PENDING);
+ space->IncreaseUnsweptFreeBytes(p);
}
space->set_end_of_unswept_pages(p);
break;
diff --git a/src/mark-compact.h b/src/mark-compact.h
index 6b7c09b..bcbc056 100644
--- a/src/mark-compact.h
+++ b/src/mark-compact.h
@@ -577,7 +577,7 @@
};
enum SweepingParallelism {
- SWEEP_SEQUENTIALLY,
+ SWEEP_ON_MAIN_THREAD,
SWEEP_IN_PARALLEL
};
@@ -590,7 +590,7 @@
#endif
// Sweep a single page from the given space conservatively.
- // Return a number of reclaimed bytes.
+ // Returns the size of the biggest continuous freed memory chunk in bytes.
template<SweepingParallelism type>
static intptr_t SweepConservatively(PagedSpace* space,
FreeList* free_list,
@@ -659,8 +659,11 @@
MarkingParity marking_parity() { return marking_parity_; }
- // Concurrent and parallel sweeping support.
- void SweepInParallel(PagedSpace* space);
+ // Concurrent and parallel sweeping support. If required_freed_bytes was set
+ // to a value larger than 0, then sweeping returns after a block of at least
+ // required_freed_bytes was freed. If required_freed_bytes was set to zero
+ // then the whole given space is swept.
+ int SweepInParallel(PagedSpace* space, int required_freed_bytes);
void WaitUntilSweepingCompleted();
diff --git a/src/messages.js b/src/messages.js
index e3d941b..12cc197 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -127,7 +127,6 @@
illegal_break: ["Illegal break statement"],
illegal_continue: ["Illegal continue statement"],
illegal_return: ["Illegal return statement"],
- illegal_let: ["Illegal let declaration outside extended mode"],
error_loading_debugger: ["Error loading debugger"],
no_input_to_regexp: ["No input to ", "%0"],
invalid_json: ["String '", "%0", "' is not valid JSON"],
@@ -137,8 +136,6 @@
array_indexof_not_defined: ["Array.getIndexOf: Argument undefined"],
object_not_extensible: ["Can't add property ", "%0", ", object is not extensible"],
illegal_access: ["Illegal access"],
- invalid_cached_data_function: ["Invalid cached data for function ", "%0"],
- invalid_cached_data: ["Invalid cached data"],
strict_mode_with: ["Strict mode code may not include a with statement"],
strict_eval_arguments: ["Unexpected eval or arguments in strict mode"],
too_many_arguments: ["Too many arguments in function call (only 65535 allowed)"],
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index a2e1a27..130664d 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -87,15 +87,6 @@
}
-void KeyedStoreFastElementStub::InitializeInterfaceDescriptor(
- CodeStubInterfaceDescriptor* descriptor) {
- Register registers[] = { a2, a1, a0 };
- descriptor->Initialize(
- ARRAY_SIZE(registers), registers,
- FUNCTION_ADDR(KeyedStoreIC_MissFromStubFailure));
-}
-
-
void TransitionElementsKindStub::InitializeInterfaceDescriptor(
CodeStubInterfaceDescriptor* descriptor) {
Register registers[] = { a0, a1 };
@@ -230,14 +221,6 @@
}
-void StoreGlobalStub::InitializeInterfaceDescriptor(
- CodeStubInterfaceDescriptor* descriptor) {
- Register registers[] = { a1, a2, a0 };
- descriptor->Initialize(ARRAY_SIZE(registers), registers,
- FUNCTION_ADDR(StoreIC_MissFromStubFailure));
-}
-
-
void ElementsTransitionAndStoreStub::InitializeInterfaceDescriptor(
CodeStubInterfaceDescriptor* descriptor) {
Register registers[] = { a0, a3, a1, a2 };
diff --git a/src/mips/debug-mips.cc b/src/mips/debug-mips.cc
index 424a87a..ef28f33 100644
--- a/src/mips/debug-mips.cc
+++ b/src/mips/debug-mips.cc
@@ -193,31 +193,27 @@
void DebugCodegen::GenerateStoreICDebugBreak(MacroAssembler* masm) {
// Calling convention for IC store (from ic-mips.cc).
- // ----------- S t a t e -------------
- // -- a0 : value
- // -- a1 : receiver
- // -- a2 : name
- // -- ra : return address
- // -----------------------------------
- // Registers a0, a1, and a2 contain objects that need to be pushed on the
- // expression stack of the fake JS frame.
- Generate_DebugBreakCallHelper(masm, a0.bit() | a1.bit() | a2.bit(), 0);
+ Register receiver = StoreIC::ReceiverRegister();
+ Register name = StoreIC::NameRegister();
+ Register value = StoreIC::ValueRegister();
+ Generate_DebugBreakCallHelper(
+ masm, receiver.bit() | name.bit() | value.bit(), 0);
}
void DebugCodegen::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
- // Calling convention for keyed IC load (from ic-arm.cc).
+ // Calling convention for keyed IC load (from ic-mips.cc).
GenerateLoadICDebugBreak(masm);
}
void DebugCodegen::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
- // ---------- S t a t e --------------
- // -- a0 : value
- // -- a1 : key
- // -- a2 : receiver
- // -- ra : return address
- Generate_DebugBreakCallHelper(masm, a0.bit() | a1.bit() | a2.bit(), 0);
+ // Calling convention for IC keyed store call (from ic-mips.cc).
+ Register receiver = KeyedStoreIC::ReceiverRegister();
+ Register name = KeyedStoreIC::NameRegister();
+ Register value = KeyedStoreIC::ValueRegister();
+ Generate_DebugBreakCallHelper(
+ masm, receiver.bit() | name.bit() | value.bit(), 0);
}
diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc
index 11a67b7..1704b2f 100644
--- a/src/mips/full-codegen-mips.cc
+++ b/src/mips/full-codegen-mips.cc
@@ -1689,9 +1689,10 @@
if (key->value()->IsInternalizedString()) {
if (property->emit_store()) {
VisitForAccumulatorValue(value);
- __ mov(a0, result_register());
- __ li(a2, Operand(key->value()));
- __ lw(a1, MemOperand(sp));
+ __ mov(StoreIC::ValueRegister(), result_register());
+ ASSERT(StoreIC::ValueRegister().is(a0));
+ __ li(StoreIC::NameRegister(), Operand(key->value()));
+ __ lw(StoreIC::ReceiverRegister(), MemOperand(sp));
CallStoreIC(key->LiteralFeedbackId());
PrepareForBailoutForId(key->id(), NO_REGISTERS);
} else {
@@ -2414,9 +2415,10 @@
case NAMED_PROPERTY: {
__ push(result_register()); // Preserve value.
VisitForAccumulatorValue(prop->obj());
- __ mov(a1, result_register());
- __ pop(a0); // Restore value.
- __ li(a2, Operand(prop->key()->AsLiteral()->value()));
+ __ mov(StoreIC::ReceiverRegister(), result_register());
+ __ pop(StoreIC::ValueRegister()); // Restore value.
+ __ li(StoreIC::NameRegister(),
+ Operand(prop->key()->AsLiteral()->value()));
CallStoreIC();
break;
}
@@ -2424,8 +2426,8 @@
__ push(result_register()); // Preserve value.
VisitForStackValue(prop->obj());
VisitForAccumulatorValue(prop->key());
- __ mov(a1, result_register());
- __ Pop(a0, a2); // a0 = restored value.
+ __ mov(KeyedStoreIC::NameRegister(), result_register());
+ __ Pop(KeyedStoreIC::ValueRegister(), KeyedStoreIC::ReceiverRegister());
Handle<Code> ic = strict_mode() == SLOPPY
? isolate()->builtins()->KeyedStoreIC_Initialize()
: isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
@@ -2462,9 +2464,9 @@
void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op) {
if (var->IsUnallocated()) {
// Global var, const, or let.
- __ mov(a0, result_register());
- __ li(a2, Operand(var->name()));
- __ lw(a1, GlobalObjectOperand());
+ __ mov(StoreIC::ValueRegister(), result_register());
+ __ li(StoreIC::NameRegister(), Operand(var->name()));
+ __ lw(StoreIC::ReceiverRegister(), GlobalObjectOperand());
CallStoreIC();
} else if (op == Token::INIT_CONST_LEGACY) {
@@ -2533,10 +2535,9 @@
// Record source code position before IC call.
SetSourcePosition(expr->position());
- __ mov(a0, result_register()); // Load the value.
- __ li(a2, Operand(prop->key()->AsLiteral()->value()));
- __ pop(a1);
-
+ __ mov(StoreIC::ValueRegister(), result_register());
+ __ li(StoreIC::NameRegister(), Operand(prop->key()->AsLiteral()->value()));
+ __ pop(StoreIC::ReceiverRegister());
CallStoreIC(expr->AssignmentFeedbackId());
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
@@ -2554,8 +2555,9 @@
// - a0 is the value,
// - a1 is the key,
// - a2 is the receiver.
- __ mov(a0, result_register());
- __ Pop(a2, a1); // a1 = key.
+ __ mov(KeyedStoreIC::ValueRegister(), result_register());
+ __ Pop(KeyedStoreIC::ReceiverRegister(), KeyedStoreIC::NameRegister());
+ ASSERT(KeyedStoreIC::ValueRegister().is(a0));
Handle<Code> ic = strict_mode() == SLOPPY
? isolate()->builtins()->KeyedStoreIC_Initialize()
@@ -4387,9 +4389,10 @@
}
break;
case NAMED_PROPERTY: {
- __ mov(a0, result_register()); // Value.
- __ li(a2, Operand(prop->key()->AsLiteral()->value())); // Name.
- __ pop(a1); // Receiver.
+ __ mov(StoreIC::ValueRegister(), result_register());
+ __ li(StoreIC::NameRegister(),
+ Operand(prop->key()->AsLiteral()->value()));
+ __ pop(StoreIC::ReceiverRegister());
CallStoreIC(expr->CountStoreFeedbackId());
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
if (expr->is_postfix()) {
@@ -4402,8 +4405,8 @@
break;
}
case KEYED_PROPERTY: {
- __ mov(a0, result_register()); // Value.
- __ Pop(a2, a1); // a1 = key, a2 = receiver.
+ __ mov(KeyedStoreIC::ValueRegister(), result_register());
+ __ Pop(KeyedStoreIC::ReceiverRegister(), KeyedStoreIC::NameRegister());
Handle<Code> ic = strict_mode() == SLOPPY
? isolate()->builtins()->KeyedStoreIC_Initialize()
: isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
diff --git a/src/mips/ic-mips.cc b/src/mips/ic-mips.cc
index 2ca6b4d..f38e736 100644
--- a/src/mips/ic-mips.cc
+++ b/src/mips/ic-mips.cc
@@ -507,30 +507,31 @@
void KeyedStoreIC::GenerateSloppyArguments(MacroAssembler* masm) {
- // ---------- S t a t e --------------
- // -- a0 : value
- // -- a1 : key
- // -- a2 : receiver
- // -- lr : return address
- // -----------------------------------
+ Register receiver = ReceiverRegister();
+ Register key = NameRegister();
+ Register value = ValueRegister();
+ ASSERT(receiver.is(a2));
+ ASSERT(key.is(a1));
+ ASSERT(value.is(a0));
+
Label slow, notin;
// Store address is returned in register (of MemOperand) mapped_location.
- MemOperand mapped_location =
- GenerateMappedArgumentsLookup(masm, a2, a1, a3, t0, t1, ¬in, &slow);
- __ sw(a0, mapped_location);
- __ mov(t5, a0);
+ MemOperand mapped_location = GenerateMappedArgumentsLookup(
+ masm, receiver, key, a3, t0, t1, ¬in, &slow);
+ __ sw(value, mapped_location);
+ __ mov(t5, value);
ASSERT_EQ(mapped_location.offset(), 0);
__ RecordWrite(a3, mapped_location.rm(), t5,
kRAHasNotBeenSaved, kDontSaveFPRegs);
__ Ret(USE_DELAY_SLOT);
- __ mov(v0, a0); // (In delay slot) return the value stored in v0.
+ __ mov(v0, value); // (In delay slot) return the value stored in v0.
__ bind(¬in);
// The unmapped lookup expects that the parameter map is in a3.
// Store address is returned in register (of MemOperand) unmapped_location.
MemOperand unmapped_location =
- GenerateUnmappedArgumentsLookup(masm, a1, a3, t0, &slow);
- __ sw(a0, unmapped_location);
- __ mov(t5, a0);
+ GenerateUnmappedArgumentsLookup(masm, key, a3, t0, &slow);
+ __ sw(value, unmapped_location);
+ __ mov(t5, value);
ASSERT_EQ(unmapped_location.offset(), 0);
__ RecordWrite(a3, unmapped_location.rm(), t5,
kRAHasNotBeenSaved, kDontSaveFPRegs);
@@ -562,6 +563,16 @@
const Register LoadIC::NameRegister() { return a2; }
+const Register StoreIC::ReceiverRegister() { return a1; }
+const Register StoreIC::NameRegister() { return a2; }
+const Register StoreIC::ValueRegister() { return a0; }
+
+
+const Register KeyedStoreIC::ReceiverRegister() { return a2; }
+const Register KeyedStoreIC::NameRegister() { return a1; }
+const Register KeyedStoreIC::ValueRegister() { return a0; }
+
+
void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
// The return address is in ra.
@@ -772,15 +783,8 @@
void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
StrictMode strict_mode) {
- // ---------- S t a t e --------------
- // -- a0 : value
- // -- a1 : key
- // -- a2 : receiver
- // -- ra : return address
- // -----------------------------------
-
// Push receiver, key and value for runtime call.
- __ Push(a2, a1, a0);
+ __ Push(ReceiverRegister(), NameRegister(), ValueRegister());
__ li(a0, Operand(Smi::FromInt(strict_mode))); // Strict mode.
__ Push(a0);
@@ -974,9 +978,12 @@
Label array, extra, check_if_double_array;
// Register usage.
- Register value = a0;
- Register key = a1;
- Register receiver = a2;
+ Register value = ValueRegister();
+ Register key = NameRegister();
+ Register receiver = ReceiverRegister();
+ ASSERT(receiver.is(a2));
+ ASSERT(key.is(a1));
+ ASSERT(value.is(a0));
Register receiver_map = a3;
Register elements_map = t2;
Register elements = t3; // Elements array of the receiver.
@@ -1095,15 +1102,8 @@
void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
- // ---------- S t a t e --------------
- // -- a0 : value
- // -- a1 : key
- // -- a2 : receiver
- // -- ra : return address
- // -----------------------------------
-
// Push receiver, key and value for runtime call.
- __ Push(a2, a1, a0);
+ __ Push(ReceiverRegister(), NameRegister(), ValueRegister());
ExternalReference ref =
ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
@@ -1112,15 +1112,8 @@
void StoreIC::GenerateSlow(MacroAssembler* masm) {
- // ---------- S t a t e --------------
- // -- a0 : value
- // -- a2 : key
- // -- a1 : receiver
- // -- ra : return address
- // -----------------------------------
-
// Push receiver, key and value for runtime call.
- __ Push(a1, a2, a0);
+ __ Push(ReceiverRegister(), NameRegister(), ValueRegister());
// The slow case calls into the runtime to complete the store without causing
// an IC miss that would otherwise cause a transition to the generic stub.
@@ -1131,16 +1124,9 @@
void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
- // ---------- S t a t e --------------
- // -- a0 : value
- // -- a1 : key
- // -- a2 : receiver
- // -- ra : return address
- // -----------------------------------
-
// Push receiver, key and value for runtime call.
// We can't use MultiPush as the order of the registers is important.
- __ Push(a2, a1, a0);
+ __ Push(ReceiverRegister(), NameRegister(), ValueRegister());
// The slow case calls into the runtime to complete the store without causing
// an IC miss that would otherwise cause a transition to the generic stub.
@@ -1152,17 +1138,16 @@
void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- a0 : value
- // -- a1 : receiver
- // -- a2 : name
- // -- ra : return address
- // -----------------------------------
+ Register receiver = ReceiverRegister();
+ Register name = NameRegister();
+ ASSERT(receiver.is(a1));
+ ASSERT(name.is(a2));
+ ASSERT(ValueRegister().is(a0));
// Get the receiver from the stack and probe the stub cache.
Code::Flags flags = Code::ComputeHandlerFlags(Code::STORE_IC);
masm->isolate()->stub_cache()->GenerateProbe(
- masm, flags, a1, a2, a3, t0, t1, t2);
+ masm, flags, receiver, name, a3, t0, t1, t2);
// Cache miss: Jump to runtime.
GenerateMiss(masm);
@@ -1170,14 +1155,7 @@
void StoreIC::GenerateMiss(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- a0 : value
- // -- a1 : receiver
- // -- a2 : name
- // -- ra : return address
- // -----------------------------------
-
- __ Push(a1, a2, a0);
+ __ Push(ReceiverRegister(), NameRegister(), ValueRegister());
// Perform tail call to the entry.
ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_Miss),
masm->isolate());
@@ -1186,17 +1164,17 @@
void StoreIC::GenerateNormal(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- a0 : value
- // -- a1 : receiver
- // -- a2 : name
- // -- ra : return address
- // -----------------------------------
Label miss;
+ Register receiver = ReceiverRegister();
+ Register name = NameRegister();
+ Register value = ValueRegister();
+ ASSERT(receiver.is(a1));
+ ASSERT(name.is(a2));
+ ASSERT(value.is(a0));
- GenerateNameDictionaryReceiverCheck(masm, a1, a3, t0, t1, &miss);
+ GenerateNameDictionaryReceiverCheck(masm, receiver, a3, t0, t1, &miss);
- GenerateDictionaryStore(masm, &miss, a3, a2, a0, t0, t1);
+ GenerateDictionaryStore(masm, &miss, a3, name, value, t0, t1);
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->store_normal_hit(), 1, t0, t1);
__ Ret();
@@ -1209,14 +1187,7 @@
void StoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
StrictMode strict_mode) {
- // ----------- S t a t e -------------
- // -- a0 : value
- // -- a1 : receiver
- // -- a2 : name
- // -- ra : return address
- // -----------------------------------
-
- __ Push(a1, a2, a0);
+ __ Push(ReceiverRegister(), NameRegister(), ValueRegister());
__ li(a0, Operand(Smi::FromInt(strict_mode)));
__ Push(a0);
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc
index 247572a..95f6847 100644
--- a/src/mips/lithium-codegen-mips.cc
+++ b/src/mips/lithium-codegen-mips.cc
@@ -4131,11 +4131,10 @@
void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
ASSERT(ToRegister(instr->context()).is(cp));
- ASSERT(ToRegister(instr->object()).is(a1));
- ASSERT(ToRegister(instr->value()).is(a0));
+ ASSERT(ToRegister(instr->object()).is(StoreIC::ReceiverRegister()));
+ ASSERT(ToRegister(instr->value()).is(StoreIC::ValueRegister()));
- // Name is always in a2.
- __ li(a2, Operand(instr->name()));
+ __ li(StoreIC::NameRegister(), Operand(instr->name()));
Handle<Code> ic = StoreIC::initialize_stub(isolate(), instr->strict_mode());
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
@@ -4363,9 +4362,9 @@
void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
ASSERT(ToRegister(instr->context()).is(cp));
- ASSERT(ToRegister(instr->object()).is(a2));
- ASSERT(ToRegister(instr->key()).is(a1));
- ASSERT(ToRegister(instr->value()).is(a0));
+ ASSERT(ToRegister(instr->object()).is(KeyedStoreIC::ReceiverRegister()));
+ ASSERT(ToRegister(instr->key()).is(KeyedStoreIC::NameRegister()));
+ ASSERT(ToRegister(instr->value()).is(KeyedStoreIC::ValueRegister()));
Handle<Code> ic = (instr->strict_mode() == STRICT)
? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc
index f264f62..0e0fea3 100644
--- a/src/mips/lithium-mips.cc
+++ b/src/mips/lithium-mips.cc
@@ -2201,9 +2201,9 @@
LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
LOperand* context = UseFixed(instr->context(), cp);
- LOperand* obj = UseFixed(instr->object(), a2);
- LOperand* key = UseFixed(instr->key(), a1);
- LOperand* val = UseFixed(instr->value(), a0);
+ LOperand* obj = UseFixed(instr->object(), KeyedStoreIC::ReceiverRegister());
+ LOperand* key = UseFixed(instr->key(), KeyedStoreIC::NameRegister());
+ LOperand* val = UseFixed(instr->value(), KeyedStoreIC::ValueRegister());
ASSERT(instr->object()->representation().IsTagged());
ASSERT(instr->key()->representation().IsTagged());
@@ -2277,8 +2277,8 @@
LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
LOperand* context = UseFixed(instr->context(), cp);
- LOperand* obj = UseFixed(instr->object(), a1);
- LOperand* val = UseFixed(instr->value(), a0);
+ LOperand* obj = UseFixed(instr->object(), StoreIC::ReceiverRegister());
+ LOperand* val = UseFixed(instr->value(), StoreIC::ValueRegister());
LInstruction* result = new(zone()) LStoreNamedGeneric(context, obj, val);
return MarkAsCall(result, instr);
diff --git a/src/mips/stub-cache-mips.cc b/src/mips/stub-cache-mips.cc
index 3611a28..d08d597 100644
--- a/src/mips/stub-cache-mips.cc
+++ b/src/mips/stub-cache-mips.cc
@@ -1270,20 +1270,24 @@
Register StoreStubCompiler::value() {
- return a0;
+ return StoreIC::ValueRegister();
}
Register* StoreStubCompiler::registers() {
// receiver, name, scratch1, scratch2, scratch3.
- static Register registers[] = { a1, a2, a3, t0, t1 };
+ Register receiver = StoreIC::ReceiverRegister();
+ Register name = StoreIC::NameRegister();
+ static Register registers[] = { receiver, name, a3, t0, t1 };
return registers;
}
Register* KeyedStoreStubCompiler::registers() {
// receiver, name, scratch1, scratch2, scratch3.
- static Register registers[] = { a2, a1, a3, t0, t1 };
+ Register receiver = KeyedStoreIC::ReceiverRegister();
+ Register name = KeyedStoreIC::NameRegister();
+ static Register registers[] = { receiver, name, a3, t0, t1 };
return registers;
}
diff --git a/src/mips64/code-stubs-mips64.cc b/src/mips64/code-stubs-mips64.cc
index db42d4b..823ce07 100644
--- a/src/mips64/code-stubs-mips64.cc
+++ b/src/mips64/code-stubs-mips64.cc
@@ -87,15 +87,6 @@
}
-void KeyedStoreFastElementStub::InitializeInterfaceDescriptor(
- CodeStubInterfaceDescriptor* descriptor) {
- Register registers[] = { a2, a1, a0 };
- descriptor->Initialize(
- ARRAY_SIZE(registers), registers,
- FUNCTION_ADDR(KeyedStoreIC_MissFromStubFailure));
-}
-
-
void TransitionElementsKindStub::InitializeInterfaceDescriptor(
CodeStubInterfaceDescriptor* descriptor) {
Register registers[] = { a0, a1 };
@@ -230,14 +221,6 @@
}
-void StoreGlobalStub::InitializeInterfaceDescriptor(
- CodeStubInterfaceDescriptor* descriptor) {
- Register registers[] = { a1, a2, a0 };
- descriptor->Initialize(ARRAY_SIZE(registers), registers,
- FUNCTION_ADDR(StoreIC_MissFromStubFailure));
-}
-
-
void ElementsTransitionAndStoreStub::InitializeInterfaceDescriptor(
CodeStubInterfaceDescriptor* descriptor) {
Register registers[] = { a0, a3, a1, a2 };
diff --git a/src/mips64/debug-mips64.cc b/src/mips64/debug-mips64.cc
index 6b805c7..cc8895d 100644
--- a/src/mips64/debug-mips64.cc
+++ b/src/mips64/debug-mips64.cc
@@ -195,32 +195,27 @@
void DebugCodegen::GenerateStoreICDebugBreak(MacroAssembler* masm) {
- // Calling convention for IC store (from ic-mips.cc).
- // ----------- S t a t e -------------
- // -- a0 : value
- // -- a1 : receiver
- // -- a2 : name
- // -- ra : return address
- // -----------------------------------
- // Registers a0, a1, and a2 contain objects that need to be pushed on the
- // expression stack of the fake JS frame.
- Generate_DebugBreakCallHelper(masm, a0.bit() | a1.bit() | a2.bit(), 0);
+ Register receiver = StoreIC::ReceiverRegister();
+ Register name = StoreIC::NameRegister();
+ Register value = StoreIC::ValueRegister();
+ Generate_DebugBreakCallHelper(
+ masm, receiver.bit() | name.bit() | value.bit(), 0);
}
void DebugCodegen::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
- // Calling convention for keyed IC load (from ic-arm.cc).
+ // Calling convention for keyed IC load (from ic-mips64.cc).
GenerateLoadICDebugBreak(masm);
}
void DebugCodegen::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
- // ---------- S t a t e --------------
- // -- a0 : value
- // -- a1 : key
- // -- a2 : receiver
- // -- ra : return address
- Generate_DebugBreakCallHelper(masm, a0.bit() | a1.bit() | a2.bit(), 0);
+ // Calling convention for IC keyed store call (from ic-mips64.cc).
+ Register receiver = KeyedStoreIC::ReceiverRegister();
+ Register name = KeyedStoreIC::NameRegister();
+ Register value = KeyedStoreIC::ValueRegister();
+ Generate_DebugBreakCallHelper(
+ masm, receiver.bit() | name.bit() | value.bit(), 0);
}
diff --git a/src/mips64/full-codegen-mips64.cc b/src/mips64/full-codegen-mips64.cc
index 5f036b6..15192cb 100644
--- a/src/mips64/full-codegen-mips64.cc
+++ b/src/mips64/full-codegen-mips64.cc
@@ -1686,9 +1686,10 @@
if (key->value()->IsInternalizedString()) {
if (property->emit_store()) {
VisitForAccumulatorValue(value);
- __ mov(a0, result_register());
- __ li(a2, Operand(key->value()));
- __ ld(a1, MemOperand(sp));
+ __ mov(StoreIC::ValueRegister(), result_register());
+ ASSERT(StoreIC::ValueRegister().is(a0));
+ __ li(StoreIC::NameRegister(), Operand(key->value()));
+ __ ld(StoreIC::ReceiverRegister(), MemOperand(sp));
CallStoreIC(key->LiteralFeedbackId());
PrepareForBailoutForId(key->id(), NO_REGISTERS);
} else {
@@ -2409,9 +2410,10 @@
case NAMED_PROPERTY: {
__ push(result_register()); // Preserve value.
VisitForAccumulatorValue(prop->obj());
- __ mov(a1, result_register());
- __ pop(a0); // Restore value.
- __ li(a2, Operand(prop->key()->AsLiteral()->value()));
+ __ mov(StoreIC::ReceiverRegister(), result_register());
+ __ pop(StoreIC::ValueRegister()); // Restore value.
+ __ li(StoreIC::NameRegister(),
+ Operand(prop->key()->AsLiteral()->value()));
CallStoreIC();
break;
}
@@ -2419,8 +2421,8 @@
__ push(result_register()); // Preserve value.
VisitForStackValue(prop->obj());
VisitForAccumulatorValue(prop->key());
- __ mov(a1, result_register());
- __ Pop(a0, a2); // a0 = restored value.
+ __ Move(KeyedStoreIC::NameRegister(), result_register());
+ __ Pop(KeyedStoreIC::ValueRegister(), KeyedStoreIC::ReceiverRegister());
Handle<Code> ic = strict_mode() == SLOPPY
? isolate()->builtins()->KeyedStoreIC_Initialize()
: isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
@@ -2457,9 +2459,9 @@
void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op) {
if (var->IsUnallocated()) {
// Global var, const, or let.
- __ mov(a0, result_register());
- __ li(a2, Operand(var->name()));
- __ ld(a1, GlobalObjectOperand());
+ __ mov(StoreIC::ValueRegister(), result_register());
+ __ li(StoreIC::NameRegister(), Operand(var->name()));
+ __ ld(StoreIC::ReceiverRegister(), GlobalObjectOperand());
CallStoreIC();
} else if (op == Token::INIT_CONST_LEGACY) {
// Const initializers need a write barrier.
@@ -2527,10 +2529,9 @@
// Record source code position before IC call.
SetSourcePosition(expr->position());
- __ mov(a0, result_register()); // Load the value.
- __ li(a2, Operand(prop->key()->AsLiteral()->value()));
- __ pop(a1);
-
+ __ mov(StoreIC::ValueRegister(), result_register());
+ __ li(StoreIC::NameRegister(), Operand(prop->key()->AsLiteral()->value()));
+ __ pop(StoreIC::ReceiverRegister());
CallStoreIC(expr->AssignmentFeedbackId());
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
@@ -2548,8 +2549,9 @@
// - a0 is the value,
// - a1 is the key,
// - a2 is the receiver.
- __ mov(a0, result_register());
- __ Pop(a2, a1); // a1 = key.
+ __ mov(KeyedStoreIC::ValueRegister(), result_register());
+ __ Pop(KeyedStoreIC::ReceiverRegister(), KeyedStoreIC::NameRegister());
+ ASSERT(KeyedStoreIC::ValueRegister().is(a0));
Handle<Code> ic = strict_mode() == SLOPPY
? isolate()->builtins()->KeyedStoreIC_Initialize()
@@ -4380,9 +4382,10 @@
}
break;
case NAMED_PROPERTY: {
- __ mov(a0, result_register()); // Value.
- __ li(a2, Operand(prop->key()->AsLiteral()->value())); // Name.
- __ pop(a1); // Receiver.
+ __ mov(StoreIC::ValueRegister(), result_register());
+ __ li(StoreIC::NameRegister(),
+ Operand(prop->key()->AsLiteral()->value()));
+ __ pop(StoreIC::ReceiverRegister());
CallStoreIC(expr->CountStoreFeedbackId());
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
if (expr->is_postfix()) {
@@ -4395,8 +4398,8 @@
break;
}
case KEYED_PROPERTY: {
- __ mov(a0, result_register()); // Value.
- __ Pop(a2, a1); // a1 = key, a2 = receiver.
+ __ mov(KeyedStoreIC::ValueRegister(), result_register());
+ __ Pop(KeyedStoreIC::ReceiverRegister(), KeyedStoreIC::NameRegister());
Handle<Code> ic = strict_mode() == SLOPPY
? isolate()->builtins()->KeyedStoreIC_Initialize()
: isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
diff --git a/src/mips64/ic-mips64.cc b/src/mips64/ic-mips64.cc
index d8f7173..bafd189 100644
--- a/src/mips64/ic-mips64.cc
+++ b/src/mips64/ic-mips64.cc
@@ -507,30 +507,31 @@
void KeyedStoreIC::GenerateSloppyArguments(MacroAssembler* masm) {
- // ---------- S t a t e --------------
- // -- a0 : value
- // -- a1 : key
- // -- a2 : receiver
- // -- lr : return address
- // -----------------------------------
+ Register receiver = ReceiverRegister();
+ Register key = NameRegister();
+ Register value = ValueRegister();
+ ASSERT(receiver.is(a2));
+ ASSERT(key.is(a1));
+ ASSERT(value.is(a0));
+
Label slow, notin;
// Store address is returned in register (of MemOperand) mapped_location.
- MemOperand mapped_location =
- GenerateMappedArgumentsLookup(masm, a2, a1, a3, a4, a5, ¬in, &slow);
- __ sd(a0, mapped_location);
- __ mov(t1, a0);
+ MemOperand mapped_location = GenerateMappedArgumentsLookup(
+ masm, receiver, key, a3, a4, a5, ¬in, &slow);
+ __ sd(value, mapped_location);
+ __ mov(t1, value);
ASSERT_EQ(mapped_location.offset(), 0);
__ RecordWrite(a3, mapped_location.rm(), t1,
kRAHasNotBeenSaved, kDontSaveFPRegs);
__ Ret(USE_DELAY_SLOT);
- __ mov(v0, a0); // (In delay slot) return the value stored in v0.
+ __ mov(v0, value); // (In delay slot) return the value stored in v0.
__ bind(¬in);
// The unmapped lookup expects that the parameter map is in a3.
// Store address is returned in register (of MemOperand) unmapped_location.
MemOperand unmapped_location =
- GenerateUnmappedArgumentsLookup(masm, a1, a3, a4, &slow);
- __ sd(a0, unmapped_location);
- __ mov(t1, a0);
+ GenerateUnmappedArgumentsLookup(masm, key, a3, a4, &slow);
+ __ sd(value, unmapped_location);
+ __ mov(t1, value);
ASSERT_EQ(unmapped_location.offset(), 0);
__ RecordWrite(a3, unmapped_location.rm(), t1,
kRAHasNotBeenSaved, kDontSaveFPRegs);
@@ -562,6 +563,16 @@
const Register LoadIC::NameRegister() { return a2; }
+const Register StoreIC::ReceiverRegister() { return a1; }
+const Register StoreIC::NameRegister() { return a2; }
+const Register StoreIC::ValueRegister() { return a0; }
+
+
+const Register KeyedStoreIC::ReceiverRegister() { return a2; }
+const Register KeyedStoreIC::NameRegister() { return a1; }
+const Register KeyedStoreIC::ValueRegister() { return a0; }
+
+
void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
// The return address is in ra.
@@ -779,15 +790,9 @@
void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
StrictMode strict_mode) {
- // ---------- S t a t e --------------
- // -- a0 : value
- // -- a1 : key
- // -- a2 : receiver
- // -- ra : return address
- // -----------------------------------
-
// Push receiver, key and value for runtime call.
- __ Push(a2, a1, a0);
+ __ Push(ReceiverRegister(), NameRegister(), ValueRegister());
+
__ li(a0, Operand(Smi::FromInt(strict_mode))); // Strict mode.
__ Push(a0);
@@ -984,9 +989,12 @@
Label array, extra, check_if_double_array;
// Register usage.
- Register value = a0;
- Register key = a1;
- Register receiver = a2;
+ Register value = ValueRegister();
+ Register key = NameRegister();
+ Register receiver = ReceiverRegister();
+ ASSERT(receiver.is(a2));
+ ASSERT(key.is(a1));
+ ASSERT(value.is(a0));
Register receiver_map = a3;
Register elements_map = a6;
Register elements = a7; // Elements array of the receiver.
@@ -1105,15 +1113,8 @@
void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
- // ---------- S t a t e --------------
- // -- a0 : value
- // -- a1 : key
- // -- a2 : receiver
- // -- ra : return address
- // -----------------------------------
-
// Push receiver, key and value for runtime call.
- __ Push(a2, a1, a0);
+ __ Push(ReceiverRegister(), NameRegister(), ValueRegister());
ExternalReference ref =
ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
@@ -1122,15 +1123,8 @@
void StoreIC::GenerateSlow(MacroAssembler* masm) {
- // ---------- S t a t e --------------
- // -- a0 : value
- // -- a2 : key
- // -- a1 : receiver
- // -- ra : return address
- // -----------------------------------
-
// Push receiver, key and value for runtime call.
- __ Push(a1, a2, a0);
+ __ Push(ReceiverRegister(), NameRegister(), ValueRegister());
// The slow case calls into the runtime to complete the store without causing
// an IC miss that would otherwise cause a transition to the generic stub.
@@ -1141,16 +1135,9 @@
void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
- // ---------- S t a t e --------------
- // -- a0 : value
- // -- a1 : key
- // -- a2 : receiver
- // -- ra : return address
- // -----------------------------------
-
// Push receiver, key and value for runtime call.
// We can't use MultiPush as the order of the registers is important.
- __ Push(a2, a1, a0);
+ __ Push(ReceiverRegister(), NameRegister(), ValueRegister());
// The slow case calls into the runtime to complete the store without causing
// an IC miss that would otherwise cause a transition to the generic stub.
ExternalReference ref =
@@ -1161,17 +1148,16 @@
void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- a0 : value
- // -- a1 : receiver
- // -- a2 : name
- // -- ra : return address
- // -----------------------------------
+ Register receiver = ReceiverRegister();
+ Register name = NameRegister();
+ ASSERT(receiver.is(a1));
+ ASSERT(name.is(a2));
+ ASSERT(ValueRegister().is(a0));
// Get the receiver from the stack and probe the stub cache.
Code::Flags flags = Code::ComputeHandlerFlags(Code::STORE_IC);
masm->isolate()->stub_cache()->GenerateProbe(
- masm, flags, a1, a2, a3, a4, a5, a6);
+ masm, flags, receiver, name, a3, a4, a5, a6);
// Cache miss: Jump to runtime.
GenerateMiss(masm);
@@ -1179,14 +1165,7 @@
void StoreIC::GenerateMiss(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- a0 : value
- // -- a1 : receiver
- // -- a2 : name
- // -- ra : return address
- // -----------------------------------
-
- __ Push(a1, a2, a0);
+ __ Push(ReceiverRegister(), NameRegister(), ValueRegister());
// Perform tail call to the entry.
ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_Miss),
masm->isolate());
@@ -1195,17 +1174,17 @@
void StoreIC::GenerateNormal(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- a0 : value
- // -- a1 : receiver
- // -- a2 : name
- // -- ra : return address
- // -----------------------------------
Label miss;
+ Register receiver = ReceiverRegister();
+ Register name = NameRegister();
+ Register value = ValueRegister();
+ ASSERT(receiver.is(a1));
+ ASSERT(name.is(a2));
+ ASSERT(value.is(a0));
- GenerateNameDictionaryReceiverCheck(masm, a1, a3, a4, a5, &miss);
+ GenerateNameDictionaryReceiverCheck(masm, receiver, a3, a4, a5, &miss);
- GenerateDictionaryStore(masm, &miss, a3, a2, a0, a4, a5);
+ GenerateDictionaryStore(masm, &miss, a3, name, value, a4, a5);
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->store_normal_hit(), 1, a4, a5);
__ Ret();
@@ -1218,14 +1197,7 @@
void StoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
StrictMode strict_mode) {
- // ----------- S t a t e -------------
- // -- a0 : value
- // -- a1 : receiver
- // -- a2 : name
- // -- ra : return address
- // -----------------------------------
-
- __ Push(a1, a2, a0);
+ __ Push(ReceiverRegister(), NameRegister(), ValueRegister());
__ li(a0, Operand(Smi::FromInt(strict_mode)));
__ Push(a0);
diff --git a/src/mips64/lithium-codegen-mips64.cc b/src/mips64/lithium-codegen-mips64.cc
index bf856b4..1972f13 100644
--- a/src/mips64/lithium-codegen-mips64.cc
+++ b/src/mips64/lithium-codegen-mips64.cc
@@ -4189,11 +4189,10 @@
void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
ASSERT(ToRegister(instr->context()).is(cp));
- ASSERT(ToRegister(instr->object()).is(a1));
- ASSERT(ToRegister(instr->value()).is(a0));
+ ASSERT(ToRegister(instr->object()).is(StoreIC::ReceiverRegister()));
+ ASSERT(ToRegister(instr->value()).is(StoreIC::ValueRegister()));
- // Name is always in a2.
- __ li(a2, Operand(instr->name()));
+ __ li(StoreIC::NameRegister(), Operand(instr->name()));
Handle<Code> ic = StoreIC::initialize_stub(isolate(), instr->strict_mode());
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
@@ -4454,9 +4453,9 @@
void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
ASSERT(ToRegister(instr->context()).is(cp));
- ASSERT(ToRegister(instr->object()).is(a2));
- ASSERT(ToRegister(instr->key()).is(a1));
- ASSERT(ToRegister(instr->value()).is(a0));
+ ASSERT(ToRegister(instr->object()).is(KeyedStoreIC::ReceiverRegister()));
+ ASSERT(ToRegister(instr->key()).is(KeyedStoreIC::NameRegister()));
+ ASSERT(ToRegister(instr->value()).is(KeyedStoreIC::ValueRegister()));
Handle<Code> ic = (instr->strict_mode() == STRICT)
? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
diff --git a/src/mips64/lithium-mips64.cc b/src/mips64/lithium-mips64.cc
index dd1c6ca..e90760d 100644
--- a/src/mips64/lithium-mips64.cc
+++ b/src/mips64/lithium-mips64.cc
@@ -2200,9 +2200,9 @@
LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
LOperand* context = UseFixed(instr->context(), cp);
- LOperand* obj = UseFixed(instr->object(), a2);
- LOperand* key = UseFixed(instr->key(), a1);
- LOperand* val = UseFixed(instr->value(), a0);
+ LOperand* obj = UseFixed(instr->object(), KeyedStoreIC::ReceiverRegister());
+ LOperand* key = UseFixed(instr->key(), KeyedStoreIC::NameRegister());
+ LOperand* val = UseFixed(instr->value(), KeyedStoreIC::ValueRegister());
ASSERT(instr->object()->representation().IsTagged());
ASSERT(instr->key()->representation().IsTagged());
@@ -2276,8 +2276,8 @@
LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
LOperand* context = UseFixed(instr->context(), cp);
- LOperand* obj = UseFixed(instr->object(), a1);
- LOperand* val = UseFixed(instr->value(), a0);
+ LOperand* obj = UseFixed(instr->object(), StoreIC::ReceiverRegister());
+ LOperand* val = UseFixed(instr->value(), StoreIC::ValueRegister());
LInstruction* result = new(zone()) LStoreNamedGeneric(context, obj, val);
return MarkAsCall(result, instr);
diff --git a/src/mips64/stub-cache-mips64.cc b/src/mips64/stub-cache-mips64.cc
index 6c46321..2627049 100644
--- a/src/mips64/stub-cache-mips64.cc
+++ b/src/mips64/stub-cache-mips64.cc
@@ -1270,20 +1270,24 @@
Register StoreStubCompiler::value() {
- return a0;
+ return StoreIC::ValueRegister();
}
Register* StoreStubCompiler::registers() {
// receiver, name, scratch1, scratch2, scratch3.
- static Register registers[] = { a1, a2, a3, a4, a5 };
+ Register receiver = StoreIC::ReceiverRegister();
+ Register name = StoreIC::NameRegister();
+ static Register registers[] = { receiver, name, a3, a4, a5 };
return registers;
}
Register* KeyedStoreStubCompiler::registers() {
// receiver, name, scratch1, scratch2, scratch3.
- static Register registers[] = { a2, a1, a3, a4, a5 };
+ Register receiver = KeyedStoreIC::ReceiverRegister();
+ Register name = KeyedStoreIC::NameRegister();
+ static Register registers[] = { receiver, name, a3, a4, a5 };
return registers;
}
diff --git a/src/mksnapshot.cc b/src/mksnapshot.cc
index 36c0376..57880e2 100644
--- a/src/mksnapshot.cc
+++ b/src/mksnapshot.cc
@@ -27,8 +27,8 @@
class Compressor {
public:
virtual ~Compressor() {}
- virtual bool Compress(i::Vector<char> input) = 0;
- virtual i::Vector<char>* output() = 0;
+ virtual bool Compress(i::Vector<i::byte> input) = 0;
+ virtual i::Vector<i::byte>* output() = 0;
};
@@ -63,9 +63,9 @@
startup_blob_file_ = GetFileDescriptorOrDie(startup_blob_file);
}
- void WriteSnapshot(const i::List<char>& snapshot_data,
+ void WriteSnapshot(const i::List<i::byte>& snapshot_data,
const i::Serializer& serializer,
- const i::List<char>& context_snapshot_data,
+ const i::List<i::byte>& context_snapshot_data,
const i::Serializer& context_serializer) const {
WriteSnapshotFile(snapshot_data, serializer,
context_snapshot_data, context_serializer);
@@ -74,14 +74,14 @@
}
private:
- void MaybeWriteStartupBlob(const i::List<char>& snapshot_data,
+ void MaybeWriteStartupBlob(const i::List<i::byte>& snapshot_data,
const i::Serializer& serializer,
- const i::List<char>& context_snapshot_data,
+ const i::List<i::byte>& context_snapshot_data,
const i::Serializer& context_serializer) const {
if (!startup_blob_file_)
return;
- i::List<char> startup_blob;
+ i::List<i::byte> startup_blob;
i::ListSnapshotSink sink(&startup_blob);
int spaces[] = {
@@ -89,13 +89,12 @@
i::MAP_SPACE, i::CELL_SPACE, i::PROPERTY_CELL_SPACE
};
- i::byte* snapshot_bytes = reinterpret_cast<i::byte*>(snapshot_data.begin());
+ i::byte* snapshot_bytes = snapshot_data.begin();
sink.PutBlob(snapshot_bytes, snapshot_data.length(), "snapshot");
for (size_t i = 0; i < ARRAY_SIZE(spaces); ++i)
sink.PutInt(serializer.CurrentAllocationAddress(spaces[i]), "spaces");
- i::byte* context_bytes =
- reinterpret_cast<i::byte*>(context_snapshot_data.begin());
+ i::byte* context_bytes = context_snapshot_data.begin();
sink.PutBlob(context_bytes, context_snapshot_data.length(), "context");
for (size_t i = 0; i < ARRAY_SIZE(spaces); ++i)
sink.PutInt(context_serializer.CurrentAllocationAddress(spaces[i]),
@@ -109,9 +108,9 @@
}
}
- void WriteSnapshotFile(const i::List<char>& snapshot_data,
+ void WriteSnapshotFile(const i::List<i::byte>& snapshot_data,
const i::Serializer& serializer,
- const i::List<char>& context_snapshot_data,
+ const i::List<i::byte>& context_snapshot_data,
const i::Serializer& context_serializer) const {
WriteFilePrefix();
WriteData("", snapshot_data, raw_file_);
@@ -135,11 +134,10 @@
fprintf(fp_, "} // namespace v8\n");
}
- void WriteData(const char* prefix,
- const i::List<char>& source_data,
+ void WriteData(const char* prefix, const i::List<i::byte>& source_data,
FILE* raw_file) const {
- const i::List <char>* data_to_be_written = NULL;
- i::List<char> compressed_data;
+ const i::List<i::byte>* data_to_be_written = NULL;
+ i::List<i::byte> compressed_data;
if (!compressor_) {
data_to_be_written = &source_data;
} else if (compressor_->Compress(source_data.ToVector())) {
@@ -155,7 +153,7 @@
WriteData(prefix, source_data, data_to_be_written);
}
- void MaybeWriteRawFile(const i::List<char>* data, FILE* raw_file) const {
+ void MaybeWriteRawFile(const i::List<i::byte>* data, FILE* raw_file) const {
if (!data || !raw_file)
return;
@@ -170,9 +168,8 @@
}
}
- void WriteData(const char* prefix,
- const i::List<char>& source_data,
- const i::List<char>* data_to_be_written) const {
+ void WriteData(const char* prefix, const i::List<i::byte>& source_data,
+ const i::List<i::byte>* data_to_be_written) const {
fprintf(fp_, "const byte Snapshot::%sdata_[] = {\n", prefix);
WriteSnapshotData(data_to_be_written);
fprintf(fp_, "};\n");
@@ -209,7 +206,7 @@
prefix, name, ser.CurrentAllocationAddress(space));
}
- void WriteSnapshotData(const i::List<char>* data) const {
+ void WriteSnapshotData(const i::List<i::byte>* data) const {
for (int i = 0; i < data->length(); i++) {
if ((i & 0x1f) == 0x1f)
fprintf(fp_, "\n");
@@ -405,12 +402,12 @@
// This results in a somewhat smaller snapshot, probably because it gets
// rid of some things that are cached between garbage collections.
- i::List<char> snapshot_data;
+ i::List<i::byte> snapshot_data;
i::ListSnapshotSink snapshot_sink(&snapshot_data);
i::StartupSerializer ser(internal_isolate, &snapshot_sink);
ser.SerializeStrongReferences();
- i::List<char> context_data;
+ i::List<i::byte> context_data;
i::ListSnapshotSink contex_sink(&context_data);
i::PartialSerializer context_ser(internal_isolate, &ser, &contex_sink);
context_ser.Serialize(&raw_context);
diff --git a/src/objects-inl.h b/src/objects-inl.h
index b841ee6..7fa2a0e 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -1480,22 +1480,6 @@
}
-bool HeapObject::ContainsPointers() {
- InstanceType type = map()->instance_type();
- if (type <= LAST_NAME_TYPE) {
- if (type == SYMBOL_TYPE) {
- return true;
- }
- 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.
- return ((type & kIsIndirectStringMask) == kIsIndirectStringTag);
- }
- return (type > LAST_DATA_TYPE);
-}
-
-
void HeapObject::IteratePointers(ObjectVisitor* v, int start, int end) {
v->VisitPointers(reinterpret_cast<Object**>(FIELD_ADDR(this, start)),
reinterpret_cast<Object**>(FIELD_ADDR(this, end)));
@@ -6032,8 +6016,7 @@
}
-ACCESSORS(JSSet, table, Object, kTableOffset)
-ACCESSORS(JSMap, table, Object, kTableOffset)
+ACCESSORS(JSCollection, table, Object, kTableOffset)
#define ORDERED_HASH_TABLE_ITERATOR_ACCESSORS(name, type, offset) \
diff --git a/src/objects.cc b/src/objects.cc
index 702d8a2..ad066af 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -2339,17 +2339,22 @@
// Unless the instance is being migrated, ensure that modify_index is a field.
PropertyDetails details = descriptors->GetDetails(modify_index);
- if (store_mode == FORCE_FIELD && details.type() != FIELD) {
+ if (store_mode == FORCE_FIELD &&
+ (details.type() != FIELD || details.attributes() != attributes)) {
+ int field_index = details.type() == FIELD ? details.field_index()
+ : new_map->NumberOfFields();
FieldDescriptor d(handle(descriptors->GetKey(modify_index), isolate),
- new_map->NumberOfFields(),
- attributes,
- Representation::Tagged());
+ field_index, attributes, Representation::Tagged());
descriptors->Replace(modify_index, &d);
- int unused_property_fields = new_map->unused_property_fields() - 1;
- if (unused_property_fields < 0) {
- unused_property_fields += JSObject::kFieldsAdded;
+ if (details.type() != FIELD) {
+ int unused_property_fields = new_map->unused_property_fields() - 1;
+ if (unused_property_fields < 0) {
+ unused_property_fields += JSObject::kFieldsAdded;
+ }
+ new_map->set_unused_property_fields(unused_property_fields);
}
- new_map->set_unused_property_fields(unused_property_fields);
+ } else {
+ ASSERT(details.attributes() == attributes);
}
if (FLAG_trace_generalization) {
diff --git a/src/objects.h b/src/objects.h
index 007d4c1..af8cc28 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -44,8 +44,9 @@
// - JSArrayBufferView
// - JSTypedArray
// - JSDataView
-// - JSSet
-// - JSMap
+// - JSCollection
+// - JSSet
+// - JSMap
// - JSSetIterator
// - JSMapIterator
// - JSWeakCollection
@@ -716,7 +717,6 @@
FIXED_UINT8_CLAMPED_ARRAY_TYPE, // LAST_FIXED_TYPED_ARRAY_TYPE
FIXED_DOUBLE_ARRAY_TYPE,
- CONSTANT_POOL_ARRAY_TYPE,
FILLER_TYPE, // LAST_DATA_TYPE
// Structs.
@@ -743,6 +743,7 @@
BREAK_POINT_INFO_TYPE,
FIXED_ARRAY_TYPE,
+ CONSTANT_POOL_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
// All the following types are subtypes of JSReceiver, which corresponds to
@@ -1718,10 +1719,6 @@
// Returns the heap object's size in bytes
inline int Size();
- // Returns true if this heap object contains only references to other
- // heap objects.
- inline bool ContainsPointers();
-
// Given a heap object's map pointer, returns the heap size in bytes
// Useful when the map pointer field is used for other purposes.
// GC internal.
@@ -10078,41 +10075,42 @@
};
-// The JSSet describes EcmaScript Harmony sets
-class JSSet: public JSObject {
+class JSCollection : public JSObject {
public:
- // [set]: the backing hash set containing keys.
+ // [table]: the backing hash table
DECL_ACCESSORS(table, Object)
+ static const int kTableOffset = JSObject::kHeaderSize;
+ static const int kSize = kTableOffset + kPointerSize;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSCollection);
+};
+
+
+// The JSSet describes EcmaScript Harmony sets
+class JSSet : public JSCollection {
+ public:
DECLARE_CAST(JSSet)
// Dispatched behavior.
DECLARE_PRINTER(JSSet)
DECLARE_VERIFIER(JSSet)
- static const int kTableOffset = JSObject::kHeaderSize;
- static const int kSize = kTableOffset + kPointerSize;
-
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSSet);
};
// The JSMap describes EcmaScript Harmony maps
-class JSMap: public JSObject {
+class JSMap : public JSCollection {
public:
- // [table]: the backing hash table mapping keys to values.
- DECL_ACCESSORS(table, Object)
-
DECLARE_CAST(JSMap)
// Dispatched behavior.
DECLARE_PRINTER(JSMap)
DECLARE_VERIFIER(JSMap)
- static const int kTableOffset = JSObject::kHeaderSize;
- static const int kSize = kTableOffset + kPointerSize;
-
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSMap);
};
diff --git a/src/parser.cc b/src/parser.cc
index 544c8c7..3542b4c 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -182,147 +182,86 @@
}
-ScriptData* ScriptData::New(const char* data, int length, bool owns_store) {
- // The length is obviously invalid.
- if (length % sizeof(unsigned) != 0) {
- return NULL;
- }
-
- int deserialized_data_length = length / sizeof(unsigned);
- unsigned* deserialized_data;
- owns_store =
- owns_store || reinterpret_cast<intptr_t>(data) % sizeof(unsigned) != 0;
- if (owns_store) {
- // Copy the data to align it.
- deserialized_data = i::NewArray<unsigned>(deserialized_data_length);
- i::CopyBytes(reinterpret_cast<char*>(deserialized_data),
- data, static_cast<size_t>(length));
- } else {
- // If aligned, don't create a copy of the data.
- deserialized_data = reinterpret_cast<unsigned*>(const_cast<char*>(data));
- }
- return new ScriptData(
- Vector<unsigned>(deserialized_data, deserialized_data_length),
- owns_store);
-}
-
-
-FunctionEntry ScriptData::GetFunctionEntry(int start) {
+FunctionEntry ParseData::GetFunctionEntry(int start) {
// The current pre-data entry must be a FunctionEntry with the given
// start position.
- if ((function_index_ + FunctionEntry::kSize <= store_.length())
- && (static_cast<int>(store_[function_index_]) == start)) {
+ if ((function_index_ + FunctionEntry::kSize <= Length()) &&
+ (static_cast<int>(Data()[function_index_]) == start)) {
int index = function_index_;
function_index_ += FunctionEntry::kSize;
- return FunctionEntry(store_.SubVector(index,
- index + FunctionEntry::kSize));
+ Vector<unsigned> subvector(&(Data()[index]), FunctionEntry::kSize);
+ return FunctionEntry(subvector);
}
return FunctionEntry();
}
-int ScriptData::GetSymbolIdentifier() {
- return ReadNumber(&symbol_data_);
+int ParseData::FunctionCount() {
+ int functions_size = FunctionsSize();
+ if (functions_size < 0) return 0;
+ if (functions_size % FunctionEntry::kSize != 0) return 0;
+ return functions_size / FunctionEntry::kSize;
}
-bool ScriptData::SanityCheck() {
+bool ParseData::IsSane() {
// Check that the header data is valid and doesn't specify
// point to positions outside the store.
- if (store_.length() < PreparseDataConstants::kHeaderSize) return false;
- if (magic() != PreparseDataConstants::kMagicNumber) return false;
- if (version() != PreparseDataConstants::kCurrentVersion) return false;
- if (has_error()) {
- // Extra sane sanity check for error message encoding.
- if (store_.length() <= PreparseDataConstants::kHeaderSize
- + PreparseDataConstants::kMessageTextPos) {
- return false;
- }
- if (Read(PreparseDataConstants::kMessageStartPos) >
- Read(PreparseDataConstants::kMessageEndPos)) {
- return false;
- }
- unsigned arg_count = Read(PreparseDataConstants::kMessageArgCountPos);
- int pos = PreparseDataConstants::kMessageTextPos;
- for (unsigned int i = 0; i <= arg_count; i++) {
- if (store_.length() <= PreparseDataConstants::kHeaderSize + pos) {
- return false;
- }
- int length = static_cast<int>(Read(pos));
- if (length < 0) return false;
- pos += 1 + length;
- }
- if (store_.length() < PreparseDataConstants::kHeaderSize + pos) {
- return false;
- }
- return true;
- }
+ int data_length = Length();
+ if (data_length < PreparseDataConstants::kHeaderSize) return false;
+ if (Magic() != PreparseDataConstants::kMagicNumber) return false;
+ if (Version() != PreparseDataConstants::kCurrentVersion) return false;
+ if (HasError()) return false;
// Check that the space allocated for function entries is sane.
- int functions_size =
- static_cast<int>(store_[PreparseDataConstants::kFunctionsSizeOffset]);
+ int functions_size = FunctionsSize();
if (functions_size < 0) return false;
if (functions_size % FunctionEntry::kSize != 0) return false;
// Check that the total size has room for header and function entries.
int minimum_size =
PreparseDataConstants::kHeaderSize + functions_size;
- if (store_.length() < minimum_size) return false;
+ if (data_length < minimum_size) return false;
return true;
}
-
-const char* ScriptData::ReadString(unsigned* start, int* chars) {
- int length = start[0];
- char* result = NewArray<char>(length + 1);
- for (int i = 0; i < length; i++) {
- result[i] = start[i + 1];
+void ParseData::Initialize() {
+ // Prepares state for use.
+ int data_length = Length();
+ if (data_length >= PreparseDataConstants::kHeaderSize) {
+ function_index_ = PreparseDataConstants::kHeaderSize;
}
- result[length] = '\0';
- if (chars != NULL) *chars = length;
- return result;
}
-Scanner::Location ScriptData::MessageLocation() const {
- int beg_pos = Read(PreparseDataConstants::kMessageStartPos);
- int end_pos = Read(PreparseDataConstants::kMessageEndPos);
- return Scanner::Location(beg_pos, end_pos);
+bool ParseData::HasError() {
+ return Data()[PreparseDataConstants::kHasErrorOffset];
}
-bool ScriptData::IsReferenceError() const {
- return Read(PreparseDataConstants::kIsReferenceErrorPos);
+unsigned ParseData::Magic() {
+ return Data()[PreparseDataConstants::kMagicOffset];
}
-const char* ScriptData::BuildMessage() const {
- unsigned* start = ReadAddress(PreparseDataConstants::kMessageTextPos);
- return ReadString(start, NULL);
+unsigned ParseData::Version() {
+ return Data()[PreparseDataConstants::kVersionOffset];
}
-const char* ScriptData::BuildArg() const {
- int arg_count = Read(PreparseDataConstants::kMessageArgCountPos);
- ASSERT(arg_count == 0 || arg_count == 1);
- if (arg_count == 0) {
- return NULL;
+int ParseData::FunctionsSize() {
+ return static_cast<int>(Data()[PreparseDataConstants::kFunctionsSizeOffset]);
+}
+
+
+void Parser::SetCachedData() {
+ if (cached_data_mode() == NO_CACHED_DATA) {
+ cached_parse_data_ = NULL;
+ } else {
+ ASSERT(info_->cached_data() != NULL);
+ if (cached_data_mode() == CONSUME_CACHED_DATA) {
+ cached_parse_data_ = new ParseData(*info_->cached_data());
+ }
}
- // Position after text found by skipping past length field and
- // length field content words.
- int pos = PreparseDataConstants::kMessageTextPos + 1
- + Read(PreparseDataConstants::kMessageTextPos);
- int count = 0;
- return ReadString(ReadAddress(pos), &count);
-}
-
-
-unsigned ScriptData::Read(int position) const {
- return store_[PreparseDataConstants::kHeaderSize + position];
-}
-
-
-unsigned* ScriptData::ReadAddress(int position) const {
- return &store_[PreparseDataConstants::kHeaderSize + position];
}
@@ -757,18 +696,14 @@
Parser::Parser(CompilationInfo* info)
: ParserBase<ParserTraits>(&scanner_,
info->isolate()->stack_guard()->real_climit(),
- info->extension(),
- NULL,
- info->zone(),
- this),
+ info->extension(), NULL, info->zone(), this),
isolate_(info->isolate()),
script_(info->script()),
scanner_(isolate_->unicode_cache()),
reusable_preparser_(NULL),
original_scope_(NULL),
target_stack_(NULL),
- cached_data_(NULL),
- cached_data_mode_(NO_CACHED_DATA),
+ cached_parse_data_(NULL),
ast_value_factory_(NULL),
info_(info),
has_pending_error_(false),
@@ -805,10 +740,10 @@
// Initialize parser state.
CompleteParserRecorder recorder;
- if (cached_data_mode_ == PRODUCE_CACHED_DATA) {
+ if (cached_data_mode() == PRODUCE_CACHED_DATA) {
log_ = &recorder;
- } else if (cached_data_mode_ == CONSUME_CACHED_DATA) {
- (*cached_data_)->Initialize();
+ } else if (cached_data_mode() == CONSUME_CACHED_DATA) {
+ cached_parse_data_->Initialize();
}
source = String::Flatten(source);
@@ -840,11 +775,8 @@
}
PrintF(" - took %0.3f ms]\n", ms);
}
- if (cached_data_mode_ == PRODUCE_CACHED_DATA) {
- if (result != NULL) {
- Vector<unsigned> store = recorder.ExtractData();
- *cached_data_ = new ScriptData(store);
- }
+ if (cached_data_mode() == PRODUCE_CACHED_DATA) {
+ if (result != NULL) *info_->cached_data() = recorder.GetScriptData();
log_ = NULL;
}
return result;
@@ -1158,13 +1090,18 @@
switch (peek()) {
case Token::FUNCTION:
return ParseFunctionDeclaration(NULL, ok);
- case Token::LET:
- case Token::CONST:
- return ParseVariableStatement(kModuleElement, NULL, ok);
case Token::IMPORT:
return ParseImportDeclaration(ok);
case Token::EXPORT:
return ParseExportDeclaration(ok);
+ case Token::CONST:
+ return ParseVariableStatement(kModuleElement, NULL, ok);
+ case Token::LET:
+ ASSERT(allow_harmony_scoping());
+ if (strict_mode() == STRICT) {
+ return ParseVariableStatement(kModuleElement, NULL, ok);
+ }
+ // Fall through.
default: {
Statement* stmt = ParseStatement(labels, CHECK_OK);
// Handle 'module' as a context-sensitive keyword.
@@ -1545,9 +1482,14 @@
switch (peek()) {
case Token::FUNCTION:
return ParseFunctionDeclaration(NULL, ok);
- case Token::LET:
case Token::CONST:
return ParseVariableStatement(kModuleElement, NULL, ok);
+ case Token::LET:
+ ASSERT(allow_harmony_scoping());
+ if (strict_mode() == STRICT) {
+ return ParseVariableStatement(kModuleElement, NULL, ok);
+ }
+ // Fall through.
default:
return ParseStatement(labels, ok);
}
@@ -1583,11 +1525,6 @@
case Token::LBRACE:
return ParseBlock(labels, ok);
- case Token::CONST: // fall through
- case Token::LET:
- case Token::VAR:
- return ParseVariableStatement(kStatement, NULL, ok);
-
case Token::SEMICOLON:
Next();
return factory()->NewEmptyStatement(RelocInfo::kNoPosition);
@@ -1659,6 +1596,16 @@
case Token::DEBUGGER:
return ParseDebuggerStatement(ok);
+ case Token::VAR:
+ case Token::CONST:
+ return ParseVariableStatement(kStatement, NULL, ok);
+
+ case Token::LET:
+ ASSERT(allow_harmony_scoping());
+ if (strict_mode() == STRICT) {
+ return ParseVariableStatement(kStatement, NULL, ok);
+ }
+ // Fall through.
default:
return ParseExpressionOrLabelledStatement(labels, ok);
}
@@ -2062,20 +2009,8 @@
}
is_const = true;
needs_init = true;
- } else if (peek() == Token::LET) {
- // ES6 Draft Rev4 section 12.2.1:
- //
- // LetDeclaration : let LetBindingList ;
- //
- // * It is a Syntax Error if the code that matches this production is not
- // contained in extended code.
- //
- // TODO(rossberg): make 'let' a legal identifier in sloppy mode.
- if (!allow_harmony_scoping() || strict_mode() == SLOPPY) {
- ReportMessage("illegal_let");
- *ok = false;
- return NULL;
- }
+ } else if (peek() == Token::LET && strict_mode() == STRICT) {
+ ASSERT(allow_harmony_scoping());
Consume(Token::LET);
if (var_context == kStatement) {
// Let declarations are only allowed in source element positions.
@@ -3114,7 +3049,8 @@
} else {
init = variable_statement;
}
- } else if (peek() == Token::LET) {
+ } else if (peek() == Token::LET && strict_mode() == STRICT) {
+ ASSERT(allow_harmony_scoping());
const AstRawString* name = NULL;
VariableDeclarationProperties decl_props = kHasNoInitializers;
Block* variable_statement =
@@ -3292,12 +3228,6 @@
}
-void Parser::ReportInvalidCachedData(const AstRawString* name, bool* ok) {
- ParserTraits::ReportMessage("invalid_cached_data_function", name);
- *ok = false;
-}
-
-
bool CompileTimeValue::IsCompileTimeValue(Expression* expression) {
if (expression->IsLiteral()) return true;
MaterializedLiteral* lit = expression->AsMaterializedLiteral();
@@ -3500,8 +3430,8 @@
fvar_init_op = Token::INIT_CONST;
}
VariableMode fvar_mode =
- allow_harmony_scoping() && strict_mode() == STRICT ? CONST
- : CONST_LEGACY;
+ allow_harmony_scoping() && strict_mode() == STRICT
+ ? CONST : CONST_LEGACY;
ASSERT(function_name != NULL);
fvar = new(zone()) Variable(scope_,
function_name, fvar_mode, true /* is valid LHS */,
@@ -3614,37 +3544,27 @@
int* expected_property_count,
bool* ok) {
int function_block_pos = position();
- if (cached_data_mode_ == CONSUME_CACHED_DATA) {
+ if (cached_data_mode() == CONSUME_CACHED_DATA) {
// If we have cached data, we use it to skip parsing the function body. The
// data contains the information we need to construct the lazy function.
FunctionEntry entry =
- (*cached_data())->GetFunctionEntry(function_block_pos);
- if (entry.is_valid()) {
- if (entry.end_pos() <= function_block_pos) {
- // End position greater than end of stream is safe, and hard to check.
- ReportInvalidCachedData(function_name, ok);
- if (!*ok) {
- return;
- }
- }
- scanner()->SeekForward(entry.end_pos() - 1);
+ cached_parse_data_->GetFunctionEntry(function_block_pos);
+ // Check that cached data is valid.
+ CHECK(entry.is_valid());
+ // End position greater than end of stream is safe, and hard to check.
+ CHECK(entry.end_pos() > function_block_pos);
+ scanner()->SeekForward(entry.end_pos() - 1);
- scope_->set_end_position(entry.end_pos());
- Expect(Token::RBRACE, ok);
- if (!*ok) {
- return;
- }
- isolate()->counters()->total_preparse_skipped()->Increment(
- scope_->end_position() - function_block_pos);
- *materialized_literal_count = entry.literal_count();
- *expected_property_count = entry.property_count();
- scope_->SetStrictMode(entry.strict_mode());
- } else {
- // This case happens when we have preparse data but it doesn't contain an
- // entry for the function. Fail the compilation.
- ReportInvalidCachedData(function_name, ok);
+ scope_->set_end_position(entry.end_pos());
+ Expect(Token::RBRACE, ok);
+ if (!*ok) {
return;
}
+ isolate()->counters()->total_preparse_skipped()->Increment(
+ scope_->end_position() - function_block_pos);
+ *materialized_literal_count = entry.literal_count();
+ *expected_property_count = entry.property_count();
+ scope_->SetStrictMode(entry.strict_mode());
} else {
// With no cached data, we partially parse the function, without building an
// AST. This gathers the data needed to build a lazy function.
@@ -3674,7 +3594,7 @@
*materialized_literal_count = logger.literals();
*expected_property_count = logger.properties();
scope_->SetStrictMode(logger.strict_mode());
- if (cached_data_mode_ == PRODUCE_CACHED_DATA) {
+ if (cached_data_mode() == PRODUCE_CACHED_DATA) {
ASSERT(log_);
// Position right after terminal '}'.
int body_end = scanner()->location().end_pos;
@@ -4766,70 +4686,6 @@
// ----------------------------------------------------------------------------
// The Parser interface.
-ScriptData::~ScriptData() {
- if (owns_store_) store_.Dispose();
-}
-
-
-int ScriptData::Length() {
- return store_.length() * sizeof(unsigned);
-}
-
-
-const char* ScriptData::Data() {
- return reinterpret_cast<const char*>(store_.start());
-}
-
-
-bool ScriptData::HasError() {
- return has_error();
-}
-
-
-void ScriptData::Initialize() {
- // Prepares state for use.
- if (store_.length() >= PreparseDataConstants::kHeaderSize) {
- function_index_ = PreparseDataConstants::kHeaderSize;
- int symbol_data_offset = PreparseDataConstants::kHeaderSize
- + store_[PreparseDataConstants::kFunctionsSizeOffset];
- if (store_.length() > symbol_data_offset) {
- symbol_data_ = reinterpret_cast<byte*>(&store_[symbol_data_offset]);
- } else {
- // Partial preparse causes no symbol information.
- symbol_data_ = reinterpret_cast<byte*>(&store_[0] + store_.length());
- }
- symbol_data_end_ = reinterpret_cast<byte*>(&store_[0] + store_.length());
- }
-}
-
-
-int ScriptData::ReadNumber(byte** source) {
- // Reads a number from symbol_data_ in base 128. The most significant
- // bit marks that there are more digits.
- // If the first byte is 0x80 (kNumberTerminator), it would normally
- // represent a leading zero. Since that is useless, and therefore won't
- // appear as the first digit of any actual value, it is used to
- // mark the end of the input stream.
- byte* data = *source;
- if (data >= symbol_data_end_) return -1;
- byte input = *data;
- if (input == PreparseDataConstants::kNumberTerminator) {
- // End of stream marker.
- return -1;
- }
- int result = input & 0x7f;
- data++;
- while ((input & 0x80u) != 0) {
- if (data >= symbol_data_end_) return -1;
- input = *data;
- result = (result << 7) | (input & 0x7f);
- data++;
- }
- *source = data;
- return result;
-}
-
-
bool RegExpParser::ParseRegExp(FlatStringReader* input,
bool multiline,
RegExpCompileData* result,
@@ -4876,7 +4732,7 @@
result = ParseProgram();
}
} else {
- SetCachedData(info()->cached_data(), info()->cached_data_mode());
+ SetCachedData();
result = ParseProgram();
}
info()->SetFunction(result);
diff --git a/src/parser.h b/src/parser.h
index ac27664..d0b67b7 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -59,73 +59,39 @@
};
-class ScriptData {
+// Wrapper around ScriptData to provide parser-specific functionality.
+class ParseData {
public:
- explicit ScriptData(Vector<unsigned> store)
- : store_(store),
- owns_store_(true) { }
-
- ScriptData(Vector<unsigned> store, bool owns_store)
- : store_(store),
- owns_store_(owns_store) { }
-
- // The created ScriptData won't take ownership of the data. If the alignment
- // is not correct, this will copy the data (and the created ScriptData will
- // take ownership of the copy).
- static ScriptData* New(const char* data, int length, bool owns_store = false);
-
- virtual ~ScriptData();
- virtual int Length();
- virtual const char* Data();
- virtual bool HasError();
-
- void Initialize();
- void ReadNextSymbolPosition();
-
- FunctionEntry GetFunctionEntry(int start);
- int GetSymbolIdentifier();
- bool SanityCheck();
-
- Scanner::Location MessageLocation() const;
- bool IsReferenceError() const;
- const char* BuildMessage() const;
- const char* BuildArg() const;
-
- int function_count() {
- int functions_size =
- static_cast<int>(store_[PreparseDataConstants::kFunctionsSizeOffset]);
- if (functions_size < 0) return 0;
- if (functions_size % FunctionEntry::kSize != 0) return 0;
- return functions_size / FunctionEntry::kSize;
+ explicit ParseData(ScriptData* script_data) : script_data_(script_data) {
+ CHECK(IsAligned(script_data->length(), sizeof(unsigned)));
+ CHECK(IsSane());
}
- // The following functions should only be called if SanityCheck has
- // returned true.
- bool has_error() { return store_[PreparseDataConstants::kHasErrorOffset]; }
- unsigned magic() { return store_[PreparseDataConstants::kMagicOffset]; }
- unsigned version() { return store_[PreparseDataConstants::kVersionOffset]; }
+ void Initialize();
+ FunctionEntry GetFunctionEntry(int start);
+ int FunctionCount();
+
+ bool HasError();
+
+ unsigned* Data() { // Writable data as unsigned int array.
+ return reinterpret_cast<unsigned*>(const_cast<byte*>(script_data_->data()));
+ }
private:
- // Disable copying and assigning; because of owns_store they won't be correct.
- ScriptData(const ScriptData&);
- ScriptData& operator=(const ScriptData&);
+ bool IsSane();
+ unsigned Magic();
+ unsigned Version();
+ int FunctionsSize();
+ int Length() const {
+ // Script data length is already checked to be a multiple of unsigned size.
+ return script_data_->length() / sizeof(unsigned);
+ }
- friend class v8::ScriptCompiler;
- Vector<unsigned> store_;
- unsigned char* symbol_data_;
- unsigned char* symbol_data_end_;
+ ScriptData* script_data_;
int function_index_;
- bool owns_store_;
- unsigned Read(int position) const;
- unsigned* ReadAddress(int position) const;
- // Reads a number from the current symbols
- int ReadNumber(byte** source);
-
- // Read strings written by ParserRecorder::WriteString.
- static const char* ReadString(unsigned* start, int* chars);
+ DISALLOW_COPY_AND_ASSIGN(ParseData);
};
-
// ----------------------------------------------------------------------------
// REGEXP PARSING
@@ -595,6 +561,8 @@
~Parser() {
delete reusable_preparser_;
reusable_preparser_ = NULL;
+ delete cached_parse_data_;
+ cached_parse_data_ = NULL;
}
// Parses the source code represented by the compilation info and sets its
@@ -646,23 +614,10 @@
FunctionLiteral* DoParseProgram(CompilationInfo* info,
Handle<String> source);
- // Report syntax error
- void ReportInvalidCachedData(const AstRawString* name, bool* ok);
-
- void SetCachedData(ScriptData** data,
- CachedDataMode cached_data_mode) {
- cached_data_mode_ = cached_data_mode;
- if (cached_data_mode == NO_CACHED_DATA) {
- cached_data_ = NULL;
- } else {
- ASSERT(data != NULL);
- cached_data_ = data;
- }
- }
+ void SetCachedData();
bool inside_with() const { return scope_->inside_with(); }
- ScriptData** cached_data() const { return cached_data_; }
- CachedDataMode cached_data_mode() const { return cached_data_mode_; }
+ CachedDataMode cached_data_mode() const { return info_->cached_data_mode(); }
Scope* DeclarationScope(VariableMode mode) {
return IsLexicalVariableMode(mode)
? scope_ : scope_->DeclarationScope();
@@ -809,7 +764,7 @@
PreParser* reusable_preparser_;
Scope* original_scope_; // for ES5 function declarations in sloppy eval
Target* target_stack_; // for break, continue statements
- ScriptData** cached_data_;
+ ParseData* cached_parse_data_;
CachedDataMode cached_data_mode_;
AstValueFactory* ast_value_factory_;
diff --git a/src/preparse-data.cc b/src/preparse-data.cc
index 50e9120..3dd02bd 100644
--- a/src/preparse-data.cc
+++ b/src/preparse-data.cc
@@ -4,6 +4,7 @@
#include "include/v8stdint.h"
#include "src/base/logging.h"
+#include "src/compiler.h"
#include "src/globals.h"
#include "src/hashmap.h"
#include "src/preparse-data.h"
@@ -34,7 +35,7 @@
const char* message,
const char* arg_opt,
bool is_reference_error) {
- if (has_error()) return;
+ if (HasError()) return;
preamble_[PreparseDataConstants::kHasErrorOffset] = true;
function_store_.Reset();
STATIC_ASSERT(PreparseDataConstants::kMessageStartPos == 0);
@@ -59,17 +60,21 @@
}
-Vector<unsigned> CompleteParserRecorder::ExtractData() {
+ScriptData* CompleteParserRecorder::GetScriptData() {
int function_size = function_store_.size();
int total_size = PreparseDataConstants::kHeaderSize + function_size;
- Vector<unsigned> data = Vector<unsigned>::New(total_size);
+ unsigned* data = NewArray<unsigned>(total_size);
preamble_[PreparseDataConstants::kFunctionsSizeOffset] = function_size;
- MemCopy(data.start(), preamble_, sizeof(preamble_));
+ MemCopy(data, preamble_, sizeof(preamble_));
if (function_size > 0) {
- function_store_.WriteTo(data.SubVector(PreparseDataConstants::kHeaderSize,
- total_size));
+ function_store_.WriteTo(Vector<unsigned>(
+ data + PreparseDataConstants::kHeaderSize, function_size));
}
- return data;
+ ASSERT(IsAligned(reinterpret_cast<intptr_t>(data), kPointerAlignment));
+ ScriptData* result = new ScriptData(reinterpret_cast<byte*>(data),
+ total_size * sizeof(unsigned));
+ result->AcquireDataOwnership();
+ return result;
}
diff --git a/src/preparse-data.h b/src/preparse-data.h
index 36c481c..caae0ef 100644
--- a/src/preparse-data.h
+++ b/src/preparse-data.h
@@ -13,6 +13,8 @@
namespace v8 {
namespace internal {
+class ScriptData;
+
// Abstract interface for preparse data recorder.
class ParserRecorder {
@@ -149,13 +151,17 @@
const char* message,
const char* argument_opt,
bool is_reference_error_);
- Vector<unsigned> ExtractData();
+ ScriptData* GetScriptData();
- private:
- bool has_error() {
+ bool HasError() {
return static_cast<bool>(preamble_[PreparseDataConstants::kHasErrorOffset]);
}
+ Vector<unsigned> ErrorMessageData() {
+ ASSERT(HasError());
+ return function_store_.ToVector();
+ }
+ private:
void WriteString(Vector<const char> str);
// Write a non-negative number to the symbol store.
diff --git a/src/preparser.cc b/src/preparser.cc
index df9e48e..8c8746d 100644
--- a/src/preparser.cc
+++ b/src/preparser.cc
@@ -61,6 +61,8 @@
} else if (scanner->current_token() ==
Token::FUTURE_STRICT_RESERVED_WORD) {
return PreParserIdentifier::FutureStrictReserved();
+ } else if (scanner->current_token() == Token::LET) {
+ return PreParserIdentifier::Let();
} else if (scanner->current_token() == Token::YIELD) {
return PreParserIdentifier::Yield();
}
@@ -167,9 +169,14 @@
switch (peek()) {
case Token::FUNCTION:
return ParseFunctionDeclaration(ok);
- case Token::LET:
case Token::CONST:
return ParseVariableStatement(kSourceElement, ok);
+ case Token::LET:
+ ASSERT(allow_harmony_scoping());
+ if (strict_mode() == STRICT) {
+ return ParseVariableStatement(kSourceElement, ok);
+ }
+ // Fall through.
default:
return ParseStatement(ok);
}
@@ -237,11 +244,6 @@
case Token::LBRACE:
return ParseBlock(ok);
- case Token::CONST:
- case Token::LET:
- case Token::VAR:
- return ParseVariableStatement(kStatement, ok);
-
case Token::SEMICOLON:
Next();
return Statement::Default();
@@ -297,6 +299,16 @@
case Token::DEBUGGER:
return ParseDebuggerStatement(ok);
+ case Token::VAR:
+ case Token::CONST:
+ return ParseVariableStatement(kStatement, ok);
+
+ case Token::LET:
+ ASSERT(allow_harmony_scoping());
+ if (strict_mode() == STRICT) {
+ return ParseVariableStatement(kStatement, ok);
+ }
+ // Fall through.
default:
return ParseExpressionOrLabelledStatement(ok);
}
@@ -415,23 +427,9 @@
return Statement::Default();
}
}
- } else if (peek() == Token::LET) {
- // ES6 Draft Rev4 section 12.2.1:
- //
- // LetDeclaration : let LetBindingList ;
- //
- // * It is a Syntax Error if the code that matches this production is not
- // contained in extended code.
- //
- // TODO(rossberg): make 'let' a legal identifier in sloppy mode.
- if (!allow_harmony_scoping() || strict_mode() == SLOPPY) {
- ReportMessageAt(scanner()->peek_location(), "illegal_let");
- *ok = false;
- return Statement::Default();
- }
+ } else if (peek() == Token::LET && strict_mode() == STRICT) {
Consume(Token::LET);
- if (var_context != kSourceElement &&
- var_context != kForStatement) {
+ if (var_context != kSourceElement && var_context != kForStatement) {
ReportMessageAt(scanner()->peek_location(), "unprotected_let");
*ok = false;
return Statement::Default();
@@ -669,7 +667,7 @@
Expect(Token::LPAREN, CHECK_OK);
if (peek() != Token::SEMICOLON) {
if (peek() == Token::VAR || peek() == Token::CONST ||
- peek() == Token::LET) {
+ (peek() == Token::LET && strict_mode() == STRICT)) {
bool is_let = peek() == Token::LET;
int decl_count;
VariableDeclarationProperties decl_props = kHasNoInitializers;
diff --git a/src/preparser.h b/src/preparser.h
index d143938..902d20a 100644
--- a/src/preparser.h
+++ b/src/preparser.h
@@ -301,6 +301,7 @@
return next == Token::IDENTIFIER ||
next == Token::FUTURE_RESERVED_WORD ||
next == Token::FUTURE_STRICT_RESERVED_WORD ||
+ next == Token::LET ||
next == Token::YIELD;
}
@@ -548,6 +549,9 @@
static PreParserIdentifier FutureStrictReserved() {
return PreParserIdentifier(kFutureStrictReservedIdentifier);
}
+ static PreParserIdentifier Let() {
+ return PreParserIdentifier(kLetIdentifier);
+ }
static PreParserIdentifier Yield() {
return PreParserIdentifier(kYieldIdentifier);
}
@@ -566,6 +570,7 @@
kUnknownIdentifier,
kFutureReservedIdentifier,
kFutureStrictReservedIdentifier,
+ kLetIdentifier,
kYieldIdentifier,
kEvalIdentifier,
kArgumentsIdentifier
@@ -1271,6 +1276,7 @@
return ReportMessageAt(source_location, "unexpected_token_identifier");
case Token::FUTURE_RESERVED_WORD:
return ReportMessageAt(source_location, "unexpected_reserved");
+ case Token::LET:
case Token::YIELD:
case Token::FUTURE_STRICT_RESERVED_WORD:
return ReportMessageAt(source_location, strict_mode() == SLOPPY
@@ -1298,6 +1304,7 @@
return name;
} else if (strict_mode() == SLOPPY &&
(next == Token::FUTURE_STRICT_RESERVED_WORD ||
+ (next == Token::LET) ||
(next == Token::YIELD && !is_generator()))) {
return this->GetSymbol(scanner());
} else {
@@ -1316,6 +1323,7 @@
if (next == Token::IDENTIFIER) {
*is_strict_reserved = false;
} else if (next == Token::FUTURE_STRICT_RESERVED_WORD ||
+ next == Token::LET ||
(next == Token::YIELD && !this->is_generator())) {
*is_strict_reserved = true;
} else {
@@ -1332,6 +1340,7 @@
ParserBase<Traits>::ParseIdentifierName(bool* ok) {
Token::Value next = Next();
if (next != Token::IDENTIFIER && next != Token::FUTURE_RESERVED_WORD &&
+ next != Token::LET && next != Token::YIELD &&
next != Token::FUTURE_STRICT_RESERVED_WORD && !Token::IsKeyword(next)) {
this->ReportUnexpectedToken(next);
*ok = false;
@@ -1427,6 +1436,7 @@
break;
case Token::IDENTIFIER:
+ case Token::LET:
case Token::YIELD:
case Token::FUTURE_STRICT_RESERVED_WORD: {
// Using eval or arguments in this context is OK even in strict mode.
@@ -1564,6 +1574,8 @@
switch (next) {
case Token::FUTURE_RESERVED_WORD:
case Token::FUTURE_STRICT_RESERVED_WORD:
+ case Token::LET:
+ case Token::YIELD:
case Token::IDENTIFIER: {
bool is_getter = false;
bool is_setter = false;
@@ -1579,6 +1591,8 @@
if (next != i::Token::IDENTIFIER &&
next != i::Token::FUTURE_RESERVED_WORD &&
next != i::Token::FUTURE_STRICT_RESERVED_WORD &&
+ next != i::Token::LET &&
+ next != i::Token::YIELD &&
next != i::Token::NUMBER &&
next != i::Token::STRING &&
!Token::IsKeyword(next)) {
diff --git a/src/serialize.cc b/src/serialize.cc
index 9e203b5..30fde9b 100644
--- a/src/serialize.cc
+++ b/src/serialize.cc
@@ -1799,13 +1799,12 @@
}
-void Serializer::PadByte() { sink_->Put(kNop, "Padding"); }
-
-
void Serializer::Pad() {
// The non-branching GetInt will read up to 3 bytes too far, so we need
// to pad the snapshot to make sure we don't read over the end.
- for (unsigned i = 0; i < sizeof(int32_t) - 1; i++) PadByte();
+ for (unsigned i = 0; i < sizeof(int32_t) - 1; i++) {
+ sink_->Put(kNop, "Padding");
+ }
}
@@ -1817,33 +1816,16 @@
ScriptData* CodeSerializer::Serialize(Handle<SharedFunctionInfo> info) {
// Serialize code object.
- List<char> payload;
- ListSnapshotSink listsink(&payload);
- CodeSerializer ser(info->GetIsolate(), &listsink);
+ List<byte> payload;
+ ListSnapshotSink list_sink(&payload);
+ CodeSerializer cs(info->GetIsolate(), &list_sink);
DisallowHeapAllocation no_gc;
Object** location = Handle<Object>::cast(info).location();
- ser.VisitPointer(location);
- ser.Pad();
+ cs.VisitPointer(location);
+ cs.Pad();
- // Allocate storage. The payload length may not be aligned. Round up.
- // TODO(yangguo) replace ScriptData with a more generic super class.
- int payload_length = payload.length();
- int raw_length = payload_length / sizeof(unsigned) + kHeaderSize;
- if (!IsAligned(payload_length, sizeof(unsigned))) raw_length++;
- unsigned* raw_data = i::NewArray<unsigned>(raw_length);
- char* payload_data = reinterpret_cast<char*>(raw_data + kHeaderSize);
-
- // Write header.
- raw_data[kVersionHashOffset] = Version::Hash();
- raw_data[kPayloadLengthOffset] = payload_length;
- STATIC_ASSERT(NEW_SPACE == 0);
- for (int i = NEW_SPACE; i <= PROPERTY_CELL_SPACE; i++) {
- raw_data[kReservationsOffset + i] = ser.CurrentAllocationAddress(i);
- }
-
- CopyBytes(payload_data, payload.begin(), static_cast<size_t>(payload_length));
-
- return new ScriptData(Vector<unsigned>(raw_data, raw_length), true);
+ SerializedCodeData data(&payload, &cs);
+ return data.GetScriptData();
}
@@ -1892,20 +1874,13 @@
Object* CodeSerializer::Deserialize(Isolate* isolate, ScriptData* data) {
- const unsigned* raw_data = reinterpret_cast<const unsigned*>(data->Data());
- CHECK_EQ(Version::Hash(), raw_data[kVersionHashOffset]);
- int payload_length = raw_data[kPayloadLengthOffset];
- const byte* payload_data =
- reinterpret_cast<const byte*>(raw_data + kHeaderSize);
- ASSERT_LE(payload_length, data->Length() - kHeaderSize);
-
- SnapshotByteSource payload(payload_data, payload_length);
+ SerializedCodeData scd(data);
+ SnapshotByteSource payload(scd.Payload(), scd.PayloadLength());
Deserializer deserializer(&payload);
STATIC_ASSERT(NEW_SPACE == 0);
// TODO(yangguo) what happens if remaining new space is too small?
for (int i = NEW_SPACE; i <= PROPERTY_CELL_SPACE; i++) {
- deserializer.set_reservation(
- i, raw_data[CodeSerializer::kReservationsOffset + i]);
+ deserializer.set_reservation(i, scd.GetReservation(i));
}
Object* root;
deserializer.DeserializePartial(isolate, &root);
@@ -1913,4 +1888,27 @@
ASSERT(root->IsSharedFunctionInfo());
return root;
}
+
+
+SerializedCodeData::SerializedCodeData(List<byte>* payload, CodeSerializer* cs)
+ : owns_script_data_(true) {
+ int data_length = payload->length() + kHeaderEntries * kIntSize;
+ byte* data = NewArray<byte>(data_length);
+ ASSERT(IsAligned(reinterpret_cast<intptr_t>(data), kPointerAlignment));
+ CopyBytes(data + kHeaderEntries * kIntSize, payload->begin(),
+ static_cast<size_t>(payload->length()));
+ script_data_ = new ScriptData(data, data_length);
+ script_data_->AcquireDataOwnership();
+ SetHeaderValue(kVersionHashOffset, Version::Hash());
+ STATIC_ASSERT(NEW_SPACE == 0);
+ for (int i = NEW_SPACE; i <= PROPERTY_CELL_SPACE; i++) {
+ SetHeaderValue(kReservationsOffset + i, cs->CurrentAllocationAddress(i));
+ }
+}
+
+
+bool SerializedCodeData::IsSane() {
+ return GetHeaderValue(kVersionHashOffset) == Version::Hash() &&
+ PayloadLength() >= SharedFunctionInfo::kSize;
+}
} } // namespace v8::internal
diff --git a/src/serialize.h b/src/serialize.h
index 6cc90ea..72bcfe5 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -5,10 +5,10 @@
#ifndef V8_SERIALIZE_H_
#define V8_SERIALIZE_H_
+#include "src/compiler.h"
#include "src/hashmap.h"
#include "src/heap-profiler.h"
#include "src/isolate.h"
-#include "src/parser.h"
#include "src/snapshot-source-sink.h"
namespace v8 {
@@ -470,7 +470,6 @@
SerializationAddressMapper address_mapper_;
intptr_t root_index_wave_front_;
void Pad();
- void PadByte();
friend class ObjectSerializer;
friend class Deserializer;
@@ -576,6 +575,67 @@
static const int kPayloadLengthOffset = 1;
static const int kReservationsOffset = 2;
};
+
+
+// Wrapper around ScriptData to provide code-serializer-specific functionality.
+class SerializedCodeData {
+ public:
+ // Used by when consuming.
+ explicit SerializedCodeData(ScriptData* data)
+ : script_data_(data), owns_script_data_(false) {
+ CHECK(IsSane());
+ }
+
+ // Used when producing.
+ SerializedCodeData(List<byte>* payload, CodeSerializer* cs);
+
+ ~SerializedCodeData() {
+ if (owns_script_data_) delete script_data_;
+ }
+
+ // Return ScriptData object and relinquish ownership over it to the caller.
+ ScriptData* GetScriptData() {
+ ScriptData* result = script_data_;
+ script_data_ = NULL;
+ ASSERT(owns_script_data_);
+ owns_script_data_ = false;
+ return result;
+ }
+
+ const byte* Payload() const {
+ return script_data_->data() + kHeaderEntries * kIntSize;
+ }
+
+ int PayloadLength() const {
+ return script_data_->length() - kHeaderEntries * kIntSize;
+ }
+
+ int GetReservation(int space) const {
+ return GetHeaderValue(kReservationsOffset + space);
+ }
+
+ private:
+ void SetHeaderValue(int offset, int value) {
+ reinterpret_cast<int*>(const_cast<byte*>(script_data_->data()))[offset] =
+ value;
+ }
+
+ int GetHeaderValue(int offset) const {
+ return reinterpret_cast<const int*>(script_data_->data())[offset];
+ }
+
+ bool IsSane();
+
+ // The data header consists of int-sized entries:
+ // [0] version hash
+ // [1..7] reservation sizes for spaces from NEW_SPACE to PROPERTY_CELL_SPACE.
+ static const int kVersionHashOffset = 0;
+ static const int kReservationsOffset = 1;
+ static const int kHeaderEntries = 8;
+
+ ScriptData* script_data_;
+ bool owns_script_data_;
+};
} } // namespace v8::internal
#endif // V8_SERIALIZE_H_
diff --git a/src/snapshot-source-sink.cc b/src/snapshot-source-sink.cc
index e9988eb..b223b58 100644
--- a/src/snapshot-source-sink.cc
+++ b/src/snapshot-source-sink.cc
@@ -92,9 +92,9 @@
}
-void DebugSnapshotSink::Put(int byte, const char* description) {
- PrintF("%24s: %x\n", description, byte);
- sink_->Put(byte, description);
+void DebugSnapshotSink::Put(byte b, const char* description) {
+ PrintF("%24s: %x\n", description, b);
+ sink_->Put(b, description);
}
} // namespace v8::internal
diff --git a/src/snapshot-source-sink.h b/src/snapshot-source-sink.h
index eae8606..f98b5d0 100644
--- a/src/snapshot-source-sink.h
+++ b/src/snapshot-source-sink.h
@@ -71,9 +71,10 @@
class SnapshotByteSink {
public:
virtual ~SnapshotByteSink() { }
- virtual void Put(int byte, const char* description) = 0;
- virtual void PutSection(int byte, const char* description) {
- Put(byte, description);
+ virtual void Put(byte b, const char* description) = 0;
+ virtual void PutSection(int b, const char* description) {
+ ASSERT_LE(b, kMaxUInt8);
+ Put(static_cast<byte>(b), description);
}
void PutInt(uintptr_t integer, const char* description);
void PutRaw(byte* data, int number_of_bytes, const char* description);
@@ -86,7 +87,7 @@
public:
DummySnapshotSink() : length_(0) {}
virtual ~DummySnapshotSink() {}
- virtual void Put(int byte, const char* description) { length_++; }
+ virtual void Put(byte b, const char* description) { length_++; }
virtual int Position() { return length_; }
private:
@@ -98,7 +99,7 @@
class DebugSnapshotSink : public SnapshotByteSink {
public:
explicit DebugSnapshotSink(SnapshotByteSink* chained) : sink_(chained) {}
- virtual void Put(int byte, const char* description) V8_OVERRIDE;
+ virtual void Put(byte b, const char* description) V8_OVERRIDE;
virtual int Position() V8_OVERRIDE { return sink_->Position(); }
private:
@@ -108,14 +109,14 @@
class ListSnapshotSink : public i::SnapshotByteSink {
public:
- explicit ListSnapshotSink(i::List<char>* data) : data_(data) {}
- virtual void Put(int byte, const char* description) V8_OVERRIDE {
- data_->Add(byte);
+ explicit ListSnapshotSink(i::List<byte>* data) : data_(data) {}
+ virtual void Put(byte b, const char* description) V8_OVERRIDE {
+ data_->Add(b);
}
virtual int Position() V8_OVERRIDE { return data_->length(); }
private:
- i::List<char>* data_;
+ i::List<byte>* data_;
};
} // namespace v8::internal
diff --git a/src/spaces.cc b/src/spaces.cc
index 12613c7..e7cb8cc 100644
--- a/src/spaces.cc
+++ b/src/spaces.cc
@@ -18,9 +18,6 @@
// HeapObjectIterator
HeapObjectIterator::HeapObjectIterator(PagedSpace* space) {
- // Check that we actually can iterate this space.
- ASSERT(space->is_iterable());
-
// You can't actually iterate over the anchor page. It is not a real page,
// just an anchor for the double linked page list. Initialize as if we have
// reached the end of the anchor page, then the first iteration will move on
@@ -35,9 +32,6 @@
HeapObjectIterator::HeapObjectIterator(PagedSpace* space,
HeapObjectCallback size_func) {
- // Check that we actually can iterate this space.
- ASSERT(space->is_iterable());
-
// You can't actually iterate over the anchor page. It is not a real page,
// just an anchor for the double linked page list. Initialize the current
// address and end as NULL, then the first iteration will move on
@@ -72,6 +66,9 @@
Address cur, Address end,
HeapObjectIterator::PageMode mode,
HeapObjectCallback size_f) {
+ // Check that we actually can iterate this space.
+ ASSERT(space->is_iterable());
+
space_ = space;
cur_addr_ = cur;
cur_end_ = end;
@@ -2581,12 +2578,23 @@
}
-HeapObject* PagedSpace::WaitForSweeperThreadsAndRetryAllocation(
+HeapObject* PagedSpace::EnsureSweepingProgress(
int size_in_bytes) {
MarkCompactCollector* collector = heap()->mark_compact_collector();
- // If sweeper threads are still running, wait for them.
if (collector->IsConcurrentSweepingInProgress(this)) {
+ // If sweeping is still in progress try to sweep pages on the main thread.
+ int free_chunk =
+ collector->SweepInParallel(this, size_in_bytes);
+ if (free_chunk >= size_in_bytes) {
+ HeapObject* object = free_list_.Allocate(size_in_bytes);
+ // We should be able to allocate an object here since we just freed that
+ // much memory.
+ ASSERT(object != NULL);
+ if (object != NULL) return object;
+ }
+
+ // Wait for the sweeper threads here and complete the sweeping phase.
collector->WaitUntilSweepingCompleted();
// After waiting for the sweeper threads, there may be new free-list
@@ -2617,7 +2625,7 @@
&& heap()->OldGenerationAllocationLimitReached()) {
// If sweeper threads are active, wait for them at that point and steal
// elements form their free-lists.
- HeapObject* object = WaitForSweeperThreadsAndRetryAllocation(size_in_bytes);
+ HeapObject* object = EnsureSweepingProgress(size_in_bytes);
if (object != NULL) return object;
}
@@ -2630,7 +2638,7 @@
// If sweeper threads are active, wait for them at that point and steal
// elements form their free-lists. Allocation may still fail their which
// would indicate that there is not enough memory for the given allocation.
- return WaitForSweeperThreadsAndRetryAllocation(size_in_bytes);
+ return EnsureSweepingProgress(size_in_bytes);
}
diff --git a/src/spaces.h b/src/spaces.h
index 71b7054..8553598 100644
--- a/src/spaces.h
+++ b/src/spaces.h
@@ -2014,8 +2014,10 @@
// address denoted by top in allocation_info_.
inline HeapObject* AllocateLinearly(int size_in_bytes);
- MUST_USE_RESULT HeapObject*
- WaitForSweeperThreadsAndRetryAllocation(int size_in_bytes);
+ // If sweeping is still in progress try to sweep unswept pages. If that is
+ // not successful, wait for the sweeper threads and re-try free-list
+ // allocation.
+ MUST_USE_RESULT HeapObject* EnsureSweepingProgress(int size_in_bytes);
// Slow path of AllocateRaw. This function is space-dependent.
MUST_USE_RESULT HeapObject* SlowAllocateRaw(int size_in_bytes);
diff --git a/src/store-buffer.cc b/src/store-buffer.cc
index a9e1356..3745d91 100644
--- a/src/store-buffer.cc
+++ b/src/store-buffer.cc
@@ -11,7 +11,6 @@
#include "src/base/atomicops.h"
#include "src/counters.h"
#include "src/store-buffer-inl.h"
-#include "src/utils.h"
namespace v8 {
namespace internal {
@@ -23,13 +22,10 @@
old_start_(NULL),
old_limit_(NULL),
old_top_(NULL),
- old_regular_limit_(NULL),
old_reserved_limit_(NULL),
- old_virtual_memory_(NULL),
- old_store_buffer_length_(0),
old_buffer_is_sorted_(false),
old_buffer_is_filtered_(false),
- allow_overflow_(false),
+ during_gc_(false),
store_buffer_rebuilding_enabled_(false),
callback_(NULL),
may_move_store_buffer_entries_(true),
@@ -48,16 +44,8 @@
reinterpret_cast<Address*>(RoundUp(start_as_int, kStoreBufferSize * 2));
limit_ = start_ + (kStoreBufferSize / kPointerSize);
- // We set the maximum store buffer size to the maximum size of a semi-space.
- // The store buffer may reach this limit during a full garbage collection.
- // Note that half of the semi-space should be good enough since half of the
- // memory in the semi-space are not object pointers.
- old_store_buffer_length_ =
- Max(static_cast<int>(heap_->MaxSemiSpaceSize() / sizeof(Address)),
- kOldRegularStoreBufferLength);
-
old_virtual_memory_ =
- new base::VirtualMemory(old_store_buffer_length_ * kPointerSize);
+ new base::VirtualMemory(kOldStoreBufferLength * kPointerSize);
old_top_ = old_start_ =
reinterpret_cast<Address*>(old_virtual_memory_->address());
// Don't know the alignment requirements of the OS, but it is certainly not
@@ -66,12 +54,9 @@
int initial_length =
static_cast<int>(base::OS::CommitPageSize() / kPointerSize);
ASSERT(initial_length > 0);
- ASSERT(initial_length <= kOldRegularStoreBufferLength);
- ASSERT(initial_length <= old_store_buffer_length_);
- ASSERT(kOldRegularStoreBufferLength <= old_store_buffer_length_);
+ ASSERT(initial_length <= kOldStoreBufferLength);
old_limit_ = old_start_ + initial_length;
- old_regular_limit_ = old_start_ + kOldRegularStoreBufferLength;
- old_reserved_limit_ = old_start_ + old_store_buffer_length_;
+ old_reserved_limit_ = old_start_ + kOldStoreBufferLength;
CHECK(old_virtual_memory_->Commit(
reinterpret_cast<void*>(old_start_),
@@ -108,13 +93,8 @@
delete old_virtual_memory_;
delete[] hash_set_1_;
delete[] hash_set_2_;
- old_start_ = NULL;
- old_top_ = NULL;
- old_limit_ = NULL;
- old_reserved_limit_ = NULL;
- old_regular_limit_ = NULL;
- start_ = NULL;
- limit_ = NULL;
+ old_start_ = old_top_ = old_limit_ = old_reserved_limit_ = NULL;
+ start_ = limit_ = NULL;
heap_->public_set_store_buffer_top(start_);
}
@@ -148,35 +128,9 @@
}
-template<StoreBuffer::ExemptPopularPagesMode mode>
-void StoreBuffer::IterativelyExemptPopularPages(intptr_t space_needed) {
- // Sample 1 entry in 97 and filter out the pages where we estimate that more
- // than 1 in 8 pointers are to new space.
- static const int kSampleFinenesses = 5;
- static const struct Samples {
- int prime_sample_step;
- int threshold;
- } samples[kSampleFinenesses] = {
- { 97, ((Page::kPageSize / kPointerSize) / 97) / 8 },
- { 23, ((Page::kPageSize / kPointerSize) / 23) / 16 },
- { 7, ((Page::kPageSize / kPointerSize) / 7) / 32 },
- { 3, ((Page::kPageSize / kPointerSize) / 3) / 256 },
- { 1, 0}
- };
- for (int i = 0; i < kSampleFinenesses; i++) {
- ExemptPopularPages(samples[i].prime_sample_step, samples[i].threshold);
- // As a last resort we mark all pages as being exempt from the store buffer.
- ASSERT(i != (kSampleFinenesses - 1) || old_top_ == old_start_);
- if (mode == ENSURE_SPACE && SpaceAvailable(space_needed)) return;
- else if (mode == SHRINK_TO_REGULAR_SIZE && old_top_ < old_limit_) return;
- }
-}
-
-
void StoreBuffer::EnsureSpace(intptr_t space_needed) {
while (old_limit_ - old_top_ < space_needed &&
- ((!allow_overflow_ && old_limit_ < old_regular_limit_) ||
- (allow_overflow_ && old_limit_ < old_reserved_limit_))) {
+ old_limit_ < old_reserved_limit_) {
size_t grow = old_limit_ - old_start_; // Double size.
CHECK(old_virtual_memory_->Commit(reinterpret_cast<void*>(old_limit_),
grow * kPointerSize,
@@ -208,8 +162,26 @@
if (SpaceAvailable(space_needed)) return;
- IterativelyExemptPopularPages<ENSURE_SPACE>(space_needed);
- ASSERT(SpaceAvailable(space_needed));
+ // Sample 1 entry in 97 and filter out the pages where we estimate that more
+ // than 1 in 8 pointers are to new space.
+ static const int kSampleFinenesses = 5;
+ static const struct Samples {
+ int prime_sample_step;
+ int threshold;
+ } samples[kSampleFinenesses] = {
+ { 97, ((Page::kPageSize / kPointerSize) / 97) / 8 },
+ { 23, ((Page::kPageSize / kPointerSize) / 23) / 16 },
+ { 7, ((Page::kPageSize / kPointerSize) / 7) / 32 },
+ { 3, ((Page::kPageSize / kPointerSize) / 3) / 256 },
+ { 1, 0}
+ };
+ for (int i = 0; i < kSampleFinenesses; i++) {
+ ExemptPopularPages(samples[i].prime_sample_step, samples[i].threshold);
+ // As a last resort we mark all pages as being exempt from the store buffer.
+ ASSERT(i != (kSampleFinenesses - 1) || old_top_ == old_start_);
+ if (SpaceAvailable(space_needed)) return;
+ }
+ UNREACHABLE();
}
@@ -356,9 +328,9 @@
}
-void StoreBuffer::GCPrologue(bool allow_overflow) {
+void StoreBuffer::GCPrologue() {
ClearFilteringHashSets();
- allow_overflow_ = allow_overflow;
+ during_gc_ = true;
}
@@ -394,13 +366,7 @@
void StoreBuffer::GCEpilogue() {
- if (allow_overflow_ && old_limit_ > old_regular_limit_) {
- IterativelyExemptPopularPages<SHRINK_TO_REGULAR_SIZE>(0);
- ASSERT(old_limit_ < old_regular_limit_);
- old_virtual_memory_->Uncommit(old_limit_, old_regular_limit_ - old_limit_);
- }
-
- allow_overflow_ = false;
+ during_gc_ = false;
#ifdef VERIFY_HEAP
if (FLAG_verify_heap) {
Verify();
@@ -522,22 +488,25 @@
FindPointersToNewSpaceInRegion(start, end, slot_callback, clear_maps);
} else {
Page* page = reinterpret_cast<Page*>(chunk);
- ASSERT(page->owner() == heap_->map_space() ||
- page->owner() == heap_->old_pointer_space());
- CHECK(!page->WasSweptConservatively());
-
- HeapObjectIterator iterator(page, NULL);
- for (HeapObject* heap_object = iterator.Next();
- heap_object != NULL;
- heap_object = iterator.Next()) {
- // We iterate over objects that contain pointers only.
- if (heap_object->ContainsPointers()) {
- FindPointersToNewSpaceInRegion(
- heap_object->address() + HeapObject::kHeaderSize,
- heap_object->address() + heap_object->Size(),
- slot_callback,
- clear_maps);
+ PagedSpace* owner = reinterpret_cast<PagedSpace*>(page->owner());
+ Address start = page->area_start();
+ Address end = page->area_end();
+ if (owner == heap_->map_space()) {
+ ASSERT(page->WasSweptPrecisely());
+ HeapObjectIterator iterator(page, NULL);
+ for (HeapObject* heap_object = iterator.Next(); heap_object != NULL;
+ heap_object = iterator.Next()) {
+ // We skip free space objects.
+ if (!heap_object->IsFiller()) {
+ FindPointersToNewSpaceInRegion(
+ heap_object->address() + HeapObject::kHeaderSize,
+ heap_object->address() + heap_object->Size(), slot_callback,
+ clear_maps);
+ }
}
+ } else {
+ FindPointersToNewSpaceInRegion(
+ start, end, slot_callback, clear_maps);
}
}
}
diff --git a/src/store-buffer.h b/src/store-buffer.h
index 20ff6ff..9101c0e 100644
--- a/src/store-buffer.h
+++ b/src/store-buffer.h
@@ -19,6 +19,11 @@
typedef void (*ObjectSlotCallback)(HeapObject** from, HeapObject* to);
+typedef void (StoreBuffer::*RegionCallback)(Address start,
+ Address end,
+ ObjectSlotCallback slot_callback,
+ bool clear_maps);
+
// Used to implement the write barrier by collecting addresses of pointers
// between spaces.
class StoreBuffer {
@@ -63,13 +68,13 @@
static const int kStoreBufferOverflowBit = 1 << (14 + kPointerSizeLog2);
static const int kStoreBufferSize = kStoreBufferOverflowBit;
static const int kStoreBufferLength = kStoreBufferSize / sizeof(Address);
- static const int kOldRegularStoreBufferLength = kStoreBufferLength * 16;
+ static const int kOldStoreBufferLength = kStoreBufferLength * 16;
static const int kHashSetLengthLog2 = 12;
static const int kHashSetLength = 1 << kHashSetLengthLog2;
void Compact();
- void GCPrologue(bool allow_overflow);
+ void GCPrologue();
void GCEpilogue();
Object*** Limit() { return reinterpret_cast<Object***>(old_limit_); }
@@ -113,27 +118,12 @@
Address* old_start_;
Address* old_limit_;
Address* old_top_;
-
- // The regular limit specifies how big the store buffer may become during
- // mutator execution or while scavenging.
- Address* old_regular_limit_;
-
- // The reserved limit is bigger then the regular limit. It should be the size
- // of a semi-space to avoid new scan-on-scavenge during new space evacuation
- // after sweeping in a full garbage collection.
Address* old_reserved_limit_;
-
base::VirtualMemory* old_virtual_memory_;
- int old_store_buffer_length_;
bool old_buffer_is_sorted_;
bool old_buffer_is_filtered_;
-
- // If allow_overflow_ is set, we allow the store buffer to grow until
- // old_reserved_limit_. But we will shrink the store buffer in the epilogue to
- // stay within the old_regular_limit_.
- bool allow_overflow_;
-
+ bool during_gc_;
// The garbage collector iterates over many pointers to new space that are not
// handled by the store buffer. This flag indicates whether the pointers
// found by the callbacks should be added to the store buffer or not.
@@ -156,14 +146,6 @@
void Uniq();
void ExemptPopularPages(int prime_sample_step, int threshold);
- enum ExemptPopularPagesMode {
- ENSURE_SPACE,
- SHRINK_TO_REGULAR_SIZE
- };
-
- template <ExemptPopularPagesMode mode>
- void IterativelyExemptPopularPages(intptr_t space_needed);
-
// Set the map field of the object to NULL if contains a map.
inline void ClearDeadObject(HeapObject *object);
@@ -174,6 +156,17 @@
ObjectSlotCallback slot_callback,
bool clear_maps);
+ // For each region of pointers on a page in use from an old space call
+ // visit_pointer_region callback.
+ // If either visit_pointer_region or callback can cause an allocation
+ // in old space and changes in allocation watermark then
+ // can_preallocate_during_iteration should be set to true.
+ void IteratePointersOnPage(
+ PagedSpace* space,
+ Page* page,
+ RegionCallback region_callback,
+ ObjectSlotCallback slot_callback);
+
void IteratePointersInStoreBuffer(ObjectSlotCallback slot_callback,
bool clear_maps);
diff --git a/src/sweeper-thread.cc b/src/sweeper-thread.cc
index 9ce5ec4..fee3e92 100644
--- a/src/sweeper-thread.cc
+++ b/src/sweeper-thread.cc
@@ -41,8 +41,8 @@
return;
}
- collector_->SweepInParallel(heap_->old_data_space());
- collector_->SweepInParallel(heap_->old_pointer_space());
+ collector_->SweepInParallel(heap_->old_data_space(), 0);
+ collector_->SweepInParallel(heap_->old_pointer_space(), 0);
end_sweeping_semaphore_.Signal();
}
}
diff --git a/src/types.cc b/src/types.cc
index 024d9f6..3cd349b 100644
--- a/src/types.cc
+++ b/src/types.cc
@@ -181,10 +181,10 @@
case ODDBALL_TYPE: {
Heap* heap = map->GetHeap();
if (map == heap->undefined_map()) return kUndefined;
- if (map == heap->the_hole_map()) return kAny; // TODO(rossberg): kNone?
if (map == heap->null_map()) return kNull;
if (map == heap->boolean_map()) return kBoolean;
- ASSERT(map == heap->uninitialized_map() ||
+ ASSERT(map == heap->the_hole_map() ||
+ map == heap->uninitialized_map() ||
map == heap->no_interceptor_result_sentinel_map() ||
map == heap->termination_exception_map() ||
map == heap->arguments_marker_map());
diff --git a/src/version.cc b/src/version.cc
index 7ff8fb4..331dffd 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,7 +34,7 @@
// system so their names cannot be changed without changing the scripts.
#define MAJOR_VERSION 3
#define MINOR_VERSION 28
-#define BUILD_NUMBER 20
+#define BUILD_NUMBER 21
#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index 63b1b8f..486917f 100644
--- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc
@@ -89,15 +89,6 @@
}
-void KeyedStoreFastElementStub::InitializeInterfaceDescriptor(
- CodeStubInterfaceDescriptor* descriptor) {
- Register registers[] = { rdx, rcx, rax };
- descriptor->Initialize(
- ARRAY_SIZE(registers), registers,
- FUNCTION_ADDR(KeyedStoreIC_MissFromStubFailure));
-}
-
-
void TransitionElementsKindStub::InitializeInterfaceDescriptor(
CodeStubInterfaceDescriptor* descriptor) {
Register registers[] = { rax, rbx };
@@ -231,14 +222,6 @@
}
-void StoreGlobalStub::InitializeInterfaceDescriptor(
- CodeStubInterfaceDescriptor* descriptor) {
- Register registers[] = { rdx, rcx, rax };
- descriptor->Initialize(ARRAY_SIZE(registers), registers,
- FUNCTION_ADDR(StoreIC_MissFromStubFailure));
-}
-
-
void ElementsTransitionAndStoreStub::InitializeInterfaceDescriptor(
CodeStubInterfaceDescriptor* descriptor) {
Register registers[] = { rax, rbx, rcx, rdx };
diff --git a/src/x64/debug-x64.cc b/src/x64/debug-x64.cc
index 1870384..f00a4ef 100644
--- a/src/x64/debug-x64.cc
+++ b/src/x64/debug-x64.cc
@@ -170,13 +170,11 @@
void DebugCodegen::GenerateStoreICDebugBreak(MacroAssembler* masm) {
// Register state for IC store call (from ic-x64.cc).
- // ----------- S t a t e -------------
- // -- rax : value
- // -- rcx : name
- // -- rdx : receiver
- // -----------------------------------
+ Register receiver = StoreIC::ReceiverRegister();
+ Register name = StoreIC::NameRegister();
+ Register value = StoreIC::ValueRegister();
Generate_DebugBreakCallHelper(
- masm, rax.bit() | rcx.bit() | rdx.bit(), 0, false);
+ masm, receiver.bit() | name.bit() | value.bit(), 0, false);
}
@@ -187,14 +185,12 @@
void DebugCodegen::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
- // Register state for keyed IC load call (from ic-x64.cc).
- // ----------- S t a t e -------------
- // -- rax : value
- // -- rcx : key
- // -- rdx : receiver
- // -----------------------------------
+ // Register state for keyed IC store call (from ic-x64.cc).
+ Register receiver = KeyedStoreIC::ReceiverRegister();
+ Register name = KeyedStoreIC::NameRegister();
+ Register value = KeyedStoreIC::ValueRegister();
Generate_DebugBreakCallHelper(
- masm, rax.bit() | rcx.bit() | rdx.bit(), 0, false);
+ masm, receiver.bit() | name.bit() | value.bit(), 0, false);
}
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index e0fe835..7fc7c76 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -1666,8 +1666,9 @@
if (key->value()->IsInternalizedString()) {
if (property->emit_store()) {
VisitForAccumulatorValue(value);
- __ Move(rcx, key->value());
- __ movp(rdx, Operand(rsp, 0));
+ ASSERT(StoreIC::ValueRegister().is(rax));
+ __ Move(StoreIC::NameRegister(), key->value());
+ __ movp(StoreIC::ReceiverRegister(), Operand(rsp, 0));
CallStoreIC(key->LiteralFeedbackId());
PrepareForBailoutForId(key->id(), NO_REGISTERS);
} else {
@@ -2347,9 +2348,9 @@
case NAMED_PROPERTY: {
__ Push(rax); // Preserve value.
VisitForAccumulatorValue(prop->obj());
- __ movp(rdx, rax);
- __ Pop(rax); // Restore value.
- __ Move(rcx, prop->key()->AsLiteral()->value());
+ __ Move(StoreIC::ReceiverRegister(), rax);
+ __ Pop(StoreIC::ValueRegister()); // Restore value.
+ __ Move(StoreIC::NameRegister(), prop->key()->AsLiteral()->value());
CallStoreIC();
break;
}
@@ -2357,9 +2358,9 @@
__ Push(rax); // Preserve value.
VisitForStackValue(prop->obj());
VisitForAccumulatorValue(prop->key());
- __ movp(rcx, rax);
- __ Pop(rdx);
- __ Pop(rax); // Restore value.
+ __ Move(KeyedStoreIC::NameRegister(), rax);
+ __ Pop(KeyedStoreIC::ReceiverRegister());
+ __ Pop(KeyedStoreIC::ValueRegister()); // Restore value.
Handle<Code> ic = strict_mode() == SLOPPY
? isolate()->builtins()->KeyedStoreIC_Initialize()
: isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
@@ -2396,8 +2397,8 @@
Token::Value op) {
if (var->IsUnallocated()) {
// Global var, const, or let.
- __ Move(rcx, var->name());
- __ movp(rdx, GlobalObjectOperand());
+ __ Move(StoreIC::NameRegister(), var->name());
+ __ movp(StoreIC::ReceiverRegister(), GlobalObjectOperand());
CallStoreIC();
} else if (op == Token::INIT_CONST_LEGACY) {
@@ -2465,8 +2466,8 @@
// Record source code position before IC call.
SetSourcePosition(expr->position());
- __ Move(rcx, prop->key()->AsLiteral()->value());
- __ Pop(rdx);
+ __ Move(StoreIC::NameRegister(), prop->key()->AsLiteral()->value());
+ __ Pop(StoreIC::ReceiverRegister());
CallStoreIC(expr->AssignmentFeedbackId());
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
@@ -2477,8 +2478,9 @@
void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
// Assignment to a property, using a keyed store IC.
- __ Pop(rcx);
- __ Pop(rdx);
+ __ Pop(KeyedStoreIC::NameRegister()); // Key.
+ __ Pop(KeyedStoreIC::ReceiverRegister());
+ ASSERT(KeyedStoreIC::ValueRegister().is(rax));
// Record source code position before IC call.
SetSourcePosition(expr->position());
Handle<Code> ic = strict_mode() == SLOPPY
@@ -4340,8 +4342,8 @@
}
break;
case NAMED_PROPERTY: {
- __ Move(rcx, prop->key()->AsLiteral()->value());
- __ Pop(rdx);
+ __ Move(StoreIC::NameRegister(), prop->key()->AsLiteral()->value());
+ __ Pop(StoreIC::ReceiverRegister());
CallStoreIC(expr->CountStoreFeedbackId());
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
if (expr->is_postfix()) {
@@ -4354,8 +4356,8 @@
break;
}
case KEYED_PROPERTY: {
- __ Pop(rcx);
- __ Pop(rdx);
+ __ Pop(KeyedStoreIC::NameRegister());
+ __ Pop(KeyedStoreIC::ReceiverRegister());
Handle<Code> ic = strict_mode() == SLOPPY
? isolate()->builtins()->KeyedStoreIC_Initialize()
: isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc
index 43d3228..caa8d4c 100644
--- a/src/x64/ic-x64.cc
+++ b/src/x64/ic-x64.cc
@@ -567,12 +567,16 @@
Label transition_smi_elements;
Label finish_object_store, non_double_value, transition_double_elements;
Label fast_double_without_map_check;
+ Register receiver = KeyedStoreIC::ReceiverRegister();
+ Register key = KeyedStoreIC::NameRegister();
+ Register value = KeyedStoreIC::ValueRegister();
+ ASSERT(receiver.is(rdx));
+ ASSERT(key.is(rcx));
+ ASSERT(value.is(rax));
// Fast case: Do the store, could be either Object or double.
__ bind(fast_object);
- // rax: value
// rbx: receiver's elements array (a FixedArray)
- // rcx: index
- // rdx: receiver (a JSArray)
+ // receiver is a JSArray.
// r9: map of receiver
if (check_map == kCheckMap) {
__ movp(rdi, FieldOperand(rbx, HeapObject::kMapOffset));
@@ -585,26 +589,26 @@
// there may be a callback on the element
Label holecheck_passed1;
__ movp(kScratchRegister, FieldOperand(rbx,
- rcx,
+ key,
times_pointer_size,
FixedArray::kHeaderSize));
__ CompareRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
__ j(not_equal, &holecheck_passed1);
- __ JumpIfDictionaryInPrototypeChain(rdx, rdi, kScratchRegister, slow);
+ __ JumpIfDictionaryInPrototypeChain(receiver, rdi, kScratchRegister, slow);
__ bind(&holecheck_passed1);
// Smi stores don't require further checks.
Label non_smi_value;
- __ JumpIfNotSmi(rax, &non_smi_value);
+ __ JumpIfNotSmi(value, &non_smi_value);
if (increment_length == kIncrementLength) {
// Add 1 to receiver->length.
- __ leal(rdi, Operand(rcx, 1));
- __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi);
+ __ leal(rdi, Operand(key, 1));
+ __ Integer32ToSmiField(FieldOperand(receiver, JSArray::kLengthOffset), rdi);
}
// It's irrelevant whether array is smi-only or not when writing a smi.
- __ movp(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize),
- rax);
+ __ movp(FieldOperand(rbx, key, times_pointer_size, FixedArray::kHeaderSize),
+ value);
__ ret(0);
__ bind(&non_smi_value);
@@ -615,14 +619,14 @@
__ bind(&finish_object_store);
if (increment_length == kIncrementLength) {
// Add 1 to receiver->length.
- __ leal(rdi, Operand(rcx, 1));
- __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi);
+ __ leal(rdi, Operand(key, 1));
+ __ Integer32ToSmiField(FieldOperand(receiver, JSArray::kLengthOffset), rdi);
}
- __ movp(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize),
- rax);
- __ movp(rdx, rax); // Preserve the value which is returned.
+ __ movp(FieldOperand(rbx, key, times_pointer_size, FixedArray::kHeaderSize),
+ value);
+ __ movp(rdx, value); // Preserve the value which is returned.
__ RecordWriteArray(
- rbx, rdx, rcx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
+ rbx, rdx, key, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
__ ret(0);
__ bind(fast_double);
@@ -638,25 +642,25 @@
// We have to see if the double version of the hole is present. If so
// go to the runtime.
uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
- __ cmpl(FieldOperand(rbx, rcx, times_8, offset), Immediate(kHoleNanUpper32));
+ __ cmpl(FieldOperand(rbx, key, times_8, offset), Immediate(kHoleNanUpper32));
__ j(not_equal, &fast_double_without_map_check);
- __ JumpIfDictionaryInPrototypeChain(rdx, rdi, kScratchRegister, slow);
+ __ JumpIfDictionaryInPrototypeChain(receiver, rdi, kScratchRegister, slow);
__ bind(&fast_double_without_map_check);
- __ StoreNumberToDoubleElements(rax, rbx, rcx, xmm0,
+ __ StoreNumberToDoubleElements(value, rbx, key, xmm0,
&transition_double_elements);
if (increment_length == kIncrementLength) {
// Add 1 to receiver->length.
- __ leal(rdi, Operand(rcx, 1));
- __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi);
+ __ leal(rdi, Operand(key, 1));
+ __ Integer32ToSmiField(FieldOperand(receiver, JSArray::kLengthOffset), rdi);
}
__ ret(0);
__ bind(&transition_smi_elements);
- __ movp(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
+ __ movp(rbx, FieldOperand(receiver, HeapObject::kMapOffset));
// Transition the array appropriately depending on the value type.
- __ movp(r9, FieldOperand(rax, HeapObject::kMapOffset));
+ __ movp(r9, FieldOperand(value, HeapObject::kMapOffset));
__ CompareRoot(r9, Heap::kHeapNumberMapRootIndex);
__ j(not_equal, &non_double_value);
@@ -670,7 +674,7 @@
AllocationSiteMode mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS,
FAST_DOUBLE_ELEMENTS);
ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, slow);
- __ movp(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
+ __ movp(rbx, FieldOperand(receiver, JSObject::kElementsOffset));
__ jmp(&fast_double_without_map_check);
__ bind(&non_double_value);
@@ -683,14 +687,14 @@
mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm, mode,
slow);
- __ movp(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
+ __ movp(rbx, FieldOperand(receiver, JSObject::kElementsOffset));
__ jmp(&finish_object_store);
__ bind(&transition_double_elements);
// Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
// HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
// transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
- __ movp(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
+ __ movp(rbx, FieldOperand(receiver, HeapObject::kMapOffset));
__ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
FAST_ELEMENTS,
rbx,
@@ -698,35 +702,34 @@
slow);
mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, slow);
- __ movp(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
+ __ movp(rbx, FieldOperand(receiver, JSObject::kElementsOffset));
__ jmp(&finish_object_store);
}
void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
StrictMode strict_mode) {
- // ----------- S t a t e -------------
- // -- rax : value
- // -- rcx : key
- // -- rdx : receiver
- // -- rsp[0] : return address
- // -----------------------------------
+ // Return address is on the stack.
Label slow, slow_with_tagged_index, fast_object, fast_object_grow;
Label fast_double, fast_double_grow;
Label array, extra, check_if_double_array;
+ Register receiver = ReceiverRegister();
+ Register key = NameRegister();
+ ASSERT(receiver.is(rdx));
+ ASSERT(key.is(rcx));
// Check that the object isn't a smi.
- __ JumpIfSmi(rdx, &slow_with_tagged_index);
+ __ JumpIfSmi(receiver, &slow_with_tagged_index);
// Get the map from the receiver.
- __ movp(r9, FieldOperand(rdx, HeapObject::kMapOffset));
+ __ movp(r9, FieldOperand(receiver, HeapObject::kMapOffset));
// Check that the receiver does not require access checks and is not observed.
// The generic stub does not perform map checks or handle observed objects.
__ testb(FieldOperand(r9, Map::kBitFieldOffset),
Immediate(1 << Map::kIsAccessCheckNeeded | 1 << Map::kIsObserved));
__ j(not_zero, &slow_with_tagged_index);
// Check that the key is a smi.
- __ JumpIfNotSmi(rcx, &slow_with_tagged_index);
- __ SmiToInteger32(rcx, rcx);
+ __ JumpIfNotSmi(key, &slow_with_tagged_index);
+ __ SmiToInteger32(key, key);
__ CmpInstanceType(r9, JS_ARRAY_TYPE);
__ j(equal, &array);
@@ -735,20 +738,15 @@
__ j(below, &slow);
// Object case: Check key against length in the elements array.
- // rax: value
- // rdx: JSObject
- // rcx: index
- __ movp(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
+ __ movp(rbx, FieldOperand(receiver, JSObject::kElementsOffset));
// Check array bounds.
- __ SmiCompareInteger32(FieldOperand(rbx, FixedArray::kLengthOffset), rcx);
- // rax: value
+ __ SmiCompareInteger32(FieldOperand(rbx, FixedArray::kLengthOffset), key);
// rbx: FixedArray
- // rcx: index
__ j(above, &fast_object);
// Slow case: call runtime.
__ bind(&slow);
- __ Integer32ToSmi(rcx, rcx);
+ __ Integer32ToSmi(key, key);
__ bind(&slow_with_tagged_index);
GenerateRuntimeSetProperty(masm, strict_mode);
// Never returns to here.
@@ -757,13 +755,11 @@
// perform the store and update the length. Used for adding one
// element to the array by writing to array[array.length].
__ bind(&extra);
- // rax: value
- // rdx: receiver (a JSArray)
+ // receiver is a JSArray.
// rbx: receiver's elements array (a FixedArray)
- // rcx: index
- // flags: smicompare (rdx.length(), rbx)
+ // flags: smicompare (receiver.length(), rbx)
__ j(not_equal, &slow); // do not leave holes in the array
- __ SmiCompareInteger32(FieldOperand(rbx, FixedArray::kLengthOffset), rcx);
+ __ SmiCompareInteger32(FieldOperand(rbx, FixedArray::kLengthOffset), key);
__ j(below_equal, &slow);
// Increment index to get new length.
__ movp(rdi, FieldOperand(rbx, HeapObject::kMapOffset));
@@ -781,14 +777,12 @@
// array. Check that the array is in fast mode (and writable); if it
// is the length is always a smi.
__ bind(&array);
- // rax: value
- // rdx: receiver (a JSArray)
- // rcx: index
- __ movp(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
+ // receiver is a JSArray.
+ __ movp(rbx, FieldOperand(receiver, JSObject::kElementsOffset));
// Check the key against the length in the array, compute the
// address to store into and fall through to fast case.
- __ SmiCompareInteger32(FieldOperand(rdx, JSArray::kLengthOffset), rcx);
+ __ SmiCompareInteger32(FieldOperand(receiver, JSArray::kLengthOffset), key);
__ j(below_equal, &extra);
KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double,
@@ -906,18 +900,20 @@
void KeyedStoreIC::GenerateSloppyArguments(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- rax : value
- // -- rcx : key
- // -- rdx : receiver
- // -- rsp[0] : return address
- // -----------------------------------
+ // The return address is on the stack.
Label slow, notin;
+ Register receiver = ReceiverRegister();
+ Register name = NameRegister();
+ Register value = ValueRegister();
+ ASSERT(receiver.is(rdx));
+ ASSERT(name.is(rcx));
+ ASSERT(value.is(rax));
+
Operand mapped_location = GenerateMappedArgumentsLookup(
- masm, rdx, rcx, rbx, rdi, r8, ¬in, &slow);
- __ movp(mapped_location, rax);
+ masm, receiver, name, rbx, rdi, r8, ¬in, &slow);
+ __ movp(mapped_location, value);
__ leap(r9, mapped_location);
- __ movp(r8, rax);
+ __ movp(r8, value);
__ RecordWrite(rbx,
r9,
r8,
@@ -928,10 +924,10 @@
__ bind(¬in);
// The unmapped lookup expects that the parameter map is in rbx.
Operand unmapped_location =
- GenerateUnmappedArgumentsLookup(masm, rcx, rbx, rdi, &slow);
- __ movp(unmapped_location, rax);
+ GenerateUnmappedArgumentsLookup(masm, name, rbx, rdi, &slow);
+ __ movp(unmapped_location, value);
__ leap(r9, unmapped_location);
- __ movp(r8, rax);
+ __ movp(r8, value);
__ RecordWrite(rbx,
r9,
r8,
@@ -1049,6 +1045,26 @@
const Register LoadIC::NameRegister() { return rcx; }
+const Register StoreIC::ReceiverRegister() { return rdx; }
+const Register StoreIC::NameRegister() { return rcx; }
+const Register StoreIC::ValueRegister() { return rax; }
+
+
+const Register KeyedStoreIC::ReceiverRegister() {
+ return StoreIC::ReceiverRegister();
+}
+
+
+const Register KeyedStoreIC::NameRegister() {
+ return StoreIC::NameRegister();
+}
+
+
+const Register KeyedStoreIC::ValueRegister() {
+ return StoreIC::ValueRegister();
+}
+
+
void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
// The return address is on the stack.
@@ -1063,36 +1079,36 @@
void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- rax : value
- // -- rcx : name
- // -- rdx : receiver
- // -- rsp[0] : return address
- // -----------------------------------
+ // The return address is on the stack.
// Get the receiver from the stack and probe the stub cache.
Code::Flags flags = Code::ComputeHandlerFlags(Code::STORE_IC);
masm->isolate()->stub_cache()->GenerateProbe(
- masm, flags, rdx, rcx, rbx, no_reg);
+ masm, flags, ReceiverRegister(), NameRegister(), rbx, no_reg);
// Cache miss: Jump to runtime.
GenerateMiss(masm);
}
-void StoreIC::GenerateMiss(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- rax : value
- // -- rcx : name
- // -- rdx : receiver
- // -- rsp[0] : return address
- // -----------------------------------
+static void StoreIC_PushArgs(MacroAssembler* masm) {
+ Register receiver = StoreIC::ReceiverRegister();
+ Register name = StoreIC::NameRegister();
+ Register value = StoreIC::ValueRegister();
+
+ ASSERT(!rbx.is(receiver) && !rbx.is(name) && !rbx.is(value));
__ PopReturnAddressTo(rbx);
- __ Push(rdx); // receiver
- __ Push(rcx); // name
- __ Push(rax); // value
+ __ Push(receiver);
+ __ Push(name);
+ __ Push(value);
__ PushReturnAddressFrom(rbx);
+}
+
+
+void StoreIC::GenerateMiss(MacroAssembler* masm) {
+ // Return address is on the stack.
+ StoreIC_PushArgs(masm);
// Perform tail call to the entry.
ExternalReference ref =
@@ -1102,18 +1118,16 @@
void StoreIC::GenerateNormal(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- rax : value
- // -- rcx : name
- // -- rdx : receiver
- // -- rsp[0] : return address
- // -----------------------------------
+ // Return address is on the stack.
+ Register receiver = ReceiverRegister();
+ Register name = NameRegister();
+ Register value = ValueRegister();
Label miss;
- GenerateNameDictionaryReceiverCheck(masm, rdx, rbx, rdi, &miss);
+ GenerateNameDictionaryReceiverCheck(masm, receiver, rbx, rdi, &miss);
- GenerateDictionaryStore(masm, &miss, rbx, rcx, rax, r8, r9);
+ GenerateDictionaryStore(masm, &miss, rbx, name, value, r8, r9);
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->store_normal_hit(), 1);
__ ret(0);
@@ -1126,16 +1140,14 @@
void StoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
StrictMode strict_mode) {
- // ----------- S t a t e -------------
- // -- rax : value
- // -- rcx : name
- // -- rdx : receiver
- // -- rsp[0] : return address
- // -----------------------------------
+ // Return address is on the stack.
+ ASSERT(!rbx.is(ReceiverRegister()) && !rbx.is(NameRegister()) &&
+ !rbx.is(ValueRegister()));
+
__ PopReturnAddressTo(rbx);
- __ Push(rdx);
- __ Push(rcx);
- __ Push(rax);
+ __ Push(ReceiverRegister());
+ __ Push(NameRegister());
+ __ Push(ValueRegister());
__ Push(Smi::FromInt(strict_mode));
__ PushReturnAddressFrom(rbx);
@@ -1146,17 +1158,14 @@
void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
StrictMode strict_mode) {
- // ----------- S t a t e -------------
- // -- rax : value
- // -- rcx : key
- // -- rdx : receiver
- // -- rsp[0] : return address
- // -----------------------------------
+ // Return address is on the stack.
+ ASSERT(!rbx.is(ReceiverRegister()) && !rbx.is(NameRegister()) &&
+ !rbx.is(ValueRegister()));
__ PopReturnAddressTo(rbx);
- __ Push(rdx); // receiver
- __ Push(rcx); // key
- __ Push(rax); // value
+ __ Push(ReceiverRegister());
+ __ Push(NameRegister());
+ __ Push(ValueRegister());
__ Push(Smi::FromInt(strict_mode)); // Strict mode.
__ PushReturnAddressFrom(rbx);
@@ -1166,18 +1175,8 @@
void StoreIC::GenerateSlow(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- rax : value
- // -- rcx : key
- // -- rdx : receiver
- // -- rsp[0] : return address
- // -----------------------------------
-
- __ PopReturnAddressTo(rbx);
- __ Push(rdx); // receiver
- __ Push(rcx); // key
- __ Push(rax); // value
- __ PushReturnAddressFrom(rbx);
+ // Return address is on the stack.
+ StoreIC_PushArgs(masm);
// Do tail-call to runtime routine.
ExternalReference ref(IC_Utility(kStoreIC_Slow), masm->isolate());
@@ -1186,18 +1185,8 @@
void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- rax : value
- // -- rcx : key
- // -- rdx : receiver
- // -- rsp[0] : return address
- // -----------------------------------
-
- __ PopReturnAddressTo(rbx);
- __ Push(rdx); // receiver
- __ Push(rcx); // key
- __ Push(rax); // value
- __ PushReturnAddressFrom(rbx);
+ // Return address is on the stack.
+ StoreIC_PushArgs(masm);
// Do tail-call to runtime routine.
ExternalReference ref(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
@@ -1206,18 +1195,8 @@
void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- rax : value
- // -- rcx : key
- // -- rdx : receiver
- // -- rsp[0] : return address
- // -----------------------------------
-
- __ PopReturnAddressTo(rbx);
- __ Push(rdx); // receiver
- __ Push(rcx); // key
- __ Push(rax); // value
- __ PushReturnAddressFrom(rbx);
+ // Return address is on the stack.
+ StoreIC_PushArgs(masm);
// Do tail-call to runtime routine.
ExternalReference ref =
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index b524e8a..426673a 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -4174,10 +4174,10 @@
void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
ASSERT(ToRegister(instr->context()).is(rsi));
- ASSERT(ToRegister(instr->object()).is(rdx));
- ASSERT(ToRegister(instr->value()).is(rax));
+ ASSERT(ToRegister(instr->object()).is(StoreIC::ReceiverRegister()));
+ ASSERT(ToRegister(instr->value()).is(StoreIC::ValueRegister()));
- __ Move(rcx, instr->hydrogen()->name());
+ __ Move(StoreIC::NameRegister(), instr->hydrogen()->name());
Handle<Code> ic = StoreIC::initialize_stub(isolate(), instr->strict_mode());
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
@@ -4439,9 +4439,9 @@
void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
ASSERT(ToRegister(instr->context()).is(rsi));
- ASSERT(ToRegister(instr->object()).is(rdx));
- ASSERT(ToRegister(instr->key()).is(rcx));
- ASSERT(ToRegister(instr->value()).is(rax));
+ ASSERT(ToRegister(instr->object()).is(KeyedStoreIC::ReceiverRegister()));
+ ASSERT(ToRegister(instr->key()).is(KeyedStoreIC::NameRegister()));
+ ASSERT(ToRegister(instr->value()).is(KeyedStoreIC::ValueRegister()));
Handle<Code> ic = instr->strict_mode() == STRICT
? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index 6d1c3dd..c0be3a5 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -2272,9 +2272,10 @@
LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
LOperand* context = UseFixed(instr->context(), rsi);
- LOperand* object = UseFixed(instr->object(), rdx);
- LOperand* key = UseFixed(instr->key(), rcx);
- LOperand* value = UseFixed(instr->value(), rax);
+ LOperand* object = UseFixed(instr->object(),
+ KeyedStoreIC::ReceiverRegister());
+ LOperand* key = UseFixed(instr->key(), KeyedStoreIC::NameRegister());
+ LOperand* value = UseFixed(instr->value(), KeyedStoreIC::ValueRegister());
ASSERT(instr->object()->representation().IsTagged());
ASSERT(instr->key()->representation().IsTagged());
@@ -2369,8 +2370,8 @@
LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
LOperand* context = UseFixed(instr->context(), rsi);
- LOperand* object = UseFixed(instr->object(), rdx);
- LOperand* value = UseFixed(instr->value(), rax);
+ LOperand* object = UseFixed(instr->object(), StoreIC::ReceiverRegister());
+ LOperand* value = UseFixed(instr->value(), StoreIC::ValueRegister());
LStoreNamedGeneric* result =
new(zone()) LStoreNamedGeneric(context, object, value);
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
index b305392..886d9ad 100644
--- a/src/x64/stub-cache-x64.cc
+++ b/src/x64/stub-cache-x64.cc
@@ -1239,20 +1239,24 @@
Register StoreStubCompiler::value() {
- return rax;
+ return StoreIC::ValueRegister();
}
Register* StoreStubCompiler::registers() {
// receiver, name, scratch1, scratch2, scratch3.
- static Register registers[] = { rdx, rcx, rbx, rdi, r8 };
+ Register receiver = KeyedStoreIC::ReceiverRegister();
+ Register name = KeyedStoreIC::NameRegister();
+ static Register registers[] = { receiver, name, rbx, rdi, r8 };
return registers;
}
Register* KeyedStoreStubCompiler::registers() {
// receiver, name, scratch1, scratch2, scratch3.
- static Register registers[] = { rdx, rcx, rbx, rdi, r8 };
+ Register receiver = KeyedStoreIC::ReceiverRegister();
+ Register name = KeyedStoreIC::NameRegister();
+ static Register registers[] = { receiver, name, rbx, rdi, r8 };
return registers;
}
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 6afdf1b..6251172 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -14814,134 +14814,21 @@
v8::ScriptCompiler::kProduceDataToCache);
// Serialize.
const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
- char* serialized_data = i::NewArray<char>(cd->length);
+ i::byte* serialized_data = i::NewArray<i::byte>(cd->length);
i::MemCopy(serialized_data, cd->data, cd->length);
// Deserialize.
- i::ScriptData* deserialized = i::ScriptData::New(serialized_data, cd->length);
+ i::ScriptData* deserialized = new i::ScriptData(serialized_data, cd->length);
// Verify that the original is the same as the deserialized.
- CHECK_EQ(cd->length, deserialized->Length());
- CHECK_EQ(0, memcmp(cd->data, deserialized->Data(), cd->length));
+ CHECK_EQ(cd->length, deserialized->length());
+ CHECK_EQ(0, memcmp(cd->data, deserialized->data(), cd->length));
delete deserialized;
i::DeleteArray(serialized_data);
}
-// Attempts to deserialize bad data.
-TEST(PreCompileDeserializationError) {
- v8::V8::Initialize();
- const char* data = "DONT CARE";
- int invalid_size = 3;
- i::ScriptData* sd = i::ScriptData::New(data, invalid_size);
- CHECK_EQ(NULL, sd);
-}
-
-
-TEST(CompileWithInvalidCachedData) {
- v8::V8::Initialize();
- v8::Isolate* isolate = CcTest::isolate();
- LocalContext context;
- v8::HandleScope scope(context->GetIsolate());
- i::FLAG_min_preparse_length = 0;
-
- const char* script = "function foo(){ return 5;}\n"
- "function bar(){ return 6 + 7;} foo();";
- v8::ScriptCompiler::Source source(v8_str(script));
- v8::ScriptCompiler::Compile(isolate, &source,
- v8::ScriptCompiler::kProduceDataToCache);
- // source owns its cached data. Create a ScriptData based on it. The user
- // never needs to create ScriptDatas any more; we only need it here because we
- // want to modify the data before passing it back.
- const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
- // ScriptData does not take ownership of the buffers passed to it.
- i::ScriptData* sd =
- i::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length);
- CHECK(!sd->HasError());
- // ScriptData private implementation details
- const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
- const int kFunctionEntrySize = i::FunctionEntry::kSize;
- const int kFunctionEntryStartOffset = 0;
- const int kFunctionEntryEndOffset = 1;
- unsigned* sd_data =
- reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
-
- // Overwrite function bar's end position with 0.
- sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
- v8::TryCatch try_catch;
-
- // Make the script slightly different so that we don't hit the compilation
- // cache. Don't change the lenghts of tokens.
- const char* script2 = "function foo(){ return 6;}\n"
- "function bar(){ return 6 + 7;} foo();";
- v8::ScriptCompiler::Source source2(
- v8_str(script2),
- // CachedData doesn't take ownership of the buffers, Source takes
- // ownership of CachedData.
- new v8::ScriptCompiler::CachedData(
- reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length()));
- Local<v8::UnboundScript> compiled_script =
- v8::ScriptCompiler::CompileUnbound(isolate, &source2);
-
- CHECK(try_catch.HasCaught());
- {
- String::Utf8Value exception_value(try_catch.Message()->Get());
- CHECK_EQ("Uncaught SyntaxError: Invalid cached data for function bar",
- *exception_value);
- }
-
- try_catch.Reset();
- delete sd;
-
- // Overwrite function bar's start position with 200. The function entry will
- // not be found when searching for it by position, and the compilation fails.
-
- // ScriptData does not take ownership of the buffers passed to it.
- sd = i::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length);
- sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
- sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
- 200;
- const char* script3 = "function foo(){ return 7;}\n"
- "function bar(){ return 6 + 7;} foo();";
- v8::ScriptCompiler::Source source3(
- v8_str(script3),
- new v8::ScriptCompiler::CachedData(
- reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length()));
- compiled_script =
- v8::ScriptCompiler::CompileUnbound(isolate, &source3);
- CHECK(try_catch.HasCaught());
- {
- String::Utf8Value exception_value(try_catch.Message()->Get());
- CHECK_EQ("Uncaught SyntaxError: Invalid cached data for function bar",
- *exception_value);
- }
- CHECK(compiled_script.IsEmpty());
- try_catch.Reset();
- delete sd;
-
- // Try passing in cached data which is obviously invalid (wrong length).
- sd = i::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length);
- const char* script4 =
- "function foo(){ return 8;}\n"
- "function bar(){ return 6 + 7;} foo();";
- v8::ScriptCompiler::Source source4(
- v8_str(script4),
- new v8::ScriptCompiler::CachedData(
- reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length() - 1));
- compiled_script =
- v8::ScriptCompiler::CompileUnbound(isolate, &source4);
- CHECK(try_catch.HasCaught());
- {
- String::Utf8Value exception_value(try_catch.Message()->Get());
- CHECK_EQ("Uncaught SyntaxError: Invalid cached data",
- *exception_value);
- }
- CHECK(compiled_script.IsEmpty());
- delete sd;
-}
-
-
// This tests that we do not allow dictionary load/call inline caches
// to use functions that have not yet been compiled. The potential
// problem of loading a function that has not yet been compiled can
diff --git a/test/cctest/test-heap-profiler.cc b/test/cctest/test-heap-profiler.cc
index db6b9da..33528fb 100644
--- a/test/cctest/test-heap-profiler.cc
+++ b/test/cctest/test-heap-profiler.cc
@@ -502,9 +502,10 @@
v8::HandleScope scope(env->GetIsolate());
v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
- CompileRun("k = {}; v = {};\n"
- "ws = new WeakSet(); ws.add(k); ws.add(v);\n"
- "wm = new WeakMap(); wm.set(k, v);\n");
+ CompileRun(
+ "k = {}; v = {}; s = 'str';\n"
+ "ws = new WeakSet(); ws.add(k); ws.add(v); ws[s] = s;\n"
+ "wm = new WeakMap(); wm.set(k, v); wm[s] = s;\n");
const v8::HeapSnapshot* snapshot =
heap_profiler->TakeHeapSnapshot(v8_str("WeakCollections"));
CHECK(ValidateSnapshot(snapshot));
@@ -515,6 +516,9 @@
const v8::HeapGraphNode* v =
GetProperty(global, v8::HeapGraphEdge::kProperty, "v");
CHECK_NE(NULL, v);
+ const v8::HeapGraphNode* s =
+ GetProperty(global, v8::HeapGraphEdge::kProperty, "s");
+ CHECK_NE(NULL, s);
const v8::HeapGraphNode* ws =
GetProperty(global, v8::HeapGraphEdge::kProperty, "ws");
@@ -535,6 +539,10 @@
}
}
CHECK_EQ(1, weak_entries);
+ const v8::HeapGraphNode* ws_s =
+ GetProperty(ws, v8::HeapGraphEdge::kProperty, "str");
+ CHECK_NE(NULL, ws_s);
+ CHECK_EQ(static_cast<int>(s->GetId()), static_cast<int>(ws_s->GetId()));
const v8::HeapGraphNode* wm =
GetProperty(global, v8::HeapGraphEdge::kProperty, "wm");
@@ -556,6 +564,85 @@
}
}
CHECK_EQ(2, weak_entries);
+ const v8::HeapGraphNode* wm_s =
+ GetProperty(wm, v8::HeapGraphEdge::kProperty, "str");
+ CHECK_NE(NULL, wm_s);
+ CHECK_EQ(static_cast<int>(s->GetId()), static_cast<int>(wm_s->GetId()));
+}
+
+
+TEST(HeapSnapshotCollection) {
+ i::FLAG_harmony_collections = true;
+
+ LocalContext env;
+ v8::HandleScope scope(env->GetIsolate());
+ v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
+
+ CompileRun(
+ "k = {}; v = {}; s = 'str';\n"
+ "set = new Set(); set.add(k); set.add(v); set[s] = s;\n"
+ "map = new Map(); map.set(k, v); map[s] = s;\n");
+ const v8::HeapSnapshot* snapshot =
+ heap_profiler->TakeHeapSnapshot(v8_str("Collections"));
+ CHECK(ValidateSnapshot(snapshot));
+ const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
+ const v8::HeapGraphNode* k =
+ GetProperty(global, v8::HeapGraphEdge::kProperty, "k");
+ CHECK_NE(NULL, k);
+ const v8::HeapGraphNode* v =
+ GetProperty(global, v8::HeapGraphEdge::kProperty, "v");
+ CHECK_NE(NULL, v);
+ const v8::HeapGraphNode* s =
+ GetProperty(global, v8::HeapGraphEdge::kProperty, "s");
+ CHECK_NE(NULL, s);
+
+ const v8::HeapGraphNode* set =
+ GetProperty(global, v8::HeapGraphEdge::kProperty, "set");
+ CHECK_NE(NULL, set);
+ CHECK_EQ(v8::HeapGraphNode::kObject, set->GetType());
+ CHECK_EQ(v8_str("Set"), set->GetName());
+
+ const v8::HeapGraphNode* set_table =
+ GetProperty(set, v8::HeapGraphEdge::kInternal, "table");
+ CHECK_EQ(v8::HeapGraphNode::kArray, set_table->GetType());
+ CHECK_GT(set_table->GetChildrenCount(), 0);
+ int entries = 0;
+ for (int i = 0, count = set_table->GetChildrenCount(); i < count; ++i) {
+ const v8::HeapGraphEdge* prop = set_table->GetChild(i);
+ const v8::SnapshotObjectId to_node_id = prop->GetToNode()->GetId();
+ if (to_node_id == k->GetId() || to_node_id == v->GetId()) {
+ ++entries;
+ }
+ }
+ CHECK_EQ(2, entries);
+ const v8::HeapGraphNode* set_s =
+ GetProperty(set, v8::HeapGraphEdge::kProperty, "str");
+ CHECK_NE(NULL, set_s);
+ CHECK_EQ(static_cast<int>(s->GetId()), static_cast<int>(set_s->GetId()));
+
+ const v8::HeapGraphNode* map =
+ GetProperty(global, v8::HeapGraphEdge::kProperty, "map");
+ CHECK_NE(NULL, map);
+ CHECK_EQ(v8::HeapGraphNode::kObject, map->GetType());
+ CHECK_EQ(v8_str("Map"), map->GetName());
+
+ const v8::HeapGraphNode* map_table =
+ GetProperty(map, v8::HeapGraphEdge::kInternal, "table");
+ CHECK_EQ(v8::HeapGraphNode::kArray, map_table->GetType());
+ CHECK_GT(map_table->GetChildrenCount(), 0);
+ entries = 0;
+ for (int i = 0, count = map_table->GetChildrenCount(); i < count; ++i) {
+ const v8::HeapGraphEdge* prop = map_table->GetChild(i);
+ const v8::SnapshotObjectId to_node_id = prop->GetToNode()->GetId();
+ if (to_node_id == k->GetId() || to_node_id == v->GetId()) {
+ ++entries;
+ }
+ }
+ CHECK_EQ(2, entries);
+ const v8::HeapGraphNode* map_s =
+ GetProperty(map, v8::HeapGraphEdge::kProperty, "str");
+ CHECK_NE(NULL, map_s);
+ CHECK_EQ(static_cast<int>(s->GetId()), static_cast<int>(map_s->GetId()));
}
diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc
index b12098a..8a1e429 100644
--- a/test/cctest/test-parsing.cc
+++ b/test/cctest/test-parsing.cc
@@ -157,8 +157,7 @@
preparser.set_allow_lazy(true);
i::PreParser::PreParseResult result = preparser.PreParseProgram();
CHECK_EQ(i::PreParser::kPreParseSuccess, result);
- i::ScriptData data(log.ExtractData());
- CHECK(!data.has_error());
+ CHECK(!log.HasError());
}
for (int i = 0; fail_tests[i]; i++) {
@@ -173,8 +172,7 @@
i::PreParser::PreParseResult result = preparser.PreParseProgram();
// Even in the case of a syntax error, kPreParseSuccess is returned.
CHECK_EQ(i::PreParser::kPreParseSuccess, result);
- i::ScriptData data(log.ExtractData());
- CHECK(data.has_error());
+ CHECK(log.HasError());
}
}
@@ -306,8 +304,7 @@
preparser.set_allow_natives_syntax(true);
i::PreParser::PreParseResult result = preparser.PreParseProgram();
CHECK_EQ(i::PreParser::kPreParseSuccess, result);
- i::ScriptData data(log.ExtractData());
- CHECK(!data.has_error());
+ CHECK(!log.HasError());
}
}
@@ -339,9 +336,7 @@
preparser.set_allow_lazy(true);
i::PreParser::PreParseResult result = preparser.PreParseProgram();
CHECK_EQ(i::PreParser::kPreParseSuccess, result);
- i::ScriptData data(log.ExtractData());
- // Data contains syntax error.
- CHECK(data.has_error());
+ CHECK(log.HasError());
}
}
@@ -407,8 +402,7 @@
i::PreParser::PreParseResult result = preparser.PreParseProgram();
// Even in the case of a syntax error, kPreParseSuccess is returned.
CHECK_EQ(i::PreParser::kPreParseSuccess, result);
- i::ScriptData data(log.ExtractData());
- CHECK(data.has_error());
+ CHECK(log.HasError());
}
@@ -438,15 +432,15 @@
preparser.set_allow_lazy(true);
i::PreParser::PreParseResult result = preparser.PreParseProgram();
CHECK_EQ(i::PreParser::kPreParseSuccess, result);
- i::ScriptData data(log.ExtractData());
- CHECK(!data.has_error());
- data.Initialize();
+ i::ScriptData* sd = log.GetScriptData();
+ i::ParseData pd(sd);
+ pd.Initialize();
int first_function =
static_cast<int>(strstr(program, "function") - program);
int first_lbrace = first_function + i::StrLength("function () ");
CHECK_EQ('{', program[first_lbrace]);
- i::FunctionEntry entry1 = data.GetFunctionEntry(first_lbrace);
+ i::FunctionEntry entry1 = pd.GetFunctionEntry(first_lbrace);
CHECK(!entry1.is_valid());
int second_function =
@@ -454,9 +448,10 @@
int second_lbrace =
second_function + i::StrLength("function () ");
CHECK_EQ('{', program[second_lbrace]);
- i::FunctionEntry entry2 = data.GetFunctionEntry(second_lbrace);
+ i::FunctionEntry entry2 = pd.GetFunctionEntry(second_lbrace);
CHECK(entry2.is_valid());
CHECK_EQ('}', program[entry2.end_pos() - 1]);
+ delete sd;
}
@@ -1134,20 +1129,41 @@
}
-i::Handle<i::String> FormatMessage(i::ScriptData* data) {
+const char* ReadString(unsigned* start) {
+ int length = start[0];
+ char* result = i::NewArray<char>(length + 1);
+ for (int i = 0; i < length; i++) {
+ result[i] = start[i + 1];
+ }
+ result[length] = '\0';
+ return result;
+}
+
+
+i::Handle<i::String> FormatMessage(i::Vector<unsigned> data) {
i::Isolate* isolate = CcTest::i_isolate();
i::Factory* factory = isolate->factory();
- const char* message = data->BuildMessage();
+ const char* message =
+ ReadString(&data[i::PreparseDataConstants::kMessageTextPos]);
i::Handle<i::String> format = v8::Utils::OpenHandle(
*v8::String::NewFromUtf8(CcTest::isolate(), message));
- const char* arg = data->BuildArg();
- i::Handle<i::JSArray> args_array = factory->NewJSArray(arg == NULL ? 0 : 1);
- if (arg != NULL) {
- i::JSArray::SetElement(
- args_array, 0, v8::Utils::OpenHandle(*v8::String::NewFromUtf8(
- CcTest::isolate(), arg)),
- NONE, i::SLOPPY).Check();
+ int arg_count = data[i::PreparseDataConstants::kMessageArgCountPos];
+ const char* arg = NULL;
+ i::Handle<i::JSArray> args_array;
+ if (arg_count == 1) {
+ // Position after text found by skipping past length field and
+ // length field content words.
+ int pos = i::PreparseDataConstants::kMessageTextPos + 1 +
+ data[i::PreparseDataConstants::kMessageTextPos];
+ arg = ReadString(&data[pos]);
+ args_array = factory->NewJSArray(1);
+ i::JSArray::SetElement(args_array, 0, v8::Utils::OpenHandle(*v8_str(arg)),
+ NONE, i::SLOPPY).Check();
+ } else {
+ CHECK_EQ(0, arg_count);
+ args_array = factory->NewJSArray(0);
}
+
i::Handle<i::JSObject> builtins(isolate->js_builtins_object());
i::Handle<i::Object> format_fun = i::Object::GetProperty(
isolate, builtins, "FormatMessage").ToHandleChecked();
@@ -1157,6 +1173,7 @@
CHECK(result->IsString());
i::DeleteArray(message);
i::DeleteArray(arg);
+ data.Dispose();
return i::Handle<i::String>::cast(result);
}
@@ -1211,7 +1228,8 @@
i::PreParser::PreParseResult result = preparser.PreParseProgram();
CHECK_EQ(i::PreParser::kPreParseSuccess, result);
}
- i::ScriptData data(log.ExtractData());
+
+ bool preparse_error = log.HasError();
// Parse the data
i::FunctionLiteral* function;
@@ -1246,7 +1264,7 @@
CHECK(false);
}
- if (!data.has_error()) {
+ if (!preparse_error) {
v8::base::OS::Print(
"Parser failed on:\n"
"\t%s\n"
@@ -1257,7 +1275,8 @@
CHECK(false);
}
// Check that preparser and parser produce the same error.
- i::Handle<i::String> preparser_message = FormatMessage(&data);
+ i::Handle<i::String> preparser_message =
+ FormatMessage(log.ErrorMessageData());
if (!i::String::Equals(message_string, preparser_message)) {
v8::base::OS::Print(
"Expected parser and preparser to produce the same error on:\n"
@@ -1270,14 +1289,15 @@
preparser_message->ToCString().get());
CHECK(false);
}
- } else if (data.has_error()) {
+ } else if (preparse_error) {
v8::base::OS::Print(
"Preparser failed on:\n"
"\t%s\n"
"with error:\n"
"\t%s\n"
"However, the parser succeeded",
- source->ToCString().get(), FormatMessage(&data)->ToCString().get());
+ source->ToCString().get(),
+ FormatMessage(log.ErrorMessageData())->ToCString().get());
CHECK(false);
} else if (result == kError) {
v8::base::OS::Print(
@@ -1708,9 +1728,43 @@
}
+TEST(NoErrorsLetSloppyAllModes) {
+ // In sloppy mode, it's okay to use "let" as identifier.
+ const char* context_data[][2] = {
+ { "", "" },
+ { "function f() {", "}" },
+ { "(function f() {", "})" },
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "var let;",
+ "var foo, let;",
+ "try { } catch (let) { }",
+ "function let() { }",
+ "(function let() { })",
+ "function foo(let) { }",
+ "function foo(bar, let) { }",
+ "let = 1;",
+ "var foo = let = 1;",
+ "let * 2;",
+ "++let;",
+ "let++;",
+ "let: 34",
+ "function let(let) { let: let(let + let(0)); }",
+ "({ let: 1 })",
+ "({ get let() { 1 } })",
+ "let(100)",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
TEST(NoErrorsYieldSloppyAllModes) {
// In sloppy mode, it's okay to use "yield" as identifier, *except* inside a
- // generator (see next test).
+ // generator (see other test).
const char* context_data[][2] = {
{ "", "" },
{ "function not_gen() {", "}" },
@@ -1728,13 +1782,15 @@
"function foo(bar, yield) { }",
"yield = 1;",
"var foo = yield = 1;",
+ "yield * 2;",
"++yield;",
"yield++;",
"yield: 34",
- "function yield(yield) { yield: yield (yield + yield (0)); }",
+ "function yield(yield) { yield: yield (yield + yield(0)); }",
"({ yield: 1 })",
"({ get yield() { 1 } })",
- "yield (100)",
+ "yield(100)",
+ "yield[100]",
NULL
};
@@ -1766,20 +1822,20 @@
"(function * yield() { })",
"yield = 1;",
"var foo = yield = 1;",
+ "yield * 2;",
"++yield;",
"yield++;",
"yield: 34",
- "function yield(yield) { yield: yield (yield + yield (0)); }",
+ "function yield(yield) { yield: yield (yield + yield(0)); }",
"({ yield: 1 })",
"({ get yield() { 1 } })",
- "yield (100)",
+ "yield(100)",
+ "yield[100]",
NULL
};
// This test requires kAllowGenerators to succeed.
- static const ParserFlag always_true_flags[] = {
- kAllowGenerators
- };
+ static const ParserFlag always_true_flags[] = { kAllowGenerators };
RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
always_true_flags, 1);
}
@@ -2165,22 +2221,20 @@
factory->NewStringFromUtf8(i::CStrVector(program)).ToHandleChecked();
i::Handle<i::Script> script = factory->NewScript(source);
i::CompilationInfoWithZone info(script);
- i::ScriptData* data = NULL;
- info.SetCachedData(&data, i::PRODUCE_CACHED_DATA);
+ i::ScriptData* sd = NULL;
+ info.SetCachedData(&sd, i::PRODUCE_CACHED_DATA);
i::Parser::Parse(&info, true);
- CHECK(data);
- CHECK(!data->HasError());
+ i::ParseData pd(sd);
- if (data->function_count() != test_cases[i].functions) {
+ if (pd.FunctionCount() != test_cases[i].functions) {
v8::base::OS::Print(
"Expected preparse data for program:\n"
"\t%s\n"
"to contain %d functions, however, received %d functions.\n",
- program, test_cases[i].functions,
- data->function_count());
+ program, test_cases[i].functions, pd.FunctionCount());
CHECK(false);
}
- delete data;
+ delete sd;
}
}
diff --git a/test/cctest/test-serialize.cc b/test/cctest/test-serialize.cc
index c29f51f..d692ffc 100644
--- a/test/cctest/test-serialize.cc
+++ b/test/cctest/test-serialize.cc
@@ -177,9 +177,9 @@
fclose(fp_);
}
}
- virtual void Put(int byte, const char* description) {
+ virtual void Put(byte b, const char* description) {
if (fp_ != NULL) {
- fputc(byte, fp_);
+ fputc(b, fp_);
}
}
virtual int Position() {
diff --git a/test/mjsunit/harmony/block-early-errors.js b/test/mjsunit/harmony/block-early-errors.js
index 791f001..8ed5ea8 100644
--- a/test/mjsunit/harmony/block-early-errors.js
+++ b/test/mjsunit/harmony/block-early-errors.js
@@ -30,7 +30,6 @@
function CheckException(e) {
var string = e.toString();
assertInstanceof(e, SyntaxError);
- assertTrue(string.indexOf("Illegal let") >= 0);
}
function Check(str) {
@@ -49,7 +48,7 @@
}
// Check for early syntax errors when using let
-// declarations outside of extended mode.
+// declarations outside of strict mode.
Check("let x;");
Check("let x = 1;");
Check("let x, y;");
diff --git a/test/mjsunit/harmony/iteration-syntax.js b/test/mjsunit/harmony/iteration-syntax.js
index 3bda78e..015523d 100644
--- a/test/mjsunit/harmony/iteration-syntax.js
+++ b/test/mjsunit/harmony/iteration-syntax.js
@@ -25,7 +25,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Flags: --harmony-iteration --harmony-scoping
+// Flags: --harmony-iteration --harmony-scoping --use-strict
// Test for-of syntax.
diff --git a/tools/testrunner/local/execution.py b/tools/testrunner/local/execution.py
index a6dce63..36ce7be 100644
--- a/tools/testrunner/local/execution.py
+++ b/tools/testrunner/local/execution.py
@@ -65,6 +65,7 @@
self.perf_data_manager = perfdata.PerfDataManager(self.datapath)
self.perfdata = self.perf_data_manager.GetStore(context.arch, context.mode)
self.perf_failures = False
+ self.printed_allocations = False
self.tests = [ t for s in suites for t in s.tests ]
if not context.no_sorting:
for t in self.tests:
@@ -149,6 +150,15 @@
return not has_unexpected_output
def _ProcessTestPredictable(self, test, result, pool):
+ def HasDifferentAllocations(output1, output2):
+ def AllocationStr(stdout):
+ for line in reversed((stdout or "").splitlines()):
+ if line.startswith("### Allocations = "):
+ self.printed_allocations = True
+ return line
+ return ""
+ return (AllocationStr(output1.stdout) != AllocationStr(output2.stdout))
+
# Always pass the test duration for the database update.
test.duration = result[2]
if test.run == 1 and result[1].HasTimedOut():
@@ -159,10 +169,10 @@
self.remaining -= 1
self.failed.append(test)
self.indicator.HasRun(test, True)
- if test.run > 1 and test.output != result[1]:
- # From the second run on, check for differences. If a difference is
- # found, call the indicator twice to report both tests. All runs of each
- # test are counted as one for the statistic.
+ if test.run > 1 and HasDifferentAllocations(test.output, result[1]):
+ # From the second run on, check for different allocations. If a
+ # difference is found, call the indicator twice to report both tests.
+ # All runs of each test are counted as one for the statistic.
self.indicator.AboutToRun(test)
self.remaining -= 1
self.failed.append(test)
@@ -233,6 +243,8 @@
if queued_exception:
raise queued_exception
+ # Make sure that any allocations were printed in predictable mode.
+ assert not self.context.predictable or self.printed_allocations
def GetCommand(self, test):
d8testflag = []
diff --git a/tools/testrunner/objects/output.py b/tools/testrunner/objects/output.py
index 6b5b0cd..87b4c84 100644
--- a/tools/testrunner/objects/output.py
+++ b/tools/testrunner/objects/output.py
@@ -38,12 +38,6 @@
self.stdout = stdout
self.stderr = stderr
- def __ne__(self, other):
- return (self.exit_code != other.exit_code or
- self.timed_out != other.timed_out or
- self.stdout != other.stdout or
- self.stderr != other.stderr)
-
def HasCrashed(self):
if utils.IsWindows():
return 0x80000000 & self.exit_code and not (0x3FFFFF00 & self.exit_code)