void EmitPush(Register reg);
// Push an element on the virtual frame.
- void Push(Register reg, StaticType static_type = StaticType());
+ void Push(Register reg);
void Push(Handle<Object> value);
void Push(Smi* value) { Push(Handle<Object>(value)); }
// Pushing a result invalidates it (its contents become owned by the frame).
void Push(Result* result) {
if (result->is_register()) {
- Push(result->reg(), result->static_type());
+ Push(result->reg());
} else {
ASSERT(result->is_constant());
Push(result->handle());
// The default constructor creates an invalid frame element.
FrameElement() {
- value_ = StaticTypeField::encode(StaticType::UNKNOWN_TYPE)
- | TypeField::encode(INVALID)
+ value_ = TypeField::encode(INVALID)
| CopiedField::encode(false)
| SyncedField::encode(false)
| DataField::encode(0);
// Factory function to construct an in-register frame element.
static FrameElement RegisterElement(Register reg,
- SyncFlag is_synced,
- StaticType static_type = StaticType()) {
- return FrameElement(REGISTER, reg, is_synced, static_type);
+ SyncFlag is_synced) {
+ return FrameElement(REGISTER, reg, is_synced);
}
// Factory function to construct a frame element whose value is known at
return DataField::decode(value_);
}
- StaticType static_type() {
- return StaticType(StaticTypeField::decode(value_));
- }
-
- void set_static_type(StaticType static_type) {
- value_ = value_ & ~StaticTypeField::mask();
- value_ = value_ | StaticTypeField::encode(static_type.static_type_);
- }
-
bool Equals(FrameElement other) {
uint32_t masked_difference = (value_ ^ other.value_) & ~CopiedField::mask();
if (!masked_difference) {
if (!other->is_valid()) return other;
if (!SameLocation(other)) return NULL;
- // If either is unsynced, the result is. The result static type is
- // the merge of the static types. It's safe to set it on one of the
- // frame elements, and harmless too (because we are only going to
- // merge the reaching frames and will ensure that the types are
- // coherent, and changing the static type does not emit code).
+ // If either is unsynced, the result is.
FrameElement* result = is_synced() ? other : this;
- result->set_static_type(static_type().merge(other->static_type()));
return result;
}
// Used to construct memory and register elements.
FrameElement(Type type, Register reg, SyncFlag is_synced) {
- value_ = StaticTypeField::encode(StaticType::UNKNOWN_TYPE)
- | TypeField::encode(type)
- | CopiedField::encode(false)
- | SyncedField::encode(is_synced != NOT_SYNCED)
- | DataField::encode(reg.code_ > 0 ? reg.code_ : 0);
- }
-
- FrameElement(Type type, Register reg, SyncFlag is_synced, StaticType stype) {
- value_ = StaticTypeField::encode(stype.static_type_)
- | TypeField::encode(type)
+ value_ = TypeField::encode(type)
| CopiedField::encode(false)
| SyncedField::encode(is_synced != NOT_SYNCED)
| DataField::encode(reg.code_ > 0 ? reg.code_ : 0);
// Used to construct constant elements.
FrameElement(Handle<Object> value, SyncFlag is_synced) {
- value_ = StaticTypeField::encode(StaticType::TypeOf(*value).static_type_)
- | TypeField::encode(CONSTANT)
+ value_ = TypeField::encode(CONSTANT)
| CopiedField::encode(false)
| SyncedField::encode(is_synced != NOT_SYNCED)
| DataField::encode(ConstantList()->length());
value_ = value_ | DataField::encode(new_reg.code_);
}
- // Encode static type, type, copied, synced and data in one 32 bit integer.
+ // Encode type, copied, synced and data in one 32 bit integer.
uint32_t value_;
- class StaticTypeField: public BitField<StaticType::StaticTypeEnum, 0, 3> {};
- class TypeField: public BitField<Type, 3, 3> {};
- class CopiedField: public BitField<uint32_t, 6, 1> {};
- class SyncedField: public BitField<uint32_t, 7, 1> {};
- class DataField: public BitField<uint32_t, 8, 32 - 9> {};
+ class TypeField: public BitField<Type, 0, 3> {};
+ class CopiedField: public BitField<uint32_t, 3, 1> {};
+ class SyncedField: public BitField<uint32_t, 4, 1> {};
+ class DataField: public BitField<uint32_t, 5, 32 - 6> {};
friend class VirtualFrame;
};
Result left = frame_->Pop();
if (op == Token::ADD) {
- bool left_is_string = left.static_type().is_jsstring();
- bool right_is_string = right.static_type().is_jsstring();
+ bool left_is_string = left.is_constant() && left.handle()->IsString();
+ bool right_is_string = right.is_constant() && right.handle()->IsString();
if (left_is_string || right_is_string) {
frame_->Push(&left);
frame_->Push(&right);
Result answer;
if (left_is_string) {
if (right_is_string) {
- // TODO(lrn): if (left.is_constant() && right.is_constant())
+ // TODO(lrn): if both are constant strings
// -- do a compile time cons, if allocation during codegen is allowed.
answer = frame_->CallRuntime(Runtime::kStringAdd, 2);
} else {
answer =
frame_->InvokeBuiltin(Builtins::STRING_ADD_RIGHT, CALL_FUNCTION, 2);
}
- answer.set_static_type(StaticType::jsstring());
frame_->Push(&answer);
return;
}
// result.
__ bind(&call_runtime);
switch (op_) {
- case Token::ADD:
+ case Token::ADD: {
+ // Test for string arguments before calling runtime.
+ Label not_strings, both_strings, not_string1, string1;
+ Result answer;
+ __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument.
+ __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument.
+ __ test(eax, Immediate(kSmiTagMask));
+ __ j(zero, ¬_string1);
+ __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, eax);
+ __ j(above_equal, ¬_string1);
+
+ // First argument is a a string, test second.
+ __ test(edx, Immediate(kSmiTagMask));
+ __ j(zero, &string1);
+ __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, edx);
+ __ j(above_equal, &string1);
+
+ // First and second argument are strings.
+ __ TailCallRuntime(ExternalReference(Runtime::kStringAdd), 2);
+
+ // Only first argument is a string.
+ __ bind(&string1);
+ __ InvokeBuiltin(Builtins::STRING_ADD_LEFT, JUMP_FUNCTION);
+
+ // First argument was not a string, test second.
+ __ bind(¬_string1);
+ __ test(edx, Immediate(kSmiTagMask));
+ __ j(zero, ¬_strings);
+ __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, edx);
+ __ j(above_equal, ¬_strings);
+
+ // Only second argument is a string.
+ __ InvokeBuiltin(Builtins::STRING_ADD_RIGHT, JUMP_FUNCTION);
+
+ __ bind(¬_strings);
+ // Neither argument is a string.
__ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
break;
+ }
case Token::SUB:
__ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
break;
}
}
}
- // No need to set the copied flag---there are no copies.
-
- // Backwards jump targets can never know the type of a value.
- elements_[i].set_static_type(StaticType::unknown());
+ // No need to set the copied flag --- there are no copies.
} else {
// Clear the copy flag of non-constant, non-copy elements.
// They cannot be copied because copies are not allowed.
if (element.is_memory()) {
Result temp = cgen()->allocator()->Allocate();
ASSERT(temp.is_valid());
- temp.set_static_type(element.static_type());
__ pop(temp.reg());
return temp;
}
FrameElement::RegisterElement(temp.reg(), FrameElement::SYNCED);
// Preserve the copy flag on the element.
if (element.is_copied()) new_element.set_copied();
- new_element.set_static_type(element.static_type());
elements_[index] = new_element;
__ mov(temp.reg(), Operand(ebp, fp_relative(index)));
- return Result(temp.reg(), element.static_type());
+ return Result(temp.reg());
} else if (element.is_register()) {
- return Result(element.reg(), element.static_type());
+ return Result(element.reg());
} else {
ASSERT(element.is_constant());
return Result(element.handle());
// as random access to the expression stack elements, locals, and
// parameters.
-class VirtualFrame : public ZoneObject {
+class VirtualFrame: public ZoneObject {
public:
// A utility class to introduce a scope where the virtual frame is
// expected to remain spilled. The constructor spills the code
private:
bool previous_state_;
- CodeGenerator* cgen() { return CodeGeneratorScope::Current(); }
+ CodeGenerator* cgen() {return CodeGeneratorScope::Current();}
};
// An illegal index into the virtual frame.
explicit VirtualFrame(VirtualFrame* original);
CodeGenerator* cgen() { return CodeGeneratorScope::Current(); }
+
MacroAssembler* masm() { return cgen()->masm(); }
// Create a duplicate of an existing valid frame element.
int element_count() { return elements_.length(); }
// The height of the virtual expression stack.
- int height() {
- return element_count() - expression_base_index();
- }
+ int height() { return element_count() - expression_base_index(); }
int register_location(int num) {
ASSERT(num >= 0 && num < RegisterAllocator::kNumRegisters);
void PushReceiverSlotAddress();
// Push the function on top of the frame.
- void PushFunction() { PushFrameSlotAt(function_index()); }
+ void PushFunction() {
+ PushFrameSlotAt(function_index());
+ }
// Save the value of the esi register to the context frame slot.
void SaveContextRegister();
}
// The receiver frame slot.
- Operand Receiver() { return ParameterAt(-1); }
+ Operand Receiver() {
+ return ParameterAt(-1);
+ }
// Push a try-catch or try-finally handler on top of the virtual frame.
void PushTryHandler(HandlerType type);
// Invoke builtin given the number of arguments it expects on (and
// removes from) the stack.
- Result InvokeBuiltin(Builtins::JavaScript id,
- InvokeFlag flag,
- int arg_count);
+ Result InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag, int arg_count);
// Call load IC. Name and receiver are found on top of the frame.
// Receiver is not dropped.
void Drop(int count);
// Drop one element.
- void Drop() { Drop(1); }
+ void Drop() {
+ Drop(1);
+ }
// Duplicate the top element of the frame.
- void Dup() { PushFrameSlotAt(element_count() - 1); }
+ void Dup() {
+ PushFrameSlotAt(element_count() - 1);
+ }
// Pop an element from the top of the expression stack. Returns a
// Result, which may be a constant or a register.
void EmitPush(Immediate immediate);
// Push an element on the virtual frame.
- void Push(Register reg, StaticType static_type = StaticType());
+ void Push(Register reg);
void Push(Handle<Object> value);
- void Push(Smi* value) { Push(Handle<Object>(value)); }
+ void Push(Smi* value) {
+ Push(Handle<Object> (value));
+ }
// Pushing a result invalidates it (its contents become owned by the
// frame).
void Push(Result* result) {
if (result->is_register()) {
- Push(result->reg(), result->static_type());
+ Push(result->reg());
} else {
ASSERT(result->is_constant());
Push(result->handle());
int register_locations_[RegisterAllocator::kNumRegisters];
// The number of frame-allocated locals and parameters respectively.
- int parameter_count() { return cgen()->scope()->num_parameters(); }
- int local_count() { return cgen()->scope()->num_stack_slots(); }
+ int parameter_count() {
+ return cgen()->scope()->num_parameters();
+ }
+ int local_count() {
+ return cgen()->scope()->num_stack_slots();
+ }
// The index of the element that is at the processor's frame pointer
// (the ebp register). The parameters, receiver, and return address
// are below the frame pointer.
- int frame_pointer() { return parameter_count() + 2; }
+ int frame_pointer() {
+ return parameter_count() + 2;
+ }
// The index of the first parameter. The receiver lies below the first
// parameter.
- int param0_index() { return 1; }
+ int param0_index() {
+ return 1;
+ }
// The index of the context slot in the frame. It is immediately
// above the frame pointer.
- int context_index() { return frame_pointer() + 1; }
+ int context_index() {
+ return frame_pointer() + 1;
+ }
// The index of the function slot in the frame. It is above the frame
// pointer and the context slot.
- int function_index() { return frame_pointer() + 2; }
+ int function_index() {
+ return frame_pointer() + 2;
+ }
// The index of the first local. Between the frame pointer and the
// locals lie the context and the function.
- int local0_index() { return frame_pointer() + 3; }
+ int local0_index() {
+ return frame_pointer() + 3;
+ }
// The index of the base of the expression stack.
- int expression_base_index() { return local0_index() + local_count(); }
+ int expression_base_index() {
+ return local0_index() + local_count();
+ }
// Convert a frame index into a frame pointer relative offset into the
// actual stack.
friend class JumpTarget;
};
-
} } // namespace v8::internal
#endif // V8_IA32_VIRTUAL_FRAME_IA32_H_
// frame.
for (int i = 0; i < length; i++) {
FrameElement element = initial_frame->elements_[i];
- // We do not allow copies or constants in bidirectional frames. All
- // elements above the water mark on bidirectional frames have
- // unknown static types.
+ // We do not allow copies or constants in bidirectional frames.
if (direction_ == BIDIRECTIONAL) {
if (element.is_constant() || element.is_copy()) {
elements.Add(NULL);
continue;
}
- // It's safe to change the static type on the initial frame
- // element, see comment in JumpTarget::Combine.
- initial_frame->elements_[i].set_static_type(StaticType::unknown());
}
elements.Add(&initial_frame->elements_[i]);
}
for (int i = length - 1; i >= 0; i--) {
if (elements[i] == NULL) {
// Loop over all the reaching frames to check whether the element
- // is synced on all frames, to count the registers it occupies,
- // and to compute a merged static type.
+ // is synced on all frames and to count the registers it occupies.
bool is_synced = true;
RegisterFile candidate_registers;
int best_count = kMinInt;
int best_reg_num = RegisterAllocator::kInvalidRegister;
- StaticType type; // Initially invalid.
- if (direction_ != BIDIRECTIONAL) {
- type = reaching_frames_[0]->elements_[i].static_type();
- }
-
for (int j = 0; j < reaching_frames_.length(); j++) {
FrameElement element = reaching_frames_[j]->elements_[i];
is_synced = is_synced && element.is_synced();
best_reg_num = num;
}
}
- type = type.merge(element.static_type());
}
// If the value is synced on all frames, put it in memory. This
// memory-to-register move when the value is needed later.
if (is_synced) {
// Already recorded as a memory element.
- entry_frame_->elements_[i].set_static_type(type);
continue;
}
}
}
- if (best_reg_num == RegisterAllocator::kInvalidRegister) {
- // If there was no register found, the element is already
- // recorded as in memory.
- entry_frame_->elements_[i].set_static_type(type);
- } else {
+ if (best_reg_num != RegisterAllocator::kInvalidRegister) {
// If there was a register choice, use it. Preserve the copied
- // flag on the element. Set the static type as computed.
+ // flag on the element.
bool is_copied = entry_frame_->elements_[i].is_copied();
Register reg = RegisterAllocator::ToRegister(best_reg_num);
entry_frame_->elements_[i] =
FrameElement::RegisterElement(reg,
FrameElement::NOT_SYNCED);
if (is_copied) entry_frame_->elements_[i].set_copied();
- entry_frame_->elements_[i].set_static_type(type);
entry_frame_->set_register_location(reg, i);
}
}
Result::Result(Register reg) {
ASSERT(reg.is_valid() && !RegisterAllocator::IsReserved(reg));
CodeGeneratorScope::Current()->allocator()->Use(reg);
- value_ = StaticTypeField::encode(StaticType::UNKNOWN_TYPE)
- | TypeField::encode(REGISTER)
- | DataField::encode(reg.code_);
-}
-
-
-Result::Result(Register reg, StaticType type) {
- ASSERT(reg.is_valid() && !RegisterAllocator::IsReserved(reg));
- CodeGeneratorScope::Current()->allocator()->Use(reg);
- value_ = StaticTypeField::encode(type.static_type_)
- | TypeField::encode(REGISTER)
- | DataField::encode(reg.code_);
+ value_ = TypeField::encode(REGISTER) | DataField::encode(reg.code_);
}
namespace internal {
-// -------------------------------------------------------------------------
-// StaticType
-//
-// StaticType represent the type of an expression or a word at runtime.
-// The types are ordered by knowledge, so that if a value can come about
-// in more than one way, and there are different static types inferred
-// for the different ways, the types can be combined to a type that we
-// are still certain of (possibly just "unknown").
-
-class StaticType BASE_EMBEDDED {
- public:
- StaticType() : static_type_(UNKNOWN_TYPE) {}
-
- static StaticType unknown() { return StaticType(); }
- static StaticType smi() { return StaticType(SMI_TYPE); }
- static StaticType jsstring() { return StaticType(STRING_TYPE); }
- static StaticType heap_object() { return StaticType(HEAP_OBJECT_TYPE); }
-
- // Accessors
- bool is_unknown() { return static_type_ == UNKNOWN_TYPE; }
- bool is_smi() { return static_type_ == SMI_TYPE; }
- bool is_heap_object() { return (static_type_ & HEAP_OBJECT_TYPE) != 0; }
- bool is_jsstring() { return static_type_ == STRING_TYPE; }
-
- bool operator==(StaticType other) const {
- return static_type_ == other.static_type_;
- }
-
- // Find the best approximating type for a value.
- // The argument must not be NULL.
- static StaticType TypeOf(Object* object) {
- // Remember to make the most specific tests first. A string is also a heap
- // object, so test for string-ness first.
- if (object->IsSmi()) return smi();
- if (object->IsString()) return jsstring();
- if (object->IsHeapObject()) return heap_object();
- return unknown();
- }
-
- // Merges two static types to a type that combines the knowledge
- // of both. If there is no way to combine (e.g., being a string *and*
- // being a smi), the resulting type is unknown.
- StaticType merge(StaticType other) {
- StaticType x(
- static_cast<StaticTypeEnum>(static_type_ & other.static_type_));
- return x;
- }
-
- private:
- enum StaticTypeEnum {
- // Numbers are chosen so that least upper bound of the following
- // partial order is implemented by bitwise "and":
- //
- // string
- // |
- // heap-object smi
- // \ /
- // unknown
- //
- UNKNOWN_TYPE = 0x00,
- SMI_TYPE = 0x01,
- HEAP_OBJECT_TYPE = 0x02,
- STRING_TYPE = 0x04 | HEAP_OBJECT_TYPE
- };
- explicit StaticType(StaticTypeEnum static_type) : static_type_(static_type) {}
-
- // StaticTypeEnum static_type_;
- StaticTypeEnum static_type_;
-
- friend class FrameElement;
- friend class Result;
-};
-
-
// -------------------------------------------------------------------------
// Results
//
// Construct a register Result.
explicit Result(Register reg);
- // Construct a register Result with a known static type.
- Result(Register reg, StaticType static_type);
-
// Construct a Result whose value is a compile-time constant.
explicit Result(Handle<Object> value) {
- value_ = StaticTypeField::encode(StaticType::TypeOf(*value).static_type_)
- | TypeField::encode(CONSTANT)
+ value_ = TypeField::encode(CONSTANT)
| DataField::encode(ConstantList()->length());
ConstantList()->Add(value);
}
inline void Unuse();
- StaticType static_type() const {
- return StaticType(StaticTypeField::decode(value_));
- }
-
- void set_static_type(StaticType type) {
- value_ = value_ & ~StaticTypeField::mask();
- value_ = value_ | StaticTypeField::encode(type.static_type_);
- }
-
Type type() const { return TypeField::decode(value_); }
void invalidate() { value_ = TypeField::encode(INVALID); }
private:
uint32_t value_;
- class StaticTypeField: public BitField<StaticType::StaticTypeEnum, 0, 3> {};
- class TypeField: public BitField<Type, 3, 2> {};
- class DataField: public BitField<uint32_t, 5, 32 - 6> {};
+ class TypeField: public BitField<Type, 0, 2> {};
+ class DataField: public BitField<uint32_t, 2, 32 - 3> {};
inline void CopyTo(Result* destination) const;
case FrameElement::MEMORY: // Fall through.
case FrameElement::REGISTER:
// All copies are backed by memory or register locations.
- result.set_static_type(target.static_type());
result.set_type(FrameElement::COPY);
result.clear_copied();
result.clear_sync();
if (elements_[index].is_register()) {
Unuse(elements_[index].reg());
}
- new_element.set_static_type(elements_[index].static_type());
elements_[index] = new_element;
}
ASSERT(source.is_valid());
elements_[i].clear_sync();
}
- // No code needs to be generated to change the static type of an
- // element.
- elements_[i].set_static_type(target.static_type());
}
}
void VirtualFrame::PrepareForReturn() {
// Spill all locals. This is necessary to make sure all locals have
// the right value when breaking at the return site in the debugger.
- // Set their static type to unknown so that they will match the known
- // return frame.
for (int i = 0; i < expression_base_index(); i++) {
SpillElementAt(i);
- elements_[i].set_static_type(StaticType::unknown());
}
}
// register element, or the new element at frame_index, must be made
// a copy.
int i = register_location(value->reg());
- ASSERT(value->static_type() == elements_[i].static_type());
if (i < frame_index) {
// The register FrameElement is lower in the frame than the new copy.
Use(value->reg(), frame_index);
elements_[frame_index] =
FrameElement::RegisterElement(value->reg(),
- FrameElement::NOT_SYNCED,
- value->static_type());
+ FrameElement::NOT_SYNCED);
}
} else {
ASSERT(value->is_constant());
}
-void VirtualFrame::Push(Register reg, StaticType static_type) {
+void VirtualFrame::Push(Register reg) {
if (is_used(reg)) {
int index = register_location(reg);
FrameElement element = CopyElementAt(index);
- ASSERT(static_type.merge(element.static_type()) == element.static_type());
elements_.Add(element);
} else {
Use(reg, element_count());
FrameElement element =
FrameElement::RegisterElement(reg,
- FrameElement::NOT_SYNCED,
- static_type);
+ FrameElement::NOT_SYNCED);
elements_.Add(element);
}
}
Result left = frame_->Pop();
if (op == Token::ADD) {
- bool left_is_string = left.static_type().is_jsstring();
- bool right_is_string = right.static_type().is_jsstring();
+ bool left_is_string = left.is_constant() && left.handle()->IsString();
+ bool right_is_string = right.is_constant() && right.handle()->IsString();
if (left_is_string || right_is_string) {
frame_->Push(&left);
frame_->Push(&right);
Result answer;
if (left_is_string) {
if (right_is_string) {
- // TODO(lrn): if (left.is_constant() && right.is_constant())
+ // TODO(lrn): if both are constant strings
// -- do a compile time cons, if allocation during codegen is allowed.
answer = frame_->CallRuntime(Runtime::kStringAdd, 2);
} else {
answer =
frame_->InvokeBuiltin(Builtins::STRING_ADD_RIGHT, CALL_FUNCTION, 2);
}
- answer.set_static_type(StaticType::jsstring());
frame_->Push(&answer);
return;
}
}
}
}
- // No need to set the copied flag---there are no copies.
- elements_[i].set_static_type(StaticType::unknown());
+ // No need to set the copied flag --- there are no copies.
} else {
// Clear the copy flag of non-constant, non-copy elements.
// They cannot be copied because copies are not allowed.
if (element.is_memory()) {
Result temp = cgen()->allocator()->Allocate();
ASSERT(temp.is_valid());
- temp.set_static_type(element.static_type());
__ pop(temp.reg());
return temp;
}
FrameElement::RegisterElement(temp.reg(), FrameElement::SYNCED);
// Preserve the copy flag on the element.
if (element.is_copied()) new_element.set_copied();
- new_element.set_static_type(element.static_type());
elements_[index] = new_element;
__ movq(temp.reg(), Operand(rbp, fp_relative(index)));
- return Result(temp.reg(), element.static_type());
+ return Result(temp.reg());
} else if (element.is_register()) {
- return Result(element.reg(), element.static_type());
+ return Result(element.reg());
} else {
ASSERT(element.is_constant());
return Result(element.handle());
void EmitPush(Immediate immediate);
// Push an element on the virtual frame.
- void Push(Register reg, StaticType static_type = StaticType());
+ void Push(Register reg);
void Push(Handle<Object> value);
void Push(Smi* value) { Push(Handle<Object>(value)); }
// frame).
void Push(Result* result) {
if (result->is_register()) {
- Push(result->reg(), result->static_type());
+ Push(result->reg());
} else {
ASSERT(result->is_constant());
Push(result->handle());