Version 3.0.6
Allowed getters and setters on JSArray elements (Issue 900).
Stopped JSON objects from hitting inherited setters (part of
Issue 1015).
Allowed numbers and strings as names of getters/setters in object
initializer (Issue 820).
Added use_system_v8 option to gyp (off by default), to make it easier
for Linux distributions to ship with system-provided V8 library.
Exported external array data accessors (Issue 1016).
Added labelled thread names to help with debugging (on Linux).
git-svn-id: http://v8.googlecode.com/svn/trunk@6169 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h
index 36f7507f..cd7f07f 100644
--- a/src/arm/assembler-arm.h
+++ b/src/arm/assembler-arm.h
@@ -66,13 +66,14 @@
// such that we use an enum in optimized mode, and the struct in debug
// mode. This way we get the compile-time error checking in debug mode
// and best performance in optimized code.
-//
+
// Core register
struct Register {
static const int kNumRegisters = 16;
static const int kNumAllocatableRegisters = 8;
static int ToAllocationIndex(Register reg) {
+ ASSERT(reg.code() < kNumAllocatableRegisters);
return reg.code();
}
@@ -132,7 +133,7 @@
const Register r6 = { 6 };
const Register r7 = { 7 };
const Register r8 = { 8 }; // Used as context register.
-const Register r9 = { 9 };
+const Register r9 = { 9 }; // Used as lithium codegen scratch register.
const Register r10 = { 10 }; // Used as roots register.
const Register fp = { 11 };
const Register ip = { 12 };
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index 7c3ea89..577ac63 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -917,13 +917,6 @@
}
-void RecordWriteStub::Generate(MacroAssembler* masm) {
- __ add(offset_, object_, Operand(offset_));
- __ RecordWriteHelper(object_, offset_, scratch_);
- __ Ret();
-}
-
-
// On entry lhs_ and rhs_ are the values to be compared.
// On exit r0 is 0, positive or negative to indicate the result of
// the comparison.
@@ -1229,16 +1222,22 @@
bool generate_code_to_calculate_answer = true;
if (ShouldGenerateFPCode()) {
+ // DIV has neither SmiSmi fast code nor specialized slow code.
+ // So don't try to patch a DIV Stub.
if (runtime_operands_type_ == BinaryOpIC::DEFAULT) {
switch (op_) {
case Token::ADD:
case Token::SUB:
case Token::MUL:
- case Token::DIV:
GenerateTypeTransition(masm); // Tail call.
generate_code_to_calculate_answer = false;
break;
+ case Token::DIV:
+ // DIV has neither SmiSmi fast code nor specialized slow code.
+ // So don't try to patch a DIV Stub.
+ break;
+
default:
break;
}
@@ -1299,7 +1298,8 @@
// HEAP_NUMBERS stub is slower than GENERIC on a pair of smis.
// r0 is known to be a smi. If r1 is also a smi then switch to GENERIC.
Label r1_is_not_smi;
- if (runtime_operands_type_ == BinaryOpIC::HEAP_NUMBERS) {
+ if ((runtime_operands_type_ == BinaryOpIC::HEAP_NUMBERS) &&
+ HasSmiSmiFastPath()) {
__ tst(r1, Operand(kSmiTagMask));
__ b(ne, &r1_is_not_smi);
GenerateTypeTransition(masm); // Tail call.
diff --git a/src/arm/code-stubs-arm.h b/src/arm/code-stubs-arm.h
index 8ffca77..9fa8687 100644
--- a/src/arm/code-stubs-arm.h
+++ b/src/arm/code-stubs-arm.h
@@ -77,7 +77,7 @@
rhs_(rhs),
constant_rhs_(constant_rhs),
specialized_on_rhs_(RhsIsOneWeWantToOptimizeFor(op, constant_rhs)),
- runtime_operands_type_(BinaryOpIC::DEFAULT),
+ runtime_operands_type_(BinaryOpIC::UNINIT_OR_SMI),
name_(NULL) { }
GenericBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info)
@@ -178,6 +178,10 @@
return lhs_is_r0 ? r1 : r0;
}
+ bool HasSmiSmiFastPath() {
+ return op_ != Token::DIV;
+ }
+
bool ShouldGenerateSmiCode() {
return ((op_ != Token::DIV && op_ != Token::MOD) || specialized_on_rhs_) &&
runtime_operands_type_ != BinaryOpIC::HEAP_NUMBERS &&
@@ -437,43 +441,6 @@
};
-class RecordWriteStub : public CodeStub {
- public:
- RecordWriteStub(Register object, Register offset, Register scratch)
- : object_(object), offset_(offset), scratch_(scratch) { }
-
- void Generate(MacroAssembler* masm);
-
- private:
- Register object_;
- Register offset_;
- Register scratch_;
-
- // Minor key encoding in 12 bits. 4 bits for each of the three
- // registers (object, offset and scratch) OOOOAAAASSSS.
- class ScratchBits: public BitField<uint32_t, 0, 4> {};
- class OffsetBits: public BitField<uint32_t, 4, 4> {};
- class ObjectBits: public BitField<uint32_t, 8, 4> {};
-
- Major MajorKey() { return RecordWrite; }
-
- int MinorKey() {
- // Encode the registers.
- return ObjectBits::encode(object_.code()) |
- OffsetBits::encode(offset_.code()) |
- ScratchBits::encode(scratch_.code());
- }
-
-#ifdef DEBUG
- void Print() {
- PrintF("RecordWriteStub (object reg %d), (offset reg %d),"
- " (scratch reg %d)\n",
- object_.code(), offset_.code(), scratch_.code());
- }
-#endif
-};
-
-
// Enter C code from generated RegExp code in a way that allows
// the C code to fix the return address in case of a GC.
// Currently only needed on ARM.
diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc
index 59bc14e..4d061d2 100644
--- a/src/arm/codegen-arm.cc
+++ b/src/arm/codegen-arm.cc
@@ -5618,12 +5618,10 @@
// (or them and test against Smi mask.)
__ mov(tmp2, tmp1);
- RecordWriteStub recordWrite1(tmp1, index1, tmp3);
- __ CallStub(&recordWrite1);
-
- RecordWriteStub recordWrite2(tmp2, index2, tmp3);
- __ CallStub(&recordWrite2);
-
+ __ add(index1, index1, tmp1);
+ __ add(index2, index2, tmp1);
+ __ RecordWriteHelper(tmp1, index1, tmp3);
+ __ RecordWriteHelper(tmp2, index2, tmp3);
__ bind(&done);
deferred->BindExit();
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index d254918..0275730 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -38,6 +38,8 @@
#include "scopes.h"
#include "stub-cache.h"
+#include "arm/code-stubs-arm.h"
+
namespace v8 {
namespace internal {
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index 9c8e834..87efc92 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -767,11 +767,6 @@
}
-LInstruction* LChunkBuilder::DefineSameAsAny(LInstruction* instr) {
- return Define(instr, new LUnallocated(LUnallocated::SAME_AS_ANY_INPUT));
-}
-
-
LInstruction* LChunkBuilder::DefineSameAsFirst(LInstruction* instr) {
return Define(instr, new LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
}
@@ -1016,9 +1011,6 @@
HInstruction* current = block->first();
int start = chunk_->instructions()->length();
while (current != NULL && !is_aborted()) {
- if (FLAG_trace_environment) {
- PrintF("Process instruction %d\n", current->id());
- }
// Code for constants in registers is generated lazily.
if (!current->EmitAtUses()) {
VisitInstruction(current);
@@ -1125,7 +1117,7 @@
LEnvironment* outer = CreateEnvironment(hydrogen_env->outer());
int ast_id = hydrogen_env->ast_id();
ASSERT(ast_id != AstNode::kNoNumber);
- int value_count = hydrogen_env->values()->length();
+ int value_count = hydrogen_env->length();
LEnvironment* result = new LEnvironment(hydrogen_env->closure(),
ast_id,
hydrogen_env->parameter_count(),
@@ -1225,7 +1217,6 @@
ASSERT(compare->value()->representation().IsTagged());
return new LHasInstanceTypeAndBranch(UseRegisterAtStart(compare->value()),
- TempRegister(),
first_id,
second_id);
} else if (v->IsHasCachedArrayIndex()) {
@@ -1238,11 +1229,8 @@
HIsNull* compare = HIsNull::cast(v);
ASSERT(compare->value()->representation().IsTagged());
- // We only need a temp register for non-strict compare.
- LOperand* temp = compare->is_strict() ? NULL : TempRegister();
return new LIsNullAndBranch(UseRegisterAtStart(compare->value()),
compare->is_strict(),
- temp,
first_id,
second_id);
} else if (v->IsIsObject()) {
@@ -1295,12 +1283,8 @@
HCompareMapAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseRegisterAtStart(instr->value());
- HBasicBlock* first = instr->FirstSuccessor();
- HBasicBlock* second = instr->SecondSuccessor();
- return new LCmpMapAndBranch(value,
- instr->map(),
- first->block_id(),
- second->block_id());
+ LOperand* temp = TempRegister();
+ return new LCmpMapAndBranch(value, temp);
}
@@ -1370,6 +1354,9 @@
return AssignEnvironment(DefineAsRegister(result));
case kMathSqrt:
return DefineSameAsFirst(result);
+ case kMathRound:
+ Abort("MathRound LUnaryMathOperation not implemented");
+ return NULL;
case kMathPowHalf:
Abort("MathPowHalf LUnaryMathOperation not implemented");
return NULL;
@@ -1774,9 +1761,11 @@
LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
- LOperand* temp = TempRegister();
+ LOperand* temp1 = TempRegister();
+ LOperand* temp2 = TempRegister();
LInstruction* result =
- new LCheckPrototypeMaps(temp,
+ new LCheckPrototypeMaps(temp1,
+ temp2,
instr->holder(),
instr->receiver_map());
return AssignEnvironment(result);
@@ -1853,8 +1842,7 @@
LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
HLoadFunctionPrototype* instr) {
return AssignEnvironment(DefineAsRegister(
- new LLoadFunctionPrototype(UseRegister(instr->function()),
- TempRegister())));
+ new LLoadFunctionPrototype(UseRegister(instr->function()))));
}
@@ -2058,13 +2046,7 @@
}
}
- if (FLAG_trace_environment) {
- PrintF("Reconstructed environment ast_id=%d, instr_id=%d\n",
- instr->ast_id(),
- instr->id());
- env->PrintToStd();
- }
- ASSERT(env->values()->length() == instr->environment_height());
+ ASSERT(env->length() == instr->environment_length());
// If there is an instruction pending deoptimization environment create a
// lazy bailout instruction to capture the environment.
diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h
index 5b152ef..2f8cc1c 100644
--- a/src/arm/lithium-arm.h
+++ b/src/arm/lithium-arm.h
@@ -726,11 +726,9 @@
public:
LIsNullAndBranch(LOperand* value,
bool is_strict,
- LOperand* temp,
int true_block_id,
int false_block_id)
: LIsNull(value, is_strict),
- temp_(temp),
true_block_id_(true_block_id),
false_block_id_(false_block_id) { }
@@ -741,10 +739,7 @@
int true_block_id() const { return true_block_id_; }
int false_block_id() const { return false_block_id_; }
- LOperand* temp() const { return temp_; }
-
private:
- LOperand* temp_;
int true_block_id_;
int false_block_id_;
};
@@ -839,11 +834,9 @@
class LHasInstanceTypeAndBranch: public LHasInstanceType {
public:
LHasInstanceTypeAndBranch(LOperand* value,
- LOperand* temporary,
int true_block_id,
int false_block_id)
: LHasInstanceType(value),
- temp_(temporary),
true_block_id_(true_block_id),
false_block_id_(false_block_id) { }
@@ -855,10 +848,7 @@
int true_block_id() const { return true_block_id_; }
int false_block_id() const { return false_block_id_; }
- LOperand* temp() { return temp_; }
-
private:
- LOperand* temp_;
int true_block_id_;
int false_block_id_;
};
@@ -1121,27 +1111,25 @@
class LCmpMapAndBranch: public LUnaryOperation {
public:
- LCmpMapAndBranch(LOperand* value,
- Handle<Map> map,
- int true_block_id,
- int false_block_id)
- : LUnaryOperation(value),
- map_(map),
- true_block_id_(true_block_id),
- false_block_id_(false_block_id) { }
+ LCmpMapAndBranch(LOperand* value, LOperand* temp)
+ : LUnaryOperation(value), temp_(temp) { }
DECLARE_CONCRETE_INSTRUCTION(CmpMapAndBranch, "cmp-map-and-branch")
+ DECLARE_HYDROGEN_ACCESSOR(CompareMapAndBranch)
virtual bool IsControl() const { return true; }
- Handle<Map> map() const { return map_; }
- int true_block_id() const { return true_block_id_; }
- int false_block_id() const { return false_block_id_; }
+ LOperand* temp() const { return temp_; }
+ Handle<Map> map() const { return hydrogen()->map(); }
+ int true_block_id() const {
+ return hydrogen()->true_destination()->block_id();
+ }
+ int false_block_id() const {
+ return hydrogen()->false_destination()->block_id();
+ }
private:
- Handle<Map> map_;
- int true_block_id_;
- int false_block_id_;
+ LOperand* temp_;
};
@@ -1265,17 +1253,13 @@
class LLoadFunctionPrototype: public LUnaryOperation {
public:
- LLoadFunctionPrototype(LOperand* function, LOperand* temporary)
- : LUnaryOperation(function), temporary_(temporary) { }
+ explicit LLoadFunctionPrototype(LOperand* function)
+ : LUnaryOperation(function) { }
DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype, "load-function-prototype")
DECLARE_HYDROGEN_ACCESSOR(LoadFunctionPrototype)
LOperand* function() const { return input(); }
- LOperand* temporary() const { return temporary_; }
-
- private:
- LOperand* temporary_;
};
@@ -1678,21 +1662,25 @@
class LCheckPrototypeMaps: public LInstruction {
public:
- LCheckPrototypeMaps(LOperand* temp,
+ LCheckPrototypeMaps(LOperand* temp1,
+ LOperand* temp2,
Handle<JSObject> holder,
Handle<Map> receiver_map)
- : temp_(temp),
+ : temp1_(temp1),
+ temp2_(temp2),
holder_(holder),
receiver_map_(receiver_map) { }
DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps, "check-prototype-maps")
- LOperand* temp() const { return temp_; }
+ LOperand* temp1() const { return temp1_; }
+ LOperand* temp2() const { return temp2_; }
Handle<JSObject> holder() const { return holder_; }
Handle<Map> receiver_map() const { return receiver_map_; }
private:
- LOperand* temp_;
+ LOperand* temp1_;
+ LOperand* temp2_;
Handle<JSObject> holder_;
Handle<Map> receiver_map_;
};
@@ -2074,7 +2062,6 @@
LInstruction* Define(LInstruction* instr);
LInstruction* DefineAsRegister(LInstruction* instr);
LInstruction* DefineAsSpilled(LInstruction* instr, int index);
- LInstruction* DefineSameAsAny(LInstruction* instr);
LInstruction* DefineSameAsFirst(LInstruction* instr);
LInstruction* DefineFixed(LInstruction* instr, Register reg);
LInstruction* DefineFixedDouble(LInstruction* instr, DoubleRegister reg);
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index 53a4325..bb2461c 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -598,7 +598,7 @@
DoubleRegister dbl_scratch = d0;
LUnallocated marker_operand(LUnallocated::NONE);
- Register core_scratch = r9;
+ Register core_scratch = scratch0();
bool destroys_core_scratch = false;
LGapResolver resolver(move->move_operands(), &marker_operand);
@@ -730,7 +730,53 @@
void LCodeGen::DoCallStub(LCallStub* instr) {
- Abort("DoCallStub unimplemented.");
+ ASSERT(ToRegister(instr->result()).is(r0));
+ switch (instr->hydrogen()->major_key()) {
+ case CodeStub::RegExpConstructResult: {
+ RegExpConstructResultStub stub;
+ CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+ break;
+ }
+ case CodeStub::RegExpExec: {
+ RegExpExecStub stub;
+ CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+ break;
+ }
+ case CodeStub::SubString: {
+ SubStringStub stub;
+ CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+ break;
+ }
+ case CodeStub::StringCharAt: {
+ Abort("StringCharAtStub unimplemented.");
+ break;
+ }
+ case CodeStub::MathPow: {
+ Abort("MathPowStub unimplemented.");
+ break;
+ }
+ case CodeStub::NumberToString: {
+ NumberToStringStub stub;
+ CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+ break;
+ }
+ case CodeStub::StringAdd: {
+ StringAddStub stub(NO_STRING_ADD_FLAGS);
+ CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+ break;
+ }
+ case CodeStub::StringCompare: {
+ StringCompareStub stub;
+ CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+ break;
+ }
+ case CodeStub::TranscendentalCache: {
+ Abort("TranscendentalCache unimplemented.");
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
}
@@ -750,8 +796,8 @@
void LCodeGen::DoMulI(LMulI* instr) {
+ Register scratch = scratch0();
Register left = ToRegister(instr->left());
- Register scratch = r9;
Register right = EmitLoadRegister(instr->right(), scratch);
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero) &&
@@ -813,6 +859,7 @@
void LCodeGen::DoShiftI(LShiftI* instr) {
+ Register scratch = scratch0();
LOperand* left = instr->left();
LOperand* right = instr->right();
ASSERT(left->Equals(instr->result()));
@@ -820,21 +867,21 @@
Register result = ToRegister(left);
if (right->IsRegister()) {
// Mask the right operand.
- __ and_(r9, ToRegister(right), Operand(0x1F));
+ __ and_(scratch, ToRegister(right), Operand(0x1F));
switch (instr->op()) {
case Token::SAR:
- __ mov(result, Operand(result, ASR, r9));
+ __ mov(result, Operand(result, ASR, scratch));
break;
case Token::SHR:
if (instr->can_deopt()) {
- __ mov(result, Operand(result, LSR, r9), SetCC);
+ __ mov(result, Operand(result, LSR, scratch), SetCC);
DeoptimizeIf(mi, instr->environment());
} else {
- __ mov(result, Operand(result, LSR, r9));
+ __ mov(result, Operand(result, LSR, scratch));
}
break;
case Token::SHL:
- __ mov(result, Operand(result, LSL, r9));
+ __ mov(result, Operand(result, LSL, scratch));
break;
default:
UNREACHABLE();
@@ -902,7 +949,6 @@
Register result = ToRegister(instr->result());
Register array = ToRegister(instr->input());
__ ldr(result, FieldMemOperand(array, JSArray::kLengthOffset));
- Abort("DoJSArrayLength untested.");
}
@@ -1060,11 +1106,10 @@
// Test for double values. Zero is false.
Label call_stub;
DoubleRegister dbl_scratch = d0;
- Register core_scratch = r9;
- ASSERT(!reg.is(core_scratch));
- __ ldr(core_scratch, FieldMemOperand(reg, HeapObject::kMapOffset));
+ Register scratch = scratch0();
+ __ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset));
__ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
- __ cmp(core_scratch, Operand(ip));
+ __ cmp(scratch, Operand(ip));
__ b(ne, &call_stub);
__ sub(ip, reg, Operand(kHeapObjectTag));
__ vldr(dbl_scratch, ip, HeapNumber::kValueOffset);
@@ -1171,11 +1216,41 @@
void LCodeGen::DoIsNull(LIsNull* instr) {
- Abort("DoIsNull unimplemented.");
+ Register reg = ToRegister(instr->input());
+ Register result = ToRegister(instr->result());
+
+ __ LoadRoot(ip, Heap::kNullValueRootIndex);
+ __ cmp(reg, ip);
+ if (instr->is_strict()) {
+ __ LoadRoot(result, Heap::kTrueValueRootIndex, eq);
+ __ LoadRoot(result, Heap::kFalseValueRootIndex, ne);
+ } else {
+ Label true_value, false_value, done;
+ __ b(eq, &true_value);
+ __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
+ __ cmp(ip, reg);
+ __ b(eq, &true_value);
+ __ tst(reg, Operand(kSmiTagMask));
+ __ b(eq, &false_value);
+ // Check for undetectable objects by looking in the bit field in
+ // the map. The object has already been smi checked.
+ Register scratch = result;
+ __ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset));
+ __ ldrb(scratch, FieldMemOperand(scratch, Map::kBitFieldOffset));
+ __ tst(scratch, Operand(1 << Map::kIsUndetectable));
+ __ b(ne, &true_value);
+ __ bind(&false_value);
+ __ LoadRoot(result, Heap::kFalseValueRootIndex);
+ __ jmp(&done);
+ __ bind(&true_value);
+ __ LoadRoot(result, Heap::kTrueValueRootIndex);
+ __ bind(&done);
+ }
}
void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) {
+ Register scratch = scratch0();
Register reg = ToRegister(instr->input());
// TODO(fsc): If the expression is known to be a smi, then it's
@@ -1199,7 +1274,6 @@
__ b(eq, false_label);
// Check for undetectable objects by looking in the bit field in
// the map. The object has already been smi checked.
- Register scratch = ToRegister(instr->temp());
__ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset));
__ ldrb(scratch, FieldMemOperand(scratch, Map::kBitFieldOffset));
__ tst(scratch, Operand(1 << Map::kIsUndetectable));
@@ -1277,8 +1351,8 @@
void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
+ Register scratch = scratch0();
Register input = ToRegister(instr->input());
- Register temp = ToRegister(instr->temp());
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
@@ -1288,7 +1362,7 @@
__ tst(input, Operand(kSmiTagMask));
__ b(eq, false_label);
- __ CompareObjectType(input, temp, temp, instr->TestType());
+ __ CompareObjectType(input, scratch, scratch, instr->TestType());
EmitBranch(true_block, false_block, instr->BranchCondition());
}
@@ -1327,7 +1401,14 @@
void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
- Abort("DoCmpMapAndBranch unimplemented.");
+ Register reg = ToRegister(instr->input());
+ Register temp = ToRegister(instr->temp());
+ int true_block = instr->true_block_id();
+ int false_block = instr->false_block_id();
+
+ __ ldr(temp, FieldMemOperand(reg, HeapObject::kMapOffset));
+ __ cmp(temp, Operand(instr->map()));
+ EmitBranch(true_block, false_block, eq);
}
@@ -1429,7 +1510,14 @@
void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
- Abort("DoLoadNamedField unimplemented.");
+ Register object = ToRegister(instr->input());
+ Register result = ToRegister(instr->result());
+ if (instr->hydrogen()->is_in_object()) {
+ __ ldr(result, FieldMemOperand(object, instr->hydrogen()->offset()));
+ } else {
+ __ ldr(result, FieldMemOperand(object, JSObject::kPropertiesOffset));
+ __ ldr(result, FieldMemOperand(result, instr->hydrogen()->offset()));
+ }
}
@@ -1445,19 +1533,19 @@
void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
+ Register scratch = scratch0();
Register function = ToRegister(instr->function());
- Register temp = ToRegister(instr->temporary());
Register result = ToRegister(instr->result());
// Check that the function really is a function. Load map into the
// result register.
- __ CompareObjectType(function, result, temp, JS_FUNCTION_TYPE);
+ __ CompareObjectType(function, result, scratch, JS_FUNCTION_TYPE);
DeoptimizeIf(ne, instr->environment());
// Make sure that the function has an instance prototype.
Label non_instance;
- __ ldrb(temp, FieldMemOperand(result, Map::kBitFieldOffset));
- __ tst(temp, Operand(1 << Map::kHasNonInstancePrototype));
+ __ ldrb(scratch, FieldMemOperand(result, Map::kBitFieldOffset));
+ __ tst(scratch, Operand(1 << Map::kHasNonInstancePrototype));
__ b(ne, &non_instance);
// Get the prototype or initial map from the function.
@@ -1471,7 +1559,7 @@
// If the function does not have an initial map, we're done.
Label done;
- __ CompareObjectType(result, temp, temp, MAP_TYPE);
+ __ CompareObjectType(result, scratch, scratch, MAP_TYPE);
__ b(ne, &done);
// Get the prototype from the initial map.
@@ -1585,7 +1673,9 @@
void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
- Abort("DoCallConstantFunction unimplemented.");
+ ASSERT(ToRegister(instr->result()).is(r0));
+ __ mov(r1, Operand(instr->function()));
+ CallKnownFunction(instr->function(), instr->arity(), instr);
}
@@ -1645,7 +1735,13 @@
void LCodeGen::DoCallFunction(LCallFunction* instr) {
- Abort("DoCallFunction unimplemented.");
+ ASSERT(ToRegister(instr->result()).is(r0));
+
+ int arity = instr->arity();
+ CallFunctionStub stub(arity, NOT_IN_LOOP, RECEIVER_MIGHT_BE_VALUE);
+ CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+ __ Drop(1);
+ __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
}
@@ -1693,7 +1789,8 @@
void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
- Abort("DoBoundsCheck unimplemented.");
+ __ cmp(ToRegister(instr->index()), ToOperand(instr->length()));
+ DeoptimizeIf(hs, instr->environment());
}
@@ -1798,10 +1895,10 @@
};
DoubleRegister input_reg = ToDoubleRegister(instr->input());
+ Register scratch = scratch0();
Register reg = ToRegister(instr->result());
Register temp1 = ToRegister(instr->temp1());
Register temp2 = ToRegister(instr->temp2());
- Register scratch = r9;
DeferredNumberTagD* deferred = new DeferredNumberTagD(this, instr);
if (FLAG_inline_new) {
@@ -1849,8 +1946,7 @@
void LCodeGen::EmitNumberUntagD(Register input_reg,
DoubleRegister result_reg,
LEnvironment* env) {
- Register core_scratch = r9;
- ASSERT(!input_reg.is(core_scratch));
+ Register scratch = scratch0();
SwVfpRegister flt_scratch = s0;
ASSERT(!result_reg.is(d0));
@@ -1861,9 +1957,9 @@
__ b(eq, &load_smi);
// Heap number map check.
- __ ldr(core_scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset));
+ __ ldr(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset));
__ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
- __ cmp(core_scratch, Operand(ip));
+ __ cmp(scratch, Operand(ip));
__ b(eq, &heap_number);
__ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
@@ -1905,16 +2001,15 @@
void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
Label done;
Register input_reg = ToRegister(instr->input());
- Register core_scratch = r9;
- ASSERT(!input_reg.is(core_scratch));
+ Register scratch = scratch0();
DoubleRegister dbl_scratch = d0;
SwVfpRegister flt_scratch = s0;
DoubleRegister dbl_tmp = ToDoubleRegister(instr->temp());
// Heap number map check.
- __ ldr(core_scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset));
+ __ ldr(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset));
__ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
- __ cmp(core_scratch, Operand(ip));
+ __ cmp(scratch, Operand(ip));
if (instr->truncating()) {
Label heap_number;
@@ -2026,33 +2121,99 @@
void LCodeGen::DoCheckMap(LCheckMap* instr) {
+ Register scratch = scratch0();
LOperand* input = instr->input();
ASSERT(input->IsRegister());
Register reg = ToRegister(input);
- __ ldr(r9, FieldMemOperand(reg, HeapObject::kMapOffset));
- __ cmp(r9, Operand(instr->hydrogen()->map()));
+ __ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset));
+ __ cmp(scratch, Operand(instr->hydrogen()->map()));
DeoptimizeIf(ne, instr->environment());
}
void LCodeGen::LoadPrototype(Register result,
Handle<JSObject> prototype) {
- Abort("LoadPrototype unimplemented.");
+ if (Heap::InNewSpace(*prototype)) {
+ Handle<JSGlobalPropertyCell> cell =
+ Factory::NewJSGlobalPropertyCell(prototype);
+ __ mov(result, Operand(cell));
+ } else {
+ __ mov(result, Operand(prototype));
+ }
}
void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
- Abort("DoCheckPrototypeMaps unimplemented.");
+ Register temp1 = ToRegister(instr->temp1());
+ Register temp2 = ToRegister(instr->temp2());
+
+ Handle<JSObject> holder = instr->holder();
+ Handle<Map> receiver_map = instr->receiver_map();
+ Handle<JSObject> current_prototype(JSObject::cast(receiver_map->prototype()));
+
+ // Load prototype object.
+ LoadPrototype(temp1, current_prototype);
+
+ // Check prototype maps up to the holder.
+ while (!current_prototype.is_identical_to(holder)) {
+ __ ldr(temp2, FieldMemOperand(temp1, HeapObject::kMapOffset));
+ __ cmp(temp2, Operand(Handle<Map>(current_prototype->map())));
+ DeoptimizeIf(ne, instr->environment());
+ current_prototype =
+ Handle<JSObject>(JSObject::cast(current_prototype->GetPrototype()));
+ // Load next prototype object.
+ LoadPrototype(temp1, current_prototype);
+ }
+
+ // Check the holder map.
+ __ ldr(temp2, FieldMemOperand(temp1, HeapObject::kMapOffset));
+ __ cmp(temp2, Operand(Handle<Map>(current_prototype->map())));
+ DeoptimizeIf(ne, instr->environment());
}
void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
- Abort("DoArrayLiteral unimplemented.");
+ __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+ __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset));
+ __ mov(r2, Operand(Smi::FromInt(instr->hydrogen()->literal_index())));
+ __ mov(r1, Operand(instr->hydrogen()->constant_elements()));
+ __ Push(r3, r2, r1);
+
+ // Pick the right runtime function or stub to call.
+ int length = instr->hydrogen()->length();
+ if (instr->hydrogen()->IsCopyOnWrite()) {
+ ASSERT(instr->hydrogen()->depth() == 1);
+ FastCloneShallowArrayStub::Mode mode =
+ FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS;
+ FastCloneShallowArrayStub stub(mode, length);
+ CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+ } else if (instr->hydrogen()->depth() > 1) {
+ CallRuntime(Runtime::kCreateArrayLiteral, 3, instr);
+ } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
+ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr);
+ } else {
+ FastCloneShallowArrayStub::Mode mode =
+ FastCloneShallowArrayStub::CLONE_ELEMENTS;
+ FastCloneShallowArrayStub stub(mode, length);
+ CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+ }
}
void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
- Abort("DoObjectLiteral unimplemented.");
+ __ ldr(r4, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+ __ ldr(r4, FieldMemOperand(r4, JSFunction::kLiteralsOffset));
+ __ mov(r3, Operand(Smi::FromInt(instr->hydrogen()->literal_index())));
+ __ mov(r2, Operand(instr->hydrogen()->constant_properties()));
+ __ mov(r1, Operand(Smi::FromInt(instr->hydrogen()->fast_elements() ? 1 : 0)));
+ __ Push(r4, r3, r2, r1);
+
+ // Pick the right runtime function to call.
+ if (instr->hydrogen()->depth() > 1) {
+ CallRuntime(Runtime::kCreateObjectLiteral, 4, instr);
+ } else {
+ CallRuntime(Runtime::kCreateObjectLiteralShallow, 4, instr);
+ }
}
@@ -2097,8 +2258,7 @@
Register input,
Handle<String> type_name) {
Condition final_branch_condition = no_condition;
- Register core_scratch = r9;
- ASSERT(!input.is(core_scratch));
+ Register scratch = scratch0();
if (type_name->Equals(Heap::number_symbol())) {
__ tst(input, Operand(kSmiTagMask));
__ b(eq, true_label);
@@ -2114,7 +2274,7 @@
__ ldrb(ip, FieldMemOperand(input, Map::kBitFieldOffset));
__ tst(ip, Operand(1 << Map::kIsUndetectable));
__ b(ne, false_label);
- __ CompareInstanceType(input, core_scratch, FIRST_NONSTRING_TYPE);
+ __ CompareInstanceType(input, scratch, FIRST_NONSTRING_TYPE);
final_branch_condition = lo;
} else if (type_name->Equals(Heap::boolean_symbol())) {
@@ -2140,10 +2300,10 @@
} else if (type_name->Equals(Heap::function_symbol())) {
__ tst(input, Operand(kSmiTagMask));
__ b(eq, false_label);
- __ CompareObjectType(input, input, core_scratch, JS_FUNCTION_TYPE);
+ __ CompareObjectType(input, input, scratch, JS_FUNCTION_TYPE);
__ b(eq, true_label);
// Regular expressions => 'function' (they are callable).
- __ CompareInstanceType(input, core_scratch, JS_REGEXP_TYPE);
+ __ CompareInstanceType(input, scratch, JS_REGEXP_TYPE);
final_branch_condition = eq;
} else if (type_name->Equals(Heap::object_symbol())) {
@@ -2153,16 +2313,16 @@
__ cmp(input, ip);
__ b(eq, true_label);
// Regular expressions => 'function', not 'object'.
- __ CompareObjectType(input, input, core_scratch, JS_REGEXP_TYPE);
+ __ CompareObjectType(input, input, scratch, JS_REGEXP_TYPE);
__ b(eq, false_label);
// Check for undetectable objects => false.
__ ldrb(ip, FieldMemOperand(input, Map::kBitFieldOffset));
__ tst(ip, Operand(1 << Map::kIsUndetectable));
__ b(ne, false_label);
// Check for JS objects => true.
- __ CompareInstanceType(input, core_scratch, FIRST_JS_OBJECT_TYPE);
+ __ CompareInstanceType(input, scratch, FIRST_JS_OBJECT_TYPE);
__ b(lo, false_label);
- __ CompareInstanceType(input, core_scratch, LAST_JS_OBJECT_TYPE);
+ __ CompareInstanceType(input, scratch, LAST_JS_OBJECT_TYPE);
final_branch_condition = ls;
} else {
diff --git a/src/arm/lithium-codegen-arm.h b/src/arm/lithium-codegen-arm.h
index 541a699..608efa9 100644
--- a/src/arm/lithium-codegen-arm.h
+++ b/src/arm/lithium-codegen-arm.h
@@ -103,6 +103,8 @@
HGraph* graph() const { return chunk_->graph(); }
MacroAssembler* masm() const { return masm_; }
+ Register scratch0() { return r9; }
+
int GetNextEmittedBlock(int block);
LInstruction* GetNextInstruction();
diff --git a/src/cpu-profiler.cc b/src/cpu-profiler.cc
index f13c0ee..fcf539f 100644
--- a/src/cpu-profiler.cc
+++ b/src/cpu-profiler.cc
@@ -47,7 +47,8 @@
ProfilerEventsProcessor::ProfilerEventsProcessor(ProfileGenerator* generator)
- : generator_(generator),
+ : Thread("v8:ProfEvntProc"),
+ generator_(generator),
running_(true),
ticks_buffer_(sizeof(TickSampleEventRecord),
kTickSamplesBufferChunkSize,
diff --git a/src/d8-debug.h b/src/d8-debug.h
index c7acc2f..4e33e6f 100644
--- a/src/d8-debug.h
+++ b/src/d8-debug.h
@@ -98,7 +98,8 @@
class ReceiverThread: public i::Thread {
public:
explicit ReceiverThread(RemoteDebugger* remote_debugger)
- : remote_debugger_(remote_debugger) {}
+ : Thread("d8:ReceiverThrd"),
+ remote_debugger_(remote_debugger) {}
~ReceiverThread() {}
void Run();
@@ -112,7 +113,8 @@
class KeyboardThread: public i::Thread {
public:
explicit KeyboardThread(RemoteDebugger* remote_debugger)
- : remote_debugger_(remote_debugger) {}
+ : Thread("d8:KeyboardThrd"),
+ remote_debugger_(remote_debugger) {}
~KeyboardThread() {}
void Run();
diff --git a/src/d8.cc b/src/d8.cc
index 5a1e63a..f0da7ac 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -599,7 +599,8 @@
class ShellThread : public i::Thread {
public:
ShellThread(int no, i::Vector<const char> files)
- : no_(no), files_(files) { }
+ : Thread("d8:ShellThread"),
+ no_(no), files_(files) { }
virtual void Run();
private:
int no_;
diff --git a/src/data-flow.h b/src/data-flow.h
index 6e2230c..79d760f 100644
--- a/src/data-flow.h
+++ b/src/data-flow.h
@@ -112,10 +112,13 @@
}
void CopyFrom(const BitVector& other) {
- ASSERT(other.length() == length());
- for (int i = 0; i < data_length_; i++) {
+ ASSERT(other.length() <= length());
+ for (int i = 0; i < other.data_length_; i++) {
data_[i] = other.data_[i];
}
+ for (int i = other.data_length_; i < data_length_; i++) {
+ data_[i] = 0;
+ }
}
bool Contains(int i) const {
diff --git a/src/debug-agent.h b/src/debug-agent.h
index 3647994..4cedb83 100644
--- a/src/debug-agent.h
+++ b/src/debug-agent.h
@@ -44,7 +44,8 @@
class DebuggerAgent: public Thread {
public:
explicit DebuggerAgent(const char* name, int port)
- : name_(StrDup(name)), port_(port),
+ : Thread(name),
+ name_(StrDup(name)), port_(port),
server_(OS::CreateSocket()), terminate_(false),
session_access_(OS::CreateMutex()), session_(NULL),
terminate_now_(OS::CreateSemaphore(0)),
@@ -90,7 +91,8 @@
class DebuggerAgentSession: public Thread {
public:
DebuggerAgentSession(DebuggerAgent* agent, Socket* client)
- : agent_(agent), client_(client) {}
+ : Thread("v8:DbgAgntSessn"),
+ agent_(agent), client_(client) {}
void DebuggerMessage(Vector<uint16_t> message);
void Shutdown();
diff --git a/src/debug.cc b/src/debug.cc
index ca3c1db..c41e545 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -3037,7 +3037,8 @@
MessageDispatchHelperThread::MessageDispatchHelperThread()
- : sem_(OS::CreateSemaphore(0)), mutex_(OS::CreateMutex()),
+ : Thread("v8:MsgDispHelpr"),
+ sem_(OS::CreateSemaphore(0)), mutex_(OS::CreateMutex()),
already_signalled_(false) {
}
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index f160a85..2b24d13 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -122,7 +122,6 @@
DEFINE_bool(trace_alloc, false, "trace register allocator")
DEFINE_bool(trace_range, false, "trace range analysis")
DEFINE_bool(trace_gvn, false, "trace global value numbering")
-DEFINE_bool(trace_environment, false, "trace lithium environments")
DEFINE_bool(trace_representation, false, "trace representation types")
DEFINE_bool(stress_pointer_maps, false, "pointer map for every instruction")
DEFINE_bool(stress_environments, false, "environment for every instruction")
diff --git a/src/heap-inl.h b/src/heap-inl.h
index 7b91e87..e7700e9 100644
--- a/src/heap-inl.h
+++ b/src/heap-inl.h
@@ -521,6 +521,10 @@
CALL_AND_RETRY(FUNCTION_CALL, return, return)
+#define CALL_HEAP_FUNCTION_INLINE(FUNCTION_CALL) \
+ CALL_AND_RETRY(FUNCTION_CALL, break, break)
+
+
#ifdef DEBUG
inline bool Heap::allow_allocation(bool new_state) {
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index e9c437f..a3c23c6 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -910,6 +910,9 @@
virtual HBasicBlock* FirstSuccessor() const { return true_destination_; }
virtual HBasicBlock* SecondSuccessor() const { return false_destination_; }
+ HBasicBlock* true_destination() const { return true_destination_; }
+ HBasicBlock* false_destination() const { return false_destination_; }
+
virtual void PrintDataTo(StringStream* stream) const;
Handle<Map> map() const { return map_; }
@@ -1020,10 +1023,10 @@
class HSimulate: public HInstruction {
public:
- HSimulate(int ast_id, int pop_count, int environment_height)
+ HSimulate(int ast_id, int pop_count, int environment_length)
: ast_id_(ast_id),
pop_count_(pop_count),
- environment_height_(environment_height),
+ environment_length_(environment_length),
values_(2),
assigned_indexes_(2) {}
virtual ~HSimulate() {}
@@ -1037,7 +1040,7 @@
ast_id_ = id;
}
- int environment_height() const { return environment_height_; }
+ int environment_length() const { return environment_length_; }
int pop_count() const { return pop_count_; }
const ZoneList<HValue*>* values() const { return &values_; }
int GetAssignedIndexAt(int index) const {
@@ -1079,7 +1082,7 @@
}
int ast_id_;
int pop_count_;
- int environment_height_;
+ int environment_length_;
ZoneList<HValue*> values_;
ZoneList<int> assigned_indexes_;
};
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 03ce5b3..9612ce8 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -128,7 +128,7 @@
int push_count = environment->push_count();
int pop_count = environment->pop_count();
- int length = environment->values()->length();
+ int length = environment->length();
HSimulate* instr = new HSimulate(id, pop_count, length);
for (int i = push_count - 1; i >= 0; --i) {
instr->AddPushedValue(environment->ExpressionStackAt(i));
@@ -222,7 +222,7 @@
ASSERT(IsLoopHeader() || first_ == NULL);
HEnvironment* incoming_env = pred->last_environment();
if (IsLoopHeader()) {
- ASSERT(phis()->length() == incoming_env->values()->length());
+ ASSERT(phis()->length() == incoming_env->length());
for (int i = 0; i < phis_.length(); ++i) {
phis_[i]->AddInput(incoming_env->values()->at(i));
}
@@ -1982,7 +1982,7 @@
: owner_(owner), kind_(kind), outer_(owner->ast_context()) {
owner->set_ast_context(this); // Push.
#ifdef DEBUG
- original_count_ = owner->environment()->total_count();
+ original_length_ = owner->environment()->length();
#endif
}
@@ -1995,14 +1995,14 @@
EffectContext::~EffectContext() {
ASSERT(owner()->HasStackOverflow() ||
!owner()->subgraph()->HasExit() ||
- owner()->environment()->total_count() == original_count_);
+ owner()->environment()->length() == original_length_);
}
ValueContext::~ValueContext() {
ASSERT(owner()->HasStackOverflow() ||
!owner()->subgraph()->HasExit() ||
- owner()->environment()->total_count() == original_count_ + 1);
+ owner()->environment()->length() == original_length_ + 1);
}
@@ -2343,7 +2343,7 @@
}
// Set the initial values of stack-allocated locals.
- for (int i = count; i < environment()->values()->length(); ++i) {
+ for (int i = count; i < environment()->length(); ++i) {
environment()->Bind(i, undefined_constant);
}
@@ -2702,7 +2702,7 @@
int osr_entry_id = statement->OsrEntryId();
// We want the correct environment at the OsrEntry instruction. Build
// it explicitly. The expression stack should be empty.
- int count = osr_entry->last_environment()->total_count();
+ int count = osr_entry->last_environment()->length();
ASSERT(count == (osr_entry->last_environment()->parameter_count() +
osr_entry->last_environment()->local_count()));
for (int i = 0; i < count; ++i) {
@@ -5279,6 +5279,19 @@
}
+void HEnvironment::Initialize(const HEnvironment* other) {
+ closure_ = other->closure();
+ values_.AddAll(other->values_);
+ assigned_variables_.AddAll(other->assigned_variables_);
+ parameter_count_ = other->parameter_count_;
+ local_count_ = other->local_count_;
+ if (other->outer_ != NULL) outer_ = other->outer_->Copy(); // Deep copy.
+ pop_count_ = other->pop_count_;
+ push_count_ = other->push_count_;
+ ast_id_ = other->ast_id_;
+}
+
+
void HEnvironment::AddIncomingEdge(HBasicBlock* block, HEnvironment* other) {
ASSERT(!block->IsLoopHeader());
ASSERT(values_.length() == other->values_.length());
@@ -5309,26 +5322,45 @@
}
-void HEnvironment::Initialize(const HEnvironment* other) {
- closure_ = other->closure();
- values_.AddAll(other->values_);
- assigned_variables_.AddAll(other->assigned_variables_);
- parameter_count_ = other->parameter_count_;
- local_count_ = other->local_count_;
- if (other->outer_ != NULL) outer_ = other->outer_->Copy(); // Deep copy.
- pop_count_ = other->pop_count_;
- push_count_ = other->push_count_;
- ast_id_ = other->ast_id_;
+void HEnvironment::Bind(int index, HValue* value) {
+ ASSERT(value != NULL);
+ if (!assigned_variables_.Contains(index)) {
+ assigned_variables_.Add(index);
+ }
+ values_[index] = value;
}
-int HEnvironment::IndexFor(Variable* variable) const {
- Slot* slot = variable->AsSlot();
- ASSERT(slot != NULL && slot->IsStackAllocated());
- if (slot->type() == Slot::PARAMETER) {
- return slot->index() + 1;
- } else {
- return parameter_count_ + slot->index();
+bool HEnvironment::HasExpressionAt(int index) const {
+ return index >= parameter_count_ + local_count_;
+}
+
+
+bool HEnvironment::ExpressionStackIsEmpty() const {
+ int first_expression = parameter_count() + local_count();
+ ASSERT(length() >= first_expression);
+ return length() == first_expression;
+}
+
+
+void HEnvironment::SetExpressionStackAt(int index_from_top, HValue* value) {
+ int count = index_from_top + 1;
+ int index = values_.length() - count;
+ ASSERT(HasExpressionAt(index));
+ // The push count must include at least the element in question or else
+ // the new value will not be included in this environment's history.
+ if (push_count_ < count) {
+ // This is the same effect as popping then re-pushing 'count' elements.
+ pop_count_ += (count - push_count_);
+ push_count_ = count;
+ }
+ values_[index] = value;
+}
+
+
+void HEnvironment::Drop(int count) {
+ for (int i = 0; i < count; ++i) {
+ Pop();
}
}
@@ -5393,7 +5425,7 @@
void HEnvironment::PrintTo(StringStream* stream) {
- for (int i = 0; i < total_count(); i++) {
+ for (int i = 0; i < length(); i++) {
if (i == 0) stream->Add("parameters\n");
if (i == parameter_count()) stream->Add("locals\n");
if (i == parameter_count() + local_count()) stream->Add("expressions");
diff --git a/src/hydrogen.h b/src/hydrogen.h
index ebabf3d..872ae98 100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -401,27 +401,33 @@
Scope* scope,
Handle<JSFunction> closure);
+ // Simple accessors.
+ Handle<JSFunction> closure() const { return closure_; }
+ const ZoneList<HValue*>* values() const { return &values_; }
+ const ZoneList<int>* assigned_variables() const {
+ return &assigned_variables_;
+ }
+ int parameter_count() const { return parameter_count_; }
+ int local_count() const { return local_count_; }
+ HEnvironment* outer() const { return outer_; }
+ int pop_count() const { return pop_count_; }
+ int push_count() const { return push_count_; }
+
+ int ast_id() const { return ast_id_; }
+ void set_ast_id(int id) { ast_id_ = id; }
+
+ int length() const { return values_.length(); }
+
void Bind(Variable* variable, HValue* value) {
Bind(IndexFor(variable), value);
-
- if (FLAG_trace_environment) {
- PrintF("Slot index=%d name=%s\n",
- variable->AsSlot()->index(),
- *variable->name()->ToCString());
- }
}
- void Bind(int index, HValue* value) {
- ASSERT(value != NULL);
- if (!assigned_variables_.Contains(index)) {
- assigned_variables_.Add(index);
- }
- values_[index] = value;
- }
+ void Bind(int index, HValue* value);
HValue* Lookup(Variable* variable) const {
return Lookup(IndexFor(variable));
}
+
HValue* Lookup(int index) const {
HValue* result = values_[index];
ASSERT(result != NULL);
@@ -434,53 +440,28 @@
values_.Add(value);
}
- HValue* Top() const { return ExpressionStackAt(0); }
-
- HValue* ExpressionStackAt(int index_from_top) const {
- int index = values_.length() - index_from_top - 1;
- ASSERT(IsExpressionStackIndex(index));
- return values_[index];
- }
-
- void SetExpressionStackAt(int index_from_top, HValue* value) {
- int index = values_.length() - index_from_top - 1;
- ASSERT(IsExpressionStackIndex(index));
- values_[index] = value;
- }
-
HValue* Pop() {
- ASSERT(!IsExpressionStackEmpty());
+ ASSERT(!ExpressionStackIsEmpty());
if (push_count_ > 0) {
--push_count_;
- ASSERT(push_count_ >= 0);
} else {
++pop_count_;
}
return values_.RemoveLast();
}
- void Drop(int count) {
- for (int i = 0; i < count; ++i) {
- Pop();
- }
+ void Drop(int count);
+
+ HValue* Top() const { return ExpressionStackAt(0); }
+
+ HValue* ExpressionStackAt(int index_from_top) const {
+ int index = length() - index_from_top - 1;
+ ASSERT(HasExpressionAt(index));
+ return values_[index];
}
- Handle<JSFunction> closure() const { return closure_; }
+ void SetExpressionStackAt(int index_from_top, HValue* value);
- // ID of the original AST node to identify deoptimization points.
- int ast_id() const { return ast_id_; }
- void set_ast_id(int id) { ast_id_ = id; }
-
- const ZoneList<HValue*>* values() const { return &values_; }
- const ZoneList<int>* assigned_variables() const {
- return &assigned_variables_;
- }
- int parameter_count() const { return parameter_count_; }
- int local_count() const { return local_count_; }
- int push_count() const { return push_count_; }
- int pop_count() const { return pop_count_; }
- int total_count() const { return values_.length(); }
- HEnvironment* outer() const { return outer_; }
HEnvironment* Copy() const;
HEnvironment* CopyWithoutHistory() const;
HEnvironment* CopyAsLoopHeader(HBasicBlock* block) const;
@@ -496,13 +477,15 @@
HConstant* undefined) const;
void AddIncomingEdge(HBasicBlock* block, HEnvironment* other);
+
void ClearHistory() {
pop_count_ = 0;
push_count_ = 0;
assigned_variables_.Clear();
}
+
void SetValueAt(int index, HValue* value) {
- ASSERT(index < total_count());
+ ASSERT(index < length());
values_[index] = value;
}
@@ -512,19 +495,23 @@
private:
explicit HEnvironment(const HEnvironment* other);
- bool IsExpressionStackIndex(int index) const {
- return index >= parameter_count_ + local_count_;
- }
- bool IsExpressionStackEmpty() const {
- int length = values_.length();
- int first_expression = parameter_count() + local_count();
- ASSERT(length >= first_expression);
- return length == first_expression;
- }
+ // True if index is included in the expression stack part of the environment.
+ bool HasExpressionAt(int index) const;
+
+ bool ExpressionStackIsEmpty() const;
+
void Initialize(int parameter_count, int local_count, int stack_height);
void Initialize(const HEnvironment* other);
- int VariableToIndex(Variable* var);
- int IndexFor(Variable* variable) const;
+
+ // Map a variable to an environment index. Parameter indices are shifted
+ // by 1 (receiver is parameter index -1 but environment index 0).
+ // Stack-allocated local indices are shifted by the number of parameters.
+ int IndexFor(Variable* variable) const {
+ Slot* slot = variable->AsSlot();
+ ASSERT(slot != NULL && slot->IsStackAllocated());
+ int shift = (slot->type() == Slot::PARAMETER) ? 1 : parameter_count_;
+ return slot->index() + shift;
+ }
Handle<JSFunction> closure_;
// Value array [parameters] [locals] [temporaries].
@@ -567,7 +554,7 @@
// We want to be able to assert, in a context-specific way, that the stack
// height makes sense when the context is filled.
#ifdef DEBUG
- int original_count_;
+ int original_length_;
#endif
private:
diff --git a/src/ia32/builtins-ia32.cc b/src/ia32/builtins-ia32.cc
index 918f346..0a3e093 100644
--- a/src/ia32/builtins-ia32.cc
+++ b/src/ia32/builtins-ia32.cc
@@ -399,7 +399,7 @@
static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
bool is_construct) {
// Clear the context before we push it when entering the JS frame.
- __ xor_(esi, Operand(esi)); // clear esi
+ __ Set(esi, Immediate(0));
// Enter an internal frame.
__ EnterInternalFrame();
@@ -421,7 +421,7 @@
// Copy arguments to the stack in a loop.
Label loop, entry;
- __ xor_(ecx, Operand(ecx)); // clear ecx
+ __ Set(ecx, Immediate(0));
__ jmp(&entry);
__ bind(&loop);
__ mov(edx, Operand(ebx, ecx, times_4, 0)); // push parameter from argv
@@ -644,7 +644,7 @@
__ bind(&non_function);
__ mov(Operand(esp, eax, times_4, 0), edi);
// Clear edi to indicate a non-function being called.
- __ xor_(edi, Operand(edi));
+ __ Set(edi, Immediate(0));
// 4. Shift arguments and return address one slot down on the stack
// (overwriting the original receiver). Adjust argument count to make
@@ -665,7 +665,7 @@
{ Label function;
__ test(edi, Operand(edi));
__ j(not_zero, &function, taken);
- __ xor_(ebx, Operand(ebx));
+ __ Set(ebx, Immediate(0));
__ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
__ jmp(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
RelocInfo::CODE_TARGET);
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index a371c96..bd95c8d 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -104,7 +104,7 @@
Immediate(Smi::FromInt(length)));
// Setup the fixed slots.
- __ xor_(ebx, Operand(ebx)); // Set to NULL.
+ __ Set(ebx, Immediate(0)); // Set to NULL.
__ mov(Operand(eax, Context::SlotOffset(Context::CLOSURE_INDEX)), ecx);
__ mov(Operand(eax, Context::SlotOffset(Context::FCONTEXT_INDEX)), eax);
__ mov(Operand(eax, Context::SlotOffset(Context::PREVIOUS_INDEX)), ebx);
@@ -4303,7 +4303,7 @@
// that contains the exponent and high bit of the mantissa.
STATIC_ASSERT(((kQuietNaNHighBitsMask << 1) & 0x80000000u) != 0);
__ mov(edx, FieldOperand(edx, HeapNumber::kExponentOffset));
- __ xor_(eax, Operand(eax));
+ __ Set(eax, Immediate(0));
// Shift value and mask so kQuietNaNHighBitsMask applies to topmost
// bits.
__ add(edx, Operand(edx));
@@ -4433,7 +4433,7 @@
__ j(below, &below_label, not_taken);
__ j(above, &above_label, not_taken);
- __ xor_(eax, Operand(eax));
+ __ Set(eax, Immediate(0));
__ ret(0);
__ bind(&below_label);
@@ -4646,7 +4646,7 @@
// Before returning we restore the context from the frame pointer if
// not NULL. The frame pointer is NULL in the exception handler of
// a JS entry frame.
- __ xor_(esi, Operand(esi)); // Tentatively set context pointer to NULL.
+ __ Set(esi, Immediate(0)); // Tentatively set context pointer to NULL.
NearLabel skip;
__ cmp(ebp, 0);
__ j(equal, &skip, not_taken);
@@ -4799,7 +4799,7 @@
}
// Clear the context pointer.
- __ xor_(esi, Operand(esi));
+ __ Set(esi, Immediate(0));
// Restore fp from handler and discard handler state.
STATIC_ASSERT(StackHandlerConstants::kFPOffset == 1 * kPointerSize);
diff --git a/src/ia32/debug-ia32.cc b/src/ia32/debug-ia32.cc
index ee94565..678cc93 100644
--- a/src/ia32/debug-ia32.cc
+++ b/src/ia32/debug-ia32.cc
@@ -125,7 +125,7 @@
#ifdef DEBUG
__ RecordComment("// Calling from debug break to runtime - come in - over");
#endif
- __ Set(eax, Immediate(0)); // no arguments
+ __ Set(eax, Immediate(0)); // No arguments.
__ mov(ebx, Immediate(ExternalReference::debug_break()));
CEntryStub ceb(1);
diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc
index 9c9304d..90bfd4b 100644
--- a/src/ia32/ic-ia32.cc
+++ b/src/ia32/ic-ia32.cc
@@ -1199,7 +1199,7 @@
break;
case kExternalShortArray:
case kExternalUnsignedShortArray:
- __ xor_(ecx, Operand(ecx));
+ __ Set(ecx, Immediate(0));
__ mov_w(Operand(edi, ebx, times_2, 0), ecx);
break;
case kExternalIntArray:
@@ -1219,9 +1219,6 @@
}
-// Defined in ic.cc.
-Object* CallIC_Miss(Arguments args);
-
// The generated code does not accept smi keys.
// The generated code falls through if both probes miss.
static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
@@ -1567,9 +1564,6 @@
}
-// Defined in ic.cc.
-Object* LoadIC_Miss(Arguments args);
-
void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : receiver
@@ -1795,10 +1789,6 @@
}
-// Defined in ic.cc.
-Object* KeyedLoadIC_Miss(Arguments args);
-
-
void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : key
@@ -1982,9 +1972,6 @@
}
-// Defined in ic.cc.
-Object* KeyedStoreIC_Miss(Arguments args);
-
void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : value
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 9569ac8..0f56825 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -3039,7 +3039,7 @@
__ push(Immediate(instr->hydrogen()->constant_properties()));
__ push(Immediate(Smi::FromInt(instr->hydrogen()->fast_elements() ? 1 : 0)));
- // Pick the right runtime function or stub to call.
+ // Pick the right runtime function to call.
if (instr->hydrogen()->depth() > 1) {
CallRuntime(Runtime::kCreateObjectLiteral, 4, instr);
} else {
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index 8c003a5..4fde3d4 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -767,11 +767,6 @@
}
-LInstruction* LChunkBuilder::DefineSameAsAny(LInstruction* instr) {
- return Define(instr, new LUnallocated(LUnallocated::SAME_AS_ANY_INPUT));
-}
-
-
LInstruction* LChunkBuilder::DefineSameAsFirst(LInstruction* instr) {
return Define(instr, new LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
}
@@ -1016,9 +1011,6 @@
HInstruction* current = block->first();
int start = chunk_->instructions()->length();
while (current != NULL && !is_aborted()) {
- if (FLAG_trace_environment) {
- PrintF("Process instruction %d\n", current->id());
- }
// Code for constants in registers is generated lazily.
if (!current->EmitAtUses()) {
VisitInstruction(current);
@@ -1125,7 +1117,7 @@
LEnvironment* outer = CreateEnvironment(hydrogen_env->outer());
int ast_id = hydrogen_env->ast_id();
ASSERT(ast_id != AstNode::kNoNumber);
- int value_count = hydrogen_env->values()->length();
+ int value_count = hydrogen_env->length();
LEnvironment* result = new LEnvironment(hydrogen_env->closure(),
ast_id,
hydrogen_env->parameter_count(),
@@ -2039,7 +2031,7 @@
LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
- LInstruction* result = new LTypeof(Use(instr->value()));
+ LInstruction* result = new LTypeof(UseAtStart(instr->value()));
return MarkAsCall(DefineFixed(result, eax), instr);
}
@@ -2063,14 +2055,7 @@
env->Push(value);
}
}
-
- if (FLAG_trace_environment) {
- PrintF("Reconstructed environment ast_id=%d, instr_id=%d\n",
- instr->ast_id(),
- instr->id());
- env->PrintToStd();
- }
- ASSERT(env->values()->length() == instr->environment_height());
+ ASSERT(env->length() == instr->environment_length());
// If there is an instruction pending deoptimization environment create a
// lazy bailout instruction to capture the environment.
diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h
index 94bf8fd..00dc394 100644
--- a/src/ia32/lithium-ia32.h
+++ b/src/ia32/lithium-ia32.h
@@ -2087,7 +2087,6 @@
LInstruction* Define(LInstruction* instr);
LInstruction* DefineAsRegister(LInstruction* instr);
LInstruction* DefineAsSpilled(LInstruction* instr, int index);
- LInstruction* DefineSameAsAny(LInstruction* instr);
LInstruction* DefineSameAsFirst(LInstruction* instr);
LInstruction* DefineFixed(LInstruction* instr, Register reg);
LInstruction* DefineFixedDouble(LInstruction* instr, XMMRegister reg);
diff --git a/src/ia32/regexp-macro-assembler-ia32.cc b/src/ia32/regexp-macro-assembler-ia32.cc
index cc2f30d..1213448 100644
--- a/src/ia32/regexp-macro-assembler-ia32.cc
+++ b/src/ia32/regexp-macro-assembler-ia32.cc
@@ -652,7 +652,7 @@
void RegExpMacroAssemblerIA32::Fail() {
ASSERT(FAILURE == 0); // Return value for failure is zero.
- __ xor_(eax, Operand(eax)); // zero eax.
+ __ Set(eax, Immediate(0));
__ jmp(&exit_label_);
}
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
index 99888b0..bcb02ed 100644
--- a/src/ia32/stub-cache-ia32.cc
+++ b/src/ia32/stub-cache-ia32.cc
@@ -1686,6 +1686,7 @@
Label miss;
Label index_out_of_range;
+
GenerateNameCheck(name, &miss);
// Check that the maps starting from the prototype haven't changed.
diff --git a/src/lithium-allocator.cc b/src/lithium-allocator.cc
index ac61c17..eecc441 100644
--- a/src/lithium-allocator.cc
+++ b/src/lithium-allocator.cc
@@ -27,7 +27,6 @@
#include "lithium-allocator.h"
-#include "data-flow.h"
#include "hydrogen.h"
#include "string-stream.h"
@@ -107,9 +106,6 @@
case LUnallocated::SAME_AS_FIRST_INPUT:
stream->Add("(1)");
break;
- case LUnallocated::SAME_AS_ANY_INPUT:
- stream->Add("(A)");
- break;
case LUnallocated::ANY:
stream->Add("(-)");
break;
@@ -834,6 +830,13 @@
} else if (cur_input->policy() == LUnallocated::WRITABLE_REGISTER) {
LUnallocated* input_copy = cur_input->CopyUnconstrained();
cur_input->set_virtual_register(next_virtual_register_++);
+
+ if (RequiredRegisterKind(input_copy->virtual_register()) ==
+ DOUBLE_REGISTERS) {
+ double_artificial_registers_.Add(
+ cur_input->virtual_register() - first_artificial_register_);
+ }
+
second->AddTemp(cur_input);
AddConstraintsGapMove(gap_index, input_copy, cur_input);
}
@@ -1036,6 +1039,7 @@
void LAllocator::MeetRegisterConstraints() {
HPhase phase("Register constraints", chunk());
+ first_artificial_register_ = next_virtual_register_;
const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
for (int i = 0; i < blocks->length(); ++i) {
HBasicBlock* block = blocks->at(i);
@@ -1564,16 +1568,42 @@
RegisterKind LAllocator::RequiredRegisterKind(int virtual_register) const {
- HValue* value = graph()->LookupValue(virtual_register);
- if (value != NULL && value->representation().IsDouble()) {
+ if (virtual_register < first_artificial_register_) {
+ HValue* value = graph()->LookupValue(virtual_register);
+ if (value != NULL && value->representation().IsDouble()) {
+ return DOUBLE_REGISTERS;
+ }
+ } else if (double_artificial_registers_.Contains(
+ virtual_register - first_artificial_register_)) {
return DOUBLE_REGISTERS;
}
+
return GENERAL_REGISTERS;
}
void LAllocator::MarkAsCall() {
- current_summary()->MarkAsCall();
+ // Call instructions can use only fixed registers as
+ // temporaries and outputs because all registers
+ // are blocked by the calling convention.
+ // Inputs can use either fixed register or have a short lifetime (be
+ // used at start of the instruction).
+ InstructionSummary* summary = current_summary();
+#ifdef DEBUG
+ ASSERT(summary->Output() == NULL ||
+ LUnallocated::cast(summary->Output())->HasFixedPolicy() ||
+ !LUnallocated::cast(summary->Output())->HasRegisterPolicy());
+ for (int i = 0; i < summary->InputCount(); i++) {
+ ASSERT(LUnallocated::cast(summary->InputAt(i))->HasFixedPolicy() ||
+ LUnallocated::cast(summary->InputAt(i))->IsUsedAtStart() ||
+ !LUnallocated::cast(summary->InputAt(i))->HasRegisterPolicy());
+ }
+ for (int i = 0; i < summary->TempCount(); i++) {
+ ASSERT(LUnallocated::cast(summary->TempAt(i))->HasFixedPolicy() ||
+ !LUnallocated::cast(summary->TempAt(i))->HasRegisterPolicy());
+ }
+#endif
+ summary->MarkAsCall();
}
diff --git a/src/lithium-allocator.h b/src/lithium-allocator.h
index 3ec984e..fe837e2 100644
--- a/src/lithium-allocator.h
+++ b/src/lithium-allocator.h
@@ -30,6 +30,7 @@
#include "v8.h"
+#include "data-flow.h"
#include "zone.h"
namespace v8 {
@@ -204,7 +205,6 @@
MUST_HAVE_REGISTER,
WRITABLE_REGISTER,
SAME_AS_FIRST_INPUT,
- SAME_AS_ANY_INPUT,
IGNORE
};
@@ -275,7 +275,7 @@
return policy() == WRITABLE_REGISTER || policy() == MUST_HAVE_REGISTER;
}
bool HasSameAsInputPolicy() const {
- return policy() == SAME_AS_FIRST_INPUT || policy() == SAME_AS_ANY_INPUT;
+ return policy() == SAME_AS_FIRST_INPUT;
}
Policy policy() const { return PolicyField::decode(value_); }
void set_policy(Policy policy) {
@@ -754,6 +754,40 @@
};
+class GrowableBitVector BASE_EMBEDDED {
+ public:
+ GrowableBitVector() : bits_(NULL) { }
+
+ bool Contains(int value) const {
+ if (!InBitsRange(value)) return false;
+ return bits_->Contains(value);
+ }
+
+ void Add(int value) {
+ EnsureCapacity(value);
+ bits_->Add(value);
+ }
+
+ private:
+ static const int kInitialLength = 1024;
+
+ bool InBitsRange(int value) const {
+ return bits_ != NULL && bits_->length() > value;
+ }
+
+ void EnsureCapacity(int value) {
+ if (InBitsRange(value)) return;
+ int new_length = bits_ == NULL ? kInitialLength : bits_->length();
+ while (new_length <= value) new_length *= 2;
+ BitVector* new_bits = new BitVector(new_length);
+ if (bits_ != NULL) new_bits->CopyFrom(*bits_);
+ bits_ = new_bits;
+ }
+
+ BitVector* bits_;
+};
+
+
class LAllocator BASE_EMBEDDED {
public:
explicit LAllocator(int first_virtual_register, HGraph* graph)
@@ -770,6 +804,7 @@
inactive_live_ranges_(8),
reusable_slots_(8),
next_virtual_register_(first_virtual_register),
+ first_artificial_register_(first_virtual_register),
mode_(NONE),
num_registers_(-1),
graph_(graph),
@@ -972,6 +1007,8 @@
// Next virtual register number to be assigned to temporaries.
int next_virtual_register_;
+ int first_artificial_register_;
+ GrowableBitVector double_artificial_registers_;
RegisterKind mode_;
int num_registers_;
diff --git a/src/log.cc b/src/log.cc
index db9ff7a..6eb3c9b 100644
--- a/src/log.cc
+++ b/src/log.cc
@@ -276,7 +276,8 @@
// Profiler implementation.
//
Profiler::Profiler()
- : head_(0),
+ : Thread("v8:Profiler"),
+ head_(0),
tail_(0),
overflow_(false),
buffer_semaphore_(OS::CreateSemaphore(0)),
diff --git a/src/objects.cc b/src/objects.cc
index 8c8b6e0..927194f 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -2932,7 +2932,6 @@
uint32_t index = 0;
bool is_element = name->AsArrayIndex(&index);
- if (is_element && IsJSArray()) return Heap::undefined_value();
if (is_element) {
switch (GetElementsKind()) {
@@ -6795,7 +6794,8 @@
MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index,
- Object* value) {
+ Object* value,
+ bool check_prototype) {
// Make sure that the top context does not change when doing
// callbacks or interceptor calls.
AssertNoContextChange ncc;
@@ -6819,7 +6819,9 @@
if (!result.IsEmpty()) return *value_handle;
}
MaybeObject* raw_result =
- this_handle->SetElementWithoutInterceptor(index, *value_handle);
+ this_handle->SetElementWithoutInterceptor(index,
+ *value_handle,
+ check_prototype);
RETURN_IF_SCHEDULED_EXCEPTION();
return raw_result;
}
@@ -6930,7 +6932,9 @@
// Adding n elements in fast case is O(n*n).
// Note: revisit design to have dual undefined values to capture absent
// elements.
-MaybeObject* JSObject::SetFastElement(uint32_t index, Object* value) {
+MaybeObject* JSObject::SetFastElement(uint32_t index,
+ Object* value,
+ bool check_prototype) {
ASSERT(HasFastElements());
Object* elms_obj;
@@ -6940,12 +6944,13 @@
FixedArray* elms = FixedArray::cast(elms_obj);
uint32_t elms_length = static_cast<uint32_t>(elms->length());
- if (!IsJSArray() && (index >= elms_length || elms->get(index)->IsTheHole())) {
- if (SetElementWithCallbackSetterInPrototypes(index, value)) {
- return value;
- }
+ if (check_prototype &&
+ (index >= elms_length || elms->get(index)->IsTheHole()) &&
+ SetElementWithCallbackSetterInPrototypes(index, value)) {
+ return value;
}
+
// Check whether there is extra space in fixed array..
if (index < elms_length) {
elms->set(index, value);
@@ -6983,11 +6988,13 @@
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
ASSERT(HasDictionaryElements());
- return SetElement(index, value);
+ return SetElement(index, value, check_prototype);
}
-MaybeObject* JSObject::SetElement(uint32_t index, Object* value) {
+MaybeObject* JSObject::SetElement(uint32_t index,
+ Object* value,
+ bool check_prototype) {
// Check access rights if needed.
if (IsAccessCheckNeeded() &&
!Top::MayIndexedAccess(this, index, v8::ACCESS_SET)) {
@@ -7001,24 +7008,25 @@
Object* proto = GetPrototype();
if (proto->IsNull()) return value;
ASSERT(proto->IsJSGlobalObject());
- return JSObject::cast(proto)->SetElement(index, value);
+ return JSObject::cast(proto)->SetElement(index, value, check_prototype);
}
// Check for lookup interceptor
if (HasIndexedInterceptor()) {
- return SetElementWithInterceptor(index, value);
+ return SetElementWithInterceptor(index, value, check_prototype);
}
- return SetElementWithoutInterceptor(index, value);
+ return SetElementWithoutInterceptor(index, value, check_prototype);
}
MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
- Object* value) {
+ Object* value,
+ bool check_prototype) {
switch (GetElementsKind()) {
case FAST_ELEMENTS:
// Fast case.
- return SetFastElement(index, value);
+ return SetFastElement(index, value, check_prototype);
case PIXEL_ELEMENTS: {
PixelArray* pixels = PixelArray::cast(elements());
return pixels->SetValue(index, value);
@@ -7071,10 +7079,9 @@
}
} else {
// Index not already used. Look for an accessor in the prototype chain.
- if (!IsJSArray()) {
- if (SetElementWithCallbackSetterInPrototypes(index, value)) {
- return value;
- }
+ if (check_prototype &&
+ SetElementWithCallbackSetterInPrototypes(index, value)) {
+ return value;
}
// When we set the is_extensible flag to false we always force
// the element into dictionary mode (and force them to stay there).
diff --git a/src/objects.h b/src/objects.h
index 163b713..eac7f92 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -1505,11 +1505,15 @@
bool HasElementWithInterceptor(JSObject* receiver, uint32_t index);
bool HasElementPostInterceptor(JSObject* receiver, uint32_t index);
- MUST_USE_RESULT MaybeObject* SetFastElement(uint32_t index, Object* value);
+ MUST_USE_RESULT MaybeObject* SetFastElement(uint32_t index,
+ Object* value,
+ bool check_prototype = true);
// Set the index'th array element.
// A Failure object is returned if GC is needed.
- MUST_USE_RESULT MaybeObject* SetElement(uint32_t index, Object* value);
+ MUST_USE_RESULT MaybeObject* SetElement(uint32_t index,
+ Object* value,
+ bool check_prototype = true);
// Returns the index'th element.
// The undefined object if index is out of bounds.
@@ -1763,9 +1767,12 @@
Object* value,
JSObject* holder);
MUST_USE_RESULT MaybeObject* SetElementWithInterceptor(uint32_t index,
- Object* value);
- MUST_USE_RESULT MaybeObject* SetElementWithoutInterceptor(uint32_t index,
- Object* value);
+ Object* value,
+ bool check_prototype);
+ MUST_USE_RESULT MaybeObject* SetElementWithoutInterceptor(
+ uint32_t index,
+ Object* value,
+ bool check_prototype);
MaybeObject* GetElementPostInterceptor(JSObject* receiver, uint32_t index);
diff --git a/src/parser.cc b/src/parser.cc
index 03819ee..5526933 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -2995,14 +2995,22 @@
// { ... , get foo() { ... }, ... , set foo(v) { ... v ... } , ... }
// We have already read the "get" or "set" keyword.
Token::Value next = Next();
- // TODO(820): Allow NUMBER and STRING as well (and handle array indices).
- if (next == Token::IDENTIFIER || Token::IsKeyword(next)) {
- Handle<String> name = GetSymbol(CHECK_OK);
+ bool is_keyword = Token::IsKeyword(next);
+ if (next == Token::IDENTIFIER || next == Token::NUMBER ||
+ next == Token::STRING || is_keyword) {
+ Handle<String> name;
+ if (is_keyword) {
+ name = Factory::LookupAsciiSymbol(Token::String(next));
+ } else {
+ name = GetSymbol(CHECK_OK);
+ }
FunctionLiteral* value =
ParseFunctionLiteral(name,
RelocInfo::kNoPosition,
DECLARATION,
CHECK_OK);
+ // Allow any number of parameters for compatiabilty with JSC.
+ // Specification only allows zero parameters for get and one for set.
ObjectLiteral::Property* property =
new ObjectLiteral::Property(is_getter, value);
return property;
@@ -3672,9 +3680,11 @@
if (value.is_null()) return Handle<Object>::null();
uint32_t index;
if (key->AsArrayIndex(&index)) {
- SetElement(json_object, index, value);
+ CALL_HEAP_FUNCTION_INLINE(
+ (*json_object)->SetElement(index, *value, true));
} else {
- SetProperty(json_object, key, value, NONE);
+ CALL_HEAP_FUNCTION_INLINE(
+ (*json_object)->SetPropertyPostInterceptor(*key, *value, NONE));
}
} while (scanner_.Next() == Token::COMMA);
if (scanner_.current_token() != Token::RBRACE) {
diff --git a/src/platform-freebsd.cc b/src/platform-freebsd.cc
index b58d066..ad1e499 100644
--- a/src/platform-freebsd.cc
+++ b/src/platform-freebsd.cc
@@ -411,6 +411,12 @@
Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
+ set_name("v8:<unknown>");
+}
+
+
+Thread::Thread(const char* name) : ThreadHandle(ThreadHandle::INVALID) {
+ set_names(name);
}
@@ -430,6 +436,12 @@
}
+void Thread::set_name(const char* name) {
+ strncpy(name_, name, sizeof(name_));
+ name_[sizeof(name_) - 1] = '\0';
+}
+
+
void Thread::Start() {
pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this);
ASSERT(IsValid());
diff --git a/src/platform-linux.cc b/src/platform-linux.cc
index 7efb25d..755e8cd 100644
--- a/src/platform-linux.cc
+++ b/src/platform-linux.cc
@@ -31,6 +31,7 @@
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
+#include <sys/prctl.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/syscall.h>
@@ -551,6 +552,12 @@
Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
+ set_name("v8:<unknown>");
+}
+
+
+Thread::Thread(const char* name) : ThreadHandle(ThreadHandle::INVALID) {
+ set_name(name);
}
@@ -563,6 +570,7 @@
// This is also initialized by the first argument to pthread_create() but we
// don't know which thread will run first (the original thread or the new
// one) so we initialize it here too.
+ prctl(PR_SET_NAME, thread->name(), 0, 0, 0);
thread->thread_handle_data()->thread_ = pthread_self();
ASSERT(thread->IsValid());
thread->Run();
@@ -570,6 +578,12 @@
}
+void Thread::set_name(const char* name) {
+ strncpy(name_, name, sizeof(name_));
+ name_[sizeof(name_) - 1] = '\0';
+}
+
+
void Thread::Start() {
pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this);
ASSERT(IsValid());
diff --git a/src/platform-macos.cc b/src/platform-macos.cc
index 85c7088..ce53305 100644
--- a/src/platform-macos.cc
+++ b/src/platform-macos.cc
@@ -28,6 +28,7 @@
// Platform specific code for MacOS goes here. For the POSIX comaptible parts
// the implementation is in platform-posix.cc.
+#include <dlfcn.h>
#include <unistd.h>
#include <sys/mman.h>
#include <mach/mach_init.h>
@@ -49,7 +50,6 @@
#include <sys/types.h>
#include <stdarg.h>
#include <stdlib.h>
-
#include <errno.h>
#undef MAP_TYPE
@@ -411,6 +411,12 @@
Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
+ set_name("v8:<unknown>");
+}
+
+
+Thread::Thread(const char* name) : ThreadHandle(ThreadHandle::INVALID) {
+ set_name(name);
}
@@ -418,18 +424,43 @@
}
+
+static void SetThreadName(const char* name) {
+ // pthread_setname_np is only available in 10.6 or later, so test
+ // for it at runtime.
+ int (*dynamic_pthread_setname_np)(const char*);
+ *reinterpret_cast<void**>(&dynamic_pthread_setname_np) =
+ dlsym(RTLD_DEFAULT, "pthread_setname_np");
+ if (!dynamic_pthread_setname_np)
+ return;
+
+ // Mac OS X does not expose the length limit of the name, so hardcode it.
+ static const int kMaxNameLength = 63;
+ USE(kMaxNameLength);
+ ASSERT(Thread::kMaxThreadNameLength <= kMaxNameLength);
+ dynamic_pthread_setname_np(name);
+}
+
+
static void* ThreadEntry(void* arg) {
Thread* thread = reinterpret_cast<Thread*>(arg);
// This is also initialized by the first argument to pthread_create() but we
// don't know which thread will run first (the original thread or the new
// one) so we initialize it here too.
thread->thread_handle_data()->thread_ = pthread_self();
+ SetThreadName(thread->name());
ASSERT(thread->IsValid());
thread->Run();
return NULL;
}
+void Thread::set_name(const char* name) {
+ strncpy(name_, name, sizeof(name_));
+ name_[sizeof(name_) - 1] = '\0';
+}
+
+
void Thread::Start() {
pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this);
}
diff --git a/src/platform-nullos.cc b/src/platform-nullos.cc
index 72ea0e5..f1b7695 100644
--- a/src/platform-nullos.cc
+++ b/src/platform-nullos.cc
@@ -335,6 +335,13 @@
Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
+ set_name("v8:<unknown>");
+ UNIMPLEMENTED();
+}
+
+
+Thread::Thread(const char* name) : ThreadHandle(ThreadHandle::INVALID) {
+ set_name(name);
UNIMPLEMENTED();
}
@@ -344,6 +351,12 @@
}
+void Thread::set_name(const char* name) {
+ strncpy(name_, name, sizeof(name_));
+ name_[sizeof(name_) - 1] = '\0';
+}
+
+
void Thread::Start() {
UNIMPLEMENTED();
}
diff --git a/src/platform-openbsd.cc b/src/platform-openbsd.cc
index b698d16..5de6081 100644
--- a/src/platform-openbsd.cc
+++ b/src/platform-openbsd.cc
@@ -387,6 +387,12 @@
Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
+ set_name("v8:<unknown>");
+}
+
+
+Thread::Thread(const char* name) : ThreadHandle(ThreadHandle::INVALID) {
+ set_name(name);
}
@@ -406,6 +412,12 @@
}
+void Thread::set_name(const char* name) {
+ strncpy(name_, name, sizeof(name_));
+ name_[sizeof(name_) - 1] = '\0';
+}
+
+
void Thread::Start() {
pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this);
ASSERT(IsValid());
diff --git a/src/platform-solaris.cc b/src/platform-solaris.cc
index f84e80d..04c25a9 100644
--- a/src/platform-solaris.cc
+++ b/src/platform-solaris.cc
@@ -401,6 +401,12 @@
Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
+ set_name("v8:<unknown>");
+}
+
+
+Thread::Thread(const char* name) : ThreadHandle(ThreadHandle::INVALID) {
+ set_name(name);
}
@@ -420,6 +426,12 @@
}
+void Thread::set_name(const char* name) {
+ strncpy(name_, name, sizeof(name_));
+ name_[sizeof(name_) - 1] = '\0';
+}
+
+
void Thread::Start() {
pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this);
ASSERT(IsValid());
diff --git a/src/platform-win32.cc b/src/platform-win32.cc
index 4438045..81216e1 100644
--- a/src/platform-win32.cc
+++ b/src/platform-win32.cc
@@ -1463,6 +1463,19 @@
Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
data_ = new PlatformData(kNoThread);
+ set_name("v8:<unknown>");
+}
+
+
+Thread::Thread(const char* name) : ThreadHandle(ThreadHandle::INVALID) {
+ data_ = new PlatformData(kNoThread);
+ set_name(name);
+}
+
+
+void Thread::set_name(const char* name) {
+ strncpy_s(name_, name, sizeof(name_));
+ name_[sizeof(name_) - 1] = '\0';
}
diff --git a/src/platform.h b/src/platform.h
index 5a3e4a3..7b17067 100644
--- a/src/platform.h
+++ b/src/platform.h
@@ -387,6 +387,7 @@
// Create new thread.
Thread();
+ explicit Thread(const char* name);
virtual ~Thread();
// Start new thread by calling the Run() method in the new thread.
@@ -395,6 +396,10 @@
// Wait until thread terminates.
void Join();
+ inline const char* name() const {
+ return name_;
+ }
+
// Abstract method for run handler.
virtual void Run() = 0;
@@ -416,9 +421,17 @@
// A hint to the scheduler to let another thread run.
static void YieldCPU();
+ // The thread name length is limited to 16 based on Linux's implementation of
+ // prctl().
+ static const int kMaxThreadNameLength = 16;
private:
+ void set_name(const char *name);
+
class PlatformData;
PlatformData* data_;
+
+ char name_[kMaxThreadNameLength];
+
DISALLOW_COPY_AND_ASSIGN(Thread);
};
diff --git a/src/preparser-api.cc b/src/preparser-api.cc
index cbec9b7..dba3026 100644
--- a/src/preparser-api.cc
+++ b/src/preparser-api.cc
@@ -155,7 +155,6 @@
public:
void Initialize(UC16CharacterStream* source) {
source_ = source;
- literal_flags_ = kLiteralString | kLiteralIdentifier;
Init();
// Skip initial whitespace allowing HTML comment ends just like
// after a newline and scan first token.
diff --git a/src/preparser.cc b/src/preparser.cc
index 157fbea..e05f903 100644
--- a/src/preparser.cc
+++ b/src/preparser.cc
@@ -950,13 +950,17 @@
ParseIdentifierOrGetOrSet(&is_getter, &is_setter, CHECK_OK);
if ((is_getter || is_setter) && peek() != i::Token::COLON) {
i::Token::Value name = Next();
+ bool is_keyword = i::Token::IsKeyword(name);
if (name != i::Token::IDENTIFIER &&
name != i::Token::NUMBER &&
name != i::Token::STRING &&
- !i::Token::IsKeyword(name)) {
+ !is_keyword) {
*ok = false;
return kUnknownExpression;
}
+ if (!is_keyword) {
+ LogSymbol();
+ }
ParseFunctionLiteral(CHECK_OK);
if (peek() != i::Token::RBRACE) {
Expect(i::Token::COMMA, CHECK_OK);
@@ -1120,24 +1124,24 @@
}
-PreParser::Identifier PreParser::GetIdentifierSymbol() {
+void PreParser::LogSymbol() {
int identifier_pos = scanner_->location().beg_pos;
if (scanner_->is_literal_ascii()) {
log_->LogAsciiSymbol(identifier_pos, scanner_->literal_ascii_string());
} else {
log_->LogUC16Symbol(identifier_pos, scanner_->literal_uc16_string());
}
+}
+
+
+PreParser::Identifier PreParser::GetIdentifierSymbol() {
+ LogSymbol();
return kUnknownIdentifier;
}
PreParser::Expression PreParser::GetStringSymbol() {
- int identifier_pos = scanner_->location().beg_pos;
- if (scanner_->is_literal_ascii()) {
- log_->LogAsciiSymbol(identifier_pos, scanner_->literal_ascii_string());
- } else {
- log_->LogUC16Symbol(identifier_pos, scanner_->literal_uc16_string());
- }
+ LogSymbol();
return kUnknownExpression;
}
diff --git a/src/preparser.h b/src/preparser.h
index 893b575..536e6d4 100644
--- a/src/preparser.h
+++ b/src/preparser.h
@@ -216,8 +216,11 @@
Identifier ParseIdentifierName(bool* ok);
Identifier ParseIdentifierOrGetOrSet(bool* is_get, bool* is_set, bool* ok);
+ // Logs the currently parsed literal as a symbol in the preparser data.
+ void LogSymbol();
+ // Log the currently parsed identifier.
Identifier GetIdentifierSymbol();
- unsigned int HexDigitValue(char digit);
+ // Log the currently parsed string literal.
Expression GetStringSymbol();
i::Token::Value peek() {
diff --git a/src/scanner-base.h b/src/scanner-base.h
index e773586..b668df5 100644
--- a/src/scanner-base.h
+++ b/src/scanner-base.h
@@ -214,7 +214,9 @@
ASSERT(is_ascii_);
Vector<byte> new_store;
int new_content_size = position_ * kUC16Size;
- if (new_content_size > backing_store_.length()) {
+ if (new_content_size >= backing_store_.length()) {
+ // Ensure room for all currently read characters as UC16 as well
+ // as the character about to be stored.
new_store = Vector<byte>::New(NewCapacity(new_content_size));
} else {
new_store = backing_store_;
diff --git a/src/scanner.cc b/src/scanner.cc
index 38d0b1c..7fd6ef2 100755
--- a/src/scanner.cc
+++ b/src/scanner.cc
@@ -457,7 +457,7 @@
ASSERT_EQ('"', c0_);
Advance();
LiteralScope literal(this);
- while (c0_ != '"' && c0_ > 0) {
+ while (c0_ != '"') {
// Check for control character (0x00-0x1f) or unterminated string (<0).
if (c0_ < 0x20) return Token::ILLEGAL;
if (c0_ != '\\') {
@@ -504,9 +504,6 @@
Advance();
}
}
- if (c0_ != '"') {
- return Token::ILLEGAL;
- }
literal.Complete();
Advance();
return Token::STRING;
diff --git a/src/top.cc b/src/top.cc
index 3d86d11..98c673c 100644
--- a/src/top.cc
+++ b/src/top.cc
@@ -170,7 +170,9 @@
// into for use by a stacks only core dump (aka minidump).
class PreallocatedMemoryThread: public Thread {
public:
- PreallocatedMemoryThread() : keep_running_(true) {
+ PreallocatedMemoryThread()
+ : Thread("v8:PreallocMem"),
+ keep_running_(true) {
wait_for_ever_semaphore_ = OS::CreateSemaphore(0);
data_ready_semaphore_ = OS::CreateSemaphore(0);
}
diff --git a/src/unicode.cc b/src/unicode.cc
index 35a66c6..346f673 100644
--- a/src/unicode.cc
+++ b/src/unicode.cc
@@ -25,7 +25,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
-// This file was generated at 2010-07-30 14:07:24.988557
+// This file was generated at 2011-01-03 10:57:02.088925
#include "unicode-inl.h"
#include <stdlib.h>
@@ -35,6 +35,7 @@
static const int kStartBit = (1 << 30);
static const int kChunkBits = (1 << 13);
+static const uchar kSentinel = static_cast<uchar>(-1);
/**
* \file
@@ -96,12 +97,12 @@
int32_t field = TableGet<kEntryDist>(table, low);
uchar entry = GetEntry(field);
bool is_start = IsStart(field);
- return (entry == value) ||
- (entry < value && is_start);
+ return (entry == value) || (entry < value && is_start);
}
template <int kW>
struct MultiCharacterSpecialCase {
+ static const uchar kEndOfEncoding = kSentinel;
uchar chars[kW];
};
@@ -172,7 +173,7 @@
int length = 0;
for (length = 0; length < kW; length++) {
uchar mapped = mapping.chars[length];
- if (mapped == static_cast<uchar>(-1)) break;
+ if (mapped == MultiCharacterSpecialCase<kW>::kEndOfEncoding) break;
if (ranges_are_linear) {
result[length] = mapped + (key - entry);
} else {
@@ -225,13 +226,13 @@
*cursor += 1;
return kBadChar;
}
- uchar l = ((first << 6) | second) & kMaxTwoByteChar;
- if (l <= kMaxOneByteChar) {
+ uchar code_point = ((first << 6) | second) & kMaxTwoByteChar;
+ if (code_point <= kMaxOneByteChar) {
*cursor += 1;
return kBadChar;
}
*cursor += 2;
- return l;
+ return code_point;
}
if (length == 2) {
*cursor += 1;
@@ -243,13 +244,14 @@
return kBadChar;
}
if (first < 0xF0) {
- uchar l = ((((first << 6) | second) << 6) | third) & kMaxThreeByteChar;
- if (l <= kMaxTwoByteChar) {
+ uchar code_point = ((((first << 6) | second) << 6) | third)
+ & kMaxThreeByteChar;
+ if (code_point <= kMaxTwoByteChar) {
*cursor += 1;
return kBadChar;
}
*cursor += 3;
- return l;
+ return code_point;
}
if (length == 3) {
*cursor += 1;
@@ -261,14 +263,14 @@
return kBadChar;
}
if (first < 0xF8) {
- uchar l = (((((first << 6 | second) << 6) | third) << 6) | fourth) &
- kMaxFourByteChar;
- if (l <= kMaxThreeByteChar) {
+ uchar code_point = (((((first << 6 | second) << 6) | third) << 6) | fourth)
+ & kMaxFourByteChar;
+ if (code_point <= kMaxThreeByteChar) {
*cursor += 1;
return kBadChar;
}
*cursor += 4;
- return l;
+ return code_point;
}
*cursor += 1;
return kBadChar;
@@ -823,7 +825,7 @@
}
static const MultiCharacterSpecialCase<2> kToLowercaseMultiStrings0[2] = { // NOLINT
- {{105, 775}}, {{-1}} }; // NOLINT
+ {{105, 775}}, {{kSentinel}} }; // NOLINT
static const uint16_t kToLowercaseTable0Size = 463; // NOLINT
static const int32_t kToLowercaseTable0[926] = {
1073741889, 128, 90, 128, 1073742016, 128, 214, 128, 1073742040, 128, 222, 128, 256, 4, 258, 4, // NOLINT
@@ -886,7 +888,7 @@
8171, -448, 8172, -28, 1073750008, -512, 8185, -512, 1073750010, -504, 8187, -504, 8188, -36 }; // NOLINT
static const uint16_t kToLowercaseMultiStrings0Size = 2; // NOLINT
static const MultiCharacterSpecialCase<1> kToLowercaseMultiStrings1[1] = { // NOLINT
- {{-1}} }; // NOLINT
+ {{kSentinel}} }; // NOLINT
static const uint16_t kToLowercaseTable1Size = 69; // NOLINT
static const int32_t kToLowercaseTable1[138] = {
294, -30068, 298, -33532, 299, -33048, 306, 112, 1073742176, 64, 367, 64, 387, 4, 1073743030, 104, // NOLINT
@@ -900,7 +902,7 @@
3290, 4, 3292, 4, 3294, 4, 3296, 4, 3298, 4 }; // NOLINT
static const uint16_t kToLowercaseMultiStrings1Size = 1; // NOLINT
static const MultiCharacterSpecialCase<1> kToLowercaseMultiStrings7[1] = { // NOLINT
- {{-1}} }; // NOLINT
+ {{kSentinel}} }; // NOLINT
static const uint16_t kToLowercaseTable7Size = 2; // NOLINT
static const int32_t kToLowercaseTable7[4] = {
1073749793, 128, 7994, 128 }; // NOLINT
@@ -937,22 +939,22 @@
}
static const MultiCharacterSpecialCase<3> kToUppercaseMultiStrings0[62] = { // NOLINT
- {{83, 83, -1}}, {{700, 78, -1}}, {{74, 780, -1}}, {{921, 776, 769}}, // NOLINT
- {{933, 776, 769}}, {{1333, 1362, -1}}, {{72, 817, -1}}, {{84, 776, -1}}, // NOLINT
- {{87, 778, -1}}, {{89, 778, -1}}, {{65, 702, -1}}, {{933, 787, -1}}, // NOLINT
- {{933, 787, 768}}, {{933, 787, 769}}, {{933, 787, 834}}, {{7944, 921, -1}}, // NOLINT
- {{7945, 921, -1}}, {{7946, 921, -1}}, {{7947, 921, -1}}, {{7948, 921, -1}}, // NOLINT
- {{7949, 921, -1}}, {{7950, 921, -1}}, {{7951, 921, -1}}, {{7976, 921, -1}}, // NOLINT
- {{7977, 921, -1}}, {{7978, 921, -1}}, {{7979, 921, -1}}, {{7980, 921, -1}}, // NOLINT
- {{7981, 921, -1}}, {{7982, 921, -1}}, {{7983, 921, -1}}, {{8040, 921, -1}}, // NOLINT
- {{8041, 921, -1}}, {{8042, 921, -1}}, {{8043, 921, -1}}, {{8044, 921, -1}}, // NOLINT
- {{8045, 921, -1}}, {{8046, 921, -1}}, {{8047, 921, -1}}, {{8122, 921, -1}}, // NOLINT
- {{913, 921, -1}}, {{902, 921, -1}}, {{913, 834, -1}}, {{913, 834, 921}}, // NOLINT
- {{8138, 921, -1}}, {{919, 921, -1}}, {{905, 921, -1}}, {{919, 834, -1}}, // NOLINT
- {{919, 834, 921}}, {{921, 776, 768}}, {{921, 834, -1}}, {{921, 776, 834}}, // NOLINT
- {{933, 776, 768}}, {{929, 787, -1}}, {{933, 834, -1}}, {{933, 776, 834}}, // NOLINT
- {{8186, 921, -1}}, {{937, 921, -1}}, {{911, 921, -1}}, {{937, 834, -1}}, // NOLINT
- {{937, 834, 921}}, {{-1}} }; // NOLINT
+ {{83, 83, kSentinel}}, {{700, 78, kSentinel}}, {{74, 780, kSentinel}}, {{921, 776, 769}}, // NOLINT
+ {{933, 776, 769}}, {{1333, 1362, kSentinel}}, {{72, 817, kSentinel}}, {{84, 776, kSentinel}}, // NOLINT
+ {{87, 778, kSentinel}}, {{89, 778, kSentinel}}, {{65, 702, kSentinel}}, {{933, 787, kSentinel}}, // NOLINT
+ {{933, 787, 768}}, {{933, 787, 769}}, {{933, 787, 834}}, {{7944, 921, kSentinel}}, // NOLINT
+ {{7945, 921, kSentinel}}, {{7946, 921, kSentinel}}, {{7947, 921, kSentinel}}, {{7948, 921, kSentinel}}, // NOLINT
+ {{7949, 921, kSentinel}}, {{7950, 921, kSentinel}}, {{7951, 921, kSentinel}}, {{7976, 921, kSentinel}}, // NOLINT
+ {{7977, 921, kSentinel}}, {{7978, 921, kSentinel}}, {{7979, 921, kSentinel}}, {{7980, 921, kSentinel}}, // NOLINT
+ {{7981, 921, kSentinel}}, {{7982, 921, kSentinel}}, {{7983, 921, kSentinel}}, {{8040, 921, kSentinel}}, // NOLINT
+ {{8041, 921, kSentinel}}, {{8042, 921, kSentinel}}, {{8043, 921, kSentinel}}, {{8044, 921, kSentinel}}, // NOLINT
+ {{8045, 921, kSentinel}}, {{8046, 921, kSentinel}}, {{8047, 921, kSentinel}}, {{8122, 921, kSentinel}}, // NOLINT
+ {{913, 921, kSentinel}}, {{902, 921, kSentinel}}, {{913, 834, kSentinel}}, {{913, 834, 921}}, // NOLINT
+ {{8138, 921, kSentinel}}, {{919, 921, kSentinel}}, {{905, 921, kSentinel}}, {{919, 834, kSentinel}}, // NOLINT
+ {{919, 834, 921}}, {{921, 776, 768}}, {{921, 834, kSentinel}}, {{921, 776, 834}}, // NOLINT
+ {{933, 776, 768}}, {{929, 787, kSentinel}}, {{933, 834, kSentinel}}, {{933, 776, 834}}, // NOLINT
+ {{8186, 921, kSentinel}}, {{937, 921, kSentinel}}, {{911, 921, kSentinel}}, {{937, 834, kSentinel}}, // NOLINT
+ {{937, 834, 921}}, {{kSentinel}} }; // NOLINT
static const uint16_t kToUppercaseTable0Size = 554; // NOLINT
static const int32_t kToUppercaseTable0[1108] = {
1073741921, -128, 122, -128, 181, 2972, 223, 1, 1073742048, -128, 246, -128, 1073742072, -128, 254, -128, // NOLINT
@@ -1027,7 +1029,7 @@
8183, 241, 8188, 229 }; // NOLINT
static const uint16_t kToUppercaseMultiStrings0Size = 62; // NOLINT
static const MultiCharacterSpecialCase<1> kToUppercaseMultiStrings1[1] = { // NOLINT
- {{-1}} }; // NOLINT
+ {{kSentinel}} }; // NOLINT
static const uint16_t kToUppercaseTable1Size = 67; // NOLINT
static const int32_t kToUppercaseTable1[134] = {
334, -112, 1073742192, -64, 383, -64, 388, -4, 1073743056, -104, 1257, -104, 1073744944, -192, 3166, -192, // NOLINT
@@ -1041,9 +1043,9 @@
3299, -4, 1073745152, -29056, 3365, -29056 }; // NOLINT
static const uint16_t kToUppercaseMultiStrings1Size = 1; // NOLINT
static const MultiCharacterSpecialCase<3> kToUppercaseMultiStrings7[12] = { // NOLINT
- {{70, 70, -1}}, {{70, 73, -1}}, {{70, 76, -1}}, {{70, 70, 73}}, // NOLINT
- {{70, 70, 76}}, {{83, 84, -1}}, {{1348, 1350, -1}}, {{1348, 1333, -1}}, // NOLINT
- {{1348, 1339, -1}}, {{1358, 1350, -1}}, {{1348, 1341, -1}}, {{-1}} }; // NOLINT
+ {{70, 70, kSentinel}}, {{70, 73, kSentinel}}, {{70, 76, kSentinel}}, {{70, 70, 73}}, // NOLINT
+ {{70, 70, 76}}, {{83, 84, kSentinel}}, {{1348, 1350, kSentinel}}, {{1348, 1333, kSentinel}}, // NOLINT
+ {{1348, 1339, kSentinel}}, {{1358, 1350, kSentinel}}, {{1348, 1341, kSentinel}}, {{kSentinel}} }; // NOLINT
static const uint16_t kToUppercaseTable7Size = 14; // NOLINT
static const int32_t kToUppercaseTable7[28] = {
6912, 1, 6913, 5, 6914, 9, 6915, 13, 6916, 17, 6917, 21, 6918, 21, 6931, 25, // NOLINT
@@ -1081,7 +1083,7 @@
}
static const MultiCharacterSpecialCase<1> kEcma262CanonicalizeMultiStrings0[1] = { // NOLINT
- {{-1}} }; // NOLINT
+ {{kSentinel}} }; // NOLINT
static const uint16_t kEcma262CanonicalizeTable0Size = 462; // NOLINT
static const int32_t kEcma262CanonicalizeTable0[924] = {
1073741921, -128, 122, -128, 181, 2972, 1073742048, -128, 246, -128, 1073742072, -128, 254, -128, 255, 484, // NOLINT
@@ -1144,7 +1146,7 @@
8126, -28820, 1073749968, 32, 8145, 32, 1073749984, 32, 8161, 32, 8165, 28 }; // NOLINT
static const uint16_t kEcma262CanonicalizeMultiStrings0Size = 1; // NOLINT
static const MultiCharacterSpecialCase<1> kEcma262CanonicalizeMultiStrings1[1] = { // NOLINT
- {{-1}} }; // NOLINT
+ {{kSentinel}} }; // NOLINT
static const uint16_t kEcma262CanonicalizeTable1Size = 67; // NOLINT
static const int32_t kEcma262CanonicalizeTable1[134] = {
334, -112, 1073742192, -64, 383, -64, 388, -4, 1073743056, -104, 1257, -104, 1073744944, -192, 3166, -192, // NOLINT
@@ -1158,7 +1160,7 @@
3299, -4, 1073745152, -29056, 3365, -29056 }; // NOLINT
static const uint16_t kEcma262CanonicalizeMultiStrings1Size = 1; // NOLINT
static const MultiCharacterSpecialCase<1> kEcma262CanonicalizeMultiStrings7[1] = { // NOLINT
- {{-1}} }; // NOLINT
+ {{kSentinel}} }; // NOLINT
static const uint16_t kEcma262CanonicalizeTable7Size = 2; // NOLINT
static const int32_t kEcma262CanonicalizeTable7[4] = {
1073749825, -128, 8026, -128 }; // NOLINT
@@ -1195,124 +1197,124 @@
}
static const MultiCharacterSpecialCase<4> kEcma262UnCanonicalizeMultiStrings0[469] = { // NOLINT
- {{65, 97, -1}}, {{90, 122, -1}}, {{181, 924, 956, -1}}, {{192, 224, -1}}, // NOLINT
- {{214, 246, -1}}, {{216, 248, -1}}, {{222, 254, -1}}, {{255, 376, -1}}, // NOLINT
- {{256, 257, -1}}, {{258, 259, -1}}, {{260, 261, -1}}, {{262, 263, -1}}, // NOLINT
- {{264, 265, -1}}, {{266, 267, -1}}, {{268, 269, -1}}, {{270, 271, -1}}, // NOLINT
- {{272, 273, -1}}, {{274, 275, -1}}, {{276, 277, -1}}, {{278, 279, -1}}, // NOLINT
- {{280, 281, -1}}, {{282, 283, -1}}, {{284, 285, -1}}, {{286, 287, -1}}, // NOLINT
- {{288, 289, -1}}, {{290, 291, -1}}, {{292, 293, -1}}, {{294, 295, -1}}, // NOLINT
- {{296, 297, -1}}, {{298, 299, -1}}, {{300, 301, -1}}, {{302, 303, -1}}, // NOLINT
- {{306, 307, -1}}, {{308, 309, -1}}, {{310, 311, -1}}, {{313, 314, -1}}, // NOLINT
- {{315, 316, -1}}, {{317, 318, -1}}, {{319, 320, -1}}, {{321, 322, -1}}, // NOLINT
- {{323, 324, -1}}, {{325, 326, -1}}, {{327, 328, -1}}, {{330, 331, -1}}, // NOLINT
- {{332, 333, -1}}, {{334, 335, -1}}, {{336, 337, -1}}, {{338, 339, -1}}, // NOLINT
- {{340, 341, -1}}, {{342, 343, -1}}, {{344, 345, -1}}, {{346, 347, -1}}, // NOLINT
- {{348, 349, -1}}, {{350, 351, -1}}, {{352, 353, -1}}, {{354, 355, -1}}, // NOLINT
- {{356, 357, -1}}, {{358, 359, -1}}, {{360, 361, -1}}, {{362, 363, -1}}, // NOLINT
- {{364, 365, -1}}, {{366, 367, -1}}, {{368, 369, -1}}, {{370, 371, -1}}, // NOLINT
- {{372, 373, -1}}, {{374, 375, -1}}, {{377, 378, -1}}, {{379, 380, -1}}, // NOLINT
- {{381, 382, -1}}, {{384, 579, -1}}, {{385, 595, -1}}, {{386, 387, -1}}, // NOLINT
- {{388, 389, -1}}, {{390, 596, -1}}, {{391, 392, -1}}, {{393, 598, -1}}, // NOLINT
- {{394, 599, -1}}, {{395, 396, -1}}, {{398, 477, -1}}, {{399, 601, -1}}, // NOLINT
- {{400, 603, -1}}, {{401, 402, -1}}, {{403, 608, -1}}, {{404, 611, -1}}, // NOLINT
- {{405, 502, -1}}, {{406, 617, -1}}, {{407, 616, -1}}, {{408, 409, -1}}, // NOLINT
- {{410, 573, -1}}, {{412, 623, -1}}, {{413, 626, -1}}, {{414, 544, -1}}, // NOLINT
- {{415, 629, -1}}, {{416, 417, -1}}, {{418, 419, -1}}, {{420, 421, -1}}, // NOLINT
- {{422, 640, -1}}, {{423, 424, -1}}, {{425, 643, -1}}, {{428, 429, -1}}, // NOLINT
- {{430, 648, -1}}, {{431, 432, -1}}, {{433, 650, -1}}, {{434, 651, -1}}, // NOLINT
- {{435, 436, -1}}, {{437, 438, -1}}, {{439, 658, -1}}, {{440, 441, -1}}, // NOLINT
- {{444, 445, -1}}, {{447, 503, -1}}, {{452, 453, 454, -1}}, {{455, 456, 457, -1}}, // NOLINT
- {{458, 459, 460, -1}}, {{461, 462, -1}}, {{463, 464, -1}}, {{465, 466, -1}}, // NOLINT
- {{467, 468, -1}}, {{469, 470, -1}}, {{471, 472, -1}}, {{473, 474, -1}}, // NOLINT
- {{475, 476, -1}}, {{478, 479, -1}}, {{480, 481, -1}}, {{482, 483, -1}}, // NOLINT
- {{484, 485, -1}}, {{486, 487, -1}}, {{488, 489, -1}}, {{490, 491, -1}}, // NOLINT
- {{492, 493, -1}}, {{494, 495, -1}}, {{497, 498, 499, -1}}, {{500, 501, -1}}, // NOLINT
- {{504, 505, -1}}, {{506, 507, -1}}, {{508, 509, -1}}, {{510, 511, -1}}, // NOLINT
- {{512, 513, -1}}, {{514, 515, -1}}, {{516, 517, -1}}, {{518, 519, -1}}, // NOLINT
- {{520, 521, -1}}, {{522, 523, -1}}, {{524, 525, -1}}, {{526, 527, -1}}, // NOLINT
- {{528, 529, -1}}, {{530, 531, -1}}, {{532, 533, -1}}, {{534, 535, -1}}, // NOLINT
- {{536, 537, -1}}, {{538, 539, -1}}, {{540, 541, -1}}, {{542, 543, -1}}, // NOLINT
- {{546, 547, -1}}, {{548, 549, -1}}, {{550, 551, -1}}, {{552, 553, -1}}, // NOLINT
- {{554, 555, -1}}, {{556, 557, -1}}, {{558, 559, -1}}, {{560, 561, -1}}, // NOLINT
- {{562, 563, -1}}, {{570, 11365, -1}}, {{571, 572, -1}}, {{574, 11366, -1}}, // NOLINT
- {{577, 578, -1}}, {{580, 649, -1}}, {{581, 652, -1}}, {{582, 583, -1}}, // NOLINT
- {{584, 585, -1}}, {{586, 587, -1}}, {{588, 589, -1}}, {{590, 591, -1}}, // NOLINT
- {{619, 11362, -1}}, {{637, 11364, -1}}, {{837, 921, 953, 8126}}, {{891, 1021, -1}}, // NOLINT
- {{893, 1023, -1}}, {{902, 940, -1}}, {{904, 941, -1}}, {{906, 943, -1}}, // NOLINT
- {{908, 972, -1}}, {{910, 973, -1}}, {{911, 974, -1}}, {{913, 945, -1}}, // NOLINT
- {{914, 946, 976, -1}}, {{915, 947, -1}}, {{916, 948, -1}}, {{917, 949, 1013, -1}}, // NOLINT
- {{918, 950, -1}}, {{919, 951, -1}}, {{920, 952, 977, -1}}, {{922, 954, 1008, -1}}, // NOLINT
- {{923, 955, -1}}, {{925, 957, -1}}, {{927, 959, -1}}, {{928, 960, 982, -1}}, // NOLINT
- {{929, 961, 1009, -1}}, {{931, 962, 963, -1}}, {{932, 964, -1}}, {{933, 965, -1}}, // NOLINT
- {{934, 966, 981, -1}}, {{935, 967, -1}}, {{939, 971, -1}}, {{984, 985, -1}}, // NOLINT
- {{986, 987, -1}}, {{988, 989, -1}}, {{990, 991, -1}}, {{992, 993, -1}}, // NOLINT
- {{994, 995, -1}}, {{996, 997, -1}}, {{998, 999, -1}}, {{1000, 1001, -1}}, // NOLINT
- {{1002, 1003, -1}}, {{1004, 1005, -1}}, {{1006, 1007, -1}}, {{1010, 1017, -1}}, // NOLINT
- {{1015, 1016, -1}}, {{1018, 1019, -1}}, {{1024, 1104, -1}}, {{1039, 1119, -1}}, // NOLINT
- {{1040, 1072, -1}}, {{1071, 1103, -1}}, {{1120, 1121, -1}}, {{1122, 1123, -1}}, // NOLINT
- {{1124, 1125, -1}}, {{1126, 1127, -1}}, {{1128, 1129, -1}}, {{1130, 1131, -1}}, // NOLINT
- {{1132, 1133, -1}}, {{1134, 1135, -1}}, {{1136, 1137, -1}}, {{1138, 1139, -1}}, // NOLINT
- {{1140, 1141, -1}}, {{1142, 1143, -1}}, {{1144, 1145, -1}}, {{1146, 1147, -1}}, // NOLINT
- {{1148, 1149, -1}}, {{1150, 1151, -1}}, {{1152, 1153, -1}}, {{1162, 1163, -1}}, // NOLINT
- {{1164, 1165, -1}}, {{1166, 1167, -1}}, {{1168, 1169, -1}}, {{1170, 1171, -1}}, // NOLINT
- {{1172, 1173, -1}}, {{1174, 1175, -1}}, {{1176, 1177, -1}}, {{1178, 1179, -1}}, // NOLINT
- {{1180, 1181, -1}}, {{1182, 1183, -1}}, {{1184, 1185, -1}}, {{1186, 1187, -1}}, // NOLINT
- {{1188, 1189, -1}}, {{1190, 1191, -1}}, {{1192, 1193, -1}}, {{1194, 1195, -1}}, // NOLINT
- {{1196, 1197, -1}}, {{1198, 1199, -1}}, {{1200, 1201, -1}}, {{1202, 1203, -1}}, // NOLINT
- {{1204, 1205, -1}}, {{1206, 1207, -1}}, {{1208, 1209, -1}}, {{1210, 1211, -1}}, // NOLINT
- {{1212, 1213, -1}}, {{1214, 1215, -1}}, {{1216, 1231, -1}}, {{1217, 1218, -1}}, // NOLINT
- {{1219, 1220, -1}}, {{1221, 1222, -1}}, {{1223, 1224, -1}}, {{1225, 1226, -1}}, // NOLINT
- {{1227, 1228, -1}}, {{1229, 1230, -1}}, {{1232, 1233, -1}}, {{1234, 1235, -1}}, // NOLINT
- {{1236, 1237, -1}}, {{1238, 1239, -1}}, {{1240, 1241, -1}}, {{1242, 1243, -1}}, // NOLINT
- {{1244, 1245, -1}}, {{1246, 1247, -1}}, {{1248, 1249, -1}}, {{1250, 1251, -1}}, // NOLINT
- {{1252, 1253, -1}}, {{1254, 1255, -1}}, {{1256, 1257, -1}}, {{1258, 1259, -1}}, // NOLINT
- {{1260, 1261, -1}}, {{1262, 1263, -1}}, {{1264, 1265, -1}}, {{1266, 1267, -1}}, // NOLINT
- {{1268, 1269, -1}}, {{1270, 1271, -1}}, {{1272, 1273, -1}}, {{1274, 1275, -1}}, // NOLINT
- {{1276, 1277, -1}}, {{1278, 1279, -1}}, {{1280, 1281, -1}}, {{1282, 1283, -1}}, // NOLINT
- {{1284, 1285, -1}}, {{1286, 1287, -1}}, {{1288, 1289, -1}}, {{1290, 1291, -1}}, // NOLINT
- {{1292, 1293, -1}}, {{1294, 1295, -1}}, {{1296, 1297, -1}}, {{1298, 1299, -1}}, // NOLINT
- {{1329, 1377, -1}}, {{1366, 1414, -1}}, {{4256, 11520, -1}}, {{4293, 11557, -1}}, // NOLINT
- {{7549, 11363, -1}}, {{7680, 7681, -1}}, {{7682, 7683, -1}}, {{7684, 7685, -1}}, // NOLINT
- {{7686, 7687, -1}}, {{7688, 7689, -1}}, {{7690, 7691, -1}}, {{7692, 7693, -1}}, // NOLINT
- {{7694, 7695, -1}}, {{7696, 7697, -1}}, {{7698, 7699, -1}}, {{7700, 7701, -1}}, // NOLINT
- {{7702, 7703, -1}}, {{7704, 7705, -1}}, {{7706, 7707, -1}}, {{7708, 7709, -1}}, // NOLINT
- {{7710, 7711, -1}}, {{7712, 7713, -1}}, {{7714, 7715, -1}}, {{7716, 7717, -1}}, // NOLINT
- {{7718, 7719, -1}}, {{7720, 7721, -1}}, {{7722, 7723, -1}}, {{7724, 7725, -1}}, // NOLINT
- {{7726, 7727, -1}}, {{7728, 7729, -1}}, {{7730, 7731, -1}}, {{7732, 7733, -1}}, // NOLINT
- {{7734, 7735, -1}}, {{7736, 7737, -1}}, {{7738, 7739, -1}}, {{7740, 7741, -1}}, // NOLINT
- {{7742, 7743, -1}}, {{7744, 7745, -1}}, {{7746, 7747, -1}}, {{7748, 7749, -1}}, // NOLINT
- {{7750, 7751, -1}}, {{7752, 7753, -1}}, {{7754, 7755, -1}}, {{7756, 7757, -1}}, // NOLINT
- {{7758, 7759, -1}}, {{7760, 7761, -1}}, {{7762, 7763, -1}}, {{7764, 7765, -1}}, // NOLINT
- {{7766, 7767, -1}}, {{7768, 7769, -1}}, {{7770, 7771, -1}}, {{7772, 7773, -1}}, // NOLINT
- {{7774, 7775, -1}}, {{7776, 7777, 7835, -1}}, {{7778, 7779, -1}}, {{7780, 7781, -1}}, // NOLINT
- {{7782, 7783, -1}}, {{7784, 7785, -1}}, {{7786, 7787, -1}}, {{7788, 7789, -1}}, // NOLINT
- {{7790, 7791, -1}}, {{7792, 7793, -1}}, {{7794, 7795, -1}}, {{7796, 7797, -1}}, // NOLINT
- {{7798, 7799, -1}}, {{7800, 7801, -1}}, {{7802, 7803, -1}}, {{7804, 7805, -1}}, // NOLINT
- {{7806, 7807, -1}}, {{7808, 7809, -1}}, {{7810, 7811, -1}}, {{7812, 7813, -1}}, // NOLINT
- {{7814, 7815, -1}}, {{7816, 7817, -1}}, {{7818, 7819, -1}}, {{7820, 7821, -1}}, // NOLINT
- {{7822, 7823, -1}}, {{7824, 7825, -1}}, {{7826, 7827, -1}}, {{7828, 7829, -1}}, // NOLINT
- {{7840, 7841, -1}}, {{7842, 7843, -1}}, {{7844, 7845, -1}}, {{7846, 7847, -1}}, // NOLINT
- {{7848, 7849, -1}}, {{7850, 7851, -1}}, {{7852, 7853, -1}}, {{7854, 7855, -1}}, // NOLINT
- {{7856, 7857, -1}}, {{7858, 7859, -1}}, {{7860, 7861, -1}}, {{7862, 7863, -1}}, // NOLINT
- {{7864, 7865, -1}}, {{7866, 7867, -1}}, {{7868, 7869, -1}}, {{7870, 7871, -1}}, // NOLINT
- {{7872, 7873, -1}}, {{7874, 7875, -1}}, {{7876, 7877, -1}}, {{7878, 7879, -1}}, // NOLINT
- {{7880, 7881, -1}}, {{7882, 7883, -1}}, {{7884, 7885, -1}}, {{7886, 7887, -1}}, // NOLINT
- {{7888, 7889, -1}}, {{7890, 7891, -1}}, {{7892, 7893, -1}}, {{7894, 7895, -1}}, // NOLINT
- {{7896, 7897, -1}}, {{7898, 7899, -1}}, {{7900, 7901, -1}}, {{7902, 7903, -1}}, // NOLINT
- {{7904, 7905, -1}}, {{7906, 7907, -1}}, {{7908, 7909, -1}}, {{7910, 7911, -1}}, // NOLINT
- {{7912, 7913, -1}}, {{7914, 7915, -1}}, {{7916, 7917, -1}}, {{7918, 7919, -1}}, // NOLINT
- {{7920, 7921, -1}}, {{7922, 7923, -1}}, {{7924, 7925, -1}}, {{7926, 7927, -1}}, // NOLINT
- {{7928, 7929, -1}}, {{7936, 7944, -1}}, {{7943, 7951, -1}}, {{7952, 7960, -1}}, // NOLINT
- {{7957, 7965, -1}}, {{7968, 7976, -1}}, {{7975, 7983, -1}}, {{7984, 7992, -1}}, // NOLINT
- {{7991, 7999, -1}}, {{8000, 8008, -1}}, {{8005, 8013, -1}}, {{8017, 8025, -1}}, // NOLINT
- {{8019, 8027, -1}}, {{8021, 8029, -1}}, {{8023, 8031, -1}}, {{8032, 8040, -1}}, // NOLINT
- {{8039, 8047, -1}}, {{8048, 8122, -1}}, {{8049, 8123, -1}}, {{8050, 8136, -1}}, // NOLINT
- {{8053, 8139, -1}}, {{8054, 8154, -1}}, {{8055, 8155, -1}}, {{8056, 8184, -1}}, // NOLINT
- {{8057, 8185, -1}}, {{8058, 8170, -1}}, {{8059, 8171, -1}}, {{8060, 8186, -1}}, // NOLINT
- {{8061, 8187, -1}}, {{8112, 8120, -1}}, {{8113, 8121, -1}}, {{8144, 8152, -1}}, // NOLINT
- {{8145, 8153, -1}}, {{8160, 8168, -1}}, {{8161, 8169, -1}}, {{8165, 8172, -1}}, // NOLINT
- {{-1}} }; // NOLINT
+ {{65, 97, kSentinel}}, {{90, 122, kSentinel}}, {{181, 924, 956, kSentinel}}, {{192, 224, kSentinel}}, // NOLINT
+ {{214, 246, kSentinel}}, {{216, 248, kSentinel}}, {{222, 254, kSentinel}}, {{255, 376, kSentinel}}, // NOLINT
+ {{256, 257, kSentinel}}, {{258, 259, kSentinel}}, {{260, 261, kSentinel}}, {{262, 263, kSentinel}}, // NOLINT
+ {{264, 265, kSentinel}}, {{266, 267, kSentinel}}, {{268, 269, kSentinel}}, {{270, 271, kSentinel}}, // NOLINT
+ {{272, 273, kSentinel}}, {{274, 275, kSentinel}}, {{276, 277, kSentinel}}, {{278, 279, kSentinel}}, // NOLINT
+ {{280, 281, kSentinel}}, {{282, 283, kSentinel}}, {{284, 285, kSentinel}}, {{286, 287, kSentinel}}, // NOLINT
+ {{288, 289, kSentinel}}, {{290, 291, kSentinel}}, {{292, 293, kSentinel}}, {{294, 295, kSentinel}}, // NOLINT
+ {{296, 297, kSentinel}}, {{298, 299, kSentinel}}, {{300, 301, kSentinel}}, {{302, 303, kSentinel}}, // NOLINT
+ {{306, 307, kSentinel}}, {{308, 309, kSentinel}}, {{310, 311, kSentinel}}, {{313, 314, kSentinel}}, // NOLINT
+ {{315, 316, kSentinel}}, {{317, 318, kSentinel}}, {{319, 320, kSentinel}}, {{321, 322, kSentinel}}, // NOLINT
+ {{323, 324, kSentinel}}, {{325, 326, kSentinel}}, {{327, 328, kSentinel}}, {{330, 331, kSentinel}}, // NOLINT
+ {{332, 333, kSentinel}}, {{334, 335, kSentinel}}, {{336, 337, kSentinel}}, {{338, 339, kSentinel}}, // NOLINT
+ {{340, 341, kSentinel}}, {{342, 343, kSentinel}}, {{344, 345, kSentinel}}, {{346, 347, kSentinel}}, // NOLINT
+ {{348, 349, kSentinel}}, {{350, 351, kSentinel}}, {{352, 353, kSentinel}}, {{354, 355, kSentinel}}, // NOLINT
+ {{356, 357, kSentinel}}, {{358, 359, kSentinel}}, {{360, 361, kSentinel}}, {{362, 363, kSentinel}}, // NOLINT
+ {{364, 365, kSentinel}}, {{366, 367, kSentinel}}, {{368, 369, kSentinel}}, {{370, 371, kSentinel}}, // NOLINT
+ {{372, 373, kSentinel}}, {{374, 375, kSentinel}}, {{377, 378, kSentinel}}, {{379, 380, kSentinel}}, // NOLINT
+ {{381, 382, kSentinel}}, {{384, 579, kSentinel}}, {{385, 595, kSentinel}}, {{386, 387, kSentinel}}, // NOLINT
+ {{388, 389, kSentinel}}, {{390, 596, kSentinel}}, {{391, 392, kSentinel}}, {{393, 598, kSentinel}}, // NOLINT
+ {{394, 599, kSentinel}}, {{395, 396, kSentinel}}, {{398, 477, kSentinel}}, {{399, 601, kSentinel}}, // NOLINT
+ {{400, 603, kSentinel}}, {{401, 402, kSentinel}}, {{403, 608, kSentinel}}, {{404, 611, kSentinel}}, // NOLINT
+ {{405, 502, kSentinel}}, {{406, 617, kSentinel}}, {{407, 616, kSentinel}}, {{408, 409, kSentinel}}, // NOLINT
+ {{410, 573, kSentinel}}, {{412, 623, kSentinel}}, {{413, 626, kSentinel}}, {{414, 544, kSentinel}}, // NOLINT
+ {{415, 629, kSentinel}}, {{416, 417, kSentinel}}, {{418, 419, kSentinel}}, {{420, 421, kSentinel}}, // NOLINT
+ {{422, 640, kSentinel}}, {{423, 424, kSentinel}}, {{425, 643, kSentinel}}, {{428, 429, kSentinel}}, // NOLINT
+ {{430, 648, kSentinel}}, {{431, 432, kSentinel}}, {{433, 650, kSentinel}}, {{434, 651, kSentinel}}, // NOLINT
+ {{435, 436, kSentinel}}, {{437, 438, kSentinel}}, {{439, 658, kSentinel}}, {{440, 441, kSentinel}}, // NOLINT
+ {{444, 445, kSentinel}}, {{447, 503, kSentinel}}, {{452, 453, 454, kSentinel}}, {{455, 456, 457, kSentinel}}, // NOLINT
+ {{458, 459, 460, kSentinel}}, {{461, 462, kSentinel}}, {{463, 464, kSentinel}}, {{465, 466, kSentinel}}, // NOLINT
+ {{467, 468, kSentinel}}, {{469, 470, kSentinel}}, {{471, 472, kSentinel}}, {{473, 474, kSentinel}}, // NOLINT
+ {{475, 476, kSentinel}}, {{478, 479, kSentinel}}, {{480, 481, kSentinel}}, {{482, 483, kSentinel}}, // NOLINT
+ {{484, 485, kSentinel}}, {{486, 487, kSentinel}}, {{488, 489, kSentinel}}, {{490, 491, kSentinel}}, // NOLINT
+ {{492, 493, kSentinel}}, {{494, 495, kSentinel}}, {{497, 498, 499, kSentinel}}, {{500, 501, kSentinel}}, // NOLINT
+ {{504, 505, kSentinel}}, {{506, 507, kSentinel}}, {{508, 509, kSentinel}}, {{510, 511, kSentinel}}, // NOLINT
+ {{512, 513, kSentinel}}, {{514, 515, kSentinel}}, {{516, 517, kSentinel}}, {{518, 519, kSentinel}}, // NOLINT
+ {{520, 521, kSentinel}}, {{522, 523, kSentinel}}, {{524, 525, kSentinel}}, {{526, 527, kSentinel}}, // NOLINT
+ {{528, 529, kSentinel}}, {{530, 531, kSentinel}}, {{532, 533, kSentinel}}, {{534, 535, kSentinel}}, // NOLINT
+ {{536, 537, kSentinel}}, {{538, 539, kSentinel}}, {{540, 541, kSentinel}}, {{542, 543, kSentinel}}, // NOLINT
+ {{546, 547, kSentinel}}, {{548, 549, kSentinel}}, {{550, 551, kSentinel}}, {{552, 553, kSentinel}}, // NOLINT
+ {{554, 555, kSentinel}}, {{556, 557, kSentinel}}, {{558, 559, kSentinel}}, {{560, 561, kSentinel}}, // NOLINT
+ {{562, 563, kSentinel}}, {{570, 11365, kSentinel}}, {{571, 572, kSentinel}}, {{574, 11366, kSentinel}}, // NOLINT
+ {{577, 578, kSentinel}}, {{580, 649, kSentinel}}, {{581, 652, kSentinel}}, {{582, 583, kSentinel}}, // NOLINT
+ {{584, 585, kSentinel}}, {{586, 587, kSentinel}}, {{588, 589, kSentinel}}, {{590, 591, kSentinel}}, // NOLINT
+ {{619, 11362, kSentinel}}, {{637, 11364, kSentinel}}, {{837, 921, 953, 8126}}, {{891, 1021, kSentinel}}, // NOLINT
+ {{893, 1023, kSentinel}}, {{902, 940, kSentinel}}, {{904, 941, kSentinel}}, {{906, 943, kSentinel}}, // NOLINT
+ {{908, 972, kSentinel}}, {{910, 973, kSentinel}}, {{911, 974, kSentinel}}, {{913, 945, kSentinel}}, // NOLINT
+ {{914, 946, 976, kSentinel}}, {{915, 947, kSentinel}}, {{916, 948, kSentinel}}, {{917, 949, 1013, kSentinel}}, // NOLINT
+ {{918, 950, kSentinel}}, {{919, 951, kSentinel}}, {{920, 952, 977, kSentinel}}, {{922, 954, 1008, kSentinel}}, // NOLINT
+ {{923, 955, kSentinel}}, {{925, 957, kSentinel}}, {{927, 959, kSentinel}}, {{928, 960, 982, kSentinel}}, // NOLINT
+ {{929, 961, 1009, kSentinel}}, {{931, 962, 963, kSentinel}}, {{932, 964, kSentinel}}, {{933, 965, kSentinel}}, // NOLINT
+ {{934, 966, 981, kSentinel}}, {{935, 967, kSentinel}}, {{939, 971, kSentinel}}, {{984, 985, kSentinel}}, // NOLINT
+ {{986, 987, kSentinel}}, {{988, 989, kSentinel}}, {{990, 991, kSentinel}}, {{992, 993, kSentinel}}, // NOLINT
+ {{994, 995, kSentinel}}, {{996, 997, kSentinel}}, {{998, 999, kSentinel}}, {{1000, 1001, kSentinel}}, // NOLINT
+ {{1002, 1003, kSentinel}}, {{1004, 1005, kSentinel}}, {{1006, 1007, kSentinel}}, {{1010, 1017, kSentinel}}, // NOLINT
+ {{1015, 1016, kSentinel}}, {{1018, 1019, kSentinel}}, {{1024, 1104, kSentinel}}, {{1039, 1119, kSentinel}}, // NOLINT
+ {{1040, 1072, kSentinel}}, {{1071, 1103, kSentinel}}, {{1120, 1121, kSentinel}}, {{1122, 1123, kSentinel}}, // NOLINT
+ {{1124, 1125, kSentinel}}, {{1126, 1127, kSentinel}}, {{1128, 1129, kSentinel}}, {{1130, 1131, kSentinel}}, // NOLINT
+ {{1132, 1133, kSentinel}}, {{1134, 1135, kSentinel}}, {{1136, 1137, kSentinel}}, {{1138, 1139, kSentinel}}, // NOLINT
+ {{1140, 1141, kSentinel}}, {{1142, 1143, kSentinel}}, {{1144, 1145, kSentinel}}, {{1146, 1147, kSentinel}}, // NOLINT
+ {{1148, 1149, kSentinel}}, {{1150, 1151, kSentinel}}, {{1152, 1153, kSentinel}}, {{1162, 1163, kSentinel}}, // NOLINT
+ {{1164, 1165, kSentinel}}, {{1166, 1167, kSentinel}}, {{1168, 1169, kSentinel}}, {{1170, 1171, kSentinel}}, // NOLINT
+ {{1172, 1173, kSentinel}}, {{1174, 1175, kSentinel}}, {{1176, 1177, kSentinel}}, {{1178, 1179, kSentinel}}, // NOLINT
+ {{1180, 1181, kSentinel}}, {{1182, 1183, kSentinel}}, {{1184, 1185, kSentinel}}, {{1186, 1187, kSentinel}}, // NOLINT
+ {{1188, 1189, kSentinel}}, {{1190, 1191, kSentinel}}, {{1192, 1193, kSentinel}}, {{1194, 1195, kSentinel}}, // NOLINT
+ {{1196, 1197, kSentinel}}, {{1198, 1199, kSentinel}}, {{1200, 1201, kSentinel}}, {{1202, 1203, kSentinel}}, // NOLINT
+ {{1204, 1205, kSentinel}}, {{1206, 1207, kSentinel}}, {{1208, 1209, kSentinel}}, {{1210, 1211, kSentinel}}, // NOLINT
+ {{1212, 1213, kSentinel}}, {{1214, 1215, kSentinel}}, {{1216, 1231, kSentinel}}, {{1217, 1218, kSentinel}}, // NOLINT
+ {{1219, 1220, kSentinel}}, {{1221, 1222, kSentinel}}, {{1223, 1224, kSentinel}}, {{1225, 1226, kSentinel}}, // NOLINT
+ {{1227, 1228, kSentinel}}, {{1229, 1230, kSentinel}}, {{1232, 1233, kSentinel}}, {{1234, 1235, kSentinel}}, // NOLINT
+ {{1236, 1237, kSentinel}}, {{1238, 1239, kSentinel}}, {{1240, 1241, kSentinel}}, {{1242, 1243, kSentinel}}, // NOLINT
+ {{1244, 1245, kSentinel}}, {{1246, 1247, kSentinel}}, {{1248, 1249, kSentinel}}, {{1250, 1251, kSentinel}}, // NOLINT
+ {{1252, 1253, kSentinel}}, {{1254, 1255, kSentinel}}, {{1256, 1257, kSentinel}}, {{1258, 1259, kSentinel}}, // NOLINT
+ {{1260, 1261, kSentinel}}, {{1262, 1263, kSentinel}}, {{1264, 1265, kSentinel}}, {{1266, 1267, kSentinel}}, // NOLINT
+ {{1268, 1269, kSentinel}}, {{1270, 1271, kSentinel}}, {{1272, 1273, kSentinel}}, {{1274, 1275, kSentinel}}, // NOLINT
+ {{1276, 1277, kSentinel}}, {{1278, 1279, kSentinel}}, {{1280, 1281, kSentinel}}, {{1282, 1283, kSentinel}}, // NOLINT
+ {{1284, 1285, kSentinel}}, {{1286, 1287, kSentinel}}, {{1288, 1289, kSentinel}}, {{1290, 1291, kSentinel}}, // NOLINT
+ {{1292, 1293, kSentinel}}, {{1294, 1295, kSentinel}}, {{1296, 1297, kSentinel}}, {{1298, 1299, kSentinel}}, // NOLINT
+ {{1329, 1377, kSentinel}}, {{1366, 1414, kSentinel}}, {{4256, 11520, kSentinel}}, {{4293, 11557, kSentinel}}, // NOLINT
+ {{7549, 11363, kSentinel}}, {{7680, 7681, kSentinel}}, {{7682, 7683, kSentinel}}, {{7684, 7685, kSentinel}}, // NOLINT
+ {{7686, 7687, kSentinel}}, {{7688, 7689, kSentinel}}, {{7690, 7691, kSentinel}}, {{7692, 7693, kSentinel}}, // NOLINT
+ {{7694, 7695, kSentinel}}, {{7696, 7697, kSentinel}}, {{7698, 7699, kSentinel}}, {{7700, 7701, kSentinel}}, // NOLINT
+ {{7702, 7703, kSentinel}}, {{7704, 7705, kSentinel}}, {{7706, 7707, kSentinel}}, {{7708, 7709, kSentinel}}, // NOLINT
+ {{7710, 7711, kSentinel}}, {{7712, 7713, kSentinel}}, {{7714, 7715, kSentinel}}, {{7716, 7717, kSentinel}}, // NOLINT
+ {{7718, 7719, kSentinel}}, {{7720, 7721, kSentinel}}, {{7722, 7723, kSentinel}}, {{7724, 7725, kSentinel}}, // NOLINT
+ {{7726, 7727, kSentinel}}, {{7728, 7729, kSentinel}}, {{7730, 7731, kSentinel}}, {{7732, 7733, kSentinel}}, // NOLINT
+ {{7734, 7735, kSentinel}}, {{7736, 7737, kSentinel}}, {{7738, 7739, kSentinel}}, {{7740, 7741, kSentinel}}, // NOLINT
+ {{7742, 7743, kSentinel}}, {{7744, 7745, kSentinel}}, {{7746, 7747, kSentinel}}, {{7748, 7749, kSentinel}}, // NOLINT
+ {{7750, 7751, kSentinel}}, {{7752, 7753, kSentinel}}, {{7754, 7755, kSentinel}}, {{7756, 7757, kSentinel}}, // NOLINT
+ {{7758, 7759, kSentinel}}, {{7760, 7761, kSentinel}}, {{7762, 7763, kSentinel}}, {{7764, 7765, kSentinel}}, // NOLINT
+ {{7766, 7767, kSentinel}}, {{7768, 7769, kSentinel}}, {{7770, 7771, kSentinel}}, {{7772, 7773, kSentinel}}, // NOLINT
+ {{7774, 7775, kSentinel}}, {{7776, 7777, 7835, kSentinel}}, {{7778, 7779, kSentinel}}, {{7780, 7781, kSentinel}}, // NOLINT
+ {{7782, 7783, kSentinel}}, {{7784, 7785, kSentinel}}, {{7786, 7787, kSentinel}}, {{7788, 7789, kSentinel}}, // NOLINT
+ {{7790, 7791, kSentinel}}, {{7792, 7793, kSentinel}}, {{7794, 7795, kSentinel}}, {{7796, 7797, kSentinel}}, // NOLINT
+ {{7798, 7799, kSentinel}}, {{7800, 7801, kSentinel}}, {{7802, 7803, kSentinel}}, {{7804, 7805, kSentinel}}, // NOLINT
+ {{7806, 7807, kSentinel}}, {{7808, 7809, kSentinel}}, {{7810, 7811, kSentinel}}, {{7812, 7813, kSentinel}}, // NOLINT
+ {{7814, 7815, kSentinel}}, {{7816, 7817, kSentinel}}, {{7818, 7819, kSentinel}}, {{7820, 7821, kSentinel}}, // NOLINT
+ {{7822, 7823, kSentinel}}, {{7824, 7825, kSentinel}}, {{7826, 7827, kSentinel}}, {{7828, 7829, kSentinel}}, // NOLINT
+ {{7840, 7841, kSentinel}}, {{7842, 7843, kSentinel}}, {{7844, 7845, kSentinel}}, {{7846, 7847, kSentinel}}, // NOLINT
+ {{7848, 7849, kSentinel}}, {{7850, 7851, kSentinel}}, {{7852, 7853, kSentinel}}, {{7854, 7855, kSentinel}}, // NOLINT
+ {{7856, 7857, kSentinel}}, {{7858, 7859, kSentinel}}, {{7860, 7861, kSentinel}}, {{7862, 7863, kSentinel}}, // NOLINT
+ {{7864, 7865, kSentinel}}, {{7866, 7867, kSentinel}}, {{7868, 7869, kSentinel}}, {{7870, 7871, kSentinel}}, // NOLINT
+ {{7872, 7873, kSentinel}}, {{7874, 7875, kSentinel}}, {{7876, 7877, kSentinel}}, {{7878, 7879, kSentinel}}, // NOLINT
+ {{7880, 7881, kSentinel}}, {{7882, 7883, kSentinel}}, {{7884, 7885, kSentinel}}, {{7886, 7887, kSentinel}}, // NOLINT
+ {{7888, 7889, kSentinel}}, {{7890, 7891, kSentinel}}, {{7892, 7893, kSentinel}}, {{7894, 7895, kSentinel}}, // NOLINT
+ {{7896, 7897, kSentinel}}, {{7898, 7899, kSentinel}}, {{7900, 7901, kSentinel}}, {{7902, 7903, kSentinel}}, // NOLINT
+ {{7904, 7905, kSentinel}}, {{7906, 7907, kSentinel}}, {{7908, 7909, kSentinel}}, {{7910, 7911, kSentinel}}, // NOLINT
+ {{7912, 7913, kSentinel}}, {{7914, 7915, kSentinel}}, {{7916, 7917, kSentinel}}, {{7918, 7919, kSentinel}}, // NOLINT
+ {{7920, 7921, kSentinel}}, {{7922, 7923, kSentinel}}, {{7924, 7925, kSentinel}}, {{7926, 7927, kSentinel}}, // NOLINT
+ {{7928, 7929, kSentinel}}, {{7936, 7944, kSentinel}}, {{7943, 7951, kSentinel}}, {{7952, 7960, kSentinel}}, // NOLINT
+ {{7957, 7965, kSentinel}}, {{7968, 7976, kSentinel}}, {{7975, 7983, kSentinel}}, {{7984, 7992, kSentinel}}, // NOLINT
+ {{7991, 7999, kSentinel}}, {{8000, 8008, kSentinel}}, {{8005, 8013, kSentinel}}, {{8017, 8025, kSentinel}}, // NOLINT
+ {{8019, 8027, kSentinel}}, {{8021, 8029, kSentinel}}, {{8023, 8031, kSentinel}}, {{8032, 8040, kSentinel}}, // NOLINT
+ {{8039, 8047, kSentinel}}, {{8048, 8122, kSentinel}}, {{8049, 8123, kSentinel}}, {{8050, 8136, kSentinel}}, // NOLINT
+ {{8053, 8139, kSentinel}}, {{8054, 8154, kSentinel}}, {{8055, 8155, kSentinel}}, {{8056, 8184, kSentinel}}, // NOLINT
+ {{8057, 8185, kSentinel}}, {{8058, 8170, kSentinel}}, {{8059, 8171, kSentinel}}, {{8060, 8186, kSentinel}}, // NOLINT
+ {{8061, 8187, kSentinel}}, {{8112, 8120, kSentinel}}, {{8113, 8121, kSentinel}}, {{8144, 8152, kSentinel}}, // NOLINT
+ {{8145, 8153, kSentinel}}, {{8160, 8168, kSentinel}}, {{8161, 8169, kSentinel}}, {{8165, 8172, kSentinel}}, // NOLINT
+ {{kSentinel}} }; // NOLINT
static const uint16_t kEcma262UnCanonicalizeTable0Size = 945; // NOLINT
static const int32_t kEcma262UnCanonicalizeTable0[1890] = {
1073741889, 1, 90, 5, 1073741921, 1, 122, 5, 181, 9, 1073742016, 13, 214, 17, 1073742040, 21, // NOLINT
@@ -1453,7 +1455,7 @@
{{11468, 11469}}, {{11470, 11471}}, {{11472, 11473}}, {{11474, 11475}}, // NOLINT
{{11476, 11477}}, {{11478, 11479}}, {{11480, 11481}}, {{11482, 11483}}, // NOLINT
{{11484, 11485}}, {{11486, 11487}}, {{11488, 11489}}, {{11490, 11491}}, // NOLINT
- {{4256, 11520}}, {{4293, 11557}}, {{-1}} }; // NOLINT
+ {{4256, 11520}}, {{4293, 11557}}, {{kSentinel}} }; // NOLINT
static const uint16_t kEcma262UnCanonicalizeTable1Size = 133; // NOLINT
static const int32_t kEcma262UnCanonicalizeTable1[266] = {
306, 1, 334, 1, 1073742176, 5, 367, 9, 1073742192, 5, 383, 9, 387, 13, 388, 13, // NOLINT
@@ -1475,7 +1477,7 @@
3297, 265, 3298, 269, 3299, 269, 1073745152, 273, 3365, 277 }; // NOLINT
static const uint16_t kEcma262UnCanonicalizeMultiStrings1Size = 71; // NOLINT
static const MultiCharacterSpecialCase<2> kEcma262UnCanonicalizeMultiStrings7[3] = { // NOLINT
- {{65313, 65345}}, {{65338, 65370}}, {{-1}} }; // NOLINT
+ {{65313, 65345}}, {{65338, 65370}}, {{kSentinel}} }; // NOLINT
static const uint16_t kEcma262UnCanonicalizeTable7Size = 4; // NOLINT
static const int32_t kEcma262UnCanonicalizeTable7[8] = {
1073749793, 1, 7994, 5, 1073749825, 1, 8026, 5 }; // NOLINT
@@ -1512,7 +1514,7 @@
}
static const MultiCharacterSpecialCase<1> kCanonicalizationRangeMultiStrings0[1] = { // NOLINT
- {{-1}} }; // NOLINT
+ {{kSentinel}} }; // NOLINT
static const uint16_t kCanonicalizationRangeTable0Size = 70; // NOLINT
static const int32_t kCanonicalizationRangeTable0[140] = {
1073741889, 100, 90, 0, 1073741921, 100, 122, 0, 1073742016, 88, 214, 0, 1073742040, 24, 222, 0, // NOLINT
@@ -1526,14 +1528,14 @@
1073749864, 28, 8047, 0, 1073749874, 12, 8053, 0, 1073749960, 12, 8139, 0 }; // NOLINT
static const uint16_t kCanonicalizationRangeMultiStrings0Size = 1; // NOLINT
static const MultiCharacterSpecialCase<1> kCanonicalizationRangeMultiStrings1[1] = { // NOLINT
- {{-1}} }; // NOLINT
+ {{kSentinel}} }; // NOLINT
static const uint16_t kCanonicalizationRangeTable1Size = 14; // NOLINT
static const int32_t kCanonicalizationRangeTable1[28] = {
1073742176, 60, 367, 0, 1073742192, 60, 383, 0, 1073743030, 100, 1231, 0, 1073743056, 100, 1257, 0, // NOLINT
1073744896, 184, 3118, 0, 1073744944, 184, 3166, 0, 1073745152, 148, 3365, 0 }; // NOLINT
static const uint16_t kCanonicalizationRangeMultiStrings1Size = 1; // NOLINT
static const MultiCharacterSpecialCase<1> kCanonicalizationRangeMultiStrings7[1] = { // NOLINT
- {{-1}} }; // NOLINT
+ {{kSentinel}} }; // NOLINT
static const uint16_t kCanonicalizationRangeTable7Size = 4; // NOLINT
static const int32_t kCanonicalizationRangeTable7[8] = {
1073749793, 100, 7994, 0, 1073749825, 100, 8026, 0 }; // NOLINT
diff --git a/src/v8threads.cc b/src/v8threads.cc
index b6e656d..8a5fe69 100644
--- a/src/v8threads.cc
+++ b/src/v8threads.cc
@@ -380,7 +380,8 @@
ContextSwitcher::ContextSwitcher(int every_n_ms)
- : keep_going_(true),
+ : Thread("v8:CtxtSwitcher"),
+ keep_going_(true),
sleep_ms_(every_n_ms) {
}
diff --git a/src/version.cc b/src/version.cc
index e362148..c434e34 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,7 +34,7 @@
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 3
#define MINOR_VERSION 0
-#define BUILD_NUMBER 5
+#define BUILD_NUMBER 6
#define PATCH_LEVEL 0
#define CANDIDATE_VERSION false
diff --git a/src/x64/assembler-x64.cc b/src/x64/assembler-x64.cc
index 8f15f23..3629967 100644
--- a/src/x64/assembler-x64.cc
+++ b/src/x64/assembler-x64.cc
@@ -74,7 +74,7 @@
__ xor_(rax, rdx); // Different if CPUID is supported.
__ j(not_zero, &cpuid);
- // CPUID not supported. Clear the supported features in edx:eax.
+ // CPUID not supported. Clear the supported features in rax.
__ xor_(rax, rax);
__ jmp(&done);
diff --git a/src/x64/assembler-x64.h b/src/x64/assembler-x64.h
index fde88df..7bcc7c5 100644
--- a/src/x64/assembler-x64.h
+++ b/src/x64/assembler-x64.h
@@ -536,6 +536,8 @@
// The debug break slot must be able to contain a call instruction.
static const int kDebugBreakSlotLength = kCallInstructionLength;
+ // One byte opcode for test eax,0xXXXXXXXX.
+ static const byte kTestEaxByte = 0xA9;
// ---------------------------------------------------------------------------
// Code generation
diff --git a/src/x64/builtins-x64.cc b/src/x64/builtins-x64.cc
index 456d076..d738261 100644
--- a/src/x64/builtins-x64.cc
+++ b/src/x64/builtins-x64.cc
@@ -422,7 +422,7 @@
// [rsp+0x20] : argv
// Clear the context before we push it when entering the JS frame.
- __ xor_(rsi, rsi);
+ __ Set(rsi, 0);
__ EnterInternalFrame();
// Load the function context into rsi.
@@ -451,7 +451,7 @@
// rdi : function
// Clear the context before we push it when entering the JS frame.
- __ xor_(rsi, rsi);
+ __ Set(rsi, 0);
// Enter an internal frame.
__ EnterInternalFrame();
@@ -479,7 +479,7 @@
// Register rbx points to array of pointers to handle locations.
// Push the values of these handles.
Label loop, entry;
- __ xor_(rcx, rcx); // Set loop variable to 0.
+ __ Set(rcx, 0); // Set loop variable to 0.
__ jmp(&entry);
__ bind(&loop);
__ movq(kScratchRegister, Operand(rbx, rcx, times_pointer_size, 0));
@@ -668,7 +668,7 @@
// become the receiver.
__ bind(&non_function);
__ movq(Operand(rsp, rax, times_pointer_size, 0), rdi);
- __ xor_(rdi, rdi);
+ __ Set(rdi, 0);
// 4. Shift arguments and return address one slot down on the stack
// (overwriting the original receiver). Adjust argument count to make
@@ -689,7 +689,7 @@
{ Label function;
__ testq(rdi, rdi);
__ j(not_zero, &function);
- __ xor_(rbx, rbx);
+ __ Set(rbx, 0);
__ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION);
__ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
RelocInfo::CODE_TARGET);
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index c3eb5bf..60ec35d 100644
--- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc
@@ -104,7 +104,7 @@
__ Move(FieldOperand(rax, FixedArray::kLengthOffset), Smi::FromInt(length));
// Setup the fixed slots.
- __ xor_(rbx, rbx); // Set to NULL.
+ __ Set(rbx, 0); // Set to NULL.
__ movq(Operand(rax, Context::SlotOffset(Context::CLOSURE_INDEX)), rcx);
__ movq(Operand(rax, Context::SlotOffset(Context::FCONTEXT_INDEX)), rax);
__ movq(Operand(rax, Context::SlotOffset(Context::PREVIOUS_INDEX)), rbx);
@@ -250,7 +250,7 @@
__ movq(rax, Immediate(1));
__ ret(1 * kPointerSize);
__ bind(&false_result);
- __ xor_(rax, rax);
+ __ Set(rax, 0);
__ ret(1 * kPointerSize);
}
@@ -2572,7 +2572,7 @@
// Before returning we restore the context from the frame pointer if not NULL.
// The frame pointer is NULL in the exception handler of a JS entry frame.
- __ xor_(rsi, rsi); // tentatively set context pointer to NULL
+ __ Set(rsi, 0); // Tentatively set context pointer to NULL
NearLabel skip;
__ cmpq(rbp, Immediate(0));
__ j(equal, &skip);
@@ -2756,7 +2756,7 @@
}
// Clear the context pointer.
- __ xor_(rsi, rsi);
+ __ Set(rsi, 0);
// Restore registers from handler.
STATIC_ASSERT(StackHandlerConstants::kNextOffset + kPointerSize ==
diff --git a/src/x64/code-stubs-x64.h b/src/x64/code-stubs-x64.h
index eb7ad26..0fe4f8a 100644
--- a/src/x64/code-stubs-x64.h
+++ b/src/x64/code-stubs-x64.h
@@ -87,7 +87,7 @@
ASSERT(OpBits::is_valid(Token::NUM_TOKENS));
}
- GenericBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info)
+ GenericBinaryOpStub(int key, BinaryOpIC::TypeInfo runtime_operands_type)
: op_(OpBits::decode(key)),
mode_(ModeBits::decode(key)),
flags_(FlagBits::decode(key)),
@@ -95,7 +95,7 @@
args_reversed_(ArgsReversedBits::decode(key)),
static_operands_type_(TypeInfo::ExpandedRepresentation(
StaticTypeInfoBits::decode(key))),
- runtime_operands_type_(type_info),
+ runtime_operands_type_(runtime_operands_type),
name_(NULL) {
}
@@ -348,42 +348,6 @@
};
-class RecordWriteStub : public CodeStub {
- public:
- RecordWriteStub(Register object, Register addr, Register scratch)
- : object_(object), addr_(addr), scratch_(scratch) { }
-
- void Generate(MacroAssembler* masm);
-
- private:
- Register object_;
- Register addr_;
- Register scratch_;
-
-#ifdef DEBUG
- void Print() {
- PrintF("RecordWriteStub (object reg %d), (addr reg %d), (scratch reg %d)\n",
- object_.code(), addr_.code(), scratch_.code());
- }
-#endif
-
- // Minor key encoding in 12 bits. 4 bits for each of the three
- // registers (object, address and scratch) OOOOAAAASSSS.
- class ScratchBits : public BitField<uint32_t, 0, 4> {};
- class AddressBits : public BitField<uint32_t, 4, 4> {};
- class ObjectBits : public BitField<uint32_t, 8, 4> {};
-
- Major MajorKey() { return RecordWrite; }
-
- int MinorKey() {
- // Encode the registers.
- return ObjectBits::encode(object_.code()) |
- AddressBits::encode(addr_.code()) |
- ScratchBits::encode(scratch_.code());
- }
-};
-
-
} } // namespace v8::internal
#endif // V8_X64_CODE_STUBS_X64_H_
diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc
index 9a25572..aa5d335 100644
--- a/src/x64/codegen-x64.cc
+++ b/src/x64/codegen-x64.cc
@@ -6813,12 +6813,8 @@
// (or them and test against Smi mask.)
__ movq(tmp2.reg(), tmp1.reg());
- RecordWriteStub recordWrite1(tmp2.reg(), index1.reg(), object.reg());
- __ CallStub(&recordWrite1);
-
- RecordWriteStub recordWrite2(tmp1.reg(), index2.reg(), object.reg());
- __ CallStub(&recordWrite2);
-
+ __ RecordWriteHelper(tmp1.reg(), index1.reg(), object.reg());
+ __ RecordWriteHelper(tmp2.reg(), index2.reg(), object.reg());
__ bind(&done);
deferred->BindExit();
@@ -8812,11 +8808,6 @@
#undef __
-void RecordWriteStub::Generate(MacroAssembler* masm) {
- masm->RecordWriteHelper(object_, addr_, scratch_);
- masm->ret(0);
-}
-
} } // namespace v8::internal
#endif // V8_TARGET_ARCH_X64
diff --git a/src/x64/debug-x64.cc b/src/x64/debug-x64.cc
index 2c1056f..4218647 100644
--- a/src/x64/debug-x64.cc
+++ b/src/x64/debug-x64.cc
@@ -25,7 +25,6 @@
// (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 "v8.h"
#if defined(V8_TARGET_ARCH_X64)
@@ -39,13 +38,61 @@
#ifdef ENABLE_DEBUGGER_SUPPORT
+bool BreakLocationIterator::IsDebugBreakAtReturn() {
+ return Debug::IsDebugBreakAtReturn(rinfo());
+}
+
+
+// Patch the JS frame exit code with a debug break call. See
+// CodeGenerator::VisitReturnStatement and VirtualFrame::Exit in codegen-x64.cc
+// for the precise return instructions sequence.
+void BreakLocationIterator::SetDebugBreakAtReturn() {
+ ASSERT(Assembler::kJSReturnSequenceLength >=
+ Assembler::kCallInstructionLength);
+ rinfo()->PatchCodeWithCall(Debug::debug_break_return()->entry(),
+ Assembler::kJSReturnSequenceLength - Assembler::kCallInstructionLength);
+}
+
+
+// Restore the JS frame exit code.
+void BreakLocationIterator::ClearDebugBreakAtReturn() {
+ rinfo()->PatchCode(original_rinfo()->pc(),
+ Assembler::kJSReturnSequenceLength);
+}
+
+
+// A debug break in the frame exit code is identified by the JS frame exit code
+// having been patched with a call instruction.
bool Debug::IsDebugBreakAtReturn(v8::internal::RelocInfo* rinfo) {
ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()));
return rinfo->IsPatchedReturnSequence();
}
+
+bool BreakLocationIterator::IsDebugBreakAtSlot() {
+ ASSERT(IsDebugBreakSlot());
+ // Check whether the debug break slot instructions have been patched.
+ return !Assembler::IsNop(rinfo()->pc());
+}
+
+
+void BreakLocationIterator::SetDebugBreakAtSlot() {
+ ASSERT(IsDebugBreakSlot());
+ rinfo()->PatchCodeWithCall(
+ Debug::debug_break_slot()->entry(),
+ Assembler::kDebugBreakSlotLength - Assembler::kCallInstructionLength);
+}
+
+
+void BreakLocationIterator::ClearDebugBreakAtSlot() {
+ ASSERT(IsDebugBreakSlot());
+ rinfo()->PatchCode(original_rinfo()->pc(), Assembler::kDebugBreakSlotLength);
+}
+
+
#define __ ACCESS_MASM(masm)
+
static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
RegList object_regs,
RegList non_object_regs,
@@ -55,7 +102,7 @@
// Store the registers containing live values on the expression stack to
// make sure that these are correctly updated during GC. Non object values
- // are stored as as two smi causing it to be untouched by GC.
+ // are stored as as two smis causing it to be untouched by GC.
ASSERT((object_regs & ~kJSCallerSaved) == 0);
ASSERT((non_object_regs & ~kJSCallerSaved) == 0);
ASSERT((object_regs & non_object_regs) == 0);
@@ -80,7 +127,7 @@
#ifdef DEBUG
__ RecordComment("// Calling from debug break to runtime - come in - over");
#endif
- __ xor_(rax, rax); // No arguments (argc == 0).
+ __ Set(rax, 0); // No arguments (argc == 0).
__ movq(rbx, ExternalReference::debug_break());
CEntryStub ceb(1);
@@ -126,24 +173,25 @@
}
-void Debug::GenerateCallICDebugBreak(MacroAssembler* masm) {
- // Register state for IC call call (from ic-x64.cc)
+void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) {
+ // Register state for IC load call (from ic-x64.cc).
// ----------- S t a t e -------------
- // -- rcx: function name
+ // -- rax : receiver
+ // -- rcx : name
// -----------------------------------
- Generate_DebugBreakCallHelper(masm, rcx.bit(), 0, false);
+ Generate_DebugBreakCallHelper(masm, rax.bit() | rcx.bit(), 0, false);
}
-void Debug::GenerateConstructCallDebugBreak(MacroAssembler* masm) {
- // Register state just before return from JS function (from codegen-x64.cc).
- // rax is the actual number of arguments not encoded as a smi, see comment
- // above IC call.
+void Debug::GenerateStoreICDebugBreak(MacroAssembler* masm) {
+ // Register state for IC store call (from ic-x64.cc).
// ----------- S t a t e -------------
- // -- rax: number of arguments
+ // -- rax : value
+ // -- rcx : name
+ // -- rdx : receiver
// -----------------------------------
- // The number of arguments in rax is not smi encoded.
- Generate_DebugBreakCallHelper(masm, rdi.bit(), rax.bit(), false);
+ Generate_DebugBreakCallHelper(
+ masm, rax.bit() | rcx.bit() | rdx.bit(), 0, false);
}
@@ -169,13 +217,24 @@
}
-void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) {
- // Register state for IC load call (from ic-x64.cc).
+void Debug::GenerateCallICDebugBreak(MacroAssembler* masm) {
+ // Register state for IC call call (from ic-x64.cc)
// ----------- S t a t e -------------
- // -- rax : receiver
- // -- rcx : name
+ // -- rcx: function name
// -----------------------------------
- Generate_DebugBreakCallHelper(masm, rax.bit() | rcx.bit(), 0, false);
+ Generate_DebugBreakCallHelper(masm, rcx.bit(), 0, false);
+}
+
+
+void Debug::GenerateConstructCallDebugBreak(MacroAssembler* masm) {
+ // Register state just before return from JS function (from codegen-x64.cc).
+ // rax is the actual number of arguments not encoded as a smi, see comment
+ // above IC call.
+ // ----------- S t a t e -------------
+ // -- rax: number of arguments
+ // -----------------------------------
+ // The number of arguments in rax is not smi encoded.
+ Generate_DebugBreakCallHelper(masm, rdi.bit(), rax.bit(), false);
}
@@ -188,18 +247,6 @@
}
-void Debug::GenerateStoreICDebugBreak(MacroAssembler* masm) {
- // Register state for IC store call (from ic-x64.cc).
- // ----------- S t a t e -------------
- // -- rax : value
- // -- rcx : name
- // -- rdx : receiver
- // -----------------------------------
- Generate_DebugBreakCallHelper(
- masm, rax.bit() | rcx.bit() | rdx.bit(), 0, false);
-}
-
-
void Debug::GenerateStubNoRegistersDebugBreak(MacroAssembler* masm) {
// Register state for stub CallFunction (from CallFunctionStub in ic-x64.cc).
// ----------- S t a t e -------------
@@ -262,49 +309,6 @@
#undef __
-
-
-
-void BreakLocationIterator::ClearDebugBreakAtReturn() {
- rinfo()->PatchCode(original_rinfo()->pc(),
- Assembler::kJSReturnSequenceLength);
-}
-
-
-bool BreakLocationIterator::IsDebugBreakAtReturn() {
- return Debug::IsDebugBreakAtReturn(rinfo());
-}
-
-
-void BreakLocationIterator::SetDebugBreakAtReturn() {
- ASSERT(Assembler::kJSReturnSequenceLength >=
- Assembler::kCallInstructionLength);
- rinfo()->PatchCodeWithCall(Debug::debug_break_return()->entry(),
- Assembler::kJSReturnSequenceLength - Assembler::kCallInstructionLength);
-}
-
-
-bool BreakLocationIterator::IsDebugBreakAtSlot() {
- ASSERT(IsDebugBreakSlot());
- // Check whether the debug break slot instructions have been patched.
- return !Assembler::IsNop(rinfo()->pc());
-}
-
-
-void BreakLocationIterator::SetDebugBreakAtSlot() {
- ASSERT(IsDebugBreakSlot());
- rinfo()->PatchCodeWithCall(
- Debug::debug_break_slot()->entry(),
- Assembler::kDebugBreakSlotLength - Assembler::kCallInstructionLength);
-}
-
-
-void BreakLocationIterator::ClearDebugBreakAtSlot() {
- ASSERT(IsDebugBreakSlot());
- rinfo()->PatchCode(original_rinfo()->pc(), Assembler::kDebugBreakSlotLength);
-}
-
-
#endif // ENABLE_DEBUGGER_SUPPORT
} } // namespace v8::internal
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index dd28d4d..66bc4ed 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -199,7 +199,7 @@
void FullCodeGenerator::ClearAccumulator() {
- __ xor_(rax, rax);
+ __ Set(rax, 0);
}
diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc
index aff778a..29cbed0 100644
--- a/src/x64/ic-x64.cc
+++ b/src/x64/ic-x64.cc
@@ -378,81 +378,50 @@
}
-// One byte opcode for test rax,0xXXXXXXXX.
-static const byte kTestEaxByte = 0xA9;
+// The offset from the inlined patch site to the start of the inlined
+// load instruction.
+const int LoadIC::kOffsetToLoadInstruction = 20;
-static bool PatchInlinedMapCheck(Address address, Object* map) {
- if (V8::UseCrankshaft()) return false;
-
- // Arguments are address of start of call sequence that called
- // the IC,
- Address test_instruction_address =
- address + Assembler::kCallTargetAddressOffset;
- // The keyed load has a fast inlined case if the IC call instruction
- // is immediately followed by a test instruction.
- if (*test_instruction_address != kTestEaxByte) return false;
-
- // Fetch the offset from the test instruction to the map compare
- // instructions (starting with the 64-bit immediate mov of the map
- // address). This offset is stored in the last 4 bytes of the 5
- // byte test instruction.
- Address delta_address = test_instruction_address + 1;
- int delta = *reinterpret_cast<int*>(delta_address);
- // Compute the map address. The map address is in the last 8 bytes
- // of the 10-byte immediate mov instruction (incl. REX prefix), so we add 2
- // to the offset to get the map address.
- Address map_address = test_instruction_address + delta + 2;
- // Patch the map check.
- *(reinterpret_cast<Object**>(map_address)) = map;
- return true;
-}
-
-
-bool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) {
- return PatchInlinedMapCheck(address, map);
-}
-
-
-bool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) {
- return PatchInlinedMapCheck(address, map);
-}
-
-
-void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
+void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
// ----------- S t a t e -------------
- // -- rax : key
- // -- rdx : receiver
- // -- rsp[0] : return address
+ // -- rax : receiver
+ // -- rcx : name
+ // -- rsp[0] : return address
// -----------------------------------
+ Label miss;
- __ IncrementCounter(&Counters::keyed_load_miss, 1);
-
- __ pop(rbx);
- __ push(rdx); // receiver
- __ push(rax); // name
- __ push(rbx); // return address
-
- // Perform tail call to the entry.
- ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss));
- __ TailCallExternalReference(ref, 2, 1);
+ StubCompiler::GenerateLoadArrayLength(masm, rax, rdx, &miss);
+ __ bind(&miss);
+ StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
}
-void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
+void LoadIC::GenerateStringLength(MacroAssembler* masm) {
// ----------- S t a t e -------------
- // -- rax : key
- // -- rdx : receiver
- // -- rsp[0] : return address
+ // -- rax : receiver
+ // -- rcx : name
+ // -- rsp[0] : return address
// -----------------------------------
+ Label miss;
- __ pop(rbx);
- __ push(rdx); // receiver
- __ push(rax); // name
- __ push(rbx); // return address
+ StubCompiler::GenerateLoadStringLength(masm, rax, rdx, rbx, &miss);
+ __ bind(&miss);
+ StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
+}
- // Perform tail call to the entry.
- __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
+
+void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- rax : receiver
+ // -- rcx : name
+ // -- rsp[0] : return address
+ // -----------------------------------
+ Label miss;
+
+ StubCompiler::GenerateLoadFunctionPrototype(masm, rax, rdx, rbx, &miss);
+ __ bind(&miss);
+ StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
}
@@ -923,45 +892,6 @@
}
-void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- rax : value
- // -- rcx : key
- // -- rdx : receiver
- // -- rsp[0] : return address
- // -----------------------------------
-
- __ pop(rbx);
- __ push(rdx); // receiver
- __ push(rcx); // key
- __ push(rax); // value
- __ push(rbx); // return address
-
- // Do tail-call to runtime routine.
- ExternalReference ref = ExternalReference(IC_Utility(kKeyedStoreIC_Miss));
- __ TailCallExternalReference(ref, 3, 1);
-}
-
-
-void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- rax : value
- // -- rcx : key
- // -- rdx : receiver
- // -- rsp[0] : return address
- // -----------------------------------
-
- __ pop(rbx);
- __ push(rdx); // receiver
- __ push(rcx); // key
- __ push(rax); // value
- __ push(rbx); // return address
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kSetProperty, 3, 1);
-}
-
-
void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax : value
@@ -1236,71 +1166,6 @@
}
-// Defined in ic.cc.
-Object* CallIC_Miss(Arguments args);
-
-
-static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) {
- // ----------- S t a t e -------------
- // rcx : function name
- // rsp[0] : return address
- // rsp[8] : argument argc
- // rsp[16] : argument argc - 1
- // ...
- // rsp[argc * 8] : argument 1
- // rsp[(argc + 1) * 8] : argument 0 = receiver
- // -----------------------------------
-
- if (id == IC::kCallIC_Miss) {
- __ IncrementCounter(&Counters::call_miss, 1);
- } else {
- __ IncrementCounter(&Counters::keyed_call_miss, 1);
- }
-
- // Get the receiver of the function from the stack; 1 ~ return address.
- __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
-
- // Enter an internal frame.
- __ EnterInternalFrame();
-
- // Push the receiver and the name of the function.
- __ push(rdx);
- __ push(rcx);
-
- // Call the entry.
- CEntryStub stub(1);
- __ movq(rax, Immediate(2));
- __ movq(rbx, ExternalReference(IC_Utility(id)));
- __ CallStub(&stub);
-
- // Move result to rdi and exit the internal frame.
- __ movq(rdi, rax);
- __ LeaveInternalFrame();
-
- // Check if the receiver is a global object of some sort.
- // This can happen only for regular CallIC but not KeyedCallIC.
- if (id == IC::kCallIC_Miss) {
- Label invoke, global;
- __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); // receiver
- __ JumpIfSmi(rdx, &invoke);
- __ CmpObjectType(rdx, JS_GLOBAL_OBJECT_TYPE, rcx);
- __ j(equal, &global);
- __ CmpInstanceType(rcx, JS_BUILTINS_OBJECT_TYPE);
- __ j(not_equal, &invoke);
-
- // Patch the receiver on the stack.
- __ bind(&global);
- __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
- __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
- __ bind(&invoke);
- }
-
- // Invoke the function.
- ParameterCount actual(argc);
- __ InvokeFunction(rdi, actual, JUMP_FUNCTION);
-}
-
-
// The generated code does not accept smi keys.
// The generated code falls through if both probes miss.
static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
@@ -1409,7 +1274,7 @@
}
-void CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
+static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) {
// ----------- S t a t e -------------
// rcx : function name
// rsp[0] : return address
@@ -1419,7 +1284,54 @@
// rsp[argc * 8] : argument 1
// rsp[(argc + 1) * 8] : argument 0 = receiver
// -----------------------------------
- GenerateCallMiss(masm, argc, IC::kCallIC_Miss);
+
+ if (id == IC::kCallIC_Miss) {
+ __ IncrementCounter(&Counters::call_miss, 1);
+ } else {
+ __ IncrementCounter(&Counters::keyed_call_miss, 1);
+ }
+
+ // Get the receiver of the function from the stack; 1 ~ return address.
+ __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
+
+ // Enter an internal frame.
+ __ EnterInternalFrame();
+
+ // Push the receiver and the name of the function.
+ __ push(rdx);
+ __ push(rcx);
+
+ // Call the entry.
+ CEntryStub stub(1);
+ __ movq(rax, Immediate(2));
+ __ movq(rbx, ExternalReference(IC_Utility(id)));
+ __ CallStub(&stub);
+
+ // Move result to rdi and exit the internal frame.
+ __ movq(rdi, rax);
+ __ LeaveInternalFrame();
+
+ // Check if the receiver is a global object of some sort.
+ // This can happen only for regular CallIC but not KeyedCallIC.
+ if (id == IC::kCallIC_Miss) {
+ Label invoke, global;
+ __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); // receiver
+ __ JumpIfSmi(rdx, &invoke);
+ __ CmpObjectType(rdx, JS_GLOBAL_OBJECT_TYPE, rcx);
+ __ j(equal, &global);
+ __ CmpInstanceType(rcx, JS_BUILTINS_OBJECT_TYPE);
+ __ j(not_equal, &invoke);
+
+ // Patch the receiver on the stack.
+ __ bind(&global);
+ __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
+ __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
+ __ bind(&invoke);
+ }
+
+ // Invoke the function.
+ ParameterCount actual(argc);
+ __ InvokeFunction(rdi, actual, JUMP_FUNCTION);
}
@@ -1457,7 +1369,7 @@
}
-void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) {
+void CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
// ----------- S t a t e -------------
// rcx : function name
// rsp[0] : return address
@@ -1468,7 +1380,7 @@
// rsp[(argc + 1) * 8] : argument 0 = receiver
// -----------------------------------
- GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss);
+ GenerateCallMiss(masm, argc, IC::kCallIC_Miss);
}
@@ -1594,56 +1506,18 @@
}
-// The offset from the inlined patch site to the start of the inlined
-// load instruction.
-const int LoadIC::kOffsetToLoadInstruction = 20;
-
-
-void LoadIC::GenerateMiss(MacroAssembler* masm) {
+void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) {
// ----------- S t a t e -------------
- // -- rax : receiver
- // -- rcx : name
- // -- rsp[0] : return address
+ // rcx : function name
+ // rsp[0] : return address
+ // rsp[8] : argument argc
+ // rsp[16] : argument argc - 1
+ // ...
+ // rsp[argc * 8] : argument 1
+ // rsp[(argc + 1) * 8] : argument 0 = receiver
// -----------------------------------
- __ IncrementCounter(&Counters::load_miss, 1);
-
- __ pop(rbx);
- __ push(rax); // receiver
- __ push(rcx); // name
- __ push(rbx); // return address
-
- // Perform tail call to the entry.
- ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss));
- __ TailCallExternalReference(ref, 2, 1);
-}
-
-
-void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- rax : receiver
- // -- rcx : name
- // -- rsp[0] : return address
- // -----------------------------------
- Label miss;
-
- StubCompiler::GenerateLoadArrayLength(masm, rax, rdx, &miss);
- __ bind(&miss);
- StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
-}
-
-
-void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- rax : receiver
- // -- rcx : name
- // -- rsp[0] : return address
- // -----------------------------------
- Label miss;
-
- StubCompiler::GenerateLoadFunctionPrototype(masm, rax, rdx, rbx, &miss);
- __ bind(&miss);
- StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
+ GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss);
}
@@ -1686,17 +1560,23 @@
}
-void LoadIC::GenerateStringLength(MacroAssembler* masm) {
+void LoadIC::GenerateMiss(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax : receiver
// -- rcx : name
// -- rsp[0] : return address
// -----------------------------------
- Label miss;
- StubCompiler::GenerateLoadStringLength(masm, rax, rdx, rbx, &miss);
- __ bind(&miss);
- StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
+ __ IncrementCounter(&Counters::load_miss, 1);
+
+ __ pop(rbx);
+ __ push(rax); // receiver
+ __ push(rcx); // name
+ __ push(rbx); // return address
+
+ // Perform tail call to the entry.
+ ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss));
+ __ TailCallExternalReference(ref, 2, 1);
}
@@ -1708,7 +1588,7 @@
address + Assembler::kCallTargetAddressOffset;
// If the instruction following the call is not a test rax, nothing
// was inlined.
- if (*test_instruction_address != kTestEaxByte) return false;
+ if (*test_instruction_address != Assembler::kTestEaxByte) return false;
Address delta_address = test_instruction_address + 1;
// The delta to the start of the map check instruction.
@@ -1739,11 +1619,6 @@
}
-// The offset from the inlined patch site to the start of the inlined
-// store instruction.
-const int StoreIC::kOffsetToStoreInstruction = 20;
-
-
bool StoreIC::PatchInlinedStore(Address address, Object* map, int offset) {
if (V8::UseCrankshaft()) return false;
@@ -1753,7 +1628,7 @@
// If the instruction following the call is not a test rax, nothing
// was inlined.
- if (*test_instruction_address != kTestEaxByte) return false;
+ if (*test_instruction_address != Assembler::kTestEaxByte) return false;
// Extract the encoded deltas from the test rax instruction.
Address encoded_offsets_address = test_instruction_address + 1;
@@ -1792,23 +1667,77 @@
}
-void StoreIC::GenerateMiss(MacroAssembler* masm) {
+static bool PatchInlinedMapCheck(Address address, Object* map) {
+ if (V8::UseCrankshaft()) return false;
+
+ // Arguments are address of start of call sequence that called
+ // the IC,
+ Address test_instruction_address =
+ address + Assembler::kCallTargetAddressOffset;
+ // The keyed load has a fast inlined case if the IC call instruction
+ // is immediately followed by a test instruction.
+ if (*test_instruction_address != Assembler::kTestEaxByte) return false;
+
+ // Fetch the offset from the test instruction to the map compare
+ // instructions (starting with the 64-bit immediate mov of the map
+ // address). This offset is stored in the last 4 bytes of the 5
+ // byte test instruction.
+ Address delta_address = test_instruction_address + 1;
+ int delta = *reinterpret_cast<int*>(delta_address);
+ // Compute the map address. The map address is in the last 8 bytes
+ // of the 10-byte immediate mov instruction (incl. REX prefix), so we add 2
+ // to the offset to get the map address.
+ Address map_address = test_instruction_address + delta + 2;
+ // Patch the map check.
+ *(reinterpret_cast<Object**>(map_address)) = map;
+ return true;
+}
+
+
+bool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) {
+ return PatchInlinedMapCheck(address, map);
+}
+
+
+bool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) {
+ return PatchInlinedMapCheck(address, map);
+}
+
+
+void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
// ----------- S t a t e -------------
- // -- rax : value
- // -- rcx : name
+ // -- rax : key
// -- rdx : receiver
- // -- rsp[0] : return address
+ // -- rsp[0] : return address
+ // -----------------------------------
+
+ __ IncrementCounter(&Counters::keyed_load_miss, 1);
+
+ __ pop(rbx);
+ __ push(rdx); // receiver
+ __ push(rax); // name
+ __ push(rbx); // return address
+
+ // Perform tail call to the entry.
+ ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss));
+ __ TailCallExternalReference(ref, 2, 1);
+}
+
+
+void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- rax : key
+ // -- rdx : receiver
+ // -- rsp[0] : return address
// -----------------------------------
__ pop(rbx);
__ push(rdx); // receiver
- __ push(rcx); // name
- __ push(rax); // value
+ __ push(rax); // name
__ push(rbx); // return address
// Perform tail call to the entry.
- ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_Miss));
- __ TailCallExternalReference(ref, 3, 1);
+ __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
}
@@ -1831,6 +1760,31 @@
}
+void StoreIC::GenerateMiss(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- rax : value
+ // -- rcx : name
+ // -- rdx : receiver
+ // -- rsp[0] : return address
+ // -----------------------------------
+
+ __ pop(rbx);
+ __ push(rdx); // receiver
+ __ push(rcx); // name
+ __ push(rax); // value
+ __ push(rbx); // return address
+
+ // Perform tail call to the entry.
+ ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_Miss));
+ __ TailCallExternalReference(ref, 3, 1);
+}
+
+
+// The offset from the inlined patch site to the start of the inlined
+// store instruction.
+const int StoreIC::kOffsetToStoreInstruction = 20;
+
+
void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax : value
@@ -1923,6 +1877,45 @@
}
+void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- rax : value
+ // -- rcx : key
+ // -- rdx : receiver
+ // -- rsp[0] : return address
+ // -----------------------------------
+
+ __ pop(rbx);
+ __ push(rdx); // receiver
+ __ push(rcx); // key
+ __ push(rax); // value
+ __ push(rbx); // return address
+
+ // Do tail-call to runtime routine.
+ __ TailCallRuntime(Runtime::kSetProperty, 3, 1);
+}
+
+
+void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- rax : value
+ // -- rcx : key
+ // -- rdx : receiver
+ // -- rsp[0] : return address
+ // -----------------------------------
+
+ __ pop(rbx);
+ __ push(rdx); // receiver
+ __ push(rcx); // key
+ __ push(rax); // value
+ __ push(rbx); // return address
+
+ // Do tail-call to runtime routine.
+ ExternalReference ref = ExternalReference(IC_Utility(kKeyedStoreIC_Miss));
+ __ TailCallExternalReference(ref, 3, 1);
+}
+
+
#undef __
@@ -1976,6 +1969,7 @@
UNIMPLEMENTED();
}
+
} } // namespace v8::internal
#endif // V8_TARGET_ARCH_X64
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc
index 1df9b47..70a3dab 100644
--- a/src/x64/macro-assembler-x64.cc
+++ b/src/x64/macro-assembler-x64.cc
@@ -1110,7 +1110,7 @@
void MacroAssembler::SmiAndConstant(Register dst, Register src, Smi* constant) {
if (constant->value() == 0) {
- xor_(dst, dst);
+ Set(dst, 0);
} else if (dst.is(src)) {
ASSERT(!dst.is(kScratchRegister));
Register constant_reg = GetSmiConstant(constant);
@@ -1605,7 +1605,7 @@
#ifdef ENABLE_DEBUGGER_SUPPORT
void MacroAssembler::DebugBreak() {
ASSERT(allow_stub_calls());
- xor_(rax, rax); // no arguments
+ Set(rax, 0); // No arguments.
movq(rbx, ExternalReference(Runtime::kDebugBreak));
CEntryStub ces(1);
Call(ces.GetCode(), RelocInfo::DEBUG_BREAK);
diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h
index d8f2fba..30b9ba5 100644
--- a/src/x64/macro-assembler-x64.h
+++ b/src/x64/macro-assembler-x64.h
@@ -1176,7 +1176,7 @@
jmp(on_not_smi_result);
bind(&zero_correct_result);
- xor_(dst, dst);
+ Set(dst, 0);
bind(&correct_result);
} else {
diff --git a/src/x64/regexp-macro-assembler-x64.cc b/src/x64/regexp-macro-assembler-x64.cc
index 0838ddd..27f3482 100644
--- a/src/x64/regexp-macro-assembler-x64.cc
+++ b/src/x64/regexp-macro-assembler-x64.cc
@@ -688,7 +688,7 @@
void RegExpMacroAssemblerX64::Fail() {
ASSERT(FAILURE == 0); // Return value for failure is zero.
- __ xor_(rax, rax); // zero rax.
+ __ Set(rax, 0);
__ jmp(&exit_label_);
}
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
index 63e9769..57cba14 100644
--- a/src/x64/stub-cache-x64.cc
+++ b/src/x64/stub-cache-x64.cc
@@ -25,23 +25,17 @@
// (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 "v8.h"
#if defined(V8_TARGET_ARCH_X64)
#include "ic-inl.h"
-#include "code-stubs.h"
#include "codegen-inl.h"
#include "stub-cache.h"
-#include "macro-assembler.h"
namespace v8 {
namespace internal {
-//-----------------------------------------------------------------------------
-// StubCompiler static helper functions
-
#define __ ACCESS_MASM(masm)
@@ -182,92 +176,6 @@
}
-void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
- ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
- Code* code = NULL;
- if (kind == Code::LOAD_IC) {
- code = Builtins::builtin(Builtins::LoadIC_Miss);
- } else {
- code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
- }
-
- Handle<Code> ic(code);
- __ Jump(ic, RelocInfo::CODE_TARGET);
-}
-
-
-void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
- int index,
- Register prototype) {
- // Load the global or builtins object from the current context.
- __ movq(prototype,
- Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
- // Load the global context from the global or builtins object.
- __ movq(prototype,
- FieldOperand(prototype, GlobalObject::kGlobalContextOffset));
- // Load the function from the global context.
- __ movq(prototype, Operand(prototype, Context::SlotOffset(index)));
- // Load the initial map. The global functions all have initial maps.
- __ movq(prototype,
- FieldOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
- // Load the prototype from the initial map.
- __ movq(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
-}
-
-
-void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
- MacroAssembler* masm, int index, Register prototype, Label* miss) {
- // Check we're still in the same context.
- __ Move(prototype, Top::global());
- __ cmpq(Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)),
- prototype);
- __ j(not_equal, miss);
- // Get the global function with the given index.
- JSFunction* function = JSFunction::cast(Top::global_context()->get(index));
- // Load its initial map. The global functions all have initial maps.
- __ Move(prototype, Handle<Map>(function->initial_map()));
- // Load the prototype from the initial map.
- __ movq(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
-}
-
-
-// Load a fast property out of a holder object (src). In-object properties
-// are loaded directly otherwise the property is loaded from the properties
-// fixed array.
-void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
- Register dst, Register src,
- JSObject* holder, int index) {
- // Adjust for the number of properties stored in the holder.
- index -= holder->map()->inobject_properties();
- if (index < 0) {
- // Get the property straight out of the holder.
- int offset = holder->map()->instance_size() + (index * kPointerSize);
- __ movq(dst, FieldOperand(src, offset));
- } else {
- // Calculate the offset into the properties array.
- int offset = index * kPointerSize + FixedArray::kHeaderSize;
- __ movq(dst, FieldOperand(src, JSObject::kPropertiesOffset));
- __ movq(dst, FieldOperand(dst, offset));
- }
-}
-
-
-static void PushInterceptorArguments(MacroAssembler* masm,
- Register receiver,
- Register holder,
- Register name,
- JSObject* holder_obj) {
- __ push(name);
- InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
- ASSERT(!Heap::InNewSpace(interceptor));
- __ Move(kScratchRegister, Handle<Object>(interceptor));
- __ push(kScratchRegister);
- __ push(receiver);
- __ push(holder);
- __ push(FieldOperand(kScratchRegister, InterceptorInfo::kDataOffset));
-}
-
-
void StubCache::GenerateProbe(MacroAssembler* masm,
Code::Flags flags,
Register receiver,
@@ -324,83 +232,38 @@
}
-// Both name_reg and receiver_reg are preserved on jumps to miss_label,
-// but may be destroyed if store is successful.
-void StubCompiler::GenerateStoreField(MacroAssembler* masm,
- JSObject* object,
- int index,
- Map* transition,
- Register receiver_reg,
- Register name_reg,
- Register scratch,
- Label* miss_label) {
- // Check that the object isn't a smi.
- __ JumpIfSmi(receiver_reg, miss_label);
+void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
+ int index,
+ Register prototype) {
+ // Load the global or builtins object from the current context.
+ __ movq(prototype,
+ Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
+ // Load the global context from the global or builtins object.
+ __ movq(prototype,
+ FieldOperand(prototype, GlobalObject::kGlobalContextOffset));
+ // Load the function from the global context.
+ __ movq(prototype, Operand(prototype, Context::SlotOffset(index)));
+ // Load the initial map. The global functions all have initial maps.
+ __ movq(prototype,
+ FieldOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
+ // Load the prototype from the initial map.
+ __ movq(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
+}
- // Check that the map of the object hasn't changed.
- __ Cmp(FieldOperand(receiver_reg, HeapObject::kMapOffset),
- Handle<Map>(object->map()));
- __ j(not_equal, miss_label);
- // Perform global security token check if needed.
- if (object->IsJSGlobalProxy()) {
- __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
- }
-
- // Stub never generated for non-global objects that require access
- // checks.
- ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
-
- // Perform map transition for the receiver if necessary.
- if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
- // The properties must be extended before we can store the value.
- // We jump to a runtime call that extends the properties array.
- __ pop(scratch); // Return address.
- __ push(receiver_reg);
- __ Push(Handle<Map>(transition));
- __ push(rax);
- __ push(scratch);
- __ TailCallExternalReference(
- ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage)), 3, 1);
- return;
- }
-
- if (transition != NULL) {
- // Update the map of the object; no write barrier updating is
- // needed because the map is never in new space.
- __ Move(FieldOperand(receiver_reg, HeapObject::kMapOffset),
- Handle<Map>(transition));
- }
-
- // Adjust for the number of properties stored in the object. Even in the
- // face of a transition we can use the old map here because the size of the
- // object and the number of in-object properties is not going to change.
- index -= object->map()->inobject_properties();
-
- if (index < 0) {
- // Set the property straight into the object.
- int offset = object->map()->instance_size() + (index * kPointerSize);
- __ movq(FieldOperand(receiver_reg, offset), rax);
-
- // Update the write barrier for the array address.
- // Pass the value being stored in the now unused name_reg.
- __ movq(name_reg, rax);
- __ RecordWrite(receiver_reg, offset, name_reg, scratch);
- } else {
- // Write to the properties array.
- int offset = index * kPointerSize + FixedArray::kHeaderSize;
- // Get the properties array (optimistically).
- __ movq(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
- __ movq(FieldOperand(scratch, offset), rax);
-
- // Update the write barrier for the array address.
- // Pass the value being stored in the now unused name_reg.
- __ movq(name_reg, rax);
- __ RecordWrite(scratch, offset, name_reg, receiver_reg);
- }
-
- // Return the value (register rax).
- __ ret(0);
+void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
+ MacroAssembler* masm, int index, Register prototype, Label* miss) {
+ // Check we're still in the same context.
+ __ Move(prototype, Top::global());
+ __ cmpq(Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)),
+ prototype);
+ __ j(not_equal, miss);
+ // Get the global function with the given index.
+ JSFunction* function = JSFunction::cast(Top::global_context()->get(index));
+ // Load its initial map. The global functions all have initial maps.
+ __ Move(prototype, Handle<Map>(function->initial_map()));
+ // Load the prototype from the initial map.
+ __ movq(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
}
@@ -469,6 +332,54 @@
}
+void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
+ Register receiver,
+ Register result,
+ Register scratch,
+ Label* miss_label) {
+ __ TryGetFunctionPrototype(receiver, result, miss_label);
+ if (!result.is(rax)) __ movq(rax, result);
+ __ ret(0);
+}
+
+
+// Load a fast property out of a holder object (src). In-object properties
+// are loaded directly otherwise the property is loaded from the properties
+// fixed array.
+void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
+ Register dst, Register src,
+ JSObject* holder, int index) {
+ // Adjust for the number of properties stored in the holder.
+ index -= holder->map()->inobject_properties();
+ if (index < 0) {
+ // Get the property straight out of the holder.
+ int offset = holder->map()->instance_size() + (index * kPointerSize);
+ __ movq(dst, FieldOperand(src, offset));
+ } else {
+ // Calculate the offset into the properties array.
+ int offset = index * kPointerSize + FixedArray::kHeaderSize;
+ __ movq(dst, FieldOperand(src, JSObject::kPropertiesOffset));
+ __ movq(dst, FieldOperand(dst, offset));
+ }
+}
+
+
+static void PushInterceptorArguments(MacroAssembler* masm,
+ Register receiver,
+ Register holder,
+ Register name,
+ JSObject* holder_obj) {
+ __ push(name);
+ InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
+ ASSERT(!Heap::InNewSpace(interceptor));
+ __ Move(kScratchRegister, Handle<Object>(interceptor));
+ __ push(kScratchRegister);
+ __ push(receiver);
+ __ push(holder);
+ __ push(FieldOperand(kScratchRegister, InterceptorInfo::kDataOffset));
+}
+
+
static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
Register receiver,
Register holder,
@@ -486,20 +397,10 @@
}
-
-void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
- Register receiver,
- Register result,
- Register scratch,
- Label* miss_label) {
- __ TryGetFunctionPrototype(receiver, result, miss_label);
- if (!result.is(rax)) __ movq(rax, result);
- __ ret(0);
-}
-
// Number of pointers to be reserved on stack for fast API call.
static const int kFastApiCallArguments = 3;
+
// Reserves space for the extra arguments to API function in the
// caller's frame.
//
@@ -553,7 +454,6 @@
// -- rsp[(argc + 3) * 8] : first argument
// -- rsp[(argc + 4) * 8] : receiver
// -----------------------------------
-
// Get the function and setup the context.
JSFunction* function = optimization.constant_function();
__ Move(rdi, Handle<JSFunction>(function));
@@ -833,6 +733,100 @@
};
+void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
+ ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
+ Code* code = NULL;
+ if (kind == Code::LOAD_IC) {
+ code = Builtins::builtin(Builtins::LoadIC_Miss);
+ } else {
+ code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
+ }
+
+ Handle<Code> ic(code);
+ __ Jump(ic, RelocInfo::CODE_TARGET);
+}
+
+
+// Both name_reg and receiver_reg are preserved on jumps to miss_label,
+// but may be destroyed if store is successful.
+void StubCompiler::GenerateStoreField(MacroAssembler* masm,
+ JSObject* object,
+ int index,
+ Map* transition,
+ Register receiver_reg,
+ Register name_reg,
+ Register scratch,
+ Label* miss_label) {
+ // Check that the object isn't a smi.
+ __ JumpIfSmi(receiver_reg, miss_label);
+
+ // Check that the map of the object hasn't changed.
+ __ Cmp(FieldOperand(receiver_reg, HeapObject::kMapOffset),
+ Handle<Map>(object->map()));
+ __ j(not_equal, miss_label);
+
+ // Perform global security token check if needed.
+ if (object->IsJSGlobalProxy()) {
+ __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
+ }
+
+ // Stub never generated for non-global objects that require access
+ // checks.
+ ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
+
+ // Perform map transition for the receiver if necessary.
+ if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
+ // The properties must be extended before we can store the value.
+ // We jump to a runtime call that extends the properties array.
+ __ pop(scratch); // Return address.
+ __ push(receiver_reg);
+ __ Push(Handle<Map>(transition));
+ __ push(rax);
+ __ push(scratch);
+ __ TailCallExternalReference(
+ ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage)), 3, 1);
+ return;
+ }
+
+ if (transition != NULL) {
+ // Update the map of the object; no write barrier updating is
+ // needed because the map is never in new space.
+ __ Move(FieldOperand(receiver_reg, HeapObject::kMapOffset),
+ Handle<Map>(transition));
+ }
+
+ // Adjust for the number of properties stored in the object. Even in the
+ // face of a transition we can use the old map here because the size of the
+ // object and the number of in-object properties is not going to change.
+ index -= object->map()->inobject_properties();
+
+ if (index < 0) {
+ // Set the property straight into the object.
+ int offset = object->map()->instance_size() + (index * kPointerSize);
+ __ movq(FieldOperand(receiver_reg, offset), rax);
+
+ // Update the write barrier for the array address.
+ // Pass the value being stored in the now unused name_reg.
+ __ movq(name_reg, rax);
+ __ RecordWrite(receiver_reg, offset, name_reg, scratch);
+ } else {
+ // Write to the properties array.
+ int offset = index * kPointerSize + FixedArray::kHeaderSize;
+ // Get the properties array (optimistically).
+ __ movq(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
+ __ movq(FieldOperand(scratch, offset), rax);
+
+ // Update the write barrier for the array address.
+ // Pass the value being stored in the now unused name_reg.
+ __ movq(name_reg, rax);
+ __ RecordWrite(scratch, offset, name_reg, receiver_reg);
+ }
+
+ // Return the value (register rax).
+ __ ret(0);
+}
+
+
// Generate code to check that a global property cell is empty. Create
// the property cell at compilation time if no cell exists for the
// property.
@@ -857,10 +851,420 @@
#undef __
-
#define __ ACCESS_MASM((masm()))
+Register StubCompiler::CheckPrototypes(JSObject* object,
+ Register object_reg,
+ JSObject* holder,
+ Register holder_reg,
+ Register scratch1,
+ Register scratch2,
+ String* name,
+ int save_at_depth,
+ Label* miss) {
+ // Make sure there's no overlap between holder and object registers.
+ ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
+ ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
+ && !scratch2.is(scratch1));
+
+ // Keep track of the current object in register reg. On the first
+ // iteration, reg is an alias for object_reg, on later iterations,
+ // it is an alias for holder_reg.
+ Register reg = object_reg;
+ int depth = 0;
+
+ if (save_at_depth == depth) {
+ __ movq(Operand(rsp, kPointerSize), object_reg);
+ }
+
+ // Check the maps in the prototype chain.
+ // Traverse the prototype chain from the object and do map checks.
+ JSObject* current = object;
+ while (current != holder) {
+ depth++;
+
+ // Only global objects and objects that do not require access
+ // checks are allowed in stubs.
+ ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
+
+ JSObject* prototype = JSObject::cast(current->GetPrototype());
+ if (!current->HasFastProperties() &&
+ !current->IsJSGlobalObject() &&
+ !current->IsJSGlobalProxy()) {
+ if (!name->IsSymbol()) {
+ MaybeObject* lookup_result = Heap::LookupSymbol(name);
+ if (lookup_result->IsFailure()) {
+ set_failure(Failure::cast(lookup_result));
+ return reg;
+ } else {
+ name = String::cast(lookup_result->ToObjectUnchecked());
+ }
+ }
+ ASSERT(current->property_dictionary()->FindEntry(name) ==
+ StringDictionary::kNotFound);
+
+ GenerateDictionaryNegativeLookup(masm(),
+ miss,
+ reg,
+ name,
+ scratch1,
+ scratch2);
+ __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
+ reg = holder_reg; // from now the object is in holder_reg
+ __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
+ } else if (Heap::InNewSpace(prototype)) {
+ // Get the map of the current object.
+ __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
+ __ Cmp(scratch1, Handle<Map>(current->map()));
+ // Branch on the result of the map check.
+ __ j(not_equal, miss);
+ // Check access rights to the global object. This has to happen
+ // after the map check so that we know that the object is
+ // actually a global object.
+ if (current->IsJSGlobalProxy()) {
+ __ CheckAccessGlobalProxy(reg, scratch1, miss);
+
+ // Restore scratch register to be the map of the object.
+ // We load the prototype from the map in the scratch register.
+ __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
+ }
+ // The prototype is in new space; we cannot store a reference
+ // to it in the code. Load it from the map.
+ reg = holder_reg; // from now the object is in holder_reg
+ __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
+
+ } else {
+ // Check the map of the current object.
+ __ Cmp(FieldOperand(reg, HeapObject::kMapOffset),
+ Handle<Map>(current->map()));
+ // Branch on the result of the map check.
+ __ j(not_equal, miss);
+ // Check access rights to the global object. This has to happen
+ // after the map check so that we know that the object is
+ // actually a global object.
+ if (current->IsJSGlobalProxy()) {
+ __ CheckAccessGlobalProxy(reg, scratch1, miss);
+ }
+ // The prototype is in old space; load it directly.
+ reg = holder_reg; // from now the object is in holder_reg
+ __ Move(reg, Handle<JSObject>(prototype));
+ }
+
+ if (save_at_depth == depth) {
+ __ movq(Operand(rsp, kPointerSize), reg);
+ }
+
+ // Go to the next object in the prototype chain.
+ current = prototype;
+ }
+
+ // Check the holder map.
+ __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), Handle<Map>(holder->map()));
+ __ j(not_equal, miss);
+
+ // Log the check depth.
+ LOG(IntEvent("check-maps-depth", depth + 1));
+
+ // Perform security check for access to the global object and return
+ // the holder register.
+ ASSERT(current == holder);
+ ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
+ if (current->IsJSGlobalProxy()) {
+ __ CheckAccessGlobalProxy(reg, scratch1, miss);
+ }
+
+ // If we've skipped any global objects, it's not enough to verify
+ // that their maps haven't changed. We also need to check that the
+ // property cell for the property is still empty.
+ current = object;
+ while (current != holder) {
+ if (current->IsGlobalObject()) {
+ MaybeObject* cell = GenerateCheckPropertyCell(masm(),
+ GlobalObject::cast(current),
+ name,
+ scratch1,
+ miss);
+ if (cell->IsFailure()) {
+ set_failure(Failure::cast(cell));
+ return reg;
+ }
+ }
+ current = JSObject::cast(current->GetPrototype());
+ }
+
+ // Return the register containing the holder.
+ return reg;
+}
+
+
+void StubCompiler::GenerateLoadField(JSObject* object,
+ JSObject* holder,
+ Register receiver,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ int index,
+ String* name,
+ Label* miss) {
+ // Check that the receiver isn't a smi.
+ __ JumpIfSmi(receiver, miss);
+
+ // Check the prototype chain.
+ Register reg =
+ CheckPrototypes(object, receiver, holder,
+ scratch1, scratch2, scratch3, name, miss);
+
+ // Get the value from the properties.
+ GenerateFastPropertyLoad(masm(), rax, reg, holder, index);
+ __ ret(0);
+}
+
+
+bool StubCompiler::GenerateLoadCallback(JSObject* object,
+ JSObject* holder,
+ Register receiver,
+ Register name_reg,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ AccessorInfo* callback,
+ String* name,
+ Label* miss,
+ Failure** failure) {
+ // Check that the receiver isn't a smi.
+ __ JumpIfSmi(receiver, miss);
+
+ // Check that the maps haven't changed.
+ Register reg =
+ CheckPrototypes(object, receiver, holder, scratch1,
+ scratch2, scratch3, name, miss);
+
+ Handle<AccessorInfo> callback_handle(callback);
+
+ // Insert additional parameters into the stack frame above return address.
+ ASSERT(!scratch2.is(reg));
+ __ pop(scratch2); // Get return address to place it below.
+
+ __ push(receiver); // receiver
+ __ push(reg); // holder
+ if (Heap::InNewSpace(callback_handle->data())) {
+ __ Move(scratch1, callback_handle);
+ __ push(FieldOperand(scratch1, AccessorInfo::kDataOffset)); // data
+ } else {
+ __ Push(Handle<Object>(callback_handle->data()));
+ }
+ __ push(name_reg); // name
+ // Save a pointer to where we pushed the arguments pointer.
+ // This will be passed as the const AccessorInfo& to the C++ callback.
+
+#ifdef _WIN64
+ // Win64 uses first register--rcx--for returned value.
+ Register accessor_info_arg = r8;
+ Register name_arg = rdx;
+#else
+ Register accessor_info_arg = rsi;
+ Register name_arg = rdi;
+#endif
+
+ ASSERT(!name_arg.is(scratch2));
+ __ movq(name_arg, rsp);
+ __ push(scratch2); // Restore return address.
+
+ // Do call through the api.
+ Address getter_address = v8::ToCData<Address>(callback->getter());
+ ApiFunction fun(getter_address);
+
+ // 3 elements array for v8::Agruments::values_ and handler for name.
+ const int kStackSpace = 4;
+
+ // Allocate v8::AccessorInfo in non-GCed stack space.
+ const int kArgStackSpace = 1;
+
+ __ PrepareCallApiFunction(kArgStackSpace);
+ __ lea(rax, Operand(name_arg, 3 * kPointerSize));
+
+ // v8::AccessorInfo::args_.
+ __ movq(StackSpaceOperand(0), rax);
+
+ // The context register (rsi) has been saved in PrepareCallApiFunction and
+ // could be used to pass arguments.
+ __ lea(accessor_info_arg, StackSpaceOperand(0));
+
+ // Emitting a stub call may try to allocate (if the code is not
+ // already generated). Do not allow the assembler to perform a
+ // garbage collection but instead return the allocation failure
+ // object.
+ MaybeObject* result = masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace);
+ if (result->IsFailure()) {
+ *failure = Failure::cast(result);
+ return false;
+ }
+ return true;
+}
+
+
+void StubCompiler::GenerateLoadConstant(JSObject* object,
+ JSObject* holder,
+ Register receiver,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ Object* value,
+ String* name,
+ Label* miss) {
+ // Check that the receiver isn't a smi.
+ __ JumpIfSmi(receiver, miss);
+
+ // Check that the maps haven't changed.
+ Register reg =
+ CheckPrototypes(object, receiver, holder,
+ scratch1, scratch2, scratch3, name, miss);
+
+ // Return the constant value.
+ __ Move(rax, Handle<Object>(value));
+ __ ret(0);
+}
+
+
+void StubCompiler::GenerateLoadInterceptor(JSObject* object,
+ JSObject* interceptor_holder,
+ LookupResult* lookup,
+ Register receiver,
+ Register name_reg,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ String* name,
+ Label* miss) {
+ ASSERT(interceptor_holder->HasNamedInterceptor());
+ ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
+
+ // Check that the receiver isn't a smi.
+ __ JumpIfSmi(receiver, miss);
+
+ // So far the most popular follow ups for interceptor loads are FIELD
+ // and CALLBACKS, so inline only them, other cases may be added
+ // later.
+ bool compile_followup_inline = false;
+ if (lookup->IsProperty() && lookup->IsCacheable()) {
+ if (lookup->type() == FIELD) {
+ compile_followup_inline = true;
+ } else if (lookup->type() == CALLBACKS &&
+ lookup->GetCallbackObject()->IsAccessorInfo() &&
+ AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) {
+ compile_followup_inline = true;
+ }
+ }
+
+ if (compile_followup_inline) {
+ // Compile the interceptor call, followed by inline code to load the
+ // property from further up the prototype chain if the call fails.
+ // Check that the maps haven't changed.
+ Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
+ scratch1, scratch2, scratch3,
+ name, miss);
+ ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
+
+ // Save necessary data before invoking an interceptor.
+ // Requires a frame to make GC aware of pushed pointers.
+ __ EnterInternalFrame();
+
+ if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
+ // CALLBACKS case needs a receiver to be passed into C++ callback.
+ __ push(receiver);
+ }
+ __ push(holder_reg);
+ __ push(name_reg);
+
+ // Invoke an interceptor. Note: map checks from receiver to
+ // interceptor's holder has been compiled before (see a caller
+ // of this method.)
+ CompileCallLoadPropertyWithInterceptor(masm(),
+ receiver,
+ holder_reg,
+ name_reg,
+ interceptor_holder);
+
+ // Check if interceptor provided a value for property. If it's
+ // the case, return immediately.
+ Label interceptor_failed;
+ __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
+ __ j(equal, &interceptor_failed);
+ __ LeaveInternalFrame();
+ __ ret(0);
+
+ __ bind(&interceptor_failed);
+ __ pop(name_reg);
+ __ pop(holder_reg);
+ if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
+ __ pop(receiver);
+ }
+
+ __ LeaveInternalFrame();
+
+ // Check that the maps from interceptor's holder to lookup's holder
+ // haven't changed. And load lookup's holder into |holder| register.
+ if (interceptor_holder != lookup->holder()) {
+ holder_reg = CheckPrototypes(interceptor_holder,
+ holder_reg,
+ lookup->holder(),
+ scratch1,
+ scratch2,
+ scratch3,
+ name,
+ miss);
+ }
+
+ if (lookup->type() == FIELD) {
+ // We found FIELD property in prototype chain of interceptor's holder.
+ // Retrieve a field from field's holder.
+ GenerateFastPropertyLoad(masm(), rax, holder_reg,
+ lookup->holder(), lookup->GetFieldIndex());
+ __ ret(0);
+ } else {
+ // We found CALLBACKS property in prototype chain of interceptor's
+ // holder.
+ ASSERT(lookup->type() == CALLBACKS);
+ ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
+ AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
+ ASSERT(callback != NULL);
+ ASSERT(callback->getter() != NULL);
+
+ // Tail call to runtime.
+ // Important invariant in CALLBACKS case: the code above must be
+ // structured to never clobber |receiver| register.
+ __ pop(scratch2); // return address
+ __ push(receiver);
+ __ push(holder_reg);
+ __ Move(holder_reg, Handle<AccessorInfo>(callback));
+ __ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset));
+ __ push(holder_reg);
+ __ push(name_reg);
+ __ push(scratch2); // restore return address
+
+ ExternalReference ref =
+ ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
+ __ TailCallExternalReference(ref, 5, 1);
+ }
+ } else { // !compile_followup_inline
+ // Call the runtime system to load the interceptor.
+ // Check that the maps haven't changed.
+ Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
+ scratch1, scratch2, scratch3,
+ name, miss);
+ __ pop(scratch2); // save old return address
+ PushInterceptorArguments(masm(), receiver, holder_reg,
+ name_reg, interceptor_holder);
+ __ push(scratch2); // restore old return address
+
+ ExternalReference ref = ExternalReference(
+ IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
+ __ TailCallExternalReference(ref, 5, 1);
+ }
+}
+
+
void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) {
if (kind_ == Code::KEYED_CALL_IC) {
__ Cmp(rcx, Handle<String>(name));
@@ -932,177 +1336,6 @@
}
-MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
- JSObject* holder,
- JSFunction* function,
- String* name,
- CheckType check) {
- // ----------- S t a t e -------------
- // rcx : function name
- // rsp[0] : return address
- // rsp[8] : argument argc
- // rsp[16] : argument argc - 1
- // ...
- // rsp[argc * 8] : argument 1
- // rsp[(argc + 1) * 8] : argument 0 = receiver
- // -----------------------------------
-
- SharedFunctionInfo* function_info = function->shared();
- if (function_info->HasBuiltinFunctionId()) {
- BuiltinFunctionId id = function_info->builtin_function_id();
- MaybeObject* maybe_result = CompileCustomCall(
- id, object, holder, NULL, function, name);
- Object* result;
- if (!maybe_result->ToObject(&result)) return maybe_result;
- // undefined means bail out to regular compiler.
- if (!result->IsUndefined()) return result;
- }
-
- Label miss_in_smi_check;
-
- GenerateNameCheck(name, &miss_in_smi_check);
-
- // Get the receiver from the stack.
- const int argc = arguments().immediate();
- __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
-
- // Check that the receiver isn't a smi.
- if (check != NUMBER_CHECK) {
- __ JumpIfSmi(rdx, &miss_in_smi_check);
- }
-
- // Make sure that it's okay not to patch the on stack receiver
- // unless we're doing a receiver map check.
- ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
-
- CallOptimization optimization(function);
- int depth = kInvalidProtoDepth;
- Label miss;
-
- switch (check) {
- case RECEIVER_MAP_CHECK:
- __ IncrementCounter(&Counters::call_const, 1);
-
- if (optimization.is_simple_api_call() && !object->IsGlobalObject()) {
- depth = optimization.GetPrototypeDepthOfExpectedType(
- JSObject::cast(object), holder);
- }
-
- if (depth != kInvalidProtoDepth) {
- __ IncrementCounter(&Counters::call_const_fast_api, 1);
- // Allocate space for v8::Arguments implicit values. Must be initialized
- // before to call any runtime function.
- __ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
- }
-
- // Check that the maps haven't changed.
- CheckPrototypes(JSObject::cast(object), rdx, holder,
- rbx, rax, rdi, name, depth, &miss);
-
- // Patch the receiver on the stack with the global proxy if
- // necessary.
- if (object->IsGlobalObject()) {
- ASSERT(depth == kInvalidProtoDepth);
- __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
- __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
- }
- break;
-
- case STRING_CHECK:
- if (!function->IsBuiltin()) {
- // Calling non-builtins with a value as receiver requires boxing.
- __ jmp(&miss);
- } else {
- // Check that the object is a two-byte string or a symbol.
- __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rax);
- __ j(above_equal, &miss);
- // Check that the maps starting from the prototype haven't changed.
- GenerateDirectLoadGlobalFunctionPrototype(
- masm(), Context::STRING_FUNCTION_INDEX, rax, &miss);
- CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
- rbx, rdx, rdi, name, &miss);
- }
- break;
-
- case NUMBER_CHECK: {
- if (!function->IsBuiltin()) {
- // Calling non-builtins with a value as receiver requires boxing.
- __ jmp(&miss);
- } else {
- Label fast;
- // Check that the object is a smi or a heap number.
- __ JumpIfSmi(rdx, &fast);
- __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rax);
- __ j(not_equal, &miss);
- __ bind(&fast);
- // Check that the maps starting from the prototype haven't changed.
- GenerateDirectLoadGlobalFunctionPrototype(
- masm(), Context::NUMBER_FUNCTION_INDEX, rax, &miss);
- CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
- rbx, rdx, rdi, name, &miss);
- }
- break;
- }
-
- case BOOLEAN_CHECK: {
- if (!function->IsBuiltin()) {
- // Calling non-builtins with a value as receiver requires boxing.
- __ jmp(&miss);
- } else {
- Label fast;
- // Check that the object is a boolean.
- __ CompareRoot(rdx, Heap::kTrueValueRootIndex);
- __ j(equal, &fast);
- __ CompareRoot(rdx, Heap::kFalseValueRootIndex);
- __ j(not_equal, &miss);
- __ bind(&fast);
- // Check that the maps starting from the prototype haven't changed.
- GenerateDirectLoadGlobalFunctionPrototype(
- masm(), Context::BOOLEAN_FUNCTION_INDEX, rax, &miss);
- CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
- rbx, rdx, rdi, name, &miss);
- }
- break;
- }
-
- default:
- UNREACHABLE();
- }
-
- if (depth != kInvalidProtoDepth) {
- Failure* failure;
- // Move the return address on top of the stack.
- __ movq(rax, Operand(rsp, 3 * kPointerSize));
- __ movq(Operand(rsp, 0 * kPointerSize), rax);
-
- // rsp[2 * kPointerSize] is uninitialized, rsp[3 * kPointerSize] contains
- // duplicate of return address and will be overwritten.
- bool success = GenerateFastApiCall(masm(), optimization, argc, &failure);
- if (!success) {
- return failure;
- }
- } else {
- __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
- }
-
- // Handle call cache miss.
- __ bind(&miss);
- if (depth != kInvalidProtoDepth) {
- __ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
- }
-
- // Handle call cache miss.
- __ bind(&miss_in_smi_check);
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
-
- // Return the generated code.
- return GetCode(function);
-}
-
-
MaybeObject* CallStubCompiler::CompileCallField(JSObject* object,
JSObject* holder,
int index,
@@ -1248,8 +1481,7 @@
__ InNewSpace(rbx, rcx, equal, &exit);
- RecordWriteStub stub(rbx, rdx, rcx);
- __ CallStub(&stub);
+ __ RecordWriteHelper(rbx, rdx, rcx);
__ ret((argc + 1) * kPointerSize);
@@ -1408,6 +1640,79 @@
}
+MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
+ Object* object,
+ JSObject* holder,
+ JSGlobalPropertyCell* cell,
+ JSFunction* function,
+ String* name) {
+ // ----------- S t a t e -------------
+ // -- rcx : function name
+ // -- rsp[0] : return address
+ // -- rsp[(argc - n) * 8] : arg[n] (zero-based)
+ // -- ...
+ // -- rsp[(argc + 1) * 8] : receiver
+ // -----------------------------------
+
+ // If object is not a string, bail out to regular call.
+ if (!object->IsString() || cell != NULL) return Heap::undefined_value();
+
+ const int argc = arguments().immediate();
+
+ Label miss;
+ Label index_out_of_range;
+
+ GenerateNameCheck(name, &miss);
+
+ // Check that the maps starting from the prototype haven't changed.
+ GenerateDirectLoadGlobalFunctionPrototype(masm(),
+ Context::STRING_FUNCTION_INDEX,
+ rax,
+ &miss);
+ ASSERT(object != holder);
+ CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
+ rbx, rdx, rdi, name, &miss);
+
+ Register receiver = rbx;
+ Register index = rdi;
+ Register scratch = rdx;
+ Register result = rax;
+ __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize));
+ if (argc > 0) {
+ __ movq(index, Operand(rsp, (argc - 0) * kPointerSize));
+ } else {
+ __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
+ }
+
+ StringCharCodeAtGenerator char_code_at_generator(receiver,
+ index,
+ scratch,
+ result,
+ &miss, // When not a string.
+ &miss, // When not a number.
+ &index_out_of_range,
+ STRING_INDEX_IS_NUMBER);
+ char_code_at_generator.GenerateFast(masm());
+ __ ret((argc + 1) * kPointerSize);
+
+ StubRuntimeCallHelper call_helper;
+ char_code_at_generator.GenerateSlow(masm(), call_helper);
+
+ __ bind(&index_out_of_range);
+ __ LoadRoot(rax, Heap::kNanValueRootIndex);
+ __ ret((argc + 1) * kPointerSize);
+
+ __ bind(&miss);
+ Object* obj;
+ { MaybeObject* maybe_obj = GenerateMissBranch();
+ if (!maybe_obj->ToObject(&obj)) return maybe_obj;
+ }
+
+ // Return the generated code.
+ return GetCode(function);
+}
+
+
MaybeObject* CallStubCompiler::CompileStringCharAtCall(
Object* object,
JSObject* holder,
@@ -1483,78 +1788,6 @@
}
-MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
- Object* object,
- JSObject* holder,
- JSGlobalPropertyCell* cell,
- JSFunction* function,
- String* name) {
- // ----------- S t a t e -------------
- // -- rcx : function name
- // -- rsp[0] : return address
- // -- rsp[(argc - n) * 8] : arg[n] (zero-based)
- // -- ...
- // -- rsp[(argc + 1) * 8] : receiver
- // -----------------------------------
-
- // If object is not a string, bail out to regular call.
- if (!object->IsString() || cell != NULL) return Heap::undefined_value();
-
- const int argc = arguments().immediate();
-
- Label miss;
- Label index_out_of_range;
- GenerateNameCheck(name, &miss);
-
- // Check that the maps starting from the prototype haven't changed.
- GenerateDirectLoadGlobalFunctionPrototype(masm(),
- Context::STRING_FUNCTION_INDEX,
- rax,
- &miss);
- ASSERT(object != holder);
- CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
- rbx, rdx, rdi, name, &miss);
-
- Register receiver = rbx;
- Register index = rdi;
- Register scratch = rdx;
- Register result = rax;
- __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize));
- if (argc > 0) {
- __ movq(index, Operand(rsp, (argc - 0) * kPointerSize));
- } else {
- __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
- }
-
- StringCharCodeAtGenerator char_code_at_generator(receiver,
- index,
- scratch,
- result,
- &miss, // When not a string.
- &miss, // When not a number.
- &index_out_of_range,
- STRING_INDEX_IS_NUMBER);
- char_code_at_generator.GenerateFast(masm());
- __ ret((argc + 1) * kPointerSize);
-
- StubRuntimeCallHelper call_helper;
- char_code_at_generator.GenerateSlow(masm(), call_helper);
-
- __ bind(&index_out_of_range);
- __ LoadRoot(rax, Heap::kNanValueRootIndex);
- __ ret((argc + 1) * kPointerSize);
-
- __ bind(&miss);
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
-
- // Return the generated code.
- return GetCode(function);
-}
-
-
MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall(
Object* object,
JSObject* holder,
@@ -1741,6 +1974,178 @@
}
+MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
+ JSObject* holder,
+ JSFunction* function,
+ String* name,
+ CheckType check) {
+ // ----------- S t a t e -------------
+ // rcx : function name
+ // rsp[0] : return address
+ // rsp[8] : argument argc
+ // rsp[16] : argument argc - 1
+ // ...
+ // rsp[argc * 8] : argument 1
+ // rsp[(argc + 1) * 8] : argument 0 = receiver
+ // -----------------------------------
+
+ SharedFunctionInfo* function_info = function->shared();
+ if (function_info->HasBuiltinFunctionId()) {
+ BuiltinFunctionId id = function_info->builtin_function_id();
+ MaybeObject* maybe_result = CompileCustomCall(
+ id, object, holder, NULL, function, name);
+ Object* result;
+ if (!maybe_result->ToObject(&result)) return maybe_result;
+ // undefined means bail out to regular compiler.
+ if (!result->IsUndefined()) return result;
+ }
+
+ Label miss_in_smi_check;
+
+ GenerateNameCheck(name, &miss_in_smi_check);
+
+ // Get the receiver from the stack.
+ const int argc = arguments().immediate();
+ __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
+
+ // Check that the receiver isn't a smi.
+ if (check != NUMBER_CHECK) {
+ __ JumpIfSmi(rdx, &miss_in_smi_check);
+ }
+
+ // Make sure that it's okay not to patch the on stack receiver
+ // unless we're doing a receiver map check.
+ ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
+
+ CallOptimization optimization(function);
+ int depth = kInvalidProtoDepth;
+ Label miss;
+
+ switch (check) {
+ case RECEIVER_MAP_CHECK:
+ __ IncrementCounter(&Counters::call_const, 1);
+
+ if (optimization.is_simple_api_call() && !object->IsGlobalObject()) {
+ depth = optimization.GetPrototypeDepthOfExpectedType(
+ JSObject::cast(object), holder);
+ }
+
+ if (depth != kInvalidProtoDepth) {
+ __ IncrementCounter(&Counters::call_const_fast_api, 1);
+
+ // Allocate space for v8::Arguments implicit values. Must be initialized
+ // before to call any runtime function.
+ __ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
+ }
+
+ // Check that the maps haven't changed.
+ CheckPrototypes(JSObject::cast(object), rdx, holder,
+ rbx, rax, rdi, name, depth, &miss);
+
+ // Patch the receiver on the stack with the global proxy if
+ // necessary.
+ if (object->IsGlobalObject()) {
+ ASSERT(depth == kInvalidProtoDepth);
+ __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
+ __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
+ }
+ break;
+
+ case STRING_CHECK:
+ if (!function->IsBuiltin()) {
+ // Calling non-builtins with a value as receiver requires boxing.
+ __ jmp(&miss);
+ } else {
+ // Check that the object is a two-byte string or a symbol.
+ __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rax);
+ __ j(above_equal, &miss);
+ // Check that the maps starting from the prototype haven't changed.
+ GenerateDirectLoadGlobalFunctionPrototype(
+ masm(), Context::STRING_FUNCTION_INDEX, rax, &miss);
+ CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
+ rbx, rdx, rdi, name, &miss);
+ }
+ break;
+
+ case NUMBER_CHECK: {
+ if (!function->IsBuiltin()) {
+ // Calling non-builtins with a value as receiver requires boxing.
+ __ jmp(&miss);
+ } else {
+ Label fast;
+ // Check that the object is a smi or a heap number.
+ __ JumpIfSmi(rdx, &fast);
+ __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rax);
+ __ j(not_equal, &miss);
+ __ bind(&fast);
+ // Check that the maps starting from the prototype haven't changed.
+ GenerateDirectLoadGlobalFunctionPrototype(
+ masm(), Context::NUMBER_FUNCTION_INDEX, rax, &miss);
+ CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
+ rbx, rdx, rdi, name, &miss);
+ }
+ break;
+ }
+
+ case BOOLEAN_CHECK: {
+ if (!function->IsBuiltin()) {
+ // Calling non-builtins with a value as receiver requires boxing.
+ __ jmp(&miss);
+ } else {
+ Label fast;
+ // Check that the object is a boolean.
+ __ CompareRoot(rdx, Heap::kTrueValueRootIndex);
+ __ j(equal, &fast);
+ __ CompareRoot(rdx, Heap::kFalseValueRootIndex);
+ __ j(not_equal, &miss);
+ __ bind(&fast);
+ // Check that the maps starting from the prototype haven't changed.
+ GenerateDirectLoadGlobalFunctionPrototype(
+ masm(), Context::BOOLEAN_FUNCTION_INDEX, rax, &miss);
+ CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
+ rbx, rdx, rdi, name, &miss);
+ }
+ break;
+ }
+
+ default:
+ UNREACHABLE();
+ }
+
+ if (depth != kInvalidProtoDepth) {
+ Failure* failure;
+ // Move the return address on top of the stack.
+ __ movq(rax, Operand(rsp, 3 * kPointerSize));
+ __ movq(Operand(rsp, 0 * kPointerSize), rax);
+
+ // rsp[2 * kPointerSize] is uninitialized, rsp[3 * kPointerSize] contains
+ // duplicate of return address and will be overwritten.
+ bool success = GenerateFastApiCall(masm(), optimization, argc, &failure);
+ if (!success) {
+ return failure;
+ }
+ } else {
+ __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
+ }
+
+ // Handle call cache miss.
+ __ bind(&miss);
+ if (depth != kInvalidProtoDepth) {
+ __ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
+ }
+
+ // Handle call cache miss.
+ __ bind(&miss_in_smi_check);
+ Object* obj;
+ { MaybeObject* maybe_obj = GenerateMissBranch();
+ if (!maybe_obj->ToObject(&obj)) return maybe_obj;
+ }
+
+ // Return the generated code.
+ return GetCode(function);
+}
+
+
MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
JSObject* holder,
String* name) {
@@ -1881,415 +2286,33 @@
}
-MaybeObject* LoadStubCompiler::CompileLoadCallback(String* name,
- JSObject* object,
- JSObject* holder,
- AccessorInfo* callback) {
+MaybeObject* StoreStubCompiler::CompileStoreField(JSObject* object,
+ int index,
+ Map* transition,
+ String* name) {
// ----------- S t a t e -------------
- // -- rax : receiver
+ // -- rax : value
// -- rcx : name
- // -- rsp[0] : return address
- // -----------------------------------
- Label miss;
-
- Failure* failure = Failure::InternalError();
- bool success = GenerateLoadCallback(object, holder, rax, rcx, rdx, rbx, rdi,
- callback, name, &miss, &failure);
- if (!success) {
- miss.Unuse();
- return failure;
- }
-
- __ bind(&miss);
- GenerateLoadMiss(masm(), Code::LOAD_IC);
-
- // Return the generated code.
- return GetCode(CALLBACKS, name);
-}
-
-
-MaybeObject* LoadStubCompiler::CompileLoadConstant(JSObject* object,
- JSObject* holder,
- Object* value,
- String* name) {
- // ----------- S t a t e -------------
- // -- rax : receiver
- // -- rcx : name
- // -- rsp[0] : return address
- // -----------------------------------
- Label miss;
-
- GenerateLoadConstant(object, holder, rax, rbx, rdx, rdi, value, name, &miss);
- __ bind(&miss);
- GenerateLoadMiss(masm(), Code::LOAD_IC);
-
- // Return the generated code.
- return GetCode(CONSTANT_FUNCTION, name);
-}
-
-
-MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name,
- JSObject* object,
- JSObject* last) {
- // ----------- S t a t e -------------
- // -- rax : receiver
- // -- rcx : name
- // -- rsp[0] : return address
- // -----------------------------------
- Label miss;
-
- // Chech that receiver is not a smi.
- __ JumpIfSmi(rax, &miss);
-
- // Check the maps of the full prototype chain. Also check that
- // global property cells up to (but not including) the last object
- // in the prototype chain are empty.
- CheckPrototypes(object, rax, last, rbx, rdx, rdi, name, &miss);
-
- // If the last object in the prototype chain is a global object,
- // check that the global property cell is empty.
- if (last->IsGlobalObject()) {
- MaybeObject* cell = GenerateCheckPropertyCell(masm(),
- GlobalObject::cast(last),
- name,
- rdx,
- &miss);
- if (cell->IsFailure()) {
- miss.Unuse();
- return cell;
- }
- }
-
- // Return undefined if maps of the full prototype chain are still the
- // same and no global property with this name contains a value.
- __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
- __ ret(0);
-
- __ bind(&miss);
- GenerateLoadMiss(masm(), Code::LOAD_IC);
-
- // Return the generated code.
- return GetCode(NONEXISTENT, Heap::empty_string());
-}
-
-
-MaybeObject* LoadStubCompiler::CompileLoadField(JSObject* object,
- JSObject* holder,
- int index,
- String* name) {
- // ----------- S t a t e -------------
- // -- rax : receiver
- // -- rcx : name
- // -- rsp[0] : return address
- // -----------------------------------
- Label miss;
-
- GenerateLoadField(object, holder, rax, rbx, rdx, rdi, index, name, &miss);
- __ bind(&miss);
- GenerateLoadMiss(masm(), Code::LOAD_IC);
-
- // Return the generated code.
- return GetCode(FIELD, name);
-}
-
-
-MaybeObject* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
- JSObject* holder,
- String* name) {
- // ----------- S t a t e -------------
- // -- rax : receiver
- // -- rcx : name
- // -- rsp[0] : return address
- // -----------------------------------
- Label miss;
-
- LookupResult lookup;
- LookupPostInterceptor(holder, name, &lookup);
-
- // TODO(368): Compile in the whole chain: all the interceptors in
- // prototypes and ultimate answer.
- GenerateLoadInterceptor(receiver,
- holder,
- &lookup,
- rax,
- rcx,
- rdx,
- rbx,
- rdi,
- name,
- &miss);
-
- __ bind(&miss);
- GenerateLoadMiss(masm(), Code::LOAD_IC);
-
- // Return the generated code.
- return GetCode(INTERCEPTOR, name);
-}
-
-
-MaybeObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
- GlobalObject* holder,
- JSGlobalPropertyCell* cell,
- String* name,
- bool is_dont_delete) {
- // ----------- S t a t e -------------
- // -- rax : receiver
- // -- rcx : name
- // -- rsp[0] : return address
- // -----------------------------------
- Label miss;
-
- // If the object is the holder then we know that it's a global
- // object which can only happen for contextual loads. In this case,
- // the receiver cannot be a smi.
- if (object != holder) {
- __ JumpIfSmi(rax, &miss);
- }
-
- // Check that the maps haven't changed.
- CheckPrototypes(object, rax, holder, rbx, rdx, rdi, name, &miss);
-
- // Get the value from the cell.
- __ Move(rbx, Handle<JSGlobalPropertyCell>(cell));
- __ movq(rbx, FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset));
-
- // Check for deleted property if property can actually be deleted.
- if (!is_dont_delete) {
- __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
- __ j(equal, &miss);
- } else if (FLAG_debug_code) {
- __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
- __ Check(not_equal, "DontDelete cells can't contain the hole");
- }
-
- __ IncrementCounter(&Counters::named_load_global_stub, 1);
- __ movq(rax, rbx);
- __ ret(0);
-
- __ bind(&miss);
- __ IncrementCounter(&Counters::named_load_global_stub_miss, 1);
- GenerateLoadMiss(masm(), Code::LOAD_IC);
-
- // Return the generated code.
- return GetCode(NORMAL, name);
-}
-
-
-MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback(
- String* name,
- JSObject* receiver,
- JSObject* holder,
- AccessorInfo* callback) {
- // ----------- S t a t e -------------
- // -- rax : key
- // -- rdx : receiver
- // -- rsp[0] : return address
- // -----------------------------------
- Label miss;
-
- __ IncrementCounter(&Counters::keyed_load_callback, 1);
-
- // Check that the name has not changed.
- __ Cmp(rax, Handle<String>(name));
- __ j(not_equal, &miss);
-
- Failure* failure = Failure::InternalError();
- bool success = GenerateLoadCallback(receiver, holder, rdx, rax, rbx, rcx, rdi,
- callback, name, &miss, &failure);
- if (!success) {
- miss.Unuse();
- return failure;
- }
-
- __ bind(&miss);
- __ DecrementCounter(&Counters::keyed_load_callback, 1);
- GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
-
- // Return the generated code.
- return GetCode(CALLBACKS, name);
-}
-
-
-MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
- // ----------- S t a t e -------------
- // -- rax : key
- // -- rdx : receiver
- // -- rsp[0] : return address
- // -----------------------------------
- Label miss;
-
- __ IncrementCounter(&Counters::keyed_load_array_length, 1);
-
- // Check that the name has not changed.
- __ Cmp(rax, Handle<String>(name));
- __ j(not_equal, &miss);
-
- GenerateLoadArrayLength(masm(), rdx, rcx, &miss);
- __ bind(&miss);
- __ DecrementCounter(&Counters::keyed_load_array_length, 1);
- GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
-
- // Return the generated code.
- return GetCode(CALLBACKS, name);
-}
-
-
-MaybeObject* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
- JSObject* receiver,
- JSObject* holder,
- Object* value) {
- // ----------- S t a t e -------------
- // -- rax : key
- // -- rdx : receiver
- // -- rsp[0] : return address
- // -----------------------------------
- Label miss;
-
- __ IncrementCounter(&Counters::keyed_load_constant_function, 1);
-
- // Check that the name has not changed.
- __ Cmp(rax, Handle<String>(name));
- __ j(not_equal, &miss);
-
- GenerateLoadConstant(receiver, holder, rdx, rbx, rcx, rdi,
- value, name, &miss);
- __ bind(&miss);
- __ DecrementCounter(&Counters::keyed_load_constant_function, 1);
- GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
-
- // Return the generated code.
- return GetCode(CONSTANT_FUNCTION, name);
-}
-
-
-MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
- // ----------- S t a t e -------------
- // -- rax : key
- // -- rdx : receiver
- // -- rsp[0] : return address
- // -----------------------------------
- Label miss;
-
- __ IncrementCounter(&Counters::keyed_load_function_prototype, 1);
-
- // Check that the name has not changed.
- __ Cmp(rax, Handle<String>(name));
- __ j(not_equal, &miss);
-
- GenerateLoadFunctionPrototype(masm(), rdx, rcx, rbx, &miss);
- __ bind(&miss);
- __ DecrementCounter(&Counters::keyed_load_function_prototype, 1);
- GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
-
- // Return the generated code.
- return GetCode(CALLBACKS, name);
-}
-
-
-MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
- JSObject* holder,
- String* name) {
- // ----------- S t a t e -------------
- // -- rax : key
- // -- rdx : receiver
- // -- rsp[0] : return address
- // -----------------------------------
- Label miss;
-
- __ IncrementCounter(&Counters::keyed_load_interceptor, 1);
-
- // Check that the name has not changed.
- __ Cmp(rax, Handle<String>(name));
- __ j(not_equal, &miss);
-
- LookupResult lookup;
- LookupPostInterceptor(holder, name, &lookup);
- GenerateLoadInterceptor(receiver,
- holder,
- &lookup,
- rdx,
- rax,
- rcx,
- rbx,
- rdi,
- name,
- &miss);
- __ bind(&miss);
- __ DecrementCounter(&Counters::keyed_load_interceptor, 1);
- GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
-
- // Return the generated code.
- return GetCode(INTERCEPTOR, name);
-}
-
-
-MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
- // ----------- S t a t e -------------
- // -- rax : key
// -- rdx : receiver
// -- rsp[0] : return address
// -----------------------------------
Label miss;
- __ IncrementCounter(&Counters::keyed_load_string_length, 1);
+ // Generate store field code. Preserves receiver and name on jump to miss.
+ GenerateStoreField(masm(),
+ object,
+ index,
+ transition,
+ rdx, rcx, rbx,
+ &miss);
- // Check that the name has not changed.
- __ Cmp(rax, Handle<String>(name));
- __ j(not_equal, &miss);
-
- GenerateLoadStringLength(masm(), rdx, rcx, rbx, &miss);
+ // Handle store cache miss.
__ bind(&miss);
- __ DecrementCounter(&Counters::keyed_load_string_length, 1);
- GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+ Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
+ __ Jump(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
- return GetCode(CALLBACKS, name);
-}
-
-
-MaybeObject* KeyedLoadStubCompiler::CompileLoadSpecialized(JSObject* receiver) {
- // ----------- S t a t e -------------
- // -- rax : key
- // -- rdx : receiver
- // -- esp[0] : return address
- // -----------------------------------
- Label miss;
-
- // Check that the receiver isn't a smi.
- __ JumpIfSmi(rdx, &miss);
-
- // Check that the map matches.
- __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
- Handle<Map>(receiver->map()));
- __ j(not_equal, &miss);
-
- // Check that the key is a smi.
- __ JumpIfNotSmi(rax, &miss);
-
- // Get the elements array.
- __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
- __ AssertFastElements(rcx);
-
- // Check that the key is within bounds.
- __ SmiCompare(rax, FieldOperand(rcx, FixedArray::kLengthOffset));
- __ j(above_equal, &miss);
-
- // Load the result and make sure it's not the hole.
- SmiIndex index = masm()->SmiToIndex(rbx, rax, kPointerSizeLog2);
- __ movq(rbx, FieldOperand(rcx,
- index.reg,
- index.scale,
- FixedArray::kHeaderSize));
- __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
- __ j(equal, &miss);
- __ movq(rax, rbx);
- __ ret(0);
-
- __ bind(&miss);
- GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
-
- // Return the generated code.
- return GetCode(NORMAL, NULL);
+ return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
}
@@ -2343,36 +2366,6 @@
}
-MaybeObject* StoreStubCompiler::CompileStoreField(JSObject* object,
- int index,
- Map* transition,
- String* name) {
- // ----------- S t a t e -------------
- // -- rax : value
- // -- rcx : name
- // -- rdx : receiver
- // -- rsp[0] : return address
- // -----------------------------------
- Label miss;
-
- // Generate store field code. Preserves receiver and name on jump to miss.
- GenerateStoreField(masm(),
- object,
- index,
- transition,
- rdx, rcx, rbx,
- &miss);
-
- // Handle store cache miss.
- __ bind(&miss);
- Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
- __ Jump(ic, RelocInfo::CODE_TARGET);
-
- // Return the generated code.
- return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
-}
-
-
MaybeObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
String* name) {
// ----------- S t a t e -------------
@@ -2456,34 +2449,6 @@
}
-MaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name,
- JSObject* receiver,
- JSObject* holder,
- int index) {
- // ----------- S t a t e -------------
- // -- rax : key
- // -- rdx : receiver
- // -- rsp[0] : return address
- // -----------------------------------
- Label miss;
-
- __ IncrementCounter(&Counters::keyed_load_field, 1);
-
- // Check that the name has not changed.
- __ Cmp(rax, Handle<String>(name));
- __ j(not_equal, &miss);
-
- GenerateLoadField(receiver, holder, rdx, rbx, rcx, rdi, index, name, &miss);
-
- __ bind(&miss);
- __ DecrementCounter(&Counters::keyed_load_field, 1);
- GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
-
- // Return the generated code.
- return GetCode(FIELD, name);
-}
-
-
MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
int index,
Map* transition,
@@ -2578,414 +2543,444 @@
}
-void StubCompiler::GenerateLoadInterceptor(JSObject* object,
- JSObject* interceptor_holder,
- LookupResult* lookup,
- Register receiver,
- Register name_reg,
- Register scratch1,
- Register scratch2,
- Register scratch3,
- String* name,
- Label* miss) {
- ASSERT(interceptor_holder->HasNamedInterceptor());
- ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
+MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name,
+ JSObject* object,
+ JSObject* last) {
+ // ----------- S t a t e -------------
+ // -- rax : receiver
+ // -- rcx : name
+ // -- rsp[0] : return address
+ // -----------------------------------
+ Label miss;
- // Check that the receiver isn't a smi.
- __ JumpIfSmi(receiver, miss);
+ // Chech that receiver is not a smi.
+ __ JumpIfSmi(rax, &miss);
- // So far the most popular follow ups for interceptor loads are FIELD
- // and CALLBACKS, so inline only them, other cases may be added
- // later.
- bool compile_followup_inline = false;
- if (lookup->IsProperty() && lookup->IsCacheable()) {
- if (lookup->type() == FIELD) {
- compile_followup_inline = true;
- } else if (lookup->type() == CALLBACKS &&
- lookup->GetCallbackObject()->IsAccessorInfo() &&
- AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) {
- compile_followup_inline = true;
+ // Check the maps of the full prototype chain. Also check that
+ // global property cells up to (but not including) the last object
+ // in the prototype chain are empty.
+ CheckPrototypes(object, rax, last, rbx, rdx, rdi, name, &miss);
+
+ // If the last object in the prototype chain is a global object,
+ // check that the global property cell is empty.
+ if (last->IsGlobalObject()) {
+ MaybeObject* cell = GenerateCheckPropertyCell(masm(),
+ GlobalObject::cast(last),
+ name,
+ rdx,
+ &miss);
+ if (cell->IsFailure()) {
+ miss.Unuse();
+ return cell;
}
}
- if (compile_followup_inline) {
- // Compile the interceptor call, followed by inline code to load the
- // property from further up the prototype chain if the call fails.
- // Check that the maps haven't changed.
- Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
- scratch1, scratch2, scratch3,
- name, miss);
- ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
+ // Return undefined if maps of the full prototype chain are still the
+ // same and no global property with this name contains a value.
+ __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
+ __ ret(0);
- // Save necessary data before invoking an interceptor.
- // Requires a frame to make GC aware of pushed pointers.
- __ EnterInternalFrame();
+ __ bind(&miss);
+ GenerateLoadMiss(masm(), Code::LOAD_IC);
- if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
- // CALLBACKS case needs a receiver to be passed into C++ callback.
- __ push(receiver);
- }
- __ push(holder_reg);
- __ push(name_reg);
-
- // Invoke an interceptor. Note: map checks from receiver to
- // interceptor's holder has been compiled before (see a caller
- // of this method.)
- CompileCallLoadPropertyWithInterceptor(masm(),
- receiver,
- holder_reg,
- name_reg,
- interceptor_holder);
-
- // Check if interceptor provided a value for property. If it's
- // the case, return immediately.
- Label interceptor_failed;
- __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
- __ j(equal, &interceptor_failed);
- __ LeaveInternalFrame();
- __ ret(0);
-
- __ bind(&interceptor_failed);
- __ pop(name_reg);
- __ pop(holder_reg);
- if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
- __ pop(receiver);
- }
-
- __ LeaveInternalFrame();
-
- // Check that the maps from interceptor's holder to lookup's holder
- // haven't changed. And load lookup's holder into |holder| register.
- if (interceptor_holder != lookup->holder()) {
- holder_reg = CheckPrototypes(interceptor_holder,
- holder_reg,
- lookup->holder(),
- scratch1,
- scratch2,
- scratch3,
- name,
- miss);
- }
-
- if (lookup->type() == FIELD) {
- // We found FIELD property in prototype chain of interceptor's holder.
- // Retrieve a field from field's holder.
- GenerateFastPropertyLoad(masm(), rax, holder_reg,
- lookup->holder(), lookup->GetFieldIndex());
- __ ret(0);
- } else {
- // We found CALLBACKS property in prototype chain of interceptor's
- // holder.
- ASSERT(lookup->type() == CALLBACKS);
- ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
- AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
- ASSERT(callback != NULL);
- ASSERT(callback->getter() != NULL);
-
- // Tail call to runtime.
- // Important invariant in CALLBACKS case: the code above must be
- // structured to never clobber |receiver| register.
- __ pop(scratch2); // return address
- __ push(receiver);
- __ push(holder_reg);
- __ Move(holder_reg, Handle<AccessorInfo>(callback));
- __ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset));
- __ push(holder_reg);
- __ push(name_reg);
- __ push(scratch2); // restore return address
-
- ExternalReference ref =
- ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
- __ TailCallExternalReference(ref, 5, 1);
- }
- } else { // !compile_followup_inline
- // Call the runtime system to load the interceptor.
- // Check that the maps haven't changed.
- Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
- scratch1, scratch2, scratch3,
- name, miss);
- __ pop(scratch2); // save old return address
- PushInterceptorArguments(masm(), receiver, holder_reg,
- name_reg, interceptor_holder);
- __ push(scratch2); // restore old return address
-
- ExternalReference ref = ExternalReference(
- IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
- __ TailCallExternalReference(ref, 5, 1);
- }
+ // Return the generated code.
+ return GetCode(NONEXISTENT, Heap::empty_string());
}
-bool StubCompiler::GenerateLoadCallback(JSObject* object,
- JSObject* holder,
- Register receiver,
- Register name_reg,
- Register scratch1,
- Register scratch2,
- Register scratch3,
- AccessorInfo* callback,
- String* name,
- Label* miss,
- Failure** failure) {
- // Check that the receiver isn't a smi.
- __ JumpIfSmi(receiver, miss);
+MaybeObject* LoadStubCompiler::CompileLoadField(JSObject* object,
+ JSObject* holder,
+ int index,
+ String* name) {
+ // ----------- S t a t e -------------
+ // -- rax : receiver
+ // -- rcx : name
+ // -- rsp[0] : return address
+ // -----------------------------------
+ Label miss;
+
+ GenerateLoadField(object, holder, rax, rbx, rdx, rdi, index, name, &miss);
+ __ bind(&miss);
+ GenerateLoadMiss(masm(), Code::LOAD_IC);
+
+ // Return the generated code.
+ return GetCode(FIELD, name);
+}
+
+
+MaybeObject* LoadStubCompiler::CompileLoadCallback(String* name,
+ JSObject* object,
+ JSObject* holder,
+ AccessorInfo* callback) {
+ // ----------- S t a t e -------------
+ // -- rax : receiver
+ // -- rcx : name
+ // -- rsp[0] : return address
+ // -----------------------------------
+ Label miss;
+
+ Failure* failure = Failure::InternalError();
+ bool success = GenerateLoadCallback(object, holder, rax, rcx, rdx, rbx, rdi,
+ callback, name, &miss, &failure);
+ if (!success) {
+ miss.Unuse();
+ return failure;
+ }
+
+ __ bind(&miss);
+ GenerateLoadMiss(masm(), Code::LOAD_IC);
+
+ // Return the generated code.
+ return GetCode(CALLBACKS, name);
+}
+
+
+MaybeObject* LoadStubCompiler::CompileLoadConstant(JSObject* object,
+ JSObject* holder,
+ Object* value,
+ String* name) {
+ // ----------- S t a t e -------------
+ // -- rax : receiver
+ // -- rcx : name
+ // -- rsp[0] : return address
+ // -----------------------------------
+ Label miss;
+
+ GenerateLoadConstant(object, holder, rax, rbx, rdx, rdi, value, name, &miss);
+ __ bind(&miss);
+ GenerateLoadMiss(masm(), Code::LOAD_IC);
+
+ // Return the generated code.
+ return GetCode(CONSTANT_FUNCTION, name);
+}
+
+
+MaybeObject* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
+ JSObject* holder,
+ String* name) {
+ // ----------- S t a t e -------------
+ // -- rax : receiver
+ // -- rcx : name
+ // -- rsp[0] : return address
+ // -----------------------------------
+ Label miss;
+
+ LookupResult lookup;
+ LookupPostInterceptor(holder, name, &lookup);
+
+ // TODO(368): Compile in the whole chain: all the interceptors in
+ // prototypes and ultimate answer.
+ GenerateLoadInterceptor(receiver,
+ holder,
+ &lookup,
+ rax,
+ rcx,
+ rdx,
+ rbx,
+ rdi,
+ name,
+ &miss);
+
+ __ bind(&miss);
+ GenerateLoadMiss(masm(), Code::LOAD_IC);
+
+ // Return the generated code.
+ return GetCode(INTERCEPTOR, name);
+}
+
+
+MaybeObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
+ GlobalObject* holder,
+ JSGlobalPropertyCell* cell,
+ String* name,
+ bool is_dont_delete) {
+ // ----------- S t a t e -------------
+ // -- rax : receiver
+ // -- rcx : name
+ // -- rsp[0] : return address
+ // -----------------------------------
+ Label miss;
+
+ // If the object is the holder then we know that it's a global
+ // object which can only happen for contextual loads. In this case,
+ // the receiver cannot be a smi.
+ if (object != holder) {
+ __ JumpIfSmi(rax, &miss);
+ }
// Check that the maps haven't changed.
- Register reg =
- CheckPrototypes(object, receiver, holder, scratch1,
- scratch2, scratch3, name, miss);
+ CheckPrototypes(object, rax, holder, rbx, rdx, rdi, name, &miss);
- Handle<AccessorInfo> callback_handle(callback);
+ // Get the value from the cell.
+ __ Move(rbx, Handle<JSGlobalPropertyCell>(cell));
+ __ movq(rbx, FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset));
- // Insert additional parameters into the stack frame above return address.
- ASSERT(!scratch2.is(reg));
- __ pop(scratch2); // Get return address to place it below.
-
- __ push(receiver); // receiver
- __ push(reg); // holder
- if (Heap::InNewSpace(callback_handle->data())) {
- __ Move(scratch1, callback_handle);
- __ push(FieldOperand(scratch1, AccessorInfo::kDataOffset)); // data
- } else {
- __ Push(Handle<Object>(callback_handle->data()));
- }
- __ push(name_reg); // name
- // Save a pointer to where we pushed the arguments pointer.
- // This will be passed as the const AccessorInfo& to the C++ callback.
-
-#ifdef _WIN64
- // Win64 uses first register--rcx--for returned value.
- Register accessor_info_arg = r8;
- Register name_arg = rdx;
-#else
- Register accessor_info_arg = rsi;
- Register name_arg = rdi;
-#endif
-
- ASSERT(!name_arg.is(scratch2));
- __ movq(name_arg, rsp);
- __ push(scratch2); // Restore return address.
-
- // Do call through the api.
- Address getter_address = v8::ToCData<Address>(callback->getter());
- ApiFunction fun(getter_address);
-
- // 3 elements array for v8::Agruments::values_ and handler for name.
- const int kStackSpace = 4;
-
- // Allocate v8::AccessorInfo in non-GCed stack space.
- const int kArgStackSpace = 1;
-
- __ PrepareCallApiFunction(kArgStackSpace);
- __ lea(rax, Operand(name_arg, 3 * kPointerSize));
-
- // v8::AccessorInfo::args_.
- __ movq(StackSpaceOperand(0), rax);
-
- // The context register (rsi) has been saved in PrepareCallApiFunction and
- // could be used to pass arguments.
- __ lea(accessor_info_arg, StackSpaceOperand(0));
-
- // Emitting a stub call may try to allocate (if the code is not
- // already generated). Do not allow the assembler to perform a
- // garbage collection but instead return the allocation failure
- // object.
- MaybeObject* result = masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace);
- if (result->IsFailure()) {
- *failure = Failure::cast(result);
- return false;
- }
- return true;
-}
-
-
-Register StubCompiler::CheckPrototypes(JSObject* object,
- Register object_reg,
- JSObject* holder,
- Register holder_reg,
- Register scratch1,
- Register scratch2,
- String* name,
- int save_at_depth,
- Label* miss) {
- // Make sure there's no overlap between holder and object registers.
- ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
- ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
- && !scratch2.is(scratch1));
-
- // Keep track of the current object in register reg. On the first
- // iteration, reg is an alias for object_reg, on later iterations,
- // it is an alias for holder_reg.
- Register reg = object_reg;
- int depth = 0;
-
- if (save_at_depth == depth) {
- __ movq(Operand(rsp, kPointerSize), object_reg);
+ // Check for deleted property if property can actually be deleted.
+ if (!is_dont_delete) {
+ __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
+ __ j(equal, &miss);
+ } else if (FLAG_debug_code) {
+ __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
+ __ Check(not_equal, "DontDelete cells can't contain the hole");
}
- // Check the maps in the prototype chain.
- // Traverse the prototype chain from the object and do map checks.
- JSObject* current = object;
- while (current != holder) {
- depth++;
-
- // Only global objects and objects that do not require access
- // checks are allowed in stubs.
- ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
-
- JSObject* prototype = JSObject::cast(current->GetPrototype());
- if (!current->HasFastProperties() &&
- !current->IsJSGlobalObject() &&
- !current->IsJSGlobalProxy()) {
- if (!name->IsSymbol()) {
- MaybeObject* lookup_result = Heap::LookupSymbol(name);
- if (lookup_result->IsFailure()) {
- set_failure(Failure::cast(lookup_result));
- return reg;
- } else {
- name = String::cast(lookup_result->ToObjectUnchecked());
- }
- }
- ASSERT(current->property_dictionary()->FindEntry(name) ==
- StringDictionary::kNotFound);
-
- GenerateDictionaryNegativeLookup(masm(),
- miss,
- reg,
- name,
- scratch1,
- scratch2);
- __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
- reg = holder_reg; // from now the object is in holder_reg
- __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
- } else if (Heap::InNewSpace(prototype)) {
- // Get the map of the current object.
- __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
- __ Cmp(scratch1, Handle<Map>(current->map()));
- // Branch on the result of the map check.
- __ j(not_equal, miss);
- // Check access rights to the global object. This has to happen
- // after the map check so that we know that the object is
- // actually a global object.
- if (current->IsJSGlobalProxy()) {
- __ CheckAccessGlobalProxy(reg, scratch1, miss);
-
- // Restore scratch register to be the map of the object.
- // We load the prototype from the map in the scratch register.
- __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
- }
- // The prototype is in new space; we cannot store a reference
- // to it in the code. Load it from the map.
- reg = holder_reg; // from now the object is in holder_reg
- __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
-
- } else {
- // Check the map of the current object.
- __ Cmp(FieldOperand(reg, HeapObject::kMapOffset),
- Handle<Map>(current->map()));
- // Branch on the result of the map check.
- __ j(not_equal, miss);
- // Check access rights to the global object. This has to happen
- // after the map check so that we know that the object is
- // actually a global object.
- if (current->IsJSGlobalProxy()) {
- __ CheckAccessGlobalProxy(reg, scratch1, miss);
- }
- // The prototype is in old space; load it directly.
- reg = holder_reg; // from now the object is in holder_reg
- __ Move(reg, Handle<JSObject>(prototype));
- }
-
- if (save_at_depth == depth) {
- __ movq(Operand(rsp, kPointerSize), reg);
- }
-
- // Go to the next object in the prototype chain.
- current = prototype;
- }
-
- // Check the holder map.
- __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), Handle<Map>(holder->map()));
- __ j(not_equal, miss);
-
- // Log the check depth.
- LOG(IntEvent("check-maps-depth", depth + 1));
-
- // Perform security check for access to the global object and return
- // the holder register.
- ASSERT(current == holder);
- ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
- if (current->IsJSGlobalProxy()) {
- __ CheckAccessGlobalProxy(reg, scratch1, miss);
- }
-
- // If we've skipped any global objects, it's not enough to verify
- // that their maps haven't changed. We also need to check that the
- // property cell for the property is still empty.
- current = object;
- while (current != holder) {
- if (current->IsGlobalObject()) {
- MaybeObject* cell = GenerateCheckPropertyCell(masm(),
- GlobalObject::cast(current),
- name,
- scratch1,
- miss);
- if (cell->IsFailure()) {
- set_failure(Failure::cast(cell));
- return reg;
- }
- }
- current = JSObject::cast(current->GetPrototype());
- }
-
- // Return the register containing the holder.
- return reg;
-}
-
-
-void StubCompiler::GenerateLoadField(JSObject* object,
- JSObject* holder,
- Register receiver,
- Register scratch1,
- Register scratch2,
- Register scratch3,
- int index,
- String* name,
- Label* miss) {
- // Check that the receiver isn't a smi.
- __ JumpIfSmi(receiver, miss);
-
- // Check the prototype chain.
- Register reg =
- CheckPrototypes(object, receiver, holder,
- scratch1, scratch2, scratch3, name, miss);
-
- // Get the value from the properties.
- GenerateFastPropertyLoad(masm(), rax, reg, holder, index);
+ __ IncrementCounter(&Counters::named_load_global_stub, 1);
+ __ movq(rax, rbx);
__ ret(0);
+
+ __ bind(&miss);
+ __ IncrementCounter(&Counters::named_load_global_stub_miss, 1);
+ GenerateLoadMiss(masm(), Code::LOAD_IC);
+
+ // Return the generated code.
+ return GetCode(NORMAL, name);
}
-void StubCompiler::GenerateLoadConstant(JSObject* object,
- JSObject* holder,
- Register receiver,
- Register scratch1,
- Register scratch2,
- Register scratch3,
- Object* value,
- String* name,
- Label* miss) {
+MaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name,
+ JSObject* receiver,
+ JSObject* holder,
+ int index) {
+ // ----------- S t a t e -------------
+ // -- rax : key
+ // -- rdx : receiver
+ // -- rsp[0] : return address
+ // -----------------------------------
+ Label miss;
+
+ __ IncrementCounter(&Counters::keyed_load_field, 1);
+
+ // Check that the name has not changed.
+ __ Cmp(rax, Handle<String>(name));
+ __ j(not_equal, &miss);
+
+ GenerateLoadField(receiver, holder, rdx, rbx, rcx, rdi, index, name, &miss);
+
+ __ bind(&miss);
+ __ DecrementCounter(&Counters::keyed_load_field, 1);
+ GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+
+ // Return the generated code.
+ return GetCode(FIELD, name);
+}
+
+
+MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback(
+ String* name,
+ JSObject* receiver,
+ JSObject* holder,
+ AccessorInfo* callback) {
+ // ----------- S t a t e -------------
+ // -- rax : key
+ // -- rdx : receiver
+ // -- rsp[0] : return address
+ // -----------------------------------
+ Label miss;
+
+ __ IncrementCounter(&Counters::keyed_load_callback, 1);
+
+ // Check that the name has not changed.
+ __ Cmp(rax, Handle<String>(name));
+ __ j(not_equal, &miss);
+
+ Failure* failure = Failure::InternalError();
+ bool success = GenerateLoadCallback(receiver, holder, rdx, rax, rbx, rcx, rdi,
+ callback, name, &miss, &failure);
+ if (!success) {
+ miss.Unuse();
+ return failure;
+ }
+
+ __ bind(&miss);
+
+ __ DecrementCounter(&Counters::keyed_load_callback, 1);
+ GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+
+ // Return the generated code.
+ return GetCode(CALLBACKS, name);
+}
+
+
+MaybeObject* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
+ JSObject* receiver,
+ JSObject* holder,
+ Object* value) {
+ // ----------- S t a t e -------------
+ // -- rax : key
+ // -- rdx : receiver
+ // -- rsp[0] : return address
+ // -----------------------------------
+ Label miss;
+
+ __ IncrementCounter(&Counters::keyed_load_constant_function, 1);
+
+ // Check that the name has not changed.
+ __ Cmp(rax, Handle<String>(name));
+ __ j(not_equal, &miss);
+
+ GenerateLoadConstant(receiver, holder, rdx, rbx, rcx, rdi,
+ value, name, &miss);
+ __ bind(&miss);
+ __ DecrementCounter(&Counters::keyed_load_constant_function, 1);
+ GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+
+ // Return the generated code.
+ return GetCode(CONSTANT_FUNCTION, name);
+}
+
+
+MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
+ JSObject* holder,
+ String* name) {
+ // ----------- S t a t e -------------
+ // -- rax : key
+ // -- rdx : receiver
+ // -- rsp[0] : return address
+ // -----------------------------------
+ Label miss;
+
+ __ IncrementCounter(&Counters::keyed_load_interceptor, 1);
+
+ // Check that the name has not changed.
+ __ Cmp(rax, Handle<String>(name));
+ __ j(not_equal, &miss);
+
+ LookupResult lookup;
+ LookupPostInterceptor(holder, name, &lookup);
+ GenerateLoadInterceptor(receiver,
+ holder,
+ &lookup,
+ rdx,
+ rax,
+ rcx,
+ rbx,
+ rdi,
+ name,
+ &miss);
+ __ bind(&miss);
+ __ DecrementCounter(&Counters::keyed_load_interceptor, 1);
+ GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+
+ // Return the generated code.
+ return GetCode(INTERCEPTOR, name);
+}
+
+
+MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
+ // ----------- S t a t e -------------
+ // -- rax : key
+ // -- rdx : receiver
+ // -- rsp[0] : return address
+ // -----------------------------------
+ Label miss;
+
+ __ IncrementCounter(&Counters::keyed_load_array_length, 1);
+
+ // Check that the name has not changed.
+ __ Cmp(rax, Handle<String>(name));
+ __ j(not_equal, &miss);
+
+ GenerateLoadArrayLength(masm(), rdx, rcx, &miss);
+ __ bind(&miss);
+ __ DecrementCounter(&Counters::keyed_load_array_length, 1);
+ GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+
+ // Return the generated code.
+ return GetCode(CALLBACKS, name);
+}
+
+
+MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
+ // ----------- S t a t e -------------
+ // -- rax : key
+ // -- rdx : receiver
+ // -- rsp[0] : return address
+ // -----------------------------------
+ Label miss;
+
+ __ IncrementCounter(&Counters::keyed_load_string_length, 1);
+
+ // Check that the name has not changed.
+ __ Cmp(rax, Handle<String>(name));
+ __ j(not_equal, &miss);
+
+ GenerateLoadStringLength(masm(), rdx, rcx, rbx, &miss);
+ __ bind(&miss);
+ __ DecrementCounter(&Counters::keyed_load_string_length, 1);
+ GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+
+ // Return the generated code.
+ return GetCode(CALLBACKS, name);
+}
+
+
+MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
+ // ----------- S t a t e -------------
+ // -- rax : key
+ // -- rdx : receiver
+ // -- rsp[0] : return address
+ // -----------------------------------
+ Label miss;
+
+ __ IncrementCounter(&Counters::keyed_load_function_prototype, 1);
+
+ // Check that the name has not changed.
+ __ Cmp(rax, Handle<String>(name));
+ __ j(not_equal, &miss);
+
+ GenerateLoadFunctionPrototype(masm(), rdx, rcx, rbx, &miss);
+ __ bind(&miss);
+ __ DecrementCounter(&Counters::keyed_load_function_prototype, 1);
+ GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+
+ // Return the generated code.
+ return GetCode(CALLBACKS, name);
+}
+
+
+MaybeObject* KeyedLoadStubCompiler::CompileLoadSpecialized(JSObject* receiver) {
+ // ----------- S t a t e -------------
+ // -- rax : key
+ // -- rdx : receiver
+ // -- esp[0] : return address
+ // -----------------------------------
+ Label miss;
+
// Check that the receiver isn't a smi.
- __ JumpIfSmi(receiver, miss);
+ __ JumpIfSmi(rdx, &miss);
- // Check that the maps haven't changed.
- Register reg =
- CheckPrototypes(object, receiver, holder,
- scratch1, scratch2, scratch3, name, miss);
+ // Check that the map matches.
+ __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
+ Handle<Map>(receiver->map()));
+ __ j(not_equal, &miss);
- // Return the constant value.
- __ Move(rax, Handle<Object>(value));
+ // Check that the key is a smi.
+ __ JumpIfNotSmi(rax, &miss);
+
+ // Get the elements array.
+ __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
+ __ AssertFastElements(rcx);
+
+ // Check that the key is within bounds.
+ __ SmiCompare(rax, FieldOperand(rcx, FixedArray::kLengthOffset));
+ __ j(above_equal, &miss);
+
+ // Load the result and make sure it's not the hole.
+ SmiIndex index = masm()->SmiToIndex(rbx, rax, kPointerSizeLog2);
+ __ movq(rbx, FieldOperand(rcx,
+ index.reg,
+ index.scale,
+ FixedArray::kHeaderSize));
+ __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
+ __ j(equal, &miss);
+ __ movq(rax, rbx);
__ ret(0);
+
+ __ bind(&miss);
+ GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+
+ // Return the generated code.
+ return GetCode(NORMAL, NULL);
}