Version 3.20.12
Removed buggy ToNumber truncation (partial fix for issue 2813)
Calling Map etc without new should throw TypeError (issue 2819)
Fixed a crash for large code objects on ARM (Chromium issue 2736)
Fixed stale unhandlified value in JSObject::SetPropertyForResult. (Chromium issue 265894)
Added new Harmony methods to String.prototype object. (issue 2796,v8:2797,v8:2798,v8:2799)
Performance and stability improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@16010 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/accessors.cc b/src/accessors.cc
index 51db361..a43eb78 100644
--- a/src/accessors.cc
+++ b/src/accessors.cc
@@ -292,7 +292,7 @@
MaybeObject* Accessors::ScriptGetCompilationType(Object* object, void*) {
Object* script = JSValue::cast(object)->value();
- return Script::cast(script)->compilation_type();
+ return Smi::FromInt(Script::cast(script)->compilation_type());
}
@@ -388,8 +388,7 @@
Handle<Script> script(raw_script);
// If this is not a script compiled through eval there is no eval position.
- int compilation_type = Smi::cast(script->compilation_type())->value();
- if (compilation_type != Script::COMPILATION_TYPE_EVAL) {
+ if (script->compilation_type() != Script::COMPILATION_TYPE_EVAL) {
return script->GetHeap()->undefined_value();
}
diff --git a/src/api.cc b/src/api.cc
index c93b23c..d532a1f 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -1918,6 +1918,7 @@
i::Handle<i::Object> name_obj;
int line_offset = 0;
int column_offset = 0;
+ bool is_shared_cross_origin = false;
if (origin != NULL) {
if (!origin->ResourceName().IsEmpty()) {
name_obj = Utils::OpenHandle(*origin->ResourceName());
@@ -1929,6 +1930,10 @@
column_offset =
static_cast<int>(origin->ResourceColumnOffset()->Value());
}
+ if (!origin->ResourceIsSharedCrossOrigin().IsEmpty()) {
+ is_shared_cross_origin =
+ origin->ResourceIsSharedCrossOrigin() == v8::True();
+ }
}
EXCEPTION_PREAMBLE(isolate);
i::ScriptDataImpl* pre_data_impl =
@@ -1945,6 +1950,7 @@
name_obj,
line_offset,
column_offset,
+ is_shared_cross_origin,
isolate->global_context(),
NULL,
pre_data_impl,
@@ -2412,6 +2418,20 @@
}
+bool Message::IsSharedCrossOrigin() const {
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::Message::IsSharedCrossOrigin()")) return 0;
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
+ i::Handle<i::JSMessageObject> message =
+ i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
+ i::Handle<i::JSValue> script =
+ i::Handle<i::JSValue>::cast(i::Handle<i::Object>(message->script(),
+ isolate));
+ return i::Script::cast(script->value())->is_shared_cross_origin();
+}
+
+
Local<String> Message::GetSourceLine() const {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ON_BAILOUT(isolate, "v8::Message::GetSourceLine()", return Local<String>());
@@ -5931,6 +5951,23 @@
}
+bool RedirectToExternalString(i::Isolate* isolate,
+ i::Handle<i::String> parent,
+ i::Handle<i::String> external) {
+ if (parent->IsConsString()) {
+ i::Handle<i::ConsString> cons = i::Handle<i::ConsString>::cast(parent);
+ cons->set_first(*external);
+ cons->set_second(isolate->heap()->empty_string());
+ } else {
+ ASSERT(parent->IsSlicedString());
+ i::Handle<i::SlicedString> slice = i::Handle<i::SlicedString>::cast(parent);
+ slice->set_parent(*external);
+ slice->set_offset(0);
+ }
+ return true;
+}
+
+
Local<String> v8::String::NewExternal(
v8::String::ExternalStringResource* resource) {
i::Isolate* isolate = i::Isolate::Current();
@@ -5959,9 +5996,23 @@
return false;
}
CHECK(resource && resource->data());
- bool result = obj->MakeExternal(resource);
- if (result && !obj->IsInternalizedString()) {
- isolate->heap()->external_string_table()->AddString(*obj);
+
+ bool result;
+ i::Handle<i::String> external;
+ if (isolate->heap()->old_pointer_space()->Contains(*obj)) {
+ // We do not allow external strings in the old pointer space. Instead of
+ // converting the string in-place, we keep the cons/sliced string and
+ // point it to a newly-allocated external string.
+ external = NewExternalStringHandle(isolate, resource);
+ result = RedirectToExternalString(isolate, obj, external);
+ } else {
+ result = obj->MakeExternal(resource);
+ external = obj;
+ }
+
+ ASSERT(external->IsExternalString());
+ if (result && !external->IsInternalizedString()) {
+ isolate->heap()->external_string_table()->AddString(*external);
}
return result;
}
@@ -5996,9 +6047,23 @@
return false;
}
CHECK(resource && resource->data());
- bool result = obj->MakeExternal(resource);
- if (result && !obj->IsInternalizedString()) {
- isolate->heap()->external_string_table()->AddString(*obj);
+
+ bool result;
+ i::Handle<i::String> external;
+ if (isolate->heap()->old_pointer_space()->Contains(*obj)) {
+ // We do not allow external strings in the old pointer space. Instead of
+ // converting the string in-place, we keep the cons/sliced string and
+ // point it to a newly-allocated external string.
+ external = NewExternalAsciiStringHandle(isolate, resource);
+ result = RedirectToExternalString(isolate, obj, external);
+ } else {
+ result = obj->MakeExternal(resource);
+ external = obj;
+ }
+
+ ASSERT(external->IsExternalString());
+ if (result && !external->IsInternalizedString()) {
+ isolate->heap()->external_string_table()->AddString(*external);
}
return result;
}
@@ -6039,7 +6104,7 @@
}
-double v8::NumberObject::NumberValue() const {
+double v8::NumberObject::ValueOf() const {
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::NumberObject::NumberValue()")) return 0;
LOG_API(isolate, "NumberObject::NumberValue");
@@ -6063,7 +6128,7 @@
}
-bool v8::BooleanObject::BooleanValue() const {
+bool v8::BooleanObject::ValueOf() const {
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::BooleanObject::BooleanValue()")) return 0;
LOG_API(isolate, "BooleanObject::BooleanValue");
@@ -6084,7 +6149,7 @@
}
-Local<v8::String> v8::StringObject::StringValue() const {
+Local<v8::String> v8::StringObject::ValueOf() const {
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::StringObject::StringValue()")) {
return Local<v8::String>();
@@ -6108,7 +6173,7 @@
}
-Local<v8::Symbol> v8::SymbolObject::SymbolValue() const {
+Local<v8::Symbol> v8::SymbolObject::ValueOf() const {
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::SymbolObject::SymbolValue()"))
return Local<v8::Symbol>();
@@ -6137,7 +6202,7 @@
}
-double v8::Date::NumberValue() const {
+double v8::Date::ValueOf() const {
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::Date::NumberValue()")) return 0;
LOG_API(isolate, "Date::NumberValue");
diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc
index ba0dc4b..a9db5a5 100644
--- a/src/arm/assembler-arm.cc
+++ b/src/arm/assembler-arm.cc
@@ -764,10 +764,13 @@
// Linked labels refer to unknown positions in the code
// to be generated; pos() is the position of the last
// instruction using the label.
-
-
-// The link chain is terminated by a negative code position (must be aligned)
-const int kEndOfChain = -4;
+//
+// The linked labels form a link chain by making the branch offset
+// in the instruction steam to point to the previous branch
+// instruction using the same label.
+//
+// The link chain is terminated by a branch offset pointing to the
+// same position.
int Assembler::target_at(int pos) {
@@ -790,7 +793,7 @@
void Assembler::target_at_put(int pos, int target_pos) {
Instr instr = instr_at(pos);
if ((instr & ~kImm24Mask) == 0) {
- ASSERT(target_pos == kEndOfChain || target_pos >= 0);
+ ASSERT(target_pos == pos || target_pos >= 0);
// Emitted label constant, not part of a branch.
// Make label relative to Code* of generated Code object.
instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag));
@@ -886,27 +889,6 @@
}
-void Assembler::link_to(Label* L, Label* appendix) {
- if (appendix->is_linked()) {
- if (L->is_linked()) {
- // Append appendix to L's list.
- int fixup_pos;
- int link = L->pos();
- do {
- fixup_pos = link;
- link = target_at(fixup_pos);
- } while (link > 0);
- ASSERT(link == kEndOfChain);
- target_at_put(fixup_pos, appendix->pos());
- } else {
- // L is empty, simply use appendix.
- *L = *appendix;
- }
- }
- appendix->Unuse(); // appendix should not be used anymore
-}
-
-
void Assembler::bind(Label* L) {
ASSERT(!L->is_bound()); // label can only be bound once
bind_to(L, pc_offset());
@@ -916,7 +898,9 @@
void Assembler::next(Label* L) {
ASSERT(L->is_linked());
int link = target_at(L->pos());
- if (link == kEndOfChain) {
+ if (link == L->pos()) {
+ // Branch target points to the same instuction. This is the end of the link
+ // chain.
L->Unuse();
} else {
ASSERT(link >= 0);
@@ -1229,9 +1213,11 @@
target_pos = L->pos();
} else {
if (L->is_linked()) {
- target_pos = L->pos(); // L's link
+ // Point to previous instruction that uses the link.
+ target_pos = L->pos();
} else {
- target_pos = kEndOfChain;
+ // First entry of the link chain points to itself.
+ target_pos = pc_offset();
}
L->link_to(pc_offset());
}
@@ -1245,17 +1231,16 @@
void Assembler::label_at_put(Label* L, int at_offset) {
int target_pos;
- if (L->is_bound()) {
+ ASSERT(!L->is_bound());
+ if (L->is_linked()) {
+ // Point to previous instruction that uses the link.
target_pos = L->pos();
} else {
- if (L->is_linked()) {
- target_pos = L->pos(); // L's link
- } else {
- target_pos = kEndOfChain;
- }
- L->link_to(at_offset);
- instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag));
+ // First entry of the link chain points to itself.
+ target_pos = at_offset;
}
+ L->link_to(at_offset);
+ instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag));
}
diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h
index 496eb3e..f647848 100644
--- a/src/arm/assembler-arm.h
+++ b/src/arm/assembler-arm.h
@@ -1548,7 +1548,6 @@
// Labels
void print(Label* L);
void bind_to(Label* L, int pos);
- void link_to(Label* L, Label* appendix);
void next(Label* L);
enum UseConstantPoolMode {
diff --git a/src/arm/frames-arm.h b/src/arm/frames-arm.h
index 19b29b8..d022b41 100644
--- a/src/arm/frames-arm.h
+++ b/src/arm/frames-arm.h
@@ -171,6 +171,11 @@
}
+inline void StackHandler::SetFp(Address slot, Address fp) {
+ Memory::Address_at(slot) = fp;
+}
+
+
} } // namespace v8::internal
#endif // V8_ARM_FRAMES_ARM_H_
diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc
index f43846c..511a3c7 100644
--- a/src/arm/ic-arm.cc
+++ b/src/arm/ic-arm.cc
@@ -1221,51 +1221,6 @@
}
-void KeyedStoreIC::GenerateTransitionElementsSmiToDouble(MacroAssembler* masm) {
- // ---------- S t a t e --------------
- // -- r2 : receiver
- // -- r3 : target map
- // -- lr : return address
- // -----------------------------------
- // Must return the modified receiver in r0.
- if (!FLAG_trace_elements_transitions) {
- Label fail;
- AllocationSiteMode mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS,
- FAST_DOUBLE_ELEMENTS);
- ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, &fail);
- __ mov(r0, r2);
- __ Ret();
- __ bind(&fail);
- }
-
- __ push(r2);
- __ TailCallRuntime(Runtime::kTransitionElementsSmiToDouble, 1, 1);
-}
-
-
-void KeyedStoreIC::GenerateTransitionElementsDoubleToObject(
- MacroAssembler* masm) {
- // ---------- S t a t e --------------
- // -- r2 : receiver
- // -- r3 : target map
- // -- lr : return address
- // -----------------------------------
- // Must return the modified receiver in r0.
- if (!FLAG_trace_elements_transitions) {
- Label fail;
- AllocationSiteMode mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS,
- FAST_ELEMENTS);
- ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, &fail);
- __ mov(r0, r2);
- __ Ret();
- __ bind(&fail);
- }
-
- __ push(r2);
- __ TailCallRuntime(Runtime::kTransitionElementsDoubleToObject, 1, 1);
-}
-
-
void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
StrictModeFlag strict_mode) {
// ---------- S t a t e --------------
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index 0000146..1857b4a 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -272,24 +272,6 @@
}
-ExternalReference LLinkObjectInList::GetReference(Isolate* isolate) {
- switch (hydrogen()->known_list()) {
- case HLinkObjectInList::ALLOCATION_SITE_LIST:
- return ExternalReference::allocation_sites_list_address(isolate);
- }
-
- UNREACHABLE();
- // Return a dummy value
- return ExternalReference::isolate_address(isolate);
-}
-
-
-void LLinkObjectInList::PrintDataTo(StringStream* stream) {
- object()->PrintTo(stream);
- stream->Add(" offset %d", hydrogen()->store_field().offset());
-}
-
-
void LLoadContextSlot::PrintDataTo(StringStream* stream) {
context()->PrintTo(stream);
stream->Add("[%d]", slot_index());
@@ -708,9 +690,9 @@
LInstruction* LChunkBuilder::DoShift(Token::Value op,
HBitwiseBinaryOperation* instr) {
- if (instr->representation().IsSmiOrTagged()) {
- ASSERT(instr->left()->representation().IsSmiOrTagged());
- ASSERT(instr->right()->representation().IsSmiOrTagged());
+ if (instr->representation().IsTagged()) {
+ ASSERT(instr->left()->representation().IsTagged());
+ ASSERT(instr->right()->representation().IsTagged());
LOperand* left = UseFixed(instr->left(), r1);
LOperand* right = UseFixed(instr->right(), r0);
@@ -718,25 +700,35 @@
return MarkAsCall(DefineFixed(result, r0), instr);
}
- ASSERT(instr->representation().IsInteger32());
- ASSERT(instr->left()->representation().IsInteger32());
- ASSERT(instr->right()->representation().IsInteger32());
+ ASSERT(instr->representation().IsSmiOrInteger32());
+ ASSERT(instr->left()->representation().Equals(instr->representation()));
+ ASSERT(instr->right()->representation().Equals(instr->representation()));
LOperand* left = UseRegisterAtStart(instr->left());
HValue* right_value = instr->right();
LOperand* right = NULL;
int constant_value = 0;
+ bool does_deopt = false;
if (right_value->IsConstant()) {
HConstant* constant = HConstant::cast(right_value);
right = chunk_->DefineConstantOperand(constant);
constant_value = constant->Integer32Value() & 0x1f;
+ // Left shifts can deoptimize if we shift by > 0 and the result cannot be
+ // truncated to smi.
+ if (instr->representation().IsSmi() && constant_value > 0) {
+ for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) {
+ if (!it.value()->CheckFlag(HValue::kTruncatingToSmi)) {
+ does_deopt = true;
+ break;
+ }
+ }
+ }
} else {
right = UseRegisterAtStart(right_value);
}
// Shift operations can only deoptimize if we do a logical shift
// by 0 and the result cannot be truncated to int32.
- bool does_deopt = false;
if (op == Token::SHR && constant_value == 0) {
if (FLAG_opt_safe_uint32_operations) {
does_deopt = !instr->CheckFlag(HInstruction::kUint32);
@@ -2085,6 +2077,8 @@
return DefineAsRegister(new(zone()) LConstantI);
} else if (r.IsDouble()) {
return DefineAsRegister(new(zone()) LConstantD);
+ } else if (r.IsExternal()) {
+ return DefineAsRegister(new(zone()) LConstantE);
} else if (r.IsTagged()) {
return DefineAsRegister(new(zone()) LConstantT);
} else {
@@ -2128,13 +2122,6 @@
}
-LInstruction* LChunkBuilder::DoLinkObjectInList(HLinkObjectInList* instr) {
- LOperand* object = UseRegister(instr->value());
- LLinkObjectInList* result = new(zone()) LLinkObjectInList(object);
- return result;
-}
-
-
LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
LOperand* context = UseRegisterAtStart(instr->value());
LInstruction* result =
@@ -2312,21 +2299,12 @@
if (IsSimpleMapChangeTransition(instr->from_kind(), instr->to_kind())) {
LOperand* new_map_reg = TempRegister();
LTransitionElementsKind* result =
- new(zone()) LTransitionElementsKind(object, new_map_reg, NULL);
+ new(zone()) LTransitionElementsKind(object, new_map_reg);
return result;
- } else if (FLAG_compiled_transitions) {
- LTransitionElementsKind* result =
- new(zone()) LTransitionElementsKind(object, NULL, NULL);
- return AssignPointerMap(result);
} else {
- LOperand* object = UseFixed(instr->object(), r0);
- LOperand* fixed_object_reg = FixedTemp(r2);
- LOperand* new_map_reg = FixedTemp(r3);
LTransitionElementsKind* result =
- new(zone()) LTransitionElementsKind(object,
- new_map_reg,
- fixed_object_reg);
- return MarkAsCall(result, instr);
+ new(zone()) LTransitionElementsKind(object, NULL);
+ return AssignPointerMap(result);
}
}
@@ -2415,12 +2393,6 @@
}
-LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) {
- LOperand* string = UseRegisterAtStart(instr->value());
- return DefineAsRegister(new(zone()) LStringLength(string));
-}
-
-
LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) {
info()->MarkAsDeferredCalling();
LOperand* size = instr->size()->IsConstant()
diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h
index 6faa781..c568ad6 100644
--- a/src/arm/lithium-arm.h
+++ b/src/arm/lithium-arm.h
@@ -79,6 +79,7 @@
V(CmpMapAndBranch) \
V(CmpT) \
V(ConstantD) \
+ V(ConstantE) \
V(ConstantI) \
V(ConstantS) \
V(ConstantT) \
@@ -118,7 +119,6 @@
V(IsUndetectableAndBranch) \
V(Label) \
V(LazyBailout) \
- V(LinkObjectInList) \
V(LoadContextSlot) \
V(LoadExternalArrayPointer) \
V(LoadFieldByIndex) \
@@ -175,7 +175,6 @@
V(StringCharCodeAt) \
V(StringCharFromCode) \
V(StringCompareAndBranch) \
- V(StringLength) \
V(SubI) \
V(RSubI) \
V(TaggedToI) \
@@ -268,7 +267,7 @@
bool IsMarkedAsCall() const { return is_call_; }
virtual bool HasResult() const = 0;
- virtual LOperand* result() = 0;
+ virtual LOperand* result() const = 0;
LOperand* FirstInput() { return InputAt(0); }
LOperand* Output() { return HasResult() ? result() : NULL; }
@@ -304,9 +303,9 @@
public:
// Allow 0 or 1 output operands.
STATIC_ASSERT(R == 0 || R == 1);
- virtual bool HasResult() const { return R != 0; }
+ virtual bool HasResult() const { return R != 0 && result() != NULL; }
void set_result(LOperand* operand) { results_[0] = operand; }
- LOperand* result() { return results_[0]; }
+ LOperand* result() const { return results_[0]; }
protected:
EmbeddedContainer<LOperand*, R> results_;
@@ -1232,6 +1231,17 @@
};
+class LConstantE: public LTemplateInstruction<1, 0, 0> {
+ public:
+ DECLARE_CONCRETE_INSTRUCTION(ConstantE, "constant-e")
+ DECLARE_HYDROGEN_ACCESSOR(Constant)
+
+ ExternalReference value() const {
+ return hydrogen()->ExternalReferenceValue();
+ }
+};
+
+
class LConstantT: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(ConstantT, "constant-t")
@@ -1664,23 +1674,6 @@
};
-class LLinkObjectInList: public LTemplateInstruction<0, 1, 0> {
- public:
- explicit LLinkObjectInList(LOperand* object) {
- inputs_[0] = object;
- }
-
- LOperand* object() { return inputs_[0]; }
-
- ExternalReference GetReference(Isolate* isolate);
-
- DECLARE_CONCRETE_INSTRUCTION(LinkObjectInList, "link-object-in-list")
- DECLARE_HYDROGEN_ACCESSOR(LinkObjectInList)
-
- virtual void PrintDataTo(StringStream* stream);
-};
-
-
class LLoadContextSlot: public LTemplateInstruction<1, 1, 0> {
public:
explicit LLoadContextSlot(LOperand* context) {
@@ -2236,19 +2229,16 @@
};
-class LTransitionElementsKind: public LTemplateInstruction<0, 1, 2> {
+class LTransitionElementsKind: public LTemplateInstruction<0, 1, 1> {
public:
LTransitionElementsKind(LOperand* object,
- LOperand* new_map_temp,
- LOperand* fixed_object_temp) {
+ LOperand* new_map_temp) {
inputs_[0] = object;
temps_[0] = new_map_temp;
- temps_[1] = fixed_object_temp;
}
LOperand* object() { return inputs_[0]; }
LOperand* new_map_temp() { return temps_[0]; }
- LOperand* temp() { return temps_[1]; }
DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind,
"transition-elements-kind")
@@ -2323,19 +2313,6 @@
};
-class LStringLength: public LTemplateInstruction<1, 1, 0> {
- public:
- explicit LStringLength(LOperand* string) {
- inputs_[0] = string;
- }
-
- LOperand* string() { return inputs_[0]; }
-
- DECLARE_CONCRETE_INSTRUCTION(StringLength, "string-length")
- DECLARE_HYDROGEN_ACCESSOR(StringLength)
-};
-
-
class LCheckFunction: public LTemplateInstruction<0, 1, 0> {
public:
explicit LCheckFunction(LOperand* value) {
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index 41636a8..cf1e7c7 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -1742,7 +1742,18 @@
break;
case Token::SHL:
if (shift_count != 0) {
- __ mov(result, Operand(left, LSL, shift_count));
+ if (instr->hydrogen_value()->representation().IsSmi() &&
+ instr->can_deopt()) {
+ if (shift_count != 1) {
+ __ mov(result, Operand(left, LSL, shift_count - 1));
+ __ SmiTag(result, result, SetCC);
+ } else {
+ __ SmiTag(result, left, SetCC);
+ }
+ DeoptimizeIf(vs, instr->environment());
+ } else {
+ __ mov(result, Operand(left, LSL, shift_count));
+ }
} else {
__ Move(result, left);
}
@@ -1815,6 +1826,11 @@
}
+void LCodeGen::DoConstantE(LConstantE* instr) {
+ __ mov(ToRegister(instr->result()), Operand(instr->value()));
+}
+
+
void LCodeGen::DoConstantT(LConstantT* instr) {
Handle<Object> value = instr->value();
AllowDeferredHandleDereference smi_check;
@@ -2924,19 +2940,6 @@
}
-void LCodeGen::DoLinkObjectInList(LLinkObjectInList* instr) {
- Register object = ToRegister(instr->object());
- ExternalReference sites_list_address = instr->GetReference(isolate());
-
- __ mov(ip, Operand(sites_list_address));
- __ ldr(ip, MemOperand(ip));
- __ str(ip, FieldMemOperand(object,
- instr->hydrogen()->store_field().offset()));
- __ mov(ip, Operand(sites_list_address));
- __ str(object, MemOperand(ip));
-}
-
-
void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
Register context = ToRegister(instr->context());
Register result = ToRegister(instr->result());
@@ -2995,6 +2998,13 @@
HObjectAccess access = instr->hydrogen()->access();
int offset = access.offset();
Register object = ToRegister(instr->object());
+
+ if (access.IsExternalMemory()) {
+ Register result = ToRegister(instr->result());
+ __ ldr(result, MemOperand(object, offset));
+ return;
+ }
+
if (instr->hydrogen()->representation().IsDouble()) {
DwVfpRegister result = ToDoubleRegister(instr->result());
__ vldr(result, FieldMemOperand(object, offset));
@@ -4174,10 +4184,15 @@
Register object = ToRegister(instr->object());
Register scratch = scratch0();
-
HObjectAccess access = instr->hydrogen()->access();
int offset = access.offset();
+ if (access.IsExternalMemory()) {
+ Register value = ToRegister(instr->value());
+ __ str(value, MemOperand(object, offset));
+ return;
+ }
+
Handle<Map> transition = instr->transition();
if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
@@ -4500,7 +4515,7 @@
// Write barrier.
__ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg,
scratch, GetLinkRegisterState(), kDontSaveFPRegs);
- } else if (FLAG_compiled_transitions) {
+ } else {
PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
__ Move(r0, object_reg);
__ Move(r1, to_map);
@@ -4508,28 +4523,6 @@
__ CallStub(&stub);
RecordSafepointWithRegisters(
instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
- } else if (IsFastSmiElementsKind(from_kind) &&
- IsFastDoubleElementsKind(to_kind)) {
- Register fixed_object_reg = ToRegister(instr->temp());
- ASSERT(fixed_object_reg.is(r2));
- Register new_map_reg = ToRegister(instr->new_map_temp());
- ASSERT(new_map_reg.is(r3));
- __ mov(new_map_reg, Operand(to_map));
- __ mov(fixed_object_reg, object_reg);
- CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(),
- RelocInfo::CODE_TARGET, instr);
- } else if (IsFastDoubleElementsKind(from_kind) &&
- IsFastObjectElementsKind(to_kind)) {
- Register fixed_object_reg = ToRegister(instr->temp());
- ASSERT(fixed_object_reg.is(r2));
- Register new_map_reg = ToRegister(instr->new_map_temp());
- ASSERT(new_map_reg.is(r3));
- __ mov(new_map_reg, Operand(to_map));
- __ mov(fixed_object_reg, object_reg);
- CallCode(isolate()->builtins()->TransitionElementsDoubleToObject(),
- RelocInfo::CODE_TARGET, instr);
- } else {
- UNREACHABLE();
}
__ bind(¬_applicable);
}
@@ -4652,13 +4645,6 @@
}
-void LCodeGen::DoStringLength(LStringLength* instr) {
- Register string = ToRegister(instr->string());
- Register result = ToRegister(instr->result());
- __ ldr(result, FieldMemOperand(string, String::kLengthOffset));
-}
-
-
void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
LOperand* input = instr->value();
ASSERT(input->IsRegister() || input->IsStackSlot());
@@ -5351,10 +5337,12 @@
if (instr->hydrogen()->MustAllocateDoubleAligned()) {
flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
}
- if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
- ASSERT(!instr->hydrogen()->CanAllocateInOldDataSpace());
+ if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
+ ASSERT(!instr->hydrogen()->IsOldDataSpaceAllocation());
+ ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
- } else if (instr->hydrogen()->CanAllocateInOldDataSpace()) {
+ } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
+ ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_DATA_SPACE);
}
@@ -5413,10 +5401,12 @@
__ Push(Smi::FromInt(size));
}
- if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
- ASSERT(!instr->hydrogen()->CanAllocateInOldDataSpace());
+ if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
+ ASSERT(!instr->hydrogen()->IsOldDataSpaceAllocation());
+ ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
CallRuntimeFromDeferred(Runtime::kAllocateInOldPointerSpace, 1, instr);
- } else if (instr->hydrogen()->CanAllocateInOldDataSpace()) {
+ } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
+ ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
CallRuntimeFromDeferred(Runtime::kAllocateInOldDataSpace, 1, instr);
} else {
CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr);
diff --git a/src/assembler.h b/src/assembler.h
index 481add5..d70d5aa 100644
--- a/src/assembler.h
+++ b/src/assembler.h
@@ -684,6 +684,8 @@
typedef void* ExternalReferenceRedirector(void* original, Type type);
+ ExternalReference() : address_(NULL) {}
+
ExternalReference(Builtins::CFunctionId id, Isolate* isolate);
ExternalReference(ApiFunction* ptr, Type type, Isolate* isolate);
@@ -829,7 +831,7 @@
static ExternalReference cpu_features();
- Address address() const {return reinterpret_cast<Address>(address_);}
+ Address address() const { return reinterpret_cast<Address>(address_); }
#ifdef ENABLE_DEBUGGER_SUPPORT
// Function Debug::Break()
@@ -868,6 +870,14 @@
static ExternalReference stress_deopt_count(Isolate* isolate);
+ bool operator==(const ExternalReference& other) const {
+ return address_ == other.address_;
+ }
+
+ bool operator!=(const ExternalReference& other) const {
+ return !(*this == other);
+ }
+
private:
explicit ExternalReference(void* address)
: address_(address) {}
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index dda5fe4..c2cc6ef 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -1525,6 +1525,7 @@
script_name,
0,
0,
+ false,
top_context,
extension,
NULL,
@@ -2079,6 +2080,11 @@
"native array-iterator.js") == 0) {
if (!CompileExperimentalBuiltin(isolate(), i)) return false;
}
+ if (FLAG_harmony_strings &&
+ strcmp(ExperimentalNatives::GetScriptName(i).start(),
+ "native harmony-string.js") == 0) {
+ if (!CompileExperimentalBuiltin(isolate(), i)) return false;
+ }
}
InstallExperimentalNativeFunctions();
diff --git a/src/builtins.cc b/src/builtins.cc
index eaba839..4a5cd03 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -1551,15 +1551,6 @@
}
-static void Generate_TransitionElementsSmiToDouble(MacroAssembler* masm) {
- KeyedStoreIC::GenerateTransitionElementsSmiToDouble(masm);
-}
-
-
-static void Generate_TransitionElementsDoubleToObject(MacroAssembler* masm) {
- KeyedStoreIC::GenerateTransitionElementsDoubleToObject(masm);
-}
-
#ifdef ENABLE_DEBUGGER_SUPPORT
static void Generate_LoadIC_DebugBreak(MacroAssembler* masm) {
Debug::GenerateLoadICDebugBreak(masm);
diff --git a/src/builtins.h b/src/builtins.h
index edf650d..73a2e96 100644
--- a/src/builtins.h
+++ b/src/builtins.h
@@ -194,10 +194,6 @@
kStrictMode) \
V(KeyedStoreIC_NonStrictArguments, KEYED_STORE_IC, MONOMORPHIC, \
Code::kNoExtraICState) \
- V(TransitionElementsSmiToDouble, BUILTIN, UNINITIALIZED, \
- Code::kNoExtraICState) \
- V(TransitionElementsDoubleToObject, BUILTIN, UNINITIALIZED, \
- Code::kNoExtraICState) \
\
/* Uses KeyedLoadIC_Initialize; must be after in list. */ \
V(FunctionCall, BUILTIN, UNINITIALIZED, \
diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc
index 651ce0a..235950d 100644
--- a/src/code-stubs-hydrogen.cc
+++ b/src/code-stubs-hydrogen.cc
@@ -136,7 +136,6 @@
isolate()->GetHTracer()->TraceCompilation(&info_);
}
- Zone* zone = this->zone();
int param_count = descriptor_->register_param_count_;
HEnvironment* start_environment = graph()->start_environment();
HBasicBlock* next_block = CreateBasicBlock(start_environment);
@@ -144,15 +143,13 @@
next_block->SetJoinId(BailoutId::StubEntry());
set_current_block(next_block);
- HConstant* undefined_constant = new(zone) HConstant(
- isolate()->factory()->undefined_value());
- AddInstruction(undefined_constant);
+ HConstant* undefined_constant =
+ Add<HConstant>(isolate()->factory()->undefined_value());
graph()->set_undefined_constant(undefined_constant);
for (int i = 0; i < param_count; ++i) {
HParameter* param =
- new(zone) HParameter(i, HParameter::REGISTER_PARAMETER);
- AddInstruction(param);
+ Add<HParameter>(i, HParameter::REGISTER_PARAMETER);
start_environment->Bind(i, param);
parameters_[i] = param;
}
@@ -160,9 +157,9 @@
HInstruction* stack_parameter_count;
if (descriptor_->stack_parameter_count_ != NULL) {
ASSERT(descriptor_->environment_length() == (param_count + 1));
- stack_parameter_count = new(zone) HParameter(param_count,
- HParameter::REGISTER_PARAMETER,
- Representation::Integer32());
+ stack_parameter_count = New<HParameter>(param_count,
+ HParameter::REGISTER_PARAMETER,
+ Representation::Integer32());
stack_parameter_count->set_type(HType::Smi());
// It's essential to bind this value to the environment in case of deopt.
AddInstruction(stack_parameter_count);
@@ -174,7 +171,7 @@
arguments_length_ = graph()->GetConstant0();
}
- context_ = new(zone) HContext();
+ context_ = New<HContext>();
AddInstruction(context_);
start_environment->BindContext(context_);
@@ -191,20 +188,18 @@
if (!stack_parameter_count->IsConstant() &&
descriptor_->hint_stack_parameter_count_ < 0) {
HInstruction* amount = graph()->GetConstant1();
- stack_pop_count = AddInstruction(
- HAdd::New(zone, context_, stack_parameter_count, amount));
+ stack_pop_count = Add<HAdd>(stack_parameter_count, amount);
stack_pop_count->ChangeRepresentation(Representation::Integer32());
stack_pop_count->ClearFlag(HValue::kCanOverflow);
} else {
int count = descriptor_->hint_stack_parameter_count_;
- stack_pop_count = AddInstruction(new(zone) HConstant(count));
+ stack_pop_count = Add<HConstant>(count);
}
}
if (current_block() != NULL) {
- HReturn* hreturn_instruction = new(zone) HReturn(return_value,
- context_,
- stack_pop_count);
+ HReturn* hreturn_instruction = New<HReturn>(return_value,
+ stack_pop_count);
current_block()->Finish(hreturn_instruction);
set_current_block(NULL);
}
@@ -322,9 +317,9 @@
if_number.Else();
// Convert the parameter to number using the builtin.
- HValue* function = AddLoadJSBuiltin(Builtins::TO_NUMBER, context());
+ HValue* function = AddLoadJSBuiltin(Builtins::TO_NUMBER);
Add<HPushArgument>(value);
- Push(Add<HInvokeFunction>(context(), function, 1));
+ Push(Add<HInvokeFunction>(function, 1));
if_number.End();
@@ -339,32 +334,30 @@
template <>
HValue* CodeStubGraphBuilder<FastCloneShallowArrayStub>::BuildCodeStub() {
- Zone* zone = this->zone();
Factory* factory = isolate()->factory();
HValue* undefined = graph()->GetConstantUndefined();
AllocationSiteMode alloc_site_mode = casted_stub()->allocation_site_mode();
FastCloneShallowArrayStub::Mode mode = casted_stub()->mode();
int length = casted_stub()->length();
- HInstruction* allocation_site =
- AddInstruction(new(zone) HLoadKeyed(GetParameter(0),
- GetParameter(1),
- NULL,
- FAST_ELEMENTS));
+ HInstruction* allocation_site = Add<HLoadKeyed>(GetParameter(0),
+ GetParameter(1),
+ static_cast<HValue*>(NULL),
+ FAST_ELEMENTS);
IfBuilder checker(this);
- checker.IfNot<HCompareObjectEqAndBranch, HValue*>(allocation_site, undefined);
+ checker.IfNot<HCompareObjectEqAndBranch, HValue*>(allocation_site,
+ undefined);
checker.Then();
HObjectAccess access = HObjectAccess::ForAllocationSiteTransitionInfo();
- HInstruction* boilerplate = AddLoad(allocation_site, access);
+ HInstruction* boilerplate = Add<HLoadNamedField>(allocation_site, access);
if (mode == FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS) {
HValue* elements = AddLoadElements(boilerplate);
IfBuilder if_fixed_cow(this);
if_fixed_cow.If<HCompareMap>(elements, factory->fixed_cow_array_map());
if_fixed_cow.Then();
- environment()->Push(BuildCloneShallowArray(context(),
- boilerplate,
+ environment()->Push(BuildCloneShallowArray(boilerplate,
allocation_site,
alloc_site_mode,
FAST_ELEMENTS,
@@ -374,23 +367,20 @@
IfBuilder if_fixed(this);
if_fixed.If<HCompareMap>(elements, factory->fixed_array_map());
if_fixed.Then();
- environment()->Push(BuildCloneShallowArray(context(),
- boilerplate,
+ environment()->Push(BuildCloneShallowArray(boilerplate,
allocation_site,
alloc_site_mode,
FAST_ELEMENTS,
length));
if_fixed.Else();
- environment()->Push(BuildCloneShallowArray(context(),
- boilerplate,
+ environment()->Push(BuildCloneShallowArray(boilerplate,
allocation_site,
alloc_site_mode,
FAST_DOUBLE_ELEMENTS,
length));
} else {
ElementsKind elements_kind = casted_stub()->ComputeElementsKind();
- environment()->Push(BuildCloneShallowArray(context(),
- boilerplate,
+ environment()->Push(BuildCloneShallowArray(boilerplate,
allocation_site,
alloc_site_mode,
elements_kind,
@@ -414,38 +404,33 @@
Zone* zone = this->zone();
HValue* undefined = graph()->GetConstantUndefined();
- HInstruction* boilerplate =
- AddInstruction(new(zone) HLoadKeyed(GetParameter(0),
- GetParameter(1),
- NULL,
- FAST_ELEMENTS));
+ HInstruction* boilerplate = Add<HLoadKeyed>(GetParameter(0),
+ GetParameter(1),
+ static_cast<HValue*>(NULL),
+ FAST_ELEMENTS);
IfBuilder checker(this);
- checker.IfNot<HCompareObjectEqAndBranch, HValue*>(boilerplate, undefined);
+ checker.IfNot<HCompareObjectEqAndBranch, HValue*>(boilerplate,
+ undefined);
checker.And();
int size = JSObject::kHeaderSize + casted_stub()->length() * kPointerSize;
HValue* boilerplate_size =
AddInstruction(new(zone) HInstanceSize(boilerplate));
- HValue* size_in_words =
- AddInstruction(new(zone) HConstant(size >> kPointerSizeLog2));
+ HValue* size_in_words = Add<HConstant>(size >> kPointerSizeLog2);
checker.If<HCompareNumericAndBranch>(boilerplate_size,
size_in_words, Token::EQ);
checker.Then();
- HValue* size_in_bytes = AddInstruction(new(zone) HConstant(size));
- HAllocate::Flags flags = HAllocate::CAN_ALLOCATE_IN_NEW_SPACE;
- if (isolate()->heap()->ShouldGloballyPretenure()) {
- flags = static_cast<HAllocate::Flags>(
- flags | HAllocate::CAN_ALLOCATE_IN_OLD_POINTER_SPACE);
- }
+ HValue* size_in_bytes = Add<HConstant>(size);
- HInstruction* object = AddInstruction(new(zone)
- HAllocate(context(), size_in_bytes, HType::JSObject(), flags));
+ HInstruction* object = Add<HAllocate>(size_in_bytes, HType::JSObject(),
+ isolate()->heap()->GetPretenureMode(), JS_OBJECT_TYPE);
for (int i = 0; i < size; i += kPointerSize) {
HObjectAccess access = HObjectAccess::ForJSObjectOffset(i);
- AddStore(object, access, AddLoad(boilerplate, access));
+ Add<HStoreNamedField>(object, access,
+ Add<HLoadNamedField>(boilerplate, access));
}
environment()->Push(object);
@@ -463,14 +448,9 @@
template <>
HValue* CodeStubGraphBuilder<CreateAllocationSiteStub>::BuildCodeStub() {
- Zone* zone = this->zone();
-
- HValue* size = AddInstruction(new(zone) HConstant(AllocationSite::kSize));
- HAllocate::Flags flags = HAllocate::DefaultFlags();
- flags = static_cast<HAllocate::Flags>(
- flags | HAllocate::CAN_ALLOCATE_IN_OLD_POINTER_SPACE);
- HInstruction* object = AddInstruction(new(zone)
- HAllocate(context(), size, HType::JSObject(), flags));
+ HValue* size = Add<HConstant>(AllocationSite::kSize);
+ HInstruction* object = Add<HAllocate>(size, HType::JSObject(), TENURED,
+ JS_OBJECT_TYPE);
// Store the map
Handle<Map> allocation_site_map(isolate()->heap()->allocation_site_map(),
@@ -478,14 +458,22 @@
AddStoreMapConstant(object, allocation_site_map);
// Store the payload (smi elements kind)
- HValue* initial_elements_kind = AddInstruction(new(zone) HConstant(
- GetInitialFastElementsKind()));
+ HValue* initial_elements_kind = Add<HConstant>(GetInitialFastElementsKind());
Add<HStoreNamedField>(object,
HObjectAccess::ForAllocationSiteTransitionInfo(),
initial_elements_kind);
- Add<HLinkObjectInList>(object, HObjectAccess::ForAllocationSiteWeakNext(),
- HLinkObjectInList::ALLOCATION_SITE_LIST);
+ // Link the object to the allocation site list
+ HValue* site_list = Add<HConstant>(
+ ExternalReference::allocation_sites_list_address(isolate()));
+ HValue* site = Add<HLoadNamedField>(site_list,
+ HObjectAccess::ForAllocationSiteList());
+ HStoreNamedField* store =
+ Add<HStoreNamedField>(object, HObjectAccess::ForAllocationSiteWeakNext(),
+ site);
+ store->SkipWriteBarrier();
+ Add<HStoreNamedField>(site_list, HObjectAccess::ForAllocationSiteList(),
+ object);
// We use a hammer (SkipWriteBarrier()) to indicate that we know the input
// cell is really a Cell, and so no write barrier is needed.
@@ -493,7 +481,7 @@
// a cell. (perhaps with a new instruction, HAssert).
HInstruction* cell = GetParameter(0);
HObjectAccess access = HObjectAccess::ForCellValue();
- HStoreNamedField* store = AddStore(cell, access, object);
+ store = Add<HStoreNamedField>(cell, access, object);
store->SkipWriteBarrier();
return cell;
}
@@ -590,14 +578,14 @@
ArgumentClass argument_class) {
HValue* constructor = GetParameter(ArrayConstructorStubBase::kConstructor);
if (context_mode == CONTEXT_CHECK_REQUIRED) {
- HInstruction* array_function = BuildGetArrayFunction(context());
+ HInstruction* array_function = BuildGetArrayFunction();
ArrayContextChecker checker(this, constructor, array_function);
}
HValue* property_cell = GetParameter(ArrayConstructorStubBase::kPropertyCell);
// Walk through the property cell to the AllocationSite
- HValue* alloc_site = AddInstruction(new(zone()) HLoadNamedField(property_cell,
- HObjectAccess::ForCellValue()));
+ HValue* alloc_site = Add<HLoadNamedField>(property_cell,
+ HObjectAccess::ForCellValue());
JSArrayBuilder array_builder(this, kind, alloc_site, constructor,
override_mode);
HValue* result = NULL;
@@ -645,19 +633,17 @@
HValue* constant_one = graph()->GetConstant1();
HValue* constant_zero = graph()->GetConstant0();
- HInstruction* elements = AddInstruction(
- new(zone()) HArgumentsElements(false));
+ HInstruction* elements = Add<HArgumentsElements>(false);
HInstruction* argument = AddInstruction(
new(zone()) HAccessArgumentsAt(elements, constant_one, constant_zero));
HConstant* max_alloc_length =
- new(zone()) HConstant(JSObject::kInitialMaxFastElementArray);
- AddInstruction(max_alloc_length);
+ Add<HConstant>(JSObject::kInitialMaxFastElementArray);
const int initial_capacity = JSArray::kPreallocatedArrayElements;
- HConstant* initial_capacity_node = new(zone()) HConstant(initial_capacity);
+ HConstant* initial_capacity_node = New<HConstant>(initial_capacity);
AddInstruction(initial_capacity_node);
- HBoundsCheck* checked_arg = Add<HBoundsCheck>(argument, max_alloc_length);
+ HInstruction* checked_arg = Add<HBoundsCheck>(argument, max_alloc_length);
IfBuilder if_builder(this);
if_builder.If<HCompareNumericAndBranch>(checked_arg, constant_zero,
Token::EQ);
@@ -697,12 +683,11 @@
LoopBuilder::kPostIncrement);
HValue* start = graph()->GetConstant0();
HValue* key = builder.BeginBody(start, length, Token::LT);
- HInstruction* argument_elements = AddInstruction(
- new(zone()) HArgumentsElements(false));
+ HInstruction* argument_elements = Add<HArgumentsElements>(false);
HInstruction* argument = AddInstruction(new(zone()) HAccessArgumentsAt(
argument_elements, length, key));
- AddInstruction(new(zone()) HStoreKeyed(elements, key, argument, kind));
+ Add<HStoreKeyed>(elements, key, argument, kind);
builder.EndBody();
return new_object;
}
@@ -825,8 +810,7 @@
// Prevent unwanted HChange being inserted to ensure that the stub
// deopts on newly encountered types.
if (!type->Maybe(Type::Double())) {
- input = AddInstruction(new(zone())
- HForceRepresentation(input, Representation::Smi()));
+ input = Add<HForceRepresentation>(input, Representation::Smi());
}
if (!type->Is(Type::Number())) {
@@ -838,9 +822,9 @@
HInstruction* res = BuildUnaryMathOp(input, type, stub->operation());
if_number.Return(AddInstruction(res));
if_number.Else();
- HValue* function = AddLoadJSBuiltin(stub->ToJSBuiltin(), context());
+ HValue* function = AddLoadJSBuiltin(stub->ToJSBuiltin());
Add<HPushArgument>(GetParameter(0));
- HValue* result = Add<HInvokeFunction>(context(), function, 1);
+ HValue* result = Add<HInvokeFunction>(function, 1);
if_number.Return(result);
if_number.End();
return graph()->GetConstantUndefined();
@@ -888,10 +872,9 @@
// Check that the map of the global has not changed: use a placeholder map
// that will be replaced later with the global object's map.
Handle<Map> placeholder_map = isolate()->factory()->meta_map();
- AddInstruction(HCheckMaps::New(
- receiver, placeholder_map, zone(), top_info()));
+ Add<HCheckMaps>(receiver, placeholder_map, top_info());
- HValue* cell = Add<HConstant>(placeholder_cell, Representation::Tagged());
+ HValue* cell = Add<HConstant>(placeholder_cell);
HObjectAccess access(HObjectAccess::ForCellPayload(isolate()));
HValue* cell_contents = Add<HLoadNamedField>(cell, access);
@@ -906,7 +889,7 @@
// property has been deleted and that the store must be handled by the
// runtime.
IfBuilder builder(this);
- HValue* hole_value = Add<HConstant>(hole, Representation::Tagged());
+ HValue* hole_value = Add<HConstant>(hole);
builder.If<HCompareObjectEqAndBranch>(cell_contents, hole_value);
builder.Then();
builder.Deopt();
diff --git a/src/code-stubs.cc b/src/code-stubs.cc
index 9d40ad0..5f6616e 100644
--- a/src/code-stubs.cc
+++ b/src/code-stubs.cc
@@ -818,44 +818,6 @@
}
-void ElementsTransitionAndStorePlatformStub::Generate(MacroAssembler* masm) {
- Label fail;
- AllocationSiteMode mode = AllocationSite::GetMode(from_, to_);
- ASSERT(!IsFastHoleyElementsKind(from_) || IsFastHoleyElementsKind(to_));
- if (!FLAG_trace_elements_transitions) {
- if (IsFastSmiOrObjectElementsKind(to_)) {
- if (IsFastSmiOrObjectElementsKind(from_)) {
- ElementsTransitionGenerator::
- GenerateMapChangeElementsTransition(masm, mode, &fail);
- } else if (IsFastDoubleElementsKind(from_)) {
- ASSERT(!IsFastSmiElementsKind(to_));
- ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, &fail);
- } else {
- UNREACHABLE();
- }
- KeyedStoreStubCompiler::GenerateStoreFastElement(masm,
- is_jsarray_,
- to_,
- store_mode_);
- } else if (IsFastSmiElementsKind(from_) &&
- IsFastDoubleElementsKind(to_)) {
- ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, &fail);
- KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(masm,
- is_jsarray_,
- store_mode_);
- } else if (IsFastDoubleElementsKind(from_)) {
- ASSERT(to_ == FAST_HOLEY_DOUBLE_ELEMENTS);
- ElementsTransitionGenerator::
- GenerateMapChangeElementsTransition(masm, mode, &fail);
- } else {
- UNREACHABLE();
- }
- }
- masm->bind(&fail);
- KeyedStoreIC::GenerateRuntimeSetProperty(masm, strict_mode_);
-}
-
-
void StubFailureTrampolineStub::GenerateAheadOfTime(Isolate* isolate) {
StubFailureTrampolineStub stub1(NOT_JS_FUNCTION_STUB_MODE);
StubFailureTrampolineStub stub2(JS_FUNCTION_STUB_MODE);
diff --git a/src/code-stubs.h b/src/code-stubs.h
index bc581d8..84d9b02 100644
--- a/src/code-stubs.h
+++ b/src/code-stubs.h
@@ -2310,48 +2310,6 @@
};
-// TODO(bmeurer) Remove this when compiled transitions is enabled
-class ElementsTransitionAndStorePlatformStub : public PlatformCodeStub {
- public:
- ElementsTransitionAndStorePlatformStub(ElementsKind from,
- ElementsKind to,
- bool is_jsarray,
- StrictModeFlag strict_mode,
- KeyedAccessStoreMode store_mode)
- : from_(from),
- to_(to),
- is_jsarray_(is_jsarray),
- strict_mode_(strict_mode),
- store_mode_(store_mode) {}
-
- private:
- class FromBits: public BitField<ElementsKind, 0, 8> {};
- class ToBits: public BitField<ElementsKind, 8, 8> {};
- class IsJSArrayBits: public BitField<bool, 16, 1> {};
- class StrictModeBits: public BitField<StrictModeFlag, 17, 1> {};
- class StoreModeBits: public BitField<KeyedAccessStoreMode, 18, 4> {};
-
- Major MajorKey() { return ElementsTransitionAndStore; }
- int MinorKey() {
- return FromBits::encode(from_) |
- ToBits::encode(to_) |
- IsJSArrayBits::encode(is_jsarray_) |
- StrictModeBits::encode(strict_mode_) |
- StoreModeBits::encode(store_mode_);
- }
-
- void Generate(MacroAssembler* masm);
-
- ElementsKind from_;
- ElementsKind to_;
- bool is_jsarray_;
- StrictModeFlag strict_mode_;
- KeyedAccessStoreMode store_mode_;
-
- DISALLOW_COPY_AND_ASSIGN(ElementsTransitionAndStorePlatformStub);
-};
-
-
class StoreArrayLiteralElementStub : public PlatformCodeStub {
public:
StoreArrayLiteralElementStub()
diff --git a/src/collection.js b/src/collection.js
index 63ddbbb..01537e8 100644
--- a/src/collection.js
+++ b/src/collection.js
@@ -47,7 +47,7 @@
if (%_IsConstructCall()) {
%SetInitialize(this);
} else {
- return new $Set();
+ throw MakeTypeError('constructor_not_function', ['Set']);
}
}
@@ -141,7 +141,7 @@
if (%_IsConstructCall()) {
%MapInitialize(this);
} else {
- return new $Map();
+ throw MakeTypeError('constructor_not_function', ['Map']);
}
}
@@ -243,7 +243,7 @@
if (%_IsConstructCall()) {
%WeakCollectionInitialize(this);
} else {
- return new $WeakMap();
+ throw MakeTypeError('constructor_not_function', ['WeakMap']);
}
}
@@ -335,7 +335,7 @@
if (%_IsConstructCall()) {
%WeakCollectionInitialize(this);
} else {
- return new $WeakSet();
+ throw MakeTypeError('constructor_not_function', ['WeakSet']);
}
}
diff --git a/src/compilation-cache.cc b/src/compilation-cache.cc
index 18c82e9..fffe5da 100644
--- a/src/compilation-cache.cc
+++ b/src/compilation-cache.cc
@@ -144,7 +144,8 @@
Handle<SharedFunctionInfo> function_info,
Handle<Object> name,
int line_offset,
- int column_offset) {
+ int column_offset,
+ bool is_shared_cross_origin) {
Handle<Script> script =
Handle<Script>(Script::cast(function_info->script()), isolate());
// If the script name isn't set, the boilerplate script should have
@@ -157,6 +158,8 @@
if (column_offset != script->column_offset()->value()) return false;
// Check that both names are strings. If not, no match.
if (!name->IsString() || !script->name()->IsString()) return false;
+ // Were both scripts tagged by the embedder as being shared cross-origin?
+ if (is_shared_cross_origin != script->is_shared_cross_origin()) return false;
// Compare the two name strings for equality.
return String::cast(*name)->Equals(String::cast(script->name()));
}
@@ -171,6 +174,7 @@
Handle<Object> name,
int line_offset,
int column_offset,
+ bool is_shared_cross_origin,
Handle<Context> context) {
Object* result = NULL;
int generation;
@@ -186,7 +190,11 @@
Handle<SharedFunctionInfo>::cast(probe);
// Break when we've found a suitable shared function info that
// matches the origin.
- if (HasOrigin(function_info, name, line_offset, column_offset)) {
+ if (HasOrigin(function_info,
+ name,
+ line_offset,
+ column_offset,
+ is_shared_cross_origin)) {
result = *function_info;
break;
}
@@ -214,7 +222,11 @@
if (result != NULL) {
Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result),
isolate());
- ASSERT(HasOrigin(shared, name, line_offset, column_offset));
+ ASSERT(HasOrigin(shared,
+ name,
+ line_offset,
+ column_offset,
+ is_shared_cross_origin));
// If the script was found in a later generation, we promote it to
// the first generation to let it survive longer in the cache.
if (generation != 0) Put(source, context, shared);
@@ -391,12 +403,18 @@
Handle<Object> name,
int line_offset,
int column_offset,
+ bool is_shared_cross_origin,
Handle<Context> context) {
if (!IsEnabled()) {
return Handle<SharedFunctionInfo>::null();
}
- return script_.Lookup(source, name, line_offset, column_offset, context);
+ return script_.Lookup(source,
+ name,
+ line_offset,
+ column_offset,
+ is_shared_cross_origin,
+ context);
}
diff --git a/src/compilation-cache.h b/src/compilation-cache.h
index 7a236e8..414e09e 100644
--- a/src/compilation-cache.h
+++ b/src/compilation-cache.h
@@ -99,6 +99,7 @@
Handle<Object> name,
int line_offset,
int column_offset,
+ bool is_shared_cross_origin,
Handle<Context> context);
void Put(Handle<String> source,
Handle<Context> context,
@@ -119,7 +120,8 @@
bool HasOrigin(Handle<SharedFunctionInfo> function_info,
Handle<Object> name,
int line_offset,
- int column_offset);
+ int column_offset,
+ bool is_shared_cross_origin);
void* script_histogram_;
bool script_histogram_initialized_;
@@ -212,6 +214,7 @@
Handle<Object> name,
int line_offset,
int column_offset,
+ bool is_shared_cross_origin,
Handle<Context> context);
// Finds the shared function info for a source string for eval in a
diff --git a/src/compiler.cc b/src/compiler.cc
index b5979bc..3c51baa 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -558,8 +558,7 @@
#ifdef ENABLE_DEBUGGER_SUPPORT
if (info->is_eval()) {
- Script::CompilationType compilation_type = Script::COMPILATION_TYPE_EVAL;
- script->set_compilation_type(Smi::FromInt(compilation_type));
+ script->set_compilation_type(Script::COMPILATION_TYPE_EVAL);
// For eval scripts add information on the function from which eval was
// called.
if (info->is_eval()) {
@@ -650,8 +649,7 @@
// the instances of the function.
SetExpectedNofPropertiesFromEstimate(result, lit->expected_property_count());
- script->set_compilation_state(
- Smi::FromInt(Script::COMPILATION_STATE_COMPILED));
+ script->set_compilation_state(Script::COMPILATION_STATE_COMPILED);
#ifdef ENABLE_DEBUGGER_SUPPORT
// Notify debugger
@@ -669,6 +667,7 @@
Handle<Object> script_name,
int line_offset,
int column_offset,
+ bool is_shared_cross_origin,
Handle<Context> context,
v8::Extension* extension,
ScriptDataImpl* pre_data,
@@ -691,6 +690,7 @@
script_name,
line_offset,
column_offset,
+ is_shared_cross_origin,
context);
}
@@ -714,6 +714,7 @@
script->set_line_offset(Smi::FromInt(line_offset));
script->set_column_offset(Smi::FromInt(column_offset));
}
+ script->set_is_shared_cross_origin(is_shared_cross_origin);
script->set_data(script_data.is_null() ? HEAP->undefined_value()
: *script_data);
diff --git a/src/compiler.h b/src/compiler.h
index 332d575..d36e488 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -572,6 +572,7 @@
Handle<Object> script_name,
int line_offset,
int column_offset,
+ bool is_shared_cross_origin,
Handle<Context> context,
v8::Extension* extension,
ScriptDataImpl* pre_data,
diff --git a/src/cpu-profiler-inl.h b/src/cpu-profiler-inl.h
index bafea06..868ec64 100644
--- a/src/cpu-profiler-inl.h
+++ b/src/cpu-profiler-inl.h
@@ -68,7 +68,6 @@
TickSample* ProfilerEventsProcessor::TickSampleEvent() {
- generator_->Tick();
TickSampleEventRecord* evt =
new(ticks_buffer_.Enqueue()) TickSampleEventRecord(last_code_event_id_);
return &evt->sample;
diff --git a/src/cpu-profiler.cc b/src/cpu-profiler.cc
index 0d226cf..0a83b85 100644
--- a/src/cpu-profiler.cc
+++ b/src/cpu-profiler.cc
@@ -452,9 +452,8 @@
CpuProfile* CpuProfiler::StopProfiling(const char* title) {
if (!is_profiling_) return NULL;
- const double actual_sampling_rate = generator_->actual_sampling_rate();
StopProcessorIfLastProfile(title);
- CpuProfile* result = profiles_->StopProfiling(title, actual_sampling_rate);
+ CpuProfile* result = profiles_->StopProfiling(title);
if (result != NULL) {
result->Print();
}
@@ -464,10 +463,9 @@
CpuProfile* CpuProfiler::StopProfiling(String* title) {
if (!is_profiling_) return NULL;
- const double actual_sampling_rate = generator_->actual_sampling_rate();
const char* profile_title = profiles_->GetName(title);
StopProcessorIfLastProfile(profile_title);
- return profiles_->StopProfiling(profile_title, actual_sampling_rate);
+ return profiles_->StopProfiling(profile_title);
}
diff --git a/src/cpu-profiler.h b/src/cpu-profiler.h
index 66e2b8b..cbe3e3c 100644
--- a/src/cpu-profiler.h
+++ b/src/cpu-profiler.h
@@ -184,7 +184,7 @@
} while (false)
-class CpuProfiler {
+class CpuProfiler : public CodeEventListener {
public:
explicit CpuProfiler(Isolate* isolate);
@@ -193,7 +193,7 @@
ProfileGenerator* test_generator,
ProfilerEventsProcessor* test_processor);
- ~CpuProfiler();
+ virtual ~CpuProfiler();
void StartProfiling(const char* title, bool record_samples = false);
void StartProfiling(String* title, bool record_samples);
@@ -209,30 +209,30 @@
// Must be called via PROFILE macro, otherwise will crash when
// profiling is not enabled.
- void CallbackEvent(Name* name, Address entry_point);
- void CodeCreateEvent(Logger::LogEventsAndTags tag,
- Code* code, const char* comment);
- void CodeCreateEvent(Logger::LogEventsAndTags tag,
- Code* code, Name* name);
- void CodeCreateEvent(Logger::LogEventsAndTags tag,
- Code* code,
- SharedFunctionInfo* shared,
- CompilationInfo* info,
- Name* name);
- void CodeCreateEvent(Logger::LogEventsAndTags tag,
- Code* code,
- SharedFunctionInfo* shared,
- CompilationInfo* info,
- Name* source, int line);
- void CodeCreateEvent(Logger::LogEventsAndTags tag,
- Code* code, int args_count);
- void CodeMovingGCEvent() {}
- void CodeMoveEvent(Address from, Address to);
- void CodeDeleteEvent(Address from);
- void GetterCallbackEvent(Name* name, Address entry_point);
- void RegExpCodeCreateEvent(Code* code, String* source);
- void SetterCallbackEvent(Name* name, Address entry_point);
- void SharedFunctionInfoMoveEvent(Address from, Address to);
+ virtual void CallbackEvent(Name* name, Address entry_point);
+ virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
+ Code* code, const char* comment);
+ virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
+ Code* code, Name* name);
+ virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
+ Code* code,
+ SharedFunctionInfo* shared,
+ CompilationInfo* info,
+ Name* name);
+ virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
+ Code* code,
+ SharedFunctionInfo* shared,
+ CompilationInfo* info,
+ Name* source, int line);
+ virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
+ Code* code, int args_count);
+ virtual void CodeMovingGCEvent() {}
+ virtual void CodeMoveEvent(Address from, Address to);
+ virtual void CodeDeleteEvent(Address from);
+ virtual void GetterCallbackEvent(Name* name, Address entry_point);
+ virtual void RegExpCodeCreateEvent(Code* code, String* source);
+ virtual void SetterCallbackEvent(Name* name, Address entry_point);
+ virtual void SharedFunctionInfoMoveEvent(Address from, Address to);
INLINE(bool is_profiling() const) { return is_profiling_; }
bool* is_profiling_address() {
diff --git a/src/d8.cc b/src/d8.cc
index 1efe2ae..cde8404 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -1562,7 +1562,14 @@
class ShellArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
public:
- virtual void* Allocate(size_t length) { return malloc(length); }
+ virtual void* Allocate(size_t length) {
+ void* result = malloc(length);
+ memset(result, 0, length);
+ return result;
+ }
+ virtual void* AllocateUninitialized(size_t length) {
+ return malloc(length);
+ }
virtual void Free(void* data) { free(data); }
};
diff --git a/src/debug.cc b/src/debug.cc
index 04f8a7a..a0b9884 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -786,6 +786,7 @@
function_info = Compiler::Compile(source_code,
script_name,
0, 0,
+ false,
context,
NULL, NULL,
Handle<String>::null(),
diff --git a/src/extensions/i18n/footer.js b/src/extensions/i18n/footer.js
index ac33f1e..adaa633 100644
--- a/src/extensions/i18n/footer.js
+++ b/src/extensions/i18n/footer.js
@@ -37,4 +37,4 @@
CLEANUP_RE.test('');
return Intl;
-}());
+}())});
diff --git a/src/extensions/i18n/header.js b/src/extensions/i18n/header.js
index 1c0a2d8..b854ce5 100644
--- a/src/extensions/i18n/header.js
+++ b/src/extensions/i18n/header.js
@@ -34,7 +34,7 @@
* Intl object is a single object that has some named properties,
* all of which are constructors.
*/
-var Intl = (function() {
+Object.defineProperty(this, "Intl", { enumerable: false, value: (function() {
'use strict';
diff --git a/src/factory.cc b/src/factory.cc
index b135a9c..c5a1fdd 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -453,13 +453,11 @@
script->set_data(heap->undefined_value());
script->set_context_data(heap->undefined_value());
script->set_type(Smi::FromInt(Script::TYPE_NORMAL));
- script->set_compilation_type(Smi::FromInt(Script::COMPILATION_TYPE_HOST));
- script->set_compilation_state(
- Smi::FromInt(Script::COMPILATION_STATE_INITIAL));
script->set_wrapper(*wrapper);
script->set_line_ends(heap->undefined_value());
script->set_eval_from_shared(heap->undefined_value());
script->set_eval_from_instructions_offset(Smi::FromInt(0));
+ script->set_flags(Smi::FromInt(0));
return script;
}
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 8888aed..5fc5d88 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -173,6 +173,7 @@
DEFINE_bool(harmony_iteration, false, "enable harmony iteration (for-of)")
DEFINE_bool(harmony_numeric_literals, false,
"enable harmony numeric literals (0o77, 0b11)")
+DEFINE_bool(harmony_strings, false, "enable harmony string")
DEFINE_bool(harmony, false, "enable all harmony features (except typeof)")
DEFINE_implication(harmony, harmony_scoping)
DEFINE_implication(harmony, harmony_modules)
@@ -183,6 +184,7 @@
DEFINE_implication(harmony, harmony_generators)
DEFINE_implication(harmony, harmony_iteration)
DEFINE_implication(harmony, harmony_numeric_literals)
+DEFINE_implication(harmony, harmony_strings)
DEFINE_implication(harmony_modules, harmony_scoping)
DEFINE_implication(harmony_observation, harmony_collections)
// TODO[dslomov] add harmony => harmony_typed_arrays
@@ -190,8 +192,6 @@
// Flags for experimental implementation features.
DEFINE_bool(packed_arrays, true, "optimizes arrays that have no holes")
DEFINE_bool(smi_only_arrays, true, "tracks arrays with only smi values")
-DEFINE_bool(compiled_transitions, true, "use optimizing compiler to "
- "generate array elements transition stubs")
DEFINE_bool(compiled_keyed_stores, true, "use optimizing compiler to "
"generate keyed store stubs")
DEFINE_bool(clever_optimizations,
@@ -744,11 +744,9 @@
DEFINE_bool(log_suspect, false, "Log suspect operations.")
DEFINE_bool(prof, false,
"Log statistical profiling information (implies --log-code).")
-DEFINE_bool(prof_auto, true,
- "Used with --prof, starts profiling automatically")
DEFINE_bool(prof_lazy, false,
"Used with --prof, only does sampling and logging"
- " when profiler is active (implies --noprof_auto).")
+ " when profiler is active.")
DEFINE_bool(prof_browser_mode, true,
"Used with --prof, turns on browser-compatible mode for profiling.")
DEFINE_bool(log_regexp, false, "Log regular expression execution.")
diff --git a/src/frames.cc b/src/frames.cc
index 61792a6..c17a9d5 100644
--- a/src/frames.cc
+++ b/src/frames.cc
@@ -1521,9 +1521,9 @@
FixedArray* array,
int offset,
int previous_handler_offset) const {
- STATIC_ASSERT(StackHandlerConstants::kSlotCount == 5);
+ STATIC_ASSERT(StackHandlerConstants::kSlotCount >= 5);
ASSERT_LE(0, offset);
- ASSERT_GE(array->length(), offset + 5);
+ ASSERT_GE(array->length(), offset + StackHandlerConstants::kSlotCount);
// Unwinding a stack handler into an array chains it in the opposite
// direction, re-using the "next" slot as a "previous" link, so that stack
// handlers can be later re-wound in the correct order. Decode the "state"
@@ -1542,9 +1542,9 @@
FixedArray* array,
int offset,
Address fp) {
- STATIC_ASSERT(StackHandlerConstants::kSlotCount == 5);
+ STATIC_ASSERT(StackHandlerConstants::kSlotCount >= 5);
ASSERT_LE(0, offset);
- ASSERT_GE(array->length(), offset + 5);
+ ASSERT_GE(array->length(), offset + StackHandlerConstants::kSlotCount);
Smi* prev_handler_offset = Smi::cast(array->get(offset));
Code* code = Code::cast(array->get(offset + 1));
Smi* smi_index = Smi::cast(array->get(offset + 2));
@@ -1560,7 +1560,7 @@
Memory::uintptr_at(address() + StackHandlerConstants::kStateOffset) = state;
Memory::Object_at(address() + StackHandlerConstants::kContextOffset) =
context;
- Memory::Address_at(address() + StackHandlerConstants::kFPOffset) = fp;
+ SetFp(address() + StackHandlerConstants::kFPOffset, fp);
*isolate->handler_address() = address();
diff --git a/src/frames.h b/src/frames.h
index 634ff8a..2bbbd98 100644
--- a/src/frames.h
+++ b/src/frames.h
@@ -145,6 +145,7 @@
inline Object** context_address() const;
inline Object** code_address() const;
+ inline void SetFp(Address slot, Address fp);
DISALLOW_IMPLICIT_CONSTRUCTORS(StackHandler);
};
@@ -176,7 +177,7 @@
static const int kContextOffset = -1 * kPointerSize;
static const int kCallerFPOffset = 0 * kPointerSize;
static const int kCallerPCOffset = +1 * kFPOnStackSize;
- static const int kCallerSPOffset = +2 * kPCOnStackSize;
+ static const int kCallerSPOffset = kCallerPCOffset + 1 * kPCOnStackSize;
};
diff --git a/src/harmony-string.js b/src/harmony-string.js
new file mode 100644
index 0000000..a5c6f4e
--- /dev/null
+++ b/src/harmony-string.js
@@ -0,0 +1,154 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+'use strict';
+
+// This file relies on the fact that the following declaration has been made
+// in runtime.js:
+// var $String = global.String;
+// var $Array = global.Array;
+
+// -------------------------------------------------------------------
+
+// ES6 draft 07-15-13, section 15.5.3.21
+function StringRepeat(count) {
+ if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+ throw MakeTypeError("called_on_null_or_undefined",
+ ["String.prototype.repeat"]);
+ }
+
+ var s = TO_STRING_INLINE(this);
+ var n = ToInteger(count);
+ if (n < 0 || !NUMBER_IS_FINITE(n)) {
+ throw MakeRangeError("invalid_count_value", []);
+ }
+
+ var elements = new InternalArray(n);
+ for (var i = 0; i < n; i++) {
+ elements[i] = s;
+ }
+
+ return %StringBuilderConcat(elements, n, "");
+}
+
+
+// ES6 draft 07-15-13, section 15.5.3.22
+function StringStartsWith(searchString /* position */) { // length == 1
+ if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+ throw MakeTypeError("called_on_null_or_undefined",
+ ["String.prototype.startsWith"]);
+ }
+
+ var s = TO_STRING_INLINE(this);
+ var ss = TO_STRING_INLINE(searchString);
+ var pos = 0;
+ if (%_ArgumentsLength() > 1) {
+ pos = %_Arguments(1); // position
+ pos = ToInteger(pos);
+ }
+
+ var s_len = s.length;
+ var start = MathMin(MathMax(pos, 0), s_len);
+ var ss_len = ss.length;
+ if (ss_len + start > s_len) {
+ return false;
+ }
+
+ return %StringIndexOf(s, ss, start) === start;
+}
+
+
+// ES6 draft 07-15-13, section 15.5.3.23
+function StringEndsWith(searchString /* position */) { // length == 1
+ if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+ throw MakeTypeError("called_on_null_or_undefined",
+ ["String.prototype.endsWith"]);
+ }
+
+ var s = TO_STRING_INLINE(this);
+ var ss = TO_STRING_INLINE(searchString);
+ var s_len = s.length;
+ var pos = s_len;
+ if (%_ArgumentsLength() > 1) {
+ var arg = %_Arguments(1); // position
+ if (!IS_UNDEFINED(arg)) {
+ pos = ToInteger(arg);
+ }
+ }
+
+ var end = MathMin(MathMax(pos, 0), s_len);
+ var ss_len = ss.length;
+ var start = end - ss_len;
+ if (start < 0) {
+ return false;
+ }
+
+ return %StringLastIndexOf(s, ss, start) === start;
+}
+
+
+// ES6 draft 07-15-13, section 15.5.3.24
+function StringContains(searchString /* position */) { // length == 1
+ if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
+ throw MakeTypeError("called_on_null_or_undefined",
+ ["String.prototype.contains"]);
+ }
+
+ var s = TO_STRING_INLINE(this);
+ var ss = TO_STRING_INLINE(searchString);
+ var pos = 0;
+ if (%_ArgumentsLength() > 1) {
+ pos = %_Arguments(1); // position
+ pos = ToInteger(pos);
+ }
+
+ var s_len = s.length;
+ var start = MathMin(MathMax(pos, 0), s_len);
+ var ss_len = ss.length;
+ if (ss_len + start > s_len) {
+ return false;
+ }
+
+ return %StringIndexOf(s, ss, start) !== -1;
+}
+
+
+// -------------------------------------------------------------------
+
+function ExtendStringPrototype() {
+ %CheckIsBootstrapping();
+
+ // Set up the non-enumerable functions on the String prototype object.
+ InstallFunctions($String.prototype, DONT_ENUM, $Array(
+ "repeat", StringRepeat,
+ "startsWith", StringStartsWith,
+ "endsWith", StringEndsWith,
+ "contains", StringContains
+ ));
+}
+
+ExtendStringPrototype();
\ No newline at end of file
diff --git a/src/heap.cc b/src/heap.cc
index 692ec21..c2a2707 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -3202,6 +3202,11 @@
}
set_frozen_symbol(Symbol::cast(obj));
+ { MaybeObject* maybe_obj = AllocateSymbol();
+ if (!maybe_obj->ToObject(&obj)) return false;
+ }
+ set_elements_transition_symbol(Symbol::cast(obj));
+
{ MaybeObject* maybe_obj = SeededNumberDictionary::Allocate(this, 0, TENURED);
if (!maybe_obj->ToObject(&obj)) return false;
}
@@ -6945,6 +6950,8 @@
external_string_table_.TearDown();
+ mark_compact_collector()->TearDown();
+
new_space_.TearDown();
if (old_pointer_space_ != NULL) {
diff --git a/src/heap.h b/src/heap.h
index fbe0531..672b8c1 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -178,7 +178,7 @@
V(Smi, last_script_id, LastScriptId) \
V(Script, empty_script, EmptyScript) \
V(Smi, real_stack_limit, RealStackLimit) \
- V(NameDictionary, intrinsic_function_names, IntrinsicFunctionNames) \
+ V(NameDictionary, intrinsic_function_names, IntrinsicFunctionNames) \
V(Smi, arguments_adaptor_deopt_pc_offset, ArgumentsAdaptorDeoptPCOffset) \
V(Smi, construct_stub_deopt_pc_offset, ConstructStubDeoptPCOffset) \
V(Smi, getter_stub_deopt_pc_offset, GetterStubDeoptPCOffset) \
@@ -186,6 +186,7 @@
V(JSObject, observation_state, ObservationState) \
V(Map, external_map, ExternalMap) \
V(Symbol, frozen_symbol, FrozenSymbol) \
+ V(Symbol, elements_transition_symbol, ElementsTransitionSymbol) \
V(SeededNumberDictionary, empty_slow_element_dictionary, \
EmptySlowElementDictionary) \
V(Symbol, observed_symbol, ObservedSymbol) \
@@ -482,6 +483,7 @@
INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE
};
+
class Heap {
public:
// Configure heap size before setup. Return false if the heap has been
@@ -1398,7 +1400,7 @@
// Finds out which space an object should get promoted to based on its type.
inline OldSpace* TargetSpace(HeapObject* object);
- inline AllocationSpace TargetSpaceId(InstanceType type);
+ static inline AllocationSpace TargetSpaceId(InstanceType type);
// Sets the stub_cache_ (only used when expanding the dictionary).
void public_set_code_stubs(UnseededNumberDictionary* value) {
@@ -1545,19 +1547,16 @@
MUST_USE_RESULT MaybeObject* AllocateRawFixedArray(int length,
PretenureFlag pretenure);
- // Predicate that governs global pre-tenuring decisions based on observed
- // promotion rates of previous collections.
- inline bool ShouldGloballyPretenure() {
- return FLAG_pretenuring && new_space_high_promotion_mode_active_;
- }
-
// This is only needed for testing high promotion mode.
void SetNewSpaceHighPromotionModeActive(bool mode) {
new_space_high_promotion_mode_active_ = mode;
}
+ // Returns the allocation mode (pre-tenuring) based on observed promotion
+ // rates of previous collections.
inline PretenureFlag GetPretenureMode() {
- return new_space_high_promotion_mode_active_ ? TENURED : NOT_TENURED;
+ return FLAG_pretenuring && new_space_high_promotion_mode_active_
+ ? TENURED : NOT_TENURED;
}
inline Address* NewSpaceHighPromotionModeActiveAddress() {
diff --git a/src/hydrogen-bce.cc b/src/hydrogen-bce.cc
index ff0b072..7c81ec1 100644
--- a/src/hydrogen-bce.cc
+++ b/src/hydrogen-bce.cc
@@ -260,12 +260,12 @@
HValue* index_context = IndexContext(*add, check);
if (index_context == NULL) return false;
- HConstant* new_constant = new(BasicBlock()->zone()) HConstant(
- new_offset, representation);
+ Zone* zone = BasicBlock()->zone();
+ HConstant* new_constant = HConstant::New(zone, index_context,
+ new_offset, representation);
if (*add == NULL) {
new_constant->InsertBefore(check);
- (*add) = HAdd::New(
- BasicBlock()->zone(), index_context, original_value, new_constant);
+ (*add) = HAdd::New(zone, index_context, original_value, new_constant);
(*add)->AssumeRepresentation(representation);
(*add)->InsertBefore(check);
} else {
diff --git a/src/hydrogen-bch.cc b/src/hydrogen-bch.cc
index 8646747..137d629 100644
--- a/src/hydrogen-bch.cc
+++ b/src/hydrogen-bch.cc
@@ -278,10 +278,12 @@
}
// Choose the appropriate limit.
+ Zone* zone = graph()->zone();
+ HValue* context = graph()->GetInvalidContext();
HValue* limit = data->limit();
if (has_upper_constant_limit) {
- HConstant* new_limit = new(pre_header->graph()->zone()) HConstant(
- upper_constant_limit, length->representation());
+ HConstant* new_limit = HConstant::New(zone, context,
+ upper_constant_limit);
new_limit->InsertBefore(pre_header->end());
limit = new_limit;
}
@@ -290,15 +292,15 @@
if (limit->IsInteger32Constant() &&
limit->block() != pre_header &&
!limit->block()->Dominates(pre_header)) {
- HConstant* new_limit = new(pre_header->graph()->zone()) HConstant(
- limit->GetInteger32Constant(), length->representation());
+ HConstant* new_limit = HConstant::New(zone, context,
+ limit->GetInteger32Constant());
new_limit->InsertBefore(pre_header->end());
limit = new_limit;
}
// Do the hoisting.
- HBoundsCheck* hoisted_check = new(pre_header->zone()) HBoundsCheck(
- limit, check->check()->length());
+ HBoundsCheck* hoisted_check = HBoundsCheck::New(
+ zone, context, limit, check->check()->length());
hoisted_check->InsertBefore(pre_header->end());
hoisted_check->set_allow_equality(true);
hoisted_check->block()->graph()->isolate()->counters()->
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index 5fe3af1..3eb4aa6 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -448,6 +448,7 @@
// Note: The c1visualizer syntax for locals allows only a sequence of the
// following characters: A-Za-z0-9_-|:
switch (type_) {
+ case kNone: return "none";
case kTagged: return "tagged";
case kTaggedPrimitive: return "primitive";
case kTaggedNumber: return "number";
@@ -458,7 +459,6 @@
case kNonPrimitive: return "non-primitive";
case kJSArray: return "array";
case kJSObject: return "object";
- case kUninitialized: return "uninitialized";
}
UNREACHABLE();
return "unreachable";
@@ -1091,12 +1091,13 @@
int actual_offset = decomposition.offset() + offset();
int actual_scale = decomposition.scale() + scale();
+ Zone* zone = block()->graph()->zone();
+ HValue* context = block()->graph()->GetInvalidContext();
if (actual_offset != 0) {
- HConstant* add_offset = new(block()->graph()->zone()) HConstant(
- actual_offset, index()->representation());
+ HConstant* add_offset = HConstant::New(zone, context, actual_offset);
add_offset->InsertBefore(this);
- HInstruction* add = HAdd::New(block()->graph()->zone(),
- block()->graph()->GetInvalidContext(), current_index, add_offset);
+ HInstruction* add = HAdd::New(zone, context,
+ current_index, add_offset);
add->InsertBefore(this);
add->AssumeRepresentation(index()->representation());
add->ClearFlag(kCanOverflow);
@@ -1104,11 +1105,10 @@
}
if (actual_scale != 0) {
- HConstant* sar_scale = new(block()->graph()->zone()) HConstant(
- actual_scale, index()->representation());
+ HConstant* sar_scale = HConstant::New(zone, context, actual_scale);
sar_scale->InsertBefore(this);
- HInstruction* sar = HSar::New(block()->graph()->zone(),
- block()->graph()->GetInvalidContext(), current_index, sar_scale);
+ HInstruction* sar = HSar::New(zone, context,
+ current_index, sar_scale);
sar->InsertBefore(this);
sar->AssumeRepresentation(index()->representation());
current_index = sar;
@@ -1612,8 +1612,8 @@
!HInstruction::cast(new_right)->IsLinked()) {
HInstruction::cast(new_right)->InsertBefore(this);
}
- HMathFloorOfDiv* instr = new(block()->zone())
- HMathFloorOfDiv(context(), new_left, new_right);
+ HMathFloorOfDiv* instr =
+ HMathFloorOfDiv::New(block()->zone(), context(), new_left, new_right);
// Replace this HMathFloor instruction by the new HMathFloorOfDiv.
instr->InsertBefore(this);
ReplaceAllUsesWith(instr);
@@ -1632,14 +1632,14 @@
HValue* HCheckInstanceType::Canonicalize() {
- if (check_ == IS_STRING &&
- !value()->type().IsUninitialized() &&
- value()->type().IsString()) {
- return NULL;
+ if (check_ == IS_STRING && value()->type().IsString()) {
+ return value();
}
if (check_ == IS_INTERNALIZED_STRING && value()->IsConstant()) {
- if (HConstant::cast(value())->HasInternalizedStringValue()) return NULL;
+ if (HConstant::cast(value())->HasInternalizedStringValue()) {
+ return value();
+ }
}
return this;
}
@@ -2131,8 +2131,8 @@
HValue* previous_index = first_check_in_block()->index();
ASSERT(context != NULL);
- set_added_constant(new(index_base->block()->graph()->zone()) HConstant(
- mask, index_base->representation()));
+ Zone* zone = index_base->block()->graph()->zone();
+ set_added_constant(HConstant::New(zone, context, mask));
if (added_index() != NULL) {
added_constant()->InsertBefore(added_index());
} else {
@@ -2141,9 +2141,8 @@
if (added_index() == NULL) {
first_check_in_block()->ReplaceAllUsesWith(first_check_in_block()->index());
- HInstruction* new_index = HBitwise::New(
- index_base->block()->graph()->zone(),
- token, context, index_base, added_constant());
+ HInstruction* new_index = HBitwise::New(zone, context, token, index_base,
+ added_constant());
ASSERT(new_index->IsBitwise());
new_index->ClearAllSideEffects();
new_index->AssumeRepresentation(Representation::Integer32());
@@ -2642,11 +2641,13 @@
HConstant::HConstant(Handle<Object> handle, Representation r)
- : handle_(handle),
+ : HTemplateInstruction<0>(HType::TypeFromValue(handle)),
+ handle_(handle),
unique_id_(),
has_smi_value_(false),
has_int32_value_(false),
has_double_value_(false),
+ has_external_reference_value_(false),
is_internalized_string_(false),
is_not_in_new_space_(true),
is_cell_(false),
@@ -2663,7 +2664,6 @@
double_value_ = n;
has_double_value_ = true;
} else {
- type_from_value_ = HType::TypeFromValue(handle_);
is_internalized_string_ = handle_->IsInternalizedString();
}
@@ -2681,18 +2681,18 @@
bool is_not_in_new_space,
bool is_cell,
bool boolean_value)
- : handle_(handle),
- unique_id_(unique_id),
- has_smi_value_(false),
- has_int32_value_(false),
- has_double_value_(false),
- is_internalized_string_(is_internalize_string),
- is_not_in_new_space_(is_not_in_new_space),
- is_cell_(is_cell),
- boolean_value_(boolean_value),
- type_from_value_(type) {
+ : HTemplateInstruction<0>(type),
+ handle_(handle),
+ unique_id_(unique_id),
+ has_smi_value_(false),
+ has_int32_value_(false),
+ has_double_value_(false),
+ has_external_reference_value_(false),
+ is_internalized_string_(is_internalize_string),
+ is_not_in_new_space_(is_not_in_new_space),
+ is_cell_(is_cell),
+ boolean_value_(boolean_value) {
ASSERT(!handle.is_null());
- ASSERT(!type.IsUninitialized());
ASSERT(!type.IsTaggedNumber());
Initialize(r);
}
@@ -2702,17 +2702,19 @@
Representation r,
bool is_not_in_new_space,
Handle<Object> optional_handle)
- : handle_(optional_handle),
- unique_id_(),
- has_int32_value_(true),
- has_double_value_(true),
- is_internalized_string_(false),
- is_not_in_new_space_(is_not_in_new_space),
- is_cell_(false),
- boolean_value_(integer_value != 0),
- int32_value_(integer_value),
- double_value_(FastI2D(integer_value)) {
- has_smi_value_ = Smi::IsValid(int32_value_);
+ : handle_(optional_handle),
+ unique_id_(),
+ has_smi_value_(Smi::IsValid(integer_value)),
+ has_int32_value_(true),
+ has_double_value_(true),
+ has_external_reference_value_(false),
+ is_internalized_string_(false),
+ is_not_in_new_space_(is_not_in_new_space),
+ is_cell_(false),
+ boolean_value_(integer_value != 0),
+ int32_value_(integer_value),
+ double_value_(FastI2D(integer_value)) {
+ set_type(has_smi_value_ ? HType::Smi() : HType::TaggedNumber());
Initialize(r);
}
@@ -2721,21 +2723,38 @@
Representation r,
bool is_not_in_new_space,
Handle<Object> optional_handle)
- : handle_(optional_handle),
- unique_id_(),
- has_int32_value_(IsInteger32(double_value)),
- has_double_value_(true),
- is_internalized_string_(false),
- is_not_in_new_space_(is_not_in_new_space),
- is_cell_(false),
- boolean_value_(double_value != 0 && !std::isnan(double_value)),
- int32_value_(DoubleToInt32(double_value)),
- double_value_(double_value) {
+ : handle_(optional_handle),
+ unique_id_(),
+ has_int32_value_(IsInteger32(double_value)),
+ has_double_value_(true),
+ has_external_reference_value_(false),
+ is_internalized_string_(false),
+ is_not_in_new_space_(is_not_in_new_space),
+ is_cell_(false),
+ boolean_value_(double_value != 0 && !std::isnan(double_value)),
+ int32_value_(DoubleToInt32(double_value)),
+ double_value_(double_value) {
has_smi_value_ = has_int32_value_ && Smi::IsValid(int32_value_);
+ set_type(has_smi_value_ ? HType::Smi() : HType::TaggedNumber());
Initialize(r);
}
+HConstant::HConstant(ExternalReference reference)
+ : HTemplateInstruction<0>(HType::None()),
+ has_smi_value_(false),
+ has_int32_value_(false),
+ has_double_value_(false),
+ has_external_reference_value_(true),
+ is_internalized_string_(false),
+ is_not_in_new_space_(true),
+ is_cell_(false),
+ boolean_value_(true),
+ external_reference_value_(reference) {
+ Initialize(Representation::External());
+}
+
+
void HConstant::Initialize(Representation r) {
if (r.IsNone()) {
if (has_smi_value_ && kSmiValueSize == 31) {
@@ -2744,6 +2763,8 @@
r = Representation::Integer32();
} else if (has_double_value_) {
r = Representation::Double();
+ } else if (has_external_reference_value_) {
+ r = Representation::External();
} else {
r = Representation::Tagged();
}
@@ -2768,17 +2789,21 @@
if (r.IsSmi() && !has_smi_value_) return NULL;
if (r.IsInteger32() && !has_int32_value_) return NULL;
if (r.IsDouble() && !has_double_value_) return NULL;
+ if (r.IsExternal() && !has_external_reference_value_) return NULL;
if (has_int32_value_) {
return new(zone) HConstant(int32_value_, r, is_not_in_new_space_, handle_);
}
if (has_double_value_) {
return new(zone) HConstant(double_value_, r, is_not_in_new_space_, handle_);
}
+ if (has_external_reference_value_) {
+ return new(zone) HConstant(external_reference_value_);
+ }
ASSERT(!handle_.is_null());
return new(zone) HConstant(handle_,
unique_id_,
r,
- type_from_value_,
+ type_,
is_internalized_string_,
is_not_in_new_space_,
is_cell_,
@@ -2826,6 +2851,9 @@
stream->Add("%d ", int32_value_);
} else if (has_double_value_) {
stream->Add("%f ", FmtElm(double_value_));
+ } else if (has_external_reference_value_) {
+ stream->Add("%p ", reinterpret_cast<void*>(
+ external_reference_value_.address()));
} else {
handle()->ShortPrint(stream);
}
@@ -3022,6 +3050,14 @@
}
+Range* HLoadNamedField::InferRange(Zone* zone) {
+ if (access().IsStringLength()) {
+ return new(zone) Range(0, String::kMaxLength);
+ }
+ return HValue::InferRange(zone);
+}
+
+
Range* HLoadKeyed::InferRange(Zone* zone) {
switch (elements_kind()) {
case EXTERNAL_PIXEL_ELEMENTS:
@@ -3254,9 +3290,10 @@
}
-HCheckMaps* HCheckMaps::New(HValue* value,
+HCheckMaps* HCheckMaps::New(Zone* zone,
+ HValue* context,
+ HValue* value,
Handle<Map> map,
- Zone* zone,
CompilationInfo* info,
HValue* typecheck) {
HCheckMaps* check_map = new(zone) HCheckMaps(value, zone, typecheck);
@@ -3270,39 +3307,6 @@
}
-HCheckMaps* HCheckMaps::NewWithTransitions(HValue* value,
- Handle<Map> map,
- Zone* zone,
- CompilationInfo* info) {
- HCheckMaps* check_map = new(zone) HCheckMaps(value, zone, value);
- check_map->map_set_.Add(map, zone);
-
- // Since transitioned elements maps of the initial map don't fail the map
- // check, the CheckMaps instruction doesn't need to depend on ElementsKinds.
- check_map->ClearGVNFlag(kDependsOnElementsKind);
-
- ElementsKind kind = map->elements_kind();
- bool packed = IsFastPackedElementsKind(kind);
- while (CanTransitionToMoreGeneralFastElementsKind(kind, packed)) {
- kind = GetNextMoreGeneralFastElementsKind(kind, packed);
- Map* transitioned_map =
- map->LookupElementsTransitionMap(kind);
- if (transitioned_map) {
- check_map->map_set_.Add(Handle<Map>(transitioned_map), zone);
- }
- };
-
- if (map->CanOmitMapChecks() &&
- value->IsConstant() &&
- HConstant::cast(value)->InstanceOf(map)) {
- check_map->omit(info);
- }
-
- check_map->map_set_.Sort();
- return check_map;
-}
-
-
void HCheckMaps::FinalizeUniqueValueId() {
if (!map_unique_ids_.is_empty()) return;
Zone* zone = block()->zone();
@@ -3475,8 +3479,13 @@
HForInCacheArray* index_cache =
names_cache->index_cache();
HCheckMapValue* map_check =
- new(block()->zone()) HCheckMapValue(object(), names_cache->map());
- HInstruction* index = new(block()->zone()) HLoadKeyed(
+ HCheckMapValue::New(block()->graph()->zone(),
+ block()->graph()->GetInvalidContext(),
+ object(),
+ names_cache->map());
+ HInstruction* index = HLoadKeyed::New(
+ block()->graph()->zone(),
+ block()->graph()->GetInvalidContext(),
index_cache,
key_load->key(),
key_load->key(),
@@ -3605,12 +3614,6 @@
}
-void HLinkObjectInList::PrintDataTo(StringStream* stream) {
- value()->PrintNameTo(stream);
- stream->Add(" offset %d", store_field_.offset());
-}
-
-
void HLoadContextSlot::PrintDataTo(StringStream* stream) {
value()->PrintNameTo(stream);
stream->Add("[%d]", slot_index());
@@ -3632,29 +3635,10 @@
}
-HType HCheckMaps::CalculateInferredType() {
- return value()->type();
-}
-
-
-HType HCheckFunction::CalculateInferredType() {
- return value()->type();
-}
-
-
-HType HCheckHeapObject::CalculateInferredType() {
- return HType::NonPrimitive();
-}
-
-
-HType HCheckSmi::CalculateInferredType() {
- return HType::Smi();
-}
-
-
HType HPhi::CalculateInferredType() {
- HType result = HType::Uninitialized();
- for (int i = 0; i < OperandCount(); ++i) {
+ if (OperandCount() == 0) return HType::Tagged();
+ HType result = OperandAt(0)->type();
+ for (int i = 1; i < OperandCount(); ++i) {
HType current = OperandAt(i)->type();
result = result.Combine(current);
}
@@ -3662,62 +3646,12 @@
}
-HType HConstant::CalculateInferredType() {
- if (has_int32_value_) {
- return Smi::IsValid(int32_value_) ? HType::Smi() : HType::HeapNumber();
- }
- if (has_double_value_) return HType::HeapNumber();
- ASSERT(!type_from_value_.IsUninitialized());
- return type_from_value_;
-}
-
-
-HType HCompareGeneric::CalculateInferredType() {
- return HType::Boolean();
-}
-
-
-HType HInstanceOf::CalculateInferredType() {
- return HType::Boolean();
-}
-
-
-HType HInstanceOfKnownGlobal::CalculateInferredType() {
- return HType::Boolean();
-}
-
-
HType HChange::CalculateInferredType() {
if (from().IsDouble() && to().IsTagged()) return HType::HeapNumber();
return type();
}
-HType HBitwiseBinaryOperation::CalculateInferredType() {
- return HType::TaggedNumber();
-}
-
-
-HType HArithmeticBinaryOperation::CalculateInferredType() {
- return HType::TaggedNumber();
-}
-
-
-HType HAdd::CalculateInferredType() {
- return HType::Tagged();
-}
-
-
-HType HBitNot::CalculateInferredType() {
- return HType::TaggedNumber();
-}
-
-
-HType HUnaryMathOperation::CalculateInferredType() {
- return HType::TaggedNumber();
-}
-
-
Representation HUnaryMathOperation::RepresentationFromInputs() {
Representation rep = representation();
// If any of the actual input representation is more general than what we
@@ -3728,11 +3662,6 @@
}
-HType HStringCharFromCode::CalculateInferredType() {
- return HType::String();
-}
-
-
void HAllocate::HandleSideEffectDominator(GVNFlag side_effect,
HValue* dominator) {
ASSERT(side_effect == kChangesNewSpacePromotion);
@@ -3752,8 +3681,8 @@
HValue* current_size = size();
// We can just fold allocations that are guaranteed in new space.
// TODO(hpayer): Add support for non-constant allocation in dominator.
- if (!GuaranteedInNewSpace() || !current_size->IsInteger32Constant() ||
- !dominator_allocate_instr->GuaranteedInNewSpace() ||
+ if (!IsNewSpaceAllocation() || !current_size->IsInteger32Constant() ||
+ !dominator_allocate_instr->IsNewSpaceAllocation() ||
!dominator_size->IsInteger32Constant()) {
if (FLAG_trace_allocation_folding) {
PrintF("#%d (%s) cannot fold into #%d (%s)\n",
@@ -3771,7 +3700,7 @@
if (MustAllocateDoubleAligned()) {
if (!dominator_allocate_instr->MustAllocateDoubleAligned()) {
- dominator_allocate_instr->SetFlags(HAllocate::ALLOCATE_DOUBLE_ALIGNED);
+ dominator_allocate_instr->MakeDoubleAligned();
}
if ((dominator_size_constant & kDoubleAlignmentMask) != 0) {
dominator_size_constant += kDoubleSize / 2;
@@ -3789,22 +3718,24 @@
}
HBasicBlock* block = dominator->block();
Zone* zone = block->zone();
- HInstruction* new_dominator_size_constant = new(zone) HConstant(
- new_dominator_size);
+ HInstruction* new_dominator_size_constant =
+ HConstant::New(zone, context(), new_dominator_size);
new_dominator_size_constant->InsertBefore(dominator_allocate_instr);
dominator_allocate_instr->UpdateSize(new_dominator_size_constant);
#ifdef VERIFY_HEAP
if (FLAG_verify_heap) {
- dominator_allocate_instr->SetFlags(HAllocate::PREFILL_WITH_FILLER);
+ dominator_allocate_instr->MakePrefillWithFiller();
}
#endif
// After that replace the dominated allocate instruction.
HInstruction* dominated_allocate_instr =
- new(zone) HInnerAllocatedObject(dominator_allocate_instr,
- dominator_size_constant,
- type());
+ HInnerAllocatedObject::New(zone,
+ context(),
+ dominator_allocate_instr,
+ dominator_size_constant,
+ type());
dominated_allocate_instr->InsertBefore(this);
DeleteAndReplaceWith(dominated_allocate_instr);
if (FLAG_trace_allocation_folding) {
@@ -3816,17 +3747,13 @@
void HAllocate::PrintDataTo(StringStream* stream) {
size()->PrintNameTo(stream);
- if (!GuaranteedInNewSpace()) stream->Add(" (pretenure)");
-}
-
-
-HType HRegExpLiteral::CalculateInferredType() {
- return HType::JSObject();
-}
-
-
-HType HFunctionLiteral::CalculateInferredType() {
- return HType::JSObject();
+ stream->Add(" (");
+ if (IsNewSpaceAllocation()) stream->Add("N");
+ if (IsOldPointerSpaceAllocation()) stream->Add("P");
+ if (IsOldDataSpaceAllocation()) stream->Add("D");
+ if (MustAllocateDoubleAligned()) stream->Add("A");
+ if (MustPrefillWithFiller()) stream->Add("F");
+ stream->Add(")");
}
@@ -3952,10 +3879,10 @@
}
-#define H_CONSTANT_INT(val) \
-new(zone) HConstant(static_cast<int32_t>(val))
+#define H_CONSTANT_INT(val) \
+HConstant::New(zone, context, static_cast<int32_t>(val))
#define H_CONSTANT_DOUBLE(val) \
-new(zone) HConstant(static_cast<double>(val), Representation::Double())
+HConstant::New(zone, context, static_cast<double>(val))
#define DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR(HInstr, op) \
HInstruction* HInstr::New( \
@@ -3966,7 +3893,7 @@
if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { \
double double_res = c_left->DoubleValue() op c_right->DoubleValue(); \
if (TypeInfo::IsInt32Double(double_res)) { \
- return H_CONSTANT_INT(double_res); \
+ return H_CONSTANT_INT(double_res); \
} \
return H_CONSTANT_DOUBLE(double_res); \
} \
@@ -3993,7 +3920,7 @@
if (c_left->HasStringValue() && c_right->HasStringValue()) {
Handle<String> concat = zone->isolate()->factory()->NewFlatConcatString(
c_left->StringValue(), c_right->StringValue());
- return new(zone) HConstant(concat, Representation::Tagged());
+ return HConstant::New(zone, context, concat);
}
}
return new(zone) HStringAdd(context, left, right, flags);
@@ -4008,29 +3935,16 @@
if (c_code->HasNumberValue()) {
if (std::isfinite(c_code->DoubleValue())) {
uint32_t code = c_code->NumberValueAsInteger32() & 0xffff;
- return new(zone) HConstant(LookupSingleCharacterStringFromCode(isolate,
- code),
- Representation::Tagged());
+ return HConstant::New(zone, context,
+ LookupSingleCharacterStringFromCode(isolate, code));
}
- return new(zone) HConstant(isolate->factory()->empty_string(),
- Representation::Tagged());
+ return HConstant::New(zone, context, isolate->factory()->empty_string());
}
}
return new(zone) HStringCharFromCode(context, char_code);
}
-HInstruction* HStringLength::New(Zone* zone, HValue* string) {
- if (FLAG_fold_constants && string->IsConstant()) {
- HConstant* c_string = HConstant::cast(string);
- if (c_string->HasStringValue()) {
- return new(zone) HConstant(c_string->StringValue()->length());
- }
- }
- return new(zone) HStringLength(string);
-}
-
-
HInstruction* HUnaryMathOperation::New(
Zone* zone, HValue* context, HValue* value, BuiltinFunctionId op) {
do {
@@ -4099,7 +4013,10 @@
}
-HInstruction* HPower::New(Zone* zone, HValue* left, HValue* right) {
+HInstruction* HPower::New(Zone* zone,
+ HValue* context,
+ HValue* left,
+ HValue* right) {
if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) {
HConstant* c_left = HConstant::cast(left);
HConstant* c_right = HConstant::cast(right);
@@ -4198,7 +4115,7 @@
HInstruction* HBitwise::New(
- Zone* zone, Token::Value op, HValue* context, HValue* left, HValue* right) {
+ Zone* zone, HValue* context, Token::Value op, HValue* left, HValue* right) {
if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) {
HConstant* c_left = HConstant::cast(left);
HConstant* c_right = HConstant::cast(right);
@@ -4223,7 +4140,7 @@
return H_CONSTANT_INT(result);
}
}
- return new(zone) HBitwise(op, context, left, right);
+ return new(zone) HBitwise(context, op, left, right);
}
@@ -4292,7 +4209,8 @@
continue;
} else if (operand->HasDoubleValue()) {
HConstant* integer_input =
- new(graph->zone()) HConstant(DoubleToInt32(operand->DoubleValue()));
+ HConstant::New(graph->zone(), graph->GetInvalidContext(),
+ DoubleToInt32(operand->DoubleValue()));
integer_input->InsertAfter(operand);
SetOperandAt(i, integer_input);
} else if (operand == graph->GetConstantTrue()) {
@@ -4361,7 +4279,11 @@
// We check for observed_input_representation elsewhere.
Representation use_rep =
it.value()->RequiredInputRepresentation(it.index());
- if (!use_rep.IsNone() && !use_rep.IsSmi()) return true;
+ if (!use_rep.IsNone() &&
+ !use_rep.IsSmi() &&
+ !use_rep.IsTagged()) {
+ return true;
+ }
}
return false;
}
@@ -4500,6 +4422,10 @@
instr->SetGVNFlag(is_store
? kChangesArrayLengths : kDependsOnArrayLengths);
break;
+ case kStringLengths:
+ instr->SetGVNFlag(is_store
+ ? kChangesStringLengths : kDependsOnStringLengths);
+ break;
case kInobject:
instr->SetGVNFlag(is_store
? kChangesInobjectFields : kDependsOnInobjectFields);
@@ -4520,6 +4446,10 @@
instr->SetGVNFlag(is_store
? kChangesMaps : kDependsOnMaps);
break;
+ case kExternalMemory:
+ instr->SetGVNFlag(is_store
+ ? kChangesExternalMemory : kDependsOnExternalMemory);
+ break;
}
}
@@ -4529,6 +4459,7 @@
switch (portion()) {
case kArrayLengths:
+ case kStringLengths:
stream->Add("%length");
break;
case kElementsPointer:
@@ -4546,6 +4477,9 @@
if (!name_.is_null()) stream->Add(*String::cast(*name_)->ToCString());
stream->Add("[backing-store]");
break;
+ case kExternalMemory:
+ stream->Add("[external-memory]");
+ break;
}
stream->Add("@%d", offset());
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index 40bbc90..eac5173 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -135,7 +135,6 @@
V(IsSmiAndBranch) \
V(IsUndetectableAndBranch) \
V(LeaveInlined) \
- V(LinkObjectInList) \
V(LoadContextSlot) \
V(LoadExternalArrayPointer) \
V(LoadFieldByIndex) \
@@ -179,7 +178,6 @@
V(StringCharCodeAt) \
V(StringCharFromCode) \
V(StringCompareAndBranch) \
- V(StringLength) \
V(Sub) \
V(ThisFunction) \
V(Throw) \
@@ -201,6 +199,7 @@
#define GVN_UNTRACKED_FLAG_LIST(V) \
V(ArrayElements) \
V(ArrayLengths) \
+ V(StringLengths) \
V(BackingStoreFields) \
V(Calls) \
V(ContextSlots) \
@@ -211,7 +210,7 @@
V(GlobalVars) \
V(InobjectFields) \
V(OsrEntries) \
- V(SpecializedArrayElements)
+ V(ExternalMemory)
#define DECLARE_ABSTRACT_INSTRUCTION(type) \
@@ -350,8 +349,7 @@
class HType {
public:
- HType() : type_(kUninitialized) { }
-
+ static HType None() { return HType(kNone); }
static HType Tagged() { return HType(kTagged); }
static HType TaggedPrimitive() { return HType(kTaggedPrimitive); }
static HType TaggedNumber() { return HType(kTaggedNumber); }
@@ -362,7 +360,6 @@
static HType NonPrimitive() { return HType(kNonPrimitive); }
static HType JSArray() { return HType(kJSArray); }
static HType JSObject() { return HType(kJSObject); }
- static HType Uninitialized() { return HType(kUninitialized); }
// Return the weakest (least precise) common type.
HType Combine(HType other) {
@@ -378,32 +375,26 @@
}
bool IsTagged() const {
- ASSERT(type_ != kUninitialized);
return ((type_ & kTagged) == kTagged);
}
bool IsTaggedPrimitive() const {
- ASSERT(type_ != kUninitialized);
return ((type_ & kTaggedPrimitive) == kTaggedPrimitive);
}
bool IsTaggedNumber() const {
- ASSERT(type_ != kUninitialized);
return ((type_ & kTaggedNumber) == kTaggedNumber);
}
bool IsSmi() const {
- ASSERT(type_ != kUninitialized);
return ((type_ & kSmi) == kSmi);
}
bool IsHeapNumber() const {
- ASSERT(type_ != kUninitialized);
return ((type_ & kHeapNumber) == kHeapNumber);
}
bool IsString() const {
- ASSERT(type_ != kUninitialized);
return ((type_ & kString) == kString);
}
@@ -413,32 +404,41 @@
}
bool IsBoolean() const {
- ASSERT(type_ != kUninitialized);
return ((type_ & kBoolean) == kBoolean);
}
bool IsNonPrimitive() const {
- ASSERT(type_ != kUninitialized);
return ((type_ & kNonPrimitive) == kNonPrimitive);
}
bool IsJSArray() const {
- ASSERT(type_ != kUninitialized);
return ((type_ & kJSArray) == kJSArray);
}
bool IsJSObject() const {
- ASSERT(type_ != kUninitialized);
return ((type_ & kJSObject) == kJSObject);
}
- bool IsUninitialized() const {
- return type_ == kUninitialized;
+ bool IsHeapObject() const {
+ return IsHeapNumber() || IsString() || IsBoolean() || IsNonPrimitive();
}
- bool IsHeapObject() const {
- ASSERT(type_ != kUninitialized);
- return IsHeapNumber() || IsString() || IsBoolean() || IsNonPrimitive();
+ bool ToStringOrToNumberCanBeObserved(Representation representation) {
+ switch (type_) {
+ case kTaggedPrimitive: // fallthru
+ case kTaggedNumber: // fallthru
+ case kSmi: // fallthru
+ case kHeapNumber: // fallthru
+ case kString: // fallthru
+ case kBoolean:
+ return false;
+ case kJSArray: // fallthru
+ case kJSObject:
+ return true;
+ case kTagged:
+ break;
+ }
+ return !representation.IsSmiOrInteger32() && !representation.IsDouble();
}
static HType TypeFromValue(Handle<Object> value);
@@ -447,6 +447,7 @@
private:
enum Type {
+ kNone = 0x0, // 0000 0000 0000 0000
kTagged = 0x1, // 0000 0000 0000 0001
kTaggedPrimitive = 0x5, // 0000 0000 0000 0101
kTaggedNumber = 0xd, // 0000 0000 0000 1101
@@ -456,12 +457,11 @@
kBoolean = 0x85, // 0000 0000 1000 0101
kNonPrimitive = 0x101, // 0000 0001 0000 0001
kJSObject = 0x301, // 0000 0011 0000 0001
- kJSArray = 0x701, // 0000 0111 0000 0001
- kUninitialized = 0x1fff // 0001 1111 1111 1111
+ kJSArray = 0x701 // 0000 0111 0000 0001
};
// Make sure type fits in int16.
- STATIC_ASSERT(kUninitialized < (1 << (2 * kBitsPerByte)));
+ STATIC_ASSERT(kJSArray < (1 << (2 * kBitsPerByte)));
explicit HType(Type t) : type_(t) { }
@@ -872,12 +872,13 @@
HYDROGEN_ABSTRACT_INSTRUCTION_LIST(DECLARE_PREDICATE)
#undef DECLARE_PREDICATE
- HValue() : block_(NULL),
- id_(kNoNumber),
- type_(HType::Tagged()),
- use_list_(NULL),
- range_(NULL),
- flags_(0) {}
+ HValue(HType type = HType::Tagged())
+ : block_(NULL),
+ id_(kNoNumber),
+ type_(type),
+ use_list_(NULL),
+ range_(NULL),
+ flags_(0) {}
virtual ~HValue() {}
HBasicBlock* block() const { return block_; }
@@ -1145,6 +1146,18 @@
}
}
+ // Returns true conservatively if the program might be able to observe a
+ // ToString() operation on this value.
+ bool ToStringCanBeObserved() const {
+ return type().ToStringOrToNumberCanBeObserved(representation());
+ }
+
+ // Returns true conservatively if the program might be able to observe a
+ // ToNumber() operation on this value.
+ bool ToNumberCanBeObserved() const {
+ return type().ToStringOrToNumberCanBeObserved(representation());
+ }
+
protected:
void TryGuaranteeRangeRecursive(RangeEvaluationContext* context);
@@ -1295,6 +1308,48 @@
};
+#define DECLARE_INSTRUCTION_FACTORY_P0(I) \
+ static I* New(Zone* zone, HValue* context) { \
+ return new(zone) I(); \
+}
+
+#define DECLARE_INSTRUCTION_FACTORY_P1(I, P1) \
+ static I* New(Zone* zone, HValue* context, P1 p1) { \
+ return new(zone) I(p1); \
+ }
+
+#define DECLARE_INSTRUCTION_FACTORY_P2(I, P1, P2) \
+ static I* New(Zone* zone, HValue* context, P1 p1, P2 p2) { \
+ return new(zone) I(p1, p2); \
+ }
+
+#define DECLARE_INSTRUCTION_FACTORY_P3(I, P1, P2, P3) \
+ static I* New(Zone* zone, HValue* context, P1 p1, P2 p2, P3 p3) { \
+ return new(zone) I(p1, p2, p3); \
+ }
+
+#define DECLARE_INSTRUCTION_FACTORY_P4(I, P1, P2, P3, P4) \
+ static I* New(Zone* zone, \
+ HValue* context, \
+ P1 p1, \
+ P2 p2, \
+ P3 p3, \
+ P4 p4) { \
+ return new(zone) I(p1, p2, p3, p4); \
+ }
+
+#define DECLARE_INSTRUCTION_FACTORY_P5(I, P1, P2, P3, P4, P5) \
+ static I* New(Zone* zone, \
+ HValue* context, \
+ P1 p1, \
+ P2 p2, \
+ P3 p3, \
+ P4 p4, \
+ P5 p5) { \
+ return new(zone) I(p1, p2, p3, p4, p5); \
+ }
+
+
class HInstruction: public HValue {
public:
HInstruction* next() const { return next_; }
@@ -1330,8 +1385,9 @@
DECLARE_ABSTRACT_INSTRUCTION(Instruction)
protected:
- HInstruction()
- : next_(NULL),
+ HInstruction(HType type = HType::Tagged())
+ : HValue(type),
+ next_(NULL),
previous_(NULL),
position_(RelocInfo::kNoPosition) {
SetGVNFlag(kDependsOnOsrEntries);
@@ -1362,6 +1418,8 @@
HValue* OperandAt(int i) const { return inputs_[i]; }
protected:
+ HTemplateInstruction(HType type = HType::Tagged()) : HInstruction(type) {}
+
void InternalSetOperandAt(int i, HValue* value) { inputs_[i] = value; }
private:
@@ -1435,12 +1493,12 @@
class HDummyUse: public HTemplateInstruction<1> {
public:
- explicit HDummyUse(HValue* value) {
+ explicit HDummyUse(HValue* value)
+ : HTemplateInstruction<1>(HType::Smi()) {
SetOperandAt(0, value);
// Pretend to be a Smi so that the HChange instructions inserted
// before any use generate as little code as possible.
set_representation(Representation::Tagged());
- set_type(HType::Smi());
}
HValue* value() { return OperandAt(0); }
@@ -1504,7 +1562,7 @@
class HDeoptimize: public HTemplateInstruction<0> {
public:
- explicit HDeoptimize(Deoptimizer::BailoutType type) : type_(type) {}
+ DECLARE_INSTRUCTION_FACTORY_P1(HDeoptimize, Deoptimizer::BailoutType);
virtual Representation RequiredInputRepresentation(int index) {
return Representation::None();
@@ -1515,6 +1573,8 @@
DECLARE_CONCRETE_INSTRUCTION(Deoptimize)
private:
+ explicit HDeoptimize(Deoptimizer::BailoutType type) : type_(type) {}
+
Deoptimizer::BailoutType type_;
};
@@ -1615,12 +1675,44 @@
};
+class HContext: public HTemplateInstruction<0> {
+ public:
+ static HContext* New(Zone* zone) {
+ return new(zone) HContext();
+ }
+
+ virtual Representation RequiredInputRepresentation(int index) {
+ return Representation::None();
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(Context)
+
+ protected:
+ virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+ HContext() {
+ set_representation(Representation::Tagged());
+ SetFlag(kUseGVN);
+ }
+
+ virtual bool IsDeletable() const { return true; }
+};
+
+
class HReturn: public HTemplateControlInstruction<0, 3> {
public:
- HReturn(HValue* value, HValue* context, HValue* parameter_count) {
- SetOperandAt(0, value);
- SetOperandAt(1, context);
- SetOperandAt(2, parameter_count);
+ static HInstruction* New(Zone* zone,
+ HValue* context,
+ HValue* value,
+ HValue* parameter_count) {
+ return new(zone) HReturn(value, context, parameter_count);
+ }
+
+ static HInstruction* New(Zone* zone,
+ HValue* context,
+ HValue* value) {
+ return new(zone) HReturn(value, context, 0);
}
virtual Representation RequiredInputRepresentation(int index) {
@@ -1634,6 +1726,13 @@
HValue* parameter_count() { return OperandAt(2); }
DECLARE_CONCRETE_INSTRUCTION(Return)
+
+ private:
+ HReturn(HValue* value, HValue* context, HValue* parameter_count) {
+ SetOperandAt(0, value);
+ SetOperandAt(1, context);
+ SetOperandAt(2, parameter_count);
+ }
};
@@ -1649,7 +1748,8 @@
class HUnaryOperation: public HTemplateInstruction<1> {
public:
- explicit HUnaryOperation(HValue* value) {
+ HUnaryOperation(HValue* value, HType type = HType::Tagged())
+ : HTemplateInstruction<1>(type) {
SetOperandAt(0, value);
}
@@ -1664,10 +1764,10 @@
class HThrow: public HTemplateInstruction<2> {
public:
- HThrow(HValue* context, HValue* value) {
- SetOperandAt(0, context);
- SetOperandAt(1, value);
- SetAllSideEffects();
+ static HThrow* New(Zone* zone,
+ HValue* context,
+ HValue* value) {
+ return new(zone) HThrow(context, value);
}
virtual Representation RequiredInputRepresentation(int index) {
@@ -1678,27 +1778,34 @@
HValue* value() { return OperandAt(1); }
DECLARE_CONCRETE_INSTRUCTION(Throw)
+
+ private:
+ HThrow(HValue* context, HValue* value) {
+ SetOperandAt(0, context);
+ SetOperandAt(1, value);
+ SetAllSideEffects();
+ }
};
class HUseConst: public HUnaryOperation {
public:
- explicit HUseConst(HValue* old_value) : HUnaryOperation(old_value) { }
+ DECLARE_INSTRUCTION_FACTORY_P1(HUseConst, HValue*);
virtual Representation RequiredInputRepresentation(int index) {
return Representation::None();
}
DECLARE_CONCRETE_INSTRUCTION(UseConst)
+
+ private:
+ explicit HUseConst(HValue* old_value) : HUnaryOperation(old_value) { }
};
class HForceRepresentation: public HTemplateInstruction<1> {
public:
- HForceRepresentation(HValue* value, Representation required_representation) {
- SetOperandAt(0, value);
- set_representation(required_representation);
- }
+ DECLARE_INSTRUCTION_FACTORY_P2(HForceRepresentation, HValue*, Representation);
HValue* value() { return OperandAt(0); }
@@ -1711,6 +1818,12 @@
virtual void PrintDataTo(StringStream* stream);
DECLARE_CONCRETE_INSTRUCTION(ForceRepresentation)
+
+ private:
+ HForceRepresentation(HValue* value, Representation required_representation) {
+ SetOperandAt(0, value);
+ set_representation(required_representation);
+ }
};
@@ -1772,12 +1885,7 @@
class HClampToUint8: public HUnaryOperation {
public:
- explicit HClampToUint8(HValue* value)
- : HUnaryOperation(value) {
- set_representation(Representation::Integer32());
- SetFlag(kAllowUndefinedAsNaN);
- SetFlag(kUseGVN);
- }
+ DECLARE_INSTRUCTION_FACTORY_P1(HClampToUint8, HValue*);
virtual Representation RequiredInputRepresentation(int index) {
return Representation::None();
@@ -1789,6 +1897,13 @@
virtual bool DataEquals(HValue* other) { return true; }
private:
+ explicit HClampToUint8(HValue* value)
+ : HUnaryOperation(value) {
+ set_representation(Representation::Integer32());
+ SetFlag(kAllowUndefinedAsNaN);
+ SetFlag(kUseGVN);
+ }
+
virtual bool IsDeletable() const { return true; }
};
@@ -1945,10 +2060,7 @@
kBackwardsBranch
};
- HStackCheck(HValue* context, Type type) : type_(type) {
- SetOperandAt(0, context);
- SetGVNFlag(kChangesNewSpacePromotion);
- }
+ DECLARE_INSTRUCTION_FACTORY_P2(HStackCheck, HValue*, Type);
HValue* context() { return OperandAt(0); }
@@ -1970,6 +2082,11 @@
DECLARE_CONCRETE_INSTRUCTION(StackCheck)
private:
+ HStackCheck(HValue* context, Type type) : type_(type) {
+ SetOperandAt(0, context);
+ SetGVNFlag(kChangesNewSpacePromotion);
+ }
+
Type type_;
};
@@ -1988,23 +2105,18 @@
class HEnterInlined: public HTemplateInstruction<0> {
public:
- HEnterInlined(Handle<JSFunction> closure,
- int arguments_count,
- FunctionLiteral* function,
- InliningKind inlining_kind,
- Variable* arguments_var,
- HArgumentsObject* arguments_object,
- bool undefined_receiver,
- Zone* zone)
- : closure_(closure),
- arguments_count_(arguments_count),
- arguments_pushed_(false),
- function_(function),
- inlining_kind_(inlining_kind),
- arguments_var_(arguments_var),
- arguments_object_(arguments_object),
- undefined_receiver_(undefined_receiver),
- return_targets_(2, zone) {
+ static HEnterInlined* New(Zone* zone,
+ HValue* context,
+ Handle<JSFunction> closure,
+ int arguments_count,
+ FunctionLiteral* function,
+ InliningKind inlining_kind,
+ Variable* arguments_var,
+ HArgumentsObject* arguments_object,
+ bool undefined_receiver) {
+ return new(zone) HEnterInlined(closure, arguments_count, function,
+ inlining_kind, arguments_var,
+ arguments_object, undefined_receiver, zone);
}
void RegisterReturnTarget(HBasicBlock* return_target, Zone* zone);
@@ -2030,6 +2142,25 @@
DECLARE_CONCRETE_INSTRUCTION(EnterInlined)
private:
+ HEnterInlined(Handle<JSFunction> closure,
+ int arguments_count,
+ FunctionLiteral* function,
+ InliningKind inlining_kind,
+ Variable* arguments_var,
+ HArgumentsObject* arguments_object,
+ bool undefined_receiver,
+ Zone* zone)
+ : closure_(closure),
+ arguments_count_(arguments_count),
+ arguments_pushed_(false),
+ function_(function),
+ inlining_kind_(inlining_kind),
+ arguments_var_(arguments_var),
+ arguments_object_(arguments_object),
+ undefined_receiver_(undefined_receiver),
+ return_targets_(2, zone) {
+ }
+
Handle<JSFunction> closure_;
int arguments_count_;
bool arguments_pushed_;
@@ -2056,9 +2187,7 @@
class HPushArgument: public HUnaryOperation {
public:
- explicit HPushArgument(HValue* value) : HUnaryOperation(value) {
- set_representation(Representation::Tagged());
- }
+ DECLARE_INSTRUCTION_FACTORY_P1(HPushArgument, HValue*);
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
@@ -2067,6 +2196,11 @@
HValue* argument() { return OperandAt(0); }
DECLARE_CONCRETE_INSTRUCTION(PushArgument)
+
+ private:
+ explicit HPushArgument(HValue* value) : HUnaryOperation(value) {
+ set_representation(Representation::Tagged());
+ }
};
@@ -2091,33 +2225,9 @@
};
-class HContext: public HTemplateInstruction<0> {
- public:
- HContext() {
- set_representation(Representation::Tagged());
- SetFlag(kUseGVN);
- }
-
- virtual Representation RequiredInputRepresentation(int index) {
- return Representation::None();
- }
-
- DECLARE_CONCRETE_INSTRUCTION(Context)
-
- protected:
- virtual bool DataEquals(HValue* other) { return true; }
-
- private:
- virtual bool IsDeletable() const { return true; }
-};
-
-
class HOuterContext: public HUnaryOperation {
public:
- explicit HOuterContext(HValue* inner) : HUnaryOperation(inner) {
- set_representation(Representation::Tagged());
- SetFlag(kUseGVN);
- }
+ DECLARE_INSTRUCTION_FACTORY_P1(HOuterContext, HValue*);
DECLARE_CONCRETE_INSTRUCTION(OuterContext);
@@ -2129,6 +2239,11 @@
virtual bool DataEquals(HValue* other) { return true; }
private:
+ explicit HOuterContext(HValue* inner) : HUnaryOperation(inner) {
+ set_representation(Representation::Tagged());
+ SetFlag(kUseGVN);
+ }
+
virtual bool IsDeletable() const { return true; }
};
@@ -2145,6 +2260,13 @@
SetAllSideEffects();
}
+ static HDeclareGlobals* New(Zone* zone,
+ HValue* context,
+ Handle<FixedArray> pairs,
+ int flags) {
+ return new(zone) HDeclareGlobals(context, pairs, flags);
+ }
+
HValue* context() { return OperandAt(0); }
Handle<FixedArray> pairs() const { return pairs_; }
int flags() const { return flags_; }
@@ -2154,6 +2276,7 @@
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
}
+
private:
Handle<FixedArray> pairs_;
int flags_;
@@ -2167,6 +2290,10 @@
SetFlag(kUseGVN);
}
+ static HGlobalObject* New(Zone* zone, HValue* context) {
+ return new(zone) HGlobalObject(context);
+ }
+
DECLARE_CONCRETE_INSTRUCTION(GlobalObject)
virtual Representation RequiredInputRepresentation(int index) {
@@ -2183,11 +2310,7 @@
class HGlobalReceiver: public HUnaryOperation {
public:
- explicit HGlobalReceiver(HValue* global_object)
- : HUnaryOperation(global_object) {
- set_representation(Representation::Tagged());
- SetFlag(kUseGVN);
- }
+ DECLARE_INSTRUCTION_FACTORY_P1(HGlobalReceiver, HValue*);
DECLARE_CONCRETE_INSTRUCTION(GlobalReceiver)
@@ -2199,6 +2322,12 @@
virtual bool DataEquals(HValue* other) { return true; }
private:
+ explicit HGlobalReceiver(HValue* global_object)
+ : HUnaryOperation(global_object) {
+ set_representation(Representation::Tagged());
+ SetFlag(kUseGVN);
+ }
+
virtual bool IsDeletable() const { return true; }
};
@@ -2265,6 +2394,13 @@
: HBinaryCall(context, function, argument_count) {
}
+ static HInvokeFunction* New(Zone* zone,
+ HValue* context,
+ HValue* function,
+ int argument_count) {
+ return new(zone) HInvokeFunction(context, function, argument_count);
+ }
+
HInvokeFunction(HValue* context,
HValue* function,
Handle<JSFunction> known_function,
@@ -2275,6 +2411,15 @@
? 0 : known_function->shared()->formal_parameter_count();
}
+ static HInvokeFunction* New(Zone* zone,
+ HValue* context,
+ HValue* function,
+ Handle<JSFunction> known_function,
+ int argument_count) {
+ return new(zone) HInvokeFunction(context, function,
+ known_function, argument_count);
+ }
+
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
}
@@ -2366,6 +2511,13 @@
: HBinaryCall(context, function, argument_count) {
}
+ static HCallFunction* New(Zone* zone,
+ HValue* context,
+ HValue* function,
+ int argument_count) {
+ return new(zone) HCallFunction(context, function, argument_count);
+ }
+
HValue* context() { return first(); }
HValue* function() { return second(); }
@@ -2383,6 +2535,13 @@
: HUnaryCall(context, argument_count), name_(name) {
}
+ static HCallGlobal* New(Zone* zone,
+ HValue* context,
+ Handle<String> name,
+ int argument_count) {
+ return new(zone) HCallGlobal(context, name, argument_count);
+ }
+
virtual void PrintDataTo(StringStream* stream);
HValue* context() { return value(); }
@@ -2466,12 +2625,12 @@
class HCallRuntime: public HCall<1> {
public:
- HCallRuntime(HValue* context,
- Handle<String> name,
- const Runtime::Function* c_function,
- int argument_count)
- : HCall<1>(argument_count), c_function_(c_function), name_(name) {
- SetOperandAt(0, context);
+ static HCallRuntime* New(Zone* zone,
+ HValue* context,
+ Handle<String> name,
+ const Runtime::Function* c_function,
+ int argument_count) {
+ return new(zone) HCallRuntime(context, name, c_function, argument_count);
}
virtual void PrintDataTo(StringStream* stream);
@@ -2487,6 +2646,14 @@
DECLARE_CONCRETE_INSTRUCTION(CallRuntime)
private:
+ HCallRuntime(HValue* context,
+ Handle<String> name,
+ const Runtime::Function* c_function,
+ int argument_count)
+ : HCall<1>(argument_count), c_function_(c_function), name_(name) {
+ SetOperandAt(0, context);
+ }
+
const Runtime::Function* c_function_;
Handle<String> name_;
};
@@ -2494,12 +2661,7 @@
class HMapEnumLength: public HUnaryOperation {
public:
- explicit HMapEnumLength(HValue* value) : HUnaryOperation(value) {
- set_type(HType::Smi());
- set_representation(Representation::Smi());
- SetFlag(kUseGVN);
- SetGVNFlag(kDependsOnMaps);
- }
+ DECLARE_INSTRUCTION_FACTORY_P1(HMapEnumLength, HValue*);
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
@@ -2511,6 +2673,13 @@
virtual bool DataEquals(HValue* other) { return true; }
private:
+ explicit HMapEnumLength(HValue* value)
+ : HUnaryOperation(value, HType::Smi()) {
+ set_representation(Representation::Smi());
+ SetFlag(kUseGVN);
+ SetGVNFlag(kDependsOnMaps);
+ }
+
virtual bool IsDeletable() const { return true; }
};
@@ -2539,12 +2708,7 @@
class HBitNot: public HUnaryOperation {
public:
- explicit HBitNot(HValue* value) : HUnaryOperation(value) {
- set_representation(Representation::Integer32());
- SetFlag(kUseGVN);
- SetFlag(kTruncatingToInt32);
- SetFlag(kAllowUndefinedAsNaN);
- }
+ DECLARE_INSTRUCTION_FACTORY_P1(HBitNot, HValue*);
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Integer32();
@@ -2552,7 +2716,6 @@
virtual Representation observed_input_representation(int index) {
return Representation::Integer32();
}
- virtual HType CalculateInferredType();
virtual HValue* Canonicalize();
@@ -2562,6 +2725,14 @@
virtual bool DataEquals(HValue* other) { return true; }
private:
+ explicit HBitNot(HValue* value)
+ : HUnaryOperation(value, HType::TaggedNumber()) {
+ set_representation(Representation::Integer32());
+ SetFlag(kUseGVN);
+ SetFlag(kTruncatingToInt32);
+ SetFlag(kAllowUndefinedAsNaN);
+ }
+
virtual bool IsDeletable() const { return true; }
};
@@ -2578,8 +2749,6 @@
virtual void PrintDataTo(StringStream* stream);
- virtual HType CalculateInferredType();
-
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
virtual Representation RequiredInputRepresentation(int index) {
@@ -2624,7 +2793,7 @@
private:
HUnaryMathOperation(HValue* context, HValue* value, BuiltinFunctionId op)
- : op_(op) {
+ : HTemplateInstruction<2>(HType::TaggedNumber()), op_(op) {
SetOperandAt(0, context);
SetOperandAt(1, value);
switch (op) {
@@ -2668,6 +2837,22 @@
class HLoadExternalArrayPointer: public HUnaryOperation {
public:
+ DECLARE_INSTRUCTION_FACTORY_P1(HLoadExternalArrayPointer, HValue*);
+
+ virtual Representation RequiredInputRepresentation(int index) {
+ return Representation::Tagged();
+ }
+
+ virtual HType CalculateInferredType() {
+ return HType::None();
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(LoadExternalArrayPointer)
+
+ protected:
+ virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
explicit HLoadExternalArrayPointer(HValue* value)
: HUnaryOperation(value) {
set_representation(Representation::External());
@@ -2678,25 +2863,17 @@
SetFlag(kUseGVN);
}
- virtual Representation RequiredInputRepresentation(int index) {
- return Representation::Tagged();
- }
-
- DECLARE_CONCRETE_INSTRUCTION(LoadExternalArrayPointer)
-
- protected:
- virtual bool DataEquals(HValue* other) { return true; }
-
- private:
virtual bool IsDeletable() const { return true; }
};
class HCheckMaps: public HTemplateInstruction<2> {
public:
- static HCheckMaps* New(HValue* value, Handle<Map> map, Zone* zone,
- CompilationInfo* info, HValue *typecheck = NULL);
- static HCheckMaps* New(HValue* value, SmallMapList* maps, Zone* zone,
+ static HCheckMaps* New(Zone* zone, HValue* context, HValue* value,
+ Handle<Map> map, CompilationInfo* info,
+ HValue *typecheck = NULL);
+ static HCheckMaps* New(Zone* zone, HValue* context,
+ HValue* value, SmallMapList* maps,
HValue *typecheck = NULL) {
HCheckMaps* check_map = new(zone) HCheckMaps(value, zone, typecheck);
for (int i = 0; i < maps->length(); i++) {
@@ -2706,9 +2883,6 @@
return check_map;
}
- static HCheckMaps* NewWithTransitions(HValue* value, Handle<Map> map,
- Zone* zone, CompilationInfo* info);
-
bool CanOmitMapChecks() { return omit_; }
virtual bool HasEscapingOperandAt(int index) { return false; }
@@ -2718,7 +2892,6 @@
virtual void HandleSideEffectDominator(GVNFlag side_effect,
HValue* dominator);
virtual void PrintDataTo(StringStream* stream);
- virtual HType CalculateInferredType();
HValue* value() { return OperandAt(0); }
SmallMapList* map_set() { return &map_set_; }
@@ -2746,7 +2919,8 @@
private:
// Clients should use one of the static New* methods above.
HCheckMaps(HValue* value, Zone *zone, HValue* typecheck)
- : omit_(false), map_unique_ids_(0, zone) {
+ : HTemplateInstruction<2>(value->type()),
+ omit_(false), map_unique_ids_(0, zone) {
SetOperandAt(0, value);
// Use the object value for the dependency if NULL is passed.
// TODO(titzer): do GVN flags already express this dependency?
@@ -2775,18 +2949,12 @@
class HCheckFunction: public HUnaryOperation {
public:
- HCheckFunction(HValue* value, Handle<JSFunction> function)
- : HUnaryOperation(value), target_(function), target_unique_id_() {
- set_representation(Representation::Tagged());
- SetFlag(kUseGVN);
- target_in_new_space_ = Isolate::Current()->heap()->InNewSpace(*function);
- }
+ DECLARE_INSTRUCTION_FACTORY_P2(HCheckFunction, HValue*, Handle<JSFunction>);
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
}
virtual void PrintDataTo(StringStream* stream);
- virtual HType CalculateInferredType();
virtual HValue* Canonicalize();
@@ -2810,6 +2978,14 @@
}
private:
+ HCheckFunction(HValue* value, Handle<JSFunction> function)
+ : HUnaryOperation(value, value->type()),
+ target_(function), target_unique_id_() {
+ set_representation(Representation::Tagged());
+ SetFlag(kUseGVN);
+ target_in_new_space_ = Isolate::Current()->heap()->InNewSpace(*function);
+ }
+
Handle<JSFunction> target_;
UniqueValueId target_unique_id_;
bool target_in_new_space_;
@@ -2878,17 +3054,12 @@
class HCheckSmi: public HUnaryOperation {
public:
- explicit HCheckSmi(HValue* value) : HUnaryOperation(value) {
- set_representation(Representation::Smi());
- SetFlag(kUseGVN);
- }
+ DECLARE_INSTRUCTION_FACTORY_P1(HCheckSmi, HValue*);
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
}
- virtual HType CalculateInferredType();
-
virtual HValue* Canonicalize() {
HType value_type = value()->type();
if (value_type.IsSmi()) {
@@ -2901,6 +3072,12 @@
protected:
virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+ explicit HCheckSmi(HValue* value) : HUnaryOperation(value, HType::Smi()) {
+ set_representation(Representation::Smi());
+ SetFlag(kUseGVN);
+ }
};
@@ -2921,67 +3098,42 @@
class HCheckHeapObject: public HUnaryOperation {
public:
- explicit HCheckHeapObject(HValue* value) : HUnaryOperation(value) {
- set_representation(Representation::Tagged());
- SetFlag(kUseGVN);
- }
+ DECLARE_INSTRUCTION_FACTORY_P1(HCheckHeapObject, HValue*);
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
}
- virtual HType CalculateInferredType();
-
#ifdef DEBUG
virtual void Verify();
#endif
virtual HValue* Canonicalize() {
- HType value_type = value()->type();
- if (!value_type.IsUninitialized() && value_type.IsHeapObject()) {
- return NULL;
- }
- return this;
+ return value()->type().IsHeapObject() ? NULL : this;
}
DECLARE_CONCRETE_INSTRUCTION(CheckHeapObject)
protected:
virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+ explicit HCheckHeapObject(HValue* value)
+ : HUnaryOperation(value, HType::NonPrimitive()) {
+ set_representation(Representation::Tagged());
+ SetFlag(kUseGVN);
+ }
};
class HCheckPrototypeMaps: public HTemplateInstruction<0> {
public:
- HCheckPrototypeMaps(Handle<JSObject> prototype,
- Handle<JSObject> holder,
- Zone* zone,
- CompilationInfo* info)
- : prototypes_(2, zone),
- maps_(2, zone),
- first_prototype_unique_id_(),
- last_prototype_unique_id_(),
- can_omit_prototype_maps_(true) {
- SetFlag(kUseGVN);
- SetGVNFlag(kDependsOnMaps);
- // Keep a list of all objects on the prototype chain up to the holder
- // and the expected maps.
- while (true) {
- prototypes_.Add(prototype, zone);
- Handle<Map> map(prototype->map());
- maps_.Add(map, zone);
- can_omit_prototype_maps_ &= map->CanOmitPrototypeChecks();
- if (prototype.is_identical_to(holder)) break;
- prototype = Handle<JSObject>(JSObject::cast(prototype->GetPrototype()));
- }
- if (can_omit_prototype_maps_) {
- // Mark in-flight compilation as dependent on those maps.
- for (int i = 0; i < maps()->length(); i++) {
- Handle<Map> map = maps()->at(i);
- map->AddDependentCompilationInfo(DependentCode::kPrototypeCheckGroup,
- info);
- }
- }
+ static HCheckPrototypeMaps* New(Zone* zone,
+ HValue* context,
+ Handle<JSObject> prototype,
+ Handle<JSObject> holder,
+ CompilationInfo* info) {
+ return new(zone) HCheckPrototypeMaps(prototype, holder, zone, info);
}
ZoneList<Handle<JSObject> >* prototypes() { return &prototypes_; }
@@ -3016,6 +3168,37 @@
}
private:
+ HCheckPrototypeMaps(Handle<JSObject> prototype,
+ Handle<JSObject> holder,
+ Zone* zone,
+ CompilationInfo* info)
+ : prototypes_(2, zone),
+ maps_(2, zone),
+ first_prototype_unique_id_(),
+ last_prototype_unique_id_(),
+ can_omit_prototype_maps_(true) {
+ SetFlag(kUseGVN);
+ SetGVNFlag(kDependsOnMaps);
+ // Keep a list of all objects on the prototype chain up to the holder
+ // and the expected maps.
+ while (true) {
+ prototypes_.Add(prototype, zone);
+ Handle<Map> map(prototype->map());
+ maps_.Add(map, zone);
+ can_omit_prototype_maps_ &= map->CanOmitPrototypeChecks();
+ if (prototype.is_identical_to(holder)) break;
+ prototype = Handle<JSObject>(JSObject::cast(prototype->GetPrototype()));
+ }
+ if (can_omit_prototype_maps_) {
+ // Mark in-flight compilation as dependent on those maps.
+ for (int i = 0; i < maps()->length(); i++) {
+ Handle<Map> map = maps()->at(i);
+ map->AddDependentCompilationInfo(DependentCode::kPrototypeCheckGroup,
+ info);
+ }
+ }
+ }
+
ZoneList<Handle<JSObject> > prototypes_;
ZoneList<Handle<Map> > maps_;
UniqueValueId first_prototype_unique_id_;
@@ -3343,9 +3526,6 @@
void SimplifyConstantInputs();
- // TODO(titzer): we can't eliminate the receiver for generating backtraces
- virtual bool IsDeletable() const { return !IsReceiver(); }
-
protected:
virtual void DeleteFromGraph();
virtual void InternalSetOperandAt(int index, HValue* value) {
@@ -3365,6 +3545,9 @@
int indirect_uses_[Representation::kNumRepresentations];
int phi_id_;
InductionVariableData* induction_variable_data_;
+
+ // TODO(titzer): we can't eliminate the receiver for generating backtraces
+ virtual bool IsDeletable() const { return !IsReceiver(); }
};
@@ -3417,9 +3600,10 @@
class HArgumentsObject: public HTemplateInstruction<0> {
public:
- HArgumentsObject(int count, Zone* zone) : values_(count, zone) {
- set_representation(Representation::Tagged());
- SetFlag(kIsArguments);
+ static HArgumentsObject* New(Zone* zone,
+ HValue* context,
+ int count) {
+ return new(zone) HArgumentsObject(count, zone);
}
const ZoneList<HValue*>* arguments_values() const { return &values_; }
@@ -3446,6 +3630,11 @@
}
private:
+ HArgumentsObject(int count, Zone* zone) : values_(count, zone) {
+ set_representation(Representation::Tagged());
+ SetFlag(kIsArguments);
+ }
+
virtual bool IsDeletable() const { return true; }
ZoneList<HValue*> values_;
@@ -3454,23 +3643,11 @@
class HConstant: public HTemplateInstruction<0> {
public:
- HConstant(Handle<Object> handle, Representation r = Representation::None());
- HConstant(int32_t value,
- Representation r = Representation::None(),
- bool is_not_in_new_space = true,
- Handle<Object> optional_handle = Handle<Object>::null());
- HConstant(double value,
- Representation r = Representation::None(),
- bool is_not_in_new_space = true,
- Handle<Object> optional_handle = Handle<Object>::null());
- HConstant(Handle<Object> handle,
- UniqueValueId unique_id,
- Representation r,
- HType type,
- bool is_internalized_string,
- bool is_not_in_new_space,
- bool is_cell,
- bool boolean_value);
+ DECLARE_INSTRUCTION_FACTORY_P1(HConstant, int32_t);
+ DECLARE_INSTRUCTION_FACTORY_P2(HConstant, int32_t, Representation);
+ DECLARE_INSTRUCTION_FACTORY_P1(HConstant, double);
+ DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Handle<Object>);
+ DECLARE_INSTRUCTION_FACTORY_P1(HConstant, ExternalReference);
Handle<Object> handle() {
if (handle_.is_null()) {
@@ -3535,12 +3712,12 @@
if (HasSmiValue() && kSmiValueSize == 31) return Representation::Smi();
if (HasInteger32Value()) return Representation::Integer32();
if (HasNumberValue()) return Representation::Double();
+ if (HasExternalReferenceValue()) return Representation::External();
return Representation::Tagged();
}
virtual bool EmitAtUses();
virtual void PrintDataTo(StringStream* stream);
- virtual HType CalculateInferredType();
bool IsInteger() { return handle()->IsSmi(); }
HConstant* CopyToRepresentation(Representation r, Zone* zone) const;
Maybe<HConstant*> CopyToTruncatedInt32(Zone* zone);
@@ -3577,7 +3754,7 @@
bool HasStringValue() const {
if (has_double_value_ || has_int32_value_) return false;
ASSERT(!handle_.is_null());
- return type_from_value_.IsString();
+ return type_.IsString();
}
Handle<String> StringValue() const {
ASSERT(HasStringValue());
@@ -3587,6 +3764,13 @@
return HasStringValue() && is_internalized_string_;
}
+ bool HasExternalReferenceValue() const {
+ return has_external_reference_value_;
+ }
+ ExternalReference ExternalReferenceValue() const {
+ return external_reference_value_;
+ }
+
bool BooleanValue() const { return boolean_value_; }
virtual intptr_t Hashcode() {
@@ -3594,6 +3778,8 @@
return static_cast<intptr_t>(int32_value_);
} else if (has_double_value_) {
return static_cast<intptr_t>(BitCast<int64_t>(double_value_));
+ } else if (has_external_reference_value_) {
+ return reinterpret_cast<intptr_t>(external_reference_value_.address());
} else {
ASSERT(!handle_.is_null());
return unique_id_.Hashcode();
@@ -3601,14 +3787,15 @@
}
virtual void FinalizeUniqueValueId() {
- if (!has_double_value_) {
+ if (!has_double_value_ && !has_external_reference_value_) {
ASSERT(!handle_.is_null());
unique_id_ = UniqueValueId(handle_);
}
}
bool UniqueValueIdsMatch(UniqueValueId other) {
- return !has_double_value_ && unique_id_ == other;
+ return !has_double_value_ && !has_external_reference_value_ &&
+ unique_id_ == other;
}
#ifdef DEBUG
@@ -3629,6 +3816,10 @@
return other_constant->has_double_value_ &&
BitCast<int64_t>(double_value_) ==
BitCast<int64_t>(other_constant->double_value_);
+ } else if (has_external_reference_value_) {
+ return other_constant->has_external_reference_value_ &&
+ external_reference_value_ ==
+ other_constant->external_reference_value_;
} else {
ASSERT(!handle_.is_null());
return !other_constant->handle_.is_null() &&
@@ -3637,6 +3828,26 @@
}
private:
+ friend class HGraph;
+ HConstant(Handle<Object> handle, Representation r = Representation::None());
+ HConstant(int32_t value,
+ Representation r = Representation::None(),
+ bool is_not_in_new_space = true,
+ Handle<Object> optional_handle = Handle<Object>::null());
+ HConstant(double value,
+ Representation r = Representation::None(),
+ bool is_not_in_new_space = true,
+ Handle<Object> optional_handle = Handle<Object>::null());
+ HConstant(Handle<Object> handle,
+ UniqueValueId unique_id,
+ Representation r,
+ HType type,
+ bool is_internalized_string,
+ bool is_not_in_new_space,
+ bool is_cell,
+ bool boolean_value);
+ explicit HConstant(ExternalReference reference);
+
void Initialize(Representation r);
virtual bool IsDeletable() const { return true; }
@@ -3656,20 +3867,23 @@
bool has_smi_value_ : 1;
bool has_int32_value_ : 1;
bool has_double_value_ : 1;
+ bool has_external_reference_value_ : 1;
bool is_internalized_string_ : 1; // TODO(yangguo): make this part of HType.
bool is_not_in_new_space_ : 1;
bool is_cell_ : 1;
bool boolean_value_ : 1;
int32_t int32_value_;
double double_value_;
- HType type_from_value_;
+ ExternalReference external_reference_value_;
};
class HBinaryOperation: public HTemplateInstruction<3> {
public:
- HBinaryOperation(HValue* context, HValue* left, HValue* right)
- : observed_output_representation_(Representation::None()) {
+ HBinaryOperation(HValue* context, HValue* left, HValue* right,
+ HType type = HType::Tagged())
+ : HTemplateInstruction<3>(type),
+ observed_output_representation_(Representation::None()) {
ASSERT(left != NULL && right != NULL);
SetOperandAt(0, context);
SetOperandAt(1, left);
@@ -3678,9 +3892,9 @@
observed_input_representation_[1] = Representation::None();
}
- HValue* context() { return OperandAt(0); }
- HValue* left() { return OperandAt(1); }
- HValue* right() { return OperandAt(2); }
+ HValue* context() const { return OperandAt(0); }
+ HValue* left() const { return OperandAt(1); }
+ HValue* right() const { return OperandAt(2); }
// True if switching left and right operands likely generates better code.
bool AreOperandsBetterSwitched() {
@@ -3753,11 +3967,7 @@
class HWrapReceiver: public HTemplateInstruction<2> {
public:
- HWrapReceiver(HValue* receiver, HValue* function) {
- set_representation(Representation::Tagged());
- SetOperandAt(0, receiver);
- SetOperandAt(1, function);
- }
+ DECLARE_INSTRUCTION_FACTORY_P2(HWrapReceiver, HValue*, HValue*);
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
@@ -3771,6 +3981,13 @@
virtual void PrintDataTo(StringStream* stream);
DECLARE_CONCRETE_INSTRUCTION(WrapReceiver)
+
+ private:
+ HWrapReceiver(HValue* receiver, HValue* function) {
+ set_representation(Representation::Tagged());
+ SetOperandAt(0, receiver);
+ SetOperandAt(1, function);
+ }
};
@@ -3806,12 +4023,7 @@
class HArgumentsElements: public HTemplateInstruction<0> {
public:
- explicit HArgumentsElements(bool from_inlined) : from_inlined_(from_inlined) {
- // The value produced by this instruction is a pointer into the stack
- // that looks as if it was a smi because of alignment.
- set_representation(Representation::Tagged());
- SetFlag(kUseGVN);
- }
+ DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsElements, bool);
DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements)
@@ -3825,6 +4037,13 @@
virtual bool DataEquals(HValue* other) { return true; }
private:
+ explicit HArgumentsElements(bool from_inlined) : from_inlined_(from_inlined) {
+ // The value produced by this instruction is a pointer into the stack
+ // that looks as if it was a smi because of alignment.
+ set_representation(Representation::Tagged());
+ SetFlag(kUseGVN);
+ }
+
virtual bool IsDeletable() const { return true; }
bool from_inlined_;
@@ -3833,10 +4052,7 @@
class HArgumentsLength: public HUnaryOperation {
public:
- explicit HArgumentsLength(HValue* value) : HUnaryOperation(value) {
- set_representation(Representation::Integer32());
- SetFlag(kUseGVN);
- }
+ DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsLength, HValue*);
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
@@ -3848,6 +4064,11 @@
virtual bool DataEquals(HValue* other) { return true; }
private:
+ explicit HArgumentsLength(HValue* value) : HUnaryOperation(value) {
+ set_representation(Representation::Integer32());
+ SetFlag(kUseGVN);
+ }
+
virtual bool IsDeletable() const { return true; }
};
@@ -3886,23 +4107,11 @@
class HBoundsCheck: public HTemplateInstruction<2> {
public:
- // Normally HBoundsCheck should be created using the
- // HGraphBuilder::AddBoundsCheck() helper.
- // However when building stubs, where we know that the arguments are Int32,
- // it makes sense to invoke this constructor directly.
- HBoundsCheck(HValue* index, HValue* length)
- : skip_check_(false),
- base_(NULL), offset_(0), scale_(0),
- responsibility_direction_(DIRECTION_NONE),
- allow_equality_(false) {
- SetOperandAt(0, index);
- SetOperandAt(1, length);
- SetFlag(kFlexibleRepresentation);
- SetFlag(kUseGVN);
- }
+ DECLARE_INSTRUCTION_FACTORY_P2(HBoundsCheck, HValue*, HValue*);
bool skip_check() const { return skip_check_; }
void set_skip_check() { skip_check_ = true; }
+
HValue* base() { return base_; }
int offset() { return offset_; }
int scale() { return scale_; }
@@ -3934,9 +4143,6 @@
virtual Representation RequiredInputRepresentation(int arg_index) {
return representation();
}
- virtual bool IsDeletable() const {
- return skip_check() && !FLAG_debug_code;
- }
virtual bool IsRelationTrueInternal(NumericRelation relation,
HValue* related_value,
@@ -3973,6 +4179,26 @@
int scale_;
RangeGuaranteeDirection responsibility_direction_;
bool allow_equality_;
+
+ private:
+ // Normally HBoundsCheck should be created using the
+ // HGraphBuilder::AddBoundsCheck() helper.
+ // However when building stubs, where we know that the arguments are Int32,
+ // it makes sense to invoke this constructor directly.
+ HBoundsCheck(HValue* index, HValue* length)
+ : skip_check_(false),
+ base_(NULL), offset_(0), scale_(0),
+ responsibility_direction_(DIRECTION_NONE),
+ allow_equality_(false) {
+ SetOperandAt(0, index);
+ SetOperandAt(1, length);
+ SetFlag(kFlexibleRepresentation);
+ SetFlag(kUseGVN);
+ }
+
+ virtual bool IsDeletable() const {
+ return skip_check() && !FLAG_debug_code;
+ }
};
@@ -4018,8 +4244,9 @@
class HBitwiseBinaryOperation: public HBinaryOperation {
public:
- HBitwiseBinaryOperation(HValue* context, HValue* left, HValue* right)
- : HBinaryOperation(context, left, right) {
+ HBitwiseBinaryOperation(HValue* context, HValue* left, HValue* right,
+ HType type = HType::Tagged())
+ : HBinaryOperation(context, left, right, type) {
SetFlag(kFlexibleRepresentation);
SetFlag(kTruncatingToInt32);
SetFlag(kAllowUndefinedAsNaN);
@@ -4056,8 +4283,6 @@
HBinaryOperation::initialize_output_representation(observed);
}
- virtual HType CalculateInferredType();
-
DECLARE_ABSTRACT_INSTRUCTION(BitwiseBinaryOperation)
private:
@@ -4067,15 +4292,11 @@
class HMathFloorOfDiv: public HBinaryOperation {
public:
- HMathFloorOfDiv(HValue* context, HValue* left, HValue* right)
- : HBinaryOperation(context, left, right) {
- set_representation(Representation::Integer32());
- SetFlag(kUseGVN);
- SetFlag(kCanOverflow);
- if (!right->IsConstant()) {
- SetFlag(kCanBeDivByZero);
- }
- SetFlag(kAllowUndefinedAsNaN);
+ static HMathFloorOfDiv* New(Zone* zone,
+ HValue* context,
+ HValue* left,
+ HValue* right) {
+ return new(zone) HMathFloorOfDiv(context, left, right);
}
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
@@ -4090,6 +4311,17 @@
virtual bool DataEquals(HValue* other) { return true; }
private:
+ HMathFloorOfDiv(HValue* context, HValue* left, HValue* right)
+ : HBinaryOperation(context, left, right) {
+ set_representation(Representation::Integer32());
+ SetFlag(kUseGVN);
+ SetFlag(kCanOverflow);
+ if (!right->IsConstant()) {
+ SetFlag(kCanBeDivByZero);
+ }
+ SetFlag(kAllowUndefinedAsNaN);
+ }
+
virtual bool IsDeletable() const { return true; }
};
@@ -4097,7 +4329,7 @@
class HArithmeticBinaryOperation: public HBinaryOperation {
public:
HArithmeticBinaryOperation(HValue* context, HValue* left, HValue* right)
- : HBinaryOperation(context, left, right) {
+ : HBinaryOperation(context, left, right, HType::TaggedNumber()) {
SetAllSideEffects();
SetFlag(kFlexibleRepresentation);
SetFlag(kAllowUndefinedAsNaN);
@@ -4113,8 +4345,6 @@
}
}
- virtual HType CalculateInferredType();
-
DECLARE_ABSTRACT_INSTRUCTION(ArithmeticBinaryOperation)
private:
@@ -4128,7 +4358,8 @@
HValue* left,
HValue* right,
Token::Value token)
- : HBinaryOperation(context, left, right), token_(token) {
+ : HBinaryOperation(context, left, right, HType::Boolean()),
+ token_(token) {
ASSERT(Token::IsCompareOp(token));
set_representation(Representation::Tagged());
SetAllSideEffects();
@@ -4143,8 +4374,6 @@
Token::Value token() const { return token_; }
virtual void PrintDataTo(StringStream* stream);
- virtual HType CalculateInferredType();
-
DECLARE_CONCRETE_INSTRUCTION(CompareGeneric)
private:
@@ -4194,11 +4423,16 @@
class HCompareObjectEqAndBranch: public HTemplateControlInstruction<2, 2> {
public:
- HCompareObjectEqAndBranch(HValue* left, HValue* right) {
+ // TODO(danno): make this private when the IfBuilder properly constructs
+ // control flow instructions.
+ HCompareObjectEqAndBranch(HValue* left,
+ HValue* right) {
SetOperandAt(0, left);
SetOperandAt(1, right);
}
+ DECLARE_INSTRUCTION_FACTORY_P2(HCompareObjectEqAndBranch, HValue*, HValue*);
+
HValue* left() { return OperandAt(0); }
HValue* right() { return OperandAt(1); }
@@ -4420,7 +4654,7 @@
class HInstanceOf: public HBinaryOperation {
public:
HInstanceOf(HValue* context, HValue* left, HValue* right)
- : HBinaryOperation(context, left, right) {
+ : HBinaryOperation(context, left, right, HType::Boolean()) {
set_representation(Representation::Tagged());
SetAllSideEffects();
}
@@ -4429,8 +4663,6 @@
return Representation::Tagged();
}
- virtual HType CalculateInferredType();
-
virtual void PrintDataTo(StringStream* stream);
DECLARE_CONCRETE_INSTRUCTION(InstanceOf)
@@ -4442,7 +4674,7 @@
HInstanceOfKnownGlobal(HValue* context,
HValue* left,
Handle<JSFunction> right)
- : function_(right) {
+ : HTemplateInstruction<2>(HType::Boolean()), function_(right) {
SetOperandAt(0, context);
SetOperandAt(1, left);
set_representation(Representation::Tagged());
@@ -4457,8 +4689,6 @@
return Representation::Tagged();
}
- virtual HType CalculateInferredType();
-
DECLARE_CONCRETE_INSTRUCTION(InstanceOfKnownGlobal)
private:
@@ -4488,7 +4718,10 @@
class HPower: public HTemplateInstruction<2> {
public:
- static HInstruction* New(Zone* zone, HValue* left, HValue* right);
+ static HInstruction* New(Zone* zone,
+ HValue* context,
+ HValue* left,
+ HValue* right);
HValue* left() { return OperandAt(0); }
HValue* right() const { return OperandAt(1); }
@@ -4557,8 +4790,6 @@
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
- virtual HType CalculateInferredType();
-
virtual HValue* Canonicalize();
virtual bool TryDecompose(DecompositionResult* decomposition) {
@@ -4792,8 +5023,7 @@
virtual Representation RepresentationFromInputs() {
Representation left_rep = left()->representation();
Representation right_rep = right()->representation();
- // TODO(verwaest): Initialize to Smi once lithium-codegen has been fixed.
- Representation result = Representation::Integer32();
+ Representation result = Representation::Smi();
result = result.generalize(left_rep);
result = result.generalize(right_rep);
if (result.IsTagged()) return Representation::Double();
@@ -4826,8 +5056,8 @@
class HBitwise: public HBitwiseBinaryOperation {
public:
static HInstruction* New(Zone* zone,
- Token::Value op,
HValue* context,
+ Token::Value op,
HValue* left,
HValue* right);
@@ -4849,8 +5079,12 @@
virtual Range* InferRange(Zone* zone);
private:
- HBitwise(Token::Value op, HValue* context, HValue* left, HValue* right)
- : HBitwiseBinaryOperation(context, left, right), op_(op) {
+ HBitwise(HValue* context,
+ Token::Value op,
+ HValue* left,
+ HValue* right)
+ : HBitwiseBinaryOperation(context, left, right, HType::TaggedNumber()),
+ op_(op) {
ASSERT(op == Token::BIT_AND || op == Token::BIT_OR || op == Token::BIT_XOR);
// BIT_AND with a smi-range positive value will always unset the
// entire sign-extension of the smi-sign.
@@ -4891,7 +5125,11 @@
virtual void UpdateRepresentation(Representation new_rep,
HInferRepresentationPhase* h_infer,
const char* reason) {
- if (new_rep.IsSmi()) new_rep = Representation::Integer32();
+ if (new_rep.IsSmi() &&
+ !(right()->IsInteger32Constant() &&
+ right()->GetInteger32Constant() >= 0)) {
+ new_rep = Representation::Integer32();
+ }
HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
}
@@ -5007,10 +5245,7 @@
class HOsrEntry: public HTemplateInstruction<0> {
public:
- explicit HOsrEntry(BailoutId ast_id) : ast_id_(ast_id) {
- SetGVNFlag(kChangesOsrEntries);
- SetGVNFlag(kChangesNewSpacePromotion);
- }
+ DECLARE_INSTRUCTION_FACTORY_P1(HOsrEntry, BailoutId);
BailoutId ast_id() const { return ast_id_; }
@@ -5021,6 +5256,11 @@
DECLARE_CONCRETE_INSTRUCTION(OsrEntry)
private:
+ explicit HOsrEntry(BailoutId ast_id) : ast_id_(ast_id) {
+ SetGVNFlag(kChangesOsrEntries);
+ SetGVNFlag(kChangesNewSpacePromotion);
+ }
+
BailoutId ast_id_;
};
@@ -5032,6 +5272,23 @@
REGISTER_PARAMETER
};
+ DECLARE_INSTRUCTION_FACTORY_P1(HParameter, unsigned);
+ DECLARE_INSTRUCTION_FACTORY_P2(HParameter, unsigned, ParameterKind);
+ DECLARE_INSTRUCTION_FACTORY_P3(HParameter, unsigned, ParameterKind,
+ Representation);
+
+ unsigned index() const { return index_; }
+ ParameterKind kind() const { return kind_; }
+
+ virtual void PrintDataTo(StringStream* stream);
+
+ virtual Representation RequiredInputRepresentation(int index) {
+ return Representation::None();
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(Parameter)
+
+ private:
explicit HParameter(unsigned index,
ParameterKind kind = STACK_PARAMETER)
: index_(index),
@@ -5047,18 +5304,6 @@
set_representation(r);
}
- unsigned index() const { return index_; }
- ParameterKind kind() const { return kind_; }
-
- virtual void PrintDataTo(StringStream* stream);
-
- virtual Representation RequiredInputRepresentation(int index) {
- return Representation::None();
- }
-
- DECLARE_CONCRETE_INSTRUCTION(Parameter)
-
- private:
unsigned index_;
ParameterKind kind_;
};
@@ -5099,10 +5344,7 @@
class HUnknownOSRValue: public HTemplateInstruction<0> {
public:
- HUnknownOSRValue()
- : incoming_value_(NULL) {
- set_representation(Representation::Tagged());
- }
+ DECLARE_INSTRUCTION_FACTORY_P0(HUnknownOSRValue)
virtual Representation RequiredInputRepresentation(int index) {
return Representation::None();
@@ -5124,6 +5366,11 @@
DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue)
private:
+ HUnknownOSRValue()
+ : incoming_value_(NULL) {
+ set_representation(Representation::Tagged());
+ }
+
HPhi* incoming_value_;
};
@@ -5206,41 +5453,19 @@
class HAllocate: public HTemplateInstruction<2> {
public:
- enum Flags {
- CAN_ALLOCATE_IN_NEW_SPACE = 1 << 0,
- CAN_ALLOCATE_IN_OLD_DATA_SPACE = 1 << 1,
- CAN_ALLOCATE_IN_OLD_POINTER_SPACE = 1 << 2,
- ALLOCATE_DOUBLE_ALIGNED = 1 << 3,
- PREFILL_WITH_FILLER = 1 << 4
- };
-
- HAllocate(HValue* context, HValue* size, HType type, Flags flags)
- : flags_(flags) {
- SetOperandAt(0, context);
- SetOperandAt(1, size);
- set_type(type);
- set_representation(Representation::Tagged());
- SetFlag(kTrackSideEffectDominators);
- SetGVNFlag(kChangesNewSpacePromotion);
- SetGVNFlag(kDependsOnNewSpacePromotion);
+ static HAllocate* New(Zone* zone,
+ HValue* context,
+ HValue* size,
+ HType type,
+ PretenureFlag pretenure_flag,
+ InstanceType instance_type) {
+ return new(zone) HAllocate(context, size, type, pretenure_flag,
+ instance_type);
}
// Maximum instance size for which allocations will be inlined.
static const int kMaxInlineSize = 64 * kPointerSize;
- static Flags DefaultFlags() {
- return CAN_ALLOCATE_IN_NEW_SPACE;
- }
-
- static Flags DefaultFlags(ElementsKind kind) {
- Flags flags = CAN_ALLOCATE_IN_NEW_SPACE;
- if (IsFastDoubleElementsKind(kind)) {
- flags = static_cast<HAllocate::Flags>(
- flags | HAllocate::ALLOCATE_DOUBLE_ALIGNED);
- }
- return flags;
- }
-
HValue* context() { return OperandAt(0); }
HValue* size() { return OperandAt(1); }
@@ -5260,25 +5485,16 @@
known_initial_map_ = known_initial_map;
}
- bool CanAllocateInNewSpace() const {
- return (flags_ & CAN_ALLOCATE_IN_NEW_SPACE) != 0;
+ bool IsNewSpaceAllocation() const {
+ return (flags_ & ALLOCATE_IN_NEW_SPACE) != 0;
}
- bool CanAllocateInOldDataSpace() const {
- return (flags_ & CAN_ALLOCATE_IN_OLD_DATA_SPACE) != 0;
+ bool IsOldDataSpaceAllocation() const {
+ return (flags_ & ALLOCATE_IN_OLD_DATA_SPACE) != 0;
}
- bool CanAllocateInOldPointerSpace() const {
- return (flags_ & CAN_ALLOCATE_IN_OLD_POINTER_SPACE) != 0;
- }
-
- bool CanAllocateInOldSpace() const {
- return CanAllocateInOldDataSpace() ||
- CanAllocateInOldPointerSpace();
- }
-
- bool GuaranteedInNewSpace() const {
- return CanAllocateInNewSpace() && !CanAllocateInOldSpace();
+ bool IsOldPointerSpaceAllocation() const {
+ return (flags_ & ALLOCATE_IN_OLD_POINTER_SPACE) != 0;
}
bool MustAllocateDoubleAligned() const {
@@ -5289,8 +5505,12 @@
return (flags_ & PREFILL_WITH_FILLER) != 0;
}
- void SetFlags(Flags flags) {
- flags_ = static_cast<HAllocate::Flags>(flags_ | flags);
+ void MakePrefillWithFiller() {
+ flags_ = static_cast<HAllocate::Flags>(flags_ | PREFILL_WITH_FILLER);
+ }
+
+ void MakeDoubleAligned() {
+ flags_ = static_cast<HAllocate::Flags>(flags_ | ALLOCATE_DOUBLE_ALIGNED);
}
void UpdateSize(HValue* size) {
@@ -5305,6 +5525,36 @@
DECLARE_CONCRETE_INSTRUCTION(Allocate)
private:
+ enum Flags {
+ ALLOCATE_IN_NEW_SPACE = 1 << 0,
+ ALLOCATE_IN_OLD_DATA_SPACE = 1 << 1,
+ ALLOCATE_IN_OLD_POINTER_SPACE = 1 << 2,
+ ALLOCATE_DOUBLE_ALIGNED = 1 << 3,
+ PREFILL_WITH_FILLER = 1 << 4
+ };
+
+ HAllocate(HValue* context,
+ HValue* size,
+ HType type,
+ PretenureFlag pretenure_flag,
+ InstanceType instance_type)
+ : HTemplateInstruction<2>(type) {
+ SetOperandAt(0, context);
+ SetOperandAt(1, size);
+ set_representation(Representation::Tagged());
+ SetFlag(kTrackSideEffectDominators);
+ SetGVNFlag(kChangesNewSpacePromotion);
+ SetGVNFlag(kDependsOnNewSpacePromotion);
+ flags_ = pretenure_flag == TENURED
+ ? (Heap::TargetSpaceId(instance_type) == OLD_POINTER_SPACE
+ ? ALLOCATE_IN_OLD_POINTER_SPACE : ALLOCATE_IN_OLD_DATA_SPACE)
+ : ALLOCATE_IN_NEW_SPACE;
+ if (instance_type == FIXED_DOUBLE_ARRAY_TYPE) {
+ flags_ = static_cast<HAllocate::Flags>(flags_ |
+ ALLOCATE_DOUBLE_ALIGNED);
+ }
+ }
+
Flags flags_;
Handle<Map> known_initial_map_;
};
@@ -5312,12 +5562,12 @@
class HInnerAllocatedObject: public HTemplateInstruction<1> {
public:
- HInnerAllocatedObject(HValue* value, int offset, HType type = HType::Tagged())
- : offset_(offset) {
- ASSERT(value->IsAllocate());
- SetOperandAt(0, value);
- set_type(type);
- set_representation(Representation::Tagged());
+ static HInnerAllocatedObject* New(Zone* zone,
+ HValue* context,
+ HValue* value,
+ int offset,
+ HType type = HType::Tagged()) {
+ return new(zone) HInnerAllocatedObject(value, offset, type);
}
HValue* base_object() { return OperandAt(0); }
@@ -5332,6 +5582,14 @@
DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject)
private:
+ HInnerAllocatedObject(HValue* value, int offset, HType type = HType::Tagged())
+ : HTemplateInstruction<1>(type), offset_(offset) {
+ ASSERT(value->IsAllocate());
+ SetOperandAt(0, value);
+ set_type(type);
+ set_representation(Representation::Tagged());
+ }
+
int offset_;
};
@@ -5353,9 +5611,14 @@
if (object->IsConstant() && HConstant::cast(object)->IsCell()) {
return false;
}
+ if (object->IsConstant() &&
+ HConstant::cast(object)->HasExternalReferenceValue()) {
+ // Stores to external references require no write barriers
+ return false;
+ }
if (object != new_space_dominator) return true;
if (object->IsAllocate()) {
- return !HAllocate::cast(object)->GuaranteedInNewSpace();
+ return !HAllocate::cast(object)->IsNewSpaceAllocation();
}
return true;
}
@@ -5363,14 +5626,8 @@
class HStoreGlobalCell: public HUnaryOperation {
public:
- HStoreGlobalCell(HValue* value,
- Handle<PropertyCell> cell,
- PropertyDetails details)
- : HUnaryOperation(value),
- cell_(cell),
- details_(details) {
- SetGVNFlag(kChangesGlobalVars);
- }
+ DECLARE_INSTRUCTION_FACTORY_P3(HStoreGlobalCell, HValue*,
+ Handle<PropertyCell>, PropertyDetails);
Handle<PropertyCell> cell() const { return cell_; }
bool RequiresHoleCheck() {
@@ -5388,6 +5645,15 @@
DECLARE_CONCRETE_INSTRUCTION(StoreGlobalCell)
private:
+ HStoreGlobalCell(HValue* value,
+ Handle<PropertyCell> cell,
+ PropertyDetails details)
+ : HUnaryOperation(value),
+ cell_(cell),
+ details_(details) {
+ SetGVNFlag(kChangesGlobalVars);
+ }
+
Handle<PropertyCell> cell_;
PropertyDetails details_;
};
@@ -5395,18 +5661,14 @@
class HStoreGlobalGeneric: public HTemplateInstruction<3> {
public:
- HStoreGlobalGeneric(HValue* context,
- HValue* global_object,
- Handle<Object> name,
- HValue* value,
- StrictModeFlag strict_mode_flag)
- : name_(name),
- strict_mode_flag_(strict_mode_flag) {
- SetOperandAt(0, context);
- SetOperandAt(1, global_object);
- SetOperandAt(2, value);
- set_representation(Representation::Tagged());
- SetAllSideEffects();
+ inline static HStoreGlobalGeneric* New(Zone* zone,
+ HValue* context,
+ HValue* global_object,
+ Handle<Object> name,
+ HValue* value,
+ StrictModeFlag strict_mode_flag) {
+ return new(zone) HStoreGlobalGeneric(context, global_object,
+ name, value, strict_mode_flag);
}
HValue* context() { return OperandAt(0); }
@@ -5424,6 +5686,20 @@
DECLARE_CONCRETE_INSTRUCTION(StoreGlobalGeneric)
private:
+ HStoreGlobalGeneric(HValue* context,
+ HValue* global_object,
+ Handle<Object> name,
+ HValue* value,
+ StrictModeFlag strict_mode_flag)
+ : name_(name),
+ strict_mode_flag_(strict_mode_flag) {
+ SetOperandAt(0, context);
+ SetOperandAt(1, global_object);
+ SetOperandAt(2, value);
+ set_representation(Representation::Tagged());
+ SetAllSideEffects();
+ }
+
Handle<Object> name_;
StrictModeFlag strict_mode_flag_;
};
@@ -5511,12 +5787,8 @@
kCheckIgnoreAssignment
};
- HStoreContextSlot(HValue* context, int slot_index, Mode mode, HValue* value)
- : slot_index_(slot_index), mode_(mode) {
- SetOperandAt(0, context);
- SetOperandAt(1, value);
- SetGVNFlag(kChangesContextSlots);
- }
+ DECLARE_INSTRUCTION_FACTORY_P4(HStoreContextSlot, HValue*, int,
+ Mode, HValue*);
HValue* context() { return OperandAt(0); }
HValue* value() { return OperandAt(1); }
@@ -5544,6 +5816,13 @@
DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot)
private:
+ HStoreContextSlot(HValue* context, int slot_index, Mode mode, HValue* value)
+ : slot_index_(slot_index), mode_(mode) {
+ SetOperandAt(0, context);
+ SetOperandAt(1, value);
+ SetGVNFlag(kChangesContextSlots);
+ }
+
int slot_index_;
Mode mode_;
};
@@ -5554,7 +5833,15 @@
class HObjectAccess {
public:
inline bool IsInobject() const {
- return portion() != kBackingStore;
+ return portion() != kBackingStore && portion() != kExternalMemory;
+ }
+
+ inline bool IsExternalMemory() const {
+ return portion() == kExternalMemory;
+ }
+
+ inline bool IsStringLength() const {
+ return portion() == kStringLengths;
}
inline int offset() const {
@@ -5584,9 +5871,11 @@
static HObjectAccess ForArrayLength(ElementsKind elements_kind) {
return HObjectAccess(
- kArrayLengths, JSArray::kLengthOffset,
- IsFastElementsKind(elements_kind) && FLAG_track_fields ?
- Representation::Smi() : Representation::Tagged());
+ kArrayLengths,
+ JSArray::kLengthOffset,
+ IsFastElementsKind(elements_kind) &&
+ FLAG_track_fields
+ ? Representation::Smi() : Representation::Tagged());
}
static HObjectAccess ForAllocationSiteTransitionInfo() {
@@ -5597,11 +5886,23 @@
return HObjectAccess(kInobject, AllocationSite::kWeakNextOffset);
}
+ static HObjectAccess ForAllocationSiteList() {
+ return HObjectAccess(kExternalMemory, 0, Representation::Tagged());
+ }
+
static HObjectAccess ForFixedArrayLength() {
return HObjectAccess(
- kArrayLengths, FixedArray::kLengthOffset,
- FLAG_track_fields ?
- Representation::Smi() : Representation::Tagged());
+ kArrayLengths,
+ FixedArray::kLengthOffset,
+ FLAG_track_fields ? Representation::Smi() : Representation::Tagged());
+ }
+
+ static HObjectAccess ForStringLength() {
+ STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
+ return HObjectAccess(
+ kStringLengths,
+ String::kLengthOffset,
+ FLAG_track_fields ? Representation::Smi() : Representation::Tagged());
}
static HObjectAccess ForPropertiesPointer() {
@@ -5628,6 +5929,10 @@
return HObjectAccess(kInobject, AllocationMemento::kAllocationSiteOffset);
}
+ static HObjectAccess ForCounter() {
+ return HObjectAccess(kExternalMemory, 0, Representation::Integer32());
+ }
+
// Create an access to an offset in a fixed array header.
static HObjectAccess ForFixedArrayHeader(int offset);
@@ -5663,10 +5968,12 @@
enum Portion {
kMaps, // map of an object
kArrayLengths, // the length of an array
+ kStringLengths, // the length of a string
kElementsPointer, // elements pointer
kBackingStore, // some field in the backing store
kDouble, // some double field
- kInobject // some other in-object field
+ kInobject, // some other in-object field
+ kExternalMemory // some field in external memory
};
HObjectAccess(Portion portion, int offset,
@@ -5698,63 +6005,11 @@
};
-class HLinkObjectInList: public HUnaryOperation {
- public:
- // There needs to be a mapping from every KnownList to an external reference
- enum KnownList {
- ALLOCATION_SITE_LIST
- };
-
- HLinkObjectInList(HValue* object, HObjectAccess store_field,
- KnownList known_list)
- : HUnaryOperation(object),
- store_field_(store_field),
- known_list_(known_list) {
- set_representation(Representation::Tagged());
- }
-
- HObjectAccess store_field() const { return store_field_; }
- KnownList known_list() const { return known_list_; }
-
- virtual Representation RequiredInputRepresentation(int index) {
- return Representation::Tagged();
- }
-
- virtual void PrintDataTo(StringStream* stream);
-
- DECLARE_CONCRETE_INSTRUCTION(LinkObjectInList)
-
- private:
- HObjectAccess store_field_;
- KnownList known_list_;
-};
-
-
class HLoadNamedField: public HTemplateInstruction<2> {
public:
- HLoadNamedField(HValue* object,
- HObjectAccess access,
- HValue* typecheck = NULL)
- : access_(access) {
- ASSERT(object != NULL);
- SetOperandAt(0, object);
- SetOperandAt(1, typecheck != NULL ? typecheck : object);
-
- Representation representation = access.representation();
- if (representation.IsSmi()) {
- set_type(HType::Smi());
- set_representation(representation);
- } else if (representation.IsDouble()) {
- set_representation(representation);
- } else if (FLAG_track_heap_object_fields &&
- representation.IsHeapObject()) {
- set_type(HType::NonPrimitive());
- set_representation(Representation::Tagged());
- } else {
- set_representation(Representation::Tagged());
- }
- access.SetGVNFlags(this, false);
- }
+ DECLARE_INSTRUCTION_FACTORY_P2(HLoadNamedField, HValue*, HObjectAccess);
+ DECLARE_INSTRUCTION_FACTORY_P3(HLoadNamedField, HValue*, HObjectAccess,
+ HValue*);
HValue* object() { return OperandAt(0); }
HValue* typecheck() {
@@ -5770,8 +6025,13 @@
virtual bool HasEscapingOperandAt(int index) { return false; }
virtual Representation RequiredInputRepresentation(int index) {
+ if (index == 0 && access().IsExternalMemory()) {
+ // object must be external in case of external memory access
+ return Representation::External();
+ }
return Representation::Tagged();
}
+ virtual Range* InferRange(Zone* zone);
virtual void PrintDataTo(StringStream* stream);
DECLARE_CONCRETE_INSTRUCTION(LoadNamedField)
@@ -5783,6 +6043,32 @@
}
private:
+ HLoadNamedField(HValue* object,
+ HObjectAccess access,
+ HValue* typecheck = NULL)
+ : access_(access) {
+ ASSERT(object != NULL);
+ SetOperandAt(0, object);
+ SetOperandAt(1, typecheck != NULL ? typecheck : object);
+
+ Representation representation = access.representation();
+ if (representation.IsSmi()) {
+ set_type(HType::Smi());
+ set_representation(representation);
+ } else if (representation.IsDouble() ||
+ representation.IsExternal() ||
+ representation.IsInteger32()) {
+ set_representation(representation);
+ } else if (FLAG_track_heap_object_fields &&
+ representation.IsHeapObject()) {
+ set_type(HType::NonPrimitive());
+ set_representation(Representation::Tagged());
+ } else {
+ set_representation(Representation::Tagged());
+ }
+ access.SetGVNFlags(this, false);
+ }
+
virtual bool IsDeletable() const { return true; }
HObjectAccess access_;
@@ -5901,55 +6187,10 @@
class HLoadKeyed
: public HTemplateInstruction<3>, public ArrayInstructionInterface {
public:
- HLoadKeyed(HValue* obj,
- HValue* key,
- HValue* dependency,
- ElementsKind elements_kind,
- LoadKeyedHoleMode mode = NEVER_RETURN_HOLE)
- : bit_field_(0) {
- bit_field_ = ElementsKindField::encode(elements_kind) |
- HoleModeField::encode(mode);
-
- SetOperandAt(0, obj);
- SetOperandAt(1, key);
- SetOperandAt(2, dependency != NULL ? dependency : obj);
-
- if (!is_external()) {
- // I can detect the case between storing double (holey and fast) and
- // smi/object by looking at elements_kind_.
- ASSERT(IsFastSmiOrObjectElementsKind(elements_kind) ||
- IsFastDoubleElementsKind(elements_kind));
-
- if (IsFastSmiOrObjectElementsKind(elements_kind)) {
- if (IsFastSmiElementsKind(elements_kind) &&
- (!IsHoleyElementsKind(elements_kind) ||
- mode == NEVER_RETURN_HOLE)) {
- set_type(HType::Smi());
- set_representation(Representation::Smi());
- } else {
- set_representation(Representation::Tagged());
- }
-
- SetGVNFlag(kDependsOnArrayElements);
- } else {
- set_representation(Representation::Double());
- SetGVNFlag(kDependsOnDoubleArrayElements);
- }
- } else {
- if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
- elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
- set_representation(Representation::Double());
- } else {
- set_representation(Representation::Integer32());
- }
-
- SetGVNFlag(kDependsOnSpecializedArrayElements);
- // Native code could change the specialized array.
- SetGVNFlag(kDependsOnCalls);
- }
-
- SetFlag(kUseGVN);
- }
+ DECLARE_INSTRUCTION_FACTORY_P4(HLoadKeyed, HValue*, HValue*, HValue*,
+ ElementsKind);
+ DECLARE_INSTRUCTION_FACTORY_P5(HLoadKeyed, HValue*, HValue*, HValue*,
+ ElementsKind, LoadKeyedHoleMode);
bool is_external() const {
return IsExternalArrayElementsKind(elements_kind());
@@ -6018,6 +6259,56 @@
}
private:
+ HLoadKeyed(HValue* obj,
+ HValue* key,
+ HValue* dependency,
+ ElementsKind elements_kind,
+ LoadKeyedHoleMode mode = NEVER_RETURN_HOLE)
+ : bit_field_(0) {
+ bit_field_ = ElementsKindField::encode(elements_kind) |
+ HoleModeField::encode(mode);
+
+ SetOperandAt(0, obj);
+ SetOperandAt(1, key);
+ SetOperandAt(2, dependency != NULL ? dependency : obj);
+
+ if (!is_external()) {
+ // I can detect the case between storing double (holey and fast) and
+ // smi/object by looking at elements_kind_.
+ ASSERT(IsFastSmiOrObjectElementsKind(elements_kind) ||
+ IsFastDoubleElementsKind(elements_kind));
+
+ if (IsFastSmiOrObjectElementsKind(elements_kind)) {
+ if (IsFastSmiElementsKind(elements_kind) &&
+ (!IsHoleyElementsKind(elements_kind) ||
+ mode == NEVER_RETURN_HOLE)) {
+ set_type(HType::Smi());
+ set_representation(Representation::Smi());
+ } else {
+ set_representation(Representation::Tagged());
+ }
+
+ SetGVNFlag(kDependsOnArrayElements);
+ } else {
+ set_representation(Representation::Double());
+ SetGVNFlag(kDependsOnDoubleArrayElements);
+ }
+ } else {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
+ elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
+ set_representation(Representation::Double());
+ } else {
+ set_representation(Representation::Integer32());
+ }
+
+ SetGVNFlag(kDependsOnExternalMemory);
+ // Native code could change the specialized array.
+ SetGVNFlag(kDependsOnCalls);
+ }
+
+ SetFlag(kUseGVN);
+ }
+
virtual bool IsDeletable() const {
return !RequiresHoleCheck();
}
@@ -6083,26 +6374,20 @@
class HStoreNamedField: public HTemplateInstruction<2> {
public:
- HStoreNamedField(HValue* obj,
- HObjectAccess access,
- HValue* val)
- : access_(access),
- transition_(),
- transition_unique_id_(),
- new_space_dominator_(NULL),
- write_barrier_mode_(UPDATE_WRITE_BARRIER) {
- SetOperandAt(0, obj);
- SetOperandAt(1, val);
- access.SetGVNFlags(this, true);
- }
+ DECLARE_INSTRUCTION_FACTORY_P3(HStoreNamedField, HValue*,
+ HObjectAccess, HValue*);
DECLARE_CONCRETE_INSTRUCTION(StoreNamedField)
virtual bool HasEscapingOperandAt(int index) { return index == 1; }
virtual Representation RequiredInputRepresentation(int index) {
- if (index == 1 && field_representation().IsDouble()) {
- return field_representation();
- } else if (index == 1 && field_representation().IsSmi()) {
+ if (index == 0 && access().IsExternalMemory()) {
+ // object must be external in case of external memory access
+ return Representation::External();
+ } else if (index == 1 &&
+ (field_representation().IsDouble() ||
+ field_representation().IsSmi() ||
+ field_representation().IsInteger32())) {
return field_representation();
}
return Representation::Tagged();
@@ -6140,6 +6425,8 @@
if (IsSkipWriteBarrier()) return false;
if (field_representation().IsDouble()) return false;
if (field_representation().IsSmi()) return false;
+ if (field_representation().IsInteger32()) return false;
+ if (field_representation().IsExternal()) return false;
return StoringValueNeedsWriteBarrier(value()) &&
ReceiverObjectNeedsWriteBarrier(object(), new_space_dominator());
}
@@ -6158,6 +6445,19 @@
}
private:
+ HStoreNamedField(HValue* obj,
+ HObjectAccess access,
+ HValue* val)
+ : access_(access),
+ transition_(),
+ transition_unique_id_(),
+ new_space_dominator_(NULL),
+ write_barrier_mode_(UPDATE_WRITE_BARRIER) {
+ SetOperandAt(0, obj);
+ SetOperandAt(1, val);
+ access.SetGVNFlags(this, true);
+ }
+
HObjectAccess access_;
Handle<Map> transition_;
UniqueValueId transition_unique_id_;
@@ -6204,38 +6504,8 @@
class HStoreKeyed
: public HTemplateInstruction<3>, public ArrayInstructionInterface {
public:
- HStoreKeyed(HValue* obj, HValue* key, HValue* val,
- ElementsKind elements_kind)
- : elements_kind_(elements_kind),
- index_offset_(0),
- is_dehoisted_(false),
- is_uninitialized_(false),
- new_space_dominator_(NULL) {
- SetOperandAt(0, obj);
- SetOperandAt(1, key);
- SetOperandAt(2, val);
-
- if (IsFastObjectElementsKind(elements_kind)) {
- SetFlag(kTrackSideEffectDominators);
- SetGVNFlag(kDependsOnNewSpacePromotion);
- }
- if (is_external()) {
- SetGVNFlag(kChangesSpecializedArrayElements);
- SetFlag(kAllowUndefinedAsNaN);
- } else if (IsFastDoubleElementsKind(elements_kind)) {
- SetGVNFlag(kChangesDoubleArrayElements);
- } else if (IsFastSmiElementsKind(elements_kind)) {
- SetGVNFlag(kChangesArrayElements);
- } else {
- SetGVNFlag(kChangesArrayElements);
- }
-
- // EXTERNAL_{UNSIGNED_,}{BYTE,SHORT,INT}_ELEMENTS are truncating.
- if (elements_kind >= EXTERNAL_BYTE_ELEMENTS &&
- elements_kind <= EXTERNAL_UNSIGNED_INT_ELEMENTS) {
- SetFlag(kTruncatingToInt32);
- }
- }
+ DECLARE_INSTRUCTION_FACTORY_P4(HStoreKeyed, HValue*, HValue*, HValue*,
+ ElementsKind);
virtual bool HasEscapingOperandAt(int index) { return index != 0; }
virtual Representation RequiredInputRepresentation(int index) {
@@ -6332,6 +6602,39 @@
DECLARE_CONCRETE_INSTRUCTION(StoreKeyed)
private:
+ HStoreKeyed(HValue* obj, HValue* key, HValue* val,
+ ElementsKind elements_kind)
+ : elements_kind_(elements_kind),
+ index_offset_(0),
+ is_dehoisted_(false),
+ is_uninitialized_(false),
+ new_space_dominator_(NULL) {
+ SetOperandAt(0, obj);
+ SetOperandAt(1, key);
+ SetOperandAt(2, val);
+
+ if (IsFastObjectElementsKind(elements_kind)) {
+ SetFlag(kTrackSideEffectDominators);
+ SetGVNFlag(kDependsOnNewSpacePromotion);
+ }
+ if (is_external()) {
+ SetGVNFlag(kChangesExternalMemory);
+ SetFlag(kAllowUndefinedAsNaN);
+ } else if (IsFastDoubleElementsKind(elements_kind)) {
+ SetGVNFlag(kChangesDoubleArrayElements);
+ } else if (IsFastSmiElementsKind(elements_kind)) {
+ SetGVNFlag(kChangesArrayElements);
+ } else {
+ SetGVNFlag(kChangesArrayElements);
+ }
+
+ // EXTERNAL_{UNSIGNED_,}{BYTE,SHORT,INT}_ELEMENTS are truncating.
+ if (elements_kind >= EXTERNAL_BYTE_ELEMENTS &&
+ elements_kind <= EXTERNAL_UNSIGNED_INT_ELEMENTS) {
+ SetFlag(kTruncatingToInt32);
+ }
+ }
+
ElementsKind elements_kind_;
uint32_t index_offset_;
bool is_dehoisted_ : 1;
@@ -6377,29 +6680,13 @@
class HTransitionElementsKind: public HTemplateInstruction<2> {
public:
- HTransitionElementsKind(HValue* context,
- HValue* object,
- Handle<Map> original_map,
- Handle<Map> transitioned_map)
- : original_map_(original_map),
- transitioned_map_(transitioned_map),
- original_map_unique_id_(),
- transitioned_map_unique_id_(),
- from_kind_(original_map->elements_kind()),
- to_kind_(transitioned_map->elements_kind()) {
- SetOperandAt(0, object);
- SetOperandAt(1, context);
- SetFlag(kUseGVN);
- SetGVNFlag(kChangesElementsKind);
- if (original_map->has_fast_double_elements()) {
- SetGVNFlag(kChangesElementsPointer);
- SetGVNFlag(kChangesNewSpacePromotion);
- }
- if (transitioned_map->has_fast_double_elements()) {
- SetGVNFlag(kChangesElementsPointer);
- SetGVNFlag(kChangesNewSpacePromotion);
- }
- set_representation(Representation::Tagged());
+ inline static HTransitionElementsKind* New(Zone* zone,
+ HValue* context,
+ HValue* object,
+ Handle<Map> original_map,
+ Handle<Map> transitioned_map) {
+ return new(zone) HTransitionElementsKind(context, object,
+ original_map, transitioned_map);
}
virtual Representation RequiredInputRepresentation(int index) {
@@ -6430,6 +6717,31 @@
}
private:
+ HTransitionElementsKind(HValue* context,
+ HValue* object,
+ Handle<Map> original_map,
+ Handle<Map> transitioned_map)
+ : original_map_(original_map),
+ transitioned_map_(transitioned_map),
+ original_map_unique_id_(),
+ transitioned_map_unique_id_(),
+ from_kind_(original_map->elements_kind()),
+ to_kind_(transitioned_map->elements_kind()) {
+ SetOperandAt(0, object);
+ SetOperandAt(1, context);
+ SetFlag(kUseGVN);
+ SetGVNFlag(kChangesElementsKind);
+ if (original_map->has_fast_double_elements()) {
+ SetGVNFlag(kChangesElementsPointer);
+ SetGVNFlag(kChangesNewSpacePromotion);
+ }
+ if (transitioned_map->has_fast_double_elements()) {
+ SetGVNFlag(kChangesElementsPointer);
+ SetGVNFlag(kChangesNewSpacePromotion);
+ }
+ set_representation(Representation::Tagged());
+ }
+
Handle<Map> original_map_;
Handle<Map> transitioned_map_;
UniqueValueId original_map_unique_id_;
@@ -6453,10 +6765,6 @@
return Representation::Tagged();
}
- virtual HType CalculateInferredType() {
- return HType::String();
- }
-
DECLARE_CONCRETE_INSTRUCTION(StringAdd)
protected:
@@ -6464,15 +6772,16 @@
private:
HStringAdd(HValue* context, HValue* left, HValue* right, StringAddFlags flags)
- : HBinaryOperation(context, left, right), flags_(flags) {
+ : HBinaryOperation(context, left, right, HType::String()), flags_(flags) {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
SetGVNFlag(kDependsOnMaps);
SetGVNFlag(kChangesNewSpacePromotion);
}
- // TODO(svenpanne) Might be safe, but leave it out until we know for sure.
- // virtual bool IsDeletable() const { return true; }
+ // No side-effects except possible allocation.
+ // NOTE: this instruction _does not_ call ToString() on its inputs.
+ virtual bool IsDeletable() const { return true; }
const StringAddFlags flags_;
};
@@ -6480,14 +6789,11 @@
class HStringCharCodeAt: public HTemplateInstruction<3> {
public:
- HStringCharCodeAt(HValue* context, HValue* string, HValue* index) {
- SetOperandAt(0, context);
- SetOperandAt(1, string);
- SetOperandAt(2, index);
- set_representation(Representation::Integer32());
- SetFlag(kUseGVN);
- SetGVNFlag(kDependsOnMaps);
- SetGVNFlag(kChangesNewSpacePromotion);
+ static HStringCharCodeAt* New(Zone* zone,
+ HValue* context,
+ HValue* string,
+ HValue* index) {
+ return new(zone) HStringCharCodeAt(context, string, index);
}
virtual Representation RequiredInputRepresentation(int index) {
@@ -6497,9 +6803,9 @@
: Representation::Tagged();
}
- HValue* context() { return OperandAt(0); }
- HValue* string() { return OperandAt(1); }
- HValue* index() { return OperandAt(2); }
+ HValue* context() const { return OperandAt(0); }
+ HValue* string() const { return OperandAt(1); }
+ HValue* index() const { return OperandAt(2); }
DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt)
@@ -6510,9 +6816,19 @@
return new(zone) Range(0, String::kMaxUtf16CodeUnit);
}
- // TODO(svenpanne) Might be safe, but leave it out until we know for sure.
- // private:
- // virtual bool IsDeletable() const { return true; }
+ private:
+ HStringCharCodeAt(HValue* context, HValue* string, HValue* index) {
+ SetOperandAt(0, context);
+ SetOperandAt(1, string);
+ SetOperandAt(2, index);
+ set_representation(Representation::Integer32());
+ SetFlag(kUseGVN);
+ SetGVNFlag(kDependsOnMaps);
+ SetGVNFlag(kChangesNewSpacePromotion);
+ }
+
+ // No side effects: runtime function assumes string + number inputs.
+ virtual bool IsDeletable() const { return true; }
};
@@ -6527,17 +6843,17 @@
? Representation::Tagged()
: Representation::Integer32();
}
- virtual HType CalculateInferredType();
- HValue* context() { return OperandAt(0); }
- HValue* value() { return OperandAt(1); }
+ HValue* context() const { return OperandAt(0); }
+ HValue* value() const { return OperandAt(1); }
virtual bool DataEquals(HValue* other) { return true; }
DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode)
private:
- HStringCharFromCode(HValue* context, HValue* char_code) {
+ HStringCharFromCode(HValue* context, HValue* char_code)
+ : HTemplateInstruction<2>(HType::String()) {
SetOperandAt(0, context);
SetOperandAt(1, char_code);
set_representation(Representation::Tagged());
@@ -6545,41 +6861,9 @@
SetGVNFlag(kChangesNewSpacePromotion);
}
- // TODO(svenpanne) Might be safe, but leave it out until we know for sure.
- // virtual bool IsDeletable() const { return true; }
-};
-
-
-class HStringLength: public HUnaryOperation {
- public:
- static HInstruction* New(Zone* zone, HValue* string);
-
- virtual Representation RequiredInputRepresentation(int index) {
- return Representation::Tagged();
+ virtual bool IsDeletable() const {
+ return !value()->ToNumberCanBeObserved();
}
-
- virtual HType CalculateInferredType() {
- STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
- return HType::Smi();
- }
-
- DECLARE_CONCRETE_INSTRUCTION(StringLength)
-
- protected:
- virtual bool DataEquals(HValue* other) { return true; }
-
- virtual Range* InferRange(Zone* zone) {
- return new(zone) Range(0, String::kMaxLength);
- }
-
- private:
- explicit HStringLength(HValue* string) : HUnaryOperation(string) {
- set_representation(Representation::Tagged());
- SetFlag(kUseGVN);
- SetGVNFlag(kDependsOnMaps);
- }
-
- virtual bool IsDeletable() const { return true; }
};
@@ -6625,6 +6909,7 @@
flags_(flags) {
SetOperandAt(0, context);
SetAllSideEffects();
+ set_type(HType::JSObject());
}
HValue* context() { return OperandAt(0); }
@@ -6635,7 +6920,6 @@
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
}
- virtual HType CalculateInferredType();
DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral)
@@ -6651,7 +6935,8 @@
HFunctionLiteral(HValue* context,
Handle<SharedFunctionInfo> shared,
bool pretenure)
- : shared_info_(shared),
+ : HTemplateInstruction<1>(HType::JSObject()),
+ shared_info_(shared),
pretenure_(pretenure),
has_no_literals_(shared->num_literals() == 0),
is_generator_(shared->is_generator()),
@@ -6666,7 +6951,6 @@
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
}
- virtual HType CalculateInferredType();
DECLARE_CONCRETE_INSTRUCTION(FunctionLiteral)
@@ -6713,9 +6997,7 @@
class HTrapAllocationMemento : public HTemplateInstruction<1> {
public:
- explicit HTrapAllocationMemento(HValue* obj) {
- SetOperandAt(0, obj);
- }
+ DECLARE_INSTRUCTION_FACTORY_P1(HTrapAllocationMemento, HValue*);
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
@@ -6724,11 +7006,25 @@
HValue* object() { return OperandAt(0); }
DECLARE_CONCRETE_INSTRUCTION(TrapAllocationMemento)
+
+ private:
+ explicit HTrapAllocationMemento(HValue* obj) {
+ SetOperandAt(0, obj);
+ }
};
class HToFastProperties: public HUnaryOperation {
public:
+ DECLARE_INSTRUCTION_FACTORY_P1(HToFastProperties, HValue*);
+
+ virtual Representation RequiredInputRepresentation(int index) {
+ return Representation::Tagged();
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(ToFastProperties)
+
+ private:
explicit HToFastProperties(HValue* value) : HUnaryOperation(value) {
// This instruction is not marked as having side effects, but
// changes the map of the input operand. Use it only when creating
@@ -6742,13 +7038,6 @@
set_representation(Representation::Tagged());
}
- virtual Representation RequiredInputRepresentation(int index) {
- return Representation::Tagged();
- }
-
- DECLARE_CONCRETE_INSTRUCTION(ToFastProperties)
-
- private:
virtual bool IsDeletable() const { return true; }
};
@@ -6821,15 +7110,7 @@
class HCheckMapValue: public HTemplateInstruction<2> {
public:
- HCheckMapValue(HValue* value,
- HValue* map) {
- SetOperandAt(0, value);
- SetOperandAt(1, map);
- set_representation(Representation::Tagged());
- SetFlag(kUseGVN);
- SetGVNFlag(kDependsOnMaps);
- SetGVNFlag(kDependsOnElementsKind);
- }
+ DECLARE_INSTRUCTION_FACTORY_P2(HCheckMapValue, HValue*, HValue*);
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
@@ -6850,17 +7131,26 @@
virtual bool DataEquals(HValue* other) {
return true;
}
+
+ private:
+ HCheckMapValue(HValue* value,
+ HValue* map) {
+ SetOperandAt(0, value);
+ SetOperandAt(1, map);
+ set_representation(Representation::Tagged());
+ SetFlag(kUseGVN);
+ SetGVNFlag(kDependsOnMaps);
+ SetGVNFlag(kDependsOnElementsKind);
+ }
};
class HForInPrepareMap : public HTemplateInstruction<2> {
public:
- HForInPrepareMap(HValue* context,
- HValue* object) {
- SetOperandAt(0, context);
- SetOperandAt(1, object);
- set_representation(Representation::Tagged());
- SetAllSideEffects();
+ static HForInPrepareMap* New(Zone* zone,
+ HValue* context,
+ HValue* object) {
+ return new(zone) HForInPrepareMap(context, object);
}
virtual Representation RequiredInputRepresentation(int index) {
@@ -6877,18 +7167,21 @@
}
DECLARE_CONCRETE_INSTRUCTION(ForInPrepareMap);
+
+ private:
+ HForInPrepareMap(HValue* context,
+ HValue* object) {
+ SetOperandAt(0, context);
+ SetOperandAt(1, object);
+ set_representation(Representation::Tagged());
+ SetAllSideEffects();
+ }
};
class HForInCacheArray : public HTemplateInstruction<2> {
public:
- HForInCacheArray(HValue* enumerable,
- HValue* keys,
- int idx) : idx_(idx) {
- SetOperandAt(0, enumerable);
- SetOperandAt(1, keys);
- set_representation(Representation::Tagged());
- }
+ DECLARE_INSTRUCTION_FACTORY_P3(HForInCacheArray, HValue*, HValue*, int);
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
@@ -6915,6 +7208,14 @@
DECLARE_CONCRETE_INSTRUCTION(ForInCacheArray);
private:
+ HForInCacheArray(HValue* enumerable,
+ HValue* keys,
+ int idx) : idx_(idx) {
+ SetOperandAt(0, enumerable);
+ SetOperandAt(1, keys);
+ set_representation(Representation::Tagged());
+ }
+
int idx_;
HForInCacheArray* index_cache_;
};
diff --git a/src/hydrogen-mark-deoptimize.cc b/src/hydrogen-mark-deoptimize.cc
new file mode 100644
index 0000000..111fcd2
--- /dev/null
+++ b/src/hydrogen-mark-deoptimize.cc
@@ -0,0 +1,71 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "hydrogen-mark-deoptimize.h"
+
+namespace v8 {
+namespace internal {
+
+void HMarkDeoptimizeOnUndefinedPhase::Run() {
+ const ZoneList<HPhi*>* phi_list = graph()->phi_list();
+ for (int i = 0; i < phi_list->length(); i++) {
+ HPhi* phi = phi_list->at(i);
+ if (phi->CheckFlag(HValue::kAllowUndefinedAsNaN)) {
+ for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) {
+ HValue* use_value = it.value();
+ if (!use_value->CheckFlag(HValue::kAllowUndefinedAsNaN)) {
+ ProcessPhi(phi);
+ break;
+ }
+ }
+ }
+ }
+}
+
+
+void HMarkDeoptimizeOnUndefinedPhase::ProcessPhi(HPhi* phi) {
+ ASSERT(phi->CheckFlag(HValue::kAllowUndefinedAsNaN));
+ ASSERT(worklist_.is_empty());
+
+ // Push the phi onto the worklist
+ phi->ClearFlag(HValue::kAllowUndefinedAsNaN);
+ worklist_.Add(phi, zone());
+
+ // Process all phis that can reach this phi
+ while (!worklist_.is_empty()) {
+ phi = worklist_.RemoveLast();
+ for (int i = phi->OperandCount() - 1; i >= 0; --i) {
+ HValue* input = phi->OperandAt(i);
+ if (input->IsPhi() && input->CheckFlag(HValue::kAllowUndefinedAsNaN)) {
+ input->ClearFlag(HValue::kAllowUndefinedAsNaN);
+ worklist_.Add(HPhi::cast(input), zone());
+ }
+ }
+ }
+}
+
+} } // namespace v8::internal
diff --git a/src/hydrogen-mark-deoptimize.h b/src/hydrogen-mark-deoptimize.h
new file mode 100644
index 0000000..0aa2c2c
--- /dev/null
+++ b/src/hydrogen-mark-deoptimize.h
@@ -0,0 +1,63 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_HYDROGEN_MARK_DEOPTIMIZE_H_
+#define V8_HYDROGEN_MARK_DEOPTIMIZE_H_
+
+#include "hydrogen.h"
+
+namespace v8 {
+namespace internal {
+
+
+// Compute DeoptimizeOnUndefined flag for phis. Any phi that can reach a use
+// with DeoptimizeOnUndefined set must have DeoptimizeOnUndefined set.
+// Currently only HCompareNumericAndBranch, with double input representation,
+// has this flag set. The flag is used by HChange tagged->double, which must
+// deoptimize if one of its uses has this flag set.
+class HMarkDeoptimizeOnUndefinedPhase : public HPhase {
+ public:
+ explicit HMarkDeoptimizeOnUndefinedPhase(HGraph* graph)
+ : HPhase("H_Mark deoptimize on undefined", graph),
+ worklist_(16, zone()) {}
+
+ void Run();
+
+ private:
+ void ProcessPhi(HPhi* phi);
+
+ // Preallocated worklist used as an optimization so we don't have
+ // to allocate a new ZoneList for every ProcessPhi() invocation.
+ ZoneList<HPhi*> worklist_;
+
+ DISALLOW_COPY_AND_ASSIGN(HMarkDeoptimizeOnUndefinedPhase);
+};
+
+
+} } // namespace v8::internal
+
+#endif // V8_HYDROGEN_MARK_DEOPTIMIZE_H_
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index e346880..7ec65df 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -44,6 +44,7 @@
#include "hydrogen-infer-representation.h"
#include "hydrogen-infer-types.h"
#include "hydrogen-gvn.h"
+#include "hydrogen-mark-deoptimize.h"
#include "hydrogen-minus-zero.h"
#include "hydrogen-osr.h"
#include "hydrogen-range-analysis.h"
@@ -608,7 +609,9 @@
HConstant* HGraph::GetConstant(SetOncePointer<HConstant>* pointer,
int32_t value) {
if (!pointer->is_set()) {
- HConstant* constant = new(zone()) HConstant(value);
+ // Can't pass GetInvalidContext() to HConstant::New, because that will
+ // recursively call GetConstant
+ HConstant* constant = HConstant::New(zone(), NULL, value);
constant->InsertAfter(GetConstantUndefined());
pointer->set(constant);
}
@@ -834,9 +837,8 @@
void HGraphBuilder::IfBuilder::Return(HValue* value) {
HBasicBlock* block = builder_->current_block();
- HValue* context = builder_->environment()->LookupContext();
HValue* parameter_count = builder_->graph()->GetConstantMinus1();
- block->FinishExit(new(zone()) HReturn(value, context, parameter_count));
+ block->FinishExit(builder_->New<HReturn>(value, parameter_count));
builder_->set_current_block(NULL);
if (did_else_) {
first_false_block_ = NULL;
@@ -986,6 +988,28 @@
}
+void HGraphBuilder::AddIncrementCounter(StatsCounter* counter,
+ HValue* context) {
+ if (FLAG_native_code_counters && counter->Enabled()) {
+ HValue* reference = Add<HConstant>(ExternalReference(counter));
+ HValue* old_value = Add<HLoadNamedField>(reference,
+ HObjectAccess::ForCounter());
+ HValue* new_value = Add<HAdd>(old_value, graph()->GetConstant1());
+ new_value->ClearFlag(HValue::kCanOverflow); // Ignore counter overflow
+ Add<HStoreNamedField>(reference, HObjectAccess::ForCounter(),
+ new_value);
+ }
+}
+
+
+void HGraphBuilder::AddSimulate(BailoutId id,
+ RemovableSimulate removable) {
+ ASSERT(current_block() != NULL);
+ ASSERT(no_side_effects_scope_count_ == 0);
+ current_block()->AddSimulate(id, removable);
+}
+
+
HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) {
HBasicBlock* b = graph()->CreateBasicBlock();
b->SetInitialEnvironment(env);
@@ -1042,9 +1066,7 @@
HValue* HGraphBuilder::BuildCheckMap(HValue* obj, Handle<Map> map) {
- HCheckMaps* check = HCheckMaps::New(obj, map, zone(), top_info());
- AddInstruction(check);
- return check;
+ return Add<HCheckMaps>(obj, map, top_info());
}
@@ -1076,10 +1098,17 @@
Token::GTE);
capacity_checker.Then();
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
- HValue* new_capacity = BuildNewElementsCapacity(context, key);
+ HValue* max_gap = Add<HConstant>(static_cast<int32_t>(JSObject::kMaxGap));
+ HValue* max_capacity = Add<HAdd>(current_capacity, max_gap);
+ IfBuilder key_checker(this);
+ key_checker.If<HCompareNumericAndBranch>(key, max_capacity, Token::LT);
+ key_checker.Then();
+ key_checker.ElseDeopt();
+ key_checker.End();
+ HValue* new_capacity = BuildNewElementsCapacity(key);
HValue* new_elements = BuildGrowElementsCapacity(object, elements,
kind, kind, length,
new_capacity);
@@ -1095,7 +1124,8 @@
HAdd::New(zone, context, key, graph_->GetConstant1()));
new_length->ClearFlag(HValue::kCanOverflow);
- AddStore(object, HObjectAccess::ForArrayLength(kind), new_length);
+ Add<HStoreNamedField>(object, HObjectAccess::ForArrayLength(kind),
+ new_length);
}
length_checker.Else();
@@ -1152,7 +1182,7 @@
HInstruction* elements = AddLoadElements(object);
HInstruction* empty_fixed_array = Add<HConstant>(
- isolate()->factory()->empty_fixed_array(), Representation::Tagged());
+ isolate()->factory()->empty_fixed_array());
IfBuilder if_builder(this);
@@ -1163,7 +1193,7 @@
HInstruction* elements_length = AddLoadFixedArrayLength(elements);
HInstruction* array_length = is_jsarray
- ? AddLoad(object, HObjectAccess::ForArrayLength(from_kind), NULL)
+ ? Add<HLoadNamedField>(object, HObjectAccess::ForArrayLength(from_kind))
: elements_length;
BuildGrowElementsCapacity(object, elements, from_kind, to_kind,
@@ -1172,7 +1202,7 @@
if_builder.End();
}
- AddStore(object, HObjectAccess::ForMap(), map);
+ Add<HStoreNamedField>(object, HObjectAccess::ForMap(), map);
}
@@ -1187,7 +1217,6 @@
LoadKeyedHoleMode load_mode,
KeyedAccessStoreMode store_mode) {
ASSERT(!IsExternalArrayElementsKind(elements_kind) || !is_js_array);
- Zone* zone = this->zone();
// No GVNFlag is necessary for ElementsKind if there is an explicit dependency
// on a HElementsTransition instruction. The flag can also be removed if the
// map to check has FAST_HOLEY_ELEMENTS, since there can be no further
@@ -1205,15 +1234,14 @@
HValue* elements = AddLoadElements(object, mapcheck);
if (is_store && (fast_elements || fast_smi_only_elements) &&
store_mode != STORE_NO_TRANSITION_HANDLE_COW) {
- HCheckMaps* check_cow_map = HCheckMaps::New(
- elements, isolate()->factory()->fixed_array_map(), zone, top_info());
+ HCheckMaps* check_cow_map = Add<HCheckMaps>(
+ elements, isolate()->factory()->fixed_array_map(), top_info());
check_cow_map->ClearGVNFlag(kDependsOnElementsKind);
- AddInstruction(check_cow_map);
}
HInstruction* length = NULL;
if (is_js_array) {
- length = AddLoad(object, HObjectAccess::ForArrayLength(elements_kind),
- mapcheck);
+ length = Add<HLoadNamedField>(object,
+ HObjectAccess::ForArrayLength(elements_kind), mapcheck);
} else {
length = AddLoadFixedArrayLength(elements);
}
@@ -1222,8 +1250,8 @@
if (IsExternalArrayElementsKind(elements_kind)) {
if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
NoObservableSideEffectsScope no_effects(this);
- HLoadExternalArrayPointer* external_elements =
- Add<HLoadExternalArrayPointer>(elements);
+ HLoadExternalArrayPointer* external_elements =
+ Add<HLoadExternalArrayPointer>(elements);
IfBuilder length_checker(this);
length_checker.If<HCompareNumericAndBranch>(key, length, Token::LT);
length_checker.Then();
@@ -1273,11 +1301,10 @@
elements = BuildCopyElementsOnWrite(object, elements, elements_kind,
length);
} else {
- HCheckMaps* check_cow_map = HCheckMaps::New(
+ HCheckMaps* check_cow_map = Add<HCheckMaps>(
elements, isolate()->factory()->fixed_array_map(),
- zone, top_info());
+ top_info());
check_cow_map->ClearGVNFlag(kDependsOnElementsKind);
- AddInstruction(check_cow_map);
}
}
}
@@ -1286,37 +1313,29 @@
}
-HValue* HGraphBuilder::BuildAllocateElements(HValue* context,
- ElementsKind kind,
+HValue* HGraphBuilder::BuildAllocateElements(ElementsKind kind,
HValue* capacity) {
- Zone* zone = this->zone();
+ int elements_size;
+ InstanceType instance_type;
- int elements_size = IsFastDoubleElementsKind(kind)
- ? kDoubleSize : kPointerSize;
+ if (IsFastDoubleElementsKind(kind)) {
+ elements_size = kDoubleSize;
+ instance_type = FIXED_DOUBLE_ARRAY_TYPE;
+ } else {
+ elements_size = kPointerSize;
+ instance_type = FIXED_ARRAY_TYPE;
+ }
+
HConstant* elements_size_value = Add<HConstant>(elements_size);
- HValue* mul = AddInstruction(
- HMul::New(zone, context, capacity, elements_size_value));
+ HValue* mul = Add<HMul>(capacity, elements_size_value);
mul->ClearFlag(HValue::kCanOverflow);
HConstant* header_size = Add<HConstant>(FixedArray::kHeaderSize);
- HValue* total_size = AddInstruction(
- HAdd::New(zone, context, mul, header_size));
+ HValue* total_size = Add<HAdd>(mul, header_size);
total_size->ClearFlag(HValue::kCanOverflow);
- HAllocate::Flags flags = HAllocate::DefaultFlags(kind);
- if (isolate()->heap()->ShouldGloballyPretenure()) {
- // TODO(hpayer): When pretenuring can be internalized, flags can become
- // private to HAllocate.
- if (IsFastDoubleElementsKind(kind)) {
- flags = static_cast<HAllocate::Flags>(
- flags | HAllocate::CAN_ALLOCATE_IN_OLD_DATA_SPACE);
- } else {
- flags = static_cast<HAllocate::Flags>(
- flags | HAllocate::CAN_ALLOCATE_IN_OLD_POINTER_SPACE);
- }
- }
-
- return Add<HAllocate>(context, total_size, HType::JSArray(), flags);
+ return Add<HAllocate>(total_size, HType::JSArray(),
+ isolate()->heap()->GetPretenureMode(), instance_type);
}
@@ -1329,15 +1348,18 @@
: factory->fixed_array_map();
AddStoreMapConstant(elements, map);
- AddStore(elements, HObjectAccess::ForFixedArrayLength(), capacity);
+ Add<HStoreNamedField>(elements, HObjectAccess::ForFixedArrayLength(),
+ capacity);
}
HValue* HGraphBuilder::BuildAllocateElementsAndInitializeElementsHeader(
- HValue* context,
ElementsKind kind,
HValue* capacity) {
- HValue* new_elements = BuildAllocateElements(context, kind, capacity);
+ // The HForceRepresentation is to prevent possible deopt on int-smi
+ // conversion after allocation but before the new object fields are set.
+ capacity = Add<HForceRepresentation>(capacity, Representation::Smi());
+ HValue* new_elements = BuildAllocateElements(kind, capacity);
BuildInitializeElementsHeader(new_elements, kind, capacity);
return new_elements;
}
@@ -1350,14 +1372,15 @@
HValue* allocation_site_payload,
HValue* length_field) {
- AddStore(array, HObjectAccess::ForMap(), array_map);
+ Add<HStoreNamedField>(array, HObjectAccess::ForMap(), array_map);
HConstant* empty_fixed_array =
- Add<HConstant>(isolate()->factory()->empty_fixed_array());
+ Add<HConstant>(isolate()->factory()->empty_fixed_array());
HObjectAccess access = HObjectAccess::ForPropertiesPointer();
- AddStore(array, access, empty_fixed_array);
- AddStore(array, HObjectAccess::ForArrayLength(elements_kind), length_field);
+ Add<HStoreNamedField>(array, access, empty_fixed_array);
+ Add<HStoreNamedField>(array, HObjectAccess::ForArrayLength(elements_kind),
+ length_field);
if (mode == TRACK_ALLOCATION_SITE) {
BuildCreateAllocationMemento(array,
@@ -1370,10 +1393,9 @@
elements_location += AllocationMemento::kSize;
}
- HInnerAllocatedObject* elements =
- Add<HInnerAllocatedObject>(array, elements_location);
- AddStore(array, HObjectAccess::ForElementsPointer(), elements);
- return elements;
+ HValue* elements = Add<HInnerAllocatedObject>(array, elements_location);
+ Add<HStoreNamedField>(array, HObjectAccess::ForElementsPointer(), elements);
+ return static_cast<HInnerAllocatedObject*>(elements);
}
@@ -1416,8 +1438,10 @@
return Add<HStoreKeyed>(external_elements, checked_key, val, elements_kind);
} else {
ASSERT(val == NULL);
- HLoadKeyed* load = Add<HLoadKeyed>(external_elements, checked_key,
- dependency, elements_kind);
+ HLoadKeyed* load = Add<HLoadKeyed>(external_elements,
+ checked_key,
+ dependency,
+ elements_kind);
if (FLAG_opt_safe_uint32_operations &&
elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
graph()->RecordUint32Instruction(load);
@@ -1459,31 +1483,27 @@
HLoadNamedField* HGraphBuilder::AddLoadElements(HValue* object,
HValue* typecheck) {
- return AddLoad(object, HObjectAccess::ForElementsPointer(), typecheck);
+ return Add<HLoadNamedField>(object,
+ HObjectAccess::ForElementsPointer(),
+ typecheck);
}
HLoadNamedField* HGraphBuilder::AddLoadFixedArrayLength(HValue* object) {
- return AddLoad(object, HObjectAccess::ForFixedArrayLength());
+ return Add<HLoadNamedField>(object,
+ HObjectAccess::ForFixedArrayLength());
}
-HValue* HGraphBuilder::BuildNewElementsCapacity(HValue* context,
- HValue* old_capacity) {
- Zone* zone = this->zone();
- HValue* half_old_capacity =
- AddInstruction(HShr::New(zone, context, old_capacity,
- graph_->GetConstant1()));
- half_old_capacity->ClearFlag(HValue::kCanOverflow);
+HValue* HGraphBuilder::BuildNewElementsCapacity(HValue* old_capacity) {
+ HValue* half_old_capacity = Add<HShr>(old_capacity, graph_->GetConstant1());
- HValue* new_capacity = AddInstruction(
- HAdd::New(zone, context, half_old_capacity, old_capacity));
+ HValue* new_capacity = Add<HAdd>(half_old_capacity, old_capacity);
new_capacity->ClearFlag(HValue::kCanOverflow);
HValue* min_growth = Add<HConstant>(16);
- new_capacity = AddInstruction(
- HAdd::New(zone, context, new_capacity, min_growth));
+ new_capacity = Add<HAdd>(new_capacity, min_growth);
new_capacity->ClearFlag(HValue::kCanOverflow);
return new_capacity;
@@ -1497,8 +1517,6 @@
int max_size = heap->MaxRegularSpaceAllocationSize() / element_size;
max_size -= JSArray::kSize / element_size;
HConstant* max_size_constant = Add<HConstant>(max_size);
- // Since we're forcing Integer32 representation for this HBoundsCheck,
- // there's no need to Smi-check the index.
Add<HBoundsCheck>(length, max_size_constant);
}
@@ -1509,25 +1527,23 @@
ElementsKind new_kind,
HValue* length,
HValue* new_capacity) {
- HValue* context = environment()->LookupContext();
-
BuildNewSpaceArrayCheck(new_capacity, new_kind);
HValue* new_elements = BuildAllocateElementsAndInitializeElementsHeader(
- context, new_kind, new_capacity);
+ new_kind, new_capacity);
- BuildCopyElements(context, elements, kind,
+ BuildCopyElements(elements, kind,
new_elements, new_kind,
length, new_capacity);
- AddStore(object, HObjectAccess::ForElementsPointer(), new_elements);
+ Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
+ new_elements);
return new_elements;
}
-void HGraphBuilder::BuildFillElementsWithHole(HValue* context,
- HValue* elements,
+void HGraphBuilder::BuildFillElementsWithHole(HValue* elements,
ElementsKind elements_kind,
HValue* from,
HValue* to) {
@@ -1569,7 +1585,7 @@
Add<HStoreKeyed>(elements, key, hole, elements_kind);
}
} else {
- LoopBuilder builder(this, context, LoopBuilder::kPostIncrement);
+ LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement);
HValue* key = builder.BeginBody(from, to, Token::LT);
@@ -1580,8 +1596,7 @@
}
-void HGraphBuilder::BuildCopyElements(HValue* context,
- HValue* from_elements,
+void HGraphBuilder::BuildCopyElements(HValue* from_elements,
ElementsKind from_elements_kind,
HValue* to_elements,
ElementsKind to_elements_kind,
@@ -1595,11 +1610,11 @@
// If the copy might trigger a GC, make sure that the FixedArray is
// pre-initialized with holes to make sure that it's always in a consistent
// state.
- BuildFillElementsWithHole(context, to_elements, to_elements_kind,
+ BuildFillElementsWithHole(to_elements, to_elements_kind,
graph()->GetConstant0(), capacity);
}
- LoopBuilder builder(this, context, LoopBuilder::kPostIncrement);
+ LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement);
HValue* key = builder.BeginBody(graph()->GetConstant0(), length, Token::LT);
@@ -1621,14 +1636,13 @@
if (!pre_fill_with_holes && length != capacity) {
// Fill unused capacity with the hole.
- BuildFillElementsWithHole(context, to_elements, to_elements_kind,
+ BuildFillElementsWithHole(to_elements, to_elements_kind,
key, capacity);
}
}
-HValue* HGraphBuilder::BuildCloneShallowArray(HContext* context,
- HValue* boilerplate,
+HValue* HGraphBuilder::BuildCloneShallowArray(HValue* boilerplate,
HValue* allocation_site,
AllocationSiteMode mode,
ElementsKind kind,
@@ -1641,26 +1655,28 @@
size += AllocationMemento::kSize;
}
int elems_offset = size;
+ InstanceType instance_type = IsFastDoubleElementsKind(kind) ?
+ FIXED_DOUBLE_ARRAY_TYPE : FIXED_ARRAY_TYPE;
if (length > 0) {
size += IsFastDoubleElementsKind(kind)
? FixedDoubleArray::SizeFor(length)
: FixedArray::SizeFor(length);
}
- HAllocate::Flags allocate_flags = HAllocate::DefaultFlags(kind);
// Allocate both the JS array and the elements array in one big
// allocation. This avoids multiple limit checks.
HValue* size_in_bytes = Add<HConstant>(size);
- HInstruction* object = Add<HAllocate>(context,
- size_in_bytes,
+ HInstruction* object = Add<HAllocate>(size_in_bytes,
HType::JSObject(),
- allocate_flags);
+ NOT_TENURED,
+ instance_type);
// Copy the JS array part.
for (int i = 0; i < JSArray::kSize; i += kPointerSize) {
if ((i != JSArray::kElementsOffset) || (length == 0)) {
HObjectAccess access = HObjectAccess::ForJSArrayOffset(i);
- AddStore(object, access, AddLoad(boilerplate, access));
+ Add<HStoreNamedField>(object, access,
+ Add<HLoadNamedField>(boilerplate, access));
}
}
@@ -1674,12 +1690,14 @@
// elements pointer in the resulting object.
HValue* boilerplate_elements = AddLoadElements(boilerplate);
HValue* object_elements = Add<HInnerAllocatedObject>(object, elems_offset);
- AddStore(object, HObjectAccess::ForElementsPointer(), object_elements);
+ Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
+ object_elements);
// Copy the elements array header.
for (int i = 0; i < FixedArrayBase::kHeaderSize; i += kPointerSize) {
HObjectAccess access = HObjectAccess::ForFixedArrayHeader(i);
- AddStore(object_elements, access, AddLoad(boilerplate_elements, access));
+ Add<HStoreNamedField>(object_elements, access,
+ Add<HLoadNamedField>(boilerplate_elements, access));
}
// Copy the elements array contents.
@@ -1709,8 +1727,7 @@
UNREACHABLE();
case Token::SUB: {
HInstruction* instr =
- HMul::New(zone(), environment()->LookupContext(),
- input, graph()->GetConstantMinus1());
+ NewUncasted<HMul>(input, graph()->GetConstantMinus1());
Representation rep = Representation::FromType(type);
if (type->Is(Type::None())) {
Add<HDeoptimize>(Deoptimizer::SOFT);
@@ -1726,7 +1743,7 @@
if (type->Is(Type::None())) {
Add<HDeoptimize>(Deoptimizer::SOFT);
}
- return new(zone()) HBitNot(input);
+ return New<HBitNot>(input);
}
}
@@ -1781,22 +1798,22 @@
isolate()->heap()->allocation_memento_map());
AddStoreMapConstant(alloc_memento, alloc_memento_map);
HObjectAccess access = HObjectAccess::ForAllocationMementoSite();
- AddStore(alloc_memento, access, alloc_site);
+ Add<HStoreNamedField>(alloc_memento, access, alloc_site);
return alloc_memento;
}
-HInstruction* HGraphBuilder::BuildGetNativeContext(HValue* context) {
+HInstruction* HGraphBuilder::BuildGetNativeContext() {
// Get the global context, then the native context
- HInstruction* global_object = Add<HGlobalObject>(context);
+ HInstruction* global_object = Add<HGlobalObject>();
HObjectAccess access = HObjectAccess::ForJSObjectOffset(
GlobalObject::kNativeContextOffset);
- return AddLoad(global_object, access);
+ return Add<HLoadNamedField>(global_object, access);
}
-HInstruction* HGraphBuilder::BuildGetArrayFunction(HValue* context) {
- HInstruction* native_context = BuildGetNativeContext(context);
+HInstruction* HGraphBuilder::BuildGetArrayFunction() {
+ HInstruction* native_context = BuildGetNativeContext();
HInstruction* index =
Add<HConstant>(static_cast<int32_t>(Context::ARRAY_FUNCTION_INDEX));
return Add<HLoadKeyed>(
@@ -1830,7 +1847,7 @@
}
-HValue* HGraphBuilder::JSArrayBuilder::EmitMapCode(HValue* context) {
+HValue* HGraphBuilder::JSArrayBuilder::EmitMapCode() {
if (kind_ == GetInitialFastElementsKind()) {
// No need for a context lookup if the kind_ matches the initial
// map, because we can just load the map in that case.
@@ -1839,7 +1856,7 @@
builder()->BuildLoadNamedField(constructor_function_, access));
}
- HInstruction* native_context = builder()->BuildGetNativeContext(context);
+ HInstruction* native_context = builder()->BuildGetNativeContext();
HInstruction* index = builder()->Add<HConstant>(
static_cast<int32_t>(Context::JS_ARRAY_MAPS_INDEX));
@@ -1863,7 +1880,6 @@
HValue* HGraphBuilder::JSArrayBuilder::EstablishAllocationSize(
HValue* length_node) {
- HValue* context = builder()->environment()->LookupContext();
ASSERT(length_node != NULL);
int base_size = JSArray::kSize;
@@ -1876,15 +1892,12 @@
HInstruction* elements_size_value =
builder()->Add<HConstant>(elements_size());
- HInstruction* mul = HMul::New(zone(), context, length_node,
- elements_size_value);
+ HInstruction* mul = builder()->Add<HMul>(length_node, elements_size_value);
mul->ClearFlag(HValue::kCanOverflow);
- builder()->AddInstruction(mul);
HInstruction* base = builder()->Add<HConstant>(base_size);
- HInstruction* total_size = HAdd::New(zone(), context, base, mul);
+ HInstruction* total_size = builder()->Add<HAdd>(base, mul);
total_size->ClearFlag(HValue::kCanOverflow);
- builder()->AddInstruction(total_size);
return total_size;
}
@@ -1925,19 +1938,23 @@
HValue* capacity,
HValue* length_field,
bool fill_with_hole) {
- HValue* context = builder()->environment()->LookupContext();
-
+ // These HForceRepresentations are because we store these as fields in the
+ // objects we construct, and an int32-to-smi HChange could deopt. Accept
+ // the deopt possibility now, before allocation occurs.
+ capacity = builder()->Add<HForceRepresentation>(capacity,
+ Representation::Smi());
+ length_field = builder()->Add<HForceRepresentation>(length_field,
+ Representation::Smi());
// Allocate (dealing with failure appropriately)
- HAllocate::Flags flags = HAllocate::DefaultFlags(kind_);
- HAllocate* new_object = builder()->Add<HAllocate>(context, size_in_bytes,
- HType::JSArray(), flags);
+ HAllocate* new_object = builder()->Add<HAllocate>(size_in_bytes,
+ HType::JSArray(), NOT_TENURED, JS_ARRAY_TYPE);
// Fill in the fields: map, properties, length
HValue* map;
if (allocation_site_payload_ == NULL) {
map = EmitInternalMapCode();
} else {
- map = EmitMapCode(context);
+ map = EmitMapCode();
}
elements_location_ = builder()->BuildJSArrayHeader(new_object,
map,
@@ -1950,7 +1967,7 @@
builder()->BuildInitializeElementsHeader(elements_location_, kind_, capacity);
if (fill_with_hole) {
- builder()->BuildFillElementsWithHole(context, elements_location_, kind_,
+ builder()->BuildFillElementsWithHole(elements_location_, kind_,
graph()->GetConstant0(), capacity);
}
@@ -1958,20 +1975,6 @@
}
-HStoreNamedField* HGraphBuilder::AddStore(HValue *object,
- HObjectAccess access,
- HValue *val) {
- return Add<HStoreNamedField>(object, access, val);
-}
-
-
-HLoadNamedField* HGraphBuilder::AddLoad(HValue *object,
- HObjectAccess access,
- HValue *typecheck) {
- return Add<HLoadNamedField>(object, access, typecheck);
-}
-
-
HStoreNamedField* HGraphBuilder::AddStoreMapConstant(HValue *object,
Handle<Map> map) {
return Add<HStoreNamedField>(object, HObjectAccess::ForMap(),
@@ -1979,15 +1982,14 @@
}
-HValue* HGraphBuilder::AddLoadJSBuiltin(Builtins::JavaScript builtin,
- HValue* context) {
- HGlobalObject* global_object = Add<HGlobalObject>(context);
+HValue* HGraphBuilder::AddLoadJSBuiltin(Builtins::JavaScript builtin) {
+ HGlobalObject* global_object = Add<HGlobalObject>();
HObjectAccess access = HObjectAccess::ForJSObjectOffset(
GlobalObject::kBuiltinsOffset);
- HValue* builtins = AddLoad(global_object, access);
+ HValue* builtins = Add<HLoadNamedField>(global_object, access);
HObjectAccess function_access = HObjectAccess::ForJSObjectOffset(
JSBuiltinsObject::OffsetOfFunctionWithId(builtin));
- return AddLoad(builtins, function_access);
+ return Add<HLoadNamedField>(builtins, function_access);
}
@@ -2485,38 +2487,6 @@
}
-void HGraph::RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi* phi) {
- if (!phi->CheckFlag(HValue::kAllowUndefinedAsNaN)) return;
- phi->ClearFlag(HValue::kAllowUndefinedAsNaN);
- for (int i = 0; i < phi->OperandCount(); ++i) {
- HValue* input = phi->OperandAt(i);
- if (input->IsPhi()) {
- RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi::cast(input));
- }
- }
-}
-
-
-void HGraph::MarkDeoptimizeOnUndefined() {
- HPhase phase("H_MarkDeoptimizeOnUndefined", this);
- // Compute DeoptimizeOnUndefined flag for phis. Any phi that can reach a use
- // with DeoptimizeOnUndefined set must have DeoptimizeOnUndefined set.
- // Currently only HCompareNumericAndBranch, with double input representation,
- // has this flag set. The flag is used by HChange tagged->double, which must
- // deoptimize if one of its uses has this flag set.
- for (int i = 0; i < phi_list()->length(); i++) {
- HPhi* phi = phi_list()->at(i);
- for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) {
- HValue* use_value = it.value();
- if (!use_value->CheckFlag(HValue::kAllowUndefinedAsNaN)) {
- RecursivelyMarkPhiDeoptimizeOnUndefined(phi);
- break;
- }
- }
- }
-}
-
-
// Implementation of utility class to encapsulate the translation state for
// a (possibly inlined) function.
FunctionState::FunctionState(HOptimizedGraphBuilder* owner,
@@ -2911,7 +2881,7 @@
VisitDeclarations(scope->declarations());
Add<HSimulate>(BailoutId::Declarations());
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
Add<HStackCheck>(context, HStackCheck::kFunctionEntry);
VisitStatements(current_info()->function()->body());
@@ -2989,7 +2959,7 @@
// This must happen after inferring representations.
Run<HMergeRemovableSimulatesPhase>();
- MarkDeoptimizeOnUndefined();
+ Run<HMarkDeoptimizeOnUndefinedPhase>();
Run<HRepresentationChangesPhase>();
Run<HInferTypesPhase>();
@@ -3122,15 +3092,19 @@
void HOptimizedGraphBuilder::SetUpScope(Scope* scope) {
- HConstant* undefined_constant = Add<HConstant>(
- isolate()->factory()->undefined_value());
+ // First special is HContext.
+ HInstruction* context = Add<HContext>();
+ environment()->BindContext(context);
+
+ HConstant* undefined_constant = HConstant::cast(Add<HConstant>(
+ isolate()->factory()->undefined_value()));
graph()->set_undefined_constant(undefined_constant);
// Create an arguments object containing the initial parameters. Set the
// initial values of parameters including "this" having parameter index 0.
ASSERT_EQ(scope->num_parameters() + 1, environment()->parameter_count());
HArgumentsObject* arguments_object =
- new(zone()) HArgumentsObject(environment()->parameter_count(), zone());
+ New<HArgumentsObject>(environment()->parameter_count());
for (int i = 0; i < environment()->parameter_count(); ++i) {
HInstruction* parameter = Add<HParameter>(i);
arguments_object->AddArgument(parameter, zone());
@@ -3139,10 +3113,6 @@
AddInstruction(arguments_object);
graph()->SetArgumentsObject(arguments_object);
- // First special is HContext.
- HInstruction* context = Add<HContext>();
- environment()->BindContext(context);
-
// Initialize specials and locals to undefined.
for (int i = environment()->parameter_count() + 1;
i < environment()->length();
@@ -3410,7 +3380,7 @@
return Bailout("SwitchStatement: mixed or non-literal switch labels");
}
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
CHECK_ALIVE(VisitForValue(stmt->tag()));
Add<HSimulate>(stmt->EntryId());
@@ -3558,9 +3528,9 @@
BreakAndContinueInfo* break_info) {
BreakAndContinueScope push(break_info, this);
Add<HSimulate>(stmt->StackCheckId());
- HValue* context = environment()->LookupContext();
- HStackCheck* stack_check = Add<HStackCheck>(
- context, HStackCheck::kBackwardsBranch);
+ HValue* context = environment()->context();
+ HStackCheck* stack_check = HStackCheck::cast(Add<HStackCheck>(
+ context, HStackCheck::kBackwardsBranch));
ASSERT(loop_entry->IsLoopHeader());
loop_entry->loop_information()->set_stack_check(stack_check);
CHECK_BAILOUT(Visit(stmt->body()));
@@ -3716,8 +3686,7 @@
CHECK_ALIVE(VisitForValue(stmt->enumerable()));
HValue* enumerable = Top(); // Leave enumerable at the top.
- HInstruction* map = Add<HForInPrepareMap>(
- environment()->LookupContext(), enumerable);
+ HInstruction* map = Add<HForInPrepareMap>(enumerable);
Add<HSimulate>(stmt->PrepareId());
HInstruction* array = Add<HForInCacheArray>(
@@ -3783,9 +3752,7 @@
set_current_block(body_exit);
HValue* current_index = Pop();
- HInstruction* new_index = HAdd::New(zone(),
- environment()->LookupContext(),
- current_index,
+ HInstruction* new_index = New<HAdd>(current_index,
graph()->GetConstant1());
PushAndAdd(new_index);
body_exit = current_block();
@@ -3864,7 +3831,7 @@
}
// We also have a stack overflow if the recursive compilation did.
if (HasStackOverflow()) return;
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
HFunctionLiteral* instr =
new(zone()) HFunctionLiteral(context, shared_info, expr->pretenure());
return ast_context()->ReturnInstruction(instr, expr->id());
@@ -3938,7 +3905,7 @@
HValue* HOptimizedGraphBuilder::BuildContextChainWalk(Variable* var) {
ASSERT(var->IsContextSlot());
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
int length = current_info()->scope()->ContextChainLength(var->scope());
while (length-- > 0) {
context = Add<HOuterContext>(context);
@@ -3963,7 +3930,7 @@
Handle<Object> constant_value =
isolate()->factory()->GlobalConstantFor(variable->name());
if (!constant_value.is_null()) {
- HConstant* instr = new(zone()) HConstant(constant_value);
+ HConstant* instr = New<HConstant>(constant_value);
return ast_context()->ReturnInstruction(instr, expr->id());
}
@@ -3986,7 +3953,7 @@
constant_object =
FlattenGetString(Handle<String>::cast(constant_object));
}
- HConstant* constant = new(zone()) HConstant(constant_object);
+ HConstant* constant = New<HConstant>(constant_object);
return ast_context()->ReturnInstruction(constant, expr->id());
} else {
HLoadGlobalCell* instr =
@@ -3994,7 +3961,7 @@
return ast_context()->ReturnInstruction(instr, expr->id());
}
} else {
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
HGlobalObject* global_object = new(zone()) HGlobalObject(context);
AddInstruction(global_object);
HLoadGlobalGeneric* instr =
@@ -4034,7 +4001,7 @@
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
- HConstant* instr = new(zone()) HConstant(expr->value());
+ HConstant* instr = New<HConstant>(expr->value());
return ast_context()->ReturnInstruction(instr, expr->id());
}
@@ -4045,7 +4012,7 @@
ASSERT(current_block()->HasPredecessor());
Handle<JSFunction> closure = function_state()->compilation_info()->closure();
Handle<FixedArray> literals(closure->literals());
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
HRegExpLiteral* instr = new(zone()) HRegExpLiteral(context,
literals,
@@ -4222,7 +4189,7 @@
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
Handle<JSFunction> closure = function_state()->compilation_info()->closure();
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
HInstruction* literal;
// Check whether to use fast or slow deep-copying for boilerplate.
@@ -4267,8 +4234,7 @@
Runtime::FunctionId function_id =
(expr->depth() > 1 || expr->may_store_doubles())
? Runtime::kCreateObjectLiteral : Runtime::kCreateObjectLiteralShallow;
- literal = Add<HCallRuntime>(context,
- isolate()->factory()->empty_string(),
+ literal = Add<HCallRuntime>(isolate()->factory()->empty_string(),
Runtime::FunctionForId(function_id),
4);
}
@@ -4350,7 +4316,7 @@
ASSERT(current_block()->HasPredecessor());
ZoneList<Expression*>* subexprs = expr->values();
int length = subexprs->length();
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
HInstruction* literal;
Handle<AllocationSite> site;
@@ -4429,15 +4395,14 @@
Runtime::FunctionId function_id = (expr->depth() > 1)
? Runtime::kCreateArrayLiteral : Runtime::kCreateArrayLiteralShallow;
- literal = Add<HCallRuntime>(context,
- isolate()->factory()->empty_string(),
+ literal = Add<HCallRuntime>(isolate()->factory()->empty_string(),
Runtime::FunctionForId(function_id),
3);
// De-opt if elements kind changed from boilerplate_elements_kind.
Handle<Map> map = Handle<Map>(original_boilerplate_object->map(),
isolate());
- AddInstruction(HCheckMaps::New(literal, map, zone(), top_info()));
+ Add<HCheckMaps>(literal, map, top_info());
}
// The array is expected in the bailout environment during computation
@@ -4514,15 +4479,7 @@
void HOptimizedGraphBuilder::AddCheckMap(HValue* object, Handle<Map> map) {
BuildCheckHeapObject(object);
- AddInstruction(HCheckMaps::New(object, map, zone(), top_info()));
-}
-
-
-void HOptimizedGraphBuilder::AddCheckMapsWithTransitions(HValue* object,
- Handle<Map> map) {
- BuildCheckHeapObject(object);
- AddInstruction(HCheckMaps::NewWithTransitions(
- object, map, zone(), top_info()));
+ Add<HCheckMaps>(object, map, top_info());
}
@@ -4557,9 +4514,9 @@
ASSERT(proto->GetPrototype(isolate())->IsNull());
}
ASSERT(proto->IsJSObject());
- Add<HCheckPrototypeMaps>(Handle<JSObject>(JSObject::cast(map->prototype())),
- Handle<JSObject>(JSObject::cast(proto)),
- zone(), top_info());
+ Add<HCheckPrototypeMaps>(
+ Handle<JSObject>(JSObject::cast(map->prototype())),
+ Handle<JSObject>(JSObject::cast(proto)), top_info());
}
HObjectAccess field_access = HObjectAccess::ForField(map, lookup, name);
@@ -4573,23 +4530,26 @@
// The store requires a mutable HeapNumber to be allocated.
NoObservableSideEffectsScope no_side_effects(this);
HInstruction* heap_number_size = Add<HConstant>(HeapNumber::kSize);
- HInstruction* heap_number = Add<HAllocate>(
- environment()->LookupContext(), heap_number_size,
- HType::HeapNumber(), HAllocate::CAN_ALLOCATE_IN_NEW_SPACE);
+ HInstruction* heap_number = Add<HAllocate>(heap_number_size,
+ HType::HeapNumber(), isolate()->heap()->GetPretenureMode(),
+ HEAP_NUMBER_TYPE);
AddStoreMapConstant(heap_number, isolate()->factory()->heap_number_map());
- AddStore(heap_number, HObjectAccess::ForHeapNumberValue(), value);
- instr = new(zone()) HStoreNamedField(
- object, heap_number_access, heap_number);
+ Add<HStoreNamedField>(heap_number, HObjectAccess::ForHeapNumberValue(),
+ value);
+ instr = New<HStoreNamedField>(object, heap_number_access,
+ heap_number);
} else {
// Already holds a HeapNumber; load the box and write its value field.
- HInstruction* heap_number = AddLoad(object, heap_number_access);
+ HInstruction* heap_number = Add<HLoadNamedField>(object,
+ heap_number_access);
heap_number->set_type(HType::HeapNumber());
- instr = new(zone()) HStoreNamedField(heap_number,
- HObjectAccess::ForHeapNumberValue(), value);
+ instr = New<HStoreNamedField>(heap_number,
+ HObjectAccess::ForHeapNumberValue(),
+ value);
}
} else {
// This is a normal store.
- instr = new(zone()) HStoreNamedField(object, field_access, value);
+ instr = New<HStoreNamedField>(object, field_access, value);
}
if (transition_to_field) {
@@ -4607,7 +4567,7 @@
HValue* object,
Handle<String> name,
HValue* value) {
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
return new(zone()) HStoreNamedGeneric(
context,
object,
@@ -4625,7 +4585,7 @@
// Handle a store to a known field.
LookupResult lookup(isolate());
if (ComputeLoadStoreField(map, name, &lookup, true)) {
- AddCheckMapsWithTransitions(object, map);
+ AddCheckMap(object, map);
return BuildStoreNamedField(object, name, value, map, &lookup);
}
@@ -4684,7 +4644,7 @@
if (count == types->length()) {
// Everything matched; can use monomorphic load.
BuildCheckHeapObject(object);
- AddInstruction(HCheckMaps::New(object, types, zone()));
+ Add<HCheckMaps>(object, types);
return BuildLoadNamedField(object, access);
}
@@ -4706,13 +4666,13 @@
if (!lookup.IsField()) return NULL;
BuildCheckHeapObject(object);
- AddInstruction(HCheckMaps::New(object, types, zone()));
+ Add<HCheckMaps>(object, types);
Handle<JSObject> holder(lookup.holder());
Handle<Map> holder_map(holder->map());
- AddInstruction(new(zone()) HCheckPrototypeMaps(
- Handle<JSObject>::cast(prototype), holder, zone(), top_info()));
- HValue* holder_value = AddInstruction(new(zone()) HConstant(holder));
+ Add<HCheckPrototypeMaps>(
+ Handle<JSObject>::cast(prototype), holder, top_info());
+ HValue* holder_value = Add<HConstant>(holder);
return BuildLoadNamedField(holder_value,
HObjectAccess::ForField(holder_map, &lookup, name));
}
@@ -4728,7 +4688,7 @@
if (instr == NULL) {
// Something did not match; must use a polymorphic load.
BuildCheckHeapObject(object);
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
instr = new(zone()) HLoadNamedFieldPolymorphic(
context, object, types, name, zone());
}
@@ -4785,7 +4745,7 @@
// Everything matched; can use monomorphic store.
BuildCheckHeapObject(object);
- AddInstruction(HCheckMaps::New(object, types, zone()));
+ Add<HCheckMaps>(object, types);
HInstruction* store;
CHECK_ALIVE_OR_RETURN(
store = BuildStoreNamedField(
@@ -4957,10 +4917,9 @@
Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
}
} else {
- HValue* context = environment()->LookupContext();
- HGlobalObject* global_object = Add<HGlobalObject>(context);
+ HGlobalObject* global_object = Add<HGlobalObject>();
HStoreGlobalGeneric* instr =
- Add<HStoreGlobalGeneric>(context, global_object, var->name(),
+ Add<HStoreGlobalGeneric>(global_object, var->name(),
value, function_strict_mode_flag());
instr->set_position(position);
ASSERT(instr->HasObservableSideEffects());
@@ -5101,8 +5060,8 @@
}
HValue* context = BuildContextChainWalk(var);
- HStoreContextSlot* instr = Add<HStoreContextSlot>(context, var->index(),
- mode, Top());
+ HStoreContextSlot* instr = Add<HStoreContextSlot>(
+ context, var->index(), mode, Top());
if (instr->HasObservableSideEffects()) {
Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE);
}
@@ -5313,8 +5272,8 @@
}
HValue* context = BuildContextChainWalk(var);
- HStoreContextSlot* instr = Add<HStoreContextSlot>(context, var->index(),
- mode, Top());
+ HStoreContextSlot* instr = Add<HStoreContextSlot>(
+ context, var->index(), mode, Top());
if (instr->HasObservableSideEffects()) {
Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE);
}
@@ -5346,9 +5305,8 @@
ASSERT(ast_context()->IsEffect());
CHECK_ALIVE(VisitForValue(expr->exception()));
- HValue* context = environment()->LookupContext();
HValue* value = environment()->Pop();
- HThrow* instr = Add<HThrow>(context, value);
+ HThrow* instr = Add<HThrow>(value);
instr->set_position(expr->position());
Add<HSimulate>(expr->id());
current_block()->FinishExit(new(zone()) HAbnormalExit);
@@ -5357,17 +5315,32 @@
HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object,
- HObjectAccess access) {
+ HObjectAccess access,
+ HValue* typecheck) {
if (FLAG_track_double_fields && access.representation().IsDouble()) {
// load the heap number
- HLoadNamedField* heap_number =
- AddLoad(object, access.WithRepresentation(Representation::Tagged()));
+ HLoadNamedField* heap_number = Add<HLoadNamedField>(
+ object, access.WithRepresentation(Representation::Tagged()));
heap_number->set_type(HType::HeapNumber());
// load the double value from it
- return new(zone()) HLoadNamedField(heap_number,
- HObjectAccess::ForHeapNumberValue(), NULL);
+ return New<HLoadNamedField>(heap_number,
+ HObjectAccess::ForHeapNumberValue(),
+ typecheck);
}
- return new(zone()) HLoadNamedField(object, access, NULL);
+ return New<HLoadNamedField>(object, access, typecheck);
+}
+
+
+HInstruction* HGraphBuilder::BuildLoadStringLength(HValue* object,
+ HValue* typecheck) {
+ if (FLAG_fold_constants && object->IsConstant()) {
+ HConstant* constant = HConstant::cast(object);
+ if (constant->HasStringValue()) {
+ return New<HConstant>(constant->StringValue()->length());
+ }
+ }
+ return BuildLoadNamedField(
+ object, HObjectAccess::ForStringLength(), typecheck);
}
@@ -5378,7 +5351,7 @@
if (expr->IsUninitialized()) {
Add<HDeoptimize>(Deoptimizer::SOFT);
}
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
return new(zone()) HLoadNamedGeneric(context, object, name);
}
@@ -5405,8 +5378,8 @@
// Handle access to various length properties
if (name->Equals(isolate()->heap()->length_string())) {
if (map->instance_type() == JS_ARRAY_TYPE) {
- AddCheckMapsWithTransitions(object, map);
- return new(zone()) HLoadNamedField(object,
+ AddCheckMap(object, map);
+ return New<HLoadNamedField>(object,
HObjectAccess::ForArrayLength(map->elements_kind()));
}
}
@@ -5423,7 +5396,7 @@
if (lookup.IsConstant()) {
AddCheckMap(object, map);
Handle<Object> constant(lookup.GetConstantFromMap(*map), isolate());
- return new(zone()) HConstant(constant);
+ return New<HConstant>(constant);
}
// Handle a load from a known field somewhere in the prototype chain.
@@ -5433,7 +5406,7 @@
Handle<JSObject> holder(lookup.holder());
Handle<Map> holder_map(holder->map());
AddCheckMap(object, map);
- Add<HCheckPrototypeMaps>(prototype, holder, zone(), top_info());
+ Add<HCheckPrototypeMaps>(prototype, holder, top_info());
HValue* holder_value = Add<HConstant>(holder);
return BuildLoadNamedField(holder_value,
HObjectAccess::ForField(holder_map, &lookup, name));
@@ -5445,9 +5418,9 @@
Handle<JSObject> holder(lookup.holder());
Handle<Map> holder_map(holder->map());
AddCheckMap(object, map);
- Add<HCheckPrototypeMaps>(prototype, holder, zone(), top_info());
+ Add<HCheckPrototypeMaps>(prototype, holder, top_info());
Handle<Object> constant(lookup.GetConstantFromMap(*holder_map), isolate());
- return new(zone()) HConstant(constant);
+ return New<HConstant>(constant);
}
// No luck, do a generic load.
@@ -5457,7 +5430,7 @@
HInstruction* HOptimizedGraphBuilder::BuildLoadKeyedGeneric(HValue* object,
HValue* key) {
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
return new(zone()) HLoadKeyedGeneric(context, object, key);
}
@@ -5470,9 +5443,7 @@
Handle<Map> map,
bool is_store,
KeyedAccessStoreMode store_mode) {
- HCheckMaps* mapcheck = HCheckMaps::New(
- object, map, zone(), top_info(), dependency);
- AddInstruction(mapcheck);
+ HCheckMaps* mapcheck = Add<HCheckMaps>(object, map, top_info(), dependency);
if (dependency) {
mapcheck->ClearGVNFlag(kDependsOnElementsKind);
}
@@ -5483,7 +5454,7 @@
isolate()->IsFastArrayConstructorPrototypeChainIntact()) {
Handle<JSObject> prototype(JSObject::cast(map->prototype()), isolate());
Handle<JSObject> object_prototype = isolate()->initial_object_prototype();
- Add<HCheckPrototypeMaps>(prototype, object_prototype, zone(), top_info());
+ Add<HCheckPrototypeMaps>(prototype, object_prototype, top_info());
load_mode = ALLOW_RETURN_HOLE;
graph()->MarkDependsOnEmptyArrayProtoElements();
}
@@ -5540,8 +5511,7 @@
}
if (!has_double_maps && !has_smi_or_object_maps) return NULL;
- HCheckMaps* check_maps = HCheckMaps::New(object, maps, zone());
- AddInstruction(check_maps);
+ HCheckMaps* check_maps = Add<HCheckMaps>(object, maps);
HInstruction* instr = BuildUncheckedMonomorphicElementAccess(
object, key, val, check_maps,
most_general_consolidated_map->instance_type() == JS_ARRAY_TYPE,
@@ -5606,8 +5576,7 @@
ASSERT(Map::IsValidElementsTransition(
map->elements_kind(),
transition_target.at(i)->elements_kind()));
- HValue* context = environment()->LookupContext();
- transition = Add<HTransitionElementsKind>(context, object, map,
+ transition = Add<HTransitionElementsKind>(object, map,
transition_target.at(i));
} else {
untransitionable_maps.Add(map);
@@ -5653,12 +5622,12 @@
HInstruction* access = NULL;
if (IsFastElementsKind(elements_kind)) {
if (is_store && !IsFastDoubleElementsKind(elements_kind)) {
- AddInstruction(HCheckMaps::New(
+ Add<HCheckMaps>(
elements, isolate()->factory()->fixed_array_map(),
- zone(), top_info(), mapcompare));
+ top_info(), mapcompare);
}
if (map->instance_type() == JS_ARRAY_TYPE) {
- HInstruction* length = AddLoad(
+ HInstruction* length = Add<HLoadNamedField>(
object, HObjectAccess::ForArrayLength(elements_kind), mapcompare);
checked_key = Add<HBoundsCheck>(key, length);
} else {
@@ -5754,7 +5723,7 @@
HValue* object,
HValue* key,
HValue* value) {
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
return new(zone()) HStoreKeyedGeneric(
context,
object,
@@ -5780,13 +5749,12 @@
HInstruction* insert_after = entry;
for (int i = 0; i < arguments_values->length(); i++) {
HValue* argument = arguments_values->at(i);
- HInstruction* push_argument = new(zone()) HPushArgument(argument);
+ HInstruction* push_argument = New<HPushArgument>(argument);
push_argument->InsertAfter(insert_after);
insert_after = push_argument;
}
- HArgumentsElements* arguments_elements =
- new(zone()) HArgumentsElements(true);
+ HArgumentsElements* arguments_elements = New<HArgumentsElements>(true);
arguments_elements->ClearFlag(HValue::kUseGVN);
arguments_elements->InsertAfter(insert_after);
function_state()->set_arguments_elements(arguments_elements);
@@ -5808,12 +5776,12 @@
if (function_state()->outer() == NULL) {
HInstruction* elements = Add<HArgumentsElements>(false);
- result = new(zone()) HArgumentsLength(elements);
+ result = New<HArgumentsLength>(elements);
} else {
// Number of arguments without receiver.
int argument_count = environment()->
arguments_environment()->parameter_count() - 1;
- result = new(zone()) HConstant(argument_count);
+ result = New<HConstant>(argument_count);
}
} else {
Push(graph()->GetArgumentsObject());
@@ -5856,15 +5824,16 @@
if (expr->IsStringLength()) {
HValue* string = Pop();
BuildCheckHeapObject(string);
- AddInstruction(HCheckInstanceType::NewIsString(string, zone()));
- instr = HStringLength::New(zone(), string);
+ HInstruction* checkstring =
+ AddInstruction(HCheckInstanceType::NewIsString(string, zone()));
+ instr = BuildLoadStringLength(string, checkstring);
} else if (expr->IsStringAccess()) {
CHECK_ALIVE(VisitForValue(expr->key()));
HValue* index = Pop();
HValue* string = Pop();
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
HInstruction* char_code =
- BuildStringCharCodeAt(context, string, index);
+ BuildStringCharCodeAt(string, index);
AddInstruction(char_code);
instr = HStringCharFromCode::New(zone(), context, char_code);
@@ -5935,7 +5904,7 @@
Handle<Map> receiver_map) {
if (!holder.is_null()) {
Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype()));
- Add<HCheckPrototypeMaps>(prototype, holder, zone(), top_info());
+ Add<HCheckPrototypeMaps>(prototype, holder, top_info());
}
}
@@ -5947,7 +5916,7 @@
// Constant functions have the nice property that the map will change if they
// are overwritten. Therefore it is enough to check the map of the holder and
// its prototypes.
- AddCheckMapsWithTransitions(receiver, receiver_map);
+ AddCheckMap(receiver, receiver_map);
AddCheckPrototypeMaps(holder, receiver_map);
}
@@ -6004,7 +5973,7 @@
if (!expr->ComputeTarget(map, name)) return false;
BuildCheckHeapObject(receiver);
- AddInstruction(HCheckMaps::New(receiver, types, zone()));
+ Add<HCheckMaps>(receiver, types);
AddCheckPrototypeMaps(expr->holder(), map);
if (FLAG_trace_inlining) {
Handle<JSFunction> caller = current_info()->closure();
@@ -6160,7 +6129,7 @@
Drop(argument_count - (ast_context()->IsEffect() ? 0 : 1));
FinishExitWithHardDeoptimization(join);
} else {
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
HCallNamed* call = new(zone()) HCallNamed(context, name, argument_count);
call->set_position(expr->position());
PreProcessCall(call);
@@ -6426,7 +6395,7 @@
ASSERT(function->scope()->arguments()->IsStackAllocated());
HEnvironment* arguments_env = inner_env->arguments_environment();
int arguments_count = arguments_env->parameter_count();
- arguments_object = Add<HArgumentsObject>(arguments_count, zone());
+ arguments_object = Add<HArgumentsObject>(arguments_count);
inner_env->Bind(function->scope()->arguments(), arguments_object);
for (int i = 0; i < arguments_count; i++) {
arguments_object->AddArgument(arguments_env->Lookup(i), zone());
@@ -6437,7 +6406,7 @@
Add<HEnterInlined>(target, arguments_count, function,
function_state()->inlining_kind(),
function->scope()->arguments(),
- arguments_object, undefined_receiver, zone());
+ arguments_object, undefined_receiver);
function_state()->set_entry(enter_inlined);
VisitDeclarations(target_info.scope()->declarations());
@@ -6628,7 +6597,7 @@
case kMathTan:
if (expr->arguments()->length() == 1) {
HValue* argument = Pop();
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
Drop(1); // Receiver.
HInstruction* op =
HUnaryMathOperation::New(zone(), context, argument, id);
@@ -6643,7 +6612,7 @@
HValue* right = Pop();
HValue* left = Pop();
Drop(1); // Receiver.
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
HInstruction* op = HMul::NewImul(zone(), context, left, right);
if (drop_extra) Drop(1); // Optionally drop the function.
ast_context()->ReturnInstruction(op, expr->id());
@@ -6674,13 +6643,13 @@
if (argument_count == 2 && check_type == STRING_CHECK) {
HValue* index = Pop();
HValue* string = Pop();
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
ASSERT(!expr->holder().is_null());
Add<HCheckPrototypeMaps>(Call::GetPrototypeForPrimitiveCheck(
STRING_CHECK, expr->holder()->GetIsolate()),
- expr->holder(), zone(), top_info());
+ expr->holder(), top_info());
HInstruction* char_code =
- BuildStringCharCodeAt(context, string, index);
+ BuildStringCharCodeAt(string, index);
if (id == kStringCharCodeAt) {
ast_context()->ReturnInstruction(char_code, expr->id());
return true;
@@ -6696,7 +6665,7 @@
if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) {
AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
HValue* argument = Pop();
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
Drop(1); // Receiver.
HInstruction* result =
HStringCharFromCode::New(zone(), context, argument);
@@ -6718,7 +6687,7 @@
if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) {
AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
HValue* argument = Pop();
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
Drop(1); // Receiver.
HInstruction* op =
HUnaryMathOperation::New(zone(), context, argument, id);
@@ -6733,7 +6702,7 @@
HValue* right = Pop();
HValue* left = Pop();
Pop(); // Pop receiver.
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
HInstruction* result = NULL;
// Use sqrt() if exponent is 0.5 or -0.5.
if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) {
@@ -6758,7 +6727,7 @@
}
if (result == NULL) {
- result = HPower::New(zone(), left, right);
+ result = HPower::New(zone(), context, left, right);
}
ast_context()->ReturnInstruction(result, expr->id());
return true;
@@ -6768,8 +6737,7 @@
if (argument_count == 1 && check_type == RECEIVER_MAP_CHECK) {
AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
Drop(1); // Receiver.
- HValue* context = environment()->LookupContext();
- HGlobalObject* global_object = Add<HGlobalObject>(context);
+ HGlobalObject* global_object = Add<HGlobalObject>();
HRandom* result = new(zone()) HRandom(global_object);
ast_context()->ReturnInstruction(result, expr->id());
return true;
@@ -6782,7 +6750,7 @@
HValue* right = Pop();
HValue* left = Pop();
Drop(1); // Receiver.
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
HMathMinMax::Operation op = (id == kMathMin) ? HMathMinMax::kMathMin
: HMathMinMax::kMathMax;
HInstruction* result =
@@ -6797,7 +6765,7 @@
HValue* right = Pop();
HValue* left = Pop();
Drop(1); // Receiver.
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
HInstruction* result = HMul::NewImul(zone(), context, left, right);
ast_context()->ReturnInstruction(result, expr->id());
return true;
@@ -6881,12 +6849,12 @@
}
Drop(arguments_count - 1);
- PushAndAdd(new(zone()) HPushArgument(Pop()));
+ PushAndAdd(New<HPushArgument>(Pop()));
for (int i = 1; i < arguments_count; i++) {
- PushAndAdd(new(zone()) HPushArgument(arguments_values->at(i)));
+ PushAndAdd(New<HPushArgument>(arguments_values->at(i)));
}
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
HInvokeFunction* call = new(zone()) HInvokeFunction(
context,
function,
@@ -6900,55 +6868,6 @@
}
-// Checks if all maps in |types| are from the same family, i.e., are elements
-// transitions of each other. Returns either NULL if they are not from the same
-// family, or a Map* indicating the map with the first elements kind of the
-// family that is in the list.
-static Map* CheckSameElementsFamily(SmallMapList* types) {
- if (types->length() <= 1) return NULL;
- // Check if all maps belong to the same transition family.
- Map* kinds[kFastElementsKindCount];
- Map* first_map = *types->first();
- ElementsKind first_kind = first_map->elements_kind();
- if (!IsFastElementsKind(first_kind)) return NULL;
- int first_index = GetSequenceIndexFromFastElementsKind(first_kind);
- int last_index = first_index;
-
- for (int i = 0; i < kFastElementsKindCount; i++) kinds[i] = NULL;
-
- kinds[first_index] = first_map;
-
- for (int i = 1; i < types->length(); ++i) {
- Map* map = *types->at(i);
- ElementsKind elements_kind = map->elements_kind();
- if (!IsFastElementsKind(elements_kind)) return NULL;
- int index = GetSequenceIndexFromFastElementsKind(elements_kind);
- if (index < first_index) {
- first_index = index;
- } else if (index > last_index) {
- last_index = index;
- } else if (kinds[index] != map) {
- return NULL;
- }
- kinds[index] = map;
- }
-
- Map* current = kinds[first_index];
- for (int i = first_index + 1; i <= last_index; i++) {
- Map* next = kinds[i];
- if (next != NULL) {
- ElementsKind current_kind = next->elements_kind();
- if (next != current->LookupElementsTransitionMap(current_kind)) {
- return NULL;
- }
- current = next;
- }
- }
-
- return kinds[first_index];
-}
-
-
void HOptimizedGraphBuilder::VisitCall(Call* expr) {
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
@@ -6972,7 +6891,7 @@
CHECK_ALIVE(VisitArgumentList(expr->arguments()));
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
call = new(zone()) HCallKeyed(context, key, argument_count);
call->set_position(expr->position());
Drop(argument_count + 1); // 1 is the key.
@@ -6994,12 +6913,6 @@
receiver_map = (types == NULL || types->is_empty())
? Handle<Map>::null()
: types->first();
- } else {
- Map* family_map = CheckSameElementsFamily(types);
- if (family_map != NULL) {
- receiver_map = Handle<Map>(family_map);
- monomorphic = expr->ComputeTarget(receiver_map, name);
- }
}
HValue* receiver =
@@ -7022,7 +6935,7 @@
// When the target has a custom call IC generator, use the IC,
// because it is likely to generate better code. Also use the IC
// when a primitive receiver check is required.
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
call = PreProcessCall(
new(zone()) HCallNamed(context, name, argument_count));
} else {
@@ -7039,7 +6952,7 @@
return;
} else {
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
call = PreProcessCall(
new(zone()) HCallNamed(context, name, argument_count));
}
@@ -7067,7 +6980,7 @@
if (known_global_function) {
// Push the global object instead of the global receiver because
// code generated by the full code generator expects it.
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
HGlobalObject* global_object = new(zone()) HGlobalObject(context);
PushAndAdd(global_object);
CHECK_ALIVE(VisitExpressions(expr->arguments()));
@@ -7101,7 +7014,7 @@
if (CallStubCompiler::HasCustomCallGenerator(expr->target())) {
// When the target has a custom call IC generator, use the IC,
// because it is likely to generate better code.
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
call = PreProcessCall(
new(zone()) HCallNamed(context, var->name(), argument_count));
} else {
@@ -7109,12 +7022,11 @@
argument_count));
}
} else {
- HValue* context = environment()->LookupContext();
- HGlobalObject* receiver = Add<HGlobalObject>(context);
- PushAndAdd(new(zone()) HPushArgument(receiver));
+ HGlobalObject* receiver = Add<HGlobalObject>();
+ PushAndAdd(New<HPushArgument>(receiver));
CHECK_ALIVE(VisitArgumentList(expr->arguments()));
- call = new(zone()) HCallGlobal(context, var->name(), argument_count);
+ call = New<HCallGlobal>(var->name(), argument_count);
Drop(argument_count);
}
@@ -7123,9 +7035,8 @@
// evaluation of the arguments.
CHECK_ALIVE(VisitForValue(expr->expression()));
HValue* function = Top();
- HValue* context = environment()->LookupContext();
- HGlobalObject* global = Add<HGlobalObject>(context);
- HGlobalReceiver* receiver = new(zone()) HGlobalReceiver(global);
+ HGlobalObject* global = Add<HGlobalObject>();
+ HGlobalReceiver* receiver = New<HGlobalReceiver>(global);
PushAndAdd(receiver);
CHECK_ALIVE(VisitExpressions(expr->arguments()));
Add<HCheckFunction>(function, expr->target());
@@ -7142,24 +7053,20 @@
if (TryInlineCall(expr, true)) { // Drop function from environment.
return;
} else {
- call = PreProcessCall(
- new(zone()) HInvokeFunction(context,
- function,
- expr->target(),
- argument_count));
+ call = PreProcessCall(New<HInvokeFunction>(function, expr->target(),
+ argument_count));
Drop(1); // The function.
}
} else {
CHECK_ALIVE(VisitForValue(expr->expression()));
HValue* function = Top();
- HValue* context = environment()->LookupContext();
- HGlobalObject* global_object = Add<HGlobalObject>(context);
+ HGlobalObject* global_object = Add<HGlobalObject>();
HGlobalReceiver* receiver = Add<HGlobalReceiver>(global_object);
- PushAndAdd(new(zone()) HPushArgument(receiver));
+ PushAndAdd(New<HPushArgument>(receiver));
CHECK_ALIVE(VisitArgumentList(expr->arguments()));
- call = new(zone()) HCallFunction(context, function, argument_count);
+ call = New<HCallFunction>(function, argument_count);
Drop(argument_count + 1);
}
}
@@ -7183,7 +7090,7 @@
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
int argument_count = expr->arguments()->length() + 1; // Plus constructor.
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
Factory* factory = isolate()->factory();
if (FLAG_inline_construct &&
@@ -7211,42 +7118,41 @@
// Allocate an instance of the implicit receiver object.
HValue* size_in_bytes = Add<HConstant>(instance_size);
- HAllocate::Flags flags = HAllocate::DefaultFlags();
- if (FLAG_pretenuring_call_new &&
- isolate()->heap()->ShouldGloballyPretenure()) {
- flags = static_cast<HAllocate::Flags>(
- flags | HAllocate::CAN_ALLOCATE_IN_OLD_POINTER_SPACE);
- }
+ PretenureFlag pretenure_flag =
+ (FLAG_pretenuring_call_new &&
+ isolate()->heap()->GetPretenureMode() == TENURED)
+ ? TENURED : NOT_TENURED;
HAllocate* receiver =
- Add<HAllocate>(context, size_in_bytes, HType::JSObject(), flags);
+ Add<HAllocate>(size_in_bytes, HType::JSObject(), pretenure_flag,
+ JS_OBJECT_TYPE);
receiver->set_known_initial_map(initial_map);
// Load the initial map from the constructor.
HValue* constructor_value = Add<HConstant>(constructor);
HValue* initial_map_value =
- AddLoad(constructor_value, HObjectAccess::ForJSObjectOffset(
+ Add<HLoadNamedField>(constructor_value, HObjectAccess::ForJSObjectOffset(
JSFunction::kPrototypeOrInitialMapOffset));
// Initialize map and fields of the newly allocated object.
{ NoObservableSideEffectsScope no_effects(this);
ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE);
- AddStore(receiver,
- HObjectAccess::ForJSObjectOffset(JSObject::kMapOffset),
- initial_map_value);
+ Add<HStoreNamedField>(receiver,
+ HObjectAccess::ForJSObjectOffset(JSObject::kMapOffset),
+ initial_map_value);
HValue* empty_fixed_array = Add<HConstant>(factory->empty_fixed_array());
- AddStore(receiver,
- HObjectAccess::ForJSObjectOffset(JSObject::kPropertiesOffset),
- empty_fixed_array);
- AddStore(receiver,
- HObjectAccess::ForJSObjectOffset(JSObject::kElementsOffset),
- empty_fixed_array);
+ Add<HStoreNamedField>(receiver,
+ HObjectAccess::ForJSObjectOffset(JSObject::kPropertiesOffset),
+ empty_fixed_array);
+ Add<HStoreNamedField>(receiver,
+ HObjectAccess::ForJSObjectOffset(JSObject::kElementsOffset),
+ empty_fixed_array);
if (initial_map->inobject_properties() != 0) {
HConstant* undefined = graph()->GetConstantUndefined();
for (int i = 0; i < initial_map->inobject_properties(); i++) {
int property_offset = JSObject::kHeaderSize + i * kPointerSize;
- AddStore(receiver,
- HObjectAccess::ForJSObjectOffset(property_offset),
- undefined);
+ Add<HStoreNamedField>(receiver,
+ HObjectAccess::ForJSObjectOffset(property_offset),
+ undefined);
}
}
}
@@ -7344,11 +7250,10 @@
ASSERT(function->intrinsic_type == Runtime::RUNTIME);
CHECK_ALIVE(VisitArgumentList(expr->arguments()));
- HValue* context = environment()->LookupContext();
Handle<String> name = expr->name();
int argument_count = expr->arguments()->length();
- HCallRuntime* call =
- new(zone()) HCallRuntime(context, name, function, argument_count);
+ HCallRuntime* call = New<HCallRuntime>(name, function,
+ argument_count);
Drop(argument_count);
return ast_context()->ReturnInstruction(call, expr->id());
}
@@ -7379,14 +7284,13 @@
CHECK_ALIVE(VisitForValue(prop->key()));
HValue* key = Pop();
HValue* obj = Pop();
- HValue* context = environment()->LookupContext();
- HValue* function = AddLoadJSBuiltin(Builtins::DELETE, context);
+ HValue* function = AddLoadJSBuiltin(Builtins::DELETE);
Add<HPushArgument>(obj);
Add<HPushArgument>(key);
Add<HPushArgument>(Add<HConstant>(function_strict_mode_flag()));
// TODO(olivf) InvokeFunction produces a check for the parameter count,
// even though we are certain to pass the correct number of arguments here.
- HInstruction* instr = new(zone()) HInvokeFunction(context, function, 3);
+ HInstruction* instr = New<HInvokeFunction>(function, 3);
return ast_context()->ReturnInstruction(instr, expr->id());
} else if (proxy != NULL) {
Variable* var = proxy->var();
@@ -7421,7 +7325,7 @@
void HOptimizedGraphBuilder::VisitTypeof(UnaryOperation* expr) {
CHECK_ALIVE(VisitForTypeOf(expr->expression()));
HValue* value = Pop();
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
HInstruction* instr = new(zone()) HTypeof(context, value);
return ast_context()->ReturnInstruction(instr, expr->id());
}
@@ -7518,11 +7422,9 @@
HConstant* delta = (expr->op() == Token::INC)
? graph()->GetConstant1()
: graph()->GetConstantMinus1();
- HValue* context = environment()->LookupContext();
- HInstruction* instr = HAdd::New(zone(), context, Top(), delta);
+ HInstruction* instr = Add<HAdd>(Top(), delta);
instr->SetFlag(HInstruction::kCannotBeTagged);
instr->ClearAllSideEffects();
- AddInstruction(instr);
return instr;
}
@@ -7687,7 +7589,6 @@
HInstruction* HOptimizedGraphBuilder::BuildStringCharCodeAt(
- HValue* context,
HValue* string,
HValue* index) {
if (string->IsConstant() && index->IsConstant()) {
@@ -7697,17 +7598,18 @@
int32_t i = c_index->NumberValueAsInteger32();
Handle<String> s = c_string->StringValue();
if (i < 0 || i >= s->length()) {
- return new(zone()) HConstant(OS::nan_value());
+ return New<HConstant>(OS::nan_value());
}
- return new(zone()) HConstant(s->Get(i));
+ return New<HConstant>(s->Get(i));
}
}
BuildCheckHeapObject(string);
- AddInstruction(HCheckInstanceType::NewIsString(string, zone()));
- HInstruction* length = HStringLength::New(zone(), string);
+ HValue* checkstring =
+ AddInstruction(HCheckInstanceType::NewIsString(string, zone()));
+ HInstruction* length = BuildLoadStringLength(string, checkstring);
AddInstruction(length);
HInstruction* checked_index = Add<HBoundsCheck>(index, length);
- return new(zone()) HStringCharCodeAt(context, string, checked_index);
+ return New<HStringCharCodeAt>(string, checked_index);
}
@@ -7777,26 +7679,6 @@
*expected = handle(Type::Number(), isolate());
return AddInstruction(number.value);
}
- return value;
- }
-
- Handle<Type> expected_type = *expected;
- Representation rep = Representation::FromType(expected_type);
- if (!rep.IsTagged()) return value;
-
- // If our type feedback suggests that we can non-observably truncate to number
- // we introduce the appropriate check here. This avoids 'value' having a
- // tagged representation later on.
- if (expected_type->Is(Type::Oddball())) {
- // TODO(olivf) The BinaryOpStub only records undefined. It might pay off to
- // also record booleans and convert them to 0/1 here.
- IfBuilder if_nan(this);
- if_nan.If<HCompareObjectEqAndBranch>(value,
- graph()->GetConstantUndefined());
- if_nan.Then();
- if_nan.ElseDeopt();
- if_nan.End();
- return Add<HConstant>(OS::nan_value(), Representation::Double());
}
return value;
@@ -7807,7 +7689,7 @@
BinaryOperation* expr,
HValue* left,
HValue* right) {
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
Handle<Type> left_type = expr->left()->bounds().lower;
Handle<Type> right_type = expr->right()->bounds().lower;
Handle<Type> result_type = expr->bounds().lower;
@@ -7860,7 +7742,7 @@
break;
case Token::BIT_XOR:
case Token::BIT_AND:
- instr = HBitwise::New(zone(), expr->op(), context, left, right);
+ instr = NewUncasted<HBitwise>(expr->op(), left, right);
break;
case Token::BIT_OR: {
HValue* operand, *shift_amount;
@@ -7869,7 +7751,7 @@
MatchRotateRight(left, right, &operand, &shift_amount)) {
instr = new(zone()) HRor(context, operand, shift_amount);
} else {
- instr = HBitwise::New(zone(), expr->op(), context, left, right);
+ instr = NewUncasted<HBitwise>(expr->op(), left, right);
}
break;
}
@@ -8114,14 +7996,14 @@
CHECK_ALIVE(VisitForValue(expr->left()));
CHECK_ALIVE(VisitForValue(expr->right()));
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
HValue* right = Pop();
HValue* left = Pop();
Token::Value op = expr->op();
if (IsLiteralCompareBool(left, op, right)) {
HCompareObjectEqAndBranch* result =
- new(zone()) HCompareObjectEqAndBranch(left, right);
+ New<HCompareObjectEqAndBranch>(left, right);
result->set_position(expr->position());
return ast_context()->ReturnControl(result, expr->id());
}
@@ -8167,7 +8049,7 @@
// Code below assumes that we don't fall through.
UNREACHABLE();
} else if (op == Token::IN) {
- HValue* function = AddLoadJSBuiltin(Builtins::IN, context);
+ HValue* function = AddLoadJSBuiltin(Builtins::IN);
Add<HPushArgument>(left);
Add<HPushArgument>(right);
// TODO(olivf) InvokeFunction produces a check for the parameter count,
@@ -8191,10 +8073,10 @@
// Can we get away with map check and not instance type check?
if (combined_type->IsClass()) {
Handle<Map> map = combined_type->AsClass();
- AddCheckMapsWithTransitions(left, map);
- AddCheckMapsWithTransitions(right, map);
+ AddCheckMap(left, map);
+ AddCheckMap(right, map);
HCompareObjectEqAndBranch* result =
- new(zone()) HCompareObjectEqAndBranch(left, right);
+ New<HCompareObjectEqAndBranch>(left, right);
result->set_position(expr->position());
return ast_context()->ReturnControl(result, expr->id());
} else {
@@ -8275,7 +8157,7 @@
// If we share optimized code between different closures, the
// this-function is not a constant, except inside an inlined body.
if (function_state()->outer() != NULL) {
- return new(zone()) HConstant(
+ return New<HConstant>(
function_state()->compilation_info()->closure());
} else {
return new(zone()) HThisFunction;
@@ -8296,34 +8178,27 @@
HInstruction* target = NULL;
HInstruction* data_target = NULL;
- ElementsKind kind = boilerplate_object->map()->elements_kind();
-
- if (isolate()->heap()->ShouldGloballyPretenure()) {
+ if (isolate()->heap()->GetPretenureMode() == TENURED) {
if (data_size != 0) {
- HAllocate::Flags data_flags =
- static_cast<HAllocate::Flags>(HAllocate::DefaultFlags(kind) |
- HAllocate::CAN_ALLOCATE_IN_OLD_DATA_SPACE);
HValue* size_in_bytes = Add<HConstant>(data_size);
- data_target = Add<HAllocate>(context, size_in_bytes, HType::JSObject(),
- data_flags);
+ data_target = Add<HAllocate>(size_in_bytes, HType::JSObject(), TENURED,
+ FIXED_DOUBLE_ARRAY_TYPE);
Handle<Map> free_space_map = isolate()->factory()->free_space_map();
AddStoreMapConstant(data_target, free_space_map);
HObjectAccess access =
HObjectAccess::ForJSObjectOffset(FreeSpace::kSizeOffset);
- AddStore(data_target, access, size_in_bytes);
+ Add<HStoreNamedField>(data_target, access, size_in_bytes);
}
if (pointer_size != 0) {
- HAllocate::Flags pointer_flags =
- static_cast<HAllocate::Flags>(HAllocate::DefaultFlags() |
- HAllocate::CAN_ALLOCATE_IN_OLD_POINTER_SPACE);
HValue* size_in_bytes = Add<HConstant>(pointer_size);
- target = Add<HAllocate>(context, size_in_bytes, HType::JSObject(),
- pointer_flags);
+ target = Add<HAllocate>(size_in_bytes, HType::JSObject(), TENURED,
+ JS_OBJECT_TYPE);
}
} else {
- HAllocate::Flags flags = HAllocate::DefaultFlags(kind);
+ InstanceType instance_type = boilerplate_object->map()->instance_type();
HValue* size_in_bytes = Add<HConstant>(data_size + pointer_size);
- target = Add<HAllocate>(context, size_in_bytes, HType::JSObject(), flags);
+ target = Add<HAllocate>(size_in_bytes, HType::JSObject(), NOT_TENURED,
+ instance_type);
}
int offset = 0;
@@ -8344,8 +8219,6 @@
HInstruction* data_target,
int* data_offset,
AllocationSiteMode mode) {
- Zone* zone = this->zone();
-
bool create_allocation_site_info = mode == TRACK_ALLOCATION_SITE &&
boilerplate_object->map()->CanTrackAllocationSite();
@@ -8357,8 +8230,7 @@
HInstruction* allocation_site = NULL;
if (create_allocation_site_info) {
- allocation_site = AddInstruction(new(zone) HConstant(
- allocation_site_object, Representation::Tagged()));
+ allocation_site = Add<HConstant>(allocation_site_object);
}
// Only elements backing stores for non-COW arrays need to be copied.
@@ -8439,14 +8311,15 @@
}
result = elements;
}
- AddStore(object_header, HObjectAccess::ForElementsPointer(), elements);
+ Add<HStoreNamedField>(object_header, HObjectAccess::ForElementsPointer(),
+ elements);
Handle<Object> properties_field =
Handle<Object>(boilerplate_object->properties(), isolate());
ASSERT(*properties_field == isolate()->heap()->empty_fixed_array());
HInstruction* properties = Add<HConstant>(properties_field);
HObjectAccess access = HObjectAccess::ForPropertiesPointer();
- AddStore(object_header, access, properties);
+ Add<HStoreNamedField>(object_header, access, properties);
if (boilerplate_object->IsJSArray()) {
Handle<JSArray> boilerplate_array =
@@ -8456,7 +8329,7 @@
HInstruction* length = Add<HConstant>(length_field);
ASSERT(boilerplate_array->length()->IsSmi());
- AddStore(object_header, HObjectAccess::ForArrayLength(
+ Add<HStoreNamedField>(object_header, HObjectAccess::ForArrayLength(
boilerplate_array->GetElementsKind()), length);
}
@@ -8501,7 +8374,7 @@
HInstruction* value_instruction = Add<HInnerAllocatedObject>(target,
*offset);
- AddStore(object_properties, access, value_instruction);
+ Add<HStoreNamedField>(object_properties, access, value_instruction);
BuildEmitDeepCopy(value_object, original_value_object,
Handle<Object>::null(), target,
offset, data_target, data_offset,
@@ -8522,12 +8395,12 @@
}
AddStoreMapConstant(double_box,
isolate()->factory()->heap_number_map());
- AddStore(double_box, HObjectAccess::ForHeapNumberValue(),
+ Add<HStoreNamedField>(double_box, HObjectAccess::ForHeapNumberValue(),
value_instruction);
value_instruction = double_box;
}
- AddStore(object_properties, access, value_instruction);
+ Add<HStoreNamedField>(object_properties, access, value_instruction);
}
}
@@ -8538,7 +8411,7 @@
ASSERT(boilerplate_object->IsJSObject());
int property_offset = boilerplate_object->GetInObjectPropertyOffset(i);
HObjectAccess access = HObjectAccess::ForJSObjectOffset(property_offset);
- AddStore(object_properties, access, value_instruction);
+ Add<HStoreNamedField>(object_properties, access, value_instruction);
}
}
@@ -8647,7 +8520,7 @@
int flags = DeclareGlobalsEvalFlag::encode(current_info()->is_eval()) |
DeclareGlobalsNativeFlag::encode(current_info()->is_native()) |
DeclareGlobalsLanguageMode::encode(current_info()->language_mode());
- Add<HDeclareGlobals>(environment()->LookupContext(), array, flags);
+ Add<HDeclareGlobals>(array, flags);
globals_.Clear();
}
}
@@ -8676,7 +8549,7 @@
case Variable::CONTEXT:
if (hole_init) {
HValue* value = graph()->GetConstantHole();
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
HStoreContextSlot* store = Add<HStoreContextSlot>(
context, variable->index(), HStoreContextSlot::kNoCheck, value);
if (store->HasObservableSideEffects()) {
@@ -8714,7 +8587,7 @@
case Variable::CONTEXT: {
CHECK_ALIVE(VisitForValue(declaration->fun()));
HValue* value = Pop();
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
HStoreContextSlot* store = Add<HStoreContextSlot>(
context, variable->index(), HStoreContextSlot::kNoCheck, value);
if (store->HasObservableSideEffects()) {
@@ -8889,7 +8762,7 @@
ASSERT(function_state()->outer() == NULL);
ASSERT(call->arguments()->length() == 0);
HInstruction* elements = Add<HArgumentsElements>(false);
- HArgumentsLength* result = new(zone()) HArgumentsLength(elements);
+ HArgumentsLength* result = New<HArgumentsLength>(elements);
return ast_context()->ReturnInstruction(result, call->id());
}
@@ -8998,7 +8871,7 @@
// Create in-object property store to kValueOffset.
set_current_block(if_js_value);
- AddStore(object,
+ Add<HStoreNamedField>(object,
HObjectAccess::ForJSObjectOffset(JSValue::kValueOffset), value);
if_js_value->Goto(join);
join->SetJoinId(call->id());
@@ -9014,8 +8887,7 @@
CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
HValue* index = Pop();
HValue* string = Pop();
- HValue* context = environment()->LookupContext();
- HInstruction* result = BuildStringCharCodeAt(context, string, index);
+ HInstruction* result = BuildStringCharCodeAt(string, index);
return ast_context()->ReturnInstruction(result, call->id());
}
@@ -9025,8 +8897,7 @@
ASSERT(call->arguments()->length() == 1);
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
HValue* char_code = Pop();
- HValue* context = environment()->LookupContext();
- HInstruction* result = HStringCharFromCode::New(zone(), context, char_code);
+ HInstruction* result = New<HStringCharFromCode>(char_code);
return ast_context()->ReturnInstruction(result, call->id());
}
@@ -9038,10 +8909,9 @@
CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
HValue* index = Pop();
HValue* string = Pop();
- HValue* context = environment()->LookupContext();
- HInstruction* char_code = BuildStringCharCodeAt(context, string, index);
+ HInstruction* char_code = BuildStringCharCodeAt(string, index);
AddInstruction(char_code);
- HInstruction* result = HStringCharFromCode::New(zone(), context, char_code);
+ HInstruction* result = New<HStringCharFromCode>(char_code);
return ast_context()->ReturnInstruction(result, call->id());
}
@@ -9054,7 +8924,7 @@
HValue* right = Pop();
HValue* left = Pop();
HCompareObjectEqAndBranch* result =
- new(zone()) HCompareObjectEqAndBranch(left, right);
+ New<HCompareObjectEqAndBranch>(left, right);
return ast_context()->ReturnControl(result, call->id());
}
@@ -9067,8 +8937,7 @@
// Fast support for Math.random().
void HOptimizedGraphBuilder::GenerateRandomHeapNumber(CallRuntime* call) {
- HValue* context = environment()->LookupContext();
- HGlobalObject* global_object = Add<HGlobalObject>(context);
+ HGlobalObject* global_object = Add<HGlobalObject>();
HRandom* result = new(zone()) HRandom(global_object);
return ast_context()->ReturnInstruction(result, call->id());
}
@@ -9081,7 +8950,7 @@
CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
HValue* right = Pop();
HValue* left = Pop();
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
HInstruction* result = HStringAdd::New(
zone(), context, left, right, STRING_ADD_CHECK_BOTH);
return ast_context()->ReturnInstruction(result, call->id());
@@ -9092,7 +8961,7 @@
void HOptimizedGraphBuilder::GenerateSubString(CallRuntime* call) {
ASSERT_EQ(3, call->arguments()->length());
CHECK_ALIVE(VisitArgumentList(call->arguments()));
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
HCallStub* result = new(zone()) HCallStub(context, CodeStub::SubString, 3);
Drop(3);
return ast_context()->ReturnInstruction(result, call->id());
@@ -9103,7 +8972,7 @@
void HOptimizedGraphBuilder::GenerateStringCompare(CallRuntime* call) {
ASSERT_EQ(2, call->arguments()->length());
CHECK_ALIVE(VisitArgumentList(call->arguments()));
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
HCallStub* result =
new(zone()) HCallStub(context, CodeStub::StringCompare, 2);
Drop(2);
@@ -9115,7 +8984,7 @@
void HOptimizedGraphBuilder::GenerateRegExpExec(CallRuntime* call) {
ASSERT_EQ(4, call->arguments()->length());
CHECK_ALIVE(VisitArgumentList(call->arguments()));
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
HCallStub* result = new(zone()) HCallStub(context, CodeStub::RegExpExec, 4);
Drop(4);
return ast_context()->ReturnInstruction(result, call->id());
@@ -9126,7 +8995,7 @@
void HOptimizedGraphBuilder::GenerateRegExpConstructResult(CallRuntime* call) {
ASSERT_EQ(3, call->arguments()->length());
CHECK_ALIVE(VisitArgumentList(call->arguments()));
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
HCallStub* result =
new(zone()) HCallStub(context, CodeStub::RegExpConstructResult, 3);
Drop(3);
@@ -9144,7 +9013,7 @@
void HOptimizedGraphBuilder::GenerateNumberToString(CallRuntime* call) {
ASSERT_EQ(1, call->arguments()->length());
CHECK_ALIVE(VisitArgumentList(call->arguments()));
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
HCallStub* result =
new(zone()) HCallStub(context, CodeStub::NumberToString, 1);
Drop(1);
@@ -9164,7 +9033,6 @@
CHECK_ALIVE(VisitForValue(call->arguments()->last()));
HValue* function = Pop();
- HValue* context = environment()->LookupContext();
// Branch for function proxies, or other non-functions.
HHasInstanceTypeAndBranch* typecheck =
@@ -9177,14 +9045,13 @@
current_block()->Finish(typecheck);
set_current_block(if_jsfunction);
- HInstruction* invoke_result =
- Add<HInvokeFunction>(context, function, arg_count);
+ HInstruction* invoke_result = Add<HInvokeFunction>(function, arg_count);
Drop(arg_count);
Push(invoke_result);
if_jsfunction->Goto(join);
set_current_block(if_nonfunction);
- HInstruction* call_result = Add<HCallFunction>(context, function, arg_count);
+ HInstruction* call_result = Add<HCallFunction>(function, arg_count);
Drop(arg_count);
Push(call_result);
if_nonfunction->Goto(join);
@@ -9202,7 +9069,7 @@
CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
HValue* right = Pop();
HValue* left = Pop();
- HInstruction* result = HPower::New(zone(), left, right);
+ HInstruction* result = HPower::New(zone(), context(), left, right);
return ast_context()->ReturnInstruction(result, call->id());
}
@@ -9210,7 +9077,7 @@
void HOptimizedGraphBuilder::GenerateMathSin(CallRuntime* call) {
ASSERT_EQ(1, call->arguments()->length());
CHECK_ALIVE(VisitArgumentList(call->arguments()));
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
HCallStub* result =
new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1);
result->set_transcendental_type(TranscendentalCache::SIN);
@@ -9222,7 +9089,7 @@
void HOptimizedGraphBuilder::GenerateMathCos(CallRuntime* call) {
ASSERT_EQ(1, call->arguments()->length());
CHECK_ALIVE(VisitArgumentList(call->arguments()));
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
HCallStub* result =
new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1);
result->set_transcendental_type(TranscendentalCache::COS);
@@ -9234,7 +9101,7 @@
void HOptimizedGraphBuilder::GenerateMathTan(CallRuntime* call) {
ASSERT_EQ(1, call->arguments()->length());
CHECK_ALIVE(VisitArgumentList(call->arguments()));
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
HCallStub* result =
new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1);
result->set_transcendental_type(TranscendentalCache::TAN);
@@ -9246,7 +9113,7 @@
void HOptimizedGraphBuilder::GenerateMathLog(CallRuntime* call) {
ASSERT_EQ(1, call->arguments()->length());
CHECK_ALIVE(VisitArgumentList(call->arguments()));
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
HCallStub* result =
new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1);
result->set_transcendental_type(TranscendentalCache::LOG);
@@ -9259,7 +9126,7 @@
ASSERT(call->arguments()->length() == 1);
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
HValue* value = Pop();
- HValue* context = environment()->LookupContext();
+ HValue* context = environment()->context();
HInstruction* result =
HUnaryMathOperation::New(zone(), context, value, kMathSqrt);
return ast_context()->ReturnInstruction(result, call->id());
@@ -9569,7 +9436,7 @@
if (undefined_receiver) {
inner->SetValueAt(0, undefined);
}
- inner->SetValueAt(arity + 1, LookupContext());
+ inner->SetValueAt(arity + 1, context());
for (int i = arity + 2; i < inner->length(); ++i) {
inner->SetValueAt(i, undefined);
}
diff --git a/src/hydrogen.h b/src/hydrogen.h
index 895b984..2668d19 100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -316,7 +316,6 @@
HEnvironment* start_environment() const { return start_environment_; }
void FinalizeUniqueValueIds();
- void MarkDeoptimizeOnUndefined();
bool ProcessArgumentsObject();
void OrderBlocks();
void AssignDominators();
@@ -464,7 +463,6 @@
phase.Run();
}
- void RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi* phi);
void CheckForBackEdge(HBasicBlock* block, HBasicBlock* successor);
void SetupInformativeDefinitionsInBlock(HBasicBlock* block);
void SetupInformativeDefinitionsRecursively(HBasicBlock* block);
@@ -585,7 +583,7 @@
return result;
}
- HValue* LookupContext() const {
+ HValue* context() const {
// Return first special.
return Lookup(parameter_count());
}
@@ -992,57 +990,205 @@
void Push(HValue* value) { environment()->Push(value); }
HValue* Pop() { return environment()->Pop(); }
+ virtual HValue* context() = 0;
+
// Adding instructions.
HInstruction* AddInstruction(HInstruction* instr);
template<class I>
- I* Add() { return static_cast<I*>(AddInstruction(new(zone()) I())); }
+ HInstruction* NewUncasted() { return I::New(zone(), context()); }
+
+ template<class I>
+ I* New() { return I::cast(NewUncasted<I>()); }
+
+ template<class I>
+ HInstruction* AddUncasted() { return AddInstruction(NewUncasted<I>());}
+
+ template<class I>
+ I* Add() { return I::cast(AddUncasted<I>());}
+
+ template<class I, class P1>
+ HInstruction* NewUncasted(P1 p1) {
+ return I::New(zone(), context(), p1);
+ }
+
+ template<class I, class P1>
+ I* New(P1 p1) { return I::cast(NewUncasted<I>(p1)); }
+
+ template<class I, class P1>
+ HInstruction* AddUncasted(P1 p1) {
+ HInstruction* result = AddInstruction(NewUncasted<I>(p1));
+ // Specializations must have their parameters properly casted
+ // to avoid landing here.
+ ASSERT(!result->IsReturn() && !result->IsSimulate() &&
+ !result->IsDeoptimize());
+ return result;
+ }
template<class I, class P1>
I* Add(P1 p1) {
- return static_cast<I*>(AddInstruction(new(zone()) I(p1)));
+ return I::cast(AddUncasted<I>(p1));
+ }
+
+ template<class I, class P1, class P2>
+ HInstruction* NewUncasted(P1 p1, P2 p2) {
+ return I::New(zone(), context(), p1, p2);
+ }
+
+ template<class I, class P1, class P2>
+ I* New(P1 p1, P2 p2) {
+ return I::cast(NewUncasted<I>(p1, p2));
+ }
+
+ template<class I, class P1, class P2>
+ HInstruction* AddUncasted(P1 p1, P2 p2) {
+ HInstruction* result = AddInstruction(NewUncasted<I>(p1, p2));
+ // Specializations must have their parameters properly casted
+ // to avoid landing here.
+ ASSERT(!result->IsSimulate());
+ return result;
}
template<class I, class P1, class P2>
I* Add(P1 p1, P2 p2) {
- return static_cast<I*>(AddInstruction(new(zone()) I(p1, p2)));
+ return static_cast<I*>(AddUncasted<I>(p1, p2));
+ }
+
+ template<class I, class P1, class P2, class P3>
+ HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3) {
+ return I::New(zone(), context(), p1, p2, p3);
+ }
+
+ template<class I, class P1, class P2, class P3>
+ I* New(P1 p1, P2 p2, P3 p3) {
+ return I::cast(NewUncasted<I>(p1, p2, p3));
+ }
+
+ template<class I, class P1, class P2, class P3>
+ HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3) {
+ return AddInstruction(NewUncasted<I>(p1, p2, p3));
}
template<class I, class P1, class P2, class P3>
I* Add(P1 p1, P2 p2, P3 p3) {
- return static_cast<I*>(AddInstruction(new(zone()) I(p1, p2, p3)));
+ return I::cast(AddUncasted<I>(p1, p2, p3));
+ }
+
+ template<class I, class P1, class P2, class P3, class P4>
+ HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4) {
+ return I::New(zone(), context(), p1, p2, p3, p4);
+ }
+
+ template<class I, class P1, class P2, class P3, class P4>
+ I* New(P1 p1, P2 p2, P3 p3, P4 p4) {
+ return I::cast(NewUncasted<I>(p1, p2, p3, p4));
+ }
+
+ template<class I, class P1, class P2, class P3, class P4>
+ HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4) {
+ return AddInstruction(NewUncasted<I>(p1, p2, p3, p4));
}
template<class I, class P1, class P2, class P3, class P4>
I* Add(P1 p1, P2 p2, P3 p3, P4 p4) {
- return static_cast<I*>(AddInstruction(new(zone()) I(p1, p2, p3, p4)));
+ return I::cast(AddUncasted<I>(p1, p2, p3, p4));
+ }
+
+ template<class I, class P1, class P2, class P3, class P4, class P5>
+ HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
+ return I::New(zone(), context(), p1, p2, p3, p4, p5);
+ }
+
+ template<class I, class P1, class P2, class P3, class P4, class P5>
+ I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
+ return I::cast(NewUncasted<I>(p1, p2, p3, p4, p5));
+ }
+
+ template<class I, class P1, class P2, class P3, class P4, class P5>
+ HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
+ return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5));
}
template<class I, class P1, class P2, class P3, class P4, class P5>
I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
- return static_cast<I*>(AddInstruction(new(zone()) I(p1, p2, p3, p4, p5)));
+ return I::cast(AddUncasted<I>(p1, p2, p3, p4, p5));
+ }
+
+ template<class I, class P1, class P2, class P3, class P4, class P5, class P6>
+ HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) {
+ return I::New(zone(), context(), p1, p2, p3, p4, p5, p6);
+ }
+
+ template<class I, class P1, class P2, class P3, class P4, class P5, class P6>
+ I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) {
+ return I::cast(NewUncasted<I>(p1, p2, p3, p4, p5, p6));
+ }
+
+ template<class I, class P1, class P2, class P3, class P4, class P5, class P6>
+ HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) {
+ return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5, p6));
}
template<class I, class P1, class P2, class P3, class P4, class P5, class P6>
I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) {
- return static_cast<I*>(AddInstruction(
- new(zone()) I(p1, p2, p3, p4, p5, p6)));
+ return I::cast(AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5, p6)));
+ }
+
+ template<class I, class P1, class P2, class P3, class P4,
+ class P5, class P6, class P7>
+ HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) {
+ return I::New(zone(), context(), p1, p2, p3, p4, p5, p6, p7);
+ }
+
+ template<class I, class P1, class P2, class P3, class P4,
+ class P5, class P6, class P7>
+ I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) {
+ return I::cast(NewUncasted<I>(p1, p2, p3, p4, p5, p6, p7));
+ }
+
+ template<class I, class P1, class P2, class P3,
+ class P4, class P5, class P6, class P7>
+ HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) {
+ return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5, p6, p7));
}
template<class I, class P1, class P2, class P3,
class P4, class P5, class P6, class P7>
I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) {
- return static_cast<I*>(AddInstruction(
- new(zone()) I(p1, p2, p3, p4, p5, p6, p7)));
+ return I::cast(AddInstruction(NewUncasted<I>(p1, p2, p3, p4,
+ p5, p6, p7)));
+ }
+
+ template<class I, class P1, class P2, class P3, class P4,
+ class P5, class P6, class P7, class P8>
+ HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4,
+ P5 p5, P6 p6, P7 p7, P8 p8) {
+ return I::New(zone(), context(), p1, p2, p3, p4, p5, p6, p7, p8);
+ }
+
+ template<class I, class P1, class P2, class P3, class P4,
+ class P5, class P6, class P7, class P8>
+ I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) {
+ return I::cast(NewUncasted<I>(p1, p2, p3, p4, p5, p6, p7, p8));
+ }
+
+ template<class I, class P1, class P2, class P3, class P4,
+ class P5, class P6, class P7, class P8>
+ HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4,
+ P5 p5, P6 p6, P7 p7, P8 p8) {
+ return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5, p6, p7, p8));
}
template<class I, class P1, class P2, class P3, class P4,
class P5, class P6, class P7, class P8>
I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) {
- return static_cast<I*>(AddInstruction(
- new(zone()) I(p1, p2, p3, p4, p5, p6, p7, p8)));
+ return I::cast(
+ AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5, p6, p7, p8)));
}
+ void AddSimulate(BailoutId id,
+ RemovableSimulate removable = FIXED_SIMULATE);
+
void IncrementInNoSideEffectsScope() {
no_side_effects_scope_count_++;
}
@@ -1091,16 +1237,6 @@
LoadKeyedHoleMode load_mode,
KeyedAccessStoreMode store_mode);
- HLoadNamedField* AddLoad(
- HValue *object,
- HObjectAccess access,
- HValue *typecheck = NULL);
-
- HLoadNamedField* BuildLoadNamedField(
- HValue* object,
- HObjectAccess access,
- Representation representation);
-
HInstruction* AddExternalArrayElementAccess(
HValue* external_elements,
HValue* checked_key,
@@ -1119,13 +1255,16 @@
LoadKeyedHoleMode load_mode,
KeyedAccessStoreMode store_mode);
- HLoadNamedField* BuildLoadNamedField(HValue* object, HObjectAccess access);
- HStoreNamedField* AddStore(HValue *object, HObjectAccess access, HValue *val);
+ HLoadNamedField* BuildLoadNamedField(
+ HValue* object,
+ HObjectAccess access,
+ HValue* typecheck = NULL);
+ HInstruction* BuildLoadStringLength(HValue* object, HValue* typecheck = NULL);
HStoreNamedField* AddStoreMapConstant(HValue *object, Handle<Map>);
HLoadNamedField* AddLoadElements(HValue *object, HValue *typecheck = NULL);
HLoadNamedField* AddLoadFixedArrayLength(HValue *object);
- HValue* AddLoadJSBuiltin(Builtins::JavaScript builtin, HValue* context);
+ HValue* AddLoadJSBuiltin(Builtins::JavaScript builtin);
HValue* TruncateToNumber(HValue* value, Handle<Type>* expected);
@@ -1133,6 +1272,9 @@
void FinishExitWithHardDeoptimization(HBasicBlock* continuation);
+ void AddIncrementCounter(StatsCounter* counter,
+ HValue* context);
+
class IfBuilder {
public:
explicit IfBuilder(HGraphBuilder* builder,
@@ -1313,8 +1455,7 @@
HGraphBuilder* builder_;
};
- HValue* BuildNewElementsCapacity(HValue* context,
- HValue* old_capacity);
+ HValue* BuildNewElementsCapacity(HValue* old_capacity);
void BuildNewSpaceArrayCheck(HValue* length,
ElementsKind kind);
@@ -1348,7 +1489,7 @@
return JSArray::kPreallocatedArrayElements;
}
- HValue* EmitMapCode(HValue* context);
+ HValue* EmitMapCode();
HValue* EmitInternalMapCode();
HValue* EstablishEmptyArrayAllocationSize();
HValue* EstablishAllocationSize(HValue* length_node);
@@ -1363,16 +1504,14 @@
HInnerAllocatedObject* elements_location_;
};
- HValue* BuildAllocateElements(HValue* context,
- ElementsKind kind,
+ HValue* BuildAllocateElements(ElementsKind kind,
HValue* capacity);
void BuildInitializeElementsHeader(HValue* elements,
ElementsKind kind,
HValue* capacity);
- HValue* BuildAllocateElementsAndInitializeElementsHeader(HValue* context,
- ElementsKind kind,
+ HValue* BuildAllocateElementsAndInitializeElementsHeader(ElementsKind kind,
HValue* capacity);
// array must have been allocated with enough room for
@@ -1393,22 +1532,19 @@
HValue* length,
HValue* new_capacity);
- void BuildFillElementsWithHole(HValue* context,
- HValue* elements,
+ void BuildFillElementsWithHole(HValue* elements,
ElementsKind elements_kind,
HValue* from,
HValue* to);
- void BuildCopyElements(HValue* context,
- HValue* from_elements,
+ void BuildCopyElements(HValue* from_elements,
ElementsKind from_elements_kind,
HValue* to_elements,
ElementsKind to_elements_kind,
HValue* length,
HValue* capacity);
- HValue* BuildCloneShallowArray(HContext* context,
- HValue* boilerplate,
+ HValue* BuildCloneShallowArray(HValue* boilerplate,
HValue* allocation_site,
AllocationSiteMode mode,
ElementsKind kind,
@@ -1427,8 +1563,8 @@
int previous_object_size,
HValue* payload);
- HInstruction* BuildGetNativeContext(HValue* context);
- HInstruction* BuildGetArrayFunction(HValue* context);
+ HInstruction* BuildGetNativeContext();
+ HInstruction* BuildGetArrayFunction();
private:
HGraphBuilder();
@@ -1444,13 +1580,14 @@
template<>
-inline HDeoptimize* HGraphBuilder::Add(Deoptimizer::BailoutType type) {
+inline HInstruction* HGraphBuilder::AddUncasted<HDeoptimize>(
+ Deoptimizer::BailoutType type) {
if (type == Deoptimizer::SOFT) {
isolate()->counters()->soft_deopts_requested()->Increment();
if (FLAG_always_opt) return NULL;
}
if (current_block()->IsDeoptimizing()) return NULL;
- HDeoptimize* instr = new(zone()) HDeoptimize(type);
+ HDeoptimize* instr = New<HDeoptimize>(type);
AddInstruction(instr);
if (type == Deoptimizer::SOFT) {
isolate()->counters()->soft_deopts_inserted()->Increment();
@@ -1462,8 +1599,16 @@
template<>
-inline HSimulate* HGraphBuilder::Add(BailoutId id,
- RemovableSimulate removable) {
+inline HDeoptimize* HGraphBuilder::Add<HDeoptimize>(
+ Deoptimizer::BailoutType type) {
+ return static_cast<HDeoptimize*>(AddUncasted<HDeoptimize>(type));
+}
+
+
+template<>
+inline HInstruction* HGraphBuilder::AddUncasted<HSimulate>(
+ BailoutId id,
+ RemovableSimulate removable) {
HSimulate* instr = current_block()->CreateSimulate(id, removable);
AddInstruction(instr);
return instr;
@@ -1471,26 +1616,46 @@
template<>
-inline HSimulate* HGraphBuilder::Add(BailoutId id) {
- return Add<HSimulate>(id, FIXED_SIMULATE);
+inline HInstruction* HGraphBuilder::NewUncasted<HLoadNamedField>(
+ HValue* object, HObjectAccess access) {
+ return NewUncasted<HLoadNamedField>(object, access,
+ static_cast<HValue*>(NULL));
}
template<>
-inline HReturn* HGraphBuilder::Add(HValue* value) {
- HValue* context = environment()->LookupContext();
+inline HInstruction* HGraphBuilder::AddUncasted<HLoadNamedField>(
+ HValue* object, HObjectAccess access) {
+ return AddUncasted<HLoadNamedField>(object, access,
+ static_cast<HValue*>(NULL));
+}
+
+
+template<>
+inline HInstruction* HGraphBuilder::AddUncasted<HSimulate>(BailoutId id) {
+ return AddUncasted<HSimulate>(id, FIXED_SIMULATE);
+}
+
+
+template<>
+inline HInstruction* HGraphBuilder::AddUncasted<HReturn>(HValue* value) {
int num_parameters = graph()->info()->num_parameters();
- HValue* params = Add<HConstant>(num_parameters);
- HReturn* return_instruction = new(graph()->zone())
- HReturn(value, context, params);
+ HValue* params = AddUncasted<HConstant>(num_parameters);
+ HReturn* return_instruction = New<HReturn>(value, params);
current_block()->FinishExit(return_instruction);
return return_instruction;
}
template<>
-inline HReturn* HGraphBuilder::Add(HConstant* p1) {
- return Add<HReturn>(static_cast<HValue*>(p1));
+inline HInstruction* HGraphBuilder::AddUncasted<HReturn>(HConstant* value) {
+ return AddUncasted<HReturn>(static_cast<HValue*>(value));
+}
+
+
+template<>
+inline HInstruction* HGraphBuilder::NewUncasted<HContext>() {
+ return HContext::New(zone());
}
@@ -1559,6 +1724,8 @@
bool inline_bailout() { return inline_bailout_; }
+ HValue* context() { return environment()->context(); }
+
void Bailout(const char* reason);
HBasicBlock* CreateJoin(HBasicBlock* first,
@@ -1834,8 +2001,7 @@
Expression* sub_expr,
NilValue nil);
- HInstruction* BuildStringCharCodeAt(HValue* context,
- HValue* string,
+ HInstruction* BuildStringCharCodeAt(HValue* string,
HValue* index);
HInstruction* BuildBinaryOperation(BinaryOperation* expr,
HValue* left,
@@ -1891,9 +2057,6 @@
void AddCheckMap(HValue* object, Handle<Map> map);
- void AddCheckMapsWithTransitions(HValue* object,
- Handle<Map> map);
-
void BuildStoreNamed(Expression* expression,
BailoutId id,
int position,
diff --git a/src/ia32/frames-ia32.h b/src/ia32/frames-ia32.h
index 6223748..8606125 100644
--- a/src/ia32/frames-ia32.h
+++ b/src/ia32/frames-ia32.h
@@ -136,6 +136,11 @@
}
+inline void StackHandler::SetFp(Address slot, Address fp) {
+ Memory::Address_at(slot) = fp;
+}
+
+
} } // namespace v8::internal
#endif // V8_IA32_FRAMES_IA32_H_
diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc
index 1e91468..bf0c80b 100644
--- a/src/ia32/ic-ia32.cc
+++ b/src/ia32/ic-ia32.cc
@@ -1591,61 +1591,6 @@
}
-void KeyedStoreIC::GenerateTransitionElementsSmiToDouble(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- ebx : target map
- // -- edx : receiver
- // -- esp[0] : return address
- // -----------------------------------
- // Must return the modified receiver in eax.
- if (!FLAG_trace_elements_transitions) {
- Label fail;
- AllocationSiteMode mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS,
- FAST_DOUBLE_ELEMENTS);
- ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, &fail);
- __ mov(eax, edx);
- __ Ret();
- __ bind(&fail);
- }
-
- __ pop(ebx);
- __ push(edx);
- __ push(ebx); // return address
- // Leaving the code managed by the register allocator and return to the
- // convention of using esi as context register.
- __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
- __ TailCallRuntime(Runtime::kTransitionElementsSmiToDouble, 1, 1);
-}
-
-
-void KeyedStoreIC::GenerateTransitionElementsDoubleToObject(
- MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- ebx : target map
- // -- edx : receiver
- // -- esp[0] : return address
- // -----------------------------------
- // Must return the modified receiver in eax.
- if (!FLAG_trace_elements_transitions) {
- Label fail;
- AllocationSiteMode mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS,
- FAST_ELEMENTS);
- ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, &fail);
- __ mov(eax, edx);
- __ Ret();
- __ bind(&fail);
- }
-
- __ pop(ebx);
- __ push(edx);
- __ push(ebx); // return address
- // Leaving the code managed by the register allocator and return to the
- // convention of using esi as context register.
- __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
- __ TailCallRuntime(Runtime::kTransitionElementsDoubleToObject, 1, 1);
-}
-
-
#undef __
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index d022a82..7a601cf 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -137,6 +137,16 @@
}
+#ifdef _MSC_VER
+void LCodeGen::MakeSureStackPagesMapped(int offset) {
+ const int kPageSize = 4 * KB;
+ for (offset -= kPageSize; offset > 0; offset -= kPageSize) {
+ __ mov(Operand(esp, offset), eax);
+ }
+}
+#endif
+
+
bool LCodeGen::GeneratePrologue() {
ASSERT(is_generating());
@@ -226,6 +236,9 @@
} else {
if (FLAG_debug_code) {
__ sub(Operand(esp), Immediate(slots * kPointerSize));
+#ifdef _MSC_VER
+ MakeSureStackPagesMapped(slots * kPointerSize);
+#endif
__ push(eax);
__ mov(Operand(eax), Immediate(slots));
Label loop;
@@ -238,15 +251,7 @@
} else {
__ sub(Operand(esp), Immediate(slots * kPointerSize));
#ifdef _MSC_VER
- // On windows, you may not access the stack more than one page below
- // the most recently mapped page. To make the allocated area randomly
- // accessible, we write to each page in turn (the value is irrelevant).
- const int kPageSize = 4 * KB;
- for (int offset = slots * kPointerSize - kPageSize;
- offset > 0;
- offset -= kPageSize) {
- __ mov(Operand(esp, offset), eax);
- }
+ MakeSureStackPagesMapped(slots * kPointerSize);
#endif
}
@@ -685,6 +690,13 @@
}
+ExternalReference LCodeGen::ToExternalReference(LConstantOperand* op) const {
+ HConstant* constant = chunk_->LookupConstant(op);
+ ASSERT(constant->HasExternalReferenceValue());
+ return constant->ExternalReferenceValue();
+}
+
+
bool LCodeGen::IsInteger32(LConstantOperand* op) const {
return chunk_->LookupLiteralRepresentation(op).IsSmiOrInteger32();
}
@@ -1762,7 +1774,16 @@
break;
case Token::SHL:
if (shift_count != 0) {
- __ shl(ToRegister(left), shift_count);
+ if (instr->hydrogen_value()->representation().IsSmi() &&
+ instr->can_deopt()) {
+ if (shift_count != 1) {
+ __ shl(ToRegister(left), shift_count - 1);
+ }
+ __ SmiTag(ToRegister(left));
+ DeoptimizeIf(overflow, instr->environment());
+ } else {
+ __ shl(ToRegister(left), shift_count);
+ }
}
break;
default:
@@ -1846,6 +1867,11 @@
}
+void LCodeGen::DoConstantE(LConstantE* instr) {
+ __ lea(ToRegister(instr->result()), Operand::StaticVariable(instr->value()));
+}
+
+
void LCodeGen::DoConstantT(LConstantT* instr) {
Register reg = ToRegister(instr->result());
Handle<Object> handle = instr->value();
@@ -2970,20 +2996,6 @@
}
-void LCodeGen::DoLinkObjectInList(LLinkObjectInList* instr) {
- Register object = ToRegister(instr->object());
- Register temp = ToRegister(instr->temp());
- ExternalReference sites_list_address = instr->GetReference(isolate());
-
- __ mov(temp, Immediate(sites_list_address));
- __ mov(temp, Operand(temp, 0));
- __ mov(FieldOperand(object, instr->hydrogen()->store_field().offset()),
- temp);
- __ mov(temp, Immediate(sites_list_address));
- __ mov(Operand(temp, 0), object);
-}
-
-
void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
Register context = ToRegister(instr->context());
Register result = ToRegister(instr->result());
@@ -3042,6 +3054,19 @@
void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
HObjectAccess access = instr->hydrogen()->access();
int offset = access.offset();
+
+ if (access.IsExternalMemory()) {
+ Register result = ToRegister(instr->result());
+ if (instr->object()->IsConstantOperand()) {
+ ExternalReference external_reference = ToExternalReference(
+ LConstantOperand::cast(instr->object()));
+ __ mov(result, MemOperand::StaticVariable(external_reference));
+ } else {
+ __ mov(result, MemOperand(ToRegister(instr->object()), offset));
+ }
+ return;
+ }
+
Register object = ToRegister(instr->object());
if (FLAG_track_double_fields &&
instr->hydrogen()->representation().IsDouble()) {
@@ -3131,9 +3156,6 @@
int i,
Isolate* isolate) {
Handle<Map> map = list->at(i);
- // If the map has ElementsKind transitions, we will generate map checks
- // for each kind in __ CompareMap(..., ALLOW_ELEMENTS_TRANSITION_MAPS).
- if (map->HasElementsTransition()) return false;
LookupResult lookup(isolate);
map->LookupDescriptor(NULL, *name, &lookup);
return lookup.IsField() || lookup.IsConstant();
@@ -4321,10 +4343,26 @@
void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
Representation representation = instr->representation();
- Register object = ToRegister(instr->object());
HObjectAccess access = instr->hydrogen()->access();
int offset = access.offset();
+ if (access.IsExternalMemory()) {
+ ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
+ MemOperand operand = instr->object()->IsConstantOperand()
+ ? MemOperand::StaticVariable(
+ ToExternalReference(LConstantOperand::cast(instr->object())))
+ : MemOperand(ToRegister(instr->object()), offset);
+ if (instr->value()->IsConstantOperand()) {
+ LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
+ __ mov(operand, Immediate(ToInteger32(operand_value)));
+ } else {
+ Register value = ToRegister(instr->value());
+ __ mov(operand, value);
+ }
+ return;
+ }
+
+ Register object = ToRegister(instr->object());
Handle<Map> transition = instr->transition();
if (FLAG_track_fields && representation.IsSmi()) {
@@ -4389,8 +4427,7 @@
Register write_register = object;
if (!access.IsInobject()) {
write_register = ToRegister(instr->temp());
- __ mov(write_register,
- FieldOperand(object, JSObject::kPropertiesOffset));
+ __ mov(write_register, FieldOperand(object, JSObject::kPropertiesOffset));
}
if (instr->value()->IsConstantOperand()) {
@@ -4708,7 +4745,7 @@
__ RecordWriteForMap(object_reg, to_map, new_map_reg,
ToRegister(instr->temp()),
kDontSaveFPRegs);
- } else if (FLAG_compiled_transitions) {
+ } else {
PushSafepointRegistersScope scope(this);
if (!object_reg.is(eax)) {
__ push(object_reg);
@@ -4722,28 +4759,6 @@
__ CallStub(&stub);
RecordSafepointWithRegisters(
instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
- } else if (IsFastSmiElementsKind(from_kind) &&
- IsFastDoubleElementsKind(to_kind)) {
- Register new_map_reg = ToRegister(instr->new_map_temp());
- __ mov(new_map_reg, to_map);
- Register fixed_object_reg = ToRegister(instr->temp());
- ASSERT(fixed_object_reg.is(edx));
- ASSERT(new_map_reg.is(ebx));
- __ mov(fixed_object_reg, object_reg);
- CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(),
- RelocInfo::CODE_TARGET, instr);
- } else if (IsFastDoubleElementsKind(from_kind) &&
- IsFastObjectElementsKind(to_kind)) {
- Register new_map_reg = ToRegister(instr->new_map_temp());
- __ mov(new_map_reg, to_map);
- Register fixed_object_reg = ToRegister(instr->temp());
- ASSERT(fixed_object_reg.is(edx));
- ASSERT(new_map_reg.is(ebx));
- __ mov(fixed_object_reg, object_reg);
- CallCode(isolate()->builtins()->TransitionElementsDoubleToObject(),
- RelocInfo::CODE_TARGET, instr);
- } else {
- UNREACHABLE();
}
__ bind(¬_applicable);
}
@@ -4852,13 +4867,6 @@
}
-void LCodeGen::DoStringLength(LStringLength* instr) {
- Register string = ToRegister(instr->string());
- Register result = ToRegister(instr->result());
- __ mov(result, FieldOperand(string, String::kLengthOffset));
-}
-
-
void LCodeGen::DoStringAdd(LStringAdd* instr) {
EmitPushTaggedOperand(instr->left());
EmitPushTaggedOperand(instr->right());
@@ -6024,10 +6032,12 @@
if (instr->hydrogen()->MustAllocateDoubleAligned()) {
flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
}
- if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
- ASSERT(!instr->hydrogen()->CanAllocateInOldDataSpace());
+ if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
+ ASSERT(!instr->hydrogen()->IsOldDataSpaceAllocation());
+ ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
- } else if (instr->hydrogen()->CanAllocateInOldDataSpace()) {
+ } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
+ ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_DATA_SPACE);
}
@@ -6079,11 +6089,13 @@
__ push(Immediate(Smi::FromInt(size)));
}
- if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
- ASSERT(!instr->hydrogen()->CanAllocateInOldDataSpace());
+ if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
+ ASSERT(!instr->hydrogen()->IsOldDataSpaceAllocation());
+ ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
CallRuntimeFromDeferred(
Runtime::kAllocateInOldPointerSpace, 1, instr, instr->context());
- } else if (instr->hydrogen()->CanAllocateInOldDataSpace()) {
+ } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
+ ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
CallRuntimeFromDeferred(
Runtime::kAllocateInOldDataSpace, 1, instr, instr->context());
} else {
diff --git a/src/ia32/lithium-codegen-ia32.h b/src/ia32/lithium-codegen-ia32.h
index 6574532..0beef85 100644
--- a/src/ia32/lithium-codegen-ia32.h
+++ b/src/ia32/lithium-codegen-ia32.h
@@ -297,6 +297,7 @@
X87Register ToX87Register(int index) const;
int ToRepresentation(LConstantOperand* op, const Representation& r) const;
int32_t ToInteger32(LConstantOperand* op) const;
+ ExternalReference ToExternalReference(LConstantOperand* op) const;
Operand BuildFastArrayOperand(LOperand* elements_pointer,
LOperand* key,
@@ -407,6 +408,14 @@
int X87ArrayIndex(X87Register reg);
int x87_st2idx(int pos);
+#ifdef _MSC_VER
+ // On windows, you may not access the stack more than one page below
+ // the most recently mapped page. To make the allocated area randomly
+ // accessible, we write an arbitrary value to each page in range
+ // esp + offset - page_size .. esp in turn.
+ void MakeSureStackPagesMapped(int offset);
+#endif
+
Zone* zone_;
LPlatformChunk* const chunk_;
MacroAssembler* const masm_;
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index f03cd72..2fa038b 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -302,24 +302,6 @@
}
-ExternalReference LLinkObjectInList::GetReference(Isolate* isolate) {
- switch (hydrogen()->known_list()) {
- case HLinkObjectInList::ALLOCATION_SITE_LIST:
- return ExternalReference::allocation_sites_list_address(isolate);
- }
-
- UNREACHABLE();
- // Return a dummy value
- return ExternalReference::isolate_address(isolate);
-}
-
-
-void LLinkObjectInList::PrintDataTo(StringStream* stream) {
- object()->PrintTo(stream);
- stream->Add(" offset %d", hydrogen()->store_field().offset());
-}
-
-
void LLoadContextSlot::PrintDataTo(StringStream* stream) {
context()->PrintTo(stream);
stream->Add("[%d]", slot_index());
@@ -761,7 +743,7 @@
LInstruction* LChunkBuilder::DoShift(Token::Value op,
HBitwiseBinaryOperation* instr) {
- if (instr->representation().IsSmiOrTagged()) {
+ if (instr->representation().IsTagged()) {
ASSERT(instr->left()->representation().IsSmiOrTagged());
ASSERT(instr->right()->representation().IsSmiOrTagged());
@@ -772,25 +754,35 @@
return MarkAsCall(DefineFixed(result, eax), instr);
}
- ASSERT(instr->representation().IsInteger32());
- ASSERT(instr->left()->representation().IsInteger32());
- ASSERT(instr->right()->representation().IsInteger32());
+ ASSERT(instr->representation().IsSmiOrInteger32());
+ ASSERT(instr->left()->representation().Equals(instr->representation()));
+ ASSERT(instr->right()->representation().Equals(instr->representation()));
LOperand* left = UseRegisterAtStart(instr->left());
HValue* right_value = instr->right();
LOperand* right = NULL;
int constant_value = 0;
+ bool does_deopt = false;
if (right_value->IsConstant()) {
HConstant* constant = HConstant::cast(right_value);
right = chunk_->DefineConstantOperand(constant);
constant_value = constant->Integer32Value() & 0x1f;
+ // Left shifts can deoptimize if we shift by > 0 and the result cannot be
+ // truncated to smi.
+ if (instr->representation().IsSmi() && constant_value > 0) {
+ for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) {
+ if (!it.value()->CheckFlag(HValue::kTruncatingToSmi)) {
+ does_deopt = true;
+ break;
+ }
+ }
+ }
} else {
right = UseFixed(right_value, ecx);
}
// Shift operations can only deoptimize if we do a logical shift by 0 and
// the result cannot be truncated to int32.
- bool does_deopt = false;
if (op == Token::SHR && constant_value == 0) {
if (FLAG_opt_safe_uint32_operations) {
does_deopt = !instr->CheckFlag(HInstruction::kUint32);
@@ -2136,6 +2128,8 @@
bool value_is_zero = BitCast<uint64_t, double>(value) == 0;
LOperand* temp = value_is_zero ? NULL : TempRegister();
return DefineAsRegister(new(zone()) LConstantD(temp));
+ } else if (r.IsExternal()) {
+ return DefineAsRegister(new(zone()) LConstantE);
} else if (r.IsTagged()) {
return DefineAsRegister(new(zone()) LConstantT);
} else {
@@ -2179,14 +2173,6 @@
}
-LInstruction* LChunkBuilder::DoLinkObjectInList(HLinkObjectInList* instr) {
- LOperand* object = UseRegister(instr->value());
- LOperand* temp = TempRegister();
- LLinkObjectInList* result = new(zone()) LLinkObjectInList(object, temp);
- return result;
-}
-
-
LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
LOperand* context = UseRegisterAtStart(instr->value());
LInstruction* result =
@@ -2212,7 +2198,10 @@
LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
- LOperand* obj = UseRegisterAtStart(instr->object());
+ LOperand* obj = (instr->access().IsExternalMemory() &&
+ instr->access().offset() == 0)
+ ? UseRegisterOrConstantAtStart(instr->object())
+ : UseRegisterAtStart(instr->object());
return DefineAsRegister(new(zone()) LLoadNamedField(obj));
}
@@ -2405,21 +2394,11 @@
new(zone()) LTransitionElementsKind(object, NULL,
new_map_reg, temp_reg);
return result;
- } else if (FLAG_compiled_transitions) {
+ } else {
LOperand* context = UseRegister(instr->context());
LTransitionElementsKind* result =
new(zone()) LTransitionElementsKind(object, context, NULL, NULL);
return AssignPointerMap(result);
- } else {
- LOperand* object = UseFixed(instr->object(), eax);
- LOperand* fixed_object_reg = FixedTemp(edx);
- LOperand* new_map_reg = FixedTemp(ebx);
- LTransitionElementsKind* result =
- new(zone()) LTransitionElementsKind(object,
- NULL,
- new_map_reg,
- fixed_object_reg);
- return MarkAsCall(result, instr);
}
}
@@ -2436,6 +2415,8 @@
LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
bool is_in_object = instr->access().IsInobject();
+ bool is_external_location = instr->access().IsExternalMemory() &&
+ instr->access().offset() == 0;
bool needs_write_barrier = instr->NeedsWriteBarrier();
bool needs_write_barrier_for_map = !instr->transition().is_null() &&
instr->NeedsWriteBarrierForMap();
@@ -2445,6 +2426,11 @@
obj = is_in_object
? UseRegister(instr->object())
: UseTempRegister(instr->object());
+ } else if (is_external_location) {
+ ASSERT(!is_in_object);
+ ASSERT(!needs_write_barrier);
+ ASSERT(!needs_write_barrier_for_map);
+ obj = UseRegisterOrConstant(instr->object());
} else {
obj = needs_write_barrier_for_map
? UseRegister(instr->object())
@@ -2528,12 +2514,6 @@
}
-LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) {
- LOperand* string = UseRegisterAtStart(instr->value());
- return DefineAsRegister(new(zone()) LStringLength(string));
-}
-
-
LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) {
info()->MarkAsDeferredCalling();
LOperand* context = UseAny(instr->context());
diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h
index 85c0468..6b0f9d0 100644
--- a/src/ia32/lithium-ia32.h
+++ b/src/ia32/lithium-ia32.h
@@ -80,6 +80,7 @@
V(CmpMapAndBranch) \
V(CmpT) \
V(ConstantD) \
+ V(ConstantE) \
V(ConstantI) \
V(ConstantS) \
V(ConstantT) \
@@ -119,7 +120,6 @@
V(IsUndetectableAndBranch) \
V(Label) \
V(LazyBailout) \
- V(LinkObjectInList) \
V(LoadContextSlot) \
V(LoadExternalArrayPointer) \
V(LoadFieldByIndex) \
@@ -174,7 +174,6 @@
V(StringCharCodeAt) \
V(StringCharFromCode) \
V(StringCompareAndBranch) \
- V(StringLength) \
V(SubI) \
V(TaggedToI) \
V(TaggedToINoSSE2) \
@@ -271,7 +270,7 @@
}
virtual bool HasResult() const = 0;
- virtual LOperand* result() = 0;
+ virtual LOperand* result() const = 0;
bool HasDoubleRegisterResult();
bool HasDoubleRegisterInput();
@@ -311,9 +310,9 @@
public:
// Allow 0 or 1 output operands.
STATIC_ASSERT(R == 0 || R == 1);
- virtual bool HasResult() const { return R != 0; }
+ virtual bool HasResult() const { return R != 0 && result() != NULL; }
void set_result(LOperand* operand) { results_[0] = operand; }
- LOperand* result() { return results_[0]; }
+ LOperand* result() const { return results_[0]; }
protected:
EmbeddedContainer<LOperand*, R> results_;
@@ -1208,6 +1207,17 @@
};
+class LConstantE: public LTemplateInstruction<1, 0, 0> {
+ public:
+ DECLARE_CONCRETE_INSTRUCTION(ConstantE, "constant-e")
+ DECLARE_HYDROGEN_ACCESSOR(Constant)
+
+ ExternalReference value() const {
+ return hydrogen()->ExternalReferenceValue();
+ }
+};
+
+
class LConstantT: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(ConstantT, "constant-t")
@@ -1693,25 +1703,6 @@
};
-class LLinkObjectInList: public LTemplateInstruction<0, 1, 1> {
- public:
- explicit LLinkObjectInList(LOperand* object, LOperand* temp) {
- inputs_[0] = object;
- temps_[0] = temp;
- }
-
- LOperand* object() { return inputs_[0]; }
- LOperand* temp() { return temps_[0]; }
-
- ExternalReference GetReference(Isolate* isolate);
-
- DECLARE_CONCRETE_INSTRUCTION(LinkObjectInList, "link-object-in-list")
- DECLARE_HYDROGEN_ACCESSOR(LinkObjectInList)
-
- virtual void PrintDataTo(StringStream* stream);
-};
-
-
class LLoadContextSlot: public LTemplateInstruction<1, 1, 0> {
public:
explicit LLoadContextSlot(LOperand* context) {
@@ -2419,19 +2410,6 @@
};
-class LStringLength: public LTemplateInstruction<1, 1, 0> {
- public:
- explicit LStringLength(LOperand* string) {
- inputs_[0] = string;
- }
-
- LOperand* string() { return inputs_[0]; }
-
- DECLARE_CONCRETE_INSTRUCTION(StringLength, "string-length")
- DECLARE_HYDROGEN_ACCESSOR(StringLength)
-};
-
-
class LCheckFunction: public LTemplateInstruction<0, 1, 0> {
public:
explicit LCheckFunction(LOperand* value) {
diff --git a/src/ic.cc b/src/ic.cc
index 269754b..a55160a 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -233,16 +233,22 @@
// The stub is not in the cache. We've ruled out all other kinds of failure
// except for proptotype chain changes, a deprecated map, a map that's
- // different from the one that the stub expects, or a constant global property
- // that will become mutable. Threat all those situations as prototype failures
- // (stay monomorphic if possible).
+ // different from the one that the stub expects, elements kind changes, or a
+ // constant global property that will become mutable. Threat all those
+ // situations as prototype failures (stay monomorphic if possible).
// If the IC is shared between multiple receivers (slow dictionary mode), then
// the map cannot be deprecated and the stub invalidated.
if (cache_holder == OWN_MAP) {
Map* old_map = target->FindFirstMap();
if (old_map == map) return true;
- if (old_map != NULL && old_map->is_deprecated()) return true;
+ if (old_map != NULL) {
+ if (old_map->is_deprecated()) return true;
+ if (IsMoreGeneralElementsKindTransition(old_map->elements_kind(),
+ map->elements_kind())) {
+ return true;
+ }
+ }
}
if (receiver->IsGlobalObject()) {
diff --git a/src/ic.h b/src/ic.h
index c9f521f..7820d40 100644
--- a/src/ic.h
+++ b/src/ic.h
@@ -649,8 +649,6 @@
StrictModeFlag strict_mode);
static void GenerateGeneric(MacroAssembler* masm, StrictModeFlag strict_mode);
static void GenerateNonStrictArguments(MacroAssembler* masm);
- static void GenerateTransitionElementsSmiToDouble(MacroAssembler* masm);
- static void GenerateTransitionElementsDoubleToObject(MacroAssembler* masm);
protected:
virtual Code::Kind kind() const { return Code::KEYED_STORE_IC; }
diff --git a/src/isolate.cc b/src/isolate.cc
index 4cf0252..61f1e2d 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -816,9 +816,9 @@
}
if (options & StackTrace::kIsEval) {
- int type = Smi::cast(script->compilation_type())->value();
- Handle<Object> is_eval = (type == Script::COMPILATION_TYPE_EVAL) ?
- factory()->true_value() : factory()->false_value();
+ Handle<Object> is_eval =
+ script->compilation_type() == Script::COMPILATION_TYPE_EVAL ?
+ factory()->true_value() : factory()->false_value();
CHECK_NOT_EMPTY_HANDLE(this,
JSObject::SetLocalPropertyIgnoreAttributes(
stack_frame, eval_key, is_eval, NONE));
@@ -844,6 +844,11 @@
}
+void Isolate::PrintStack() {
+ PrintStack(stdout);
+}
+
+
void Isolate::PrintStack(FILE* out) {
if (stack_trace_nesting_level_ == 0) {
stack_trace_nesting_level_++;
diff --git a/src/isolate.h b/src/isolate.h
index 2612242..c008317 100644
--- a/src/isolate.h
+++ b/src/isolate.h
@@ -737,6 +737,7 @@
void PrintStackTrace(FILE* out, char* thread_data);
void PrintStack(StringStream* accumulator);
void PrintStack(FILE* out);
+ void PrintStack();
Handle<String> StackTraceString();
NO_INLINE(void PushStackTraceAndDie(unsigned int magic,
Object* object,
diff --git a/src/liveedit.cc b/src/liveedit.cc
index bab2e10..859cf2b 100644
--- a/src/liveedit.cc
+++ b/src/liveedit.cc
@@ -1557,11 +1557,14 @@
copy->set_data(original->data());
copy->set_type(original->type());
copy->set_context_data(original->context_data());
- copy->set_compilation_type(original->compilation_type());
copy->set_eval_from_shared(original->eval_from_shared());
copy->set_eval_from_instructions_offset(
original->eval_from_instructions_offset());
+ // Copy all the flags, but clear compilation state.
+ copy->set_flags(original->flags());
+ copy->set_compilation_state(Script::COMPILATION_STATE_INITIAL);
+
return copy;
}
diff --git a/src/log-utils.cc b/src/log-utils.cc
index d8d8f59..6bba882 100644
--- a/src/log-utils.cc
+++ b/src/log-utils.cc
@@ -66,10 +66,9 @@
// --prof implies --log-code.
if (FLAG_prof) FLAG_log_code = true;
- // --prof_lazy controls --log-code, implies --noprof_auto.
+ // --prof_lazy controls --log-code.
if (FLAG_prof_lazy) {
FLAG_log_code = false;
- FLAG_prof_auto = false;
}
// If we're logging anything, we need to open the log file.
diff --git a/src/log.cc b/src/log.cc
index 520723e..b89c2bf 100644
--- a/src/log.cc
+++ b/src/log.cc
@@ -54,6 +54,11 @@
#undef DECLARE_EVENT
+#define CALL_LISTENERS(Call) \
+for (int i = 0; i < listeners_.length(); ++i) { \
+ listeners_[i]->Call; \
+}
+
#define PROFILER_LOG(Call) \
do { \
CpuProfiler* cpu_profiler = isolate_->cpu_profiler(); \
@@ -72,220 +77,193 @@
}
-class CodeEventLogger {
+class CodeEventLogger::NameBuffer {
public:
- virtual ~CodeEventLogger() { }
+ NameBuffer() { Reset(); }
- void CodeCreateEvent(Logger::LogEventsAndTags tag,
- Code* code,
- const char* comment);
- void CodeCreateEvent(Logger::LogEventsAndTags tag,
- Code* code,
- Name* name);
- void CodeCreateEvent(Logger::LogEventsAndTags tag,
- Code* code,
- int args_count);
- void CodeCreateEvent(Logger::LogEventsAndTags tag,
- Code* code,
- SharedFunctionInfo* shared,
- CompilationInfo* info,
- Name* name);
- void CodeCreateEvent(Logger::LogEventsAndTags tag,
- Code* code,
- SharedFunctionInfo* shared,
- CompilationInfo* info,
- Name* source,
- int line);
- void RegExpCodeCreateEvent(Code* code, String* source);
+ void Reset() {
+ utf8_pos_ = 0;
+ }
- protected:
- class NameBuffer {
- public:
- NameBuffer() { Reset(); }
+ void Init(Logger::LogEventsAndTags tag) {
+ Reset();
+ AppendBytes(kLogEventsNames[tag]);
+ AppendByte(':');
+ }
- void Reset() {
- utf8_pos_ = 0;
+ void AppendName(Name* name) {
+ if (name->IsString()) {
+ AppendString(String::cast(name));
+ } else {
+ Symbol* symbol = Symbol::cast(name);
+ AppendBytes("symbol(");
+ if (!symbol->name()->IsUndefined()) {
+ AppendBytes("\"");
+ AppendString(String::cast(symbol->name()));
+ AppendBytes("\" ");
+ }
+ AppendBytes("hash ");
+ AppendHex(symbol->Hash());
+ AppendByte(')');
}
+ }
- void Init(Logger::LogEventsAndTags tag) {
- Reset();
- AppendBytes(kLogEventsNames[tag]);
- AppendByte(':');
- }
-
- void AppendName(Name* name) {
- if (name->IsString()) {
- AppendString(String::cast(name));
+ void AppendString(String* str) {
+ if (str == NULL) return;
+ int uc16_length = Min(str->length(), kUtf16BufferSize);
+ String::WriteToFlat(str, utf16_buffer, 0, uc16_length);
+ int previous = unibrow::Utf16::kNoPreviousCharacter;
+ for (int i = 0; i < uc16_length && utf8_pos_ < kUtf8BufferSize; ++i) {
+ uc16 c = utf16_buffer[i];
+ if (c <= unibrow::Utf8::kMaxOneByteChar) {
+ utf8_buffer_[utf8_pos_++] = static_cast<char>(c);
} else {
- Symbol* symbol = Symbol::cast(name);
- AppendBytes("symbol(");
- if (!symbol->name()->IsUndefined()) {
- AppendBytes("\"");
- AppendString(String::cast(symbol->name()));
- AppendBytes("\" ");
- }
- AppendBytes("hash ");
- AppendHex(symbol->Hash());
- AppendByte(')');
+ int char_length = unibrow::Utf8::Length(c, previous);
+ if (utf8_pos_ + char_length > kUtf8BufferSize) break;
+ unibrow::Utf8::Encode(utf8_buffer_ + utf8_pos_, c, previous);
+ utf8_pos_ += char_length;
}
+ previous = c;
}
+ }
- void AppendString(String* str) {
- if (str == NULL) return;
- int uc16_length = Min(str->length(), kUtf16BufferSize);
- String::WriteToFlat(str, utf16_buffer, 0, uc16_length);
- int previous = unibrow::Utf16::kNoPreviousCharacter;
- for (int i = 0; i < uc16_length && utf8_pos_ < kUtf8BufferSize; ++i) {
- uc16 c = utf16_buffer[i];
- if (c <= unibrow::Utf8::kMaxOneByteChar) {
- utf8_buffer_[utf8_pos_++] = static_cast<char>(c);
- } else {
- int char_length = unibrow::Utf8::Length(c, previous);
- if (utf8_pos_ + char_length > kUtf8BufferSize) break;
- unibrow::Utf8::Encode(utf8_buffer_ + utf8_pos_, c, previous);
- utf8_pos_ += char_length;
- }
- previous = c;
- }
- }
+ void AppendBytes(const char* bytes, int size) {
+ size = Min(size, kUtf8BufferSize - utf8_pos_);
+ OS::MemCopy(utf8_buffer_ + utf8_pos_, bytes, size);
+ utf8_pos_ += size;
+ }
- void AppendBytes(const char* bytes, int size) {
- size = Min(size, kUtf8BufferSize - utf8_pos_);
- OS::MemCopy(utf8_buffer_ + utf8_pos_, bytes, size);
+ void AppendBytes(const char* bytes) {
+ AppendBytes(bytes, StrLength(bytes));
+ }
+
+ void AppendByte(char c) {
+ if (utf8_pos_ >= kUtf8BufferSize) return;
+ utf8_buffer_[utf8_pos_++] = c;
+ }
+
+ void AppendInt(int n) {
+ Vector<char> buffer(utf8_buffer_ + utf8_pos_,
+ kUtf8BufferSize - utf8_pos_);
+ int size = OS::SNPrintF(buffer, "%d", n);
+ if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
utf8_pos_ += size;
}
+ }
- void AppendBytes(const char* bytes) {
- AppendBytes(bytes, StrLength(bytes));
+ void AppendHex(uint32_t n) {
+ Vector<char> buffer(utf8_buffer_ + utf8_pos_,
+ kUtf8BufferSize - utf8_pos_);
+ int size = OS::SNPrintF(buffer, "%x", n);
+ if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
+ utf8_pos_ += size;
}
+ }
- void AppendByte(char c) {
- if (utf8_pos_ >= kUtf8BufferSize) return;
- utf8_buffer_[utf8_pos_++] = c;
- }
-
- void AppendInt(int n) {
- Vector<char> buffer(utf8_buffer_ + utf8_pos_,
- kUtf8BufferSize - utf8_pos_);
- int size = OS::SNPrintF(buffer, "%d", n);
- if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
- utf8_pos_ += size;
- }
- }
-
- void AppendHex(uint32_t n) {
- Vector<char> buffer(utf8_buffer_ + utf8_pos_,
- kUtf8BufferSize - utf8_pos_);
- int size = OS::SNPrintF(buffer, "%x", n);
- if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
- utf8_pos_ += size;
- }
- }
-
- const char* get() { return utf8_buffer_; }
- int size() const { return utf8_pos_; }
-
- private:
- static const int kUtf8BufferSize = 512;
- static const int kUtf16BufferSize = 128;
-
- int utf8_pos_;
- char utf8_buffer_[kUtf8BufferSize];
- uc16 utf16_buffer[kUtf16BufferSize];
- };
+ const char* get() { return utf8_buffer_; }
+ int size() const { return utf8_pos_; }
private:
- virtual void LogRecordedBuffer(Code* code,
- SharedFunctionInfo* shared,
- NameBuffer* name_buffer) = 0;
+ static const int kUtf8BufferSize = 512;
+ static const int kUtf16BufferSize = 128;
- NameBuffer name_buffer_;
+ int utf8_pos_;
+ char utf8_buffer_[kUtf8BufferSize];
+ uc16 utf16_buffer[kUtf16BufferSize];
};
+CodeEventLogger::CodeEventLogger() : name_buffer_(new NameBuffer) { }
+
+CodeEventLogger::~CodeEventLogger() { delete name_buffer_; }
+
+
void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
Code* code,
const char* comment) {
- name_buffer_.Init(tag);
- name_buffer_.AppendBytes(comment);
- LogRecordedBuffer(code, NULL, &name_buffer_);
+ name_buffer_->Init(tag);
+ name_buffer_->AppendBytes(comment);
+ LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
}
void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
Code* code,
Name* name) {
- name_buffer_.Init(tag);
- name_buffer_.AppendName(name);
- LogRecordedBuffer(code, NULL, &name_buffer_);
+ name_buffer_->Init(tag);
+ name_buffer_->AppendName(name);
+ LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
}
void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
- Code* code,
- SharedFunctionInfo* shared,
- CompilationInfo* info,
- Name* name) {
- name_buffer_.Init(tag);
- name_buffer_.AppendBytes(ComputeMarker(code));
- name_buffer_.AppendName(name);
- LogRecordedBuffer(code, shared, &name_buffer_);
+ Code* code,
+ SharedFunctionInfo* shared,
+ CompilationInfo* info,
+ Name* name) {
+ name_buffer_->Init(tag);
+ name_buffer_->AppendBytes(ComputeMarker(code));
+ name_buffer_->AppendName(name);
+ LogRecordedBuffer(code, shared, name_buffer_->get(), name_buffer_->size());
}
void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
- Code* code,
- SharedFunctionInfo* shared,
- CompilationInfo* info,
- Name* source, int line) {
- name_buffer_.Init(tag);
- name_buffer_.AppendBytes(ComputeMarker(code));
- name_buffer_.AppendString(shared->DebugName());
- name_buffer_.AppendByte(' ');
+ Code* code,
+ SharedFunctionInfo* shared,
+ CompilationInfo* info,
+ Name* source, int line) {
+ name_buffer_->Init(tag);
+ name_buffer_->AppendBytes(ComputeMarker(code));
+ name_buffer_->AppendString(shared->DebugName());
+ name_buffer_->AppendByte(' ');
if (source->IsString()) {
- name_buffer_.AppendString(String::cast(source));
+ name_buffer_->AppendString(String::cast(source));
} else {
- name_buffer_.AppendBytes("symbol(hash ");
- name_buffer_.AppendHex(Name::cast(source)->Hash());
- name_buffer_.AppendByte(')');
+ name_buffer_->AppendBytes("symbol(hash ");
+ name_buffer_->AppendHex(Name::cast(source)->Hash());
+ name_buffer_->AppendByte(')');
}
- name_buffer_.AppendByte(':');
- name_buffer_.AppendInt(line);
- LogRecordedBuffer(code, shared, &name_buffer_);
+ name_buffer_->AppendByte(':');
+ name_buffer_->AppendInt(line);
+ LogRecordedBuffer(code, shared, name_buffer_->get(), name_buffer_->size());
}
void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
Code* code,
int args_count) {
- name_buffer_.Init(tag);
- name_buffer_.AppendInt(args_count);
- LogRecordedBuffer(code, NULL, &name_buffer_);
+ name_buffer_->Init(tag);
+ name_buffer_->AppendInt(args_count);
+ LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
}
void CodeEventLogger::RegExpCodeCreateEvent(Code* code, String* source) {
- name_buffer_.Init(Logger::REG_EXP_TAG);
- name_buffer_.AppendString(source);
- LogRecordedBuffer(code, NULL, &name_buffer_);
+ name_buffer_->Init(Logger::REG_EXP_TAG);
+ name_buffer_->AppendString(source);
+ LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
}
// Low-level logging support.
+#define LL_LOG(Call) if (ll_logger_) ll_logger_->Call;
+
class LowLevelLogger : public CodeEventLogger {
public:
explicit LowLevelLogger(const char* file_name);
virtual ~LowLevelLogger();
- void CodeMoveEvent(Address from, Address to);
- void CodeDeleteEvent(Address from);
- void SnapshotPositionEvent(Address addr, int pos);
- void CodeMovingGCEvent();
+ virtual void CodeMoveEvent(Address from, Address to);
+ virtual void CodeDeleteEvent(Address from);
+ virtual void SnapshotPositionEvent(Address addr, int pos);
+ virtual void CodeMovingGCEvent();
private:
virtual void LogRecordedBuffer(Code* code,
SharedFunctionInfo* shared,
- NameBuffer* name_buffer);
+ const char* name,
+ int length);
// Low-level profiling event structures.
struct CodeCreateStruct {
@@ -383,14 +361,15 @@
void LowLevelLogger::LogRecordedBuffer(Code* code,
SharedFunctionInfo*,
- NameBuffer* name_buffer) {
+ const char* name,
+ int length) {
CodeCreateStruct event;
- event.name_size = name_buffer->size();
+ event.name_size = length;
event.code_address = code->instruction_start();
ASSERT(event.code_address == code->address() + Code::kHeaderSize);
event.code_size = code->instruction_size();
LogWriteStruct(event);
- LogWriteBytes(name_buffer->get(), name_buffer->size());
+ LogWriteBytes(name, length);
LogWriteBytes(
reinterpret_cast<const char*>(code->instruction_start()),
code->instruction_size());
@@ -434,143 +413,33 @@
}
-#define LL_LOG(Call) if (ll_logger_) ll_logger_->Call;
-
-
-class CodeAddressMap: public CodeEventLogger {
- public:
- CodeAddressMap() { }
- virtual ~CodeAddressMap() { }
-
- void CodeMoveEvent(Address from, Address to) {
- address_to_name_map_.Move(from, to);
- }
-
- void CodeDeleteEvent(Address from) {
- address_to_name_map_.Remove(from);
- }
-
- const char* Lookup(Address address) {
- return address_to_name_map_.Lookup(address);
- }
-
- private:
- class NameMap {
- public:
- NameMap() : impl_(&PointerEquals) {}
-
- ~NameMap() {
- for (HashMap::Entry* p = impl_.Start(); p != NULL; p = impl_.Next(p)) {
- DeleteArray(static_cast<const char*>(p->value));
- }
- }
-
- void Insert(Address code_address, const char* name, int name_size) {
- HashMap::Entry* entry = FindOrCreateEntry(code_address);
- if (entry->value == NULL) {
- entry->value = CopyName(name, name_size);
- }
- }
-
- const char* Lookup(Address code_address) {
- HashMap::Entry* entry = FindEntry(code_address);
- return (entry != NULL) ? static_cast<const char*>(entry->value) : NULL;
- }
-
- void Remove(Address code_address) {
- HashMap::Entry* entry = FindEntry(code_address);
- if (entry != NULL) {
- DeleteArray(static_cast<char*>(entry->value));
- RemoveEntry(entry);
- }
- }
-
- void Move(Address from, Address to) {
- if (from == to) return;
- HashMap::Entry* from_entry = FindEntry(from);
- ASSERT(from_entry != NULL);
- void* value = from_entry->value;
- RemoveEntry(from_entry);
- HashMap::Entry* to_entry = FindOrCreateEntry(to);
- ASSERT(to_entry->value == NULL);
- to_entry->value = value;
- }
-
- private:
- static bool PointerEquals(void* lhs, void* rhs) {
- return lhs == rhs;
- }
-
- static char* CopyName(const char* name, int name_size) {
- char* result = NewArray<char>(name_size + 1);
- for (int i = 0; i < name_size; ++i) {
- char c = name[i];
- if (c == '\0') c = ' ';
- result[i] = c;
- }
- result[name_size] = '\0';
- return result;
- }
-
- HashMap::Entry* FindOrCreateEntry(Address code_address) {
- return impl_.Lookup(code_address, ComputePointerHash(code_address), true);
- }
-
- HashMap::Entry* FindEntry(Address code_address) {
- return impl_.Lookup(code_address,
- ComputePointerHash(code_address),
- false);
- }
-
- void RemoveEntry(HashMap::Entry* entry) {
- impl_.Remove(entry->key, entry->hash);
- }
-
- HashMap impl_;
-
- DISALLOW_COPY_AND_ASSIGN(NameMap);
- };
-
- virtual void LogRecordedBuffer(Code* code,
- SharedFunctionInfo*,
- NameBuffer* name_buffer) {
- address_to_name_map_.Insert(code->address(),
- name_buffer->get(),
- name_buffer->size());
- }
-
- NameMap address_to_name_map_;
-};
-
-
-#define CODE_ADDRESS_MAP_LOG(Call)\
- if (Serializer::enabled()) code_address_map_->Call;
+#define JIT_LOG(Call) if (jit_logger_) jit_logger_->Call;
class JitLogger : public CodeEventLogger {
public:
explicit JitLogger(JitCodeEventHandler code_event_handler);
- void CodeMoveEvent(Address from, Address to);
- void CodeDeleteEvent(Address from);
- void AddCodeLinePosInfoEvent(
+ virtual void CodeMoveEvent(Address from, Address to);
+ virtual void CodeDeleteEvent(Address from);
+ virtual void AddCodeLinePosInfoEvent(
void* jit_handler_data,
int pc_offset,
int position,
JitCodeEvent::PositionType position_type);
+
void* StartCodePosInfoEvent();
void EndCodePosInfoEvent(Code* code, void* jit_handler_data);
private:
virtual void LogRecordedBuffer(Code* code,
SharedFunctionInfo* shared,
- CodeEventLogger::NameBuffer* name_buffer);
+ const char* name,
+ int length);
JitCodeEventHandler code_event_handler_;
};
-#define JIT_LOG(Call) if (jit_logger_) jit_logger_->Call;
-
JitLogger::JitLogger(JitCodeEventHandler code_event_handler)
: code_event_handler_(code_event_handler) {
@@ -579,7 +448,8 @@
void JitLogger::LogRecordedBuffer(Code* code,
SharedFunctionInfo* shared,
- CodeEventLogger::NameBuffer* name_buffer) {
+ const char* name,
+ int length) {
JitCodeEvent event;
memset(&event, 0, sizeof(event));
event.type = JitCodeEvent::CODE_ADDED;
@@ -590,8 +460,8 @@
script_handle = Handle<Script>(Script::cast(shared->script()));
}
event.script = ToApiHandle<v8::Script>(script_handle);
- event.name.str = name_buffer->get();
- event.name.len = name_buffer->size();
+ event.name.str = name;
+ event.name.len = length;
code_event_handler_(&event);
}
@@ -844,23 +714,34 @@
log_(new Log(this)),
ll_logger_(NULL),
jit_logger_(NULL),
- code_address_map_(new CodeAddressMap),
+ listeners_(5),
is_initialized_(false),
- last_address_(NULL),
- prev_sp_(NULL),
- prev_function_(NULL),
- prev_to_(NULL),
- prev_code_(NULL),
epoch_(0) {
}
Logger::~Logger() {
- delete code_address_map_;
delete log_;
}
+void Logger::addCodeEventListener(CodeEventListener* listener) {
+ ASSERT(!hasCodeEventListener(listener));
+ listeners_.Add(listener);
+}
+
+
+void Logger::removeCodeEventListener(CodeEventListener* listener) {
+ ASSERT(hasCodeEventListener(listener));
+ listeners_.RemoveElement(listener);
+}
+
+
+bool Logger::hasCodeEventListener(CodeEventListener* listener) {
+ return listeners_.Contains(listener);
+}
+
+
void Logger::ProfilerBeginEvent() {
if (!log_->IsEnabled()) return;
Log::MessageBuilder msg(log_);
@@ -1279,9 +1160,7 @@
PROFILER_LOG(CodeCreateEvent(tag, code, comment));
if (!is_logging_code_events()) return;
- JIT_LOG(CodeCreateEvent(tag, code, comment));
- LL_LOG(CodeCreateEvent(tag, code, comment));
- CODE_ADDRESS_MAP_LOG(CodeCreateEvent(tag, code, comment));
+ CALL_LISTENERS(CodeCreateEvent(tag, code, comment));
if (!FLAG_log_code || !log_->IsEnabled()) return;
Log::MessageBuilder msg(log_);
@@ -1298,9 +1177,7 @@
PROFILER_LOG(CodeCreateEvent(tag, code, name));
if (!is_logging_code_events()) return;
- JIT_LOG(CodeCreateEvent(tag, code, name));
- LL_LOG(CodeCreateEvent(tag, code, name));
- CODE_ADDRESS_MAP_LOG(CodeCreateEvent(tag, code, name));
+ CALL_LISTENERS(CodeCreateEvent(tag, code, name));
if (!FLAG_log_code || !log_->IsEnabled()) return;
Log::MessageBuilder msg(log_);
@@ -1325,9 +1202,7 @@
PROFILER_LOG(CodeCreateEvent(tag, code, shared, info, name));
if (!is_logging_code_events()) return;
- JIT_LOG(CodeCreateEvent(tag, code, shared, info, name));
- LL_LOG(CodeCreateEvent(tag, code, shared, info, name));
- CODE_ADDRESS_MAP_LOG(CodeCreateEvent(tag, code, shared, info, name));
+ CALL_LISTENERS(CodeCreateEvent(tag, code, shared, info, name));
if (!FLAG_log_code || !log_->IsEnabled()) return;
if (code == isolate_->builtins()->builtin(
@@ -1362,9 +1237,7 @@
PROFILER_LOG(CodeCreateEvent(tag, code, shared, info, source, line));
if (!is_logging_code_events()) return;
- JIT_LOG(CodeCreateEvent(tag, code, shared, info, source, line));
- LL_LOG(CodeCreateEvent(tag, code, shared, info, source, line));
- CODE_ADDRESS_MAP_LOG(CodeCreateEvent(tag, code, shared, info, source, line));
+ CALL_LISTENERS(CodeCreateEvent(tag, code, shared, info, source, line));
if (!FLAG_log_code || !log_->IsEnabled()) return;
Log::MessageBuilder msg(log_);
@@ -1393,9 +1266,7 @@
PROFILER_LOG(CodeCreateEvent(tag, code, args_count));
if (!is_logging_code_events()) return;
- JIT_LOG(CodeCreateEvent(tag, code, args_count));
- LL_LOG(CodeCreateEvent(tag, code, args_count));
- CODE_ADDRESS_MAP_LOG(CodeCreateEvent(tag, code, args_count));
+ CALL_LISTENERS(CodeCreateEvent(tag, code, args_count));
if (!FLAG_log_code || !log_->IsEnabled()) return;
Log::MessageBuilder msg(log_);
@@ -1411,7 +1282,7 @@
if (!is_logging_code_events()) return;
if (!log_->IsEnabled() || !FLAG_ll_prof) return;
- LL_LOG(CodeMovingGCEvent());
+ CALL_LISTENERS(CodeMovingGCEvent());
OS::SignalCodeMovingGC();
}
@@ -1420,9 +1291,7 @@
PROFILER_LOG(RegExpCodeCreateEvent(code, source));
if (!is_logging_code_events()) return;
- JIT_LOG(RegExpCodeCreateEvent(code, source));
- LL_LOG(RegExpCodeCreateEvent(code, source));
- CODE_ADDRESS_MAP_LOG(RegExpCodeCreateEvent(code, source));
+ CALL_LISTENERS(RegExpCodeCreateEvent(code, source));
if (!FLAG_log_code || !log_->IsEnabled()) return;
Log::MessageBuilder msg(log_);
@@ -1439,9 +1308,7 @@
PROFILER_LOG(CodeMoveEvent(from, to));
if (!is_logging_code_events()) return;
- JIT_LOG(CodeMoveEvent(from, to));
- LL_LOG(CodeMoveEvent(from, to));
- CODE_ADDRESS_MAP_LOG(CodeMoveEvent(from, to));
+ CALL_LISTENERS(CodeMoveEvent(from, to));
MoveEventInternal(CODE_MOVE_EVENT, from, to);
}
@@ -1450,9 +1317,7 @@
PROFILER_LOG(CodeDeleteEvent(from));
if (!is_logging_code_events()) return;
- JIT_LOG(CodeDeleteEvent(from));
- LL_LOG(CodeDeleteEvent(from));
- CODE_ADDRESS_MAP_LOG(CodeDeleteEvent(from));
+ CALL_LISTENERS(CodeDeleteEvent(from));
if (!FLAG_log_code || !log_->IsEnabled()) return;
Log::MessageBuilder msg(log_);
@@ -1496,18 +1361,19 @@
}
+void Logger::CodeNameEvent(Address addr, int pos, const char* code_name) {
+ if (code_name == NULL) return; // Not a code object.
+ Log::MessageBuilder msg(log_);
+ msg.Append("%s,%d,", kLogEventsNames[SNAPSHOT_CODE_NAME_EVENT], pos);
+ msg.AppendDoubleQuotedString(code_name);
+ msg.Append("\n");
+ msg.WriteToLogFile();
+}
+
+
void Logger::SnapshotPositionEvent(Address addr, int pos) {
if (!log_->IsEnabled()) return;
LL_LOG(SnapshotPositionEvent(addr, pos));
- if (Serializer::enabled()) {
- const char* code_name = code_address_map_->Lookup(addr);
- if (code_name == NULL) return; // Not a code object.
- Log::MessageBuilder msg(log_);
- msg.Append("%s,%d,", kLogEventsNames[SNAPSHOT_CODE_NAME_EVENT], pos);
- msg.AppendDoubleQuotedString(code_name);
- msg.Append("\n");
- msg.WriteToLogFile();
- }
if (!FLAG_log_snapshot_positions) return;
Log::MessageBuilder msg(log_);
msg.Append("%s,", kLogEventsNames[SNAPSHOT_POSITION_EVENT]);
@@ -1998,10 +1864,9 @@
FLAG_log_snapshot_positions = true;
}
- // --prof_lazy controls --log-code, implies --noprof_auto.
+ // --prof_lazy controls --log-code.
if (FLAG_prof_lazy) {
FLAG_log_code = false;
- FLAG_prof_auto = false;
}
SmartArrayPointer<const char> log_file_name =
@@ -2010,6 +1875,7 @@
if (FLAG_ll_prof) {
ll_logger_ = new LowLevelLogger(*log_file_name);
+ addCodeEventListener(ll_logger_);
}
ticker_ = new Ticker(isolate, kSamplingIntervalMs);
@@ -2020,12 +1886,10 @@
if (FLAG_prof) {
profiler_ = new Profiler(isolate);
- if (!FLAG_prof_auto) {
+ if (FLAG_prof_lazy) {
profiler_->pause();
} else {
logging_nesting_ = 1;
- }
- if (!FLAG_prof_lazy) {
profiler_->Engage();
}
}
@@ -2039,18 +1903,19 @@
void Logger::SetCodeEventHandler(uint32_t options,
JitCodeEventHandler event_handler) {
if (jit_logger_) {
+ removeCodeEventListener(jit_logger_);
delete jit_logger_;
jit_logger_ = NULL;
}
if (event_handler) {
jit_logger_ = new JitLogger(event_handler);
- }
-
- if (jit_logger_ != NULL && (options & kJitCodeEventEnumExisting)) {
- HandleScope scope(isolate_);
- LogCodeObjects();
- LogCompiledFunctions();
+ addCodeEventListener(jit_logger_);
+ if (options & kJitCodeEventEnumExisting) {
+ HandleScope scope(isolate_);
+ LogCodeObjects();
+ LogCompiledFunctions();
+ }
}
}
@@ -2075,11 +1940,13 @@
ticker_ = NULL;
if (ll_logger_) {
+ removeCodeEventListener(ll_logger_);
delete ll_logger_;
ll_logger_ = NULL;
}
if (jit_logger_) {
+ removeCodeEventListener(jit_logger_);
delete jit_logger_;
jit_logger_ = NULL;
}
diff --git a/src/log.h b/src/log.h
index 194ad9d..24d83ef 100644
--- a/src/log.h
+++ b/src/log.h
@@ -70,7 +70,7 @@
// tick profiler requires code events, so --prof implies --log-code.
// Forward declarations.
-class CodeAddressMap;
+class CodeEventListener;
class CompilationInfo;
class CpuProfiler;
class Isolate;
@@ -155,7 +155,6 @@
class LowLevelLogger;
class Sampler;
-
class Logger {
public:
#define DECLARE_ENUM(enum_item, ignore) enum_item,
@@ -226,6 +225,11 @@
// ==== Events logged by --log-code. ====
+ void addCodeEventListener(CodeEventListener* listener);
+ void removeCodeEventListener(CodeEventListener* listener);
+ bool hasCodeEventListener(CodeEventListener* listener);
+
+
// Emits a code event for a callback function.
void CallbackEvent(Name* name, Address entry_point);
void GetterCallbackEvent(Name* name, Address entry_point);
@@ -269,6 +273,7 @@
void SharedFunctionInfoMoveEvent(Address from, Address to);
+ void CodeNameEvent(Address addr, int pos, const char* code_name);
void SnapshotPositionEvent(Address addr, int pos);
// ==== Events logged by --log-gc. ====
@@ -439,29 +444,98 @@
Log* log_;
LowLevelLogger* ll_logger_;
JitLogger* jit_logger_;
- CodeAddressMap* code_address_map_;
+ List<CodeEventListener*> listeners_;
// Guards against multiple calls to TearDown() that can happen in some tests.
// 'true' between SetUp() and TearDown().
bool is_initialized_;
- // Support for 'incremental addresses' in compressed logs:
- // LogMessageBuilder::AppendAddress(Address addr)
- Address last_address_;
- // Logger::TickEvent(...)
- Address prev_sp_;
- Address prev_function_;
- // Logger::MoveEventInternal(...)
- Address prev_to_;
- // Logger::FunctionCreateEvent(...)
- Address prev_code_;
-
int64_t epoch_;
friend class CpuProfiler;
};
+class CodeEventListener {
+ public:
+ virtual ~CodeEventListener() {}
+
+ virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
+ Code* code,
+ const char* comment) = 0;
+ virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
+ Code* code,
+ Name* name) = 0;
+ virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
+ Code* code,
+ SharedFunctionInfo* shared,
+ CompilationInfo* info,
+ Name* name) = 0;
+ virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
+ Code* code,
+ SharedFunctionInfo* shared,
+ CompilationInfo* info,
+ Name* source,
+ int line) = 0;
+ virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
+ Code* code,
+ int args_count) = 0;
+ virtual void CallbackEvent(Name* name, Address entry_point) = 0;
+ virtual void GetterCallbackEvent(Name* name, Address entry_point) = 0;
+ virtual void SetterCallbackEvent(Name* name, Address entry_point) = 0;
+ virtual void RegExpCodeCreateEvent(Code* code, String* source) = 0;
+ virtual void CodeMoveEvent(Address from, Address to) = 0;
+ virtual void CodeDeleteEvent(Address from) = 0;
+ virtual void SharedFunctionInfoMoveEvent(Address from, Address to) = 0;
+ virtual void CodeMovingGCEvent() = 0;
+};
+
+
+class CodeEventLogger : public CodeEventListener {
+ public:
+ CodeEventLogger();
+ virtual ~CodeEventLogger();
+
+ virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
+ Code* code,
+ const char* comment);
+ virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
+ Code* code,
+ Name* name);
+ virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
+ Code* code,
+ int args_count);
+ virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
+ Code* code,
+ SharedFunctionInfo* shared,
+ CompilationInfo* info,
+ Name* name);
+ virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
+ Code* code,
+ SharedFunctionInfo* shared,
+ CompilationInfo* info,
+ Name* source,
+ int line);
+ virtual void RegExpCodeCreateEvent(Code* code, String* source);
+
+ virtual void CallbackEvent(Name* name, Address entry_point) { }
+ virtual void GetterCallbackEvent(Name* name, Address entry_point) { }
+ virtual void SetterCallbackEvent(Name* name, Address entry_point) { }
+ virtual void SharedFunctionInfoMoveEvent(Address from, Address to) { }
+ virtual void CodeMovingGCEvent() { }
+
+ private:
+ class NameBuffer;
+
+ virtual void LogRecordedBuffer(Code* code,
+ SharedFunctionInfo* shared,
+ const char* name,
+ int length) = 0;
+
+ NameBuffer* name_buffer_;
+};
+
+
} } // namespace v8::internal
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index 59492e1..91da8a0 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -337,6 +337,11 @@
#endif
+void MarkCompactCollector::TearDown() {
+ AbortCompaction();
+}
+
+
void MarkCompactCollector::AddEvacuationCandidate(Page* p) {
p->MarkEvacuationCandidate();
evacuation_candidates_.Add(p);
@@ -2743,8 +2748,7 @@
if (dest == OLD_POINTER_SPACE) {
// TODO(hpayer): Replace this check with an assert.
HeapObject* heap_object = HeapObject::FromAddress(src);
- CHECK(heap_object->IsExternalString() ||
- heap_->TargetSpace(heap_object) == heap_->old_pointer_space());
+ CHECK(heap_->TargetSpace(heap_object) == heap_->old_pointer_space());
Address src_slot = src;
Address dst_slot = dst;
ASSERT(IsAligned(size, kPointerSize));
diff --git a/src/mark-compact.h b/src/mark-compact.h
index 3c4dfb6..16e49e1 100644
--- a/src/mark-compact.h
+++ b/src/mark-compact.h
@@ -571,6 +571,8 @@
static void Initialize();
+ void TearDown();
+
void CollectEvacuationCandidates(PagedSpace* space);
void AddEvacuationCandidate(Page* p);
diff --git a/src/messages.js b/src/messages.js
index 8b647dd..b586d24 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -126,6 +126,7 @@
stack_overflow: ["Maximum call stack size exceeded"],
invalid_time_value: ["Invalid time value"],
+ invalid_count_value: ["Invalid count value"],
// SyntaxError
paren_in_arg_string: ["Function arg string contains parenthesis"],
not_isvar: ["builtin %IS_VAR: not a variable"],
@@ -1078,7 +1079,26 @@
}
-function FormatStackTrace(error_string, frames) {
+// Flag to prevent recursive call of Error.prepareStackTrace.
+var formatting_custom_stack_trace = false;
+
+
+function FormatStackTrace(obj, error_string, frames) {
+ if (IS_FUNCTION($Error.prepareStackTrace) && !formatting_custom_stack_trace) {
+ var array = [];
+ %MoveArrayContents(frames, array);
+ formatting_custom_stack_trace = true;
+ var stack_trace = void 0;
+ try {
+ stack_trace = $Error.prepareStackTrace(obj, array);
+ } catch (e) {
+ throw e; // The custom formatting function threw. Rethrow.
+ } finally {
+ formatting_custom_stack_trace = false;
+ }
+ return stack_trace;
+ }
+
var lines = new InternalArray();
lines.push(error_string);
for (var i = 0; i < frames.length; i++) {
@@ -1115,10 +1135,6 @@
}
-// Flag to prevent recursive call of Error.prepareStackTrace.
-var formatting_custom_stack_trace = false;
-
-
function captureStackTrace(obj, cons_opt) {
var stackTraceLimit = $Error.stackTraceLimit;
if (!stackTraceLimit || !IS_NUMBER(stackTraceLimit)) return;
@@ -1129,21 +1145,6 @@
cons_opt ? cons_opt : captureStackTrace,
stackTraceLimit);
- // Don't be lazy if the error stack formatting is custom (observable).
- if (IS_FUNCTION($Error.prepareStackTrace) && !formatting_custom_stack_trace) {
- var array = [];
- %MoveArrayContents(GetStackFrames(stack), array);
- formatting_custom_stack_trace = true;
- try {
- obj.stack = $Error.prepareStackTrace(obj, array);
- } catch (e) {
- throw e; // The custom formatting function threw. Rethrow.
- } finally {
- formatting_custom_stack_trace = false;
- }
- return;
- }
-
var error_string = FormatErrorString(obj);
// The holder of this getter ('obj') may not be the receiver ('this').
// When this getter is called the first time, we use the context values to
@@ -1151,7 +1152,7 @@
// property (on the holder).
var getter = function() {
// Stack is still a raw array awaiting to be formatted.
- var result = FormatStackTrace(error_string, GetStackFrames(stack));
+ var result = FormatStackTrace(obj, error_string, GetStackFrames(stack));
// Turn this accessor into a data property.
%DefineOrRedefineDataProperty(obj, 'stack', result, NONE);
// Release context values.
@@ -1321,7 +1322,7 @@
// We may not have captured any stack trace.
if (IS_UNDEFINED(stack)) return stack;
- var result = FormatStackTrace(error_string, GetStackFrames(stack));
+ var result = FormatStackTrace(holder, error_string, GetStackFrames(stack));
// Replace this accessor with a data property.
%DefineOrRedefineDataProperty(holder, 'stack', result, NONE);
return result;
diff --git a/src/mips/frames-mips.h b/src/mips/frames-mips.h
index f6f20cd..437bf3a 100644
--- a/src/mips/frames-mips.h
+++ b/src/mips/frames-mips.h
@@ -230,6 +230,11 @@
}
+inline void StackHandler::SetFp(Address slot, Address fp) {
+ Memory::Address_at(slot) = fp;
+}
+
+
} } // namespace v8::internal
#endif
diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc
index 9c610c3..1084af0 100644
--- a/src/mips/full-codegen-mips.cc
+++ b/src/mips/full-codegen-mips.cc
@@ -2234,7 +2234,7 @@
Handle<Map> map(isolate()->native_context()->generator_result_map());
- __ Allocate(map->instance_size(), a0, a2, a3, &gc_required, TAG_OBJECT);
+ __ Allocate(map->instance_size(), v0, a2, a3, &gc_required, TAG_OBJECT);
__ jmp(&allocated);
__ bind(&gc_required);
@@ -2249,19 +2249,18 @@
__ li(a3, Operand(isolate()->factory()->ToBoolean(done)));
__ li(t0, Operand(isolate()->factory()->empty_fixed_array()));
ASSERT_EQ(map->instance_size(), 5 * kPointerSize);
- __ sw(a1, FieldMemOperand(a0, HeapObject::kMapOffset));
- __ sw(t0, FieldMemOperand(a0, JSObject::kPropertiesOffset));
- __ sw(t0, FieldMemOperand(a0, JSObject::kElementsOffset));
+ __ sw(a1, FieldMemOperand(v0, HeapObject::kMapOffset));
+ __ sw(t0, FieldMemOperand(v0, JSObject::kPropertiesOffset));
+ __ sw(t0, FieldMemOperand(v0, JSObject::kElementsOffset));
__ sw(a2,
- FieldMemOperand(a0, JSGeneratorObject::kResultValuePropertyOffset));
+ FieldMemOperand(v0, JSGeneratorObject::kResultValuePropertyOffset));
__ sw(a3,
- FieldMemOperand(a0, JSGeneratorObject::kResultDonePropertyOffset));
+ FieldMemOperand(v0, JSGeneratorObject::kResultDonePropertyOffset));
// Only the value field needs a write barrier, as the other values are in the
// root set.
- __ RecordWriteField(a0, JSGeneratorObject::kResultValuePropertyOffset,
+ __ RecordWriteField(v0, JSGeneratorObject::kResultValuePropertyOffset,
a2, a3, kRAHasBeenSaved, kDontSaveFPRegs);
- __ mov(result_register(), a0);
}
diff --git a/src/mips/ic-mips.cc b/src/mips/ic-mips.cc
index ed67e82..eb730bb 100644
--- a/src/mips/ic-mips.cc
+++ b/src/mips/ic-mips.cc
@@ -1486,51 +1486,6 @@
}
-void KeyedStoreIC::GenerateTransitionElementsSmiToDouble(MacroAssembler* masm) {
- // ---------- S t a t e --------------
- // -- a2 : receiver
- // -- a3 : target map
- // -- ra : return address
- // -----------------------------------
- // Must return the modified receiver in v0.
- if (!FLAG_trace_elements_transitions) {
- Label fail;
- AllocationSiteMode mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS,
- FAST_DOUBLE_ELEMENTS);
- ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, &fail);
- __ Ret(USE_DELAY_SLOT);
- __ mov(v0, a2);
- __ bind(&fail);
- }
-
- __ push(a2);
- __ TailCallRuntime(Runtime::kTransitionElementsSmiToDouble, 1, 1);
-}
-
-
-void KeyedStoreIC::GenerateTransitionElementsDoubleToObject(
- MacroAssembler* masm) {
- // ---------- S t a t e --------------
- // -- a2 : receiver
- // -- a3 : target map
- // -- ra : return address
- // -----------------------------------
- // Must return the modified receiver in v0.
- if (!FLAG_trace_elements_transitions) {
- Label fail;
- AllocationSiteMode mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS,
- FAST_ELEMENTS);
- ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, &fail);
- __ Ret(USE_DELAY_SLOT);
- __ mov(v0, a2);
- __ bind(&fail);
- }
-
- __ push(a2);
- __ TailCallRuntime(Runtime::kTransitionElementsDoubleToObject, 1, 1);
-}
-
-
void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
StrictModeFlag strict_mode) {
// ----------- S t a t e -------------
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc
index f3851d4..be5809d 100644
--- a/src/mips/lithium-codegen-mips.cc
+++ b/src/mips/lithium-codegen-mips.cc
@@ -1524,6 +1524,7 @@
LOperand* right_op = instr->right();
Register left = ToRegister(instr->left());
Register result = ToRegister(instr->result());
+ Register scratch = scratch0();
if (right_op->IsRegister()) {
// No need to mask the right operand on MIPS, it is built into the variable
@@ -1580,7 +1581,18 @@
break;
case Token::SHL:
if (shift_count != 0) {
- __ sll(result, left, shift_count);
+ if (instr->hydrogen_value()->representation().IsSmi() &&
+ instr->can_deopt()) {
+ if (shift_count != 1) {
+ __ sll(result, left, shift_count - 1);
+ __ SmiTagCheckOverflow(result, result, scratch);
+ } else {
+ __ SmiTagCheckOverflow(result, left, scratch);
+ }
+ DeoptimizeIf(lt, instr->environment(), scratch, Operand(zero_reg));
+ } else {
+ __ sll(result, left, shift_count);
+ }
} else {
__ Move(result, left);
}
@@ -1650,6 +1662,11 @@
}
+void LCodeGen::DoConstantE(LConstantE* instr) {
+ __ li(ToRegister(instr->result()), Operand(instr->value()));
+}
+
+
void LCodeGen::DoConstantT(LConstantT* instr) {
Handle<Object> value = instr->value();
AllowDeferredHandleDereference smi_check;
@@ -2795,19 +2812,6 @@
}
-void LCodeGen::DoLinkObjectInList(LLinkObjectInList* instr) {
- Register object = ToRegister(instr->object());
- ExternalReference sites_list_address = instr->GetReference(isolate());
-
- __ li(at, Operand(sites_list_address));
- __ lw(at, MemOperand(at));
- __ sw(at, FieldMemOperand(object,
- instr->hydrogen()->store_field().offset()));
- __ li(at, Operand(sites_list_address));
- __ sw(object, MemOperand(at));
-}
-
-
void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
Register context = ToRegister(instr->context());
Register result = ToRegister(instr->result());
@@ -2870,6 +2874,13 @@
HObjectAccess access = instr->hydrogen()->access();
int offset = access.offset();
Register object = ToRegister(instr->object());
+
+ if (access.IsExternalMemory()) {
+ Register result = ToRegister(instr->result());
+ __ lw(result, MemOperand(object, offset));
+ return;
+ }
+
if (instr->hydrogen()->representation().IsDouble()) {
DoubleRegister result = ToDoubleRegister(instr->result());
__ ldc1(result, FieldMemOperand(object, offset));
@@ -4107,6 +4118,12 @@
HObjectAccess access = instr->hydrogen()->access();
int offset = access.offset();
+ if (access.IsExternalMemory()) {
+ Register value = ToRegister(instr->value());
+ __ sw(value, MemOperand(object, offset));
+ return;
+ }
+
Handle<Map> transition = instr->transition();
if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
@@ -4447,7 +4464,7 @@
// Write barrier.
__ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg,
scratch, GetRAState(), kDontSaveFPRegs);
- } else if (FLAG_compiled_transitions) {
+ } else {
PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
__ mov(a0, object_reg);
__ li(a1, Operand(to_map));
@@ -4455,28 +4472,6 @@
__ CallStub(&stub);
RecordSafepointWithRegisters(
instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
- } else if (IsFastSmiElementsKind(from_kind) &&
- IsFastDoubleElementsKind(to_kind)) {
- Register fixed_object_reg = ToRegister(instr->temp());
- ASSERT(fixed_object_reg.is(a2));
- Register new_map_reg = ToRegister(instr->new_map_temp());
- ASSERT(new_map_reg.is(a3));
- __ li(new_map_reg, Operand(to_map));
- __ mov(fixed_object_reg, object_reg);
- CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(),
- RelocInfo::CODE_TARGET, instr);
- } else if (IsFastDoubleElementsKind(from_kind) &&
- IsFastObjectElementsKind(to_kind)) {
- Register fixed_object_reg = ToRegister(instr->temp());
- ASSERT(fixed_object_reg.is(a2));
- Register new_map_reg = ToRegister(instr->new_map_temp());
- ASSERT(new_map_reg.is(a3));
- __ li(new_map_reg, Operand(to_map));
- __ mov(fixed_object_reg, object_reg);
- CallCode(isolate()->builtins()->TransitionElementsDoubleToObject(),
- RelocInfo::CODE_TARGET, instr);
- } else {
- UNREACHABLE();
}
__ bind(¬_applicable);
}
@@ -4601,13 +4596,6 @@
}
-void LCodeGen::DoStringLength(LStringLength* instr) {
- Register string = ToRegister(instr->string());
- Register result = ToRegister(instr->result());
- __ lw(result, FieldMemOperand(string, String::kLengthOffset));
-}
-
-
void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
LOperand* input = instr->value();
ASSERT(input->IsRegister() || input->IsStackSlot());
@@ -5326,10 +5314,12 @@
if (instr->hydrogen()->MustAllocateDoubleAligned()) {
flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
}
- if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
- ASSERT(!instr->hydrogen()->CanAllocateInOldDataSpace());
+ if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
+ ASSERT(!instr->hydrogen()->IsOldDataSpaceAllocation());
+ ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
- } else if (instr->hydrogen()->CanAllocateInOldDataSpace()) {
+ } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
+ ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_DATA_SPACE);
}
if (instr->size()->IsConstantOperand()) {
@@ -5387,10 +5377,12 @@
__ Push(Smi::FromInt(size));
}
- if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
- ASSERT(!instr->hydrogen()->CanAllocateInOldDataSpace());
+ if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
+ ASSERT(!instr->hydrogen()->IsOldDataSpaceAllocation());
+ ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
CallRuntimeFromDeferred(Runtime::kAllocateInOldPointerSpace, 1, instr);
- } else if (instr->hydrogen()->CanAllocateInOldDataSpace()) {
+ } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
+ ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
CallRuntimeFromDeferred(Runtime::kAllocateInOldDataSpace, 1, instr);
} else {
CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr);
diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc
index b03cea4..a5371f7 100644
--- a/src/mips/lithium-mips.cc
+++ b/src/mips/lithium-mips.cc
@@ -277,24 +277,6 @@
}
-ExternalReference LLinkObjectInList::GetReference(Isolate* isolate) {
- switch (hydrogen()->known_list()) {
- case HLinkObjectInList::ALLOCATION_SITE_LIST:
- return ExternalReference::allocation_sites_list_address(isolate);
- }
-
- UNREACHABLE();
- // Return a dummy value
- return ExternalReference::isolate_address(isolate);
-}
-
-
-void LLinkObjectInList::PrintDataTo(StringStream* stream) {
- object()->PrintTo(stream);
- stream->Add(" offset %d", hydrogen()->store_field().offset());
-}
-
-
void LLoadContextSlot::PrintDataTo(StringStream* stream) {
context()->PrintTo(stream);
stream->Add("[%d]", slot_index());
@@ -713,9 +695,9 @@
LInstruction* LChunkBuilder::DoShift(Token::Value op,
HBitwiseBinaryOperation* instr) {
- if (instr->representation().IsSmiOrTagged()) {
- ASSERT(instr->left()->representation().IsSmiOrTagged());
- ASSERT(instr->right()->representation().IsSmiOrTagged());
+ if (instr->representation().IsTagged()) {
+ ASSERT(instr->left()->representation().IsTagged());
+ ASSERT(instr->right()->representation().IsTagged());
LOperand* left = UseFixed(instr->left(), a1);
LOperand* right = UseFixed(instr->right(), a0);
@@ -723,25 +705,35 @@
return MarkAsCall(DefineFixed(result, v0), instr);
}
- ASSERT(instr->representation().IsInteger32());
- ASSERT(instr->left()->representation().IsInteger32());
- ASSERT(instr->right()->representation().IsInteger32());
+ ASSERT(instr->representation().IsSmiOrInteger32());
+ ASSERT(instr->left()->representation().Equals(instr->representation()));
+ ASSERT(instr->right()->representation().Equals(instr->representation()));
LOperand* left = UseRegisterAtStart(instr->left());
HValue* right_value = instr->right();
LOperand* right = NULL;
int constant_value = 0;
+ bool does_deopt = false;
if (right_value->IsConstant()) {
HConstant* constant = HConstant::cast(right_value);
right = chunk_->DefineConstantOperand(constant);
constant_value = constant->Integer32Value() & 0x1f;
+ // Left shifts can deoptimize if we shift by > 0 and the result cannot be
+ // truncated to smi.
+ if (instr->representation().IsSmi() && constant_value > 0) {
+ for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) {
+ if (!it.value()->CheckFlag(HValue::kTruncatingToSmi)) {
+ does_deopt = true;
+ break;
+ }
+ }
+ }
} else {
right = UseRegisterAtStart(right_value);
}
- // Shift operations can only deoptimize if we do a logical shift
+ // Shift operations can deoptimize if we do a logical shift
// by 0 and the result cannot be truncated to int32.
- bool does_deopt = false;
if (op == Token::SHR && constant_value == 0) {
if (FLAG_opt_safe_uint32_operations) {
does_deopt = !instr->CheckFlag(HInstruction::kUint32);
@@ -2007,6 +1999,8 @@
return DefineAsRegister(new(zone()) LConstantI);
} else if (r.IsDouble()) {
return DefineAsRegister(new(zone()) LConstantD);
+ } else if (r.IsExternal()) {
+ return DefineAsRegister(new(zone()) LConstantE);
} else if (r.IsTagged()) {
return DefineAsRegister(new(zone()) LConstantT);
} else {
@@ -2050,13 +2044,6 @@
}
-LInstruction* LChunkBuilder::DoLinkObjectInList(HLinkObjectInList* instr) {
- LOperand* object = UseRegister(instr->value());
- LLinkObjectInList* result = new(zone()) LLinkObjectInList(object);
- return result;
-}
-
-
LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
LOperand* context = UseRegisterAtStart(instr->value());
LInstruction* result =
@@ -2235,21 +2222,12 @@
if (IsSimpleMapChangeTransition(instr->from_kind(), instr->to_kind())) {
LOperand* new_map_reg = TempRegister();
LTransitionElementsKind* result =
- new(zone()) LTransitionElementsKind(object, new_map_reg, NULL);
+ new(zone()) LTransitionElementsKind(object, new_map_reg);
return result;
- } else if (FLAG_compiled_transitions) {
- LTransitionElementsKind* result =
- new(zone()) LTransitionElementsKind(object, NULL, NULL);
- return AssignPointerMap(result);
} else {
- LOperand* object = UseFixed(instr->object(), a0);
- LOperand* fixed_object_reg = FixedTemp(a2);
- LOperand* new_map_reg = FixedTemp(a3);
LTransitionElementsKind* result =
- new(zone()) LTransitionElementsKind(object,
- new_map_reg,
- fixed_object_reg);
- return MarkAsCall(result, instr);
+ new(zone()) LTransitionElementsKind(object, NULL);
+ return AssignPointerMap(result);
}
}
@@ -2338,12 +2316,6 @@
}
-LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) {
- LOperand* string = UseRegisterAtStart(instr->value());
- return DefineAsRegister(new(zone()) LStringLength(string));
-}
-
-
LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) {
info()->MarkAsDeferredCalling();
LOperand* size = instr->size()->IsConstant()
diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h
index 2b55906..44c909e 100644
--- a/src/mips/lithium-mips.h
+++ b/src/mips/lithium-mips.h
@@ -79,6 +79,7 @@
V(CmpMapAndBranch) \
V(CmpT) \
V(ConstantD) \
+ V(ConstantE) \
V(ConstantI) \
V(ConstantS) \
V(ConstantT) \
@@ -118,7 +119,6 @@
V(IsUndetectableAndBranch) \
V(Label) \
V(LazyBailout) \
- V(LinkObjectInList) \
V(LoadContextSlot) \
V(LoadExternalArrayPointer) \
V(LoadFieldByIndex) \
@@ -174,7 +174,6 @@
V(StringCharCodeAt) \
V(StringCharFromCode) \
V(StringCompareAndBranch) \
- V(StringLength) \
V(SubI) \
V(TaggedToI) \
V(ThisFunction) \
@@ -265,7 +264,7 @@
bool IsMarkedAsCall() const { return is_call_; }
virtual bool HasResult() const = 0;
- virtual LOperand* result() = 0;
+ virtual LOperand* result() const = 0;
LOperand* FirstInput() { return InputAt(0); }
LOperand* Output() { return HasResult() ? result() : NULL; }
@@ -301,9 +300,9 @@
public:
// Allow 0 or 1 output operands.
STATIC_ASSERT(R == 0 || R == 1);
- virtual bool HasResult() const { return R != 0; }
+ virtual bool HasResult() const { return R != 0 && result() != NULL; }
void set_result(LOperand* operand) { results_[0] = operand; }
- LOperand* result() { return results_[0]; }
+ LOperand* result() const { return results_[0]; }
protected:
EmbeddedContainer<LOperand*, R> results_;
@@ -1210,6 +1209,17 @@
};
+class LConstantE: public LTemplateInstruction<1, 0, 0> {
+ public:
+ DECLARE_CONCRETE_INSTRUCTION(ConstantE, "constant-e")
+ DECLARE_HYDROGEN_ACCESSOR(Constant)
+
+ ExternalReference value() const {
+ return hydrogen()->ExternalReferenceValue();
+ }
+};
+
+
class LConstantT: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(ConstantT, "constant-t")
@@ -1642,23 +1652,6 @@
};
-class LLinkObjectInList: public LTemplateInstruction<0, 1, 0> {
- public:
- explicit LLinkObjectInList(LOperand* object) {
- inputs_[0] = object;
- }
-
- LOperand* object() { return inputs_[0]; }
-
- ExternalReference GetReference(Isolate* isolate);
-
- DECLARE_CONCRETE_INSTRUCTION(LinkObjectInList, "link-object-in-list")
- DECLARE_HYDROGEN_ACCESSOR(LinkObjectInList)
-
- virtual void PrintDataTo(StringStream* stream);
-};
-
-
class LLoadContextSlot: public LTemplateInstruction<1, 1, 0> {
public:
explicit LLoadContextSlot(LOperand* context) {
@@ -2208,19 +2201,16 @@
};
-class LTransitionElementsKind: public LTemplateInstruction<0, 1, 2> {
+class LTransitionElementsKind: public LTemplateInstruction<0, 1, 1> {
public:
LTransitionElementsKind(LOperand* object,
- LOperand* new_map_temp,
- LOperand* fixed_object_temp) {
+ LOperand* new_map_temp) {
inputs_[0] = object;
temps_[0] = new_map_temp;
- temps_[1] = fixed_object_temp;
}
LOperand* object() { return inputs_[0]; }
LOperand* new_map_temp() { return temps_[0]; }
- LOperand* temp() { return temps_[1]; }
DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind,
"transition-elements-kind")
@@ -2295,19 +2285,6 @@
};
-class LStringLength: public LTemplateInstruction<1, 1, 0> {
- public:
- explicit LStringLength(LOperand* string) {
- inputs_[0] = string;
- }
-
- LOperand* string() { return inputs_[0]; }
-
- DECLARE_CONCRETE_INSTRUCTION(StringLength, "string-length")
- DECLARE_HYDROGEN_ACCESSOR(StringLength)
-};
-
-
class LCheckFunction: public LTemplateInstruction<0, 1, 0> {
public:
explicit LCheckFunction(LOperand* value) {
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index cb5f2b7..395f95c 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -1162,10 +1162,6 @@
bool TransitionArray::IsConsistentWithBackPointers(Map* current_map) {
- if (HasElementsTransition() &&
- !CheckOneBackPointer(current_map, elements_transition())) {
- return false;
- }
for (int i = 0; i < number_of_transitions(); ++i) {
if (!CheckOneBackPointer(current_map, GetTarget(i))) return false;
}
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 3189d84..128dc6b 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -3563,6 +3563,7 @@
void Map::set_dictionary_map(bool value) {
+ if (value) mark_unstable();
set_bit_field3(DictionaryMap::update(bit_field3(), value));
}
@@ -3626,6 +3627,16 @@
}
+void Map::mark_unstable() {
+ set_bit_field3(IsUnstable::update(bit_field3(), true));
+}
+
+
+bool Map::is_stable() {
+ return !IsUnstable::decode(bit_field3());
+}
+
+
bool Map::has_code_cache() {
return code_cache() != GetIsolate()->heap()->empty_fixed_array();
}
@@ -3657,21 +3668,22 @@
void Map::NotifyLeafMapLayoutChange() {
- dependent_code()->DeoptimizeDependentCodeGroup(
- GetIsolate(),
- DependentCode::kPrototypeCheckGroup);
+ if (is_stable()) {
+ mark_unstable();
+ dependent_code()->DeoptimizeDependentCodeGroup(
+ GetIsolate(),
+ DependentCode::kPrototypeCheckGroup);
+ }
}
bool Map::CanOmitPrototypeChecks() {
- return !HasTransitionArray() && !is_dictionary_map() &&
- FLAG_omit_prototype_checks_for_leaf_maps;
+ return is_stable() && FLAG_omit_prototype_checks_for_leaf_maps;
}
bool Map::CanOmitMapChecks() {
- return !HasTransitionArray() && !is_dictionary_map() &&
- FLAG_omit_map_checks_for_leaf_maps;
+ return is_stable() && FLAG_omit_map_checks_for_leaf_maps;
}
@@ -4257,7 +4269,8 @@
Map* Map::elements_transition_map() {
- return transitions()->elements_transition();
+ int index = transitions()->Search(GetHeap()->elements_transition_symbol());
+ return transitions()->GetTarget(index);
}
@@ -4288,10 +4301,14 @@
MaybeObject* Map::set_elements_transition_map(Map* transitioned_map) {
- MaybeObject* allow_elements = EnsureHasTransitionArray(this);
- if (allow_elements->IsFailure()) return allow_elements;
- transitions()->set_elements_transition(transitioned_map);
- return this;
+ TransitionArray* transitions;
+ MaybeObject* maybe_transitions = AddTransition(
+ GetHeap()->elements_transition_symbol(),
+ transitioned_map,
+ FULL_TRANSITION);
+ if (!maybe_transitions->To(&transitions)) return maybe_transitions;
+ set_transitions(transitions);
+ return transitions;
}
@@ -4482,12 +4499,30 @@
ACCESSORS(Script, context_data, Object, kContextOffset)
ACCESSORS(Script, wrapper, Foreign, kWrapperOffset)
ACCESSORS_TO_SMI(Script, type, kTypeOffset)
-ACCESSORS_TO_SMI(Script, compilation_type, kCompilationTypeOffset)
-ACCESSORS_TO_SMI(Script, compilation_state, kCompilationStateOffset)
ACCESSORS(Script, line_ends, Object, kLineEndsOffset)
ACCESSORS(Script, eval_from_shared, Object, kEvalFromSharedOffset)
ACCESSORS_TO_SMI(Script, eval_from_instructions_offset,
kEvalFrominstructionsOffsetOffset)
+ACCESSORS_TO_SMI(Script, flags, kFlagsOffset)
+BOOL_ACCESSORS(Script, flags, is_shared_cross_origin, kIsSharedCrossOriginBit)
+
+Script::CompilationType Script::compilation_type() {
+ return BooleanBit::get(flags(), kCompilationTypeBit) ?
+ COMPILATION_TYPE_EVAL : COMPILATION_TYPE_HOST;
+}
+void Script::set_compilation_type(CompilationType type) {
+ set_flags(BooleanBit::set(flags(), kCompilationTypeBit,
+ type == COMPILATION_TYPE_EVAL));
+}
+Script::CompilationState Script::compilation_state() {
+ return BooleanBit::get(flags(), kCompilationStateBit) ?
+ COMPILATION_STATE_COMPILED : COMPILATION_STATE_INITIAL;
+}
+void Script::set_compilation_state(CompilationState state) {
+ set_flags(BooleanBit::set(flags(), kCompilationStateBit,
+ state == COMPILATION_STATE_COMPILED));
+}
+
#ifdef ENABLE_DEBUGGER_SUPPORT
ACCESSORS(DebugInfo, shared, SharedFunctionInfo, kSharedFunctionInfoIndex)
diff --git a/src/objects-printer.cc b/src/objects-printer.cc
index 2327cba..87b2811 100644
--- a/src/objects-printer.cc
+++ b/src/objects-printer.cc
@@ -180,6 +180,12 @@
case JS_FUNCTION_PROXY_TYPE:
JSFunctionProxy::cast(this)->JSFunctionProxyPrint(out);
break;
+ case JS_SET_TYPE:
+ JSSet::cast(this)->JSSetPrint(out);
+ break;
+ case JS_MAP_TYPE:
+ JSMap::cast(this)->JSMapPrint(out);
+ break;
case JS_WEAK_MAP_TYPE:
JSWeakMap::cast(this)->JSWeakMapPrint(out);
break;
@@ -488,7 +494,7 @@
void JSModule::JSModulePrint(FILE* out) {
HeapObject::PrintHeader(out, "JSModule");
- PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
+ PrintF(out, " - map = %p\n", reinterpret_cast<void*>(map()));
PrintF(out, " - context = ");
context()->Print(out);
PrintF(out, " - scope_info = ");
@@ -561,6 +567,8 @@
case CODE_TYPE: return "CODE";
case JS_ARRAY_TYPE: return "JS_ARRAY";
case JS_PROXY_TYPE: return "JS_PROXY";
+ case JS_SET_TYPE: return "JS_SET";
+ case JS_MAP_TYPE: return "JS_MAP";
case JS_WEAK_MAP_TYPE: return "JS_WEAK_MAP";
case JS_WEAK_SET_TYPE: return "JS_WEAK_SET";
case JS_REGEXP_TYPE: return "JS_REGEXP";
@@ -777,7 +785,7 @@
void JSDate::JSDatePrint(FILE* out) {
HeapObject::PrintHeader(out, "JSDate");
- PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
+ PrintF(out, " - map = %p\n", reinterpret_cast<void*>(map()));
PrintF(out, " - value = ");
value()->Print(out);
if (!year()->IsSmi()) {
@@ -797,7 +805,7 @@
void JSProxy::JSProxyPrint(FILE* out) {
HeapObject::PrintHeader(out, "JSProxy");
- PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
+ PrintF(out, " - map = %p\n", reinterpret_cast<void*>(map()));
PrintF(out, " - handler = ");
handler()->Print(out);
PrintF(out, " - hash = ");
@@ -808,7 +816,7 @@
void JSFunctionProxy::JSFunctionProxyPrint(FILE* out) {
HeapObject::PrintHeader(out, "JSFunctionProxy");
- PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
+ PrintF(out, " - map = %p\n", reinterpret_cast<void*>(map()));
PrintF(out, " - handler = ");
handler()->Print(out);
PrintF(out, " - call_trap = ");
@@ -819,9 +827,27 @@
}
+void JSSet::JSSetPrint(FILE* out) {
+ HeapObject::PrintHeader(out, "JSSet");
+ PrintF(out, " - map = %p\n", reinterpret_cast<void*>(map()));
+ PrintF(out, " - table = ");
+ table()->ShortPrint(out);
+ PrintF(out, "\n");
+}
+
+
+void JSMap::JSMapPrint(FILE* out) {
+ HeapObject::PrintHeader(out, "JSMap");
+ PrintF(out, " - map = %p\n", reinterpret_cast<void*>(map()));
+ PrintF(out, " - table = ");
+ table()->ShortPrint(out);
+ PrintF(out, "\n");
+}
+
+
void JSWeakMap::JSWeakMapPrint(FILE* out) {
HeapObject::PrintHeader(out, "JSWeakMap");
- PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
+ PrintF(out, " - map = %p\n", reinterpret_cast<void*>(map()));
PrintF(out, " - table = ");
table()->ShortPrint(out);
PrintF(out, "\n");
@@ -830,7 +856,7 @@
void JSWeakSet::JSWeakSetPrint(FILE* out) {
HeapObject::PrintHeader(out, "JSWeakSet");
- PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
+ PrintF(out, " - map = %p\n", reinterpret_cast<void*>(map()));
PrintF(out, " - table = ");
table()->ShortPrint(out);
PrintF(out, "\n");
@@ -839,8 +865,8 @@
void JSArrayBuffer::JSArrayBufferPrint(FILE* out) {
HeapObject::PrintHeader(out, "JSArrayBuffer");
- PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
- PrintF(out, " - backing_store = -0x%p\n", backing_store());
+ PrintF(out, " - map = %p\n", reinterpret_cast<void*>(map()));
+ PrintF(out, " - backing_store = %p\n", backing_store());
PrintF(out, " - byte_length = ");
byte_length()->ShortPrint(out);
PrintF(out, "\n");
@@ -878,7 +904,7 @@
void JSFunction::JSFunctionPrint(FILE* out) {
HeapObject::PrintHeader(out, "Function");
- PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
+ PrintF(out, " - map = %p\n", reinterpret_cast<void*>(map()));
PrintF(out, " - initial_map = ");
if (has_initial_map()) {
initial_map()->ShortPrint(out);
@@ -1202,8 +1228,7 @@
context_data()->ShortPrint(out);
PrintF(out, "\n - wrapper: ");
wrapper()->ShortPrint(out);
- PrintF(out, "\n - compilation type: ");
- compilation_type()->ShortPrint(out);
+ PrintF(out, "\n - compilation type: %d", compilation_type());
PrintF(out, "\n - line ends: ");
line_ends()->ShortPrint(out);
PrintF(out, "\n - eval from shared: ");
diff --git a/src/objects.cc b/src/objects.cc
index 7839faa..2e9badb 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -2486,8 +2486,7 @@
deprecate();
dependent_code()->DeoptimizeDependentCodeGroup(
GetIsolate(), DependentCode::kTransitionGroup);
- dependent_code()->DeoptimizeDependentCodeGroup(
- GetIsolate(), DependentCode::kPrototypeCheckGroup);
+ NotifyLeafMapLayoutChange();
}
@@ -3949,7 +3948,7 @@
Handle<Object> hresult;
if (!result->ToHandle(&hresult, isolate)) return result;
- if (FLAG_harmony_observation && map()->is_observed()) {
+ if (FLAG_harmony_observation && self->map()->is_observed()) {
if (lookup->IsTransition()) {
EnqueueChangeRecord(self, "new", name, old_value);
} else {
@@ -6495,6 +6494,7 @@
new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0);
new_bit_field3 = EnumLengthBits::update(new_bit_field3, kInvalidEnumCache);
new_bit_field3 = Deprecated::update(new_bit_field3, false);
+ new_bit_field3 = IsUnstable::update(new_bit_field3, false);
result->set_bit_field3(new_bit_field3);
return result;
}
@@ -7023,12 +7023,6 @@
return transition_array_->GetTarget(index);
}
- if (index == number_of_transitions &&
- transition_array_->HasElementsTransition()) {
- Map* elements_transition = transition_array_->elements_transition();
- *TransitionArrayHeader() = Smi::FromInt(index + 1);
- return elements_transition;
- }
*TransitionArrayHeader() = transition_array_->GetHeap()->fixed_array_map();
return NULL;
}
@@ -9145,18 +9139,10 @@
}
}
- if (t->HasElementsTransition() &&
- ClearBackPointer(heap, t->elements_transition())) {
- if (t->elements_transition()->instance_descriptors() == descriptors) {
- descriptors_owner_died = true;
- }
- t->ClearElementsTransition();
- } else {
- // If there are no transitions to be cleared, return.
- // TODO(verwaest) Should be an assert, otherwise back pointers are not
- // properly cleared.
- if (transition_index == t->number_of_transitions()) return;
- }
+ // If there are no transitions to be cleared, return.
+ // TODO(verwaest) Should be an assert, otherwise back pointers are not
+ // properly cleared.
+ if (transition_index == t->number_of_transitions()) return;
int number_of_own_descriptors = NumberOfOwnDescriptors();
diff --git a/src/objects.h b/src/objects.h
index 36611ee..d370c32 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -5188,6 +5188,7 @@
class IsObserved: public BitField<bool, 26, 1> {};
class Deprecated: public BitField<bool, 27, 1> {};
class IsFrozen: public BitField<bool, 28, 1> {};
+ class IsUnstable: public BitField<bool, 29, 1> {};
// Tells whether the object in the prototype property will be used
// for instances created from this function. If the prototype
@@ -5492,6 +5493,8 @@
inline void set_is_observed(bool is_observed);
inline void freeze();
inline bool is_frozen();
+ inline void mark_unstable();
+ inline bool is_stable();
inline void deprecate();
inline bool is_deprecated();
inline bool CanBeDeprecated();
@@ -5849,12 +5852,6 @@
// [type]: the script type.
DECL_ACCESSORS(type, Smi)
- // [compilation]: how the the script was compiled.
- DECL_ACCESSORS(compilation_type, Smi)
-
- // [is_compiled]: determines whether the script has already been compiled.
- DECL_ACCESSORS(compilation_state, Smi)
-
// [line_ends]: FixedArray of line ends positions.
DECL_ACCESSORS(line_ends, Object)
@@ -5866,6 +5863,25 @@
// function from which eval was called where eval was called.
DECL_ACCESSORS(eval_from_instructions_offset, Smi)
+ // [flags]: Holds an exciting bitfield.
+ DECL_ACCESSORS(flags, Smi)
+
+ // [compilation_type]: how the the script was compiled. Encoded in the
+ // 'flags' field.
+ inline CompilationType compilation_type();
+ inline void set_compilation_type(CompilationType type);
+
+ // [compilation_state]: determines whether the script has already been
+ // compiled. Encoded in the 'flags' field.
+ inline CompilationState compilation_state();
+ inline void set_compilation_state(CompilationState state);
+
+ // [is_shared_cross_origin]: An opaque boolean set by the embedder via
+ // ScriptOrigin, and used by the embedder to make decisions about the
+ // script's level of privilege. V8 just passes this through. Encoded in
+ // the 'flags' field.
+ DECL_BOOLEAN_ACCESSORS(is_shared_cross_origin)
+
static inline Script* cast(Object* obj);
// If script source is an external string, check that the underlying
@@ -5884,17 +5900,21 @@
static const int kContextOffset = kDataOffset + kPointerSize;
static const int kWrapperOffset = kContextOffset + kPointerSize;
static const int kTypeOffset = kWrapperOffset + kPointerSize;
- static const int kCompilationTypeOffset = kTypeOffset + kPointerSize;
- static const int kCompilationStateOffset =
- kCompilationTypeOffset + kPointerSize;
- static const int kLineEndsOffset = kCompilationStateOffset + kPointerSize;
+ static const int kLineEndsOffset = kTypeOffset + kPointerSize;
static const int kIdOffset = kLineEndsOffset + kPointerSize;
static const int kEvalFromSharedOffset = kIdOffset + kPointerSize;
static const int kEvalFrominstructionsOffsetOffset =
kEvalFromSharedOffset + kPointerSize;
- static const int kSize = kEvalFrominstructionsOffsetOffset + kPointerSize;
+ static const int kFlagsOffset =
+ kEvalFrominstructionsOffsetOffset + kPointerSize;
+ static const int kSize = kFlagsOffset + kPointerSize;
private:
+ // Bit positions in the flags field.
+ static const int kCompilationTypeBit = 0;
+ static const int kCompilationStateBit = 1;
+ static const int kIsSharedCrossOriginBit = 2;
+
DISALLOW_IMPLICIT_CONSTRUCTORS(Script);
};
diff --git a/src/platform-win32.cc b/src/platform-win32.cc
index 80bcaf9..292c24a 100644
--- a/src/platform-win32.cc
+++ b/src/platform-win32.cc
@@ -892,7 +892,7 @@
}
-static void* GetRandomAddr() {
+void* OS::GetRandomMmapAddr() {
Isolate* isolate = Isolate::UncheckedCurrent();
// Note that the current isolate isn't set up in a call path via
// CpuFeatures::Probe. We don't care about randomization in this case because
@@ -925,7 +925,7 @@
if (protection == PAGE_EXECUTE_READWRITE || protection == PAGE_NOACCESS) {
// For exectutable pages try and randomize the allocation address
for (size_t attempts = 0; base == NULL && attempts < 3; ++attempts) {
- base = VirtualAlloc(GetRandomAddr(), size, action, protection);
+ base = VirtualAlloc(OS::GetRandomMmapAddr(), size, action, protection);
}
}
diff --git a/src/profile-generator.cc b/src/profile-generator.cc
index 8428303..4e2e389 100644
--- a/src/profile-generator.cc
+++ b/src/profile-generator.cc
@@ -372,19 +372,30 @@
}
+CpuProfile::CpuProfile(const char* title, unsigned uid, bool record_samples)
+ : title_(title),
+ uid_(uid),
+ record_samples_(record_samples),
+ start_time_ms_(OS::TimeCurrentMillis()),
+ end_time_ms_(0) {
+}
+
+
void CpuProfile::AddPath(const Vector<CodeEntry*>& path) {
ProfileNode* top_frame_node = top_down_.AddPathFromEnd(path);
if (record_samples_) samples_.Add(top_frame_node);
}
-void CpuProfile::CalculateTotalTicks() {
+void CpuProfile::CalculateTotalTicksAndSamplingRate() {
+ end_time_ms_ = OS::TimeCurrentMillis();
top_down_.CalculateTotalTicks();
-}
-
-void CpuProfile::SetActualSamplingRate(double actual_sampling_rate) {
- top_down_.SetTickRatePerMs(actual_sampling_rate);
+ double duration = end_time_ms_ - start_time_ms_;
+ if (duration < 1) duration = 1;
+ unsigned ticks = top_down_.root()->total_ticks();
+ double rate = ticks / duration;
+ top_down_.SetTickRatePerMs(rate);
}
@@ -529,8 +540,7 @@
}
-CpuProfile* CpuProfilesCollection::StopProfiling(const char* title,
- double actual_sampling_rate) {
+CpuProfile* CpuProfilesCollection::StopProfiling(const char* title) {
const int title_len = StrLength(title);
CpuProfile* profile = NULL;
current_profiles_semaphore_->Wait();
@@ -543,8 +553,7 @@
current_profiles_semaphore_->Signal();
if (profile == NULL) return NULL;
- profile->CalculateTotalTicks();
- profile->SetActualSamplingRate(actual_sampling_rate);
+ profile->CalculateTotalTicksAndSamplingRate();
finished_profiles_.Add(profile);
return profile;
}
@@ -601,29 +610,6 @@
}
-void SampleRateCalculator::Tick() {
- if (--wall_time_query_countdown_ == 0)
- UpdateMeasurements(OS::TimeCurrentMillis());
-}
-
-
-void SampleRateCalculator::UpdateMeasurements(double current_time) {
- if (measurements_count_++ != 0) {
- const double measured_ticks_per_ms =
- (kWallTimeQueryIntervalMs * ticks_per_ms_) /
- (current_time - last_wall_time_);
- // Update the average value.
- ticks_per_ms_ +=
- (measured_ticks_per_ms - ticks_per_ms_) / measurements_count_;
- // Update the externally accessible result.
- result_ = static_cast<AtomicWord>(ticks_per_ms_ * kResultScale);
- }
- last_wall_time_ = current_time;
- wall_time_query_countdown_ =
- static_cast<unsigned>(kWallTimeQueryIntervalMs * ticks_per_ms_);
-}
-
-
const char* const ProfileGenerator::kAnonymousFunctionName =
"(anonymous function)";
const char* const ProfileGenerator::kProgramEntryName =
diff --git a/src/profile-generator.h b/src/profile-generator.h
index 6b02368..7861ccd 100644
--- a/src/profile-generator.h
+++ b/src/profile-generator.h
@@ -203,13 +203,11 @@
class CpuProfile {
public:
- CpuProfile(const char* title, unsigned uid, bool record_samples)
- : title_(title), uid_(uid), record_samples_(record_samples) { }
+ CpuProfile(const char* title, unsigned uid, bool record_samples);
// Add pc -> ... -> main() call path to the profile.
void AddPath(const Vector<CodeEntry*>& path);
- void CalculateTotalTicks();
- void SetActualSamplingRate(double actual_sampling_rate);
+ void CalculateTotalTicksAndSamplingRate();
INLINE(const char* title() const) { return title_; }
INLINE(unsigned uid() const) { return uid_; }
@@ -227,6 +225,8 @@
const char* title_;
unsigned uid_;
bool record_samples_;
+ double start_time_ms_;
+ double end_time_ms_;
List<ProfileNode*> samples_;
ProfileTree top_down_;
@@ -286,7 +286,7 @@
~CpuProfilesCollection();
bool StartProfiling(const char* title, unsigned uid, bool record_samples);
- CpuProfile* StopProfiling(const char* title, double actual_sampling_rate);
+ CpuProfile* StopProfiling(const char* title);
List<CpuProfile*>* profiles() { return &finished_profiles_; }
const char* GetName(Name* name) {
return function_and_resource_names_.GetName(name);
@@ -329,44 +329,6 @@
};
-class SampleRateCalculator {
- public:
- SampleRateCalculator()
- : result_(Logger::kSamplingIntervalMs * kResultScale),
- ticks_per_ms_(Logger::kSamplingIntervalMs),
- measurements_count_(0),
- wall_time_query_countdown_(1) {
- }
-
- double ticks_per_ms() {
- return result_ / static_cast<double>(kResultScale);
- }
- void Tick();
- void UpdateMeasurements(double current_time);
-
- // Instead of querying current wall time each tick,
- // we use this constant to control query intervals.
- static const unsigned kWallTimeQueryIntervalMs = 100;
-
- private:
- // As the result needs to be accessed from a different thread, we
- // use type that guarantees atomic writes to memory. There should
- // be <= 1000 ticks per second, thus storing a value of a 10 ** 5
- // order should provide enough precision while keeping away from a
- // potential overflow.
- static const int kResultScale = 100000;
-
- AtomicWord result_;
- // All other fields are accessed only from the sampler thread.
- double ticks_per_ms_;
- unsigned measurements_count_;
- unsigned wall_time_query_countdown_;
- double last_wall_time_;
-
- DISALLOW_COPY_AND_ASSIGN(SampleRateCalculator);
-};
-
-
class ProfileGenerator {
public:
explicit ProfileGenerator(CpuProfilesCollection* profiles);
@@ -375,11 +337,6 @@
INLINE(CodeMap* code_map()) { return &code_map_; }
- INLINE(void Tick()) { sample_rate_calc_.Tick(); }
- INLINE(double actual_sampling_rate()) {
- return sample_rate_calc_.ticks_per_ms();
- }
-
static const char* const kAnonymousFunctionName;
static const char* const kProgramEntryName;
static const char* const kGarbageCollectorEntryName;
@@ -395,7 +352,6 @@
CodeEntry* program_entry_;
CodeEntry* gc_entry_;
CodeEntry* unresolved_entry_;
- SampleRateCalculator sample_rate_calc_;
DISALLOW_COPY_AND_ASSIGN(ProfileGenerator);
};
diff --git a/src/runtime-profiler.cc b/src/runtime-profiler.cc
index ff41432..0e99650 100644
--- a/src/runtime-profiler.cc
+++ b/src/runtime-profiler.cc
@@ -408,11 +408,6 @@
}
-int RuntimeProfiler::SamplerWindowSize() {
- return kSamplerWindowSize;
-}
-
-
// Update the pointers in the sampler window after a GC.
void RuntimeProfiler::UpdateSamplesAfterScavenge() {
for (int i = 0; i < kSamplerWindowSize; i++) {
diff --git a/src/runtime-profiler.h b/src/runtime-profiler.h
index 46da381..28d6d32 100644
--- a/src/runtime-profiler.h
+++ b/src/runtime-profiler.h
@@ -49,9 +49,6 @@
void Reset();
void TearDown();
- Object** SamplerWindowAddress();
- int SamplerWindowSize();
-
void NotifyICChanged() { any_ic_changed_ = true; }
// Rate limiting support.
diff --git a/src/runtime.cc b/src/runtime.cc
index 37eaf29..0970d0d 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -712,13 +712,18 @@
bool Runtime::SetupArrayBufferAllocatingData(
Isolate* isolate,
Handle<JSArrayBuffer> array_buffer,
- size_t allocated_length) {
+ size_t allocated_length,
+ bool initialize) {
void* data;
CHECK(V8::ArrayBufferAllocator() != NULL);
if (allocated_length != 0) {
- data = V8::ArrayBufferAllocator()->Allocate(allocated_length);
+ if (initialize) {
+ data = V8::ArrayBufferAllocator()->Allocate(allocated_length);
+ } else {
+ data =
+ V8::ArrayBufferAllocator()->AllocateUninitialized(allocated_length);
+ }
if (data == NULL) return false;
- memset(data, 0, allocated_length);
} else {
data = NULL;
}
@@ -805,6 +810,50 @@
ARRAY_ID_UINT8C = 9
};
+static void ArrayIdToTypeAndSize(
+ int arrayId, ExternalArrayType* array_type, size_t* element_size) {
+ switch (arrayId) {
+ case ARRAY_ID_UINT8:
+ *array_type = kExternalUnsignedByteArray;
+ *element_size = 1;
+ break;
+ case ARRAY_ID_INT8:
+ *array_type = kExternalByteArray;
+ *element_size = 1;
+ break;
+ case ARRAY_ID_UINT16:
+ *array_type = kExternalUnsignedShortArray;
+ *element_size = 2;
+ break;
+ case ARRAY_ID_INT16:
+ *array_type = kExternalShortArray;
+ *element_size = 2;
+ break;
+ case ARRAY_ID_UINT32:
+ *array_type = kExternalUnsignedIntArray;
+ *element_size = 4;
+ break;
+ case ARRAY_ID_INT32:
+ *array_type = kExternalIntArray;
+ *element_size = 4;
+ break;
+ case ARRAY_ID_FLOAT32:
+ *array_type = kExternalFloatArray;
+ *element_size = 4;
+ break;
+ case ARRAY_ID_FLOAT64:
+ *array_type = kExternalDoubleArray;
+ *element_size = 8;
+ break;
+ case ARRAY_ID_UINT8C:
+ *array_type = kExternalPixelArray;
+ *element_size = 1;
+ break;
+ default:
+ UNREACHABLE();
+ }
+}
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitialize) {
HandleScope scope(isolate);
@@ -821,49 +870,9 @@
holder->SetInternalField(i, Smi::FromInt(0));
}
- ExternalArrayType arrayType;
- size_t elementSize;
- switch (arrayId) {
- case ARRAY_ID_UINT8:
- arrayType = kExternalUnsignedByteArray;
- elementSize = 1;
- break;
- case ARRAY_ID_INT8:
- arrayType = kExternalByteArray;
- elementSize = 1;
- break;
- case ARRAY_ID_UINT16:
- arrayType = kExternalUnsignedShortArray;
- elementSize = 2;
- break;
- case ARRAY_ID_INT16:
- arrayType = kExternalShortArray;
- elementSize = 2;
- break;
- case ARRAY_ID_UINT32:
- arrayType = kExternalUnsignedIntArray;
- elementSize = 4;
- break;
- case ARRAY_ID_INT32:
- arrayType = kExternalIntArray;
- elementSize = 4;
- break;
- case ARRAY_ID_FLOAT32:
- arrayType = kExternalFloatArray;
- elementSize = 4;
- break;
- case ARRAY_ID_FLOAT64:
- arrayType = kExternalDoubleArray;
- elementSize = 8;
- break;
- case ARRAY_ID_UINT8C:
- arrayType = kExternalPixelArray;
- elementSize = 1;
- break;
- default:
- UNREACHABLE();
- return NULL;
- }
+ ExternalArrayType array_type = kExternalByteArray; // Bogus initialization.
+ size_t element_size = 1; // Bogus initialization.
+ ArrayIdToTypeAndSize(arrayId, &array_type, &element_size);
holder->set_buffer(*buffer);
holder->set_byte_offset(*byte_offset_object);
@@ -871,8 +880,8 @@
size_t byte_offset = NumberToSize(isolate, *byte_offset_object);
size_t byte_length = NumberToSize(isolate, *byte_length_object);
- ASSERT(byte_length % elementSize == 0);
- size_t length = byte_length / elementSize;
+ ASSERT(byte_length % element_size == 0);
+ size_t length = byte_length / element_size;
Handle<Object> length_obj = isolate->factory()->NewNumberFromSize(length);
holder->set_length(*length_obj);
@@ -881,13 +890,99 @@
Handle<ExternalArray> elements =
isolate->factory()->NewExternalArray(
- static_cast<int>(length), arrayType,
+ static_cast<int>(length), array_type,
static_cast<uint8_t*>(buffer->backing_store()) + byte_offset);
holder->set_elements(*elements);
return isolate->heap()->undefined_value();
}
+// Initializes a typed array from an array-like object.
+// If an array-like object happens to be a typed array of the same type,
+// initializes backing store using memove.
+//
+// Returns true if backing store was initialized or false otherwise.
+RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitializeFromArrayLike) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 4);
+ CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
+ CONVERT_SMI_ARG_CHECKED(arrayId, 1);
+ CONVERT_ARG_HANDLE_CHECKED(Object, source, 2);
+ CONVERT_ARG_HANDLE_CHECKED(Object, length_obj, 3);
+
+ ASSERT(holder->GetInternalFieldCount() ==
+ v8::ArrayBufferView::kInternalFieldCount);
+ for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
+ holder->SetInternalField(i, Smi::FromInt(0));
+ }
+
+ ExternalArrayType array_type = kExternalByteArray; // Bogus initialization.
+ size_t element_size = 1; // Bogus initialization.
+ ArrayIdToTypeAndSize(arrayId, &array_type, &element_size);
+
+ Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
+ size_t length = NumberToSize(isolate, *length_obj);
+ size_t byte_length = length * element_size;
+ if (byte_length < length) { // Overflow
+ return isolate->Throw(*isolate->factory()->
+ NewRangeError("invalid_array_buffer_length",
+ HandleVector<Object>(NULL, 0)));
+ }
+
+ // We assume that the caller of this function will initialize holder
+ // with the loop
+ // for(i = 0; i < length; i++) { holder[i] = source[i]; }
+ // If source is a typed array, this loop will always run to completion,
+ // so we are sure that the backing store will be initialized.
+ // Otherwise, we do not know (the indexing operation might throw).
+ // Hence we require zero initialization unless our source is a typed array.
+ bool should_zero_initialize = !source->IsJSTypedArray();
+
+ if (!Runtime::SetupArrayBufferAllocatingData(
+ isolate, buffer, byte_length, should_zero_initialize)) {
+ return isolate->Throw(*isolate->factory()->
+ NewRangeError("invalid_array_buffer_length",
+ HandleVector<Object>(NULL, 0)));
+ }
+
+ holder->set_buffer(*buffer);
+ holder->set_byte_offset(Smi::FromInt(0));
+ Handle<Object> byte_length_obj(
+ isolate->factory()->NewNumberFromSize(byte_length));
+ holder->set_byte_length(*byte_length_obj);
+ holder->set_length(*length_obj);
+ holder->set_weak_next(buffer->weak_first_view());
+ buffer->set_weak_first_view(*holder);
+
+ Handle<ExternalArray> elements =
+ isolate->factory()->NewExternalArray(
+ static_cast<int>(length), array_type,
+ static_cast<uint8_t*>(buffer->backing_store()));
+ holder->set_elements(*elements);
+
+ if (source->IsJSTypedArray()) {
+ Handle<JSTypedArray> typed_array(JSTypedArray::cast(*source));
+
+ if (typed_array->type() == holder->type()) {
+ uint8_t* backing_store =
+ static_cast<uint8_t*>(
+ JSArrayBuffer::cast(typed_array->buffer())->backing_store());
+ size_t source_byte_offset =
+ NumberToSize(isolate, typed_array->byte_offset());
+ OS::MemCopy(
+ buffer->backing_store(),
+ backing_store + source_byte_offset,
+ byte_length);
+ return *isolate->factory()->true_value();
+ } else {
+ return *isolate->factory()->false_value();
+ }
+ }
+
+ return *isolate->factory()->false_value();
+}
+
+
#define TYPED_ARRAY_GETTER(getter, accessor) \
RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayGet##getter) { \
HandleScope scope(isolate); \
@@ -907,6 +1002,21 @@
#undef TYPED_ARRAY_GETTER
+// Return codes for Runtime_TypedArraySetFastCases.
+// Should be synchronized with typedarray.js natives.
+enum TypedArraySetResultCodes {
+ // Set from typed array of the same type.
+ // This is processed by TypedArraySetFastCases
+ TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE = 0,
+ // Set from typed array of the different type, overlapping in memory.
+ TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING = 1,
+ // Set from typed array of the different type, non-overlapping.
+ TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING = 2,
+ // Set from non-typed array.
+ TYPED_ARRAY_SET_NON_TYPED_ARRAY = 3
+};
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArraySetFastCases) {
HandleScope scope(isolate);
CONVERT_ARG_HANDLE_CHECKED(Object, target_obj, 0);
@@ -918,7 +1028,7 @@
"not_typed_array", HandleVector<Object>(NULL, 0)));
if (!source_obj->IsJSTypedArray())
- return isolate->heap()->false_value();
+ return Smi::FromInt(TYPED_ARRAY_SET_NON_TYPED_ARRAY);
Handle<JSTypedArray> target(JSTypedArray::cast(*target_obj));
Handle<JSTypedArray> source(JSTypedArray::cast(*source_obj));
@@ -933,20 +1043,20 @@
return isolate->Throw(*isolate->factory()->NewRangeError(
"typed_array_set_source_too_large", HandleVector<Object>(NULL, 0)));
- Handle<JSArrayBuffer> target_buffer(JSArrayBuffer::cast(target->buffer()));
- Handle<JSArrayBuffer> source_buffer(JSArrayBuffer::cast(source->buffer()));
size_t target_offset = NumberToSize(isolate, target->byte_offset());
size_t source_offset = NumberToSize(isolate, source->byte_offset());
uint8_t* target_base =
- static_cast<uint8_t*>(target_buffer->backing_store()) + target_offset;
+ static_cast<uint8_t*>(
+ JSArrayBuffer::cast(target->buffer())->backing_store()) + target_offset;
uint8_t* source_base =
- static_cast<uint8_t*>(source_buffer->backing_store()) + source_offset;
+ static_cast<uint8_t*>(
+ JSArrayBuffer::cast(source->buffer())->backing_store()) + source_offset;
// Typed arrays of the same type: use memmove.
if (target->type() == source->type()) {
memmove(target_base + offset * target->element_size(),
source_base, source_byte_length);
- return isolate->heap()->true_value();
+ return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE);
}
// Typed arrays of different types over the same backing store
@@ -954,78 +1064,14 @@
source_base + source_byte_length > target_base) ||
(target_base <= source_base &&
target_base + target_byte_length > source_base)) {
- size_t target_element_size = target->element_size();
- size_t source_element_size = source->element_size();
-
- size_t source_length = NumberToSize(isolate, source->length());
-
- // Copy left part
- size_t left_index;
- {
- // First un-mutated byte after the next write
- uint8_t* target_ptr = target_base + (offset + 1) * target_element_size;
- // Next read at source_ptr. We do not care for memory changing before
- // source_ptr - we have already copied it.
- uint8_t* source_ptr = source_base;
- for (left_index = 0;
- left_index < source_length && target_ptr <= source_ptr;
- left_index++) {
- Handle<Object> v = Object::GetElement(
- source, static_cast<uint32_t>(left_index));
- JSObject::SetElement(
- target, static_cast<uint32_t>(offset + left_index), v,
- NONE, kNonStrictMode);
- target_ptr += target_element_size;
- source_ptr += source_element_size;
- }
- }
- // Copy right part
- size_t right_index;
- {
- // First unmutated byte before the next write
- uint8_t* target_ptr =
- target_base + (offset + source_length - 1) * target_element_size;
- // Next read before source_ptr. We do not care for memory changing after
- // source_ptr - we have already copied it.
- uint8_t* source_ptr =
- source_base + source_length * source_element_size;
- for (right_index = source_length - 1;
- right_index >= left_index && target_ptr >= source_ptr;
- right_index--) {
- Handle<Object> v = Object::GetElement(
- source, static_cast<uint32_t>(right_index));
- JSObject::SetElement(
- target, static_cast<uint32_t>(offset + right_index), v,
- NONE, kNonStrictMode);
- target_ptr -= target_element_size;
- source_ptr -= source_element_size;
- }
- }
- // There can be at most 8 entries left in the middle that need buffering
- // (because the largest element_size is 8 times the smallest).
- ASSERT((right_index + 1) - left_index <= 8);
- Handle<Object> temp[8];
- size_t idx;
- for (idx = left_index; idx <= right_index; idx++) {
- temp[idx - left_index] = Object::GetElement(
- source, static_cast<uint32_t>(idx));
- }
- for (idx = left_index; idx <= right_index; idx++) {
- JSObject::SetElement(
- target, static_cast<uint32_t>(offset + idx), temp[idx-left_index],
- NONE, kNonStrictMode);
- }
+ // We do not support overlapping ArrayBuffers
+ ASSERT(
+ JSArrayBuffer::cast(target->buffer())->backing_store() ==
+ JSArrayBuffer::cast(source->buffer())->backing_store());
+ return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING);
} else { // Non-overlapping typed arrays
- for (size_t idx = 0; idx < source_length; idx++) {
- Handle<Object> value = Object::GetElement(
- source, static_cast<uint32_t>(idx));
- JSObject::SetElement(
- target, static_cast<uint32_t>(offset + idx), value,
- NONE, kNonStrictMode);
- }
+ return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING);
}
-
- return isolate->heap()->true_value();
}
@@ -5230,40 +5276,6 @@
}
-RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
- SealHandleScope shs(isolate);
- RUNTIME_ASSERT(args.length() == 1);
- Handle<Object> object = args.at<Object>(0);
- if (object->IsJSObject()) {
- Handle<JSObject> js_object(Handle<JSObject>::cast(object));
- ASSERT(!js_object->map()->is_observed());
- ElementsKind new_kind = js_object->HasFastHoleyElements()
- ? FAST_HOLEY_DOUBLE_ELEMENTS
- : FAST_DOUBLE_ELEMENTS;
- return TransitionElements(object, new_kind, isolate);
- } else {
- return *object;
- }
-}
-
-
-RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
- SealHandleScope shs(isolate);
- RUNTIME_ASSERT(args.length() == 1);
- Handle<Object> object = args.at<Object>(0);
- if (object->IsJSObject()) {
- Handle<JSObject> js_object(Handle<JSObject>::cast(object));
- ASSERT(!js_object->map()->is_observed());
- ElementsKind new_kind = js_object->HasFastHoleyElements()
- ? FAST_HOLEY_ELEMENTS
- : FAST_ELEMENTS;
- return TransitionElements(object, new_kind, isolate);
- } else {
- return *object;
- }
-}
-
-
// Set the native flag on the function.
// This is used to decide if we should transform null and undefined
// into the global object when doing call and apply.
@@ -12921,7 +12933,7 @@
RUNTIME_ASSERT(script_wrapper->value()->IsScript());
Handle<Script> script(Script::cast(script_wrapper->value()));
- int compilation_state = Smi::cast(script->compilation_state())->value();
+ int compilation_state = script->compilation_state();
RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL);
script->set_source(*source);
diff --git a/src/runtime.h b/src/runtime.h
index 400145f..398cb3b 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -361,6 +361,7 @@
F(ArrayBufferSliceImpl, 3, 1) \
\
F(TypedArrayInitialize, 5, 1) \
+ F(TypedArrayInitializeFromArrayLike, 4, 1) \
F(TypedArrayGetBuffer, 1, 1) \
F(TypedArrayGetByteLength, 1, 1) \
F(TypedArrayGetByteOffset, 1, 1) \
@@ -463,8 +464,6 @@
F(HasExternalDoubleElements, 1, 1) \
F(HasFastProperties, 1, 1) \
F(TransitionElementsKind, 2, 1) \
- F(TransitionElementsSmiToDouble, 1, 1) \
- F(TransitionElementsDoubleToObject, 1, 1) \
F(HaveSameMap, 2, 1)
@@ -786,7 +785,8 @@
static bool SetupArrayBufferAllocatingData(
Isolate* isolate,
Handle<JSArrayBuffer> array_buffer,
- size_t allocated_length);
+ size_t allocated_length,
+ bool initialize = true);
static void FreeArrayBuffer(
Isolate* isolate,
diff --git a/src/serialize.cc b/src/serialize.cc
index ad56d36..6c5a620 100644
--- a/src/serialize.cc
+++ b/src/serialize.cc
@@ -665,6 +665,141 @@
bool Serializer::too_late_to_enable_now_ = false;
+class CodeAddressMap: public CodeEventLogger {
+ public:
+ explicit CodeAddressMap(Isolate* isolate)
+ : isolate_(isolate) {
+ isolate->logger()->addCodeEventListener(this);
+ }
+
+ virtual ~CodeAddressMap() {
+ isolate_->logger()->removeCodeEventListener(this);
+ }
+
+ virtual void CodeMoveEvent(Address from, Address to) {
+ address_to_name_map_.Move(from, to);
+ }
+
+ virtual void CodeDeleteEvent(Address from) {
+ address_to_name_map_.Remove(from);
+ }
+
+ const char* Lookup(Address address) {
+ return address_to_name_map_.Lookup(address);
+ }
+
+ private:
+ class NameMap {
+ public:
+ NameMap() : impl_(&PointerEquals) {}
+
+ ~NameMap() {
+ for (HashMap::Entry* p = impl_.Start(); p != NULL; p = impl_.Next(p)) {
+ DeleteArray(static_cast<const char*>(p->value));
+ }
+ }
+
+ void Insert(Address code_address, const char* name, int name_size) {
+ HashMap::Entry* entry = FindOrCreateEntry(code_address);
+ if (entry->value == NULL) {
+ entry->value = CopyName(name, name_size);
+ }
+ }
+
+ const char* Lookup(Address code_address) {
+ HashMap::Entry* entry = FindEntry(code_address);
+ return (entry != NULL) ? static_cast<const char*>(entry->value) : NULL;
+ }
+
+ void Remove(Address code_address) {
+ HashMap::Entry* entry = FindEntry(code_address);
+ if (entry != NULL) {
+ DeleteArray(static_cast<char*>(entry->value));
+ RemoveEntry(entry);
+ }
+ }
+
+ void Move(Address from, Address to) {
+ if (from == to) return;
+ HashMap::Entry* from_entry = FindEntry(from);
+ ASSERT(from_entry != NULL);
+ void* value = from_entry->value;
+ RemoveEntry(from_entry);
+ HashMap::Entry* to_entry = FindOrCreateEntry(to);
+ ASSERT(to_entry->value == NULL);
+ to_entry->value = value;
+ }
+
+ private:
+ static bool PointerEquals(void* lhs, void* rhs) {
+ return lhs == rhs;
+ }
+
+ static char* CopyName(const char* name, int name_size) {
+ char* result = NewArray<char>(name_size + 1);
+ for (int i = 0; i < name_size; ++i) {
+ char c = name[i];
+ if (c == '\0') c = ' ';
+ result[i] = c;
+ }
+ result[name_size] = '\0';
+ return result;
+ }
+
+ HashMap::Entry* FindOrCreateEntry(Address code_address) {
+ return impl_.Lookup(code_address, ComputePointerHash(code_address), true);
+ }
+
+ HashMap::Entry* FindEntry(Address code_address) {
+ return impl_.Lookup(code_address,
+ ComputePointerHash(code_address),
+ false);
+ }
+
+ void RemoveEntry(HashMap::Entry* entry) {
+ impl_.Remove(entry->key, entry->hash);
+ }
+
+ HashMap impl_;
+
+ DISALLOW_COPY_AND_ASSIGN(NameMap);
+ };
+
+ virtual void LogRecordedBuffer(Code* code,
+ SharedFunctionInfo*,
+ const char* name,
+ int length) {
+ address_to_name_map_.Insert(code->address(), name, length);
+ }
+
+ NameMap address_to_name_map_;
+ Isolate* isolate_;
+};
+
+
+CodeAddressMap* Serializer::code_address_map_ = NULL;
+
+
+void Serializer::Enable() {
+ if (!serialization_enabled_) {
+ ASSERT(!too_late_to_enable_now_);
+ }
+ if (serialization_enabled_) return;
+ serialization_enabled_ = true;
+ i::Isolate* isolate = Isolate::Current();
+ isolate->InitializeLoggingAndCounters();
+ code_address_map_ = new CodeAddressMap(isolate);
+}
+
+
+void Serializer::Disable() {
+ if (!serialization_enabled_) return;
+ serialization_enabled_ = false;
+ delete code_address_map_;
+ code_address_map_ = NULL;
+}
+
+
Deserializer::Deserializer(SnapshotByteSource* source)
: isolate_(NULL),
source_(source),
@@ -1458,7 +1593,11 @@
"ObjectSerialization");
sink_->PutInt(size >> kObjectAlignmentBits, "Size in words");
- LOG(i::Isolate::Current(),
+ ASSERT(code_address_map_);
+ const char* code_name = code_address_map_->Lookup(object_->address());
+ LOG(serializer_->isolate_,
+ CodeNameEvent(object_->address(), sink_->Position(), code_name));
+ LOG(serializer_->isolate_,
SnapshotPositionEvent(object_->address(), sink_->Position()));
// Mark this object as already serialized.
diff --git a/src/serialize.h b/src/serialize.h
index 283c1b7..563f0a0 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -459,6 +459,8 @@
};
+class CodeAddressMap;
+
// There can be only one serializer per V8 process.
class Serializer : public SerializerDeserializer {
public:
@@ -472,14 +474,9 @@
return fullness_[space];
}
- static void Enable() {
- if (!serialization_enabled_) {
- ASSERT(!too_late_to_enable_now_);
- }
- serialization_enabled_ = true;
- }
+ static void Enable();
+ static void Disable();
- static void Disable() { serialization_enabled_ = false; }
// Call this when you have made use of the fact that there is no serialization
// going on.
static void TooLateToEnableNow() { too_late_to_enable_now_ = true; }
@@ -589,6 +586,7 @@
friend class Deserializer;
private:
+ static CodeAddressMap* code_address_map_;
DISALLOW_COPY_AND_ASSIGN(Serializer);
};
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index 73c7a0a..9e29a95 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -1992,21 +1992,11 @@
bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
ElementsKind elements_kind = receiver_map->elements_kind();
if (!transitioned_map.is_null()) {
- if (FLAG_compiled_transitions) {
- cached_stub = ElementsTransitionAndStoreStub(
- elements_kind,
- transitioned_map->elements_kind(),
- is_js_array,
- store_mode_).GetCode(isolate());
- } else {
- // TODO(bmeurer) Remove this when compiled transitions is enabled
- cached_stub = ElementsTransitionAndStorePlatformStub(
- elements_kind,
- transitioned_map->elements_kind(),
- is_js_array,
- strict_mode(),
- store_mode_).GetCode(isolate());
- }
+ cached_stub = ElementsTransitionAndStoreStub(
+ elements_kind,
+ transitioned_map->elements_kind(),
+ is_js_array,
+ store_mode_).GetCode(isolate());
} else {
if (FLAG_compiled_keyed_stores &&
(receiver_map->has_fast_elements() ||
diff --git a/src/third_party/vtune/vtune-jit.cc b/src/third_party/vtune/vtune-jit.cc
index 0f35290..93de7ef 100644
--- a/src/third_party/vtune/vtune-jit.cc
+++ b/src/third_party/vtune/vtune-jit.cc
@@ -64,10 +64,15 @@
// To avoid GCC 4.4 compilation warning about hash_map being deprecated.
#define OLD_DEPRECATED __DEPRECATED
#undef __DEPRECATED
+#if defined (ANDROID)
+#include <hash_map>
+using namespace std;
+#else
#include <ext/hash_map>
-#define __DEPRECATED OLD_DEPRECATED
using namespace __gnu_cxx;
#endif
+#define __DEPRECATED OLD_DEPRECATED
+#endif
#include <list>
diff --git a/src/transitions-inl.h b/src/transitions-inl.h
index 45b6457..c4825fc 100644
--- a/src/transitions-inl.h
+++ b/src/transitions-inl.h
@@ -57,30 +57,8 @@
}
-Map* TransitionArray::elements_transition() {
- Object* transition_map = get(kElementsTransitionIndex);
- return Map::cast(transition_map);
-}
-
-
-void TransitionArray::ClearElementsTransition() {
- WRITE_FIELD(this, kElementsTransitionOffset, Smi::FromInt(0));
-}
-
-
bool TransitionArray::HasElementsTransition() {
- return IsFullTransitionArray() &&
- get(kElementsTransitionIndex) != Smi::FromInt(0);
-}
-
-
-void TransitionArray::set_elements_transition(Map* transition_map,
- WriteBarrierMode mode) {
- ASSERT(IsFullTransitionArray());
- Heap* heap = GetHeap();
- WRITE_FIELD(this, kElementsTransitionOffset, transition_map);
- CONDITIONAL_WRITE_BARRIER(
- heap, this, kElementsTransitionOffset, transition_map, mode);
+ return Search(GetHeap()->elements_transition_symbol()) != kNotFound;
}
diff --git a/src/transitions.cc b/src/transitions.cc
index df53178..086edcb 100644
--- a/src/transitions.cc
+++ b/src/transitions.cc
@@ -50,7 +50,6 @@
FixedArray* array;
MaybeObject* maybe_array = AllocateRaw(ToKeyIndex(number_of_transitions));
if (!maybe_array->To(&array)) return maybe_array;
- array->set(kElementsTransitionIndex, Smi::FromInt(0));
array->set(kPrototypeTransitionsIndex, Smi::FromInt(0));
return array;
}
@@ -120,10 +119,6 @@
maybe_array = TransitionArray::Allocate(new_size);
if (!maybe_array->To(&result)) return maybe_array;
- if (HasElementsTransition()) {
- result->set_elements_transition(elements_transition());
- }
-
if (HasPrototypeTransitions()) {
result->SetPrototypeTransitions(GetPrototypeTransitions());
}
diff --git a/src/transitions.h b/src/transitions.h
index 7abef47..fde1279 100644
--- a/src/transitions.h
+++ b/src/transitions.h
@@ -41,10 +41,10 @@
// TransitionArrays are fixed arrays used to hold map transitions for property,
// constant, and element changes. They can either be simple transition arrays
// that store a single property transition, or a full transition array that has
-// space for elements transitions, prototype transitions and multiple property
-// transitons. The details related to property transitions are accessed in the
-// descriptor array of the target map. In the case of a simple transition, the
-// key is also read from the descriptor array of the target map.
+// prototype transitions and multiple property transitons. The details related
+// to property transitions are accessed in the descriptor array of the target
+// map. In the case of a simple transition, the key is also read from the
+// descriptor array of the target map.
//
// The simple format of the these objects is:
// [0] Undefined or back pointer map
@@ -52,9 +52,8 @@
//
// The full format is:
// [0] Undefined or back pointer map
-// [1] Smi(0) or elements transition map
-// [2] Smi(0) or fixed array of prototype transitions
-// [3] First transition
+// [1] Smi(0) or fixed array of prototype transitions
+// [2] First transition
// [length() - kTransitionSize] Last transition
class TransitionArray: public FixedArray {
public:
@@ -73,12 +72,7 @@
inline PropertyDetails GetTargetDetails(int transition_number);
- inline Map* elements_transition();
- inline void set_elements_transition(
- Map* target,
- WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
inline bool HasElementsTransition();
- inline void ClearElementsTransition();
inline Object* back_pointer_storage();
inline void set_back_pointer_storage(
@@ -127,8 +121,21 @@
// Allocates a TransitionArray.
MUST_USE_RESULT static MaybeObject* Allocate(int number_of_transitions);
- bool IsSimpleTransition() { return length() == kSimpleTransitionSize; }
- bool IsFullTransitionArray() { return length() >= kFirstIndex; }
+ bool IsSimpleTransition() {
+ return length() == kSimpleTransitionSize &&
+ get(kSimpleTransitionTarget)->IsHeapObject() &&
+ // The IntrusivePrototypeTransitionIterator may have set the map of the
+ // prototype transitions array to a smi. In that case, there are
+ // prototype transitions, hence this transition array is a full
+ // transition array.
+ HeapObject::cast(get(kSimpleTransitionTarget))->map()->IsMap() &&
+ get(kSimpleTransitionTarget)->IsMap();
+ }
+
+ bool IsFullTransitionArray() {
+ return length() > kFirstIndex ||
+ (length() == kFirstIndex && !IsSimpleTransition());
+ }
// Casting.
static inline TransitionArray* cast(Object* obj);
@@ -139,9 +146,8 @@
static const int kBackPointerStorageIndex = 0;
// Layout for full transition arrays.
- static const int kElementsTransitionIndex = 1;
- static const int kPrototypeTransitionsIndex = 2;
- static const int kFirstIndex = 3;
+ static const int kPrototypeTransitionsIndex = 1;
+ static const int kFirstIndex = 2;
// Layout for simple transition arrays.
static const int kSimpleTransitionTarget = 1;
@@ -152,9 +158,7 @@
static const int kBackPointerStorageOffset = FixedArray::kHeaderSize;
// Layout for the full transition array header.
- static const int kElementsTransitionOffset = kBackPointerStorageOffset +
- kPointerSize;
- static const int kPrototypeTransitionsOffset = kElementsTransitionOffset +
+ static const int kPrototypeTransitionsOffset = kBackPointerStorageOffset +
kPointerSize;
// Layout of map transition entries in full transition arrays.
diff --git a/src/typedarray.js b/src/typedarray.js
index d5357b4..7bd16f6 100644
--- a/src/typedarray.js
+++ b/src/typedarray.js
@@ -77,11 +77,10 @@
function ConstructByArrayLike(obj, arrayLike) {
var length = arrayLike.length;
var l = ToPositiveInteger(length, "invalid_typed_array_length");
- var byteLength = l * elementSize;
- var buffer = new $ArrayBuffer(byteLength);
- %TypedArrayInitialize(obj, arrayId, buffer, 0, byteLength);
- for (var i = 0; i < l; i++) {
- obj[i] = arrayLike[i];
+ if(!%TypedArrayInitializeFromArrayLike(obj, arrayId, arrayLike, l)) {
+ for (var i = 0; i < l; i++) {
+ obj[i] = arrayLike[i];
+ }
}
}
@@ -144,30 +143,103 @@
}
}
+function TypedArraySetFromArrayLike(target, source, sourceLength, offset) {
+ if (offset > 0) {
+ for (var i = 0; i < sourceLength; i++) {
+ target[offset + i] = source[i];
+ }
+ }
+ else {
+ for (var i = 0; i < sourceLength; i++) {
+ target[i] = source[i];
+ }
+ }
+}
+
+function TypedArraySetFromOverlappingTypedArray(target, source, offset) {
+ var sourceElementSize = source.BYTES_PER_ELEMENT;
+ var targetElementSize = target.BYTES_PER_ELEMENT;
+ var sourceLength = source.length;
+
+ // Copy left part.
+ function CopyLeftPart() {
+ // First un-mutated byte after the next write
+ var targetPtr = target.byteOffset + (offset + 1) * targetElementSize;
+ // Next read at sourcePtr. We do not care for memory changing before
+ // sourcePtr - we have already copied it.
+ var sourcePtr = source.byteOffset;
+ for (var leftIndex = 0;
+ leftIndex < sourceLength && targetPtr <= sourcePtr;
+ leftIndex++) {
+ target[offset + leftIndex] = source[leftIndex];
+ targetPtr += targetElementSize;
+ sourcePtr += sourceElementSize;
+ }
+ return leftIndex;
+ }
+ var leftIndex = CopyLeftPart();
+
+ // Copy rigth part;
+ function CopyRightPart() {
+ // First unmutated byte before the next write
+ var targetPtr =
+ target.byteOffset + (offset + sourceLength - 1) * targetElementSize;
+ // Next read before sourcePtr. We do not care for memory changing after
+ // sourcePtr - we have already copied it.
+ var sourcePtr =
+ source.byteOffset + sourceLength * sourceElementSize;
+ for(var rightIndex = sourceLength - 1;
+ rightIndex >= leftIndex && targetPtr >= sourcePtr;
+ rightIndex--) {
+ target[offset + rightIndex] = source[rightIndex];
+ targetPtr -= targetElementSize;
+ sourcePtr -= sourceElementSize;
+ }
+ return rightIndex;
+ }
+ var rightIndex = CopyRightPart();
+
+ var temp = new $Array(rightIndex + 1 - leftIndex);
+ for (var i = leftIndex; i <= rightIndex; i++) {
+ temp[i - leftIndex] = source[i];
+ }
+ for (i = leftIndex; i <= rightIndex; i++) {
+ target[offset + i] = temp[i - leftIndex];
+ }
+}
+
function TypedArraySet(obj, offset) {
var intOffset = IS_UNDEFINED(offset) ? 0 : TO_INTEGER(offset);
if (intOffset < 0) {
throw MakeTypeError("typed_array_set_negative_offset");
}
- if (%TypedArraySetFastCases(this, obj, intOffset))
- return;
-
- var l = obj.length;
- if (IS_UNDEFINED(l)) {
- if (IS_NUMBER(obj)) {
- // For number as a first argument, throw TypeError
- // instead of silently ignoring the call, so that
- // the user knows (s)he did something wrong.
- // (Consistent with Firefox and Blink/WebKit)
- throw MakeTypeError("invalid_argument");
- }
- return;
- }
- if (intOffset + l > this.length) {
- throw MakeRangeError("typed_array_set_source_too_large");
- }
- for (var i = 0; i < l; i++) {
- this[intOffset + i] = obj[i];
+ switch (%TypedArraySetFastCases(this, obj, intOffset)) {
+ // These numbers should be synchronized with runtime.cc.
+ case 0: // TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE
+ return;
+ case 1: // TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING
+ TypedArraySetFromOverlappingTypedArray(this, obj, intOffset);
+ return;
+ case 2: // TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING
+ TypedArraySetFromArrayLike(this, obj, obj.length, intOffset);
+ return;
+ case 3: // TYPED_ARRAY_SET_NON_TYPED_ARRAY
+ var l = obj.length;
+ if (IS_UNDEFINED(l)) {
+ if (IS_NUMBER(obj)) {
+ // For number as a first argument, throw TypeError
+ // instead of silently ignoring the call, so that
+ // the user knows (s)he did something wrong.
+ // (Consistent with Firefox and Blink/WebKit)
+ throw MakeTypeError("invalid_argument");
+ }
+ return;
+ }
+ if (intOffset + l > this.length) {
+ throw MakeRangeError("typed_array_set_source_too_large");
+ }
+ TypedArraySetFromArrayLike(this, obj, l, intOffset);
+ return;
}
}
diff --git a/src/version.cc b/src/version.cc
index 02e5d6c..be0a4b5 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,8 +34,8 @@
// system so their names cannot be changed without changing the scripts.
#define MAJOR_VERSION 3
#define MINOR_VERSION 20
-#define BUILD_NUMBER 11
-#define PATCH_LEVEL 2
+#define BUILD_NUMBER 12
+#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
#define IS_CANDIDATE_VERSION 0
diff --git a/src/x64/frames-x64.h b/src/x64/frames-x64.h
index a24ab53..2af5a81 100644
--- a/src/x64/frames-x64.h
+++ b/src/x64/frames-x64.h
@@ -126,6 +126,12 @@
return Memory::Object_at(fp() + offset);
}
+
+inline void StackHandler::SetFp(Address slot, Address fp) {
+ Memory::Address_at(slot) = fp;
+}
+
+
} } // namespace v8::internal
#endif // V8_X64_FRAMES_X64_H_
diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc
index f26b234..6e238c7 100644
--- a/src/x64/ic-x64.cc
+++ b/src/x64/ic-x64.cc
@@ -1610,55 +1610,6 @@
}
-void KeyedStoreIC::GenerateTransitionElementsSmiToDouble(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- rbx : target map
- // -- rdx : receiver
- // -- rsp[0] : return address
- // -----------------------------------
- // Must return the modified receiver in eax.
- if (!FLAG_trace_elements_transitions) {
- Label fail;
- AllocationSiteMode mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS,
- FAST_DOUBLE_ELEMENTS);
- ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, &fail);
- __ movq(rax, rdx);
- __ Ret();
- __ bind(&fail);
- }
-
- __ pop(rbx);
- __ push(rdx);
- __ push(rbx); // return address
- __ TailCallRuntime(Runtime::kTransitionElementsSmiToDouble, 1, 1);
-}
-
-
-void KeyedStoreIC::GenerateTransitionElementsDoubleToObject(
- MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- rbx : target map
- // -- rdx : receiver
- // -- rsp[0] : return address
- // -----------------------------------
- // Must return the modified receiver in eax.
- if (!FLAG_trace_elements_transitions) {
- Label fail;
- AllocationSiteMode mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS,
- FAST_ELEMENTS);
- ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, &fail);
- __ movq(rax, rdx);
- __ Ret();
- __ bind(&fail);
- }
-
- __ pop(rbx);
- __ push(rdx);
- __ push(rbx); // return address
- __ TailCallRuntime(Runtime::kTransitionElementsDoubleToObject, 1, 1);
-}
-
-
#undef __
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index 364c3a1..f84c357 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -120,6 +120,16 @@
}
+#ifdef _MSC_VER
+void LCodeGen::MakeSureStackPagesMapped(int offset) {
+ const int kPageSize = 4 * KB;
+ for (offset -= kPageSize; offset > 0; offset -= kPageSize) {
+ __ movq(Operand(rsp, offset), rax);
+ }
+}
+#endif
+
+
bool LCodeGen::GeneratePrologue() {
ASSERT(is_generating());
@@ -169,6 +179,9 @@
if (slots > 0) {
if (FLAG_debug_code) {
__ subq(rsp, Immediate(slots * kPointerSize));
+#ifdef _MSC_VER
+ MakeSureStackPagesMapped(slots * kPointerSize);
+#endif
__ push(rax);
__ Set(rax, slots);
__ movq(kScratchRegister, kSlotsZapValue, RelocInfo::NONE64);
@@ -182,15 +195,7 @@
} else {
__ subq(rsp, Immediate(slots * kPointerSize));
#ifdef _MSC_VER
- // On windows, you may not access the stack more than one page below
- // the most recently mapped page. To make the allocated area randomly
- // accessible, we write to each page in turn (the value is irrelevant).
- const int kPageSize = 4 * KB;
- for (int offset = slots * kPointerSize - kPageSize;
- offset > 0;
- offset -= kPageSize) {
- __ movq(Operand(rsp, offset), rax);
- }
+ MakeSureStackPagesMapped(slots * kPointerSize);
#endif
}
@@ -429,6 +434,13 @@
}
+ExternalReference LCodeGen::ToExternalReference(LConstantOperand* op) const {
+ HConstant* constant = chunk_->LookupConstant(op);
+ ASSERT(constant->HasExternalReferenceValue());
+ return constant->ExternalReferenceValue();
+}
+
+
Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
HConstant* constant = chunk_->LookupConstant(op);
ASSERT(chunk_->LookupLiteralRepresentation(op).IsSmiOrTagged());
@@ -1453,7 +1465,11 @@
break;
case Token::SHL:
if (shift_count != 0) {
- __ shll(ToRegister(left), Immediate(shift_count));
+ if (instr->hydrogen_value()->representation().IsSmi()) {
+ __ shl(ToRegister(left), Immediate(shift_count));
+ } else {
+ __ shll(ToRegister(left), Immediate(shift_count));
+ }
}
break;
default:
@@ -1519,6 +1535,11 @@
}
+void LCodeGen::DoConstantE(LConstantE* instr) {
+ __ LoadAddress(ToRegister(instr->result()), instr->value());
+}
+
+
void LCodeGen::DoConstantT(LConstantT* instr) {
Handle<Object> value = instr->value();
AllowDeferredHandleDereference smi_check;
@@ -1699,7 +1720,7 @@
LOperand* right = instr->right();
ASSERT(left->Equals(instr->result()));
HMathMinMax::Operation operation = instr->hydrogen()->operation();
- if (instr->hydrogen()->representation().IsInteger32()) {
+ if (instr->hydrogen()->representation().IsSmiOrInteger32()) {
Label return_left;
Condition condition = (operation == HMathMinMax::kMathMin)
? less_equal
@@ -1708,17 +1729,26 @@
if (right->IsConstantOperand()) {
Immediate right_imm =
Immediate(ToInteger32(LConstantOperand::cast(right)));
+ ASSERT(!instr->hydrogen_value()->representation().IsSmi());
__ cmpl(left_reg, right_imm);
__ j(condition, &return_left, Label::kNear);
__ movq(left_reg, right_imm);
} else if (right->IsRegister()) {
Register right_reg = ToRegister(right);
- __ cmpl(left_reg, right_reg);
+ if (instr->hydrogen_value()->representation().IsSmi()) {
+ __ cmpq(left_reg, right_reg);
+ } else {
+ __ cmpl(left_reg, right_reg);
+ }
__ j(condition, &return_left, Label::kNear);
__ movq(left_reg, right_reg);
} else {
Operand right_op = ToOperand(right);
- __ cmpl(left_reg, right_op);
+ if (instr->hydrogen_value()->representation().IsSmi()) {
+ __ cmpq(left_reg, right_op);
+ } else {
+ __ cmpl(left_reg, right_op);
+ }
__ j(condition, &return_left, Label::kNear);
__ movq(left_reg, right_op);
}
@@ -2609,16 +2639,6 @@
}
-void LCodeGen::DoLinkObjectInList(LLinkObjectInList* instr) {
- Register object = ToRegister(instr->object());
- ExternalReference sites_list_address = instr->GetReference(isolate());
- __ Load(kScratchRegister, sites_list_address);
- __ movq(FieldOperand(object, instr->hydrogen()->store_field().offset()),
- kScratchRegister);
- __ Store(sites_list_address, object);
-}
-
-
void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
Register context = ToRegister(instr->context());
Register result = ToRegister(instr->result());
@@ -2676,6 +2696,19 @@
void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
HObjectAccess access = instr->hydrogen()->access();
int offset = access.offset();
+
+ if (access.IsExternalMemory()) {
+ Register result = ToRegister(instr->result());
+ if (instr->object()->IsConstantOperand()) {
+ ASSERT(result.is(rax));
+ __ load_rax(ToExternalReference(LConstantOperand::cast(instr->object())));
+ } else {
+ Register object = ToRegister(instr->object());
+ __ movq(result, MemOperand(object, offset));
+ }
+ return;
+ }
+
Register object = ToRegister(instr->object());
if (FLAG_track_double_fields &&
instr->hydrogen()->representation().IsDouble()) {
@@ -2742,9 +2775,6 @@
int i,
Isolate* isolate) {
Handle<Map> map = list->at(i);
- // If the map has ElementsKind transitions, we will generate map checks
- // for each kind in __ CompareMap(..., ALLOW_ELEMENTS_TRANSITION_MAPS).
- if (map->HasElementsTransition()) return false;
LookupResult lookup(isolate);
map->LookupDescriptor(NULL, *name, &lookup);
return lookup.IsField() || lookup.IsConstant();
@@ -3913,11 +3943,24 @@
void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
Representation representation = instr->representation();
- Register object = ToRegister(instr->object());
-
HObjectAccess access = instr->hydrogen()->access();
int offset = access.offset();
+ if (access.IsExternalMemory()) {
+ ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
+ Register value = ToRegister(instr->value());
+ if (instr->object()->IsConstantOperand()) {
+ ASSERT(value.is(rax));
+ LConstantOperand* object = LConstantOperand::cast(instr->object());
+ __ store_rax(ToExternalReference(object));
+ } else {
+ Register object = ToRegister(instr->object());
+ __ movq(MemOperand(object, offset), value);
+ }
+ return;
+ }
+
+ Register object = ToRegister(instr->object());
Handle<Map> transition = instr->transition();
if (FLAG_track_fields && representation.IsSmi()) {
@@ -4275,7 +4318,7 @@
ASSERT_NE(instr->temp(), NULL);
__ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg,
ToRegister(instr->temp()), kDontSaveFPRegs);
- } else if (FLAG_compiled_transitions) {
+ } else {
PushSafepointRegistersScope scope(this);
if (!object_reg.is(rax)) {
__ movq(rax, object_reg);
@@ -4285,28 +4328,6 @@
__ CallStub(&stub);
RecordSafepointWithRegisters(
instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
- } else if (IsFastSmiElementsKind(from_kind) &&
- IsFastDoubleElementsKind(to_kind)) {
- Register fixed_object_reg = ToRegister(instr->temp());
- ASSERT(fixed_object_reg.is(rdx));
- Register new_map_reg = ToRegister(instr->new_map_temp());
- ASSERT(new_map_reg.is(rbx));
- __ movq(new_map_reg, to_map, RelocInfo::EMBEDDED_OBJECT);
- __ movq(fixed_object_reg, object_reg);
- CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(),
- RelocInfo::CODE_TARGET, instr);
- } else if (IsFastDoubleElementsKind(from_kind) &&
- IsFastObjectElementsKind(to_kind)) {
- Register fixed_object_reg = ToRegister(instr->temp());
- ASSERT(fixed_object_reg.is(rdx));
- Register new_map_reg = ToRegister(instr->new_map_temp());
- ASSERT(new_map_reg.is(rbx));
- __ movq(new_map_reg, to_map, RelocInfo::EMBEDDED_OBJECT);
- __ movq(fixed_object_reg, object_reg);
- CallCode(isolate()->builtins()->TransitionElementsDoubleToObject(),
- RelocInfo::CODE_TARGET, instr);
- } else {
- UNREACHABLE();
}
__ bind(¬_applicable);
}
@@ -4429,13 +4450,6 @@
}
-void LCodeGen::DoStringLength(LStringLength* instr) {
- Register string = ToRegister(instr->string());
- Register result = ToRegister(instr->result());
- __ movq(result, FieldOperand(string, String::kLengthOffset));
-}
-
-
void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
LOperand* input = instr->value();
ASSERT(input->IsRegister() || input->IsStackSlot());
@@ -5063,10 +5077,12 @@
if (instr->hydrogen()->MustAllocateDoubleAligned()) {
flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
}
- if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
- ASSERT(!instr->hydrogen()->CanAllocateInOldDataSpace());
+ if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
+ ASSERT(!instr->hydrogen()->IsOldDataSpaceAllocation());
+ ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
- } else if (instr->hydrogen()->CanAllocateInOldDataSpace()) {
+ } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
+ ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_DATA_SPACE);
}
@@ -5118,10 +5134,12 @@
__ Push(Smi::FromInt(size));
}
- if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
- ASSERT(!instr->hydrogen()->CanAllocateInOldDataSpace());
+ if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
+ ASSERT(!instr->hydrogen()->IsOldDataSpaceAllocation());
+ ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
CallRuntimeFromDeferred(Runtime::kAllocateInOldPointerSpace, 1, instr);
- } else if (instr->hydrogen()->CanAllocateInOldDataSpace()) {
+ } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
+ ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
CallRuntimeFromDeferred(Runtime::kAllocateInOldDataSpace, 1, instr);
} else {
CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr);
diff --git a/src/x64/lithium-codegen-x64.h b/src/x64/lithium-codegen-x64.h
index 5ad1c40..4286d07 100644
--- a/src/x64/lithium-codegen-x64.h
+++ b/src/x64/lithium-codegen-x64.h
@@ -106,6 +106,7 @@
int32_t ToInteger32(LConstantOperand* op) const;
Smi* ToSmi(LConstantOperand* op) const;
double ToDouble(LConstantOperand* op) const;
+ ExternalReference ToExternalReference(LConstantOperand* op) const;
bool IsTaggedConstant(LConstantOperand* op) const;
Handle<Object> ToHandle(LConstantOperand* op) const;
Operand ToOperand(LOperand* op) const;
@@ -344,6 +345,13 @@
void DoStoreKeyedExternalArray(LStoreKeyed* instr);
void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr);
void DoStoreKeyedFixedArray(LStoreKeyed* instr);
+#ifdef _MSC_VER
+ // On windows, you may not access the stack more than one page below
+ // the most recently mapped page. To make the allocated area randomly
+ // accessible, we write an arbitrary value to each page in range
+ // rsp + offset - page_size .. rsp in turn.
+ void MakeSureStackPagesMapped(int offset);
+#endif
Zone* zone_;
LPlatformChunk* const chunk_;
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index d6f05c0..e403165 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -275,24 +275,6 @@
}
-ExternalReference LLinkObjectInList::GetReference(Isolate* isolate) {
- switch (hydrogen()->known_list()) {
- case HLinkObjectInList::ALLOCATION_SITE_LIST:
- return ExternalReference::allocation_sites_list_address(isolate);
- }
-
- UNREACHABLE();
- // Return a dummy value
- return ExternalReference::isolate_address(isolate);
-}
-
-
-void LLinkObjectInList::PrintDataTo(StringStream* stream) {
- object()->PrintTo(stream);
- stream->Add(" offset %d", hydrogen()->store_field().offset());
-}
-
-
void LLoadContextSlot::PrintDataTo(StringStream* stream) {
context()->PrintTo(stream);
stream->Add("[%d]", slot_index());
@@ -717,9 +699,9 @@
LInstruction* LChunkBuilder::DoShift(Token::Value op,
HBitwiseBinaryOperation* instr) {
- if (instr->representation().IsSmiOrTagged()) {
- ASSERT(instr->left()->representation().IsSmiOrTagged());
- ASSERT(instr->right()->representation().IsSmiOrTagged());
+ if (instr->representation().IsTagged()) {
+ ASSERT(instr->left()->representation().IsTagged());
+ ASSERT(instr->right()->representation().IsTagged());
LOperand* left = UseFixed(instr->left(), rdx);
LOperand* right = UseFixed(instr->right(), rax);
@@ -727,9 +709,9 @@
return MarkAsCall(DefineFixed(result, rax), instr);
}
- ASSERT(instr->representation().IsInteger32());
- ASSERT(instr->left()->representation().IsInteger32());
- ASSERT(instr->right()->representation().IsInteger32());
+ ASSERT(instr->representation().IsSmiOrInteger32());
+ ASSERT(instr->left()->representation().Equals(instr->representation()));
+ ASSERT(instr->right()->representation().Equals(instr->representation()));
LOperand* left = UseRegisterAtStart(instr->left());
HValue* right_value = instr->right();
@@ -1562,9 +1544,9 @@
LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
LOperand* left = NULL;
LOperand* right = NULL;
- if (instr->representation().IsInteger32()) {
- ASSERT(instr->left()->representation().IsInteger32());
- ASSERT(instr->right()->representation().IsInteger32());
+ if (instr->representation().IsSmiOrInteger32()) {
+ ASSERT(instr->left()->representation().Equals(instr->representation()));
+ ASSERT(instr->right()->representation().Equals(instr->representation()));
left = UseRegisterAtStart(instr->BetterLeftOperand());
right = UseOrConstantAtStart(instr->BetterRightOperand());
} else {
@@ -1997,6 +1979,8 @@
} else if (r.IsDouble()) {
LOperand* temp = TempRegister();
return DefineAsRegister(new(zone()) LConstantD(temp));
+ } else if (r.IsExternal()) {
+ return DefineAsRegister(new(zone()) LConstantE);
} else if (r.IsTagged()) {
return DefineAsRegister(new(zone()) LConstantT);
} else {
@@ -2040,13 +2024,6 @@
}
-LInstruction* LChunkBuilder::DoLinkObjectInList(HLinkObjectInList* instr) {
- LOperand* object = UseRegister(instr->value());
- LLinkObjectInList* result = new(zone()) LLinkObjectInList(object);
- return result;
-}
-
-
LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
LOperand* context = UseRegisterAtStart(instr->value());
LInstruction* result =
@@ -2074,6 +2051,10 @@
LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
+ if (instr->access().IsExternalMemory() && instr->access().offset() == 0) {
+ LOperand* obj = UseRegisterOrConstantAtStart(instr->object());
+ return DefineFixed(new(zone()) LLoadNamedField(obj), rax);
+ }
LOperand* obj = UseRegisterAtStart(instr->object());
return DefineAsRegister(new(zone()) LLoadNamedField(obj));
}
@@ -2229,19 +2210,10 @@
LTransitionElementsKind* result =
new(zone()) LTransitionElementsKind(object, new_map_reg, temp_reg);
return result;
- } else if (FLAG_compiled_transitions) {
+ } else {
LTransitionElementsKind* result =
new(zone()) LTransitionElementsKind(object, NULL, NULL);
return AssignPointerMap(result);
- } else {
- LOperand* object = UseFixed(instr->object(), rax);
- LOperand* fixed_object_reg = FixedTemp(rdx);
- LOperand* new_map_reg = FixedTemp(rbx);
- LTransitionElementsKind* result =
- new(zone()) LTransitionElementsKind(object,
- new_map_reg,
- fixed_object_reg);
- return MarkAsCall(result, instr);
}
}
@@ -2258,6 +2230,8 @@
LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
bool is_in_object = instr->access().IsInobject();
+ bool is_external_location = instr->access().IsExternalMemory() &&
+ instr->access().offset() == 0;
bool needs_write_barrier = instr->NeedsWriteBarrier();
bool needs_write_barrier_for_map = !instr->transition().is_null() &&
instr->NeedsWriteBarrierForMap();
@@ -2267,6 +2241,11 @@
obj = is_in_object
? UseRegister(instr->object())
: UseTempRegister(instr->object());
+ } else if (is_external_location) {
+ ASSERT(!is_in_object);
+ ASSERT(!needs_write_barrier);
+ ASSERT(!needs_write_barrier_for_map);
+ obj = UseRegisterOrConstant(instr->object());
} else {
obj = needs_write_barrier_for_map
? UseRegister(instr->object())
@@ -2280,6 +2259,8 @@
LOperand* val;
if (needs_write_barrier) {
val = UseTempRegister(instr->value());
+ } else if (is_external_location) {
+ val = UseFixed(instr->value(), rax);
} else if (can_be_constant) {
val = UseRegisterOrConstant(instr->value());
} else if (FLAG_track_fields && instr->field_representation().IsSmi()) {
@@ -2339,12 +2320,6 @@
}
-LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) {
- LOperand* string = UseRegisterAtStart(instr->value());
- return DefineAsRegister(new(zone()) LStringLength(string));
-}
-
-
LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) {
info()->MarkAsDeferredCalling();
LOperand* size = instr->size()->IsConstant()
diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h
index 50e32d8..31e5437 100644
--- a/src/x64/lithium-x64.h
+++ b/src/x64/lithium-x64.h
@@ -79,6 +79,7 @@
V(CmpMapAndBranch) \
V(CmpT) \
V(ConstantD) \
+ V(ConstantE) \
V(ConstantI) \
V(ConstantS) \
V(ConstantT) \
@@ -118,7 +119,6 @@
V(IsUndetectableAndBranch) \
V(Label) \
V(LazyBailout) \
- V(LinkObjectInList) \
V(LoadContextSlot) \
V(LoadExternalArrayPointer) \
V(LoadFieldByIndex) \
@@ -173,7 +173,6 @@
V(StringCharCodeAt) \
V(StringCharFromCode) \
V(StringCompareAndBranch) \
- V(StringLength) \
V(SubI) \
V(TaggedToI) \
V(ThisFunction) \
@@ -266,7 +265,7 @@
bool IsMarkedAsCall() const { return is_call_; }
virtual bool HasResult() const = 0;
- virtual LOperand* result() = 0;
+ virtual LOperand* result() const = 0;
LOperand* FirstInput() { return InputAt(0); }
LOperand* Output() { return HasResult() ? result() : NULL; }
@@ -302,9 +301,9 @@
public:
// Allow 0 or 1 output operands.
STATIC_ASSERT(R == 0 || R == 1);
- virtual bool HasResult() const { return R != 0; }
+ virtual bool HasResult() const { return R != 0 && result() != NULL; }
void set_result(LOperand* operand) { results_[0] = operand; }
- LOperand* result() { return results_[0]; }
+ LOperand* result() const { return results_[0]; }
protected:
EmbeddedContainer<LOperand*, R> results_;
@@ -1166,6 +1165,17 @@
};
+class LConstantE: public LTemplateInstruction<1, 0, 0> {
+ public:
+ DECLARE_CONCRETE_INSTRUCTION(ConstantE, "constant-e")
+ DECLARE_HYDROGEN_ACCESSOR(Constant)
+
+ ExternalReference value() const {
+ return hydrogen()->ExternalReferenceValue();
+ }
+};
+
+
class LConstantT: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(ConstantT, "constant-t")
@@ -1601,23 +1611,6 @@
};
-class LLinkObjectInList: public LTemplateInstruction<0, 1, 0> {
- public:
- explicit LLinkObjectInList(LOperand* object) {
- inputs_[0] = object;
- }
-
- LOperand* object() { return inputs_[0]; }
-
- ExternalReference GetReference(Isolate* isolate);
-
- DECLARE_CONCRETE_INSTRUCTION(LinkObjectInList, "link-object-in-list")
- DECLARE_HYDROGEN_ACCESSOR(LinkObjectInList)
-
- virtual void PrintDataTo(StringStream* stream);
-};
-
-
class LLoadContextSlot: public LTemplateInstruction<1, 1, 0> {
public:
explicit LLoadContextSlot(LOperand* context) {
@@ -2230,19 +2223,6 @@
};
-class LStringLength: public LTemplateInstruction<1, 1, 0> {
- public:
- explicit LStringLength(LOperand* string) {
- inputs_[0] = string;
- }
-
- LOperand* string() { return inputs_[0]; }
-
- DECLARE_CONCRETE_INSTRUCTION(StringLength, "string-length")
- DECLARE_HYDROGEN_ACCESSOR(StringLength)
-};
-
-
class LCheckFunction: public LTemplateInstruction<0, 1, 0> {
public:
explicit LCheckFunction(LOperand* value) {
diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h
index 9d5d2a3..e611c8a 100644
--- a/src/x64/macro-assembler-x64.h
+++ b/src/x64/macro-assembler-x64.h
@@ -1518,6 +1518,10 @@
}
+inline Operand StackOperandForReturnAddress(int32_t disp) {
+ return Operand(rsp, disp);
+}
+
#ifdef GENERATED_CODE_COVERAGE
extern void LogGeneratedCodeCoverage(const char* file_line);
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
index 542018f..39ff656 100644
--- a/src/x64/stub-cache-x64.cc
+++ b/src/x64/stub-cache-x64.cc
@@ -410,9 +410,9 @@
// -- rsp[0] : return address
// -- rsp[8] : last argument in the internal frame of the caller
// -----------------------------------
- __ movq(scratch, Operand(rsp, 0));
+ __ movq(scratch, StackOperandForReturnAddress(0));
__ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
- __ movq(Operand(rsp, 0), scratch);
+ __ movq(StackOperandForReturnAddress(0), scratch);
__ Move(scratch, Smi::FromInt(0));
for (int i = 1; i <= kFastApiCallArguments; i++) {
__ movq(Operand(rsp, i * kPointerSize), scratch);
@@ -431,8 +431,9 @@
// -- rsp[kFastApiCallArguments * 8 + 8] : last argument in the internal
// frame.
// -----------------------------------
- __ movq(scratch, Operand(rsp, 0));
- __ movq(Operand(rsp, kFastApiCallArguments * kPointerSize), scratch);
+ __ movq(scratch, StackOperandForReturnAddress(0));
+ __ movq(StackOperandForReturnAddress(kFastApiCallArguments * kPointerSize),
+ scratch);
__ addq(rsp, Immediate(kPointerSize * kFastApiCallArguments));
}
@@ -2350,8 +2351,9 @@
name, depth, &miss);
// Move the return address on top of the stack.
- __ movq(rax, Operand(rsp, kFastApiCallArguments * kPointerSize));
- __ movq(Operand(rsp, 0 * kPointerSize), rax);
+ __ movq(rax,
+ StackOperandForReturnAddress(kFastApiCallArguments * kPointerSize));
+ __ movq(StackOperandForReturnAddress(0), rax);
GenerateFastApiCall(masm(), optimization, argc);