HCompareSymbolEq* compare = HCompareSymbolEq::cast(v);
return new LCmpSymbolEqAndBranch(UseRegisterAtStart(compare->left()),
UseRegisterAtStart(compare->right()));
+ } else if (v->IsCompareConstantEq()) {
+ HCompareConstantEq* compare = HCompareConstantEq::cast(v);
+ return new LCmpConstantEqAndBranch(UseRegisterAtStart(compare->value()));
} else if (v->IsTypeofIs()) {
HTypeofIs* typeof_is = HTypeofIs::cast(v);
return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value()));
}
+LInstruction* LChunkBuilder::DoCompareConstantEq(
+ HCompareConstantEq* instr) {
+ LOperand* left = UseRegisterAtStart(instr->value());
+ return DefineAsRegister(new LCmpConstantEq(left));
+}
+
+
LInstruction* LChunkBuilder::DoIsNull(HIsNull* instr) {
ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseRegisterAtStart(instr->value());
}
+LInstruction* LChunkBuilder::DoElementsKind(HElementsKind* instr) {
+ LOperand* object = UseRegisterAtStart(instr->value());
+ return DefineAsRegister(new LElementsKind(object));
+}
+
+
LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
LOperand* object = UseRegister(instr->value());
LValueOf* result = new LValueOf(object, TempRegister());
V(ClampTToUint8) \
V(ClassOfTest) \
V(ClassOfTestAndBranch) \
+ V(CmpConstantEq) \
+ V(CmpConstantEqAndBranch) \
V(CmpID) \
V(CmpIDAndBranch) \
V(CmpJSObjectEq) \
V(Deoptimize) \
V(DivI) \
V(DoubleToI) \
+ V(ElementsKind) \
V(ExternalArrayLength) \
V(FixedArrayLength) \
V(FunctionLiteral) \
};
+class LCmpConstantEq: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LCmpConstantEq(LOperand* left) {
+ inputs_[0] = left;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(CmpConstantEq, "cmp-constant-eq")
+ DECLARE_HYDROGEN_ACCESSOR(CompareConstantEq)
+};
+
+
+class LCmpConstantEqAndBranch: public LControlInstruction<1, 0> {
+ public:
+ explicit LCmpConstantEqAndBranch(LOperand* left) {
+ inputs_[0] = left;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(CmpConstantEqAndBranch,
+ "cmp-constant-eq-and-branch")
+ DECLARE_HYDROGEN_ACCESSOR(CompareConstantEq)
+};
+
+
class LIsNull: public LTemplateInstruction<1, 1, 0> {
public:
explicit LIsNull(LOperand* value) {
};
+class LElementsKind: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LElementsKind(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(ElementsKind, "elements-kind")
+ DECLARE_HYDROGEN_ACCESSOR(ElementsKind)
+};
+
+
class LValueOf: public LTemplateInstruction<1, 1, 1> {
public:
LValueOf(LOperand* value, LOperand* temp) {
}
+void LCodeGen::DoElementsKind(LElementsKind* instr) {
+ Register result = ToRegister(instr->result());
+ Register input = ToRegister(instr->InputAt(0));
+
+ // Load map into |result|.
+ __ ldr(result, FieldMemOperand(input, HeapObject::kMapOffset));
+ // Load the map's "bit field 2" into |result|. We only need the first byte,
+ // but the following bit field extraction takes care of that anyway.
+ __ ldr(result, FieldMemOperand(result, Map::kBitField2Offset));
+ // Retrieve elements_kind from bit field 2.
+ __ ubfx(result, result, Map::kElementsKindShift, Map::kElementsKindBitCount);
+}
+
+
void LCodeGen::DoValueOf(LValueOf* instr) {
Register input = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
}
+void LCodeGen::DoCmpConstantEq(LCmpConstantEq* instr) {
+ Register left = ToRegister(instr->InputAt(0));
+ Register result = ToRegister(instr->result());
+
+ Label done;
+ __ cmp(left, Operand(instr->hydrogen()->right()));
+ __ LoadRoot(result, Heap::kTrueValueRootIndex, eq);
+ __ LoadRoot(result, Heap::kFalseValueRootIndex, ne);
+}
+
+
+void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) {
+ Register left = ToRegister(instr->InputAt(0));
+ int true_block = chunk_->LookupDestination(instr->true_block_id());
+ int false_block = chunk_->LookupDestination(instr->false_block_id());
+
+ __ cmp(left, Operand(instr->hydrogen()->right()));
+ EmitBranch(true_block, false_block, eq);
+}
+
+
void LCodeGen::DoIsNull(LIsNull* instr) {
Register reg = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
__ ldr(result, FieldMemOperand(input, JSObject::kElementsOffset));
if (FLAG_debug_code) {
- Label done;
+ Label done, fail;
__ ldr(scratch, FieldMemOperand(result, HeapObject::kMapOffset));
__ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
__ cmp(scratch, ip);
__ LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex);
__ cmp(scratch, ip);
__ b(eq, &done);
- __ ldr(scratch, FieldMemOperand(result, HeapObject::kMapOffset));
- __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
- __ sub(scratch, scratch, Operand(FIRST_EXTERNAL_ARRAY_TYPE));
- __ cmp(scratch, Operand(kExternalArrayTypeCount));
- __ Check(cc, "Check for fast elements failed.");
+ // |scratch| still contains |input|'s map.
+ __ ldr(scratch, FieldMemOperand(scratch, Map::kBitField2Offset));
+ __ ubfx(scratch, scratch, Map::kElementsKindShift,
+ Map::kElementsKindBitCount);
+ __ cmp(scratch, Operand(JSObject::FAST_ELEMENTS));
+ __ b(eq, &done);
+ __ cmp(scratch, Operand(JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND));
+ __ b(lt, &fail);
+ __ cmp(scratch, Operand(JSObject::LAST_EXTERNAL_ARRAY_ELEMENTS_KIND));
+ __ b(le, &done);
+ __ bind(&fail);
+ __ Abort("Check for fast or external elements failed.");
__ bind(&done);
}
}
is_string_access_ = true;
} else if (is_monomorphic_) {
monomorphic_receiver_type_ = oracle->LoadMonomorphicReceiverType(this);
+ } else if (oracle->LoadIsMegamorphicWithTypeInfo(this)) {
+ receiver_types_ = new ZoneMapList(kMaxKeyedPolymorphism);
+ oracle->CollectKeyedReceiverTypes(this->id(), receiver_types_);
}
}
ZoneMapList* types = oracle->StoreReceiverTypes(this, name);
receiver_types_ = types;
} else if (is_monomorphic_) {
- // Record receiver type for monomorphic keyed loads.
+ // Record receiver type for monomorphic keyed stores.
monomorphic_receiver_type_ = oracle->StoreMonomorphicReceiverType(this);
+ } else if (oracle->StoreIsMegamorphicWithTypeInfo(this)) {
+ receiver_types_ = new ZoneMapList(kMaxKeyedPolymorphism);
+ oracle->CollectKeyedReceiverTypes(this->id(), receiver_types_);
}
}
void CountOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
is_monomorphic_ = oracle->StoreIsMonomorphicNormal(this);
if (is_monomorphic_) {
- // Record receiver type for monomorphic keyed loads.
+ // Record receiver type for monomorphic keyed stores.
monomorphic_receiver_type_ = oracle->StoreMonomorphicReceiverType(this);
+ } else if (oracle->StoreIsMegamorphicWithTypeInfo(this)) {
+ receiver_types_ = new ZoneMapList(kMaxKeyedPolymorphism);
+ oracle->CollectKeyedReceiverTypes(this->id(), receiver_types_);
}
}
expression_(expr),
pos_(pos),
assignment_id_(GetNextId()),
- count_id_(GetNextId()) { }
+ count_id_(GetNextId()),
+ receiver_types_(NULL) { }
DECLARE_NODE_TYPE(CountOperation)
virtual Handle<Map> GetMonomorphicReceiverType() {
return monomorphic_receiver_type_;
}
+ virtual ZoneMapList* GetReceiverTypes() { return receiver_types_; }
// Bailout support.
int AssignmentId() const { return assignment_id_; }
int assignment_id_;
int count_id_;
Handle<Map> monomorphic_receiver_type_;
+ ZoneMapList* receiver_types_;
};
V(CompareJSObjectEq) \
V(CompareMap) \
V(CompareSymbolEq) \
+ V(CompareConstantEq) \
V(Constant) \
V(Context) \
V(DeleteProperty) \
V(Deoptimize) \
V(Div) \
+ V(ElementsKind) \
V(EnterInlined) \
V(ExternalArrayLength) \
V(FixedArrayLength) \
kBoolean = 0x85, // 0000 0000 1000 0101
kNonPrimitive = 0x101, // 0000 0001 0000 0001
kJSObject = 0x301, // 0000 0011 0000 0001
- kJSArray = 0x701, // 0000 0111 1000 0001
+ kJSArray = 0x701, // 0000 0111 0000 0001
kUninitialized = 0x1fff // 0001 1111 1111 1111
};
GVN_FLAG_LIST(DECLARE_DO)
#undef DECLARE_DO
kFlexibleRepresentation,
+ // Participate in Global Value Numbering, i.e. elimination of
+ // unnecessary recomputations. If an instruction sets this flag, it must
+ // implement DataEquals(), which will be used to determine if other
+ // occurrences of the instruction are indeed the same.
kUseGVN,
kCanOverflow,
kBailoutOnMinusZero,
};
+class HElementsKind: public HUnaryOperation {
+ public:
+ explicit HElementsKind(HValue* value) : HUnaryOperation(value) {
+ set_representation(Representation::Integer32());
+ SetFlag(kUseGVN);
+ SetFlag(kDependsOnMaps);
+ }
+
+ virtual Representation RequiredInputRepresentation(int index) const {
+ return Representation::Tagged();
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(ElementsKind)
+
+ protected:
+ virtual bool DataEquals(HValue* other) { return true; }
+};
+
+
class HBitNot: public HUnaryOperation {
public:
explicit HBitNot(HValue* value) : HUnaryOperation(value) {
};
+class HCompareConstantEq: public HUnaryOperation {
+ public:
+ HCompareConstantEq(HValue* left, int right, Token::Value op)
+ : HUnaryOperation(left), op_(op), right_(right) {
+ ASSERT(op == Token::EQ_STRICT);
+ set_representation(Representation::Tagged());
+ SetFlag(kUseGVN);
+ }
+
+ Token::Value op() const { return op_; }
+ int right() const { return right_; }
+
+ virtual bool EmitAtUses() {
+ return !HasSideEffects() && !HasMultipleUses();
+ }
+
+ virtual Representation RequiredInputRepresentation(int index) const {
+ return Representation::Integer32();
+ }
+
+ virtual HType CalculateInferredType() { return HType::Boolean(); }
+
+ DECLARE_CONCRETE_INSTRUCTION(CompareConstantEq);
+
+ protected:
+ virtual bool DataEquals(HValue* other) {
+ HCompareConstantEq* other_instr = HCompareConstantEq::cast(other);
+ return (op_ == other_instr->op_ &&
+ right_ == other_instr->right_);
+ }
+
+ private:
+ const Token::Value op_;
+ const int right_;
+};
+
+
class HUnaryPredicate: public HUnaryOperation {
public:
explicit HUnaryPredicate(HValue* value) : HUnaryOperation(value) {
InstanceType from() { return from_; }
InstanceType to() { return to_; }
+ virtual bool EmitAtUses() {
+ return !HasSideEffects() && !HasMultipleUses();
+ }
+
virtual void PrintDataTo(StringStream* stream);
DECLARE_CONCRETE_INSTRUCTION(HasInstanceType)
value = Pop();
HValue* key = Pop();
HValue* object = Pop();
- instr = BuildStoreKeyed(object, key, value, expr);
+ bool has_side_effects = false;
+ HandleKeyedElementAccess(object, key, value, expr, expr->AssignmentId(),
+ expr->position(),
+ true, // is_store
+ &has_side_effects);
+ Push(value);
+ ASSERT(has_side_effects); // Stores always have side effects.
+ AddSimulate(expr->AssignmentId());
+ ast_context()->ReturnValue(Pop());
+ return;
}
Push(value);
instr->set_position(expr->position());
HValue* obj = environment()->ExpressionStackAt(1);
HValue* key = environment()->ExpressionStackAt(0);
- HInstruction* load = BuildLoadKeyed(obj, key, prop);
- PushAndAdd(load);
- if (load->HasSideEffects()) AddSimulate(expr->CompoundLoadId());
+ bool has_side_effects = false;
+ HValue* load = HandleKeyedElementAccess(
+ obj, key, NULL, prop, expr->CompoundLoadId(), RelocInfo::kNoPosition,
+ false, // is_store
+ &has_side_effects);
+ Push(load);
+ if (has_side_effects) AddSimulate(expr->CompoundLoadId());
+
CHECK_ALIVE(VisitForValue(expr->value()));
HValue* right = Pop();
if (instr->HasSideEffects()) AddSimulate(operation->id());
expr->RecordTypeFeedback(oracle());
- HInstruction* store = BuildStoreKeyed(obj, key, instr, expr);
- AddInstruction(store);
+ HandleKeyedElementAccess(obj, key, instr, expr, expr->AssignmentId(),
+ RelocInfo::kNoPosition,
+ true, // is_store
+ &has_side_effects);
+
// Drop the simulated receiver, key, and value. Return the value.
Drop(3);
Push(instr);
- if (store->HasSideEffects()) AddSimulate(expr->AssignmentId());
+ ASSERT(has_side_effects); // Stores always have side effects.
+ AddSimulate(expr->AssignmentId());
ast_context()->ReturnValue(Pop());
}
}
-HInstruction* HGraphBuilder::BuildLoadKeyedFastElement(HValue* object,
- HValue* key,
- Property* expr) {
- ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic());
- AddInstruction(new(zone()) HCheckNonSmi(object));
+HInstruction* HGraphBuilder::BuildExternalArrayElementAccess(
+ HValue* external_elements,
+ HValue* checked_key,
+ HValue* val,
+ JSObject::ElementsKind elements_kind,
+ bool is_store) {
+ if (is_store) {
+ ASSERT(val != NULL);
+ switch (elements_kind) {
+ case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
+ HClampToUint8* clamp = new(zone()) HClampToUint8(val);
+ AddInstruction(clamp);
+ val = clamp;
+ break;
+ }
+ case JSObject::EXTERNAL_BYTE_ELEMENTS:
+ case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case JSObject::EXTERNAL_SHORT_ELEMENTS:
+ case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case JSObject::EXTERNAL_INT_ELEMENTS:
+ case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
+ HToInt32* floor_val = new(zone()) HToInt32(val);
+ AddInstruction(floor_val);
+ val = floor_val;
+ break;
+ }
+ case JSObject::EXTERNAL_FLOAT_ELEMENTS:
+ case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
+ break;
+ case JSObject::FAST_ELEMENTS:
+ case JSObject::FAST_DOUBLE_ELEMENTS:
+ case JSObject::DICTIONARY_ELEMENTS:
+ case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ UNREACHABLE();
+ break;
+ }
+ return new(zone()) HStoreKeyedSpecializedArrayElement(
+ external_elements, checked_key, val, elements_kind);
+ } else {
+ return new(zone()) HLoadKeyedSpecializedArrayElement(
+ external_elements, checked_key, elements_kind);
+ }
+}
+
+
+HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object,
+ HValue* key,
+ HValue* val,
+ Expression* expr,
+ bool is_store) {
+ ASSERT(expr->IsMonomorphic());
Handle<Map> map = expr->GetMonomorphicReceiverType();
- ASSERT(map->has_fast_elements());
+ if (!map->has_fast_elements() && !map->has_external_array_elements()) {
+ return is_store ? BuildStoreKeyedGeneric(object, key, val)
+ : BuildLoadKeyedGeneric(object, key);
+ }
+ AddInstruction(new(zone()) HCheckNonSmi(object));
AddInstruction(new(zone()) HCheckMap(object, map));
- bool is_array = (map->instance_type() == JS_ARRAY_TYPE);
- HLoadElements* elements = new(zone()) HLoadElements(object);
+ HInstruction* elements = new(zone()) HLoadElements(object);
HInstruction* length = NULL;
HInstruction* checked_key = NULL;
- if (is_array) {
+ if (map->has_external_array_elements()) {
+ AddInstruction(elements);
+ length = AddInstruction(new(zone()) HExternalArrayLength(elements));
+ checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
+ HLoadExternalArrayPointer* external_elements =
+ new(zone()) HLoadExternalArrayPointer(elements);
+ AddInstruction(external_elements);
+ return BuildExternalArrayElementAccess(external_elements, checked_key,
+ val, map->elements_kind(), is_store);
+ }
+ ASSERT(map->has_fast_elements());
+ if (map->instance_type() == JS_ARRAY_TYPE) {
length = AddInstruction(new(zone()) HJSArrayLength(object));
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
AddInstruction(elements);
length = AddInstruction(new(zone()) HFixedArrayLength(elements));
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
}
- return new(zone()) HLoadKeyedFastElement(elements, checked_key);
+ if (is_store) {
+ return new(zone()) HStoreKeyedFastElement(elements, checked_key, val);
+ } else {
+ return new(zone()) HLoadKeyedFastElement(elements, checked_key);
+ }
}
-HInstruction* HGraphBuilder::BuildLoadKeyedSpecializedArrayElement(
- HValue* object,
- HValue* key,
- Property* expr) {
- ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic());
+HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
+ HValue* key,
+ HValue* val,
+ Expression* prop,
+ int ast_id,
+ int position,
+ bool is_store,
+ bool* has_side_effects) {
+ *has_side_effects = false;
AddInstruction(new(zone()) HCheckNonSmi(object));
- Handle<Map> map = expr->GetMonomorphicReceiverType();
- ASSERT(!map->has_fast_elements());
- ASSERT(map->has_external_array_elements());
- AddInstruction(new(zone()) HCheckMap(object, map));
- HLoadElements* elements = new(zone()) HLoadElements(object);
- AddInstruction(elements);
- HInstruction* length = new(zone()) HExternalArrayLength(elements);
- AddInstruction(length);
- HInstruction* checked_key =
- AddInstruction(new(zone()) HBoundsCheck(key, length));
- HLoadExternalArrayPointer* external_elements =
- new(zone()) HLoadExternalArrayPointer(elements);
- AddInstruction(external_elements);
- HLoadKeyedSpecializedArrayElement* pixel_array_value =
- new(zone()) HLoadKeyedSpecializedArrayElement(
- external_elements, checked_key, map->elements_kind());
- return pixel_array_value;
+ AddInstruction(HCheckInstanceType::NewIsSpecObject(object));
+ ZoneMapList* maps = prop->GetReceiverTypes();
+ bool todo_external_array = false;
+
+ static const int kNumElementTypes = JSObject::kElementsKindCount;
+ bool type_todo[kNumElementTypes];
+ for (int i = 0; i < kNumElementTypes; ++i) {
+ type_todo[i] = false;
+ }
+
+ for (int i = 0; i < maps->length(); ++i) {
+ ASSERT(maps->at(i)->IsMap());
+ type_todo[maps->at(i)->elements_kind()] = true;
+ if (maps->at(i)->elements_kind()
+ >= JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND) {
+ todo_external_array = true;
+ }
+ }
+ // We can't treat dictionary elements here (need to deopt instead).
+ type_todo[JSObject::DICTIONARY_ELEMENTS] = false;
+ // Support for FAST_DOUBLE_ELEMENTS isn't implemented yet, so we deopt.
+ type_todo[JSObject::FAST_DOUBLE_ELEMENTS] = false;
+
+ HBasicBlock* join = graph()->CreateBasicBlock();
+
+ HInstruction* elements_kind_instr =
+ AddInstruction(new(zone()) HElementsKind(object));
+ HInstruction* elements = NULL;
+ HLoadExternalArrayPointer* external_elements = NULL;
+ HInstruction* checked_key = NULL;
+
+ // FAST_ELEMENTS is assumed to be the first case.
+ STATIC_ASSERT(JSObject::FAST_ELEMENTS == 0);
+
+ for (JSObject::ElementsKind elements_kind = JSObject::FAST_ELEMENTS;
+ elements_kind <= JSObject::LAST_ELEMENTS_KIND;
+ elements_kind = JSObject::ElementsKind(elements_kind + 1)) {
+ // After having handled FAST_ELEMENTS in the first run of the loop, we
+ // need to add some code that's executed for all other cases.
+ if (elements_kind == 1 && todo_external_array) {
+ elements = AddInstruction(new(zone()) HLoadElements(object));
+ // We need to forcibly prevent some ElementsKind-dependent instructions
+ // from being hoisted out of any loops they might occur in, because
+ // the current loop-invariant-code-motion algorithm isn't clever enough
+ // to deal with them properly.
+ // There's some performance to be gained by developing a smarter
+ // solution for this.
+ elements->ClearFlag(HValue::kUseGVN);
+ HInstruction* length =
+ AddInstruction(new(zone()) HExternalArrayLength(elements));
+ checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
+ external_elements = new(zone()) HLoadExternalArrayPointer(elements);
+ AddInstruction(external_elements);
+ }
+ if (type_todo[elements_kind]) {
+ HBasicBlock* if_true = graph()->CreateBasicBlock();
+ HBasicBlock* if_false = graph()->CreateBasicBlock();
+ HCompareConstantEq* compare = new(zone()) HCompareConstantEq(
+ elements_kind_instr,
+ elements_kind,
+ Token::EQ_STRICT);
+ AddInstruction(compare);
+ HTest* branch = new(zone()) HTest(compare, if_true, if_false);
+ current_block()->Finish(branch);
+
+ set_current_block(if_true);
+ HInstruction* access;
+ if (elements_kind == JSObject::FAST_ELEMENTS) {
+ HBasicBlock* if_jsarray = graph()->CreateBasicBlock();
+ HBasicBlock* if_fastobject = graph()->CreateBasicBlock();
+ HInstruction* typecheck =
+ AddInstruction(new(zone()) HHasInstanceType(object, JS_ARRAY_TYPE));
+ HTest* test = new(zone()) HTest(typecheck, if_jsarray, if_fastobject);
+ current_block()->Finish(test);
+
+ set_current_block(if_jsarray);
+ HInstruction* length = new(zone()) HJSArrayLength(object);
+ AddInstruction(length);
+ length->ClearFlag(HValue::kUseGVN);
+ checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
+ elements = AddInstruction(new(zone()) HLoadElements(object));
+ elements->ClearFlag(HValue::kUseGVN);
+ if (is_store) {
+ access = AddInstruction(
+ new(zone()) HStoreKeyedFastElement(elements, checked_key, val));
+ } else {
+ access = AddInstruction(
+ new(zone()) HLoadKeyedFastElement(elements, checked_key));
+ Push(access);
+ }
+ *has_side_effects |= access->HasSideEffects();
+ if (position != -1) {
+ access->set_position(position);
+ }
+ if_jsarray->Goto(join);
+
+ set_current_block(if_fastobject);
+ elements = AddInstruction(new(zone()) HLoadElements(object));
+ elements->ClearFlag(HValue::kUseGVN);
+ length = AddInstruction(new(zone()) HFixedArrayLength(elements));
+ checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
+ if (is_store) {
+ access = AddInstruction(
+ new(zone()) HStoreKeyedFastElement(elements, checked_key, val));
+ } else {
+ access = AddInstruction(
+ new(zone()) HLoadKeyedFastElement(elements, checked_key));
+ }
+ } else { // External array elements.
+ access = AddInstruction(BuildExternalArrayElementAccess(
+ external_elements, checked_key, val, elements_kind, is_store));
+ }
+ *has_side_effects |= access->HasSideEffects();
+ access->set_position(position);
+ if (!is_store) {
+ Push(access);
+ }
+ current_block()->Goto(join);
+ set_current_block(if_false);
+ }
+ }
+
+ // Deopt if none of the cases matched.
+ current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses);
+ join->SetJoinId(ast_id);
+ set_current_block(join);
+ return is_store ? NULL : Pop();
}
-HInstruction* HGraphBuilder::BuildLoadKeyed(HValue* obj,
- HValue* key,
- Property* prop) {
- if (prop->IsMonomorphic()) {
- Handle<Map> receiver_type(prop->GetMonomorphicReceiverType());
- // An object has either fast elements or pixel array elements, but never
- // both. Pixel array maps that are assigned to pixel array elements are
- // always created with the fast elements flag cleared.
- if (receiver_type->has_external_array_elements()) {
- return BuildLoadKeyedSpecializedArrayElement(obj, key, prop);
- } else if (receiver_type->has_fast_elements()) {
- return BuildLoadKeyedFastElement(obj, key, prop);
+HValue* HGraphBuilder::HandleKeyedElementAccess(HValue* obj,
+ HValue* key,
+ HValue* val,
+ Expression* expr,
+ int ast_id,
+ int position,
+ bool is_store,
+ bool* has_side_effects) {
+ ASSERT(!expr->IsPropertyName());
+ HInstruction* instr = NULL;
+ if (expr->IsMonomorphic()) {
+ instr = BuildMonomorphicElementAccess(obj, key, val, expr, is_store);
+ } else if (expr->GetReceiverTypes() != NULL &&
+ !expr->GetReceiverTypes()->is_empty()) {
+ return HandlePolymorphicElementAccess(
+ obj, key, val, expr, ast_id, position, is_store, has_side_effects);
+ } else {
+ if (is_store) {
+ instr = BuildStoreKeyedGeneric(obj, key, val);
+ } else {
+ instr = BuildLoadKeyedGeneric(obj, key);
}
}
- return BuildLoadKeyedGeneric(obj, key);
+ instr->set_position(position);
+ AddInstruction(instr);
+ *has_side_effects = instr->HasSideEffects();
+ return instr;
}
function_strict_mode());
}
-
-HInstruction* HGraphBuilder::BuildStoreKeyedFastElement(HValue* object,
- HValue* key,
- HValue* val,
- Expression* expr) {
- ASSERT(expr->IsMonomorphic());
- AddInstruction(new(zone()) HCheckNonSmi(object));
- Handle<Map> map = expr->GetMonomorphicReceiverType();
- ASSERT(map->has_fast_elements());
- AddInstruction(new(zone()) HCheckMap(object, map));
- HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object));
- AddInstruction(new(zone()) HCheckMap(
- elements, isolate()->factory()->fixed_array_map()));
- bool is_array = (map->instance_type() == JS_ARRAY_TYPE);
- HInstruction* length = NULL;
- if (is_array) {
- length = AddInstruction(new(zone()) HJSArrayLength(object));
- } else {
- length = AddInstruction(new(zone()) HFixedArrayLength(elements));
- }
- HInstruction* checked_key =
- AddInstruction(new(zone()) HBoundsCheck(key, length));
- return new(zone()) HStoreKeyedFastElement(elements, checked_key, val);
-}
-
-
-HInstruction* HGraphBuilder::BuildStoreKeyedSpecializedArrayElement(
- HValue* object,
- HValue* key,
- HValue* val,
- Expression* expr) {
- ASSERT(expr->IsMonomorphic());
- AddInstruction(new(zone()) HCheckNonSmi(object));
- Handle<Map> map = expr->GetMonomorphicReceiverType();
- ASSERT(!map->has_fast_elements());
- ASSERT(map->has_external_array_elements());
- AddInstruction(new(zone()) HCheckMap(object, map));
- HLoadElements* elements = new(zone()) HLoadElements(object);
- AddInstruction(elements);
- HInstruction* length = AddInstruction(
- new(zone()) HExternalArrayLength(elements));
- HInstruction* checked_key =
- AddInstruction(new(zone()) HBoundsCheck(key, length));
- HLoadExternalArrayPointer* external_elements =
- new(zone()) HLoadExternalArrayPointer(elements);
- AddInstruction(external_elements);
- JSObject::ElementsKind elements_kind = map->elements_kind();
- switch (elements_kind) {
- case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
- HClampToUint8* clamp = new(zone()) HClampToUint8(val);
- AddInstruction(clamp);
- val = clamp;
- break;
- }
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
- HToInt32* floor_val = new(zone()) HToInt32(val);
- AddInstruction(floor_val);
- val = floor_val;
- break;
- }
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- break;
-
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
- UNREACHABLE();
- break;
- }
- return new(zone()) HStoreKeyedSpecializedArrayElement(
- external_elements,
- checked_key,
- val,
- map->elements_kind());
-}
-
-
-HInstruction* HGraphBuilder::BuildStoreKeyed(HValue* object,
- HValue* key,
- HValue* value,
- Expression* expr) {
- if (expr->IsMonomorphic()) {
- Handle<Map> receiver_type(expr->GetMonomorphicReceiverType());
- // An object has either fast elements or external array elements, but
- // never both. Pixel array maps that are assigned to pixel array elements
- // are always created with the fast elements flag cleared.
- if (receiver_type->has_external_array_elements()) {
- return BuildStoreKeyedSpecializedArrayElement(object,
- key,
- value,
- expr);
- } else if (receiver_type->has_fast_elements()) {
- return BuildStoreKeyedFastElement(object, key, value, expr);
- }
- }
- return BuildStoreKeyedGeneric(object, key, value);
-}
-
-
bool HGraphBuilder::TryArgumentsAccess(Property* expr) {
VariableProxy* proxy = expr->obj()->AsVariableProxy();
if (proxy == NULL) return false;
HValue* key = Pop();
HValue* obj = Pop();
- instr = BuildLoadKeyed(obj, key, expr);
+
+ bool has_side_effects = false;
+ HValue* load = HandleKeyedElementAccess(
+ obj, key, NULL, expr, expr->id(), expr->position(),
+ false, // is_store
+ &has_side_effects);
+ if (has_side_effects) {
+ if (ast_context()->IsEffect()) {
+ AddSimulate(expr->id());
+ } else {
+ Push(load);
+ AddSimulate(expr->id());
+ Drop(1);
+ }
+ }
+ ast_context()->ReturnValue(load);
+ return;
}
instr->set_position(expr->position());
ast_context()->ReturnInstruction(instr, expr->id());
HValue* obj = environment()->ExpressionStackAt(1);
HValue* key = environment()->ExpressionStackAt(0);
- HInstruction* load = BuildLoadKeyed(obj, key, prop);
- PushAndAdd(load);
- if (load->HasSideEffects()) AddSimulate(expr->CountId());
+ bool has_side_effects = false;
+ HValue* load = HandleKeyedElementAccess(
+ obj, key, NULL, prop, expr->CountId(), RelocInfo::kNoPosition,
+ false, // is_store
+ &has_side_effects);
+ Push(load);
+ if (has_side_effects) AddSimulate(expr->CountId());
after = BuildIncrement(returns_original_input, expr);
input = Pop();
expr->RecordTypeFeedback(oracle());
- HInstruction* store = BuildStoreKeyed(obj, key, after, expr);
- AddInstruction(store);
+ HandleKeyedElementAccess(obj, key, after, expr, expr->AssignmentId(),
+ RelocInfo::kNoPosition,
+ true, // is_store
+ &has_side_effects);
// Drop the key from the bailout environment. Overwrite the receiver
// with the result of the operation, and the placeholder with the
Drop(1);
environment()->SetExpressionStackAt(0, after);
if (returns_original_input) environment()->SetExpressionStackAt(1, input);
- if (store->HasSideEffects()) AddSimulate(expr->AssignmentId());
+ ASSERT(has_side_effects); // Stores always have side effects.
+ AddSimulate(expr->AssignmentId());
}
}
LookupResult* result,
bool smi_and_map_check);
HInstruction* BuildLoadNamedGeneric(HValue* object, Property* expr);
- HInstruction* BuildLoadKeyedFastElement(HValue* object,
- HValue* key,
- Property* expr);
- HInstruction* BuildLoadKeyedSpecializedArrayElement(HValue* object,
- HValue* key,
- Property* expr);
HInstruction* BuildLoadKeyedGeneric(HValue* object,
HValue* key);
-
- HInstruction* BuildLoadKeyed(HValue* obj,
- HValue* key,
- Property* prop);
+ HInstruction* BuildExternalArrayElementAccess(
+ HValue* external_elements,
+ HValue* checked_key,
+ HValue* val,
+ JSObject::ElementsKind elements_kind,
+ bool is_store);
+
+ HInstruction* BuildMonomorphicElementAccess(HValue* object,
+ HValue* key,
+ HValue* val,
+ Expression* expr,
+ bool is_store);
+ HValue* HandlePolymorphicElementAccess(HValue* object,
+ HValue* key,
+ HValue* val,
+ Expression* prop,
+ int ast_id,
+ int position,
+ bool is_store,
+ bool* has_side_effects);
+
+ HValue* HandleKeyedElementAccess(HValue* obj,
+ HValue* key,
+ HValue* val,
+ Expression* expr,
+ int ast_id,
+ int position,
+ bool is_store,
+ bool* has_side_effects);
HInstruction* BuildLoadNamed(HValue* object,
Property* prop,
HValue* key,
HValue* value);
- HInstruction* BuildStoreKeyedFastElement(HValue* object,
- HValue* key,
- HValue* val,
- Expression* expr);
-
- HInstruction* BuildStoreKeyedSpecializedArrayElement(
- HValue* object,
- HValue* key,
- HValue* val,
- Expression* expr);
-
- HInstruction* BuildStoreKeyed(HValue* object,
- HValue* key,
- HValue* value,
- Expression* assignment);
-
HValue* BuildContextChainWalk(Variable* var);
void AddCheckConstantFunction(Call* expr,
}
+void LCodeGen::DoElementsKind(LElementsKind* instr) {
+ Register result = ToRegister(instr->result());
+ Register input = ToRegister(instr->InputAt(0));
+
+ // Load map into |result|.
+ __ mov(result, FieldOperand(input, HeapObject::kMapOffset));
+ // Load the map's "bit field 2" into |result|. We only need the first byte,
+ // but the following masking takes care of that anyway.
+ __ mov(result, FieldOperand(result, Map::kBitField2Offset));
+ // Retrieve elements_kind from bit field 2.
+ __ and_(result, Map::kElementsKindMask);
+ __ shr(result, Map::kElementsKindShift);
+}
+
+
void LCodeGen::DoValueOf(LValueOf* instr) {
Register input = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
}
+void LCodeGen::DoCmpConstantEq(LCmpConstantEq* instr) {
+ Register left = ToRegister(instr->InputAt(0));
+ Register result = ToRegister(instr->result());
+
+ Label done;
+ __ cmp(left, instr->hydrogen()->right());
+ __ mov(result, factory()->true_value());
+ __ j(equal, &done, Label::kNear);
+ __ mov(result, factory()->false_value());
+ __ bind(&done);
+}
+
+
+void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) {
+ Register left = ToRegister(instr->InputAt(0));
+ int true_block = chunk_->LookupDestination(instr->true_block_id());
+ int false_block = chunk_->LookupDestination(instr->false_block_id());
+
+ __ cmp(left, instr->hydrogen()->right());
+ EmitBranch(true_block, false_block, equal);
+}
+
+
void LCodeGen::DoIsNull(LIsNull* instr) {
Register reg = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
Register input = ToRegister(instr->InputAt(0));
__ mov(result, FieldOperand(input, JSObject::kElementsOffset));
if (FLAG_debug_code) {
- Label done;
+ Label done, ok, fail;
__ cmp(FieldOperand(result, HeapObject::kMapOffset),
Immediate(factory()->fixed_array_map()));
__ j(equal, &done, Label::kNear);
Register temp((result.is(eax)) ? ebx : eax);
__ push(temp);
__ mov(temp, FieldOperand(result, HeapObject::kMapOffset));
- __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
- __ sub(Operand(temp), Immediate(FIRST_EXTERNAL_ARRAY_TYPE));
- __ cmp(Operand(temp), Immediate(kExternalArrayTypeCount));
+ __ movzx_b(temp, FieldOperand(temp, Map::kBitField2Offset));
+ __ and_(temp, Map::kElementsKindMask);
+ __ shr(temp, Map::kElementsKindShift);
+ __ cmp(temp, JSObject::FAST_ELEMENTS);
+ __ j(equal, &ok, Label::kNear);
+ __ cmp(temp, JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
+ __ j(less, &fail, Label::kNear);
+ __ cmp(temp, JSObject::LAST_EXTERNAL_ARRAY_ELEMENTS_KIND);
+ __ j(less_equal, &ok, Label::kNear);
+ __ bind(&fail);
+ __ Abort("Check for fast or external elements failed.");
+ __ bind(&ok);
__ pop(temp);
- __ Check(below, "Check for fast elements or pixel array failed.");
__ bind(&done);
}
}
HCompareSymbolEq* compare = HCompareSymbolEq::cast(v);
return new LCmpSymbolEqAndBranch(UseRegisterAtStart(compare->left()),
UseRegisterAtStart(compare->right()));
+ } else if (v->IsCompareConstantEq()) {
+ HCompareConstantEq* compare = HCompareConstantEq::cast(v);
+ return new LCmpConstantEqAndBranch(UseRegisterAtStart(compare->value()));
} else if (v->IsTypeofIs()) {
HTypeofIs* typeof_is = HTypeofIs::cast(v);
return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value()));
}
+LInstruction* LChunkBuilder::DoCompareConstantEq(
+ HCompareConstantEq* instr) {
+ LOperand* left = UseRegisterAtStart(instr->value());
+ return DefineAsRegister(new LCmpConstantEq(left));
+}
+
+
LInstruction* LChunkBuilder::DoIsNull(HIsNull* instr) {
ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseRegisterAtStart(instr->value());
}
+LInstruction* LChunkBuilder::DoElementsKind(HElementsKind* instr) {
+ LOperand* object = UseRegisterAtStart(instr->value());
+ return DefineAsRegister(new LElementsKind(object));
+}
+
+
LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
LOperand* object = UseRegister(instr->value());
LValueOf* result = new LValueOf(object, TempRegister());
V(CmpIDAndBranch) \
V(CmpJSObjectEq) \
V(CmpJSObjectEqAndBranch) \
+ V(CmpMapAndBranch) \
V(CmpSymbolEq) \
V(CmpSymbolEqAndBranch) \
- V(CmpMapAndBranch) \
V(CmpT) \
+ V(CmpConstantEq) \
+ V(CmpConstantEqAndBranch) \
V(ConstantD) \
V(ConstantI) \
V(ConstantT) \
V(Deoptimize) \
V(DivI) \
V(DoubleToI) \
+ V(ElementsKind) \
V(ExternalArrayLength) \
V(FixedArrayLength) \
V(FunctionLiteral) \
};
+class LCmpConstantEq: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LCmpConstantEq(LOperand* left) {
+ inputs_[0] = left;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(CmpConstantEq, "cmp-constant-eq")
+ DECLARE_HYDROGEN_ACCESSOR(CompareConstantEq)
+};
+
+
+class LCmpConstantEqAndBranch: public LControlInstruction<1, 0> {
+ public:
+ explicit LCmpConstantEqAndBranch(LOperand* left) {
+ inputs_[0] = left;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(CmpConstantEqAndBranch,
+ "cmp-constant-eq-and-branch")
+ DECLARE_HYDROGEN_ACCESSOR(CompareConstantEq)
+};
+
+
class LIsNull: public LTemplateInstruction<1, 1, 0> {
public:
explicit LIsNull(LOperand* value) {
};
+class LElementsKind: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LElementsKind(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(ElementsKind, "elements-kind")
+ DECLARE_HYDROGEN_ACCESSOR(ElementsKind)
+};
+
+
class LValueOf: public LTemplateInstruction<1, 1, 1> {
public:
LValueOf(LOperand* value, LOperand* temp) {
// If the maximum number of receiver maps has been exceeded, use the generic
// version of the IC.
- if (target_receiver_maps.length() > KeyedIC::kMaxKeyedPolymorphism) {
+ if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
return generic_stub;
}
explicit KeyedIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) {}
virtual ~KeyedIC() {}
- static const int kMaxKeyedPolymorphism = 4;
-
virtual MaybeObject* GetFastElementStubWithoutMapCheck(
bool is_js_array) = 0;
SMI_ACCESSORS(FixedArrayBase, length, kLengthOffset)
SMI_ACCESSORS(ByteArray, length, kLengthOffset)
+// TODO(jkummerow): Investigate if it's possible to s/INT/SMI/ here (and
+// subsequently unify H{Fixed,External}ArrayLength).
INT_ACCESSORS(ExternalArray, length, kLengthOffset)
MapList* maps_; // weak.
int code_flags_;
- static const int kDefaultListAllocationSize =
- KeyedIC::kMaxKeyedPolymorphism + 1;
+ static const int kDefaultListAllocationSize = kMaxKeyedPolymorphism + 1;
};
if (name != NULL) {
PrintF(out, "extra_ic_state = %s\n", name);
} else {
- PrintF(out, "etra_ic_state = %d\n", extra);
+ PrintF(out, "extra_ic_state = %d\n", extra);
}
}
static const int kOptimizableOffset = kKindSpecificFlagsOffset;
static const int kStackSlotsOffset = kKindSpecificFlagsOffset;
static const int kCheckTypeOffset = kKindSpecificFlagsOffset;
- static const int kExternalArrayTypeOffset = kKindSpecificFlagsOffset;
static const int kCompareStateOffset = kStubMajorKeyOffset + 1;
static const int kUnaryOpTypeOffset = kStubMajorKeyOffset + 1;
#include "v8.h"
#include "ast.h"
+#include "code-stubs.h"
#include "compiler.h"
#include "ic.h"
#include "macro-assembler.h"
}
+bool TypeFeedbackOracle::LoadIsMegamorphicWithTypeInfo(Property* expr) {
+ Handle<Object> map_or_code(GetInfo(expr->id()));
+ if (map_or_code->IsCode()) {
+ Handle<Code> code = Handle<Code>::cast(map_or_code);
+ Builtins* builtins = Isolate::Current()->builtins();
+ return code->is_keyed_load_stub() &&
+ *code != builtins->builtin(Builtins::kKeyedLoadIC_Generic) &&
+ code->ic_state() == MEGAMORPHIC;
+ }
+ return false;
+}
+
+
bool TypeFeedbackOracle::StoreIsMonomorphicNormal(Expression* expr) {
Handle<Object> map_or_code(GetInfo(expr->id()));
if (map_or_code->IsMap()) return true;
}
+bool TypeFeedbackOracle::StoreIsMegamorphicWithTypeInfo(Expression* expr) {
+ Handle<Object> map_or_code(GetInfo(expr->id()));
+ if (map_or_code->IsCode()) {
+ Handle<Code> code = Handle<Code>::cast(map_or_code);
+ Builtins* builtins = Isolate::Current()->builtins();
+ return code->is_keyed_store_stub() &&
+ *code != builtins->builtin(Builtins::kKeyedStoreIC_Generic) &&
+ code->ic_state() == MEGAMORPHIC;
+ }
+ return false;
+}
+
+
bool TypeFeedbackOracle::CallIsMonomorphic(Call* expr) {
Handle<Object> value = GetInfo(expr->id());
return value->IsMap() || value->IsSmi();
}
+void TypeFeedbackOracle::CollectKeyedReceiverTypes(
+ unsigned ast_id,
+ ZoneMapList* types) {
+ Handle<Object> object = GetInfo(ast_id);
+ if (!object->IsCode()) return;
+ Handle<Code> code = Handle<Code>::cast(object);
+ if (code->kind() == Code::KEYED_LOAD_IC ||
+ code->kind() == Code::KEYED_STORE_IC) {
+ AssertNoAllocation no_allocation;
+ int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
+ for (RelocIterator it(*code, mask); !it.done(); it.next()) {
+ RelocInfo* info = it.rinfo();
+ Object* object = info->target_object();
+ if (object->IsMap()) {
+ types->Add(Handle<Map>(Map::cast(object)));
+ }
+ }
+ }
+}
+
+
void TypeFeedbackOracle::SetInfo(unsigned ast_id, Object* target) {
ASSERT(dictionary_->FindEntry(ast_id) == NumberDictionary::kNotFound);
MaybeObject* maybe_result = dictionary_->AtNumberPut(ast_id, target);
namespace v8 {
namespace internal {
+const int kMaxKeyedPolymorphism = 4;
+
// Unknown
// | \____________
// | |
TypeFeedbackOracle(Handle<Code> code, Handle<Context> global_context);
bool LoadIsMonomorphicNormal(Property* expr);
+ bool LoadIsMegamorphicWithTypeInfo(Property* expr);
bool StoreIsMonomorphicNormal(Expression* expr);
+ bool StoreIsMegamorphicWithTypeInfo(Expression* expr);
bool CallIsMonomorphic(Call* expr);
Handle<Map> LoadMonomorphicReceiverType(Property* expr);
ZoneMapList* CallReceiverTypes(Call* expr,
Handle<String> name,
CallKind call_kind);
+ void CollectKeyedReceiverTypes(unsigned ast_id,
+ ZoneMapList* types);
CheckType GetCallCheckType(Call* expr);
Handle<JSObject> GetPrototypeForPrimitiveCheck(CheckType check);
}
+void LCodeGen::DoElementsKind(LElementsKind* instr) {
+ Register result = ToRegister(instr->result());
+ Register input = ToRegister(instr->InputAt(0));
+
+ // Load map into |result|.
+ __ movq(result, FieldOperand(input, HeapObject::kMapOffset));
+ // Load the map's "bit field 2" into |result|. We only need the first byte.
+ __ movzxbq(result, FieldOperand(result, Map::kBitField2Offset));
+ // Retrieve elements_kind from bit field 2.
+ __ and_(result, Immediate(Map::kElementsKindMask));
+ __ shr(result, Immediate(Map::kElementsKindShift));
+}
+
+
void LCodeGen::DoValueOf(LValueOf* instr) {
Register input = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
}
+void LCodeGen::DoCmpConstantEq(LCmpConstantEq* instr) {
+ Register left = ToRegister(instr->InputAt(0));
+ Register result = ToRegister(instr->result());
+
+ Label done;
+ __ cmpq(left, Immediate(instr->hydrogen()->right()));
+ __ LoadRoot(result, Heap::kTrueValueRootIndex);
+ __ j(equal, &done, Label::kNear);
+ __ LoadRoot(result, Heap::kFalseValueRootIndex);
+ __ bind(&done);
+}
+
+
+void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) {
+ Register left = ToRegister(instr->InputAt(0));
+ int true_block = chunk_->LookupDestination(instr->true_block_id());
+ int false_block = chunk_->LookupDestination(instr->false_block_id());
+
+ __ cmpq(left, Immediate(instr->hydrogen()->right()));
+ EmitBranch(true_block, false_block, equal);
+}
+
+
void LCodeGen::DoIsNull(LIsNull* instr) {
Register reg = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
Register input = ToRegister(instr->InputAt(0));
__ movq(result, FieldOperand(input, JSObject::kElementsOffset));
if (FLAG_debug_code) {
- Label done;
+ Label done, ok, fail;
__ CompareRoot(FieldOperand(result, HeapObject::kMapOffset),
Heap::kFixedArrayMapRootIndex);
__ j(equal, &done, Label::kNear);
Register temp((result.is(rax)) ? rbx : rax);
__ push(temp);
__ movq(temp, FieldOperand(result, HeapObject::kMapOffset));
- __ movzxbq(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
- __ subq(temp, Immediate(FIRST_EXTERNAL_ARRAY_TYPE));
- __ cmpq(temp, Immediate(kExternalArrayTypeCount));
+ __ movzxbq(temp, FieldOperand(temp, Map::kBitField2Offset));
+ __ and_(temp, Immediate(Map::kElementsKindMask));
+ __ shr(temp, Immediate(Map::kElementsKindShift));
+ __ cmpl(temp, Immediate(JSObject::FAST_ELEMENTS));
+ __ j(equal, &ok, Label::kNear);
+ __ cmpl(temp, Immediate(JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND));
+ __ j(less, &fail, Label::kNear);
+ __ cmpl(temp, Immediate(JSObject::LAST_EXTERNAL_ARRAY_ELEMENTS_KIND));
+ __ j(less_equal, &ok, Label::kNear);
+ __ bind(&fail);
+ __ Abort("Check for fast or external elements failed");
+ __ bind(&ok);
__ pop(temp);
- __ Check(below, "Check for fast elements failed.");
__ bind(&done);
}
}
HCompareSymbolEq* compare = HCompareSymbolEq::cast(v);
return new LCmpSymbolEqAndBranch(UseRegisterAtStart(compare->left()),
UseRegisterAtStart(compare->right()));
+ } else if (v->IsCompareConstantEq()) {
+ HCompareConstantEq* compare = HCompareConstantEq::cast(v);
+ return new LCmpConstantEqAndBranch(UseRegisterAtStart(compare->value()));
} else if (v->IsTypeofIs()) {
HTypeofIs* typeof_is = HTypeofIs::cast(v);
return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value()));
}
+LInstruction* LChunkBuilder::DoCompareConstantEq(
+ HCompareConstantEq* instr) {
+ LOperand* left = UseRegisterAtStart(instr->value());
+ return DefineAsRegister(new LCmpConstantEq(left));
+}
+
+
LInstruction* LChunkBuilder::DoIsNull(HIsNull* instr) {
ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseRegisterAtStart(instr->value());
}
+LInstruction* LChunkBuilder::DoElementsKind(HElementsKind* instr) {
+ LOperand* object = UseRegisterAtStart(instr->value());
+ return DefineAsRegister(new LElementsKind(object));
+}
+
+
LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
LOperand* object = UseRegister(instr->value());
LValueOf* result = new LValueOf(object);
V(ClampTToUint8) \
V(ClassOfTest) \
V(ClassOfTestAndBranch) \
+ V(CmpConstantEq) \
+ V(CmpConstantEqAndBranch) \
V(CmpID) \
V(CmpIDAndBranch) \
V(CmpJSObjectEq) \
V(Deoptimize) \
V(DivI) \
V(DoubleToI) \
+ V(ElementsKind) \
V(ExternalArrayLength) \
V(FixedArrayLength) \
V(FunctionLiteral) \
};
+class LCmpConstantEq: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LCmpConstantEq(LOperand* left) {
+ inputs_[0] = left;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(CmpConstantEq, "cmp-constant-eq")
+ DECLARE_HYDROGEN_ACCESSOR(CompareConstantEq)
+};
+
+
+class LCmpConstantEqAndBranch: public LControlInstruction<1, 0> {
+ public:
+ explicit LCmpConstantEqAndBranch(LOperand* left) {
+ inputs_[0] = left;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(CmpConstantEqAndBranch,
+ "cmp-constant-eq-and-branch")
+ DECLARE_HYDROGEN_ACCESSOR(CompareConstantEq)
+};
+
+
class LIsNull: public LTemplateInstruction<1, 1, 0> {
public:
explicit LIsNull(LOperand* value) {
};
+class LElementsKind: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LElementsKind(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(ElementsKind, "elements-kind")
+ DECLARE_HYDROGEN_ACCESSOR(ElementsKind)
+};
+
+
class LValueOf: public LTemplateInstruction<1, 1, 0> {
public:
explicit LValueOf(LOperand* value) {