diff options
author | Steve Block <steveblock@google.com> | 2011-05-12 15:51:54 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2011-05-12 16:12:25 +0100 |
commit | 9fac840a46e8b7e26894f4792ba26dde14c56b04 (patch) | |
tree | 0b8b71befb5175abac552daa0d084fc51c1090b8 | |
parent | b0fe1620dcb4135ac3ab2d66ff93072373911299 (diff) | |
download | android_external_v8-9fac840a46e8b7e26894f4792ba26dde14c56b04.tar.gz android_external_v8-9fac840a46e8b7e26894f4792ba26dde14c56b04.tar.bz2 android_external_v8-9fac840a46e8b7e26894f4792ba26dde14c56b04.zip |
Update V8 to r6190 as required by WebKit r75315
Change-Id: I0b2f598e4d8748df417ad350fc47a1c465ad1fef
111 files changed, 5040 insertions, 4075 deletions
@@ -1,3 +1,28 @@ +2010-01-05: 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). + + +2011-01-03: Version 3.0.5 + + Fixed a couple of cast errors for gcc-3.4.3. + + Performance improvements in GC and IA32 code generator. + + 2010-12-21: Version 3.0.4 Added Date::ResetCache() to the API so that the cached values in the diff --git a/V8_MERGE_REVISION b/V8_MERGE_REVISION index afd88f3d..e9ea6594 100644 --- a/V8_MERGE_REVISION +++ b/V8_MERGE_REVISION @@ -1,5 +1,7 @@ We use a V8 revision that has been used for a Chromium release. -http://src.chromium.org/svn/releases/10.0.621.0/DEPS -http://v8.googlecode.com/svn/trunk@6101 (+ 1 cherry pick from r6346 in src/v8utils.h to fix compile on Android) +http://src.chromium.org/svn/releases/10.0.634.0/DEPS +http://v8.googlecode.com/svn/trunk@6190 plus two partial cherry-picks to fix Android build ... +- r6346 - include platform.h in src/v8utils.h +- r7077 - CreateThread() in src/platform-linux.cc diff --git a/include/v8.h b/include/v8.h index 2c0f3508..883bfad9 100644 --- a/include/v8.h +++ b/include/v8.h @@ -1651,9 +1651,9 @@ class Object : public Value { * the backing store is preserved while V8 has a reference. */ V8EXPORT void SetIndexedPropertiesToPixelData(uint8_t* data, int length); - bool HasIndexedPropertiesInPixelData(); - uint8_t* GetIndexedPropertiesPixelData(); - int GetIndexedPropertiesPixelDataLength(); + V8EXPORT bool HasIndexedPropertiesInPixelData(); + V8EXPORT uint8_t* GetIndexedPropertiesPixelData(); + V8EXPORT int GetIndexedPropertiesPixelDataLength(); /** * Set the backing store of the indexed properties to be managed by the @@ -1666,10 +1666,10 @@ class Object : public Value { void* data, ExternalArrayType array_type, int number_of_elements); - bool HasIndexedPropertiesInExternalArrayData(); - void* GetIndexedPropertiesExternalArrayData(); - ExternalArrayType GetIndexedPropertiesExternalArrayDataType(); - int GetIndexedPropertiesExternalArrayDataLength(); + V8EXPORT bool HasIndexedPropertiesInExternalArrayData(); + V8EXPORT void* GetIndexedPropertiesExternalArrayData(); + V8EXPORT ExternalArrayType GetIndexedPropertiesExternalArrayDataType(); + V8EXPORT int GetIndexedPropertiesExternalArrayDataLength(); V8EXPORT static Local<Object> New(); static inline Object* Cast(Value* obj); @@ -3076,6 +3076,18 @@ class V8EXPORT Context { * Returns a persistent handle to the newly allocated context. This * persistent handle has to be disposed when the context is no * longer used so the context can be garbage collected. + * + * \param extensions An optional extension configuration containing + * the extensions to be installed in the newly created context. + * + * \param global_template An optional object template from which the + * global object for the newly created context will be created. + * + * \param global_object An optional global object to be reused for + * the newly created context. This global object must have been + * created by a previous call to Context::New with the same global + * template. The state of the global object will be completely reset + * and only object identify will remain. */ static Persistent<Context> New( ExtensionConfiguration* extensions = NULL, diff --git a/src/SConscript b/src/SConscript index dfa099cb..b1f9bb61 100755 --- a/src/SConscript +++ b/src/SConscript @@ -229,9 +229,10 @@ SOURCES = { 'os:win32': ['platform-win32.cc'], 'mode:release': [], 'mode:debug': [ - 'objects-debug.cc', 'prettyprinter.cc', 'regexp-macro-assembler-tracer.cc' + 'objects-debug.cc', 'objects-printer.cc', 'prettyprinter.cc', + 'regexp-macro-assembler-tracer.cc' ], - 'objectprint:on': ['objects-debug.cc'] + 'objectprint:on': ['objects-printer.cc'] } diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h index 36f7507f..cd7f07f0 100644 --- a/src/arm/assembler-arm.h +++ b/src/arm/assembler-arm.h @@ -66,13 +66,14 @@ namespace internal { // 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 r5 = { 5 }; 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 5ec8584f..577ac633 100644 --- a/src/arm/code-stubs-arm.cc +++ b/src/arm/code-stubs-arm.cc @@ -917,13 +917,6 @@ void NumberToStringStub::Generate(MacroAssembler* masm) { } -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 @@ void GenericBinaryOpStub::HandleBinaryOpSlowCases( 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 @@ void GenericBinaryOpStub::HandleBinaryOpSlowCases( // 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. @@ -2894,45 +2894,45 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { // Uses registers r0 to r4. Expected input is -// function in r0 (or at sp+1*ptrsz) and object in +// object in r0 (or at sp+1*kPointerSize) and function in // r1 (or at sp), depending on whether or not // args_in_registers() is true. void InstanceofStub::Generate(MacroAssembler* masm) { // Fixed register usage throughout the stub: - const Register object = r1; // Object (lhs). + const Register object = r0; // Object (lhs). const Register map = r3; // Map of the object. - const Register function = r0; // Function (rhs). + const Register function = r1; // Function (rhs). const Register prototype = r4; // Prototype of the function. const Register scratch = r2; Label slow, loop, is_instance, is_not_instance, not_js_object; if (!args_in_registers()) { - __ ldr(function, MemOperand(sp, 1 * kPointerSize)); - __ ldr(object, MemOperand(sp, 0)); + __ ldr(object, MemOperand(sp, 1 * kPointerSize)); + __ ldr(function, MemOperand(sp, 0)); } // Check that the left hand is a JS object and load map. - __ BranchOnSmi(object, &slow); - __ IsObjectJSObjectType(object, map, scratch, &slow); + __ BranchOnSmi(object, ¬_js_object); + __ IsObjectJSObjectType(object, map, scratch, ¬_js_object); // Look up the function and the map in the instanceof cache. Label miss; __ LoadRoot(ip, Heap::kInstanceofCacheFunctionRootIndex); - __ cmp(object, ip); + __ cmp(function, ip); __ b(ne, &miss); __ LoadRoot(ip, Heap::kInstanceofCacheMapRootIndex); __ cmp(map, ip); __ b(ne, &miss); - __ LoadRoot(function, Heap::kInstanceofCacheAnswerRootIndex); + __ LoadRoot(r0, Heap::kInstanceofCacheAnswerRootIndex); __ Ret(args_in_registers() ? 0 : 2); __ bind(&miss); - __ TryGetFunctionPrototype(object, prototype, scratch, &slow); + __ TryGetFunctionPrototype(function, prototype, scratch, &slow); // Check that the function prototype is a JS object. __ BranchOnSmi(prototype, &slow); __ IsObjectJSObjectType(prototype, scratch, scratch, &slow); - __ StoreRoot(object, Heap::kInstanceofCacheFunctionRootIndex); + __ StoreRoot(function, Heap::kInstanceofCacheFunctionRootIndex); __ StoreRoot(map, Heap::kInstanceofCacheMapRootIndex); // Register mapping: r3 is object map and r4 is function prototype. @@ -2957,6 +2957,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) { __ bind(&is_not_instance); __ mov(r0, Operand(Smi::FromInt(1))); + __ StoreRoot(r0, Heap::kInstanceofCacheAnswerRootIndex); __ Ret(args_in_registers() ? 0 : 2); Label object_not_null, object_not_null_or_smi; @@ -2986,6 +2987,9 @@ void InstanceofStub::Generate(MacroAssembler* masm) { __ Ret(args_in_registers() ? 0 : 2); // Slow-case. Tail call builtin. + if (args_in_registers()) { + __ Push(r0, r1); + } __ bind(&slow); __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_JS); } diff --git a/src/arm/code-stubs-arm.h b/src/arm/code-stubs-arm.h index 8ffca773..9fa86879 100644 --- a/src/arm/code-stubs-arm.h +++ b/src/arm/code-stubs-arm.h @@ -77,7 +77,7 @@ class GenericBinaryOpStub : public CodeStub { 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 @@ class GenericBinaryOpStub : public CodeStub { 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 NumberToStringStub: public CodeStub { }; -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 59bc14e7..4d061d23 100644 --- a/src/arm/codegen-arm.cc +++ b/src/arm/codegen-arm.cc @@ -5618,12 +5618,10 @@ void CodeGenerator::GenerateSwapElements(ZoneList<Expression*>* args) { // (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 d2549183..0275730a 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 e31d2e1d..87efc92c 100644 --- a/src/arm/lithium-arm.cc +++ b/src/arm/lithium-arm.cc @@ -767,11 +767,6 @@ LInstruction* LChunkBuilder::DefineAsSpilled(LInstruction* instr, int index) { } -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 @@ void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) { 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* LChunkBuilder::CreateEnvironment(HEnvironment* hydrogen_env) { 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 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) { ASSERT(compare->value()->representation().IsTagged()); return new LHasInstanceTypeAndBranch(UseRegisterAtStart(compare->value()), - TempRegister(), first_id, second_id); } else if (v->IsHasCachedArrayIndex()) { @@ -1238,11 +1229,8 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) { 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 @@ LInstruction* LChunkBuilder::DoCompareMapAndBranch( 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); } @@ -1316,8 +1300,8 @@ LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) { LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) { LInstruction* result = - new LInstanceOf(UseFixed(instr->left(), r1), - UseFixed(instr->right(), r0)); + new LInstanceOf(UseFixed(instr->left(), r0), + UseFixed(instr->right(), r1)); return MarkAsCall(DefineFixed(result, r0), instr); } @@ -1370,6 +1354,9 @@ LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) { 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; @@ -1666,19 +1653,15 @@ LInstruction* LChunkBuilder::DoClassOfTest(HClassOfTest* instr) { } -LInstruction* LChunkBuilder::DoArrayLength(HArrayLength* instr) { - LOperand* array = NULL; - LOperand* temporary = NULL; +LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) { + LOperand* array = UseRegisterAtStart(instr->value()); + return DefineAsRegister(new LJSArrayLength(array)); +} - if (instr->value()->IsLoadElements()) { - array = UseRegisterAtStart(instr->value()); - } else { - array = UseRegister(instr->value()); - temporary = TempRegister(); - } - LInstruction* result = new LArrayLength(array, temporary); - return AssignEnvironment(DefineAsRegister(result)); +LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) { + LOperand* array = UseRegisterAtStart(instr->value()); + return DefineAsRegister(new LFixedArrayLength(array)); } @@ -1778,9 +1761,11 @@ LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) { 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); @@ -1854,6 +1839,13 @@ LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) { } +LInstruction* LChunkBuilder::DoLoadFunctionPrototype( + HLoadFunctionPrototype* instr) { + return AssignEnvironment(DefineAsRegister( + new LLoadFunctionPrototype(UseRegister(instr->function())))); +} + + LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) { LOperand* input = UseRegisterAtStart(instr->value()); return DefineSameAsFirst(new LLoadElements(input)); @@ -2054,13 +2046,7 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) { } } - 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 41209c67..2f8cc1c7 100644 --- a/src/arm/lithium-arm.h +++ b/src/arm/lithium-arm.h @@ -101,7 +101,8 @@ class Translation; // LStoreNamedField // LStoreNamedGeneric // LUnaryOperation -// LArrayLength +// LJSArrayLength +// LFixedArrayLength // LBitNotI // LBranch // LCallNew @@ -127,6 +128,7 @@ class Translation; // LIsSmiAndBranch // LLoadNamedField // LLoadNamedGeneric +// LLoadFunctionPrototype // LNumberTagD // LNumberTagI // LPushArgument @@ -161,7 +163,6 @@ class Translation; V(ArgumentsLength) \ V(ArithmeticD) \ V(ArithmeticT) \ - V(ArrayLength) \ V(ArrayLiteral) \ V(BitI) \ V(BitNotI) \ @@ -195,6 +196,7 @@ class Translation; V(Deoptimize) \ V(DivI) \ V(DoubleToI) \ + V(FixedArrayLength) \ V(FunctionLiteral) \ V(Gap) \ V(GlobalObject) \ @@ -209,6 +211,7 @@ class Translation; V(IsObjectAndBranch) \ V(IsSmi) \ V(IsSmiAndBranch) \ + V(JSArrayLength) \ V(HasInstanceType) \ V(HasInstanceTypeAndBranch) \ V(HasCachedArrayIndex) \ @@ -223,6 +226,7 @@ class Translation; V(LoadKeyedGeneric) \ V(LoadNamedField) \ V(LoadNamedGeneric) \ + V(LoadFunctionPrototype) \ V(ModI) \ V(MulI) \ V(NumberTagD) \ @@ -722,11 +726,9 @@ class LIsNullAndBranch: public LIsNull { 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) { } @@ -737,10 +739,7 @@ class LIsNullAndBranch: public LIsNull { 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_; }; @@ -835,11 +834,9 @@ class LHasInstanceType: public LUnaryOperation { 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) { } @@ -851,10 +848,7 @@ class LHasInstanceTypeAndBranch: public LHasInstanceType { 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_; }; @@ -1117,42 +1111,43 @@ class LBranch: public LUnaryOperation { 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_; }; -class LArrayLength: public LUnaryOperation { +class LJSArrayLength: public LUnaryOperation { public: - LArrayLength(LOperand* input, LOperand* temporary) - : LUnaryOperation(input), temporary_(temporary) { } + explicit LJSArrayLength(LOperand* input) : LUnaryOperation(input) { } - LOperand* temporary() const { return temporary_; } + DECLARE_CONCRETE_INSTRUCTION(JSArrayLength, "js-array-length") + DECLARE_HYDROGEN_ACCESSOR(JSArrayLength) +}; - DECLARE_CONCRETE_INSTRUCTION(ArrayLength, "array-length") - DECLARE_HYDROGEN_ACCESSOR(ArrayLength) - private: - LOperand* temporary_; +class LFixedArrayLength: public LUnaryOperation { + public: + explicit LFixedArrayLength(LOperand* input) : LUnaryOperation(input) { } + + DECLARE_CONCRETE_INSTRUCTION(FixedArrayLength, "fixed-array-length") + DECLARE_HYDROGEN_ACCESSOR(FixedArrayLength) }; @@ -1256,6 +1251,18 @@ class LLoadNamedGeneric: public LUnaryOperation { }; +class LLoadFunctionPrototype: public LUnaryOperation { + public: + explicit LLoadFunctionPrototype(LOperand* function) + : LUnaryOperation(function) { } + + DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype, "load-function-prototype") + DECLARE_HYDROGEN_ACCESSOR(LoadFunctionPrototype) + + LOperand* function() const { return input(); } +}; + + class LLoadElements: public LUnaryOperation { public: explicit LLoadElements(LOperand* obj) : LUnaryOperation(obj) { } @@ -1655,21 +1662,25 @@ class LCheckMap: public LUnaryOperation { 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_; }; @@ -2051,7 +2062,6 @@ class LChunkBuilder BASE_EMBEDDED { 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 dfc48917..bb2461ce 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -598,7 +598,7 @@ void LCodeGen::DoParallelMove(LParallelMove* move) { 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::DoParameter(LParameter* instr) { 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::DoDivI(LDivI* instr) { 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::DoBitI(LBitI* instr) { 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 @@ void LCodeGen::DoShiftI(LShiftI* instr) { 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(); @@ -898,24 +945,18 @@ void LCodeGen::DoConstantT(LConstantT* instr) { } -void LCodeGen::DoArrayLength(LArrayLength* instr) { +void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) { Register result = ToRegister(instr->result()); + Register array = ToRegister(instr->input()); + __ ldr(result, FieldMemOperand(array, JSArray::kLengthOffset)); +} - if (instr->hydrogen()->value()->IsLoadElements()) { - // We load the length directly from the elements array. - Register elements = ToRegister(instr->input()); - __ ldr(result, FieldMemOperand(elements, FixedArray::kLengthOffset)); - } else { - // Check that the receiver really is an array. - Register array = ToRegister(instr->input()); - Register temporary = ToRegister(instr->temporary()); - __ CompareObjectType(array, temporary, temporary, JS_ARRAY_TYPE); - DeoptimizeIf(ne, instr->environment()); - // Load length directly from the array. - __ ldr(result, FieldMemOperand(array, JSArray::kLengthOffset)); - } - Abort("DoArrayLength untested."); +void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) { + Register result = ToRegister(instr->result()); + Register array = ToRegister(instr->input()); + __ ldr(result, FieldMemOperand(array, FixedArray::kLengthOffset)); + Abort("DoFixedArrayLength untested."); } @@ -1065,11 +1106,10 @@ void LCodeGen::DoBranch(LBranch* instr) { // 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); @@ -1176,11 +1216,41 @@ void LCodeGen::DoCmpJSObjectEqAndBranch(LCmpJSObjectEqAndBranch* instr) { 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 @@ -1204,7 +1274,6 @@ void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) { __ 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)); @@ -1282,8 +1351,8 @@ void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) { 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()); @@ -1293,7 +1362,7 @@ void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { __ 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()); } @@ -1332,19 +1401,28 @@ void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { 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); } void LCodeGen::DoInstanceOf(LInstanceOf* instr) { - // We expect object and function in registers r1 and r0. + ASSERT(ToRegister(instr->left()).is(r0)); // Object is in r0. + ASSERT(ToRegister(instr->right()).is(r1)); // Function is in r1. + InstanceofStub stub(InstanceofStub::kArgsInRegisters); CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); Label true_value, done; __ tst(r0, r0); - __ mov(r0, Operand(Factory::false_value()), LeaveCC, eq); - __ mov(r0, Operand(Factory::true_value()), LeaveCC, ne); + __ mov(r0, Operand(Factory::false_value()), LeaveCC, ne); + __ mov(r0, Operand(Factory::true_value()), LeaveCC, eq); } @@ -1432,7 +1510,14 @@ void LCodeGen::DoStoreGlobal(LStoreGlobal* instr) { 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())); + } } @@ -1447,6 +1532,50 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { } +void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) { + Register scratch = scratch0(); + Register function = ToRegister(instr->function()); + Register result = ToRegister(instr->result()); + + // Check that the function really is a function. Load map into the + // result register. + __ CompareObjectType(function, result, scratch, JS_FUNCTION_TYPE); + DeoptimizeIf(ne, instr->environment()); + + // Make sure that the function has an instance prototype. + Label non_instance; + __ 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. + __ ldr(result, + FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); + + // Check that the function has a prototype or an initial map. + __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); + __ cmp(result, ip); + DeoptimizeIf(eq, instr->environment()); + + // If the function does not have an initial map, we're done. + Label done; + __ CompareObjectType(result, scratch, scratch, MAP_TYPE); + __ b(ne, &done); + + // Get the prototype from the initial map. + __ ldr(result, FieldMemOperand(result, Map::kPrototypeOffset)); + __ jmp(&done); + + // Non-instance prototype: Fetch prototype from constructor field + // in initial map. + __ bind(&non_instance); + __ ldr(result, FieldMemOperand(result, Map::kConstructorOffset)); + + // All done. + __ bind(&done); +} + + void LCodeGen::DoLoadElements(LLoadElements* instr) { Abort("DoLoadElements unimplemented."); } @@ -1544,7 +1673,9 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function, 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); } @@ -1604,7 +1735,13 @@ void LCodeGen::DoCallNamed(LCallNamed* instr) { 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)); } @@ -1652,7 +1789,8 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { - Abort("DoBoundsCheck unimplemented."); + __ cmp(ToRegister(instr->index()), ToOperand(instr->length())); + DeoptimizeIf(hs, instr->environment()); } @@ -1757,10 +1895,10 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) { }; 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) { @@ -1808,8 +1946,7 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) { 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)); @@ -1820,9 +1957,9 @@ void LCodeGen::EmitNumberUntagD(Register input_reg, __ 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); @@ -1864,16 +2001,15 @@ class DeferredTaggedToI: public LDeferredCode { 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; @@ -1985,33 +2121,99 @@ void LCodeGen::DoCheckFunction(LCheckFunction* instr) { 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); + } } @@ -2056,8 +2258,7 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, 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); @@ -2073,7 +2274,7 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, __ 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())) { @@ -2099,10 +2300,10 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, } 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())) { @@ -2112,16 +2313,16 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, __ 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 541a6996..608efa9e 100644 --- a/src/arm/lithium-codegen-arm.h +++ b/src/arm/lithium-codegen-arm.h @@ -103,6 +103,8 @@ class LCodeGen BASE_EMBEDDED { HGraph* graph() const { return chunk_->graph(); } MacroAssembler* masm() const { return masm_; } + Register scratch0() { return r9; } + int GetNextEmittedBlock(int block); LInstruction* GetNextInstruction(); @@ -517,6 +517,9 @@ void Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) { if (key()->IsPropertyName()) { if (oracle->LoadIsBuiltin(this, Builtins::LoadIC_ArrayLength)) { is_array_length_ = true; + } else if (oracle->LoadIsBuiltin(this, + Builtins::LoadIC_FunctionPrototype)) { + is_function_prototype_ = true; } else { Literal* lit_key = key()->AsLiteral(); ASSERT(lit_key != NULL && lit_key->handle()->IsString()); @@ -1208,6 +1208,7 @@ class Property: public Expression { is_monomorphic_(false), receiver_types_(NULL), is_array_length_(false), + is_function_prototype_(false), is_arguments_access_(false) { } DECLARE_NODE_TYPE(Property) @@ -1220,6 +1221,8 @@ class Property: public Expression { int position() const { return pos_; } bool is_synthetic() const { return type_ == SYNTHETIC; } + bool IsFunctionPrototype() const { return is_function_prototype_; } + // Marks that this is actually an argument rewritten to a keyed property // accessing the argument through the arguments shadow object. void set_is_arguments_access(bool is_arguments_access) { @@ -1249,6 +1252,7 @@ class Property: public Expression { bool is_monomorphic_; ZoneMapList* receiver_types_; bool is_array_length_; + bool is_function_prototype_; bool is_arguments_access_; Handle<Map> monomorphic_receiver_type_; @@ -1391,7 +1395,7 @@ class BinaryOperation: public Expression { : op_(op), left_(left), right_(right), pos_(pos), is_smi_only_(false) { ASSERT(Token::IsBinaryOp(op)); right_id_ = (op == Token::AND || op == Token::OR) - ? GetNextId() + ? static_cast<int>(GetNextId()) : AstNode::kNoNumber; } diff --git a/src/builtins.cc b/src/builtins.cc index 21381f15..0c76f694 100644 --- a/src/builtins.cc +++ b/src/builtins.cc @@ -380,7 +380,7 @@ static inline MaybeObject* EnsureJSArrayWithWritableFastElements( Object* receiver) { if (!receiver->IsJSArray()) return NULL; JSArray* array = JSArray::cast(receiver); - HeapObject* elms = HeapObject::cast(array->elements()); + HeapObject* elms = array->elements(); if (elms->map() == Heap::fixed_array_map()) return elms; if (elms->map() == Heap::fixed_cow_array_map()) { return array->EnsureWritableFastElements(); @@ -613,42 +613,38 @@ BUILTIN(ArraySlice) { Object* receiver = *args.receiver(); FixedArray* elms; int len = -1; - { MaybeObject* maybe_elms_obj = - EnsureJSArrayWithWritableFastElements(receiver); - Object* elms_obj; - if (maybe_elms_obj != NULL && maybe_elms_obj->ToObject(&elms_obj)) { - if (!IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) { - return CallJsBuiltin("ArraySlice", args); - } - elms = FixedArray::cast(elms_obj); - JSArray* array = JSArray::cast(receiver); - ASSERT(array->HasFastElements()); + if (receiver->IsJSArray()) { + JSArray* array = JSArray::cast(receiver); + if (!array->HasFastElements() || + !IsJSArrayFastElementMovingAllowed(array)) { + return CallJsBuiltin("ArraySlice", args); + } - len = Smi::cast(array->length())->value(); - } else { - // Array.slice(arguments, ...) is quite a common idiom (notably more - // than 50% of invocations in Web apps). Treat it in C++ as well. - Map* arguments_map = - Top::context()->global_context()->arguments_boilerplate()->map(); - - bool is_arguments_object_with_fast_elements = - receiver->IsJSObject() - && JSObject::cast(receiver)->map() == arguments_map - && JSObject::cast(receiver)->HasFastElements(); - if (!is_arguments_object_with_fast_elements) { - return CallJsBuiltin("ArraySlice", args); - } - elms = FixedArray::cast(JSObject::cast(receiver)->elements()); - len = elms->length(); + elms = FixedArray::cast(array->elements()); + len = Smi::cast(array->length())->value(); + } else { + // Array.slice(arguments, ...) is quite a common idiom (notably more + // than 50% of invocations in Web apps). Treat it in C++ as well. + Map* arguments_map = + Top::context()->global_context()->arguments_boilerplate()->map(); + + bool is_arguments_object_with_fast_elements = + receiver->IsJSObject() + && JSObject::cast(receiver)->map() == arguments_map + && JSObject::cast(receiver)->HasFastElements(); + if (!is_arguments_object_with_fast_elements) { + return CallJsBuiltin("ArraySlice", args); + } + elms = FixedArray::cast(JSObject::cast(receiver)->elements()); + len = elms->length(); #ifdef DEBUG - // Arguments object by construction should have no holes, check it. - if (FLAG_enable_slow_asserts) { - for (int i = 0; i < len; i++) { - ASSERT(elms->get(i) != Heap::the_hole_value()); - } + // Arguments object by construction should have no holes, check it. + if (FLAG_enable_slow_asserts) { + for (int i = 0; i < len; i++) { + ASSERT(elms->get(i) != Heap::the_hole_value()); } -#endif } +#endif } ASSERT(len >= 0); int n_arguments = args.length() - 1; diff --git a/src/cpu-profiler.cc b/src/cpu-profiler.cc index f13c0eef..fcf539f3 100644 --- a/src/cpu-profiler.cc +++ b/src/cpu-profiler.cc @@ -47,7 +47,8 @@ static const int kTickSamplesBufferChunksCount = 16; ProfilerEventsProcessor::ProfilerEventsProcessor(ProfileGenerator* generator) - : generator_(generator), + : Thread("v8:ProfEvntProc"), + generator_(generator), running_(true), ticks_buffer_(sizeof(TickSampleEventRecord), kTickSamplesBufferChunkSize, diff --git a/src/d8-debug.cc b/src/d8-debug.cc index 5f3ed766..8a3886c6 100644 --- a/src/d8-debug.cc +++ b/src/d8-debug.cc @@ -34,12 +34,21 @@ namespace v8 { -void PrintPrompt() { - printf("dbg> "); +static bool was_running = true; + +void PrintPrompt(bool is_running) { + const char* prompt = is_running? "> " : "dbg> "; + was_running = is_running; + printf("%s", prompt); fflush(stdout); } +void PrintPrompt() { + PrintPrompt(was_running); +} + + void HandleDebugEvent(DebugEvent event, Handle<Object> exec_state, Handle<Object> event_data, @@ -91,7 +100,7 @@ void HandleDebugEvent(DebugEvent event, bool running = false; while (!running) { char command[kBufferSize]; - PrintPrompt(); + PrintPrompt(running); char* str = fgets(command, kBufferSize, stdin); if (str == NULL) break; @@ -284,7 +293,9 @@ void RemoteDebugger::HandleMessageReceived(char* message) { } else { printf("???\n"); } - PrintPrompt(); + + bool is_running = details->Get(String::New("running"))->ToBoolean()->Value(); + PrintPrompt(is_running); } diff --git a/src/d8-debug.h b/src/d8-debug.h index c7acc2f7..4e33e6f4 100644 --- a/src/d8-debug.h +++ b/src/d8-debug.h @@ -98,7 +98,8 @@ class RemoteDebugger { 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 ReceiverThread: public i::Thread { 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(); @@ -599,7 +599,8 @@ void Shell::RunShell() { 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 6e2230c6..79d760f5 100644 --- a/src/data-flow.h +++ b/src/data-flow.h @@ -112,10 +112,13 @@ class BitVector: public ZoneObject { } 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/date.js b/src/date.js index bc70327c..9eb607c7 100644 --- a/src/date.js +++ b/src/date.js @@ -1000,7 +1000,7 @@ function DateToISOString() { function DateToJSON(key) { var o = ToObject(this); var tv = DefaultNumber(o); - if (IS_NUMBER(tv) && !$isFinite(tv)) { + if (IS_NUMBER(tv) && !NUMBER_IS_FINITE(tv)) { return null; } return o.toISOString(); diff --git a/src/debug-agent.h b/src/debug-agent.h index 36479943..4cedb831 100644 --- a/src/debug-agent.h +++ b/src/debug-agent.h @@ -44,7 +44,8 @@ class DebuggerAgentSession; 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 DebuggerAgent: public Thread { 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 ca3c1db7..c41e545c 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -3037,7 +3037,8 @@ void LockingCommandMessageQueue::Clear() { 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/deoptimizer.cc b/src/deoptimizer.cc index dd70baaa..185ff922 100644 --- a/src/deoptimizer.cc +++ b/src/deoptimizer.cc @@ -309,9 +309,9 @@ void Deoptimizer::TearDown() { } -unsigned Deoptimizer::GetOutputInfo(DeoptimizationOutputData* data, - unsigned id, - SharedFunctionInfo* shared) { +int Deoptimizer::GetOutputInfo(DeoptimizationOutputData* data, + unsigned id, + SharedFunctionInfo* shared) { // TODO(kasperl): For now, we do a simple linear search for the PC // offset associated with the given node id. This should probably be // changed to a binary search. diff --git a/src/deoptimizer.h b/src/deoptimizer.h index 2d7dfc89..f9bf280e 100644 --- a/src/deoptimizer.h +++ b/src/deoptimizer.h @@ -145,9 +145,9 @@ class Deoptimizer : public Malloced { static Address GetDeoptimizationEntry(int id, BailoutType type); static int GetDeoptimizationId(Address addr, BailoutType type); - static unsigned GetOutputInfo(DeoptimizationOutputData* data, - unsigned node_id, - SharedFunctionInfo* shared); + static int GetOutputInfo(DeoptimizationOutputData* data, + unsigned node_id, + SharedFunctionInfo* shared); static void Setup(); static void TearDown(); diff --git a/src/factory.cc b/src/factory.cc index 83af447d..2bc878cc 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -99,6 +99,14 @@ Handle<String> Factory::LookupSymbol(Vector<const char> string) { CALL_HEAP_FUNCTION(Heap::LookupSymbol(string), String); } +Handle<String> Factory::LookupAsciiSymbol(Vector<const char> string) { + CALL_HEAP_FUNCTION(Heap::LookupAsciiSymbol(string), String); +} + +Handle<String> Factory::LookupTwoByteSymbol(Vector<const uc16> string) { + CALL_HEAP_FUNCTION(Heap::LookupTwoByteSymbol(string), String); +} + Handle<String> Factory::NewStringFromAscii(Vector<const char> string, PretenureFlag pretenure) { diff --git a/src/factory.h b/src/factory.h index b7a2882e..a5e15912 100644 --- a/src/factory.h +++ b/src/factory.h @@ -61,6 +61,8 @@ class Factory : public AllStatic { PretenureFlag pretenure); static Handle<String> LookupSymbol(Vector<const char> str); + static Handle<String> LookupAsciiSymbol(Vector<const char> str); + static Handle<String> LookupTwoByteSymbol(Vector<const uc16> str); static Handle<String> LookupAsciiSymbol(const char* str) { return LookupSymbol(CStrVector(str)); } diff --git a/src/flag-definitions.h b/src/flag-definitions.h index f160a85a..2b24d13c 100644 --- a/src/flag-definitions.h +++ b/src/flag-definitions.h @@ -122,7 +122,6 @@ DEFINE_bool(trace_inlining, false, "trace inlining decisions") 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/globals.h b/src/globals.h index 35156ae6..9b24bf63 100644 --- a/src/globals.h +++ b/src/globals.h @@ -181,10 +181,6 @@ typedef byte* Address; #define USING_BSD_ABI #endif -// Code-point values in Unicode 4.0 are 21 bits wide. -typedef uint16_t uc16; -typedef int32_t uc32; - // ----------------------------------------------------------------------------- // Constants @@ -228,6 +224,15 @@ const int kBinary32MinExponent = 0x01; const int kBinary32MantissaBits = 23; const int kBinary32ExponentShift = 23; +// ASCII/UC16 constants +// Code-point values in Unicode 4.0 are 21 bits wide. +typedef uint16_t uc16; +typedef int32_t uc32; +const int kASCIISize = kCharSize; +const int kUC16Size = sizeof(uc16); // NOLINT +const uc32 kMaxAsciiCharCode = 0x7f; +const uint32_t kMaxAsciiCharCodeU = 0x7fu; + // The expression OFFSET_OF(type, field) computes the byte-offset // of the specified field relative to the containing type. This diff --git a/src/heap-inl.h b/src/heap-inl.h index ef839988..e7700e9c 100644 --- a/src/heap-inl.h +++ b/src/heap-inl.h @@ -40,6 +40,19 @@ int Heap::MaxObjectSizeInPagedSpace() { } +MaybeObject* Heap::AllocateStringFromUtf8(Vector<const char> str, + PretenureFlag pretenure) { + // Check for ASCII first since this is the common case. + if (String::IsAscii(str.start(), str.length())) { + // If the string is ASCII, we do not need to convert the characters + // since UTF8 is backwards compatible with ASCII. + return AllocateStringFromAscii(str, pretenure); + } + // Non-ASCII and we need to decode. + return AllocateStringFromUtf8Slow(str, pretenure); +} + + MaybeObject* Heap::AllocateSymbol(Vector<const char> str, int chars, uint32_t hash_field) { @@ -49,6 +62,71 @@ MaybeObject* Heap::AllocateSymbol(Vector<const char> str, } +MaybeObject* Heap::AllocateAsciiSymbol(Vector<const char> str, + uint32_t hash_field) { + if (str.length() > SeqAsciiString::kMaxLength) { + return Failure::OutOfMemoryException(); + } + // Compute map and object size. + Map* map = ascii_symbol_map(); + int size = SeqAsciiString::SizeFor(str.length()); + + // Allocate string. + Object* result; + { MaybeObject* maybe_result = (size > MaxObjectSizeInPagedSpace()) + ? lo_space_->AllocateRaw(size) + : old_data_space_->AllocateRaw(size); + if (!maybe_result->ToObject(&result)) return maybe_result; + } + + reinterpret_cast<HeapObject*>(result)->set_map(map); + // Set length and hash fields of the allocated string. + String* answer = String::cast(result); + answer->set_length(str.length()); + answer->set_hash_field(hash_field); + + ASSERT_EQ(size, answer->Size()); + + // Fill in the characters. + memcpy(answer->address() + SeqAsciiString::kHeaderSize, + str.start(), str.length()); + + return answer; +} + + +MaybeObject* Heap::AllocateTwoByteSymbol(Vector<const uc16> str, + uint32_t hash_field) { + if (str.length() > SeqTwoByteString::kMaxLength) { + return Failure::OutOfMemoryException(); + } + // Compute map and object size. + Map* map = symbol_map(); + int size = SeqTwoByteString::SizeFor(str.length()); + + // Allocate string. + Object* result; + { MaybeObject* maybe_result = (size > MaxObjectSizeInPagedSpace()) + ? lo_space_->AllocateRaw(size) + : old_data_space_->AllocateRaw(size); + if (!maybe_result->ToObject(&result)) return maybe_result; + } + + reinterpret_cast<HeapObject*>(result)->set_map(map); + // Set length and hash fields of the allocated string. + String* answer = String::cast(result); + answer->set_length(str.length()); + answer->set_hash_field(hash_field); + + ASSERT_EQ(size, answer->Size()); + + // Fill in the characters. + memcpy(answer->address() + SeqTwoByteString::kHeaderSize, + str.start(), str.length() * kUC16Size); + + return answer; +} + MaybeObject* Heap::CopyFixedArray(FixedArray* src) { return CopyFixedArrayWithMap(src, src->map()); } @@ -443,6 +521,10 @@ void Heap::SetLastScriptId(Object* last_script_id) { 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/heap.cc b/src/heap.cc index 1e999916..44229f09 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -2549,20 +2549,10 @@ MaybeObject* Heap::AllocateExternalStringFromTwoByte( } // For small strings we check whether the resource contains only - // ascii characters. If yes, we use a different string map. - bool is_ascii = true; - if (length >= static_cast<size_t>(String::kMinNonFlatLength)) { - is_ascii = false; - } else { - const uc16* data = resource->data(); - for (size_t i = 0; i < length; i++) { - if (data[i] > String::kMaxAsciiCharCode) { - is_ascii = false; - break; - } - } - } - + // ASCII characters. If yes, we use a different string map. + static const size_t kAsciiCheckLengthLimit = 32; + bool is_ascii = length <= kAsciiCheckLengthLimit && + String::IsAscii(resource->data(), static_cast<int>(length)); Map* map = is_ascii ? Heap::external_string_with_ascii_data_map() : Heap::external_string_map(); Object* result; @@ -3307,8 +3297,8 @@ MaybeObject* Heap::AllocateStringFromAscii(Vector<const char> string, } -MaybeObject* Heap::AllocateStringFromUtf8(Vector<const char> string, - PretenureFlag pretenure) { +MaybeObject* Heap::AllocateStringFromUtf8Slow(Vector<const char> string, + PretenureFlag pretenure) { // V8 only supports characters in the Basic Multilingual Plane. const uc32 kMaxSupportedChar = 0xFFFF; // Count the number of characters in the UTF-8 string and check if @@ -3317,17 +3307,11 @@ MaybeObject* Heap::AllocateStringFromUtf8(Vector<const char> string, decoder(ScannerConstants::utf8_decoder()); decoder->Reset(string.start(), string.length()); int chars = 0; - bool is_ascii = true; while (decoder->has_more()) { - uc32 r = decoder->GetNext(); - if (r > String::kMaxAsciiCharCode) is_ascii = false; + decoder->GetNext(); chars++; } - // If the string is ascii, we do not need to convert the characters - // since UTF8 is backwards compatible with ascii. - if (is_ascii) return AllocateStringFromAscii(string, pretenure); - Object* result; { MaybeObject* maybe_result = AllocateRawTwoByteString(chars, pretenure); if (!maybe_result->ToObject(&result)) return maybe_result; @@ -3348,11 +3332,8 @@ MaybeObject* Heap::AllocateStringFromUtf8(Vector<const char> string, MaybeObject* Heap::AllocateStringFromTwoByte(Vector<const uc16> string, PretenureFlag pretenure) { // Check if the string is an ASCII string. - int i = 0; - while (i < string.length() && string[i] <= String::kMaxAsciiCharCode) i++; - MaybeObject* maybe_result; - if (i == string.length()) { // It's an ASCII string. + if (String::IsAscii(string.start(), string.length())) { maybe_result = AllocateRawAsciiString(string.length(), pretenure); } else { // It's not an ASCII string. maybe_result = AllocateRawTwoByteString(string.length(), pretenure); @@ -4032,6 +4013,36 @@ MaybeObject* Heap::LookupSymbol(Vector<const char> string) { } +MaybeObject* Heap::LookupAsciiSymbol(Vector<const char> string) { + Object* symbol = NULL; + Object* new_table; + { MaybeObject* maybe_new_table = + symbol_table()->LookupAsciiSymbol(string, &symbol); + if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table; + } + // Can't use set_symbol_table because SymbolTable::cast knows that + // SymbolTable is a singleton and checks for identity. + roots_[kSymbolTableRootIndex] = new_table; + ASSERT(symbol != NULL); + return symbol; +} + + +MaybeObject* Heap::LookupTwoByteSymbol(Vector<const uc16> string) { + Object* symbol = NULL; + Object* new_table; + { MaybeObject* maybe_new_table = + symbol_table()->LookupTwoByteSymbol(string, &symbol); + if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table; + } + // Can't use set_symbol_table because SymbolTable::cast knows that + // SymbolTable is a singleton and checks for identity. + roots_[kSymbolTableRootIndex] = new_table; + ASSERT(symbol != NULL); + return symbol; +} + + MaybeObject* Heap::LookupSymbol(String* string) { if (string->IsSymbol()) return string; Object* symbol = NULL; @@ -412,7 +412,10 @@ class Heap : public AllStatic { MUST_USE_RESULT static MaybeObject* AllocateStringFromAscii( Vector<const char> str, PretenureFlag pretenure = NOT_TENURED); - MUST_USE_RESULT static MaybeObject* AllocateStringFromUtf8( + MUST_USE_RESULT static inline MaybeObject* AllocateStringFromUtf8( + Vector<const char> str, + PretenureFlag pretenure = NOT_TENURED); + MUST_USE_RESULT static MaybeObject* AllocateStringFromUtf8Slow( Vector<const char> str, PretenureFlag pretenure = NOT_TENURED); MUST_USE_RESULT static MaybeObject* AllocateStringFromTwoByte( @@ -428,6 +431,14 @@ class Heap : public AllStatic { int chars, uint32_t hash_field); + MUST_USE_RESULT static inline MaybeObject* AllocateAsciiSymbol( + Vector<const char> str, + uint32_t hash_field); + + MUST_USE_RESULT static inline MaybeObject* AllocateTwoByteSymbol( + Vector<const uc16> str, + uint32_t hash_field); + MUST_USE_RESULT static MaybeObject* AllocateInternalSymbol( unibrow::CharacterStream* buffer, int chars, uint32_t hash_field); @@ -683,6 +694,9 @@ class Heap : public AllStatic { // failed. // Please note this function does not perform a garbage collection. MUST_USE_RESULT static MaybeObject* LookupSymbol(Vector<const char> str); + MUST_USE_RESULT static MaybeObject* LookupAsciiSymbol(Vector<const char> str); + MUST_USE_RESULT static MaybeObject* LookupTwoByteSymbol( + Vector<const uc16> str); MUST_USE_RESULT static MaybeObject* LookupAsciiSymbol(const char* str) { return LookupSymbol(CStrVector(str)); } diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h index cbbe8fcc..a3c23c67 100644 --- a/src/hydrogen-instructions.h +++ b/src/hydrogen-instructions.h @@ -76,7 +76,6 @@ class LChunkBuilder; // HLoadKeyed // HLoadKeyedFastElement // HLoadKeyedGeneric -// HLoadNamedGeneric // HPower // HStoreNamed // HStoreNamedField @@ -119,7 +118,6 @@ class LChunkBuilder; // HStoreKeyedFastElement // HStoreKeyedGeneric // HUnaryOperation -// HArrayLength // HBitNot // HChange // HCheckFunction @@ -129,9 +127,13 @@ class LChunkBuilder; // HCheckPrototypeMaps // HCheckSmi // HDeleteProperty +// HFixedArrayLength +// HJSArrayLength // HLoadElements // HTypeofIs // HLoadNamedField +// HLoadNamedGeneric +// HLoadFunctionPrototype // HPushArgument // HTypeof // HUnaryMathOperation @@ -170,7 +172,6 @@ class LChunkBuilder; V(ArgumentsElements) \ V(ArgumentsLength) \ V(ArgumentsObject) \ - V(ArrayLength) \ V(ArrayLiteral) \ V(BitAnd) \ V(BitNot) \ @@ -203,6 +204,7 @@ class LChunkBuilder; V(Deoptimize) \ V(Div) \ V(EnterInlined) \ + V(FixedArrayLength) \ V(FunctionLiteral) \ V(GlobalObject) \ V(GlobalReceiver) \ @@ -213,6 +215,7 @@ class LChunkBuilder; V(IsSmi) \ V(HasInstanceType) \ V(HasCachedArrayIndex) \ + V(JSArrayLength) \ V(ClassOfTest) \ V(LeaveInlined) \ V(LoadElements) \ @@ -221,6 +224,7 @@ class LChunkBuilder; V(LoadKeyedGeneric) \ V(LoadNamedField) \ V(LoadNamedGeneric) \ + V(LoadFunctionPrototype) \ V(Mod) \ V(Mul) \ V(ObjectLiteral) \ @@ -256,6 +260,7 @@ class LChunkBuilder; V(GlobalVars) \ V(Maps) \ V(ArrayLengths) \ + V(FunctionPrototypes) \ V(OsrEntries) #define DECLARE_INSTRUCTION(type) \ @@ -905,6 +910,9 @@ class HCompareMapAndBranch: public HUnaryControlInstruction { 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_; } @@ -1015,10 +1023,10 @@ class HChange: public HUnaryOperation { 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() {} @@ -1032,7 +1040,7 @@ class HSimulate: public HInstruction { 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 { @@ -1074,7 +1082,7 @@ class HSimulate: public HInstruction { } int ast_id_; int pop_count_; - int environment_height_; + int environment_length_; ZoneList<HValue*> values_; ZoneList<int> assigned_indexes_; }; @@ -1336,9 +1344,9 @@ class HCallRuntime: public HCall { }; -class HArrayLength: public HUnaryOperation { +class HJSArrayLength: public HUnaryOperation { public: - explicit HArrayLength(HValue* value) : HUnaryOperation(value) { + explicit HJSArrayLength(HValue* value) : HUnaryOperation(value) { // The length of an array is stored as a tagged value in the array // object. It is guaranteed to be 32 bit integer, but it can be // represented as either a smi or heap number. @@ -1351,7 +1359,23 @@ class HArrayLength: public HUnaryOperation { return Representation::Tagged(); } - DECLARE_CONCRETE_INSTRUCTION(ArrayLength, "array_length") + DECLARE_CONCRETE_INSTRUCTION(JSArrayLength, "js_array_length") +}; + + +class HFixedArrayLength: public HUnaryOperation { + public: + explicit HFixedArrayLength(HValue* value) : HUnaryOperation(value) { + set_representation(Representation::Tagged()); + SetFlag(kDependsOnArrayLengths); + SetFlag(kUseGVN); + } + + virtual Representation RequiredInputRepresentation(int index) const { + return Representation::Tagged(); + } + + DECLARE_CONCRETE_INSTRUCTION(FixedArrayLength, "fixed_array_length") }; @@ -1766,6 +1790,8 @@ class HConstant: public HInstruction { Handle<Object> handle() const { return handle_; } + bool InOldSpace() const { return !Heap::InNewSpace(*handle_); } + virtual bool EmitAtUses() const { return !representation().IsDouble(); } virtual void PrintDataTo(StringStream* stream) const; virtual HType CalculateInferredType() const; @@ -2617,6 +2643,27 @@ class HLoadNamedGeneric: public HUnaryOperation { }; +class HLoadFunctionPrototype: public HUnaryOperation { + public: + explicit HLoadFunctionPrototype(HValue* function) + : HUnaryOperation(function) { + set_representation(Representation::Tagged()); + SetFlagMask(kDependsOnFunctionPrototypes); + } + + HValue* function() const { return OperandAt(0); } + + virtual Representation RequiredInputRepresentation(int index) const { + return Representation::Tagged(); + } + + DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype, "load_function_prototype") + + protected: + virtual bool DataEquals(HValue* other) const { return true; } +}; + + class HLoadKeyed: public HBinaryOperation { public: HLoadKeyed(HValue* obj, HValue* key) : HBinaryOperation(obj, key) { @@ -2663,6 +2710,12 @@ class HLoadKeyedGeneric: public HLoadKeyed { }; +static inline bool StoringValueNeedsWriteBarrier(HValue* value) { + return !value->type().IsSmi() && + !(value->IsConstant() && HConstant::cast(value)->InOldSpace()); +} + + class HStoreNamed: public HBinaryOperation { public: HStoreNamed(HValue* obj, Handle<Object> name, HValue* val) @@ -2680,6 +2733,10 @@ class HStoreNamed: public HBinaryOperation { HValue* value() const { return OperandAt(1); } void set_value(HValue* value) { SetOperandAt(1, value); } + bool NeedsWriteBarrier() const { + return StoringValueNeedsWriteBarrier(value()); + } + DECLARE_INSTRUCTION(StoreNamed) protected: @@ -2760,6 +2817,10 @@ class HStoreKeyed: public HInstruction { HValue* key() const { return OperandAt(1); } HValue* value() const { return OperandAt(2); } + bool NeedsWriteBarrier() const { + return StoringValueNeedsWriteBarrier(value()); + } + DECLARE_INSTRUCTION(StoreKeyed) protected: @@ -2779,10 +2840,6 @@ class HStoreKeyedFastElement: public HStoreKeyed { SetFlag(kChangesArrayElements); } - bool NeedsWriteBarrier() const { - return !value()->type().IsSmi(); - } - virtual Representation RequiredInputRepresentation(int index) const { // The key is supposed to be Integer32. return (index == 1) ? Representation::Integer32() diff --git a/src/hydrogen.cc b/src/hydrogen.cc index e34acd67..fbe4cd72 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -128,7 +128,7 @@ HSimulate* HBasicBlock::CreateSimulate(int id) { 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 @@ void HBasicBlock::RegisterPredecessor(HBasicBlock* pred) { 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 @@ AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind) : 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 @@ AstContext::~AstContext() { 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 @@ void HGraphBuilder::SetupScope(Scope* scope) { } // 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 @@ void HSubgraph::PreProcessOsrEntry(IterationStatement* statement) { 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) { @@ -3103,8 +3103,15 @@ HBasicBlock* HGraphBuilder::BuildTypeSwitch(ZoneMapList* maps, // this basic block the current basic block. HBasicBlock* join_block = graph_->CreateBasicBlock(); for (int i = 0; i < subgraphs->length(); ++i) { - if (subgraphs->at(i)->HasExit()) { - subgraphs->at(i)->exit_block()->Goto(join_block); + HSubgraph* subgraph = subgraphs->at(i); + if (subgraph->HasExit()) { + // In an effect context the value of the type switch is not needed. + // There is no need to merge it at the join block only to discard it. + HBasicBlock* subgraph_exit = subgraph->exit_block(); + if (ast_context()->IsEffect()) { + subgraph_exit->last_environment()->Drop(1); + } + subgraph_exit->Goto(join_block); } } @@ -3242,7 +3249,8 @@ void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, Push(value); instr->set_position(expr->position()); AddInstruction(instr); - if (instr->HasSideEffects()) AddSimulate(expr->id()); + if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); + ast_context()->ReturnValue(Pop()); } else { // Build subgraph for generic store through IC. { @@ -3260,11 +3268,14 @@ void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, } HBasicBlock* new_exit_block = - BuildTypeSwitch(&maps, &subgraphs, object, expr->AssignmentId()); + BuildTypeSwitch(&maps, &subgraphs, object, expr->id()); subgraph()->set_exit_block(new_exit_block); + // In an effect context, we did not materialized the value in the + // predecessor environments so there's no need to handle it here. + if (subgraph()->HasExit() && !ast_context()->IsEffect()) { + ast_context()->ReturnValue(Pop()); + } } - - if (subgraph()->HasExit()) ast_context()->ReturnValue(Pop()); } @@ -3548,8 +3559,7 @@ void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, if (maps.length() == 0) { HInstruction* instr = BuildLoadNamedGeneric(object, expr); instr->set_position(expr->position()); - PushAndAdd(instr); - if (instr->HasSideEffects()) AddSimulate(expr->id()); + ast_context()->ReturnInstruction(instr, expr->id()); } else { // Build subgraph for generic load through IC. { @@ -3568,9 +3578,12 @@ void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, HBasicBlock* new_exit_block = BuildTypeSwitch(&maps, &subgraphs, object, expr->id()); subgraph()->set_exit_block(new_exit_block); + // In an effect context, we did not materialized the value in the + // predecessor environments so there's no need to handle it here. + if (subgraph()->HasExit() && !ast_context()->IsEffect()) { + ast_context()->ReturnValue(Pop()); + } } - - if (subgraph()->HasExit()) ast_context()->ReturnValue(Pop()); } @@ -3643,9 +3656,18 @@ HInstruction* HGraphBuilder::BuildLoadKeyedFastElement(HValue* object, Handle<Map> map = expr->GetMonomorphicReceiverType(); ASSERT(map->has_fast_elements()); AddInstruction(new HCheckMap(object, map)); - HInstruction* elements = AddInstruction(new HLoadElements(object)); - HInstruction* length = AddInstruction(new HArrayLength(elements)); - AddInstruction(new HBoundsCheck(key, length)); + bool is_array = (map->instance_type() == JS_ARRAY_TYPE); + HLoadElements* elements = new HLoadElements(object); + HInstruction* length = NULL; + if (is_array) { + length = AddInstruction(new HJSArrayLength(object)); + AddInstruction(new HBoundsCheck(key, length)); + AddInstruction(elements); + } else { + AddInstruction(elements); + length = AddInstruction(new HFixedArrayLength(elements)); + AddInstruction(new HBoundsCheck(key, length)); + } return new HLoadKeyedFastElement(elements, key); } @@ -3671,9 +3693,9 @@ HInstruction* HGraphBuilder::BuildStoreKeyedFastElement(HValue* object, bool is_array = (map->instance_type() == JS_ARRAY_TYPE); HInstruction* length = NULL; if (is_array) { - length = AddInstruction(new HArrayLength(object)); + length = AddInstruction(new HJSArrayLength(object)); } else { - length = AddInstruction(new HArrayLength(elements)); + length = AddInstruction(new HFixedArrayLength(elements)); } AddInstruction(new HBoundsCheck(key, length)); return new HStoreKeyedFastElement(elements, key, val); @@ -3720,7 +3742,13 @@ void HGraphBuilder::VisitProperty(Property* expr) { if (expr->IsArrayLength()) { HValue* array = Pop(); AddInstruction(new HCheckNonSmi(array)); - instr = new HArrayLength(array); + AddInstruction(new HCheckInstanceType(array, JS_ARRAY_TYPE, JS_ARRAY_TYPE)); + instr = new HJSArrayLength(array); + + } else if (expr->IsFunctionPrototype()) { + HValue* function = Pop(); + AddInstruction(new HCheckNonSmi(function)); + instr = new HLoadFunctionPrototype(function); } else if (expr->key()->IsPropertyName()) { Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); @@ -3841,7 +3869,11 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, HBasicBlock* new_exit_block = BuildTypeSwitch(&maps, &subgraphs, receiver, expr->id()); subgraph()->set_exit_block(new_exit_block); - if (new_exit_block != NULL) ast_context()->ReturnValue(Pop()); + // In an effect context, we did not materialized the value in the + // predecessor environments so there's no need to handle it here. + if (new_exit_block != NULL && !ast_context()->IsEffect()) { + ast_context()->ReturnValue(Pop()); + } } } @@ -4854,7 +4886,9 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { switch (op) { case Token::EQ: case Token::EQ_STRICT: { + AddInstruction(new HCheckNonSmi(left)); AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(left)); + AddInstruction(new HCheckNonSmi(right)); AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(right)); instr = new HCompareJSObjectEq(left, right); break; @@ -5262,6 +5296,19 @@ void HEnvironment::Initialize(int parameter_count, } +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()); @@ -5292,26 +5339,45 @@ void HEnvironment::AddIncomingEdge(HBasicBlock* block, HEnvironment* other) { } -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(); } } @@ -5376,7 +5442,7 @@ HEnvironment* HEnvironment::CopyForInlining(Handle<JSFunction> target, 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 ebabf3d2..872ae98e 100644 --- a/src/hydrogen.h +++ b/src/hydrogen.h @@ -401,27 +401,33 @@ class HEnvironment: public ZoneObject { 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 @@ class HEnvironment: public ZoneObject { 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(); - } - } - - Handle<JSFunction> closure() const { return closure_; } + void Drop(int count); - // 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; } + HValue* Top() const { return ExpressionStackAt(0); } - const ZoneList<HValue*>* values() const { return &values_; } - const ZoneList<int>* assigned_variables() const { - return &assigned_variables_; + HValue* ExpressionStackAt(int index_from_top) const { + int index = length() - index_from_top - 1; + ASSERT(HasExpressionAt(index)); + return values_[index]; } - 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_; } + + void SetExpressionStackAt(int index_from_top, HValue* value); + HEnvironment* Copy() const; HEnvironment* CopyWithoutHistory() const; HEnvironment* CopyAsLoopHeader(HBasicBlock* block) const; @@ -496,13 +477,15 @@ class HEnvironment: public ZoneObject { 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 @@ class HEnvironment: public ZoneObject { 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 @@ class AstContext { // 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 918f346d..0a3e0930 100644 --- a/src/ia32/builtins-ia32.cc +++ b/src/ia32/builtins-ia32.cc @@ -399,7 +399,7 @@ void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { 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 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, // 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 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) { __ 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 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) { { 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 a371c963..bd95c8d0 100644 --- a/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc @@ -104,7 +104,7 @@ void FastNewContextStub::Generate(MacroAssembler* masm) { 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 @@ void CompareStub::Generate(MacroAssembler* masm) { // 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 @@ void CompareStub::Generate(MacroAssembler* masm) { __ 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 @@ void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { // 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 @@ void CEntryStub::GenerateThrowUncatchable(MacroAssembler* masm, } // 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 ee945656..678cc931 100644 --- a/src/ia32/debug-ia32.cc +++ b/src/ia32/debug-ia32.cc @@ -125,7 +125,7 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm, #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/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index 13a11777..5beec0d3 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -379,7 +379,7 @@ void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const { void FullCodeGenerator::AccumulatorValueContext::Plug( Handle<Object> lit) const { - __ mov(result_register(), lit); + __ Set(result_register(), Immediate(lit)); } diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc index 9c9304d5..90bfd4b6 100644 --- a/src/ia32/ic-ia32.cc +++ b/src/ia32/ic-ia32.cc @@ -1199,7 +1199,7 @@ void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm, 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 @@ void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm, } -// 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 @@ void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) { } -// 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 @@ bool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) { } -// 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 @@ void StoreIC::GenerateGlobalProxy(MacroAssembler* masm) { } -// 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 d64f528e..0f568257 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -940,7 +940,7 @@ void LCodeGen::DoSubI(LSubI* instr) { void LCodeGen::DoConstantI(LConstantI* instr) { ASSERT(instr->result()->IsRegister()); - __ mov(ToRegister(instr->result()), instr->value()); + __ Set(ToRegister(instr->result()), Immediate(instr->value())); } @@ -973,27 +973,21 @@ void LCodeGen::DoConstantD(LConstantD* instr) { void LCodeGen::DoConstantT(LConstantT* instr) { ASSERT(instr->result()->IsRegister()); - __ mov(ToRegister(instr->result()), Immediate(instr->value())); + __ Set(ToRegister(instr->result()), Immediate(instr->value())); } -void LCodeGen::DoArrayLength(LArrayLength* instr) { +void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) { Register result = ToRegister(instr->result()); + Register array = ToRegister(instr->input()); + __ mov(result, FieldOperand(array, JSArray::kLengthOffset)); +} - if (instr->hydrogen()->value()->IsLoadElements()) { - // We load the length directly from the elements array. - Register elements = ToRegister(instr->input()); - __ mov(result, FieldOperand(elements, FixedArray::kLengthOffset)); - } else { - // Check that the receiver really is an array. - Register array = ToRegister(instr->input()); - Register temporary = ToRegister(instr->temporary()); - __ CmpObjectType(array, JS_ARRAY_TYPE, temporary); - DeoptimizeIf(not_equal, instr->environment()); - // Load length directly from the array. - __ mov(result, FieldOperand(array, JSArray::kLengthOffset)); - } +void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) { + Register result = ToRegister(instr->result()); + Register array = ToRegister(instr->input()); + __ mov(result, FieldOperand(array, FixedArray::kLengthOffset)); } @@ -1837,6 +1831,48 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { } +void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) { + Register function = ToRegister(instr->function()); + Register temp = ToRegister(instr->temporary()); + Register result = ToRegister(instr->result()); + + // Check that the function really is a function. + __ CmpObjectType(function, JS_FUNCTION_TYPE, result); + DeoptimizeIf(not_equal, instr->environment()); + + // Check whether the function has an instance prototype. + NearLabel non_instance; + __ test_b(FieldOperand(result, Map::kBitFieldOffset), + 1 << Map::kHasNonInstancePrototype); + __ j(not_zero, &non_instance); + + // Get the prototype or initial map from the function. + __ mov(result, + FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); + + // Check that the function has a prototype or an initial map. + __ cmp(Operand(result), Immediate(Factory::the_hole_value())); + DeoptimizeIf(equal, instr->environment()); + + // If the function does not have an initial map, we're done. + NearLabel done; + __ CmpObjectType(result, MAP_TYPE, temp); + __ j(not_equal, &done); + + // Get the prototype from the initial map. + __ mov(result, FieldOperand(result, Map::kPrototypeOffset)); + __ jmp(&done); + + // Non-instance prototype: Fetch prototype from constructor field + // in the function's map. + __ bind(&non_instance); + __ mov(result, FieldOperand(result, Map::kConstructorOffset)); + + // All done. + __ bind(&done); +} + + void LCodeGen::DoLoadElements(LLoadElements* instr) { ASSERT(instr->result()->Equals(instr->input())); Register reg = ToRegister(instr->input()); @@ -2891,9 +2927,6 @@ void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { InstanceType first = instr->hydrogen()->first(); InstanceType last = instr->hydrogen()->last(); - __ test(input, Immediate(kSmiTagMask)); - DeoptimizeIf(zero, instr->environment()); - __ mov(temp, FieldOperand(input, HeapObject::kMapOffset)); __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset), static_cast<int8_t>(first)); @@ -3006,7 +3039,7 @@ void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) { __ 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 3b272d0b..4fde3d46 100644 --- a/src/ia32/lithium-ia32.cc +++ b/src/ia32/lithium-ia32.cc @@ -767,11 +767,6 @@ LInstruction* LChunkBuilder::DefineAsSpilled(LInstruction* instr, int index) { } -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 @@ void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) { 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* LChunkBuilder::CreateEnvironment(HEnvironment* hydrogen_env) { 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(), @@ -1677,19 +1669,15 @@ LInstruction* LChunkBuilder::DoClassOfTest(HClassOfTest* instr) { } -LInstruction* LChunkBuilder::DoArrayLength(HArrayLength* instr) { - LOperand* array = NULL; - LOperand* temporary = NULL; +LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) { + LOperand* array = UseRegisterAtStart(instr->value()); + return DefineAsRegister(new LJSArrayLength(array)); +} - if (instr->value()->IsLoadElements()) { - array = UseRegisterAtStart(instr->value()); - } else { - array = UseRegister(instr->value()); - temporary = TempRegister(); - } - LInstruction* result = new LArrayLength(array, temporary); - return AssignEnvironment(DefineAsRegister(result)); +LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) { + LOperand* array = UseRegisterAtStart(instr->value()); + return DefineAsRegister(new LFixedArrayLength(array)); } @@ -1860,6 +1848,14 @@ LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) { } +LInstruction* LChunkBuilder::DoLoadFunctionPrototype( + HLoadFunctionPrototype* instr) { + return AssignEnvironment(DefineAsRegister( + new LLoadFunctionPrototype(UseRegister(instr->function()), + TempRegister()))); +} + + LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) { LOperand* input = UseRegisterAtStart(instr->value()); return DefineSameAsFirst(new LLoadElements(input)); @@ -1931,7 +1927,7 @@ LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) { LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) { - bool needs_write_barrier = !instr->value()->type().IsSmi(); + bool needs_write_barrier = instr->NeedsWriteBarrier(); LOperand* obj = needs_write_barrier ? UseTempRegister(instr->object()) @@ -2035,7 +2031,7 @@ LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) { 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); } @@ -2059,14 +2055,7 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) { 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 3f48e50e..00dc3944 100644 --- a/src/ia32/lithium-ia32.h +++ b/src/ia32/lithium-ia32.h @@ -104,7 +104,6 @@ class LGapNode; // LStoreNamedField // LStoreNamedGeneric // LUnaryOperation -// LArrayLength // LBitNotI // LBranch // LCallNew @@ -117,6 +116,7 @@ class LGapNode; // LClassOfTestAndBranch // LDeleteProperty // LDoubleToI +// LFixedArrayLength // LHasCachedArrayIndex // LHasCachedArrayIndexAndBranch // LHasInstanceType @@ -128,8 +128,10 @@ class LGapNode; // LIsObjectAndBranch // LIsSmi // LIsSmiAndBranch +// LJSArrayLength // LLoadNamedField // LLoadNamedGeneric +// LLoadFunctionPrototype // LNumberTagD // LNumberTagI // LPushArgument @@ -164,7 +166,6 @@ class LGapNode; V(ArgumentsLength) \ V(ArithmeticD) \ V(ArithmeticT) \ - V(ArrayLength) \ V(ArrayLiteral) \ V(BitI) \ V(BitNotI) \ @@ -203,6 +204,7 @@ class LGapNode; V(GlobalObject) \ V(GlobalReceiver) \ V(Goto) \ + V(FixedArrayLength) \ V(InstanceOf) \ V(InstanceOfAndBranch) \ V(Integer32ToDouble) \ @@ -212,6 +214,7 @@ class LGapNode; V(IsObjectAndBranch) \ V(IsSmi) \ V(IsSmiAndBranch) \ + V(JSArrayLength) \ V(HasInstanceType) \ V(HasInstanceTypeAndBranch) \ V(HasCachedArrayIndex) \ @@ -226,6 +229,7 @@ class LGapNode; V(LoadKeyedGeneric) \ V(LoadNamedField) \ V(LoadNamedGeneric) \ + V(LoadFunctionPrototype) \ V(ModI) \ V(MulI) \ V(NumberTagD) \ @@ -1146,18 +1150,21 @@ class LCmpMapAndBranch: public LUnaryOperation { }; -class LArrayLength: public LUnaryOperation { +class LJSArrayLength: public LUnaryOperation { public: - LArrayLength(LOperand* input, LOperand* temporary) - : LUnaryOperation(input), temporary_(temporary) { } + explicit LJSArrayLength(LOperand* input) : LUnaryOperation(input) { } - LOperand* temporary() const { return temporary_; } + DECLARE_CONCRETE_INSTRUCTION(JSArrayLength, "js-array-length") + DECLARE_HYDROGEN_ACCESSOR(JSArrayLength) +}; - DECLARE_CONCRETE_INSTRUCTION(ArrayLength, "array-length") - DECLARE_HYDROGEN_ACCESSOR(ArrayLength) - private: - LOperand* temporary_; +class LFixedArrayLength: public LUnaryOperation { + public: + explicit LFixedArrayLength(LOperand* input) : LUnaryOperation(input) { } + + DECLARE_CONCRETE_INSTRUCTION(FixedArrayLength, "fixed-array-length") + DECLARE_HYDROGEN_ACCESSOR(FixedArrayLength) }; @@ -1271,6 +1278,22 @@ class LLoadNamedGeneric: public LUnaryOperation { }; +class LLoadFunctionPrototype: public LUnaryOperation { + public: + LLoadFunctionPrototype(LOperand* function, LOperand* temporary) + : LUnaryOperation(function), temporary_(temporary) { } + + DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype, "load-function-prototype") + DECLARE_HYDROGEN_ACCESSOR(LoadFunctionPrototype) + + LOperand* function() const { return input(); } + LOperand* temporary() const { return temporary_; } + + private: + LOperand* temporary_; +}; + + class LLoadElements: public LUnaryOperation { public: explicit LLoadElements(LOperand* obj) : LUnaryOperation(obj) { } @@ -2064,7 +2087,6 @@ class LChunkBuilder BASE_EMBEDDED { 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 d435a707..12134488 100644 --- a/src/ia32/regexp-macro-assembler-ia32.cc +++ b/src/ia32/regexp-macro-assembler-ia32.cc @@ -211,9 +211,7 @@ void RegExpMacroAssemblerIA32::CheckCharacters(Vector<const uc16> str, // If input is ASCII, don't even bother calling here if the string to // match contains a non-ascii character. if (mode_ == ASCII) { - for (int i = 0; i < str.length(); i++) { - ASSERT(str[i] <= String::kMaxAsciiCharCodeU); - } + ASSERT(String::IsAscii(str.start(), str.length())); } #endif int byte_length = str.length() * char_size(); @@ -654,7 +652,7 @@ bool RegExpMacroAssemblerIA32::CheckSpecialCharacterClass(uc16 type, 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 99888b08..bcb02ed7 100644 --- a/src/ia32/stub-cache-ia32.cc +++ b/src/ia32/stub-cache-ia32.cc @@ -1686,6 +1686,7 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall( 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/json.js b/src/json.js index 89009a96..0034176b 100644 --- a/src/json.js +++ b/src/json.js @@ -27,11 +27,6 @@ var $JSON = global.JSON; -function ParseJSONUnfiltered(text) { - var s = $String(text); - return %ParseJson(s); -} - function Revive(holder, name, reviver) { var val = holder[name]; if (IS_OBJECT(val)) { @@ -58,7 +53,7 @@ function Revive(holder, name, reviver) { } function JSONParse(text, reviver) { - var unfiltered = ParseJSONUnfiltered(text); + var unfiltered = %ParseJson(TO_STRING_INLINE(text)); if (IS_FUNCTION(reviver)) { return Revive({'': unfiltered}, '', reviver); } else { @@ -158,7 +153,7 @@ function JSONSerialize(key, holder, replacer, stack, indent, gap) { if (IS_STRING(value)) { return %QuoteJSONString(value); } else if (IS_NUMBER(value)) { - return $isFinite(value) ? $String(value) : "null"; + return NUMBER_IS_FINITE(value) ? $String(value) : "null"; } else if (IS_BOOLEAN(value)) { return value ? "true" : "false"; } else if (IS_NULL(value)) { @@ -169,7 +164,7 @@ function JSONSerialize(key, holder, replacer, stack, indent, gap) { return SerializeArray(value, replacer, stack, indent, gap); } else if (IS_NUMBER_WRAPPER(value)) { value = ToNumber(value); - return $isFinite(value) ? ToString(value) : "null"; + return NUMBER_IS_FINITE(value) ? ToString(value) : "null"; } else if (IS_STRING_WRAPPER(value)) { return %QuoteJSONString(ToString(value)); } else if (IS_BOOLEAN_WRAPPER(value)) { @@ -244,7 +239,7 @@ function BasicJSONSerialize(key, holder, stack, builder) { if (IS_STRING(value)) { builder.push(%QuoteJSONString(value)); } else if (IS_NUMBER(value)) { - builder.push(($isFinite(value) ? %_NumberToString(value) : "null")); + builder.push(NUMBER_IS_FINITE(value) ? %_NumberToString(value) : "null"); } else if (IS_BOOLEAN(value)) { builder.push(value ? "true" : "false"); } else if (IS_NULL(value)) { @@ -254,7 +249,7 @@ function BasicJSONSerialize(key, holder, stack, builder) { // Unwrap value if necessary if (IS_NUMBER_WRAPPER(value)) { value = ToNumber(value); - builder.push(($isFinite(value) ? %_NumberToString(value) : "null")); + builder.push(NUMBER_IS_FINITE(value) ? %_NumberToString(value) : "null"); } else if (IS_STRING_WRAPPER(value)) { builder.push(%QuoteJSONString(ToString(value))); } else if (IS_BOOLEAN_WRAPPER(value)) { diff --git a/src/lithium-allocator.cc b/src/lithium-allocator.cc index ac61c17b..eecc441f 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 @@ void LOperand::PrintTo(StringStream* stream) { 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 @@ void LAllocator::MeetConstraintsBetween(InstructionSummary* first, } 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::Allocate(LChunk* chunk) { 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 @@ bool LAllocator::HasTaggedValue(int virtual_register) const { 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 3ec984e2..fe837e2f 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 @@ class LUnallocated: public LOperand { MUST_HAVE_REGISTER, WRITABLE_REGISTER, SAME_AS_FIRST_INPUT, - SAME_AS_ANY_INPUT, IGNORE }; @@ -275,7 +275,7 @@ class LUnallocated: public LOperand { 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 LiveRange: public ZoneObject { }; +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 @@ class LAllocator BASE_EMBEDDED { 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 @@ class LAllocator BASE_EMBEDDED { // 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/liveedit-debugger.js b/src/liveedit-debugger.js index 0f7c12d7..7ed22c84 100644 --- a/src/liveedit-debugger.js +++ b/src/liveedit-debugger.js @@ -144,8 +144,8 @@ Debug.LiveEdit = new function() { replace_code_list[i].live_shared_function_infos; if (live_shared_function_infos) { - for (var i = 0; i < live_shared_function_infos.length; i++) { - replaced_function_infos.push(live_shared_function_infos[i]); + for (var j = 0; j < live_shared_function_infos.length; j++) { + replaced_function_infos.push(live_shared_function_infos[j]); } } } @@ -276,7 +276,8 @@ void SlidingStateWindow::AddState(StateTag state) { // Profiler implementation. // Profiler::Profiler() - : head_(0), + : Thread("v8:Profiler"), + head_(0), tail_(0), overflow_(false), buffer_semaphore_(OS::CreateSemaphore(0)), diff --git a/src/macros.py b/src/macros.py index 6d66defb..01512e46 100644 --- a/src/macros.py +++ b/src/macros.py @@ -120,6 +120,7 @@ macro IS_SPEC_OBJECT(arg) = (%_IsSpecObject(arg)); # Inline macros. Use %IS_VAR to make sure arg is evaluated only once. macro NUMBER_IS_NAN(arg) = (!%_IsSmi(%IS_VAR(arg)) && !(arg == arg)); +macro NUMBER_IS_FINITE(arg) = (%_IsSmi(%IS_VAR(arg)) || arg - arg == 0); macro TO_INTEGER(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : %NumberToInteger(ToNumber(arg))); macro TO_INTEGER_MAP_MINUS_ZERO(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : %NumberToIntegerMapMinusZero(ToNumber(arg))); macro TO_INT32(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : (arg >> 0)); diff --git a/src/mirror-debugger.js b/src/mirror-debugger.js index 55836ce7..9177a6bc 100644 --- a/src/mirror-debugger.js +++ b/src/mirror-debugger.js @@ -2369,7 +2369,7 @@ function NumberToJSON_(value) { if (isNaN(value)) { return 'NaN'; } - if (!isFinite(value)) { + if (!NUMBER_IS_FINITE(value)) { if (value > 0) { return 'Infinity'; } else { diff --git a/src/objects-debug.cc b/src/objects-debug.cc index 53296d92..0b83182d 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -1,4 +1,4 @@ -// Copyright 2006-2008 the V8 project authors. All rights reserved. +// Copyright 2010 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -35,34 +35,8 @@ namespace v8 { namespace internal { -#ifdef OBJECT_PRINT - -static const char* TypeToString(InstanceType type); - - -void MaybeObject::Print(FILE* out) { - Object* this_as_object; - if (ToObject(&this_as_object)) { - if (this_as_object->IsSmi()) { - Smi::cast(this_as_object)->SmiPrint(out); - } else { - HeapObject::cast(this_as_object)->HeapObjectPrint(out); - } - } else { - Failure::cast(this)->FailurePrint(out); - } - Flush(out); -} - - -void MaybeObject::PrintLn(FILE* out) { - Print(out); - PrintF(out, "\n"); -} -#endif // OBJECT_PRINT - - #ifdef DEBUG + void MaybeObject::Verify() { Object* this_as_object; if (ToObject(&this_as_object)) { @@ -94,120 +68,8 @@ void Smi::SmiVerify() { void Failure::FailureVerify() { ASSERT(IsFailure()); } -#endif // DEBUG - - -#ifdef OBJECT_PRINT -void HeapObject::PrintHeader(FILE* out, const char* id) { - PrintF(out, "%p: [%s]\n", reinterpret_cast<void*>(this), id); -} -void HeapObject::HeapObjectPrint(FILE* out) { - InstanceType instance_type = map()->instance_type(); - - HandleScope scope; - if (instance_type < FIRST_NONSTRING_TYPE) { - String::cast(this)->StringPrint(out); - return; - } - - switch (instance_type) { - case MAP_TYPE: - Map::cast(this)->MapPrint(out); - break; - case HEAP_NUMBER_TYPE: - HeapNumber::cast(this)->HeapNumberPrint(out); - break; - case FIXED_ARRAY_TYPE: - FixedArray::cast(this)->FixedArrayPrint(out); - break; - case BYTE_ARRAY_TYPE: - ByteArray::cast(this)->ByteArrayPrint(out); - break; - case PIXEL_ARRAY_TYPE: - PixelArray::cast(this)->PixelArrayPrint(out); - break; - case EXTERNAL_BYTE_ARRAY_TYPE: - ExternalByteArray::cast(this)->ExternalByteArrayPrint(out); - break; - case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE: - ExternalUnsignedByteArray::cast(this) - ->ExternalUnsignedByteArrayPrint(out); - break; - case EXTERNAL_SHORT_ARRAY_TYPE: - ExternalShortArray::cast(this)->ExternalShortArrayPrint(out); - break; - case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE: - ExternalUnsignedShortArray::cast(this) - ->ExternalUnsignedShortArrayPrint(out); - break; - case EXTERNAL_INT_ARRAY_TYPE: - ExternalIntArray::cast(this)->ExternalIntArrayPrint(out); - break; - case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE: - ExternalUnsignedIntArray::cast(this)->ExternalUnsignedIntArrayPrint(out); - break; - case EXTERNAL_FLOAT_ARRAY_TYPE: - ExternalFloatArray::cast(this)->ExternalFloatArrayPrint(out); - break; - case FILLER_TYPE: - PrintF(out, "filler"); - break; - case JS_OBJECT_TYPE: // fall through - case JS_CONTEXT_EXTENSION_OBJECT_TYPE: - case JS_ARRAY_TYPE: - case JS_REGEXP_TYPE: - JSObject::cast(this)->JSObjectPrint(out); - break; - case ODDBALL_TYPE: - Oddball::cast(this)->to_string()->Print(out); - break; - case JS_FUNCTION_TYPE: - JSFunction::cast(this)->JSFunctionPrint(out); - break; - case JS_GLOBAL_PROXY_TYPE: - JSGlobalProxy::cast(this)->JSGlobalProxyPrint(out); - break; - case JS_GLOBAL_OBJECT_TYPE: - JSGlobalObject::cast(this)->JSGlobalObjectPrint(out); - break; - case JS_BUILTINS_OBJECT_TYPE: - JSBuiltinsObject::cast(this)->JSBuiltinsObjectPrint(out); - break; - case JS_VALUE_TYPE: - PrintF(out, "Value wrapper around:"); - JSValue::cast(this)->value()->Print(out); - break; - case CODE_TYPE: - Code::cast(this)->CodePrint(out); - break; - case PROXY_TYPE: - Proxy::cast(this)->ProxyPrint(out); - break; - case SHARED_FUNCTION_INFO_TYPE: - SharedFunctionInfo::cast(this)->SharedFunctionInfoPrint(out); - break; - case JS_GLOBAL_PROPERTY_CELL_TYPE: - JSGlobalPropertyCell::cast(this)->JSGlobalPropertyCellPrint(out); - break; -#define MAKE_STRUCT_CASE(NAME, Name, name) \ - case NAME##_TYPE: \ - Name::cast(this)->Name##Print(out); \ - break; - STRUCT_LIST(MAKE_STRUCT_CASE) -#undef MAKE_STRUCT_CASE - - default: - PrintF(out, "UNKNOWN TYPE %d", map()->instance_type()); - UNREACHABLE(); - break; - } -} -#endif // OBJECT_PRINT - - -#ifdef DEBUG void HeapObject::HeapObjectVerify() { InstanceType instance_type = map()->instance_type(); @@ -320,57 +182,8 @@ void HeapObject::VerifyHeapPointer(Object* p) { void HeapNumber::HeapNumberVerify() { ASSERT(IsHeapNumber()); } -#endif // DEBUG - - -#ifdef OBJECT_PRINT -void ByteArray::ByteArrayPrint(FILE* out) { - PrintF(out, "byte array, data starts at %p", GetDataStartAddress()); -} - - -void PixelArray::PixelArrayPrint(FILE* out) { - PrintF(out, "pixel array"); -} - - -void ExternalByteArray::ExternalByteArrayPrint(FILE* out) { - PrintF(out, "external byte array"); -} -void ExternalUnsignedByteArray::ExternalUnsignedByteArrayPrint(FILE* out) { - PrintF(out, "external unsigned byte array"); -} - - -void ExternalShortArray::ExternalShortArrayPrint(FILE* out) { - PrintF(out, "external short array"); -} - - -void ExternalUnsignedShortArray::ExternalUnsignedShortArrayPrint(FILE* out) { - PrintF(out, "external unsigned short array"); -} - - -void ExternalIntArray::ExternalIntArrayPrint(FILE* out) { - PrintF(out, "external int array"); -} - - -void ExternalUnsignedIntArray::ExternalUnsignedIntArrayPrint(FILE* out) { - PrintF(out, "external unsigned int array"); -} - - -void ExternalFloatArray::ExternalFloatArrayPrint(FILE* out) { - PrintF(out, "external float array"); -} -#endif // OBJECT_PRINT - - -#ifdef DEBUG void ByteArray::ByteArrayVerify() { ASSERT(IsByteArray()); } @@ -414,146 +227,8 @@ void ExternalUnsignedIntArray::ExternalUnsignedIntArrayVerify() { void ExternalFloatArray::ExternalFloatArrayVerify() { ASSERT(IsExternalFloatArray()); } -#endif // DEBUG - - -#ifdef OBJECT_PRINT -void JSObject::PrintProperties(FILE* out) { - if (HasFastProperties()) { - DescriptorArray* descs = map()->instance_descriptors(); - for (int i = 0; i < descs->number_of_descriptors(); i++) { - PrintF(out, " "); - descs->GetKey(i)->StringPrint(out); - PrintF(out, ": "); - switch (descs->GetType(i)) { - case FIELD: { - int index = descs->GetFieldIndex(i); - FastPropertyAt(index)->ShortPrint(out); - PrintF(out, " (field at offset %d)\n", index); - break; - } - case CONSTANT_FUNCTION: - descs->GetConstantFunction(i)->ShortPrint(out); - PrintF(out, " (constant function)\n"); - break; - case CALLBACKS: - descs->GetCallbacksObject(i)->ShortPrint(out); - PrintF(out, " (callback)\n"); - break; - case MAP_TRANSITION: - PrintF(out, " (map transition)\n"); - break; - case CONSTANT_TRANSITION: - PrintF(out, " (constant transition)\n"); - break; - case NULL_DESCRIPTOR: - PrintF(out, " (null descriptor)\n"); - break; - default: - UNREACHABLE(); - break; - } - } - } else { - property_dictionary()->Print(out); - } -} - - -void JSObject::PrintElements(FILE* out) { - switch (GetElementsKind()) { - case FAST_ELEMENTS: { - // Print in array notation for non-sparse arrays. - FixedArray* p = FixedArray::cast(elements()); - for (int i = 0; i < p->length(); i++) { - PrintF(out, " %d: ", i); - p->get(i)->ShortPrint(out); - PrintF(out, "\n"); - } - break; - } - case PIXEL_ELEMENTS: { - PixelArray* p = PixelArray::cast(elements()); - for (int i = 0; i < p->length(); i++) { - PrintF(out, " %d: %d\n", i, p->get(i)); - } - break; - } - case EXTERNAL_BYTE_ELEMENTS: { - ExternalByteArray* p = ExternalByteArray::cast(elements()); - for (int i = 0; i < p->length(); i++) { - PrintF(out, " %d: %d\n", i, static_cast<int>(p->get(i))); - } - break; - } - case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: { - ExternalUnsignedByteArray* p = - ExternalUnsignedByteArray::cast(elements()); - for (int i = 0; i < p->length(); i++) { - PrintF(out, " %d: %d\n", i, static_cast<int>(p->get(i))); - } - break; - } - case EXTERNAL_SHORT_ELEMENTS: { - ExternalShortArray* p = ExternalShortArray::cast(elements()); - for (int i = 0; i < p->length(); i++) { - PrintF(out, " %d: %d\n", i, static_cast<int>(p->get(i))); - } - break; - } - case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: { - ExternalUnsignedShortArray* p = - ExternalUnsignedShortArray::cast(elements()); - for (int i = 0; i < p->length(); i++) { - PrintF(out, " %d: %d\n", i, static_cast<int>(p->get(i))); - } - break; - } - case EXTERNAL_INT_ELEMENTS: { - ExternalIntArray* p = ExternalIntArray::cast(elements()); - for (int i = 0; i < p->length(); i++) { - PrintF(out, " %d: %d\n", i, static_cast<int>(p->get(i))); - } - break; - } - case EXTERNAL_UNSIGNED_INT_ELEMENTS: { - ExternalUnsignedIntArray* p = - ExternalUnsignedIntArray::cast(elements()); - for (int i = 0; i < p->length(); i++) { - PrintF(out, " %d: %d\n", i, static_cast<int>(p->get(i))); - } - break; - } - case EXTERNAL_FLOAT_ELEMENTS: { - ExternalFloatArray* p = ExternalFloatArray::cast(elements()); - for (int i = 0; i < p->length(); i++) { - PrintF(out, " %d: %f\n", i, p->get(i)); - } - break; - } - case DICTIONARY_ELEMENTS: - elements()->Print(out); - break; - default: - UNREACHABLE(); - break; - } -} -void JSObject::JSObjectPrint(FILE* out) { - PrintF(out, "%p: [JSObject]\n", reinterpret_cast<void*>(this)); - PrintF(out, " - map = %p\n", reinterpret_cast<void*>(map())); - PrintF(out, " - prototype = %p\n", reinterpret_cast<void*>(GetPrototype())); - PrintF(out, " {\n"); - PrintProperties(out); - PrintElements(out); - PrintF(out, " }\n"); -} -#endif // OBJECT_PRINT - - -#ifdef DEBUG void JSObject::JSObjectVerify() { VerifyHeapPointer(properties()); VerifyHeapPointer(elements()); @@ -567,103 +242,8 @@ void JSObject::JSObjectVerify() { elements()->map() == Heap::fixed_cow_array_map())); ASSERT(map()->has_fast_elements() == HasFastElements()); } -#endif // DEBUG -#ifdef OBJECT_PRINT -static const char* TypeToString(InstanceType type) { - switch (type) { - case INVALID_TYPE: return "INVALID"; - case MAP_TYPE: return "MAP"; - case HEAP_NUMBER_TYPE: return "HEAP_NUMBER"; - case SYMBOL_TYPE: return "SYMBOL"; - case ASCII_SYMBOL_TYPE: return "ASCII_SYMBOL"; - case CONS_SYMBOL_TYPE: return "CONS_SYMBOL"; - case CONS_ASCII_SYMBOL_TYPE: return "CONS_ASCII_SYMBOL"; - case EXTERNAL_ASCII_SYMBOL_TYPE: - case EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE: - case EXTERNAL_SYMBOL_TYPE: return "EXTERNAL_SYMBOL"; - case ASCII_STRING_TYPE: return "ASCII_STRING"; - case STRING_TYPE: return "TWO_BYTE_STRING"; - case CONS_STRING_TYPE: - case CONS_ASCII_STRING_TYPE: return "CONS_STRING"; - case EXTERNAL_ASCII_STRING_TYPE: - case EXTERNAL_STRING_WITH_ASCII_DATA_TYPE: - case EXTERNAL_STRING_TYPE: return "EXTERNAL_STRING"; - case FIXED_ARRAY_TYPE: return "FIXED_ARRAY"; - case BYTE_ARRAY_TYPE: return "BYTE_ARRAY"; - case PIXEL_ARRAY_TYPE: return "PIXEL_ARRAY"; - case EXTERNAL_BYTE_ARRAY_TYPE: return "EXTERNAL_BYTE_ARRAY"; - case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE: - return "EXTERNAL_UNSIGNED_BYTE_ARRAY"; - case EXTERNAL_SHORT_ARRAY_TYPE: return "EXTERNAL_SHORT_ARRAY"; - case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE: - return "EXTERNAL_UNSIGNED_SHORT_ARRAY"; - case EXTERNAL_INT_ARRAY_TYPE: return "EXTERNAL_INT_ARRAY"; - case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE: - return "EXTERNAL_UNSIGNED_INT_ARRAY"; - case EXTERNAL_FLOAT_ARRAY_TYPE: return "EXTERNAL_FLOAT_ARRAY"; - case FILLER_TYPE: return "FILLER"; - case JS_OBJECT_TYPE: return "JS_OBJECT"; - case JS_CONTEXT_EXTENSION_OBJECT_TYPE: return "JS_CONTEXT_EXTENSION_OBJECT"; - case ODDBALL_TYPE: return "ODDBALL"; - case JS_GLOBAL_PROPERTY_CELL_TYPE: return "JS_GLOBAL_PROPERTY_CELL"; - case SHARED_FUNCTION_INFO_TYPE: return "SHARED_FUNCTION_INFO"; - case JS_FUNCTION_TYPE: return "JS_FUNCTION"; - case CODE_TYPE: return "CODE"; - case JS_ARRAY_TYPE: return "JS_ARRAY"; - case JS_REGEXP_TYPE: return "JS_REGEXP"; - case JS_VALUE_TYPE: return "JS_VALUE"; - case JS_GLOBAL_OBJECT_TYPE: return "JS_GLOBAL_OBJECT"; - case JS_BUILTINS_OBJECT_TYPE: return "JS_BUILTINS_OBJECT"; - case JS_GLOBAL_PROXY_TYPE: return "JS_GLOBAL_PROXY"; - case PROXY_TYPE: return "PROXY"; -#define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE: return #NAME; - STRUCT_LIST(MAKE_STRUCT_CASE) -#undef MAKE_STRUCT_CASE - } - return "UNKNOWN"; -} - - -void Map::MapPrint(FILE* out) { - HeapObject::PrintHeader(out, "Map"); - PrintF(out, " - type: %s\n", TypeToString(instance_type())); - PrintF(out, " - instance size: %d\n", instance_size()); - PrintF(out, " - inobject properties: %d\n", inobject_properties()); - PrintF(out, " - pre-allocated property fields: %d\n", - pre_allocated_property_fields()); - PrintF(out, " - unused property fields: %d\n", unused_property_fields()); - if (is_hidden_prototype()) { - PrintF(out, " - hidden_prototype\n"); - } - if (has_named_interceptor()) { - PrintF(out, " - named_interceptor\n"); - } - if (has_indexed_interceptor()) { - PrintF(out, " - indexed_interceptor\n"); - } - if (is_undetectable()) { - PrintF(out, " - undetectable\n"); - } - if (has_instance_call_handler()) { - PrintF(out, " - instance_call_handler\n"); - } - if (is_access_check_needed()) { - PrintF(out, " - access_check_needed\n"); - } - PrintF(out, " - instance descriptors: "); - instance_descriptors()->ShortPrint(out); - PrintF(out, "\n - prototype: "); - prototype()->ShortPrint(out); - PrintF(out, "\n - constructor: "); - constructor()->ShortPrint(out); - PrintF(out, "\n"); -} -#endif // OBJECT_PRINT - - -#ifdef DEBUG void Map::MapVerify() { ASSERT(!Heap::InNewSpace(this)); ASSERT(FIRST_TYPE <= instance_type() && instance_type() <= LAST_TYPE); @@ -685,21 +265,8 @@ void Map::SharedMapVerify() { ASSERT_EQ(StaticVisitorBase::GetVisitorId(instance_type(), instance_size()), visitor_id()); } -#endif // DEBUG - - -#ifdef OBJECT_PRINT -void CodeCache::CodeCachePrint(FILE* out) { - HeapObject::PrintHeader(out, "CodeCache"); - PrintF(out, "\n - default_cache: "); - default_cache()->ShortPrint(out); - PrintF(out, "\n - normal_type_cache: "); - normal_type_cache()->ShortPrint(out); -} -#endif // OBJECT_PRINT -#ifdef DEBUG void CodeCache::CodeCacheVerify() { VerifyHeapPointer(default_cache()); VerifyHeapPointer(normal_type_cache()); @@ -707,23 +274,8 @@ void CodeCache::CodeCacheVerify() { ASSERT(normal_type_cache()->IsUndefined() || normal_type_cache()->IsCodeCacheHashTable()); } -#endif // DEBUG - - -#ifdef OBJECT_PRINT -void FixedArray::FixedArrayPrint(FILE* out) { - HeapObject::PrintHeader(out, "FixedArray"); - PrintF(out, " - length: %d", length()); - for (int i = 0; i < length(); i++) { - PrintF(out, "\n [%d]: ", i); - get(i)->ShortPrint(out); - } - PrintF(out, "\n"); -} -#endif // OBJECT_PRINT -#ifdef DEBUG void FixedArray::FixedArrayVerify() { for (int i = 0; i < length(); i++) { Object* e = get(i); @@ -734,57 +286,16 @@ void FixedArray::FixedArrayVerify() { } } } -#endif // DEBUG - -#ifdef OBJECT_PRINT -void JSValue::JSValuePrint(FILE* out) { - HeapObject::PrintHeader(out, "ValueObject"); - value()->Print(out); -} -#endif // OBJECT_PRINT - -#ifdef DEBUG void JSValue::JSValueVerify() { Object* v = value(); if (v->IsHeapObject()) { VerifyHeapPointer(v); } } -#endif // DEBUG - - -#ifdef OBJECT_PRINT -void String::StringPrint(FILE* out) { - if (StringShape(this).IsSymbol()) { - PrintF(out, "#"); - } else if (StringShape(this).IsCons()) { - PrintF(out, "c\""); - } else { - PrintF(out, "\""); - } - - const char truncated_epilogue[] = "...<truncated>"; - int len = length(); - if (!FLAG_use_verbose_printer) { - if (len > 100) { - len = 100 - sizeof(truncated_epilogue); - } - } - for (int i = 0; i < len; i++) { - PrintF(out, "%c", Get(i)); - } - if (len != length()) { - PrintF(out, "%s", truncated_epilogue); - } - - if (!StringShape(this).IsSymbol()) PrintF(out, "\""); -} -#endif // OBJECT_PRINT -#ifdef DEBUG void String::StringVerify() { CHECK(IsString()); CHECK(length() >= 0 && length() <= Smi::kMaxValue); @@ -792,36 +303,8 @@ void String::StringVerify() { CHECK(!Heap::InNewSpace(this)); } } -#endif // DEBUG - - -#ifdef OBJECT_PRINT -void JSFunction::JSFunctionPrint(FILE* out) { - HeapObject::PrintHeader(out, "Function"); - PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map())); - PrintF(out, " - initial_map = "); - if (has_initial_map()) { - initial_map()->ShortPrint(out); - } - PrintF(out, "\n - shared_info = "); - shared()->ShortPrint(out); - PrintF(out, "\n - name = "); - shared()->name()->Print(out); - PrintF(out, "\n - context = "); - unchecked_context()->ShortPrint(out); - PrintF(out, "\n - code = "); - code()->ShortPrint(out); - PrintF(out, "\n"); - - PrintProperties(out); - PrintElements(out); - - PrintF(out, "\n"); -} -#endif // OBJECT_PRINT -#ifdef DEBUG void JSFunction::JSFunctionVerify() { CHECK(IsJSFunction()); VerifyObjectField(kPrototypeOrInitialMapOffset); @@ -829,41 +312,8 @@ void JSFunction::JSFunctionVerify() { CHECK(next_function_link()->IsUndefined() || next_function_link()->IsJSFunction()); } -#endif // DEBUG - - -#ifdef OBJECT_PRINT -void SharedFunctionInfo::SharedFunctionInfoPrint(FILE* out) { - HeapObject::PrintHeader(out, "SharedFunctionInfo"); - PrintF(out, " - name: "); - name()->ShortPrint(out); - PrintF(out, "\n - expected_nof_properties: %d", expected_nof_properties()); - PrintF(out, "\n - instance class name = "); - instance_class_name()->Print(out); - PrintF(out, "\n - code = "); - code()->ShortPrint(out); - PrintF(out, "\n - source code = "); - GetSourceCode()->ShortPrint(out); - // Script files are often large, hard to read. - // PrintF(out, "\n - script ="); - // script()->Print(out); - PrintF(out, "\n - function token position = %d", function_token_position()); - PrintF(out, "\n - start position = %d", start_position()); - PrintF(out, "\n - end position = %d", end_position()); - PrintF(out, "\n - is expression = %d", is_expression()); - PrintF(out, "\n - debug info = "); - debug_info()->ShortPrint(out); - PrintF(out, "\n - length = %d", length()); - PrintF(out, "\n - has_only_simple_this_property_assignments = %d", - has_only_simple_this_property_assignments()); - PrintF(out, "\n - this_property_assignments = "); - this_property_assignments()->ShortPrint(out); - PrintF(out, "\n"); -} -#endif // OBJECT_PRINT -#ifdef DEBUG void SharedFunctionInfo::SharedFunctionInfoVerify() { CHECK(IsSharedFunctionInfo()); VerifyObjectField(kNameOffset); @@ -874,21 +324,8 @@ void SharedFunctionInfo::SharedFunctionInfoVerify() { VerifyObjectField(kScriptOffset); VerifyObjectField(kDebugInfoOffset); } -#endif // DEBUG - - -#ifdef OBJECT_PRINT -void JSGlobalProxy::JSGlobalProxyPrint(FILE* out) { - PrintF(out, "global_proxy"); - JSObjectPrint(out); - PrintF(out, "context : "); - context()->ShortPrint(out); - PrintF(out, "\n"); -} -#endif // OBJECT_PRINT -#ifdef DEBUG void JSGlobalProxy::JSGlobalProxyVerify() { CHECK(IsJSGlobalProxy()); JSObjectVerify(); @@ -898,21 +335,8 @@ void JSGlobalProxy::JSGlobalProxyVerify() { CHECK(HasFastElements()); CHECK_EQ(0, FixedArray::cast(elements())->length()); } -#endif // DEBUG - - -#ifdef OBJECT_PRINT -void JSGlobalObject::JSGlobalObjectPrint(FILE* out) { - PrintF(out, "global "); - JSObjectPrint(out); - PrintF(out, "global context : "); - global_context()->ShortPrint(out); - PrintF(out, "\n"); -} -#endif // OBJECT_PRINT -#ifdef DEBUG void JSGlobalObject::JSGlobalObjectVerify() { CHECK(IsJSGlobalObject()); JSObjectVerify(); @@ -922,18 +346,8 @@ void JSGlobalObject::JSGlobalObjectVerify() { VerifyObjectField(i); } } -#endif // DEBUG -#ifdef OBJECT_PRINT -void JSBuiltinsObject::JSBuiltinsObjectPrint(FILE* out) { - PrintF(out, "builtins "); - JSObjectPrint(out); -} -#endif // OBJECT_PRINT - - -#ifdef DEBUG void JSBuiltinsObject::JSBuiltinsObjectVerify() { CHECK(IsJSBuiltinsObject()); JSObjectVerify(); @@ -964,27 +378,8 @@ void JSGlobalPropertyCell::JSGlobalPropertyCellVerify() { CHECK(IsJSGlobalPropertyCell()); VerifyObjectField(kValueOffset); } -#endif // DEBUG - - -#ifdef OBJECT_PRINT -void JSGlobalPropertyCell::JSGlobalPropertyCellPrint(FILE* out) { - HeapObject::PrintHeader(out, "JSGlobalPropertyCell"); -} - - -void Code::CodePrint(FILE* out) { - HeapObject::PrintHeader(out, "Code"); -#ifdef ENABLE_DISASSEMBLER - if (FLAG_use_verbose_printer) { - Disassemble(NULL, out); - } -#endif -} -#endif // OBJECT_PRINT -#ifdef DEBUG void Code::CodeVerify() { CHECK(IsAligned(reinterpret_cast<intptr_t>(instruction_start()), kCodeAlignment)); @@ -1039,17 +434,8 @@ void JSRegExp::JSRegExpVerify() { break; } } -#endif // DEBUG - - -#ifdef OBJECT_PRINT -void Proxy::ProxyPrint(FILE* out) { - PrintF(out, "proxy to %p", proxy()); -} -#endif // OBJECT_PRINT -#ifdef DEBUG void Proxy::ProxyVerify() { ASSERT(IsProxy()); } @@ -1063,50 +449,16 @@ void AccessorInfo::AccessorInfoVerify() { VerifyPointer(data()); VerifyPointer(flag()); } -#endif // DEBUG - - -#ifdef OBJECT_PRINT -void AccessorInfo::AccessorInfoPrint(FILE* out) { - HeapObject::PrintHeader(out, "AccessorInfo"); - PrintF(out, "\n - getter: "); - getter()->ShortPrint(out); - PrintF(out, "\n - setter: "); - setter()->ShortPrint(out); - PrintF(out, "\n - name: "); - name()->ShortPrint(out); - PrintF(out, "\n - data: "); - data()->ShortPrint(out); - PrintF(out, "\n - flag: "); - flag()->ShortPrint(out); -} -#endif // OBJECT_PRINT -#ifdef DEBUG void AccessCheckInfo::AccessCheckInfoVerify() { CHECK(IsAccessCheckInfo()); VerifyPointer(named_callback()); VerifyPointer(indexed_callback()); VerifyPointer(data()); } -#endif // DEBUG - - -#ifdef OBJECT_PRINT -void AccessCheckInfo::AccessCheckInfoPrint(FILE* out) { - HeapObject::PrintHeader(out, "AccessCheckInfo"); - PrintF(out, "\n - named_callback: "); - named_callback()->ShortPrint(out); - PrintF(out, "\n - indexed_callback: "); - indexed_callback()->ShortPrint(out); - PrintF(out, "\n - data: "); - data()->ShortPrint(out); -} -#endif // OBJECT_PRINT -#ifdef DEBUG void InterceptorInfo::InterceptorInfoVerify() { CHECK(IsInterceptorInfo()); VerifyPointer(getter()); @@ -1116,50 +468,15 @@ void InterceptorInfo::InterceptorInfoVerify() { VerifyPointer(enumerator()); VerifyPointer(data()); } -#endif // DEBUG - - -#ifdef OBJECT_PRINT -void InterceptorInfo::InterceptorInfoPrint(FILE* out) { - HeapObject::PrintHeader(out, "InterceptorInfo"); - PrintF(out, "\n - getter: "); - getter()->ShortPrint(out); - PrintF(out, "\n - setter: "); - setter()->ShortPrint(out); - PrintF(out, "\n - query: "); - query()->ShortPrint(out); - PrintF(out, "\n - deleter: "); - deleter()->ShortPrint(out); - PrintF(out, "\n - enumerator: "); - enumerator()->ShortPrint(out); - PrintF(out, "\n - data: "); - data()->ShortPrint(out); -} -#endif // OBJECT_PRINT -#ifdef DEBUG void CallHandlerInfo::CallHandlerInfoVerify() { CHECK(IsCallHandlerInfo()); VerifyPointer(callback()); VerifyPointer(data()); } -#endif // DEBUG - - -#ifdef OBJECT_PRINT -void CallHandlerInfo::CallHandlerInfoPrint(FILE* out) { - HeapObject::PrintHeader(out, "CallHandlerInfo"); - PrintF(out, "\n - callback: "); - callback()->ShortPrint(out); - PrintF(out, "\n - data: "); - data()->ShortPrint(out); - PrintF(out, "\n - call_stub_cache: "); -} -#endif // OBJECT_PRINT -#ifdef DEBUG void TemplateInfo::TemplateInfoVerify() { VerifyPointer(tag()); VerifyPointer(property_list()); @@ -1179,106 +496,29 @@ void FunctionTemplateInfo::FunctionTemplateInfoVerify() { VerifyPointer(signature()); VerifyPointer(access_check_info()); } -#endif // DEBUG - - -#ifdef OBJECT_PRINT -void FunctionTemplateInfo::FunctionTemplateInfoPrint(FILE* out) { - HeapObject::PrintHeader(out, "FunctionTemplateInfo"); - PrintF(out, "\n - class name: "); - class_name()->ShortPrint(out); - PrintF(out, "\n - tag: "); - tag()->ShortPrint(out); - PrintF(out, "\n - property_list: "); - property_list()->ShortPrint(out); - PrintF(out, "\n - serial_number: "); - serial_number()->ShortPrint(out); - PrintF(out, "\n - call_code: "); - call_code()->ShortPrint(out); - PrintF(out, "\n - property_accessors: "); - property_accessors()->ShortPrint(out); - PrintF(out, "\n - prototype_template: "); - prototype_template()->ShortPrint(out); - PrintF(out, "\n - parent_template: "); - parent_template()->ShortPrint(out); - PrintF(out, "\n - named_property_handler: "); - named_property_handler()->ShortPrint(out); - PrintF(out, "\n - indexed_property_handler: "); - indexed_property_handler()->ShortPrint(out); - PrintF(out, "\n - instance_template: "); - instance_template()->ShortPrint(out); - PrintF(out, "\n - signature: "); - signature()->ShortPrint(out); - PrintF(out, "\n - access_check_info: "); - access_check_info()->ShortPrint(out); - PrintF(out, "\n - hidden_prototype: %s", - hidden_prototype() ? "true" : "false"); - PrintF(out, "\n - undetectable: %s", undetectable() ? "true" : "false"); - PrintF(out, "\n - need_access_check: %s", - needs_access_check() ? "true" : "false"); -} -#endif // OBJECT_PRINT -#ifdef DEBUG void ObjectTemplateInfo::ObjectTemplateInfoVerify() { CHECK(IsObjectTemplateInfo()); TemplateInfoVerify(); VerifyPointer(constructor()); VerifyPointer(internal_field_count()); } -#endif // DEBUG - - -#ifdef OBJECT_PRINT -void ObjectTemplateInfo::ObjectTemplateInfoPrint(FILE* out) { - HeapObject::PrintHeader(out, "ObjectTemplateInfo"); - PrintF(out, "\n - constructor: "); - constructor()->ShortPrint(out); - PrintF(out, "\n - internal_field_count: "); - internal_field_count()->ShortPrint(out); -} -#endif // OBJECT_PRINT -#ifdef DEBUG void SignatureInfo::SignatureInfoVerify() { CHECK(IsSignatureInfo()); VerifyPointer(receiver()); VerifyPointer(args()); } -#endif // DEBUG - - -#ifdef OBJECT_PRINT -void SignatureInfo::SignatureInfoPrint(FILE* out) { - HeapObject::PrintHeader(out, "SignatureInfo"); - PrintF(out, "\n - receiver: "); - receiver()->ShortPrint(out); - PrintF(out, "\n - args: "); - args()->ShortPrint(out); -} -#endif // OBJECT_PRINT -#ifdef DEBUG void TypeSwitchInfo::TypeSwitchInfoVerify() { CHECK(IsTypeSwitchInfo()); VerifyPointer(types()); } -#endif // DEBUG - - -#ifdef OBJECT_PRINT -void TypeSwitchInfo::TypeSwitchInfoPrint(FILE* out) { - HeapObject::PrintHeader(out, "TypeSwitchInfo"); - PrintF(out, "\n - types: "); - types()->ShortPrint(out); -} -#endif // OBJECT_PRINT -#ifdef DEBUG void Script::ScriptVerify() { CHECK(IsScript()); VerifyPointer(source()); @@ -1291,45 +531,9 @@ void Script::ScriptVerify() { VerifyPointer(line_ends()); VerifyPointer(id()); } -#endif // DEBUG - - -#ifdef OBJECT_PRINT -void Script::ScriptPrint(FILE* out) { - HeapObject::PrintHeader(out, "Script"); - PrintF(out, "\n - source: "); - source()->ShortPrint(out); - PrintF(out, "\n - name: "); - name()->ShortPrint(out); - PrintF(out, "\n - line_offset: "); - line_offset()->ShortPrint(out); - PrintF(out, "\n - column_offset: "); - column_offset()->ShortPrint(out); - PrintF(out, "\n - type: "); - type()->ShortPrint(out); - PrintF(out, "\n - id: "); - id()->ShortPrint(out); - PrintF(out, "\n - data: "); - data()->ShortPrint(out); - PrintF(out, "\n - context data: "); - context_data()->ShortPrint(out); - PrintF(out, "\n - wrapper: "); - wrapper()->ShortPrint(out); - PrintF(out, "\n - compilation type: "); - compilation_type()->ShortPrint(out); - PrintF(out, "\n - line ends: "); - line_ends()->ShortPrint(out); - PrintF(out, "\n - eval from shared: "); - eval_from_shared()->ShortPrint(out); - PrintF(out, "\n - eval from instructions offset: "); - eval_from_instructions_offset()->ShortPrint(out); - PrintF(out, "\n"); -} -#endif // OBJECT_PRINT #ifdef ENABLE_DEBUGGER_SUPPORT -#ifdef DEBUG void DebugInfo::DebugInfoVerify() { CHECK(IsDebugInfo()); VerifyPointer(shared()); @@ -1337,25 +541,8 @@ void DebugInfo::DebugInfoVerify() { VerifyPointer(code()); VerifyPointer(break_points()); } -#endif // DEBUG - - -#ifdef OBJECT_PRINT -void DebugInfo::DebugInfoPrint(FILE* out) { - HeapObject::PrintHeader(out, "DebugInfo"); - PrintF(out, "\n - shared: "); - shared()->ShortPrint(out); - PrintF(out, "\n - original_code: "); - original_code()->ShortPrint(out); - PrintF(out, "\n - code: "); - code()->ShortPrint(out); - PrintF(out, "\n - break_points: "); - break_points()->Print(out); -} -#endif // OBJECT_PRINT -#ifdef DEBUG void BreakPointInfo::BreakPointInfoVerify() { CHECK(IsBreakPointInfo()); code_position()->SmiVerify(); @@ -1363,23 +550,9 @@ void BreakPointInfo::BreakPointInfoVerify() { statement_position()->SmiVerify(); VerifyPointer(break_point_objects()); } -#endif // DEBUG - - -#ifdef OBJECT_PRINT -void BreakPointInfo::BreakPointInfoPrint(FILE* out) { - HeapObject::PrintHeader(out, "BreakPointInfo"); - PrintF(out, "\n - code_position: %d", code_position()->value()); - PrintF(out, "\n - source_position: %d", source_position()->value()); - PrintF(out, "\n - statement_position: %d", statement_position()->value()); - PrintF(out, "\n - break_point_objects: "); - break_point_objects()->ShortPrint(out); -} -#endif // OBJECT_PRINT #endif // ENABLE_DEBUGGER_SUPPORT -#ifdef DEBUG void JSObject::IncrementSpillStatistics(SpillInformation* info) { info->number_of_objects_++; // Named properties @@ -1462,24 +635,8 @@ void JSObject::SpillInformation::Print() { PrintF("\n"); } -#endif // DEBUG - - -#ifdef OBJECT_PRINT -void DescriptorArray::PrintDescriptors(FILE* out) { - PrintF(out, "Descriptor array %d\n", number_of_descriptors()); - for (int i = 0; i < number_of_descriptors(); i++) { - PrintF(out, " %d: ", i); - Descriptor desc; - Get(i, &desc); - desc.Print(out); - } - PrintF(out, "\n"); -} -#endif // OBJECT_PRINT -#ifdef DEBUG bool DescriptorArray::IsSortedNoDuplicates() { String* current_key = NULL; uint32_t current = 0; diff --git a/src/objects-printer.cc b/src/objects-printer.cc new file mode 100644 index 00000000..9879da25 --- /dev/null +++ b/src/objects-printer.cc @@ -0,0 +1,778 @@ +// Copyright 2010 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "v8.h" + +#include "disassembler.h" +#include "disasm.h" +#include "jsregexp.h" +#include "objects-visiting.h" + +namespace v8 { +namespace internal { + +#ifdef OBJECT_PRINT + +static const char* TypeToString(InstanceType type); + + +void MaybeObject::Print(FILE* out) { + Object* this_as_object; + if (ToObject(&this_as_object)) { + if (this_as_object->IsSmi()) { + Smi::cast(this_as_object)->SmiPrint(out); + } else { + HeapObject::cast(this_as_object)->HeapObjectPrint(out); + } + } else { + Failure::cast(this)->FailurePrint(out); + } + Flush(out); +} + + +void MaybeObject::PrintLn(FILE* out) { + Print(out); + PrintF(out, "\n"); +} + + +void HeapObject::PrintHeader(FILE* out, const char* id) { + PrintF(out, "%p: [%s]\n", reinterpret_cast<void*>(this), id); +} + + +void HeapObject::HeapObjectPrint(FILE* out) { + InstanceType instance_type = map()->instance_type(); + + HandleScope scope; + if (instance_type < FIRST_NONSTRING_TYPE) { + String::cast(this)->StringPrint(out); + return; + } + + switch (instance_type) { + case MAP_TYPE: + Map::cast(this)->MapPrint(out); + break; + case HEAP_NUMBER_TYPE: + HeapNumber::cast(this)->HeapNumberPrint(out); + break; + case FIXED_ARRAY_TYPE: + FixedArray::cast(this)->FixedArrayPrint(out); + break; + case BYTE_ARRAY_TYPE: + ByteArray::cast(this)->ByteArrayPrint(out); + break; + case PIXEL_ARRAY_TYPE: + PixelArray::cast(this)->PixelArrayPrint(out); + break; + case EXTERNAL_BYTE_ARRAY_TYPE: + ExternalByteArray::cast(this)->ExternalByteArrayPrint(out); + break; + case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE: + ExternalUnsignedByteArray::cast(this) + ->ExternalUnsignedByteArrayPrint(out); + break; + case EXTERNAL_SHORT_ARRAY_TYPE: + ExternalShortArray::cast(this)->ExternalShortArrayPrint(out); + break; + case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE: + ExternalUnsignedShortArray::cast(this) + ->ExternalUnsignedShortArrayPrint(out); + break; + case EXTERNAL_INT_ARRAY_TYPE: + ExternalIntArray::cast(this)->ExternalIntArrayPrint(out); + break; + case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE: + ExternalUnsignedIntArray::cast(this)->ExternalUnsignedIntArrayPrint(out); + break; + case EXTERNAL_FLOAT_ARRAY_TYPE: + ExternalFloatArray::cast(this)->ExternalFloatArrayPrint(out); + break; + case FILLER_TYPE: + PrintF(out, "filler"); + break; + case JS_OBJECT_TYPE: // fall through + case JS_CONTEXT_EXTENSION_OBJECT_TYPE: + case JS_ARRAY_TYPE: + case JS_REGEXP_TYPE: + JSObject::cast(this)->JSObjectPrint(out); + break; + case ODDBALL_TYPE: + Oddball::cast(this)->to_string()->Print(out); + break; + case JS_FUNCTION_TYPE: + JSFunction::cast(this)->JSFunctionPrint(out); + break; + case JS_GLOBAL_PROXY_TYPE: + JSGlobalProxy::cast(this)->JSGlobalProxyPrint(out); + break; + case JS_GLOBAL_OBJECT_TYPE: + JSGlobalObject::cast(this)->JSGlobalObjectPrint(out); + break; + case JS_BUILTINS_OBJECT_TYPE: + JSBuiltinsObject::cast(this)->JSBuiltinsObjectPrint(out); + break; + case JS_VALUE_TYPE: + PrintF(out, "Value wrapper around:"); + JSValue::cast(this)->value()->Print(out); + break; + case CODE_TYPE: + Code::cast(this)->CodePrint(out); + break; + case PROXY_TYPE: + Proxy::cast(this)->ProxyPrint(out); + break; + case SHARED_FUNCTION_INFO_TYPE: + SharedFunctionInfo::cast(this)->SharedFunctionInfoPrint(out); + break; + case JS_GLOBAL_PROPERTY_CELL_TYPE: + JSGlobalPropertyCell::cast(this)->JSGlobalPropertyCellPrint(out); + break; +#define MAKE_STRUCT_CASE(NAME, Name, name) \ + case NAME##_TYPE: \ + Name::cast(this)->Name##Print(out); \ + break; + STRUCT_LIST(MAKE_STRUCT_CASE) +#undef MAKE_STRUCT_CASE + + default: + PrintF(out, "UNKNOWN TYPE %d", map()->instance_type()); + UNREACHABLE(); + break; + } +} + + +void ByteArray::ByteArrayPrint(FILE* out) { + PrintF(out, "byte array, data starts at %p", GetDataStartAddress()); +} + + +void PixelArray::PixelArrayPrint(FILE* out) { + PrintF(out, "pixel array"); +} + + +void ExternalByteArray::ExternalByteArrayPrint(FILE* out) { + PrintF(out, "external byte array"); +} + + +void ExternalUnsignedByteArray::ExternalUnsignedByteArrayPrint(FILE* out) { + PrintF(out, "external unsigned byte array"); +} + + +void ExternalShortArray::ExternalShortArrayPrint(FILE* out) { + PrintF(out, "external short array"); +} + + +void ExternalUnsignedShortArray::ExternalUnsignedShortArrayPrint(FILE* out) { + PrintF(out, "external unsigned short array"); +} + + +void ExternalIntArray::ExternalIntArrayPrint(FILE* out) { + PrintF(out, "external int array"); +} + + +void ExternalUnsignedIntArray::ExternalUnsignedIntArrayPrint(FILE* out) { + PrintF(out, "external unsigned int array"); +} + + +void ExternalFloatArray::ExternalFloatArrayPrint(FILE* out) { + PrintF(out, "external float array"); +} + + +void JSObject::PrintProperties(FILE* out) { + if (HasFastProperties()) { + DescriptorArray* descs = map()->instance_descriptors(); + for (int i = 0; i < descs->number_of_descriptors(); i++) { + PrintF(out, " "); + descs->GetKey(i)->StringPrint(out); + PrintF(out, ": "); + switch (descs->GetType(i)) { + case FIELD: { + int index = descs->GetFieldIndex(i); + FastPropertyAt(index)->ShortPrint(out); + PrintF(out, " (field at offset %d)\n", index); + break; + } + case CONSTANT_FUNCTION: + descs->GetConstantFunction(i)->ShortPrint(out); + PrintF(out, " (constant function)\n"); + break; + case CALLBACKS: + descs->GetCallbacksObject(i)->ShortPrint(out); + PrintF(out, " (callback)\n"); + break; + case MAP_TRANSITION: + PrintF(out, " (map transition)\n"); + break; + case CONSTANT_TRANSITION: + PrintF(out, " (constant transition)\n"); + break; + case NULL_DESCRIPTOR: + PrintF(out, " (null descriptor)\n"); + break; + default: + UNREACHABLE(); + break; + } + } + } else { + property_dictionary()->Print(out); + } +} + + +void JSObject::PrintElements(FILE* out) { + switch (GetElementsKind()) { + case FAST_ELEMENTS: { + // Print in array notation for non-sparse arrays. + FixedArray* p = FixedArray::cast(elements()); + for (int i = 0; i < p->length(); i++) { + PrintF(out, " %d: ", i); + p->get(i)->ShortPrint(out); + PrintF(out, "\n"); + } + break; + } + case PIXEL_ELEMENTS: { + PixelArray* p = PixelArray::cast(elements()); + for (int i = 0; i < p->length(); i++) { + PrintF(out, " %d: %d\n", i, p->get(i)); + } + break; + } + case EXTERNAL_BYTE_ELEMENTS: { + ExternalByteArray* p = ExternalByteArray::cast(elements()); + for (int i = 0; i < p->length(); i++) { + PrintF(out, " %d: %d\n", i, static_cast<int>(p->get(i))); + } + break; + } + case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: { + ExternalUnsignedByteArray* p = + ExternalUnsignedByteArray::cast(elements()); + for (int i = 0; i < p->length(); i++) { + PrintF(out, " %d: %d\n", i, static_cast<int>(p->get(i))); + } + break; + } + case EXTERNAL_SHORT_ELEMENTS: { + ExternalShortArray* p = ExternalShortArray::cast(elements()); + for (int i = 0; i < p->length(); i++) { + PrintF(out, " %d: %d\n", i, static_cast<int>(p->get(i))); + } + break; + } + case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: { + ExternalUnsignedShortArray* p = + ExternalUnsignedShortArray::cast(elements()); + for (int i = 0; i < p->length(); i++) { + PrintF(out, " %d: %d\n", i, static_cast<int>(p->get(i))); + } + break; + } + case EXTERNAL_INT_ELEMENTS: { + ExternalIntArray* p = ExternalIntArray::cast(elements()); + for (int i = 0; i < p->length(); i++) { + PrintF(out, " %d: %d\n", i, static_cast<int>(p->get(i))); + } + break; + } + case EXTERNAL_UNSIGNED_INT_ELEMENTS: { + ExternalUnsignedIntArray* p = + ExternalUnsignedIntArray::cast(elements()); + for (int i = 0; i < p->length(); i++) { + PrintF(out, " %d: %d\n", i, static_cast<int>(p->get(i))); + } + break; + } + case EXTERNAL_FLOAT_ELEMENTS: { + ExternalFloatArray* p = ExternalFloatArray::cast(elements()); + for (int i = 0; i < p->length(); i++) { + PrintF(out, " %d: %f\n", i, p->get(i)); + } + break; + } + case DICTIONARY_ELEMENTS: + elements()->Print(out); + break; + default: + UNREACHABLE(); + break; + } +} + + +void JSObject::JSObjectPrint(FILE* out) { + PrintF(out, "%p: [JSObject]\n", reinterpret_cast<void*>(this)); + PrintF(out, " - map = %p\n", reinterpret_cast<void*>(map())); + PrintF(out, " - prototype = %p\n", reinterpret_cast<void*>(GetPrototype())); + PrintF(out, " {\n"); + PrintProperties(out); + PrintElements(out); + PrintF(out, " }\n"); +} + + +static const char* TypeToString(InstanceType type) { + switch (type) { + case INVALID_TYPE: return "INVALID"; + case MAP_TYPE: return "MAP"; + case HEAP_NUMBER_TYPE: return "HEAP_NUMBER"; + case SYMBOL_TYPE: return "SYMBOL"; + case ASCII_SYMBOL_TYPE: return "ASCII_SYMBOL"; + case CONS_SYMBOL_TYPE: return "CONS_SYMBOL"; + case CONS_ASCII_SYMBOL_TYPE: return "CONS_ASCII_SYMBOL"; + case EXTERNAL_ASCII_SYMBOL_TYPE: + case EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE: + case EXTERNAL_SYMBOL_TYPE: return "EXTERNAL_SYMBOL"; + case ASCII_STRING_TYPE: return "ASCII_STRING"; + case STRING_TYPE: return "TWO_BYTE_STRING"; + case CONS_STRING_TYPE: + case CONS_ASCII_STRING_TYPE: return "CONS_STRING"; + case EXTERNAL_ASCII_STRING_TYPE: + case EXTERNAL_STRING_WITH_ASCII_DATA_TYPE: + case EXTERNAL_STRING_TYPE: return "EXTERNAL_STRING"; + case FIXED_ARRAY_TYPE: return "FIXED_ARRAY"; + case BYTE_ARRAY_TYPE: return "BYTE_ARRAY"; + case PIXEL_ARRAY_TYPE: return "PIXEL_ARRAY"; + case EXTERNAL_BYTE_ARRAY_TYPE: return "EXTERNAL_BYTE_ARRAY"; + case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE: + return "EXTERNAL_UNSIGNED_BYTE_ARRAY"; + case EXTERNAL_SHORT_ARRAY_TYPE: return "EXTERNAL_SHORT_ARRAY"; + case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE: + return "EXTERNAL_UNSIGNED_SHORT_ARRAY"; + case EXTERNAL_INT_ARRAY_TYPE: return "EXTERNAL_INT_ARRAY"; + case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE: + return "EXTERNAL_UNSIGNED_INT_ARRAY"; + case EXTERNAL_FLOAT_ARRAY_TYPE: return "EXTERNAL_FLOAT_ARRAY"; + case FILLER_TYPE: return "FILLER"; + case JS_OBJECT_TYPE: return "JS_OBJECT"; + case JS_CONTEXT_EXTENSION_OBJECT_TYPE: return "JS_CONTEXT_EXTENSION_OBJECT"; + case ODDBALL_TYPE: return "ODDBALL"; + case JS_GLOBAL_PROPERTY_CELL_TYPE: return "JS_GLOBAL_PROPERTY_CELL"; + case SHARED_FUNCTION_INFO_TYPE: return "SHARED_FUNCTION_INFO"; + case JS_FUNCTION_TYPE: return "JS_FUNCTION"; + case CODE_TYPE: return "CODE"; + case JS_ARRAY_TYPE: return "JS_ARRAY"; + case JS_REGEXP_TYPE: return "JS_REGEXP"; + case JS_VALUE_TYPE: return "JS_VALUE"; + case JS_GLOBAL_OBJECT_TYPE: return "JS_GLOBAL_OBJECT"; + case JS_BUILTINS_OBJECT_TYPE: return "JS_BUILTINS_OBJECT"; + case JS_GLOBAL_PROXY_TYPE: return "JS_GLOBAL_PROXY"; + case PROXY_TYPE: return "PROXY"; +#define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE: return #NAME; + STRUCT_LIST(MAKE_STRUCT_CASE) +#undef MAKE_STRUCT_CASE + } + return "UNKNOWN"; +} + + +void Map::MapPrint(FILE* out) { + HeapObject::PrintHeader(out, "Map"); + PrintF(out, " - type: %s\n", TypeToString(instance_type())); + PrintF(out, " - instance size: %d\n", instance_size()); + PrintF(out, " - inobject properties: %d\n", inobject_properties()); + PrintF(out, " - pre-allocated property fields: %d\n", + pre_allocated_property_fields()); + PrintF(out, " - unused property fields: %d\n", unused_property_fields()); + if (is_hidden_prototype()) { + PrintF(out, " - hidden_prototype\n"); + } + if (has_named_interceptor()) { + PrintF(out, " - named_interceptor\n"); + } + if (has_indexed_interceptor()) { + PrintF(out, " - indexed_interceptor\n"); + } + if (is_undetectable()) { + PrintF(out, " - undetectable\n"); + } + if (has_instance_call_handler()) { + PrintF(out, " - instance_call_handler\n"); + } + if (is_access_check_needed()) { + PrintF(out, " - access_check_needed\n"); + } + PrintF(out, " - instance descriptors: "); + instance_descriptors()->ShortPrint(out); + PrintF(out, "\n - prototype: "); + prototype()->ShortPrint(out); + PrintF(out, "\n - constructor: "); + constructor()->ShortPrint(out); + PrintF(out, "\n"); +} + + +void CodeCache::CodeCachePrint(FILE* out) { + HeapObject::PrintHeader(out, "CodeCache"); + PrintF(out, "\n - default_cache: "); + default_cache()->ShortPrint(out); + PrintF(out, "\n - normal_type_cache: "); + normal_type_cache()->ShortPrint(out); +} + + +void FixedArray::FixedArrayPrint(FILE* out) { + HeapObject::PrintHeader(out, "FixedArray"); + PrintF(out, " - length: %d", length()); + for (int i = 0; i < length(); i++) { + PrintF(out, "\n [%d]: ", i); + get(i)->ShortPrint(out); + } + PrintF(out, "\n"); +} + + +void JSValue::JSValuePrint(FILE* out) { + HeapObject::PrintHeader(out, "ValueObject"); + value()->Print(out); +} + + +void String::StringPrint(FILE* out) { + if (StringShape(this).IsSymbol()) { + PrintF(out, "#"); + } else if (StringShape(this).IsCons()) { + PrintF(out, "c\""); + } else { + PrintF(out, "\""); + } + + const char truncated_epilogue[] = "...<truncated>"; + int len = length(); + if (!FLAG_use_verbose_printer) { + if (len > 100) { + len = 100 - sizeof(truncated_epilogue); + } + } + for (int i = 0; i < len; i++) { + PrintF(out, "%c", Get(i)); + } + if (len != length()) { + PrintF(out, "%s", truncated_epilogue); + } + + if (!StringShape(this).IsSymbol()) PrintF(out, "\""); +} + + +void JSFunction::JSFunctionPrint(FILE* out) { + HeapObject::PrintHeader(out, "Function"); + PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map())); + PrintF(out, " - initial_map = "); + if (has_initial_map()) { + initial_map()->ShortPrint(out); + } + PrintF(out, "\n - shared_info = "); + shared()->ShortPrint(out); + PrintF(out, "\n - name = "); + shared()->name()->Print(out); + PrintF(out, "\n - context = "); + unchecked_context()->ShortPrint(out); + PrintF(out, "\n - code = "); + code()->ShortPrint(out); + PrintF(out, "\n"); + + PrintProperties(out); + PrintElements(out); + + PrintF(out, "\n"); +} + + +void SharedFunctionInfo::SharedFunctionInfoPrint(FILE* out) { + HeapObject::PrintHeader(out, "SharedFunctionInfo"); + PrintF(out, " - name: "); + name()->ShortPrint(out); + PrintF(out, "\n - expected_nof_properties: %d", expected_nof_properties()); + PrintF(out, "\n - instance class name = "); + instance_class_name()->Print(out); + PrintF(out, "\n - code = "); + code()->ShortPrint(out); + PrintF(out, "\n - source code = "); + GetSourceCode()->ShortPrint(out); + // Script files are often large, hard to read. + // PrintF(out, "\n - script ="); + // script()->Print(out); + PrintF(out, "\n - function token position = %d", function_token_position()); + PrintF(out, "\n - start position = %d", start_position()); + PrintF(out, "\n - end position = %d", end_position()); + PrintF(out, "\n - is expression = %d", is_expression()); + PrintF(out, "\n - debug info = "); + debug_info()->ShortPrint(out); + PrintF(out, "\n - length = %d", length()); + PrintF(out, "\n - has_only_simple_this_property_assignments = %d", + has_only_simple_this_property_assignments()); + PrintF(out, "\n - this_property_assignments = "); + this_property_assignments()->ShortPrint(out); + PrintF(out, "\n"); +} + + +void JSGlobalProxy::JSGlobalProxyPrint(FILE* out) { + PrintF(out, "global_proxy"); + JSObjectPrint(out); + PrintF(out, "context : "); + context()->ShortPrint(out); + PrintF(out, "\n"); +} + + +void JSGlobalObject::JSGlobalObjectPrint(FILE* out) { + PrintF(out, "global "); + JSObjectPrint(out); + PrintF(out, "global context : "); + global_context()->ShortPrint(out); + PrintF(out, "\n"); +} + + +void JSBuiltinsObject::JSBuiltinsObjectPrint(FILE* out) { + PrintF(out, "builtins "); + JSObjectPrint(out); +} + + +void JSGlobalPropertyCell::JSGlobalPropertyCellPrint(FILE* out) { + HeapObject::PrintHeader(out, "JSGlobalPropertyCell"); +} + + +void Code::CodePrint(FILE* out) { + HeapObject::PrintHeader(out, "Code"); +#ifdef ENABLE_DISASSEMBLER + if (FLAG_use_verbose_printer) { + Disassemble(NULL, out); + } +#endif +} + + +void Proxy::ProxyPrint(FILE* out) { + PrintF(out, "proxy to %p", proxy()); +} + + +void AccessorInfo::AccessorInfoPrint(FILE* out) { + HeapObject::PrintHeader(out, "AccessorInfo"); + PrintF(out, "\n - getter: "); + getter()->ShortPrint(out); + PrintF(out, "\n - setter: "); + setter()->ShortPrint(out); + PrintF(out, "\n - name: "); + name()->ShortPrint(out); + PrintF(out, "\n - data: "); + data()->ShortPrint(out); + PrintF(out, "\n - flag: "); + flag()->ShortPrint(out); +} + + +void AccessCheckInfo::AccessCheckInfoPrint(FILE* out) { + HeapObject::PrintHeader(out, "AccessCheckInfo"); + PrintF(out, "\n - named_callback: "); + named_callback()->ShortPrint(out); + PrintF(out, "\n - indexed_callback: "); + indexed_callback()->ShortPrint(out); + PrintF(out, "\n - data: "); + data()->ShortPrint(out); +} + + +void InterceptorInfo::InterceptorInfoPrint(FILE* out) { + HeapObject::PrintHeader(out, "InterceptorInfo"); + PrintF(out, "\n - getter: "); + getter()->ShortPrint(out); + PrintF(out, "\n - setter: "); + setter()->ShortPrint(out); + PrintF(out, "\n - query: "); + query()->ShortPrint(out); + PrintF(out, "\n - deleter: "); + deleter()->ShortPrint(out); + PrintF(out, "\n - enumerator: "); + enumerator()->ShortPrint(out); + PrintF(out, "\n - data: "); + data()->ShortPrint(out); +} + + +void CallHandlerInfo::CallHandlerInfoPrint(FILE* out) { + HeapObject::PrintHeader(out, "CallHandlerInfo"); + PrintF(out, "\n - callback: "); + callback()->ShortPrint(out); + PrintF(out, "\n - data: "); + data()->ShortPrint(out); + PrintF(out, "\n - call_stub_cache: "); +} + + +void FunctionTemplateInfo::FunctionTemplateInfoPrint(FILE* out) { + HeapObject::PrintHeader(out, "FunctionTemplateInfo"); + PrintF(out, "\n - class name: "); + class_name()->ShortPrint(out); + PrintF(out, "\n - tag: "); + tag()->ShortPrint(out); + PrintF(out, "\n - property_list: "); + property_list()->ShortPrint(out); + PrintF(out, "\n - serial_number: "); + serial_number()->ShortPrint(out); + PrintF(out, "\n - call_code: "); + call_code()->ShortPrint(out); + PrintF(out, "\n - property_accessors: "); + property_accessors()->ShortPrint(out); + PrintF(out, "\n - prototype_template: "); + prototype_template()->ShortPrint(out); + PrintF(out, "\n - parent_template: "); + parent_template()->ShortPrint(out); + PrintF(out, "\n - named_property_handler: "); + named_property_handler()->ShortPrint(out); + PrintF(out, "\n - indexed_property_handler: "); + indexed_property_handler()->ShortPrint(out); + PrintF(out, "\n - instance_template: "); + instance_template()->ShortPrint(out); + PrintF(out, "\n - signature: "); + signature()->ShortPrint(out); + PrintF(out, "\n - access_check_info: "); + access_check_info()->ShortPrint(out); + PrintF(out, "\n - hidden_prototype: %s", + hidden_prototype() ? "true" : "false"); + PrintF(out, "\n - undetectable: %s", undetectable() ? "true" : "false"); + PrintF(out, "\n - need_access_check: %s", + needs_access_check() ? "true" : "false"); +} + + +void ObjectTemplateInfo::ObjectTemplateInfoPrint(FILE* out) { + HeapObject::PrintHeader(out, "ObjectTemplateInfo"); + PrintF(out, "\n - constructor: "); + constructor()->ShortPrint(out); + PrintF(out, "\n - internal_field_count: "); + internal_field_count()->ShortPrint(out); +} + + +void SignatureInfo::SignatureInfoPrint(FILE* out) { + HeapObject::PrintHeader(out, "SignatureInfo"); + PrintF(out, "\n - receiver: "); + receiver()->ShortPrint(out); + PrintF(out, "\n - args: "); + args()->ShortPrint(out); +} + + +void TypeSwitchInfo::TypeSwitchInfoPrint(FILE* out) { + HeapObject::PrintHeader(out, "TypeSwitchInfo"); + PrintF(out, "\n - types: "); + types()->ShortPrint(out); +} + + +void Script::ScriptPrint(FILE* out) { + HeapObject::PrintHeader(out, "Script"); + PrintF(out, "\n - source: "); + source()->ShortPrint(out); + PrintF(out, "\n - name: "); + name()->ShortPrint(out); + PrintF(out, "\n - line_offset: "); + line_offset()->ShortPrint(out); + PrintF(out, "\n - column_offset: "); + column_offset()->ShortPrint(out); + PrintF(out, "\n - type: "); + type()->ShortPrint(out); + PrintF(out, "\n - id: "); + id()->ShortPrint(out); + PrintF(out, "\n - data: "); + data()->ShortPrint(out); + PrintF(out, "\n - context data: "); + context_data()->ShortPrint(out); + PrintF(out, "\n - wrapper: "); + wrapper()->ShortPrint(out); + PrintF(out, "\n - compilation type: "); + compilation_type()->ShortPrint(out); + PrintF(out, "\n - line ends: "); + line_ends()->ShortPrint(out); + PrintF(out, "\n - eval from shared: "); + eval_from_shared()->ShortPrint(out); + PrintF(out, "\n - eval from instructions offset: "); + eval_from_instructions_offset()->ShortPrint(out); + PrintF(out, "\n"); +} + + +#ifdef ENABLE_DEBUGGER_SUPPORT +void DebugInfo::DebugInfoPrint(FILE* out) { + HeapObject::PrintHeader(out, "DebugInfo"); + PrintF(out, "\n - shared: "); + shared()->ShortPrint(out); + PrintF(out, "\n - original_code: "); + original_code()->ShortPrint(out); + PrintF(out, "\n - code: "); + code()->ShortPrint(out); + PrintF(out, "\n - break_points: "); + break_points()->Print(out); +} + + +void BreakPointInfo::BreakPointInfoPrint(FILE* out) { + HeapObject::PrintHeader(out, "BreakPointInfo"); + PrintF(out, "\n - code_position: %d", code_position()->value()); + PrintF(out, "\n - source_position: %d", source_position()->value()); + PrintF(out, "\n - statement_position: %d", statement_position()->value()); + PrintF(out, "\n - break_point_objects: "); + break_point_objects()->ShortPrint(out); +} +#endif // ENABLE_DEBUGGER_SUPPORT + + +void DescriptorArray::PrintDescriptors(FILE* out) { + PrintF(out, "Descriptor array %d\n", number_of_descriptors()); + for (int i = 0; i < number_of_descriptors(); i++) { + PrintF(out, " %d: ", i); + Descriptor desc; + Get(i, &desc); + desc.Print(out); + } + PrintF(out, "\n"); +} + + +#endif // OBJECT_PRINT + + +} } // namespace v8::internal diff --git a/src/objects-visiting.h b/src/objects-visiting.h index 55a0a53a..6510ca80 100644 --- a/src/objects-visiting.h +++ b/src/objects-visiting.h @@ -186,9 +186,9 @@ class VisitorDispatchTable { template<typename StaticVisitor> class BodyVisitorBase : public AllStatic { public: - static inline void IteratePointers(HeapObject* object, + INLINE(static void IteratePointers(HeapObject* object, int start_offset, - int end_offset) { + int end_offset)) { Object** start_slot = reinterpret_cast<Object**>(object->address() + start_offset); Object** end_slot = reinterpret_cast<Object**>(object->address() + diff --git a/src/objects.cc b/src/objects.cc index ab2f9644..927194f7 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -2932,7 +2932,6 @@ MaybeObject* JSObject::DefineGetterSetter(String* name, uint32_t index = 0; bool is_element = name->AsArrayIndex(&index); - if (is_element && IsJSArray()) return Heap::undefined_value(); if (is_element) { switch (GetElementsKind()) { @@ -5143,6 +5142,26 @@ bool String::IsEqualTo(Vector<const char> str) { } +bool String::IsAsciiEqualTo(Vector<const char> str) { + int slen = length(); + if (str.length() != slen) return false; + for (int i = 0; i < slen; i++) { + if (Get(i) != static_cast<uint16_t>(str[i])) return false; + } + return true; +} + + +bool String::IsTwoByteEqualTo(Vector<const uc16> str) { + int slen = length(); + if (str.length() != slen) return false; + for (int i = 0; i < slen; i++) { + if (Get(i) != str[i]) return false; + } + return true; +} + + template <typename schar> static inline uint32_t HashSequentialString(const schar* chars, int length) { StringHasher hasher(length); @@ -6775,7 +6794,8 @@ bool JSObject::HasElementWithReceiver(JSObject* receiver, uint32_t index) { 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; @@ -6799,7 +6819,9 @@ MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index, 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; } @@ -6910,7 +6932,9 @@ MaybeObject* JSObject::SetElementWithCallback(Object* structure, // 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; @@ -6920,12 +6944,13 @@ MaybeObject* JSObject::SetFastElement(uint32_t index, Object* value) { 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); @@ -6963,11 +6988,13 @@ MaybeObject* JSObject::SetFastElement(uint32_t index, Object* value) { 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)) { @@ -6981,24 +7008,25 @@ MaybeObject* JSObject::SetElement(uint32_t index, Object* value) { 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); @@ -7051,10 +7079,9 @@ MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index, } } 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). @@ -8086,6 +8113,85 @@ class Utf8SymbolKey : public HashTableKey { }; +template <typename Char> +class SequentialSymbolKey : public HashTableKey { + public: + explicit SequentialSymbolKey(Vector<const Char> string) + : string_(string), hash_field_(0) { } + + uint32_t Hash() { + StringHasher hasher(string_.length()); + + // Very long strings have a trivial hash that doesn't inspect the + // string contents. + if (hasher.has_trivial_hash()) { + hash_field_ = hasher.GetHashField(); + } else { + int i = 0; + // Do the iterative array index computation as long as there is a + // chance this is an array index. + while (i < string_.length() && hasher.is_array_index()) { + hasher.AddCharacter(static_cast<uc32>(string_[i])); + i++; + } + + // Process the remaining characters without updating the array + // index. + while (i < string_.length()) { + hasher.AddCharacterNoIndex(static_cast<uc32>(string_[i])); + i++; + } + hash_field_ = hasher.GetHashField(); + } + + uint32_t result = hash_field_ >> String::kHashShift; + ASSERT(result != 0); // Ensure that the hash value of 0 is never computed. + return result; + } + + + uint32_t HashForObject(Object* other) { + return String::cast(other)->Hash(); + } + + Vector<const Char> string_; + uint32_t hash_field_; +}; + + + +class AsciiSymbolKey : public SequentialSymbolKey<char> { + public: + explicit AsciiSymbolKey(Vector<const char> str) + : SequentialSymbolKey<char>(str) { } + + bool IsMatch(Object* string) { + return String::cast(string)->IsAsciiEqualTo(string_); + } + + MaybeObject* AsObject() { + if (hash_field_ == 0) Hash(); + return Heap::AllocateAsciiSymbol(string_, hash_field_); + } +}; + + +class TwoByteSymbolKey : public SequentialSymbolKey<uc16> { + public: + explicit TwoByteSymbolKey(Vector<const uc16> str) + : SequentialSymbolKey<uc16>(str) { } + + bool IsMatch(Object* string) { + return String::cast(string)->IsTwoByteEqualTo(string_); + } + + MaybeObject* AsObject() { + if (hash_field_ == 0) Hash(); + return Heap::AllocateTwoByteSymbol(string_, hash_field_); + } +}; + + // SymbolKey carries a string/symbol object as key. class SymbolKey : public HashTableKey { public: @@ -8830,6 +8936,19 @@ MaybeObject* SymbolTable::LookupSymbol(Vector<const char> str, Object** s) { } +MaybeObject* SymbolTable::LookupAsciiSymbol(Vector<const char> str, + Object** s) { + AsciiSymbolKey key(str); + return LookupKey(&key, s); +} + + +MaybeObject* SymbolTable::LookupTwoByteSymbol(Vector<const uc16> str, + Object** s) { + TwoByteSymbolKey key(str); + return LookupKey(&key, s); +} + MaybeObject* SymbolTable::LookupKey(HashTableKey* key, Object** s) { int entry = FindEntry(key); diff --git a/src/objects.h b/src/objects.h index c5fda7d0..eac7f920 100644 --- a/src/objects.h +++ b/src/objects.h @@ -1505,11 +1505,15 @@ class JSObject: public HeapObject { 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 @@ class JSObject: public HeapObject { 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); @@ -2327,6 +2334,10 @@ class SymbolTable: public HashTable<SymbolTableShape, HashTableKey*> { // been enlarged. If the return value is not a failure, the symbol // pointer *s is set to the symbol found. MUST_USE_RESULT MaybeObject* LookupSymbol(Vector<const char> str, Object** s); + MUST_USE_RESULT MaybeObject* LookupAsciiSymbol(Vector<const char> str, + Object** s); + MUST_USE_RESULT MaybeObject* LookupTwoByteSymbol(Vector<const uc16> str, + Object** s); MUST_USE_RESULT MaybeObject* LookupString(String* key, Object** s); // Looks up a symbol that is equal to the given string and returns @@ -5074,6 +5085,8 @@ class String: public HeapObject { // String equality operations. inline bool Equals(String* other); bool IsEqualTo(Vector<const char> str); + bool IsAsciiEqualTo(Vector<const char> str); + bool IsTwoByteEqualTo(Vector<const uc16> str); // Return a UTF8 representation of the string. The string is null // terminated but may optionally contain nulls. Length is returned @@ -5245,6 +5258,34 @@ class String: public HeapObject { int from, int to); + static inline bool IsAscii(const char* chars, int length) { + const char* limit = chars + length; +#ifdef V8_HOST_CAN_READ_UNALIGNED + ASSERT(kMaxAsciiCharCode == 0x7F); + const uintptr_t non_ascii_mask = kUintptrAllBitsSet / 0xFF * 0x80; + while (chars <= limit - sizeof(uintptr_t)) { + if (*reinterpret_cast<const uintptr_t*>(chars) & non_ascii_mask) { + return false; + } + chars += sizeof(uintptr_t); + } +#endif + while (chars < limit) { + if (static_cast<uint8_t>(*chars) > kMaxAsciiCharCodeU) return false; + ++chars; + } + return true; + } + + static inline bool IsAscii(const uc16* chars, int length) { + const uc16* limit = chars + length; + while (chars < limit) { + if (*chars > kMaxAsciiCharCodeU) return false; + ++chars; + } + return true; + } + protected: class ReadBlockBuffer { public: diff --git a/src/parser.cc b/src/parser.cc index 08f77b8f..55269339 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -323,22 +323,24 @@ TemporaryScope::~TemporaryScope() { } -Handle<String> Parser::LookupSymbol(int symbol_id, - Vector<const char> string) { +Handle<String> Parser::LookupSymbol(int symbol_id) { // Length of symbol cache is the number of identified symbols. // If we are larger than that, or negative, it's not a cached symbol. // This might also happen if there is no preparser symbol data, even // if there is some preparser data. if (static_cast<unsigned>(symbol_id) >= static_cast<unsigned>(symbol_cache_.length())) { - return Factory::LookupSymbol(string); + if (scanner().is_literal_ascii()) { + return Factory::LookupAsciiSymbol(scanner().literal_ascii_string()); + } else { + return Factory::LookupTwoByteSymbol(scanner().literal_uc16_string()); + } } - return LookupCachedSymbol(symbol_id, string); + return LookupCachedSymbol(symbol_id); } -Handle<String> Parser::LookupCachedSymbol(int symbol_id, - Vector<const char> string) { +Handle<String> Parser::LookupCachedSymbol(int symbol_id) { // Make sure the cache is large enough to hold the symbol identifier. if (symbol_cache_.length() <= symbol_id) { // Increase length to index + 1. @@ -347,7 +349,11 @@ Handle<String> Parser::LookupCachedSymbol(int symbol_id, } Handle<String> result = symbol_cache_.at(symbol_id); if (result.is_null()) { - result = Factory::LookupSymbol(string); + if (scanner().is_literal_ascii()) { + result = Factory::LookupAsciiSymbol(scanner().literal_ascii_string()); + } else { + result = Factory::LookupTwoByteSymbol(scanner().literal_uc16_string()); + } symbol_cache_.at(symbol_id) = result; return result; } @@ -615,11 +621,11 @@ FunctionLiteral* Parser::ParseProgram(Handle<String> source, // identical calls. ExternalTwoByteStringUC16CharacterStream stream( Handle<ExternalTwoByteString>::cast(source), 0, source->length()); - scanner_.Initialize(&stream, JavaScriptScanner::kAllLiterals); + scanner_.Initialize(&stream); return DoParseProgram(source, in_global_context, &zone_scope); } else { GenericStringUC16CharacterStream stream(source, 0, source->length()); - scanner_.Initialize(&stream, JavaScriptScanner::kAllLiterals); + scanner_.Initialize(&stream); return DoParseProgram(source, in_global_context, &zone_scope); } } @@ -705,7 +711,7 @@ FunctionLiteral* Parser::ParseLazy(Handle<SharedFunctionInfo> info) { FunctionLiteral* Parser::ParseLazy(Handle<SharedFunctionInfo> info, UC16CharacterStream* source, ZoneScope* zone_scope) { - scanner_.Initialize(source, JavaScriptScanner::kAllLiterals); + scanner_.Initialize(source); ASSERT(target_stack_ == NULL); Handle<String> name(String::cast(info->name())); @@ -757,7 +763,7 @@ Handle<String> Parser::GetSymbol(bool* ok) { if (pre_data() != NULL) { symbol_id = pre_data()->GetSymbolIdentifier(); } - return LookupSymbol(symbol_id, scanner().literal()); + return LookupSymbol(symbol_id); } @@ -2715,8 +2721,9 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) { case Token::NUMBER: { Consume(Token::NUMBER); - double value = - StringToDouble(scanner().literal(), ALLOW_HEX | ALLOW_OCTALS); + ASSERT(scanner().is_literal_ascii()); + double value = StringToDouble(scanner().literal_ascii_string(), + ALLOW_HEX | ALLOW_OCTALS); result = NewNumberLiteral(value); break; } @@ -2988,14 +2995,22 @@ ObjectLiteral::Property* Parser::ParseObjectLiteralGetSet(bool is_getter, // { ... , 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; @@ -3066,8 +3081,9 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { } case Token::NUMBER: { Consume(Token::NUMBER); - double value = - StringToDouble(scanner().literal(), ALLOW_HEX | ALLOW_OCTALS); + ASSERT(scanner().is_literal_ascii()); + double value = StringToDouble(scanner().literal_ascii_string(), + ALLOW_HEX | ALLOW_OCTALS); key = NewNumberLiteral(value); break; } @@ -3137,11 +3153,9 @@ Expression* Parser::ParseRegExpLiteral(bool seen_equal, bool* ok) { int literal_index = temp_scope_->NextMaterializedLiteralIndex(); - Handle<String> js_pattern = - Factory::NewStringFromUtf8(scanner().next_literal(), TENURED); + Handle<String> js_pattern = NextLiteralString(TENURED); scanner().ScanRegExpFlags(); - Handle<String> js_flags = - Factory::NewStringFromUtf8(scanner().next_literal(), TENURED); + Handle<String> js_flags = NextLiteralString(TENURED); Next(); return new RegExpLiteral(js_pattern, js_flags, literal_index); @@ -3423,10 +3437,10 @@ Handle<String> Parser::ParseIdentifierOrGetOrSet(bool* is_get, bool* ok) { Expect(Token::IDENTIFIER, ok); if (!*ok) return Handle<String>(); - if (scanner().literal_length() == 3) { - const char* token = scanner().literal_string(); - *is_get = strcmp(token, "get") == 0; - *is_set = !*is_get && strcmp(token, "set") == 0; + if (scanner().is_literal_ascii() && scanner().literal_length() == 3) { + const char* token = scanner().literal_ascii_string().start(); + *is_get = strncmp(token, "get", 3) == 0; + *is_set = !*is_get && strncmp(token, "set", 3) == 0; } return GetSymbol(ok); } @@ -3604,9 +3618,11 @@ Handle<String> JsonParser::GetString() { if (literal_length == 0) { return Factory::empty_string(); } - const char* literal_string = scanner_.literal_string(); - Vector<const char> literal(literal_string, literal_length); - return Factory::NewStringFromUtf8(literal); + if (scanner_.is_literal_ascii()) { + return Factory::NewStringFromAscii(scanner_.literal_ascii_string()); + } else { + return Factory::NewStringFromTwoByte(scanner_.literal_uc16_string()); + } } @@ -3618,7 +3634,8 @@ Handle<Object> JsonParser::ParseJsonValue() { return GetString(); } case Token::NUMBER: { - double value = StringToDouble(scanner_.literal(), + ASSERT(scanner_.is_literal_ascii()); + double value = StringToDouble(scanner_.literal_ascii_string(), NO_FLAGS, // Hex, octal or trailing junk. OS::nan_value()); return Factory::NewNumber(value); @@ -3663,9 +3680,11 @@ Handle<Object> JsonParser::ParseJsonObject() { 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) { @@ -4597,10 +4616,9 @@ int ScriptDataImpl::ReadNumber(byte** source) { // Create a Scanner for the preparser to use as input, and preparse the source. static ScriptDataImpl* DoPreParse(UC16CharacterStream* source, bool allow_lazy, - ParserRecorder* recorder, - int literal_flags) { + ParserRecorder* recorder) { V8JavaScriptScanner scanner; - scanner.Initialize(source, literal_flags); + scanner.Initialize(source); intptr_t stack_limit = StackGuard::real_climit(); if (!preparser::PreParser::PreParseProgram(&scanner, recorder, @@ -4628,8 +4646,7 @@ ScriptDataImpl* ParserApi::PartialPreParse(UC16CharacterStream* source, return NULL; } PartialParserRecorder recorder; - return DoPreParse(source, allow_lazy, &recorder, - JavaScriptScanner::kNoLiterals); + return DoPreParse(source, allow_lazy, &recorder); } @@ -4638,9 +4655,7 @@ ScriptDataImpl* ParserApi::PreParse(UC16CharacterStream* source, Handle<Script> no_script; bool allow_lazy = FLAG_lazy && (extension == NULL); CompleteParserRecorder recorder; - int kPreParseLiteralsFlags = - JavaScriptScanner::kLiteralString | JavaScriptScanner::kLiteralIdentifier; - return DoPreParse(source, allow_lazy, &recorder, kPreParseLiteralsFlags); + return DoPreParse(source, allow_lazy, &recorder); } diff --git a/src/parser.h b/src/parser.h index 70d0e18f..8623f384 100644 --- a/src/parser.h +++ b/src/parser.h @@ -578,6 +578,26 @@ class Parser { bool Check(Token::Value token); void ExpectSemicolon(bool* ok); + Handle<String> LiteralString(PretenureFlag tenured) { + if (scanner().is_literal_ascii()) { + return Factory::NewStringFromAscii(scanner().literal_ascii_string(), + tenured); + } else { + return Factory::NewStringFromTwoByte(scanner().literal_uc16_string(), + tenured); + } + } + + Handle<String> NextLiteralString(PretenureFlag tenured) { + if (scanner().is_next_literal_ascii()) { + return Factory::NewStringFromAscii(scanner().next_literal_ascii_string(), + tenured); + } else { + return Factory::NewStringFromTwoByte(scanner().next_literal_uc16_string(), + tenured); + } + } + Handle<String> GetSymbol(bool* ok); // Get odd-ball literals. @@ -612,11 +632,9 @@ class Parser { Scope* NewScope(Scope* parent, Scope::Type type, bool inside_with); - Handle<String> LookupSymbol(int symbol_id, - Vector<const char> string); + Handle<String> LookupSymbol(int symbol_id); - Handle<String> LookupCachedSymbol(int symbol_id, - Vector<const char> string); + Handle<String> LookupCachedSymbol(int symbol_id); Expression* NewCall(Expression* expression, ZoneList<Expression*>* arguments, diff --git a/src/platform-freebsd.cc b/src/platform-freebsd.cc index b58d0662..ad1e499a 100644 --- a/src/platform-freebsd.cc +++ b/src/platform-freebsd.cc @@ -411,6 +411,12 @@ bool ThreadHandle::IsValid() const { Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) { + set_name("v8:<unknown>"); +} + + +Thread::Thread(const char* name) : ThreadHandle(ThreadHandle::INVALID) { + set_names(name); } @@ -430,6 +436,12 @@ static void* ThreadEntry(void* arg) { } +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 7efb25de..25a9ca0b 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 @@ bool ThreadHandle::IsValid() const { Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) { + set_name("v8:<unknown>"); +} + + +Thread::Thread(const char* name) : ThreadHandle(ThreadHandle::INVALID) { + set_name(name); } @@ -563,6 +570,9 @@ static void* ThreadEntry(void* 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. + prctl(PR_SET_NAME, + reinterpret_cast<unsigned long>(thread->name()), // NOLINT + 0, 0, 0); thread->thread_handle_data()->thread_ = pthread_self(); ASSERT(thread->IsValid()); thread->Run(); @@ -570,6 +580,12 @@ static void* ThreadEntry(void* arg) { } +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 85c70882..ce533051 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 @@ bool ThreadHandle::IsValid() const { Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) { + set_name("v8:<unknown>"); +} + + +Thread::Thread(const char* name) : ThreadHandle(ThreadHandle::INVALID) { + set_name(name); } @@ -418,18 +424,43 @@ Thread::~Thread() { } + +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 72ea0e57..f1b76959 100644 --- a/src/platform-nullos.cc +++ b/src/platform-nullos.cc @@ -335,6 +335,13 @@ bool ThreadHandle::IsValid() const { 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 @@ Thread::~Thread() { } +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 b698d16b..5de60819 100644 --- a/src/platform-openbsd.cc +++ b/src/platform-openbsd.cc @@ -387,6 +387,12 @@ bool ThreadHandle::IsValid() const { Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) { + set_name("v8:<unknown>"); +} + + +Thread::Thread(const char* name) : ThreadHandle(ThreadHandle::INVALID) { + set_name(name); } @@ -406,6 +412,12 @@ static void* ThreadEntry(void* arg) { } +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 f84e80d1..04c25a90 100644 --- a/src/platform-solaris.cc +++ b/src/platform-solaris.cc @@ -401,6 +401,12 @@ bool ThreadHandle::IsValid() const { Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) { + set_name("v8:<unknown>"); +} + + +Thread::Thread(const char* name) : ThreadHandle(ThreadHandle::INVALID) { + set_name(name); } @@ -420,6 +426,12 @@ static void* ThreadEntry(void* arg) { } +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 4438045e..81216e19 100644 --- a/src/platform-win32.cc +++ b/src/platform-win32.cc @@ -1463,6 +1463,19 @@ class Thread::PlatformData : public Malloced { 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 5a3e4a3f..7b170674 100644 --- a/src/platform.h +++ b/src/platform.h @@ -387,6 +387,7 @@ class Thread: public ThreadHandle { // 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 @@ class Thread: public ThreadHandle { // 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 @@ class Thread: public ThreadHandle { // 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/preparse-data.cc b/src/preparse-data.cc index 9a367718..7c9d8a61 100644 --- a/src/preparse-data.cc +++ b/src/preparse-data.cc @@ -110,26 +110,29 @@ Vector<unsigned> PartialParserRecorder::ExtractData() { CompleteParserRecorder::CompleteParserRecorder() : FunctionLoggingParserRecorder(), + literal_chars_(0), symbol_store_(0), - symbol_entries_(0), + symbol_keys_(0), symbol_table_(vector_compare), symbol_id_(0) { } -void CompleteParserRecorder::LogSymbol( - int start, const char* literal_chars, int length) { - if (!is_recording_) return; - - Vector<const char> literal(literal_chars, length); - int hash = vector_hash(literal); - HashMap::Entry* entry = symbol_table_.Lookup(&literal, hash, true); +void CompleteParserRecorder::LogSymbol(int start, + int hash, + bool is_ascii, + Vector<const byte> literal_bytes) { + Key key = { is_ascii, literal_bytes }; + HashMap::Entry* entry = symbol_table_.Lookup(&key, hash, true); int id = static_cast<int>(reinterpret_cast<intptr_t>(entry->value)); if (id == 0) { + // Copy literal contents for later comparison. + key.literal_bytes = + Vector<const byte>::cast(literal_chars_.AddBlock(literal_bytes)); // Put (symbol_id_ + 1) into entry and increment it. id = ++symbol_id_; entry->value = reinterpret_cast<void*>(id); - Vector<Vector<const char> > symbol = symbol_entries_.AddBlock(1, literal); + Vector<Key> symbol = symbol_keys_.AddBlock(1, key); entry->key = &symbol[0]; } WriteNumber(id - 1); diff --git a/src/preparse-data.h b/src/preparse-data.h index a96e50fa..cc82bcc6 100644 --- a/src/preparse-data.h +++ b/src/preparse-data.h @@ -75,7 +75,8 @@ class ParserRecorder { int properties) = 0; // Logs a symbol creation of a literal or identifier. - virtual void LogSymbol(int start, const char* symbol, int length) = 0; + virtual void LogAsciiSymbol(int start, Vector<const char> literal) { } + virtual void LogUC16Symbol(int start, Vector<const uc16> literal) { } // Logs an error message and marks the log as containing an error. // Further logging will be ignored, and ExtractData will return a vector @@ -165,7 +166,8 @@ class FunctionLoggingParserRecorder : public ParserRecorder { class PartialParserRecorder : public FunctionLoggingParserRecorder { public: PartialParserRecorder() : FunctionLoggingParserRecorder() { } - virtual void LogSymbol(int start, const char* symbol, int length) { } + virtual void LogAsciiSymbol(int start, Vector<const char> literal) { } + virtual void LogUC16Symbol(int start, Vector<const uc16> literal) { } virtual ~PartialParserRecorder() { } virtual Vector<unsigned> ExtractData(); virtual int symbol_position() { return 0; } @@ -181,7 +183,17 @@ class CompleteParserRecorder: public FunctionLoggingParserRecorder { CompleteParserRecorder(); virtual ~CompleteParserRecorder() { } - virtual void LogSymbol(int start, const char* symbol, int length); + virtual void LogAsciiSymbol(int start, Vector<const char> literal) { + if (!is_recording_) return; + int hash = vector_hash(literal); + LogSymbol(start, hash, true, Vector<const byte>::cast(literal)); + } + + virtual void LogUC16Symbol(int start, Vector<const uc16> literal) { + if (!is_recording_) return; + int hash = vector_hash(literal); + LogSymbol(start, hash, false, Vector<const byte>::cast(literal)); + } virtual Vector<unsigned> ExtractData(); @@ -189,10 +201,21 @@ class CompleteParserRecorder: public FunctionLoggingParserRecorder { virtual int symbol_ids() { return symbol_id_; } private: - static int vector_hash(Vector<const char> string) { + struct Key { + bool is_ascii; + Vector<const byte> literal_bytes; + }; + + virtual void LogSymbol(int start, + int hash, + bool is_ascii, + Vector<const byte> literal); + + template <typename Char> + static int vector_hash(Vector<const Char> string) { int hash = 0; for (int i = 0; i < string.length(); i++) { - int c = string[i]; + int c = static_cast<int>(string[i]); hash += c; hash += (hash << 10); hash ^= (hash >> 6); @@ -201,18 +224,21 @@ class CompleteParserRecorder: public FunctionLoggingParserRecorder { } static bool vector_compare(void* a, void* b) { - Vector<const char>* string1 = reinterpret_cast<Vector<const char>* >(a); - Vector<const char>* string2 = reinterpret_cast<Vector<const char>* >(b); - int length = string1->length(); - if (string2->length() != length) return false; - return memcmp(string1->start(), string2->start(), length) == 0; + Key* string1 = reinterpret_cast<Key*>(a); + Key* string2 = reinterpret_cast<Key*>(b); + if (string1->is_ascii != string2->is_ascii) return false; + int length = string1->literal_bytes.length(); + if (string2->literal_bytes.length() != length) return false; + return memcmp(string1->literal_bytes.start(), + string2->literal_bytes.start(), length) == 0; } // Write a non-negative number to the symbol store. void WriteNumber(int number); + Collector<byte> literal_chars_; Collector<byte> symbol_store_; - Collector<Vector<const char> > symbol_entries_; + Collector<Key> symbol_keys_; HashMap symbol_table_; int symbol_id_; }; diff --git a/src/preparser-api.cc b/src/preparser-api.cc index cbec9b70..dba30265 100644 --- a/src/preparser-api.cc +++ b/src/preparser-api.cc @@ -155,7 +155,6 @@ class StandAloneJavaScriptScanner : public JavaScriptScanner { 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 7cce685e..e05f9037 100644 --- a/src/preparser.cc +++ b/src/preparser.cc @@ -950,13 +950,17 @@ PreParser::Expression PreParser::ParseObjectLiteral(bool* ok) { 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 @@ void PreParser::ExpectSemicolon(bool* ok) { } -PreParser::Identifier PreParser::GetIdentifierSymbol() { - const char* literal_chars = scanner_->literal_string(); - int literal_length = scanner_->literal_length(); +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()); + } +} - log_->LogSymbol(identifier_pos, literal_chars, literal_length); - return kUnknownExpression; +PreParser::Identifier PreParser::GetIdentifierSymbol() { + LogSymbol(); + return kUnknownIdentifier; } PreParser::Expression PreParser::GetStringSymbol() { - const char* literal_chars = scanner_->literal_string(); - int literal_length = scanner_->literal_length(); - - int literal_position = scanner_->location().beg_pos; - log_->LogSymbol(literal_position, literal_chars, literal_length); - + LogSymbol(); return kUnknownExpression; } @@ -1154,7 +1158,8 @@ PreParser::Identifier PreParser::ParseIdentifierName(bool* ok) { if (i::Token::IsKeyword(next)) { int pos = scanner_->location().beg_pos; const char* keyword = i::Token::String(next); - log_->LogSymbol(pos, keyword, i::StrLength(keyword)); + log_->LogAsciiSymbol(pos, i::Vector<const char>(keyword, + i::StrLength(keyword))); return kUnknownExpression; } if (next == i::Token::IDENTIFIER) { @@ -1173,8 +1178,8 @@ PreParser::Identifier PreParser::ParseIdentifierOrGetOrSet(bool* is_get, bool* is_set, bool* ok) { Expect(i::Token::IDENTIFIER, CHECK_OK); - if (scanner_->literal_length() == 3) { - const char* token = scanner_->literal_string(); + if (scanner_->is_literal_ascii() && scanner_->literal_length() == 3) { + const char* token = scanner_->literal_ascii_string().start(); *is_get = strncmp(token, "get", 3) == 0; *is_set = !*is_get && strncmp(token, "set", 3) == 0; } diff --git a/src/preparser.h b/src/preparser.h index 893b5751..536e6d4f 100644 --- a/src/preparser.h +++ b/src/preparser.h @@ -216,8 +216,11 @@ class PreParser { 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.cc b/src/scanner-base.cc index b26fee01..1babaebb 100644 --- a/src/scanner-base.cc +++ b/src/scanner-base.cc @@ -35,28 +35,6 @@ namespace v8 { namespace internal { // ---------------------------------------------------------------------------- -// LiteralCollector - -LiteralCollector::LiteralCollector() - : buffer_(kInitialCapacity), recording_(false) { } - - -LiteralCollector::~LiteralCollector() {} - - -void LiteralCollector::AddCharSlow(uc32 c) { - ASSERT(static_cast<unsigned>(c) > unibrow::Utf8::kMaxOneByteChar); - int length = unibrow::Utf8::Length(c); - Vector<char> block = buffer_.AddBlock(length, '\0'); -#ifdef DEBUG - int written_length = unibrow::Utf8::Encode(block.start(), c); - CHECK_EQ(length, written_length); -#else - unibrow::Utf8::Encode(block.start(), c); -#endif -} - -// ---------------------------------------------------------------------------- // Character predicates unibrow::Predicate<IdentifierStart, 128> ScannerConstants::kIsIdentifierStart; @@ -256,7 +234,7 @@ Token::Value JavaScriptScanner::ScanHtmlComment() { void JavaScriptScanner::Scan() { - next_.literal_chars = Vector<const char>(); + next_.literal_chars = NULL; Token::Value token; do { // Remember the position of the next token @@ -561,7 +539,7 @@ Token::Value JavaScriptScanner::ScanString() { uc32 quote = c0_; Advance(); // consume quote - LiteralScope literal(this, kLiteralString); + LiteralScope literal(this); while (c0_ != quote && c0_ >= 0 && !ScannerConstants::kIsLineTerminator.get(c0_)) { uc32 c = c0_; @@ -592,7 +570,7 @@ Token::Value JavaScriptScanner::ScanNumber(bool seen_period) { enum { DECIMAL, HEX, OCTAL } kind = DECIMAL; - LiteralScope literal(this, kLiteralNumber); + LiteralScope literal(this); if (seen_period) { // we have already seen a decimal point of the float AddLiteralChar('.'); @@ -681,7 +659,7 @@ uc32 JavaScriptScanner::ScanIdentifierUnicodeEscape() { Token::Value JavaScriptScanner::ScanIdentifierOrKeyword() { ASSERT(ScannerConstants::kIsIdentifierStart.get(c0_)); - LiteralScope literal(this, kLiteralIdentifier); + LiteralScope literal(this); KeywordMatcher keyword_match; // Scan identifier start character. if (c0_ == '\\') { @@ -747,7 +725,7 @@ bool JavaScriptScanner::ScanRegExpPattern(bool seen_equal) { // Scan regular expression body: According to ECMA-262, 3rd, 7.8.5, // the scanner should pass uninterpreted bodies to the RegExp // constructor. - LiteralScope literal(this, kLiteralRegExp); + LiteralScope literal(this); if (seen_equal) AddLiteralChar('='); @@ -773,7 +751,7 @@ bool JavaScriptScanner::ScanRegExpPattern(bool seen_equal) { bool JavaScriptScanner::ScanRegExpFlags() { // Scan regular expression flags. - LiteralScope literal(this, kLiteralRegExpFlags); + LiteralScope literal(this); while (ScannerConstants::kIsIdentifierPart.get(c0_)) { if (c0_ == '\\') { uc32 c = ScanIdentifierUnicodeEscape(); diff --git a/src/scanner-base.h b/src/scanner-base.h index c50b8f3e..b668df50 100644 --- a/src/scanner-base.h +++ b/src/scanner-base.h @@ -141,61 +141,105 @@ class ScannerConstants : AllStatic { }; // ---------------------------------------------------------------------------- -// LiteralCollector - Collector of chars of literals. +// LiteralBuffer - Collector of chars of literals. -class LiteralCollector { +class LiteralBuffer { public: - LiteralCollector(); - ~LiteralCollector(); - - inline void AddChar(uc32 c) { - if (recording_) { - if (static_cast<unsigned>(c) <= unibrow::Utf8::kMaxOneByteChar) { - buffer_.Add(static_cast<char>(c)); - } else { - AddCharSlow(c); + LiteralBuffer() : is_ascii_(true), position_(0), backing_store_() { } + + ~LiteralBuffer() { + if (backing_store_.length() > 0) { + backing_store_.Dispose(); + } + } + + inline void AddChar(uc16 character) { + if (position_ >= backing_store_.length()) ExpandBuffer(); + if (is_ascii_) { + if (character < kMaxAsciiCharCodeU) { + backing_store_[position_] = static_cast<byte>(character); + position_ += kASCIISize; + return; } + ConvertToUC16(); } + *reinterpret_cast<uc16*>(&backing_store_[position_]) = character; + position_ += kUC16Size; } - void StartLiteral() { - buffer_.StartSequence(); - recording_ = true; + bool is_ascii() { return is_ascii_; } + + Vector<const uc16> uc16_literal() { + ASSERT(!is_ascii_); + ASSERT((position_ & 0x1) == 0); + return Vector<const uc16>( + reinterpret_cast<const uc16*>(backing_store_.start()), + position_ >> 1); } - Vector<const char> EndLiteral() { - if (recording_) { - recording_ = false; - buffer_.Add(kEndMarker); - Vector<char> sequence = buffer_.EndSequence(); - return Vector<const char>(sequence.start(), sequence.length()); - } - return Vector<const char>(); + Vector<const char> ascii_literal() { + ASSERT(is_ascii_); + return Vector<const char>( + reinterpret_cast<const char*>(backing_store_.start()), + position_); } - void DropLiteral() { - if (recording_) { - recording_ = false; - buffer_.DropSequence(); - } + int length() { + return is_ascii_ ? position_ : (position_ >> 1); } void Reset() { - buffer_.Reset(); + position_ = 0; + is_ascii_ = true; } - - // The end marker added after a parsed literal. - // Using zero allows the usage of strlen and similar functions on - // identifiers and numbers (but not strings, since they may contain zero - // bytes). - static const char kEndMarker = '\x00'; private: - static const int kInitialCapacity = 256; - SequenceCollector<char, 4> buffer_; - bool recording_; - void AddCharSlow(uc32 c); + static const int kInitialCapacity = 16; + static const int kGrowthFactory = 4; + static const int kMinConversionSlack = 256; + static const int kMaxGrowth = 1 * MB; + inline int NewCapacity(int min_capacity) { + int capacity = Max(min_capacity, backing_store_.length()); + int new_capacity = Min(capacity * kGrowthFactory, capacity + kMaxGrowth); + return new_capacity; + } + + void ExpandBuffer() { + Vector<byte> new_store = Vector<byte>::New(NewCapacity(kInitialCapacity)); + memcpy(new_store.start(), backing_store_.start(), position_); + backing_store_.Dispose(); + backing_store_ = new_store; + } + + void ConvertToUC16() { + ASSERT(is_ascii_); + Vector<byte> new_store; + int new_content_size = position_ * kUC16Size; + 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_; + } + char* src = reinterpret_cast<char*>(backing_store_.start()); + uc16* dst = reinterpret_cast<uc16*>(new_store.start()); + for (int i = position_ - 1; i >= 0; i--) { + dst[i] = src[i]; + } + if (new_store.start() != backing_store_.start()) { + backing_store_.Dispose(); + backing_store_ = new_store; + } + position_ = new_content_size; + is_ascii_ = false; + } + + bool is_ascii_; + int position_; + Vector<byte> backing_store_; }; + // ---------------------------------------------------------------------------- // Scanner base-class. @@ -241,35 +285,40 @@ class Scanner { // collected for identifiers, strings, and numbers. // These functions only give the correct result if the literal // was scanned between calls to StartLiteral() and TerminateLiteral(). - const char* literal_string() const { - return current_.literal_chars.start(); + bool is_literal_ascii() { + ASSERT_NOT_NULL(current_.literal_chars); + return current_.literal_chars->is_ascii(); } - - int literal_length() const { - // Excluding terminal '\x00' added by TerminateLiteral(). - return current_.literal_chars.length() - 1; + Vector<const char> literal_ascii_string() { + ASSERT_NOT_NULL(current_.literal_chars); + return current_.literal_chars->ascii_literal(); } - - Vector<const char> literal() const { - return Vector<const char>(literal_string(), literal_length()); + Vector<const uc16> literal_uc16_string() { + ASSERT_NOT_NULL(current_.literal_chars); + return current_.literal_chars->uc16_literal(); + } + int literal_length() const { + ASSERT_NOT_NULL(current_.literal_chars); + return current_.literal_chars->length(); } // Returns the literal string for the next token (the token that // would be returned if Next() were called). - const char* next_literal_string() const { - return next_.literal_chars.start(); + bool is_next_literal_ascii() { + ASSERT_NOT_NULL(next_.literal_chars); + return next_.literal_chars->is_ascii(); } - - - // Returns the length of the next token (that would be returned if - // Next() were called). - int next_literal_length() const { - // Excluding terminal '\x00' added by TerminateLiteral(). - return next_.literal_chars.length() - 1; + Vector<const char> next_literal_ascii_string() { + ASSERT_NOT_NULL(next_.literal_chars); + return next_.literal_chars->ascii_literal(); } - - Vector<const char> next_literal() const { - return Vector<const char>(next_literal_string(), next_literal_length()); + Vector<const uc16> next_literal_uc16_string() { + ASSERT_NOT_NULL(next_.literal_chars); + return next_.literal_chars->uc16_literal(); + } + int next_literal_length() const { + ASSERT_NOT_NULL(next_.literal_chars); + return next_.literal_chars->length(); } static const int kCharacterLookaheadBufferSize = 1; @@ -279,7 +328,7 @@ class Scanner { struct TokenDesc { Token::Value token; Location location; - Vector<const char> literal_chars; + LiteralBuffer* literal_chars; }; // Call this after setting source_ to the input. @@ -288,29 +337,31 @@ class Scanner { ASSERT(kCharacterLookaheadBufferSize == 1); Advance(); // Initialize current_ to not refer to a literal. - current_.literal_chars = Vector<const char>(); - // Reset literal buffer. - literal_buffer_.Reset(); + current_.literal_chars = NULL; } // Literal buffer support inline void StartLiteral() { - literal_buffer_.StartLiteral(); + LiteralBuffer* free_buffer = (current_.literal_chars == &literal_buffer1_) ? + &literal_buffer2_ : &literal_buffer1_; + free_buffer->Reset(); + next_.literal_chars = free_buffer; } inline void AddLiteralChar(uc32 c) { - literal_buffer_.AddChar(c); + ASSERT_NOT_NULL(next_.literal_chars); + next_.literal_chars->AddChar(c); } // Complete scanning of a literal. inline void TerminateLiteral() { - next_.literal_chars = literal_buffer_.EndLiteral(); + // Does nothing in the current implementation. } // Stops scanning of a literal and drop the collected characters, // e.g., due to an encountered error. inline void DropLiteral() { - literal_buffer_.DropLiteral(); + next_.literal_chars = NULL; } inline void AddLiteralCharAdvance() { @@ -348,15 +399,16 @@ class Scanner { return source_->pos() - kCharacterLookaheadBufferSize; } + // Buffers collecting literal strings, numbers, etc. + LiteralBuffer literal_buffer1_; + LiteralBuffer literal_buffer2_; + TokenDesc current_; // desc for current token (as returned by Next()) TokenDesc next_; // desc for next token (one token look-ahead) // Input stream. Must be initialized to an UC16CharacterStream. UC16CharacterStream* source_; - // Buffer to hold literal values (identifiers, strings, numbers) - // using '\x00'-terminated UTF-8 encoding. Handles allocation internally. - LiteralCollector literal_buffer_; // One Unicode character look-ahead; c0_ < 0 at the end of the input. uc32 c0_; @@ -367,28 +419,14 @@ class Scanner { class JavaScriptScanner : public Scanner { public: - - // Bit vector representing set of types of literals. - enum LiteralType { - kNoLiterals = 0, - kLiteralNumber = 1, - kLiteralIdentifier = 2, - kLiteralString = 4, - kLiteralRegExp = 8, - kLiteralRegExpFlags = 16, - kAllLiterals = 31 - }; - // A LiteralScope that disables recording of some types of JavaScript // literals. If the scanner is configured to not record the specific // type of literal, the scope will not call StartLiteral. class LiteralScope { public: - LiteralScope(JavaScriptScanner* self, LiteralType type) + explicit LiteralScope(JavaScriptScanner* self) : scanner_(self), complete_(false) { - if (scanner_->RecordsLiteral(type)) { - scanner_->StartLiteral(); - } + scanner_->StartLiteral(); } ~LiteralScope() { if (!complete_) scanner_->DropLiteral(); @@ -430,11 +468,6 @@ class JavaScriptScanner : public Scanner { // tokens, which is what it is used for. void SeekForward(int pos); - // Whether this scanner records the given literal type or not. - bool RecordsLiteral(LiteralType type) { - return (literal_flags_ & type) != 0; - } - protected: bool SkipWhiteSpace(); Token::Value SkipSingleLineComment(); @@ -458,7 +491,6 @@ class JavaScriptScanner : public Scanner { // If the escape sequence cannot be decoded the result is kBadChar. uc32 ScanIdentifierUnicodeEscape(); - int literal_flags_; bool has_line_terminator_before_next_; }; diff --git a/src/scanner.cc b/src/scanner.cc index 47e9895c..7fd6ef22 100755 --- a/src/scanner.cc +++ b/src/scanner.cc @@ -324,10 +324,8 @@ void Scanner::LiteralScope::Complete() { V8JavaScriptScanner::V8JavaScriptScanner() : JavaScriptScanner() { } -void V8JavaScriptScanner::Initialize(UC16CharacterStream* source, - int literal_flags) { +void V8JavaScriptScanner::Initialize(UC16CharacterStream* source) { source_ = source; - literal_flags_ = literal_flags | kLiteralIdentifier; // Need to capture identifiers in order to recognize "get" and "set" // in object literals. Init(); @@ -377,7 +375,7 @@ bool JsonScanner::SkipJsonWhiteSpace() { void JsonScanner::ScanJson() { - next_.literal_chars = Vector<const char>(); + next_.literal_chars = NULL; Token::Value token; do { // Remember the position of the next token @@ -459,7 +457,7 @@ Token::Value JsonScanner::ScanJsonString() { 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_ != '\\') { @@ -506,9 +504,6 @@ Token::Value JsonScanner::ScanJsonString() { Advance(); } } - if (c0_ != '"') { - return Token::ILLEGAL; - } literal.Complete(); Advance(); return Token::STRING; diff --git a/src/scanner.h b/src/scanner.h index 572778f8..bdf899b5 100644 --- a/src/scanner.h +++ b/src/scanner.h @@ -134,8 +134,7 @@ class ExternalTwoByteStringUC16CharacterStream: public UC16CharacterStream { class V8JavaScriptScanner : public JavaScriptScanner { public: V8JavaScriptScanner(); - void Initialize(UC16CharacterStream* source, - int literal_flags = kAllLiterals); + void Initialize(UC16CharacterStream* source); }; diff --git a/src/string-search.h b/src/string-search.h index eac84757..5de3c095 100644 --- a/src/string-search.h +++ b/src/string-search.h @@ -66,12 +66,7 @@ class StringSearchBase { } static inline bool IsAsciiString(Vector<const uc16> string) { - for (int i = 0, n = string.length(); i < n; i++) { - if (static_cast<unsigned>(string[i]) > String::kMaxAsciiCharCodeU) { - return false; - } - } - return true; + return String::IsAscii(string.start(), string.length()); } // The following tables are shared by all searches. diff --git a/src/string.js b/src/string.js index 95275995..ab0ab54f 100644 --- a/src/string.js +++ b/src/string.js @@ -127,7 +127,7 @@ function StringLastIndexOf(pat /* position */) { // length == 1 var index = subLength - patLength; if (%_ArgumentsLength() > 1) { var position = ToNumber(%_Arguments(1)); - if (!$isNaN(position)) { + if (!NUMBER_IS_NAN(position)) { position = TO_INTEGER(position); if (position < 0) { position = 0; @@ -170,7 +170,9 @@ void Top::InitializeThreadLocal() { // 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 35a66c69..346f673f 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 @@ namespace unibrow { 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 @@ static bool LookupPredicate(const int32_t* table, uint16_t size, uchar chr) { 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 @@ static int LookupMapping(const int32_t* table, 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 @@ uchar Utf8::CalculateValue(const byte* str, *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 @@ uchar Utf8::CalculateValue(const byte* str, 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 @@ uchar Utf8::CalculateValue(const byte* str, 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 @@ bool ConnectorPunctuation::Is(uchar c) { } 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 @@ static const int32_t kToLowercaseTable0[926] = { 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 @@ static const int32_t kToLowercaseTable1[138] = { 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 @@ int ToLowercase::Convert(uchar c, } 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 @@ static const int32_t kToUppercaseTable0[1108] = { 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 @@ static const int32_t kToUppercaseTable1[134] = { 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 @@ int ToUppercase::Convert(uchar c, } 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 @@ static const int32_t kEcma262CanonicalizeTable0[924] = { 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 @@ static const int32_t kEcma262CanonicalizeTable1[134] = { 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 @@ int Ecma262Canonicalize::Convert(uchar c, } 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 @@ static const MultiCharacterSpecialCase<2> kEcma262UnCanonicalizeMultiStrings1[71 {{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 @@ static const int32_t kEcma262UnCanonicalizeTable1[266] = { 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 @@ int Ecma262UnCanonicalize::Convert(uchar c, } 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 @@ static const int32_t kCanonicalizationRangeTable0[140] = { 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/utils.h b/src/utils.h index 62b8726b..21e70d75 100644 --- a/src/utils.h +++ b/src/utils.h @@ -530,6 +530,24 @@ class Collector { } + // Add a contiguous block of elements and return a vector backed + // by the added block. + // A basic Collector will keep this vector valid as long as the Collector + // is alive. + inline Vector<T> AddBlock(Vector<const T> source) { + if (source.length() > current_chunk_.length() - index_) { + Grow(source.length()); + } + T* position = current_chunk_.start() + index_; + index_ += source.length(); + size_ += source.length(); + for (int i = 0; i < source.length(); i++) { + position[i] = source[i]; + } + return Vector<T>(position, source.length()); + } + + // Write the contents of the collector into the provided vector. void WriteTo(Vector<T> destination) { ASSERT(size_ <= destination.length()); diff --git a/src/v8threads.cc b/src/v8threads.cc index b6e656d2..8a5fe690 100644 --- a/src/v8threads.cc +++ b/src/v8threads.cc @@ -380,7 +380,8 @@ ContextSwitcher* ContextSwitcher::singleton_ = NULL; ContextSwitcher::ContextSwitcher(int every_n_ms) - : keep_going_(true), + : Thread("v8:CtxtSwitcher"), + keep_going_(true), sleep_ms_(every_n_ms) { } diff --git a/src/v8utils.h b/src/v8utils.h index 87efbcfe..e9623be6 100644 --- a/src/v8utils.h +++ b/src/v8utils.h @@ -29,10 +29,7 @@ #define V8_V8UTILS_H_ #include "utils.h" -#ifdef ANDROID -// Cherry pick from r6346 to build on Android. -#include "platform.h" -#endif +#include "platform.h" // For va_list on Solaris. namespace v8 { namespace internal { diff --git a/src/version.cc b/src/version.cc index d2c09605..008f7799 100644 --- a/src/version.cc +++ b/src/version.cc @@ -1,4 +1,4 @@ -// Copyright 2010 the V8 project authors. All rights reserved. +// Copyright 2011 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -34,7 +34,7 @@ // cannot be changed without changing the SCons build script. #define MAJOR_VERSION 3 #define MINOR_VERSION 0 -#define BUILD_NUMBER 4 +#define BUILD_NUMBER 6 #define PATCH_LEVEL 1 #define CANDIDATE_VERSION false diff --git a/src/x64/assembler-x64.cc b/src/x64/assembler-x64.cc index 8f15f23b..36299677 100644 --- a/src/x64/assembler-x64.cc +++ b/src/x64/assembler-x64.cc @@ -74,7 +74,7 @@ void CpuFeatures::Probe(bool portable) { __ 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 fde88df7..7bcc7c56 100644 --- a/src/x64/assembler-x64.h +++ b/src/x64/assembler-x64.h @@ -536,6 +536,8 @@ class Assembler : public Malloced { // 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 456d0765..d738261a 100644 --- a/src/x64/builtins-x64.cc +++ b/src/x64/builtins-x64.cc @@ -422,7 +422,7 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, // [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 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, // 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 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, // 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 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) { // 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 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) { { 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 c3eb5bf4..60ec35d0 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -104,7 +104,7 @@ void FastNewContextStub::Generate(MacroAssembler* masm) { __ 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 @@ void ToBooleanStub::Generate(MacroAssembler* masm) { __ movq(rax, Immediate(1)); __ ret(1 * kPointerSize); __ bind(&false_result); - __ xor_(rax, rax); + __ Set(rax, 0); __ ret(1 * kPointerSize); } @@ -2572,7 +2572,7 @@ void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { // 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 @@ void CEntryStub::GenerateThrowUncatchable(MacroAssembler* masm, } // 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 eb7ad267..0fe4f8ad 100644 --- a/src/x64/code-stubs-x64.h +++ b/src/x64/code-stubs-x64.h @@ -87,7 +87,7 @@ class GenericBinaryOpStub: public CodeStub { 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 @@ class GenericBinaryOpStub: public CodeStub { 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 NumberToStringStub: public CodeStub { }; -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 9a255722..aa5d3357 100644 --- a/src/x64/codegen-x64.cc +++ b/src/x64/codegen-x64.cc @@ -6813,12 +6813,8 @@ void CodeGenerator::GenerateSwapElements(ZoneList<Expression*>* args) { // (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 @@ ModuloFunction CreateModuloFunction() { #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 2c1056f5..4218647f 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 @@ namespace internal { #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 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm, // 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 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm, #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 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm, } -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,34 +217,33 @@ void Debug::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) { } -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::GenerateReturnDebugBreak(MacroAssembler* masm) { +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: return value + // -- rax: number of arguments // ----------------------------------- - Generate_DebugBreakCallHelper(masm, rax.bit(), 0, true); + // The number of arguments in rax is not smi encoded. + Generate_DebugBreakCallHelper(masm, rdi.bit(), rax.bit(), false); } -void Debug::GenerateStoreICDebugBreak(MacroAssembler* masm) { - // Register state for IC store call (from ic-x64.cc). +void Debug::GenerateReturnDebugBreak(MacroAssembler* masm) { + // Register state just before return from JS function (from codegen-x64.cc). // ----------- S t a t e ------------- - // -- rax : value - // -- rcx : name - // -- rdx : receiver + // -- rax: return value // ----------------------------------- - Generate_DebugBreakCallHelper( - masm, rax.bit() | rcx.bit() | rdx.bit(), 0, false); + Generate_DebugBreakCallHelper(masm, rax.bit(), 0, true); } @@ -262,49 +309,6 @@ const bool Debug::kFrameDropperSupported = true; #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 dd28d4d8..66bc4ede 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -199,7 +199,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { void FullCodeGenerator::ClearAccumulator() { - __ xor_(rax, rax); + __ Set(rax, 0); } diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc index aff778a5..29cbed05 100644 --- a/src/x64/ic-x64.cc +++ b/src/x64/ic-x64.cc @@ -378,81 +378,50 @@ static void GenerateNumberDictionaryLoad(MacroAssembler* masm, } -// One byte opcode for test rax,0xXXXXXXXX. -static const byte kTestEaxByte = 0xA9; - - -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; -} - +// The offset from the inlined patch site to the start of the inlined +// load instruction. +const int LoadIC::kOffsetToLoadInstruction = 20; -bool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) { - return PatchInlinedMapCheck(address, map); -} +void LoadIC::GenerateArrayLength(MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- rax : receiver + // -- rcx : name + // -- rsp[0] : return address + // ----------------------------------- + Label miss; -bool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) { - return PatchInlinedMapCheck(address, map); + StubCompiler::GenerateLoadArrayLength(masm, rax, rdx, &miss); + __ bind(&miss); + StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); } -void KeyedLoadIC::GenerateMiss(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; - __ 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::GenerateLoadStringLength(masm, rax, rdx, rbx, &miss); + __ bind(&miss); + StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); } -void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { +void LoadIC::GenerateFunctionPrototype(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 - - // Perform tail call to the entry. - __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); + StubCompiler::GenerateLoadFunctionPrototype(masm, rax, rdx, rbx, &miss); + __ bind(&miss); + StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); } @@ -923,45 +892,6 @@ void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) { } -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 @@ void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm, } -// 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 @@ static void GenerateCallNormal(MacroAssembler* masm, int argc) { } -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 @@ void CallIC::GenerateMiss(MacroAssembler* masm, int argc) { // 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 CallIC::GenerateNormal(MacroAssembler* masm, int argc) { } -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 @@ void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) { // rsp[(argc + 1) * 8] : argument 0 = receiver // ----------------------------------- - GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss); + GenerateCallMiss(masm, argc, IC::kCallIC_Miss); } @@ -1594,56 +1506,18 @@ void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) { } -// 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) { - // ----------- S t a t e ------------- - // -- rax : receiver - // -- rcx : name - // -- rsp[0] : return address - // ----------------------------------- - - __ 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) { +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 // ----------------------------------- - 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::GenerateNormal(MacroAssembler* masm) { } -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 @@ bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) { 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 @@ bool LoadIC::PatchInlinedContextualLoad(Address address, } -// 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 @@ bool StoreIC::PatchInlinedStore(Address address, Object* map, int offset) { // 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 @@ bool StoreIC::PatchInlinedStore(Address address, Object* map, int offset) { } -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(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); + 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(rax); // name + __ push(rbx); // return address + + // Perform tail call to the entry. + __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); } @@ -1831,6 +1760,31 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm) { } +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 StoreIC::GenerateGlobalProxy(MacroAssembler* masm) { } +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 @@ void PatchInlinedSmiCode(Address address) { 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 1df9b475..70a3dab6 100644 --- a/src/x64/macro-assembler-x64.cc +++ b/src/x64/macro-assembler-x64.cc @@ -1110,7 +1110,7 @@ void MacroAssembler::SmiAnd(Register dst, Register src1, Register src2) { 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 @@ void MacroAssembler::DecrementCounter(StatsCounter* counter, int value) { #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 d8f2fba4..30b9ba51 100644 --- a/src/x64/macro-assembler-x64.h +++ b/src/x64/macro-assembler-x64.h @@ -1176,7 +1176,7 @@ void MacroAssembler::SmiMul(Register dst, 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 2cf85f11..27f3482a 100644 --- a/src/x64/regexp-macro-assembler-x64.cc +++ b/src/x64/regexp-macro-assembler-x64.cc @@ -223,9 +223,7 @@ void RegExpMacroAssemblerX64::CheckCharacters(Vector<const uc16> str, // If input is ASCII, don't even bother calling here if the string to // match contains a non-ascii character. if (mode_ == ASCII) { - for (int i = 0; i < str.length(); i++) { - ASSERT(str[i] <= String::kMaxAsciiCharCodeU); - } + ASSERT(String::IsAscii(str.start(), str.length())); } #endif int byte_length = str.length() * char_size(); @@ -690,7 +688,7 @@ bool RegExpMacroAssemblerX64::CheckSpecialCharacterClass(uc16 type, 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 63e97695..57cba142 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 @@ static void GenerateDictionaryNegativeLookup(MacroAssembler* masm, } -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 @@ void StubCache::GenerateProbe(MacroAssembler* masm, } -// 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); +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)); +} - // 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::GenerateLoadStringLength(MacroAssembler* masm, } +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 @@ static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm, } - -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 @@ static bool GenerateFastApiCall(MacroAssembler* masm, // -- 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 @@ class CallInterceptorCompiler BASE_EMBEDDED { }; +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 @@ MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCell( #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::GenerateMissBranch() { } -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 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object, __ InNewSpace(rbx, rcx, equal, &exit); - RecordWriteStub stub(rbx, rdx, rcx); - __ CallStub(&stub); + __ RecordWriteHelper(rbx, rdx, rcx); __ ret((argc + 1) * kPointerSize); @@ -1408,7 +1640,7 @@ MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object, } -MaybeObject* CallStubCompiler::CompileStringCharAtCall( +MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall( Object* object, JSObject* holder, JSGlobalPropertyCell* cell, @@ -1441,10 +1673,9 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall( CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, rbx, rdx, rdi, name, &miss); - Register receiver = rax; + Register receiver = rbx; Register index = rdi; - Register scratch1 = rbx; - Register scratch2 = rdx; + Register scratch = rdx; Register result = rax; __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize)); if (argc > 0) { @@ -1453,23 +1684,22 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall( __ LoadRoot(index, Heap::kUndefinedValueRootIndex); } - StringCharAtGenerator char_at_generator(receiver, - index, - scratch1, - scratch2, - result, - &miss, // When not a string. - &miss, // When not a number. - &index_out_of_range, - STRING_INDEX_IS_NUMBER); - char_at_generator.GenerateFast(masm()); + 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_at_generator.GenerateSlow(masm(), call_helper); + char_code_at_generator.GenerateSlow(masm(), call_helper); __ bind(&index_out_of_range); - __ LoadRoot(rax, Heap::kEmptyStringRootIndex); + __ LoadRoot(rax, Heap::kNanValueRootIndex); __ ret((argc + 1) * kPointerSize); __ bind(&miss); @@ -1483,7 +1713,7 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall( } -MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall( +MaybeObject* CallStubCompiler::CompileStringCharAtCall( Object* object, JSObject* holder, JSGlobalPropertyCell* cell, @@ -1504,6 +1734,7 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall( Label miss; Label index_out_of_range; + GenerateNameCheck(name, &miss); // Check that the maps starting from the prototype haven't changed. @@ -1515,9 +1746,10 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall( CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, rbx, rdx, rdi, name, &miss); - Register receiver = rbx; + Register receiver = rax; Register index = rdi; - Register scratch = rdx; + Register scratch1 = rbx; + Register scratch2 = rdx; Register result = rax; __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize)); if (argc > 0) { @@ -1526,22 +1758,23 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall( __ 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()); + StringCharAtGenerator char_at_generator(receiver, + index, + scratch1, + scratch2, + result, + &miss, // When not a string. + &miss, // When not a number. + &index_out_of_range, + STRING_INDEX_IS_NUMBER); + char_at_generator.GenerateFast(masm()); __ ret((argc + 1) * kPointerSize); StubRuntimeCallHelper call_helper; - char_code_at_generator.GenerateSlow(masm(), call_helper); + char_at_generator.GenerateSlow(masm(), call_helper); __ bind(&index_out_of_range); - __ LoadRoot(rax, Heap::kNanValueRootIndex); + __ LoadRoot(rax, Heap::kEmptyStringRootIndex); __ ret((argc + 1) * kPointerSize); __ bind(&miss); @@ -1741,6 +1974,178 @@ MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object, } +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,50 +2286,260 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object, } -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 + // -- rdx : receiver // -- 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; + // 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::CompileStoreCallback(JSObject* object, + AccessorInfo* callback, + String* name) { + // ----------- S t a t e ------------- + // -- rax : value + // -- rcx : name + // -- rdx : receiver + // -- rsp[0] : return address + // ----------------------------------- + Label miss; + + // Check that the object isn't a smi. + __ JumpIfSmi(rdx, &miss); + + // Check that the map of the object hasn't changed. + __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), + Handle<Map>(object->map())); + __ j(not_equal, &miss); + + // Perform global security token check if needed. + if (object->IsJSGlobalProxy()) { + __ CheckAccessGlobalProxy(rdx, rbx, &miss); } + // Stub never generated for non-global objects that require access + // checks. + ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); + + __ pop(rbx); // remove the return address + __ push(rdx); // receiver + __ Push(Handle<AccessorInfo>(callback)); // callback info + __ push(rcx); // name + __ push(rax); // value + __ push(rbx); // restore return address + + // Do tail-call to the runtime system. + ExternalReference store_callback_property = + ExternalReference(IC_Utility(IC::kStoreCallbackProperty)); + __ TailCallExternalReference(store_callback_property, 4, 1); + + // Handle store cache miss. __ bind(&miss); - GenerateLoadMiss(masm(), Code::LOAD_IC); + Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); + __ Jump(ic, RelocInfo::CODE_TARGET); // Return the generated code. return GetCode(CALLBACKS, name); } -MaybeObject* LoadStubCompiler::CompileLoadConstant(JSObject* object, - JSObject* holder, - Object* value, +MaybeObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver, + String* name) { + // ----------- S t a t e ------------- + // -- rax : value + // -- rcx : name + // -- rdx : receiver + // -- rsp[0] : return address + // ----------------------------------- + Label miss; + + // Check that the object isn't a smi. + __ JumpIfSmi(rdx, &miss); + + // Check that the map of the object hasn't changed. + __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), + Handle<Map>(receiver->map())); + __ j(not_equal, &miss); + + // Perform global security token check if needed. + if (receiver->IsJSGlobalProxy()) { + __ CheckAccessGlobalProxy(rdx, rbx, &miss); + } + + // Stub never generated for non-global objects that require access + // checks. + ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded()); + + __ pop(rbx); // remove the return address + __ push(rdx); // receiver + __ push(rcx); // name + __ push(rax); // value + __ push(rbx); // restore return address + + // Do tail-call to the runtime system. + ExternalReference store_ic_property = + ExternalReference(IC_Utility(IC::kStoreInterceptorProperty)); + __ TailCallExternalReference(store_ic_property, 3, 1); + + // 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(INTERCEPTOR, name); +} + + +MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object, + JSGlobalPropertyCell* cell, String* name) { // ----------- S t a t e ------------- - // -- rax : receiver + // -- rax : value // -- rcx : name + // -- rdx : receiver // -- rsp[0] : return address // ----------------------------------- Label miss; - GenerateLoadConstant(object, holder, rax, rbx, rdx, rdi, value, name, &miss); + // Check that the map of the global has not changed. + __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), + Handle<Map>(object->map())); + __ j(not_equal, &miss); + + // Store the value in the cell. + __ Move(rcx, Handle<JSGlobalPropertyCell>(cell)); + __ movq(FieldOperand(rcx, JSGlobalPropertyCell::kValueOffset), rax); + + // Return the value (register rax). + __ IncrementCounter(&Counters::named_store_global_inline, 1); + __ ret(0); + + // Handle store cache miss. __ bind(&miss); - GenerateLoadMiss(masm(), Code::LOAD_IC); + __ IncrementCounter(&Counters::named_store_global_inline_miss, 1); + Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); + __ Jump(ic, RelocInfo::CODE_TARGET); // Return the generated code. - return GetCode(CONSTANT_FUNCTION, name); + return GetCode(NORMAL, name); +} + + +MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object, + int index, + Map* transition, + String* name) { + // ----------- S t a t e ------------- + // -- rax : value + // -- rcx : key + // -- rdx : receiver + // -- rsp[0] : return address + // ----------------------------------- + Label miss; + + __ IncrementCounter(&Counters::keyed_store_field, 1); + + // Check that the name has not changed. + __ Cmp(rcx, Handle<String>(name)); + __ j(not_equal, &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); + __ DecrementCounter(&Counters::keyed_store_field, 1); + Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss)); + __ Jump(ic, RelocInfo::CODE_TARGET); + + // Return the generated code. + return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name); +} + + +MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized( + JSObject* receiver) { + // ----------- S t a t e ------------- + // -- rax : value + // -- rcx : key + // -- rdx : receiver + // -- rsp[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(rcx, &miss); + + // Get the elements array and make sure it is a fast element array, not 'cow'. + __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset)); + __ Cmp(FieldOperand(rdi, HeapObject::kMapOffset), + Factory::fixed_array_map()); + __ j(not_equal, &miss); + + // Check that the key is within bounds. + if (receiver->IsJSArray()) { + __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset)); + __ j(above_equal, &miss); + } else { + __ SmiCompare(rcx, FieldOperand(rdi, FixedArray::kLengthOffset)); + __ j(above_equal, &miss); + } + + // Do the store and update the write barrier. Make sure to preserve + // the value in register eax. + __ movq(rdx, rax); + __ SmiToInteger32(rcx, rcx); + __ movq(FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize), + rax); + __ RecordWrite(rdi, 0, rdx, rcx); + + // Done. + __ ret(0); + + // Handle store cache miss. + __ bind(&miss); + Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss)); + __ jmp(ic, RelocInfo::CODE_TARGET); + + // Return the generated code. + return GetCode(NORMAL, NULL); } @@ -1993,6 +2608,53 @@ MaybeObject* LoadStubCompiler::CompileLoadField(JSObject* object, } +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) { @@ -2075,11 +2737,10 @@ MaybeObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object, } -MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback( - String* name, - JSObject* receiver, - JSObject* holder, - AccessorInfo* callback) { +MaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name, + JSObject* receiver, + JSObject* holder, + int index) { // ----------- S t a t e ------------- // -- rax : key // -- rdx : receiver @@ -2087,46 +2748,52 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback( // ----------------------------------- Label miss; - __ IncrementCounter(&Counters::keyed_load_callback, 1); + __ IncrementCounter(&Counters::keyed_load_field, 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; - } + GenerateLoadField(receiver, holder, rdx, rbx, rcx, rdi, index, name, &miss); __ bind(&miss); - __ DecrementCounter(&Counters::keyed_load_callback, 1); + __ DecrementCounter(&Counters::keyed_load_field, 1); GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); // Return the generated code. - return GetCode(CALLBACKS, name); + return GetCode(FIELD, name); } -MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) { +MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback( + String* name, + JSObject* receiver, + JSObject* holder, + AccessorInfo* callback) { // ----------- S t a t e ------------- - // -- rax : key - // -- rdx : receiver + // -- rax : key + // -- rdx : receiver // -- rsp[0] : return address // ----------------------------------- Label miss; - __ IncrementCounter(&Counters::keyed_load_array_length, 1); + __ IncrementCounter(&Counters::keyed_load_callback, 1); // Check that the name has not changed. __ Cmp(rax, Handle<String>(name)); __ j(not_equal, &miss); - GenerateLoadArrayLength(masm(), rdx, rcx, &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_array_length, 1); + + __ DecrementCounter(&Counters::keyed_load_callback, 1); GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); // Return the generated code. @@ -2162,30 +2829,6 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadConstant(String* 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) { @@ -2223,23 +2866,23 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, } -MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { +MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) { // ----------- S t a t e ------------- // -- rax : key // -- rdx : receiver - // -- rsp[0] : return address + // -- rsp[0] : return address // ----------------------------------- Label miss; - __ IncrementCounter(&Counters::keyed_load_string_length, 1); + __ IncrementCounter(&Counters::keyed_load_array_length, 1); // Check that the name has not changed. __ Cmp(rax, Handle<String>(name)); __ j(not_equal, &miss); - GenerateLoadStringLength(masm(), rdx, rcx, rbx, &miss); + GenerateLoadArrayLength(masm(), rdx, rcx, &miss); __ bind(&miss); - __ DecrementCounter(&Counters::keyed_load_string_length, 1); + __ DecrementCounter(&Counters::keyed_load_array_length, 1); GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); // Return the generated code. @@ -2247,287 +2890,59 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { } -MaybeObject* KeyedLoadStubCompiler::CompileLoadSpecialized(JSObject* receiver) { +MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { // ----------- 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); -} - - -MaybeObject* StoreStubCompiler::CompileStoreCallback(JSObject* object, - AccessorInfo* callback, - String* name) { - // ----------- S t a t e ------------- - // -- rax : value - // -- rcx : name - // -- rdx : receiver // -- rsp[0] : return address // ----------------------------------- Label miss; - // Check that the object isn't a smi. - __ JumpIfSmi(rdx, &miss); + __ IncrementCounter(&Counters::keyed_load_string_length, 1); - // Check that the map of the object hasn't changed. - __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), - Handle<Map>(object->map())); + // Check that the name has not changed. + __ Cmp(rax, Handle<String>(name)); __ j(not_equal, &miss); - // Perform global security token check if needed. - if (object->IsJSGlobalProxy()) { - __ CheckAccessGlobalProxy(rdx, rbx, &miss); - } - - // Stub never generated for non-global objects that require access - // checks. - ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); - - __ pop(rbx); // remove the return address - __ push(rdx); // receiver - __ Push(Handle<AccessorInfo>(callback)); // callback info - __ push(rcx); // name - __ push(rax); // value - __ push(rbx); // restore return address - - // Do tail-call to the runtime system. - ExternalReference store_callback_property = - ExternalReference(IC_Utility(IC::kStoreCallbackProperty)); - __ TailCallExternalReference(store_callback_property, 4, 1); - - // Handle store cache miss. + GenerateLoadStringLength(masm(), rdx, rcx, rbx, &miss); __ bind(&miss); - Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); - __ Jump(ic, RelocInfo::CODE_TARGET); + __ DecrementCounter(&Counters::keyed_load_string_length, 1); + GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); // Return the generated code. return GetCode(CALLBACKS, name); } -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 ------------- - // -- rax : value - // -- rcx : name - // -- rdx : receiver - // -- rsp[0] : return address - // ----------------------------------- - Label miss; - - // Check that the object isn't a smi. - __ JumpIfSmi(rdx, &miss); - - // Check that the map of the object hasn't changed. - __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), - Handle<Map>(receiver->map())); - __ j(not_equal, &miss); - - // Perform global security token check if needed. - if (receiver->IsJSGlobalProxy()) { - __ CheckAccessGlobalProxy(rdx, rbx, &miss); - } - - // Stub never generated for non-global objects that require access - // checks. - ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded()); - - __ pop(rbx); // remove the return address - __ push(rdx); // receiver - __ push(rcx); // name - __ push(rax); // value - __ push(rbx); // restore return address - - // Do tail-call to the runtime system. - ExternalReference store_ic_property = - ExternalReference(IC_Utility(IC::kStoreInterceptorProperty)); - __ TailCallExternalReference(store_ic_property, 3, 1); - - // 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(INTERCEPTOR, name); -} - - -MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object, - JSGlobalPropertyCell* cell, - String* name) { +MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) { // ----------- S t a t e ------------- - // -- rax : value - // -- rcx : name + // -- rax : key // -- rdx : receiver - // -- rsp[0] : return address - // ----------------------------------- - Label miss; - - // Check that the map of the global has not changed. - __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), - Handle<Map>(object->map())); - __ j(not_equal, &miss); - - // Store the value in the cell. - __ Move(rcx, Handle<JSGlobalPropertyCell>(cell)); - __ movq(FieldOperand(rcx, JSGlobalPropertyCell::kValueOffset), rax); - - // Return the value (register rax). - __ IncrementCounter(&Counters::named_store_global_inline, 1); - __ ret(0); - - // Handle store cache miss. - __ bind(&miss); - __ IncrementCounter(&Counters::named_store_global_inline_miss, 1); - Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); - __ Jump(ic, RelocInfo::CODE_TARGET); - - // Return the generated code. - return GetCode(NORMAL, name); -} - - -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); + __ IncrementCounter(&Counters::keyed_load_function_prototype, 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); - + GenerateLoadFunctionPrototype(masm(), rdx, rcx, rbx, &miss); __ bind(&miss); - __ DecrementCounter(&Counters::keyed_load_field, 1); + __ DecrementCounter(&Counters::keyed_load_function_prototype, 1); GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); // Return the generated code. - return GetCode(FIELD, name); -} - - -MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object, - int index, - Map* transition, - String* name) { - // ----------- S t a t e ------------- - // -- rax : value - // -- rcx : key - // -- rdx : receiver - // -- rsp[0] : return address - // ----------------------------------- - Label miss; - - __ IncrementCounter(&Counters::keyed_store_field, 1); - - // Check that the name has not changed. - __ Cmp(rcx, Handle<String>(name)); - __ j(not_equal, &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); - __ DecrementCounter(&Counters::keyed_store_field, 1); - Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss)); - __ Jump(ic, RelocInfo::CODE_TARGET); - - // Return the generated code. - return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name); + return GetCode(CALLBACKS, name); } -MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized( - JSObject* receiver) { +MaybeObject* KeyedLoadStubCompiler::CompileLoadSpecialized(JSObject* receiver) { // ----------- S t a t e ------------- - // -- rax : value - // -- rcx : key + // -- rax : key // -- rdx : receiver - // -- rsp[0] : return address + // -- esp[0] : return address // ----------------------------------- Label miss; @@ -2540,455 +2955,35 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized( __ j(not_equal, &miss); // Check that the key is a smi. - __ JumpIfNotSmi(rcx, &miss); + __ JumpIfNotSmi(rax, &miss); - // Get the elements array and make sure it is a fast element array, not 'cow'. - __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset)); - __ Cmp(FieldOperand(rdi, HeapObject::kMapOffset), - Factory::fixed_array_map()); - __ j(not_equal, &miss); + // Get the elements array. + __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset)); + __ AssertFastElements(rcx); // Check that the key is within bounds. - if (receiver->IsJSArray()) { - __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset)); - __ j(above_equal, &miss); - } else { - __ SmiCompare(rcx, FieldOperand(rdi, FixedArray::kLengthOffset)); - __ j(above_equal, &miss); - } - - // Do the store and update the write barrier. Make sure to preserve - // the value in register eax. - __ movq(rdx, rax); - __ SmiToInteger32(rcx, rcx); - __ movq(FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize), - rax); - __ RecordWrite(rdi, 0, rdx, rcx); + __ SmiCompare(rax, FieldOperand(rcx, FixedArray::kLengthOffset)); + __ j(above_equal, &miss); - // Done. + // 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); - // Handle store cache miss. __ bind(&miss); - Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss)); - __ jmp(ic, RelocInfo::CODE_TARGET); + GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); // Return the generated code. return GetCode(NORMAL, NULL); } -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); - } -} - - -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; -} - - -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); -} - - -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); -} - - // Specialized stub for constructing objects from functions which only have only // simple assignments of the form this.x = ...; in their body. MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) { diff --git a/test/cctest/test-assembler-ia32.cc b/test/cctest/test-assembler-ia32.cc index 40232ef5..14692ff1 100644 --- a/test/cctest/test-assembler-ia32.cc +++ b/test/cctest/test-assembler-ia32.cc @@ -74,7 +74,7 @@ TEST(AssemblerIa320) { Handle<Object>(Heap::undefined_value()))-> ToObjectChecked(); CHECK(code->IsCode()); -#ifdef DEBUG +#ifdef OBJECT_PRINT Code::cast(code)->Print(); #endif F2 f = FUNCTION_CAST<F2>(Code::cast(code)->entry()); @@ -112,7 +112,7 @@ TEST(AssemblerIa321) { Handle<Object>(Heap::undefined_value()))-> ToObjectChecked(); CHECK(code->IsCode()); -#ifdef DEBUG +#ifdef OBJECT_PRINT Code::cast(code)->Print(); #endif F1 f = FUNCTION_CAST<F1>(Code::cast(code)->entry()); @@ -155,7 +155,7 @@ TEST(AssemblerIa322) { Handle<Object>(Heap::undefined_value()))->ToObjectChecked(); CHECK(code->IsCode()); -#ifdef DEBUG +#ifdef OBJECT_PRINT Code::cast(code)->Print(); #endif F1 f = FUNCTION_CAST<F1>(Code::cast(code)->entry()); @@ -329,7 +329,7 @@ TEST(AssemblerIa328) { Code::ComputeFlags(Code::STUB), Handle<Object>(Heap::undefined_value()))->ToObjectChecked()); CHECK(code->IsCode()); -#ifdef DEBUG +#ifdef OBJECT_PRINT Code::cast(code)->Print(); #endif F6 f = FUNCTION_CAST<F6>(Code::cast(code)->entry()); @@ -384,7 +384,7 @@ TEST(AssemblerIa329) { Code::ComputeFlags(Code::STUB), Handle<Object>(Heap::undefined_value()))->ToObjectChecked()); CHECK(code->IsCode()); -#ifdef DEBUG +#ifdef OBJECT_PRINT Code::cast(code)->Print(); #endif diff --git a/test/cctest/test-disasm-ia32.cc b/test/cctest/test-disasm-ia32.cc index 5cd56acf..b563f8fc 100644 --- a/test/cctest/test-disasm-ia32.cc +++ b/test/cctest/test-disasm-ia32.cc @@ -443,7 +443,7 @@ TEST(DisasmIa320) { Code::ComputeFlags(Code::STUB), Handle<Object>(Heap::undefined_value()))->ToObjectChecked(); CHECK(code->IsCode()); -#ifdef DEBUG +#ifdef OBJECT_PRINT Code::cast(code)->Print(); byte* begin = Code::cast(code)->instruction_start(); byte* end = begin + Code::cast(code)->instruction_size(); diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc index e642d1b6..da5d771d 100755 --- a/test/cctest/test-parsing.cc +++ b/test/cctest/test-parsing.cc @@ -573,7 +573,7 @@ void TestStreamScanner(i::UC16CharacterStream* stream, int skip_pos = 0, // Zero means not skipping. int skip_to = 0) { i::V8JavaScriptScanner scanner; - scanner.Initialize(stream, i::JavaScriptScanner::kAllLiterals); + scanner.Initialize(stream); int i = 0; do { diff --git a/test/mjsunit/bugs/bug-1015.js b/test/mjsunit/bugs/bug-1015.js new file mode 100644 index 00000000..9e4406a9 --- /dev/null +++ b/test/mjsunit/bugs/bug-1015.js @@ -0,0 +1,66 @@ +// Copyright 2010 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// See: http://code.google.com/p/v8/issues/detail?id=1015 + +// Object and array literals should be created using DefineOwnProperty, and +// therefore not hit setters in the prototype. + +function mkFail(message) { + return function () { assertUnreachable(message); } +} + +Object.defineProperty(Object.prototype, "foo", + {get: mkFail("oget"), set: mkFail("oset")}); +Object.defineProperty(Array.prototype, "2", + {get: mkFail("aget"), set: mkFail("aset")}); + +function inFunction() { + for (var i = 0; i < 10; i++) { + // in loop. + var ja = JSON.parse('[1,2,3,4]'); + var jo = JSON.parse('{"bar": 10, "foo": 20}') + var jop = JSON.parse('{"bar": 10, "__proto__": { }, "foo": 20}') + var a = [1,2,3,4]; + var o = { bar: 10, foo: 20 }; + var op = { __proto__: { set bar(v) { assertUnreachable("bset"); } }, + bar: 10 }; + } +} + +for (var i = 0; i < 10; i++) { + // In global scope. + var ja = JSON.parse('[1,2,3,4]'); + var jo = JSON.parse('{"bar": 10, "foo": 20}') + var jop = JSON.parse('{"bar": 10, "__proto__": { }, "foo": 20}') + var a = [1,2,3,4]; + var o = { bar: 10, foo: 20 }; + var op = { __proto__: { set bar(v) { assertUnreachable("bset"); } }, + bar: 10 }; + // In function scope. + inFunction(); +} diff --git a/test/mjsunit/indexed-accessors.js b/test/mjsunit/indexed-accessors.js index 395f2ab3..16348570 100644 --- a/test/mjsunit/indexed-accessors.js +++ b/test/mjsunit/indexed-accessors.js @@ -81,19 +81,6 @@ testArray(); expected[0] = 111; testArray(); -// The functionality is not implemented for arrays due to performance issues. -var a = [ 1 ]; -a.__defineGetter__('2', function() { return 7; }); -assertEquals(undefined, a[2]); -assertEquals(1, a.length); -var b = 0; -a.__defineSetter__('5', function(y) { b = y; }); -assertEquals(1, a.length); -a[5] = 42; -assertEquals(0, b); -assertEquals(42, a[5]); -assertEquals(6, a.length); - // Using a setter where only a getter is defined throws an exception. var q = {}; q.__defineGetter__('0', function() { return 42; }); diff --git a/test/mjsunit/regress/regress-1017.js b/test/mjsunit/regress/regress-1017.js new file mode 100644 index 00000000..3daf5428 --- /dev/null +++ b/test/mjsunit/regress/regress-1017.js @@ -0,0 +1,36 @@ +// Copyright 2010 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// See: http://code.google.com/p/v8/issues/detail?id=1017 + +// 32 ASCII-characters followed by a non-ASCII character. +// This causes an internal buffer to first expand to 64 bytes, then expand the +// 32 ASCII characters to 64 bytes of UC16 characters, leaving no room +// to store the 33rd character. This fails an ASSERT in debug mode. + +assertEquals(33, "12345678901234567890123456789012\u2028".length); + diff --git a/test/mjsunit/regress/regress-900.js b/test/mjsunit/regress/regress-900.js new file mode 100644 index 00000000..9f94348d --- /dev/null +++ b/test/mjsunit/regress/regress-900.js @@ -0,0 +1,46 @@ +// Copyright 2011 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Check that we allow accessors on JSArray elements. + +var a = []; +var b = {} +Object.defineProperty(a, "1", {get: function() {return "foo";}}); +Object.defineProperty( + b, "1", {get: function() {return "bar";}, set: function() {this.x = 42;}}); +assertEquals(a[1], 'foo'); +assertEquals(b[1], 'bar'); +// Make sure we can't overwrite an accessor, but that the setter is +// instead called. +b[1] = 'foobar'; +assertEquals(b[1], 'bar'); +assertEquals(b.x, 42); + +var desc = Object.getOwnPropertyDescriptor(b, "1"); +assertEquals(desc['writable'], undefined); +assertFalse(desc['enumerable']); +assertFalse(desc['configurable']); diff --git a/test/mozilla/mozilla.status b/test/mozilla/mozilla.status index 1f9e6eb4..5688cf8d 100644 --- a/test/mozilla/mozilla.status +++ b/test/mozilla/mozilla.status @@ -653,8 +653,6 @@ js1_5/extensions/regress-336409-1: FAIL_OK js1_5/extensions/regress-336409-2: FAIL_OK js1_5/extensions/regress-336410-2: FAIL_OK js1_5/extensions/regress-341956-01: FAIL_OK -js1_5/extensions/regress-341956-02: FAIL_OK -js1_5/extensions/regress-341956-03: FAIL_OK js1_5/extensions/regress-345967: FAIL_OK js1_5/extensions/regress-346494-01: FAIL_OK js1_5/extensions/regress-346494: FAIL_OK diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp index 6af6611d..365e6503 100644 --- a/tools/gyp/v8.gyp +++ b/tools/gyp/v8.gyp @@ -27,792 +27,819 @@ { 'variables': { + 'use_system_v8%': 0, 'msvs_use_common_release': 0, 'gcc_version%': 'unknown', 'v8_target_arch%': '<(target_arch)', 'v8_use_snapshot%': 'true', }, - 'target_defaults': { - 'defines': [ - 'ENABLE_LOGGING_AND_PROFILING', - 'ENABLE_DEBUGGER_SUPPORT', - 'ENABLE_VMSTATE_TRACKING', - ], - 'conditions': [ - ['OS!="mac"', { - # TODO(mark): The OS!="mac" conditional is temporary. It can be - # removed once the Mac Chromium build stops setting target_arch to - # ia32 and instead sets it to mac. Other checks in this file for - # OS=="mac" can be removed at that time as well. This can be cleaned - # up once http://crbug.com/44205 is fixed. - 'conditions': [ - ['v8_target_arch=="arm"', { - 'defines': [ - 'V8_TARGET_ARCH_ARM', - ], - }], - ['v8_target_arch=="ia32"', { - 'defines': [ - 'V8_TARGET_ARCH_IA32', - ], - }], - ['v8_target_arch=="x64"', { - 'defines': [ - 'V8_TARGET_ARCH_X64', - ], - }], - ], - }], - ], - 'configurations': { - 'Debug': { + 'conditions': [ + ['use_system_v8==0', { + 'target_defaults': { 'defines': [ - 'DEBUG', - '_DEBUG', - 'ENABLE_DISASSEMBLER', - 'V8_ENABLE_CHECKS', - 'OBJECT_PRINT', + 'ENABLE_LOGGING_AND_PROFILING', + 'ENABLE_DEBUGGER_SUPPORT', + 'ENABLE_VMSTATE_TRACKING', ], - 'msvs_settings': { - 'VCCLCompilerTool': { - 'Optimization': '0', - - 'conditions': [ - ['OS=="win" and component=="shared_library"', { - 'RuntimeLibrary': '3', # /MDd - }, { - 'RuntimeLibrary': '1', # /MTd - }], - ], - }, - 'VCLinkerTool': { - 'LinkIncremental': '2', - }, - }, 'conditions': [ - ['OS=="freebsd" or OS=="openbsd"', { - 'cflags': [ '-I/usr/local/include' ], - }], - ], - }, - 'Release': { - 'conditions': [ - ['OS=="linux" or OS=="freebsd" or OS=="openbsd"', { - 'cflags!': [ - '-O2', - '-Os', - ], - 'cflags': [ - '-fomit-frame-pointer', - '-O3', - ], + ['OS!="mac"', { + # TODO(mark): The OS!="mac" conditional is temporary. It can be + # removed once the Mac Chromium build stops setting target_arch to + # ia32 and instead sets it to mac. Other checks in this file for + # OS=="mac" can be removed at that time as well. This can be cleaned + # up once http://crbug.com/44205 is fixed. 'conditions': [ - [ 'gcc_version==44', { - 'cflags': [ - # Avoid crashes with gcc 4.4 in the v8 test suite. - '-fno-tree-vrp', + ['v8_target_arch=="arm"', { + 'defines': [ + 'V8_TARGET_ARCH_ARM', + ], + }], + ['v8_target_arch=="ia32"', { + 'defines': [ + 'V8_TARGET_ARCH_IA32', + ], + }], + ['v8_target_arch=="x64"', { + 'defines': [ + 'V8_TARGET_ARCH_X64', ], }], ], }], - ['OS=="freebsd" or OS=="openbsd"', { - 'cflags': [ '-I/usr/local/include' ], - }], - ['OS=="mac"', { - 'xcode_settings': { - 'GCC_OPTIMIZATION_LEVEL': '3', # -O3 - 'GCC_STRICT_ALIASING': 'YES', # -fstrict-aliasing. Mainline gcc - # enables this at -O2 and above, - # but Apple gcc does not unless it - # is specified explicitly. - }, - }], - ['OS=="win"', { - 'msvs_configuration_attributes': { - 'OutputDirectory': '$(SolutionDir)$(ConfigurationName)', - 'IntermediateDirectory': '$(OutDir)\\obj\\$(ProjectName)', - 'CharacterSet': '1', - }, + ], + 'configurations': { + 'Debug': { + 'defines': [ + 'DEBUG', + '_DEBUG', + 'ENABLE_DISASSEMBLER', + 'V8_ENABLE_CHECKS', + 'OBJECT_PRINT', + ], 'msvs_settings': { 'VCCLCompilerTool': { - 'Optimization': '2', - 'InlineFunctionExpansion': '2', - 'EnableIntrinsicFunctions': 'true', - 'FavorSizeOrSpeed': '0', - 'OmitFramePointers': 'true', - 'StringPooling': 'true', - + 'Optimization': '0', + 'conditions': [ ['OS=="win" and component=="shared_library"', { - 'RuntimeLibrary': '2', #/MD + 'RuntimeLibrary': '3', # /MDd }, { - 'RuntimeLibrary': '0', #/MT + 'RuntimeLibrary': '1', # /MTd }], ], }, 'VCLinkerTool': { - 'LinkIncremental': '1', - 'OptimizeReferences': '2', - 'OptimizeForWindows98': '1', - 'EnableCOMDATFolding': '2', + 'LinkIncremental': '2', }, }, - }], - ], - }, - }, - }, - 'targets': [ - { - 'target_name': 'v8', - 'conditions': [ - ['v8_use_snapshot=="true"', { - 'dependencies': ['v8_snapshot'], + 'conditions': [ + ['OS=="freebsd" or OS=="openbsd"', { + 'cflags': [ '-I/usr/local/include' ], + }], + ], + }, + 'Release': { + 'conditions': [ + ['OS=="linux" or OS=="freebsd" or OS=="openbsd"', { + 'cflags!': [ + '-O2', + '-Os', + ], + 'cflags': [ + '-fomit-frame-pointer', + '-O3', + ], + 'conditions': [ + [ 'gcc_version==44', { + 'cflags': [ + # Avoid crashes with gcc 4.4 in the v8 test suite. + '-fno-tree-vrp', + ], + }], + ], + }], + ['OS=="freebsd" or OS=="openbsd"', { + 'cflags': [ '-I/usr/local/include' ], + }], + ['OS=="mac"', { + 'xcode_settings': { + 'GCC_OPTIMIZATION_LEVEL': '3', # -O3 + + # -fstrict-aliasing. Mainline gcc + # enables this at -O2 and above, + # but Apple gcc does not unless it + # is specified explicitly. + 'GCC_STRICT_ALIASING': 'YES', + }, + }], + ['OS=="win"', { + 'msvs_configuration_attributes': { + 'OutputDirectory': '$(SolutionDir)$(ConfigurationName)', + 'IntermediateDirectory': '$(OutDir)\\obj\\$(ProjectName)', + 'CharacterSet': '1', + }, + 'msvs_settings': { + 'VCCLCompilerTool': { + 'Optimization': '2', + 'InlineFunctionExpansion': '2', + 'EnableIntrinsicFunctions': 'true', + 'FavorSizeOrSpeed': '0', + 'OmitFramePointers': 'true', + 'StringPooling': 'true', + + 'conditions': [ + ['OS=="win" and component=="shared_library"', { + 'RuntimeLibrary': '2', #/MD + }, { + 'RuntimeLibrary': '0', #/MT + }], + ], + }, + 'VCLinkerTool': { + 'LinkIncremental': '1', + 'OptimizeReferences': '2', + 'OptimizeForWindows98': '1', + 'EnableCOMDATFolding': '2', + }, + }, + }], + ], + }, }, + }, + 'targets': [ { - 'dependencies': ['v8_nosnapshot'], - }], - ['OS=="win" and component=="shared_library"', { - 'type': '<(component)', - 'sources': [ - '../../src/v8dll-main.cc', - ], - 'defines': [ - 'BUILDING_V8_SHARED' + 'target_name': 'v8', + 'conditions': [ + ['v8_use_snapshot=="true"', { + 'dependencies': ['v8_snapshot'], + }, + { + 'dependencies': ['v8_nosnapshot'], + }], + ['OS=="win" and component=="shared_library"', { + 'type': '<(component)', + 'sources': [ + '../../src/v8dll-main.cc', + ], + 'defines': [ + 'BUILDING_V8_SHARED' + ], + 'direct_dependent_settings': { + 'defines': [ + 'USING_V8_SHARED', + ], + }, + }, + { + 'type': 'none', + }], ], 'direct_dependent_settings': { - 'defines': [ - 'USING_V8_SHARED', + 'include_dirs': [ + '../../include', ], }, }, { - 'type': 'none', - }], - ], - 'direct_dependent_settings': { - 'include_dirs': [ - '../../include', - ], - }, - }, - { - 'target_name': 'v8_preparser', - 'include_dirs': [ - '../../include', - '../../src', - ], - 'sources': [ - '../../src/allocation.cc', - '../../src/hashmap.cc', - '../../src/preparse-data.cc', - '../../src/preparser.cc', - '../../src/preparser-api.cc', - '../../src/scanner-base.cc', - '../../src/token.cc', - '../../src/unicode.cc', - ], - 'conditions': [ - ['OS=="win" and component=="shared_library"', { - 'sources': [ '../../src/v8preparserdll-main.cc' ], - 'defines': [ 'BUILDING_V8_SHARED' ], - 'direct_dependent_settings': { - 'defines': [ 'USING_V8_SHARED' ] - }, - 'type': '<(component)', - } , { - 'type': 'none' - }], - ['OS!="win"', { - 'type': '<(library)' - }], - ] - }, - { - 'target_name': 'v8_snapshot', - 'type': '<(library)', - 'conditions': [ - ['OS=="win" and component=="shared_library"', { - 'defines': [ - 'BUILDING_V8_SHARED', + 'target_name': 'v8_preparser', + 'include_dirs': [ + '../../include', + '../../src', ], - }], - ], - 'dependencies': [ - 'mksnapshot#host', - 'js2c#host', - 'v8_base', - ], - 'include_dirs+': [ - '../../src', - ], - 'sources': [ - '<(SHARED_INTERMEDIATE_DIR)/libraries-empty.cc', - '<(INTERMEDIATE_DIR)/snapshot.cc', - ], - 'actions': [ + 'sources': [ + '../../src/allocation.cc', + '../../src/hashmap.cc', + '../../src/preparse-data.cc', + '../../src/preparser.cc', + '../../src/preparser-api.cc', + '../../src/scanner-base.cc', + '../../src/token.cc', + '../../src/unicode.cc', + ], + 'conditions': [ + ['OS=="win" and component=="shared_library"', { + 'sources': [ '../../src/v8preparserdll-main.cc' ], + 'defines': [ 'BUILDING_V8_SHARED' ], + 'direct_dependent_settings': { + 'defines': [ 'USING_V8_SHARED' ] + }, + 'type': '<(component)', + } , { + 'type': 'none' + }], + ['OS!="win"', { + 'type': '<(library)' + }], + ] + }, { - 'action_name': 'run_mksnapshot', - 'inputs': [ - '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)mksnapshot<(EXECUTABLE_SUFFIX)', + 'target_name': 'v8_snapshot', + 'type': '<(library)', + 'conditions': [ + ['OS=="win" and component=="shared_library"', { + 'defines': [ + 'BUILDING_V8_SHARED', + ], + }], + ], + 'dependencies': [ + 'mksnapshot#host', + 'js2c#host', + 'v8_base', + ], + 'include_dirs+': [ + '../../src', ], - 'outputs': [ + 'sources': [ + '<(SHARED_INTERMEDIATE_DIR)/libraries-empty.cc', '<(INTERMEDIATE_DIR)/snapshot.cc', ], - 'action': ['<@(_inputs)', '<@(_outputs)'], + 'actions': [ + { + 'action_name': 'run_mksnapshot', + 'inputs': [ + '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)mksnapshot<(EXECUTABLE_SUFFIX)', + ], + 'outputs': [ + '<(INTERMEDIATE_DIR)/snapshot.cc', + ], + 'action': ['<@(_inputs)', '<@(_outputs)'], + }, + ], }, - ], - }, - { - 'target_name': 'v8_nosnapshot', - 'type': '<(library)', - 'toolsets': ['host', 'target'], - 'dependencies': [ - 'js2c#host', - 'v8_base', - ], - 'include_dirs+': [ - '../../src', - ], - 'sources': [ - '<(SHARED_INTERMEDIATE_DIR)/libraries.cc', - '../../src/snapshot-empty.cc', - ], - 'conditions': [ - # The ARM assembler assumes the host is 32 bits, so force building - # 32-bit host tools. - ['v8_target_arch=="arm" and host_arch=="x64" and _toolset=="host"', { - 'cflags': ['-m32'], - 'ldflags': ['-m32'], - }], - ['OS=="win" and component=="shared_library"', { - 'defines': [ - 'BUILDING_V8_SHARED', + { + 'target_name': 'v8_nosnapshot', + 'type': '<(library)', + 'toolsets': ['host', 'target'], + 'dependencies': [ + 'js2c#host', + 'v8_base', ], - }], - ] - }, - { - 'target_name': 'v8_base', - 'type': '<(library)', - 'toolsets': ['host', 'target'], - 'include_dirs+': [ - '../../src', - ], - 'sources': [ - '../../src/accessors.cc', - '../../src/accessors.h', - '../../src/allocation.cc', - '../../src/allocation.h', - '../../src/api.cc', - '../../src/api.h', - '../../src/apiutils.h', - '../../src/arguments.h', - '../../src/assembler.cc', - '../../src/assembler.h', - '../../src/ast.cc', - '../../src/ast-inl.h', - '../../src/ast.h', - '../../src/atomicops_internals_x86_gcc.cc', - '../../src/bignum.cc', - '../../src/bignum.h', - '../../src/bignum-dtoa.cc', - '../../src/bignum-dtoa.h', - '../../src/bootstrapper.cc', - '../../src/bootstrapper.h', - '../../src/builtins.cc', - '../../src/builtins.h', - '../../src/bytecodes-irregexp.h', - '../../src/cached-powers.cc', - '../../src/cached-powers.h', - '../../src/char-predicates-inl.h', - '../../src/char-predicates.h', - '../../src/checks.cc', - '../../src/checks.h', - '../../src/circular-queue-inl.h', - '../../src/circular-queue.cc', - '../../src/circular-queue.h', - '../../src/code-stubs.cc', - '../../src/code-stubs.h', - '../../src/code.h', - '../../src/codegen-inl.h', - '../../src/codegen.cc', - '../../src/codegen.h', - '../../src/compilation-cache.cc', - '../../src/compilation-cache.h', - '../../src/compiler.cc', - '../../src/compiler.h', - '../../src/contexts.cc', - '../../src/contexts.h', - '../../src/conversions-inl.h', - '../../src/conversions.cc', - '../../src/conversions.h', - '../../src/counters.cc', - '../../src/counters.h', - '../../src/cpu.h', - '../../src/cpu-profiler-inl.h', - '../../src/cpu-profiler.cc', - '../../src/cpu-profiler.h', - '../../src/data-flow.cc', - '../../src/data-flow.h', - '../../src/dateparser.cc', - '../../src/dateparser.h', - '../../src/dateparser-inl.h', - '../../src/debug.cc', - '../../src/debug.h', - '../../src/debug-agent.cc', - '../../src/debug-agent.h', - '../../src/deoptimizer.cc', - '../../src/deoptimizer.h', - '../../src/disasm.h', - '../../src/disassembler.cc', - '../../src/disassembler.h', - '../../src/dtoa.cc', - '../../src/dtoa.h', - '../../src/diy-fp.cc', - '../../src/diy-fp.h', - '../../src/double.h', - '../../src/execution.cc', - '../../src/execution.h', - '../../src/factory.cc', - '../../src/factory.h', - '../../src/fast-dtoa.cc', - '../../src/fast-dtoa.h', - '../../src/flag-definitions.h', - '../../src/fixed-dtoa.cc', - '../../src/fixed-dtoa.h', - '../../src/flags.cc', - '../../src/flags.h', - '../../src/frame-element.cc', - '../../src/frame-element.h', - '../../src/frames-inl.h', - '../../src/frames.cc', - '../../src/frames.h', - '../../src/full-codegen.cc', - '../../src/full-codegen.h', - '../../src/func-name-inferrer.cc', - '../../src/func-name-inferrer.h', - '../../src/global-handles.cc', - '../../src/global-handles.h', - '../../src/globals.h', - '../../src/handles-inl.h', - '../../src/handles.cc', - '../../src/handles.h', - '../../src/hashmap.cc', - '../../src/hashmap.h', - '../../src/heap-inl.h', - '../../src/heap.cc', - '../../src/heap.h', - '../../src/heap-profiler.cc', - '../../src/heap-profiler.h', - '../../src/hydrogen.cc', - '../../src/hydrogen.h', - '../../src/hydrogen-instructions.cc', - '../../src/hydrogen-instructions.h', - '../../src/ic-inl.h', - '../../src/ic.cc', - '../../src/ic.h', - '../../src/interpreter-irregexp.cc', - '../../src/interpreter-irregexp.h', - '../../src/jump-target-inl.h', - '../../src/jump-target.cc', - '../../src/jump-target.h', - '../../src/jsregexp.cc', - '../../src/jsregexp.h', - '../../src/list-inl.h', - '../../src/list.h', - '../../src/lithium-allocator.cc', - '../../src/lithium-allocator.h', - '../../src/liveedit.cc', - '../../src/liveedit.h', - '../../src/log-inl.h', - '../../src/log-utils.cc', - '../../src/log-utils.h', - '../../src/log.cc', - '../../src/log.h', - '../../src/macro-assembler.h', - '../../src/mark-compact.cc', - '../../src/mark-compact.h', - '../../src/memory.h', - '../../src/messages.cc', - '../../src/messages.h', - '../../src/natives.h', - '../../src/objects-debug.cc', - '../../src/objects-inl.h', - '../../src/objects-visiting.cc', - '../../src/objects-visiting.h', - '../../src/objects.cc', - '../../src/objects.h', - '../../src/oprofile-agent.h', - '../../src/oprofile-agent.cc', - '../../src/parser.cc', - '../../src/parser.h', - '../../src/platform.h', - '../../src/preparse-data.cc', - '../../src/preparse-data.h', - '../../src/preparser.cc', - '../../src/preparser.h', - '../../src/prettyprinter.cc', - '../../src/prettyprinter.h', - '../../src/property.cc', - '../../src/property.h', - '../../src/profile-generator-inl.h', - '../../src/profile-generator.cc', - '../../src/profile-generator.h', - '../../src/regexp-macro-assembler-irregexp-inl.h', - '../../src/regexp-macro-assembler-irregexp.cc', - '../../src/regexp-macro-assembler-irregexp.h', - '../../src/regexp-macro-assembler-tracer.cc', - '../../src/regexp-macro-assembler-tracer.h', - '../../src/regexp-macro-assembler.cc', - '../../src/regexp-macro-assembler.h', - '../../src/regexp-stack.cc', - '../../src/regexp-stack.h', - '../../src/register-allocator.h', - '../../src/register-allocator-inl.h', - '../../src/register-allocator.cc', - '../../src/rewriter.cc', - '../../src/rewriter.h', - '../../src/runtime.cc', - '../../src/runtime.h', - '../../src/runtime-profiler.cc', - '../../src/runtime-profiler.h', - '../../src/safepoint-table.cc', - '../../src/safepoint-table.h', - '../../src/scanner-base.cc', - '../../src/scanner-base.h', - '../../src/scanner.cc', - '../../src/scanner.h', - '../../src/scopeinfo.cc', - '../../src/scopeinfo.h', - '../../src/scopes.cc', - '../../src/scopes.h', - '../../src/serialize.cc', - '../../src/serialize.h', - '../../src/shell.h', - '../../src/smart-pointer.h', - '../../src/snapshot-common.cc', - '../../src/snapshot.h', - '../../src/spaces-inl.h', - '../../src/spaces.cc', - '../../src/spaces.h', - '../../src/string-search.cc', - '../../src/string-search.h', - '../../src/string-stream.cc', - '../../src/string-stream.h', - '../../src/strtod.cc', - '../../src/strtod.h', - '../../src/stub-cache.cc', - '../../src/stub-cache.h', - '../../src/token.cc', - '../../src/token.h', - '../../src/top.cc', - '../../src/top.h', - '../../src/type-info.cc', - '../../src/type-info.h', - '../../src/unbound-queue-inl.h', - '../../src/unbound-queue.h', - '../../src/unicode-inl.h', - '../../src/unicode.cc', - '../../src/unicode.h', - '../../src/utils.cc', - '../../src/utils.h', - '../../src/v8-counters.cc', - '../../src/v8-counters.h', - '../../src/v8.cc', - '../../src/v8.h', - '../../src/v8checks.h', - '../../src/v8globals.h', - '../../src/v8threads.cc', - '../../src/v8threads.h', - '../../src/v8utils.h', - '../../src/variables.cc', - '../../src/variables.h', - '../../src/version.cc', - '../../src/version.h', - '../../src/virtual-frame-inl.h', - '../../src/virtual-frame.cc', - '../../src/virtual-frame.h', - '../../src/vm-state-inl.h', - '../../src/vm-state.h', - '../../src/zone-inl.h', - '../../src/zone.cc', - '../../src/zone.h', - '../../src/extensions/externalize-string-extension.cc', - '../../src/extensions/externalize-string-extension.h', - '../../src/extensions/gc-extension.cc', - '../../src/extensions/gc-extension.h', - ], - 'conditions': [ - ['v8_target_arch=="arm"', { 'include_dirs+': [ - '../../src/arm', + '../../src', ], 'sources': [ - '../../src/jump-target-light.h', - '../../src/jump-target-light-inl.h', - '../../src/jump-target-light.cc', - '../../src/virtual-frame-light-inl.h', - '../../src/virtual-frame-light.cc', - '../../src/arm/assembler-arm-inl.h', - '../../src/arm/assembler-arm.cc', - '../../src/arm/assembler-arm.h', - '../../src/arm/builtins-arm.cc', - '../../src/arm/code-stubs-arm.cc', - '../../src/arm/code-stubs-arm.h', - '../../src/arm/codegen-arm.cc', - '../../src/arm/codegen-arm.h', - '../../src/arm/constants-arm.h', - '../../src/arm/constants-arm.cc', - '../../src/arm/cpu-arm.cc', - '../../src/arm/debug-arm.cc', - '../../src/arm/deoptimizer-arm.cc', - '../../src/arm/disasm-arm.cc', - '../../src/arm/frames-arm.cc', - '../../src/arm/frames-arm.h', - '../../src/arm/full-codegen-arm.cc', - '../../src/arm/ic-arm.cc', - '../../src/arm/jump-target-arm.cc', - '../../src/arm/lithium-codegen-arm.cc', - '../../src/arm/lithium-codegen-arm.h', - '../../src/arm/lithium-arm.cc', - '../../src/arm/lithium-arm.h', - '../../src/arm/macro-assembler-arm.cc', - '../../src/arm/macro-assembler-arm.h', - '../../src/arm/regexp-macro-assembler-arm.cc', - '../../src/arm/regexp-macro-assembler-arm.h', - '../../src/arm/register-allocator-arm.cc', - '../../src/arm/simulator-arm.cc', - '../../src/arm/stub-cache-arm.cc', - '../../src/arm/virtual-frame-arm-inl.h', - '../../src/arm/virtual-frame-arm.cc', - '../../src/arm/virtual-frame-arm.h', + '<(SHARED_INTERMEDIATE_DIR)/libraries.cc', + '../../src/snapshot-empty.cc', ], 'conditions': [ # The ARM assembler assumes the host is 32 bits, so force building # 32-bit host tools. - ['host_arch=="x64" and _toolset=="host"', { + ['v8_target_arch=="arm" and host_arch=="x64" and _toolset=="host"', { 'cflags': ['-m32'], 'ldflags': ['-m32'], - }] + }], + ['OS=="win" and component=="shared_library"', { + 'defines': [ + 'BUILDING_V8_SHARED', + ], + }], ] - }], - ['v8_target_arch=="ia32" or v8_target_arch=="mac" or OS=="mac"', { - 'include_dirs+': [ - '../../src/ia32', - ], - 'sources': [ - '../../src/jump-target-heavy.h', - '../../src/jump-target-heavy-inl.h', - '../../src/jump-target-heavy.cc', - '../../src/virtual-frame-heavy-inl.h', - '../../src/virtual-frame-heavy.cc', - '../../src/ia32/assembler-ia32-inl.h', - '../../src/ia32/assembler-ia32.cc', - '../../src/ia32/assembler-ia32.h', - '../../src/ia32/builtins-ia32.cc', - '../../src/ia32/code-stubs-ia32.cc', - '../../src/ia32/code-stubs-ia32.h', - '../../src/ia32/codegen-ia32.cc', - '../../src/ia32/codegen-ia32.h', - '../../src/ia32/cpu-ia32.cc', - '../../src/ia32/debug-ia32.cc', - '../../src/ia32/deoptimizer-ia32.cc', - '../../src/ia32/disasm-ia32.cc', - '../../src/ia32/frames-ia32.cc', - '../../src/ia32/frames-ia32.h', - '../../src/ia32/full-codegen-ia32.cc', - '../../src/ia32/ic-ia32.cc', - '../../src/ia32/jump-target-ia32.cc', - '../../src/ia32/lithium-codegen-ia32.cc', - '../../src/ia32/lithium-codegen-ia32.h', - '../../src/ia32/lithium-ia32.cc', - '../../src/ia32/lithium-ia32.h', - '../../src/ia32/macro-assembler-ia32.cc', - '../../src/ia32/macro-assembler-ia32.h', - '../../src/ia32/regexp-macro-assembler-ia32.cc', - '../../src/ia32/regexp-macro-assembler-ia32.h', - '../../src/ia32/register-allocator-ia32.cc', - '../../src/ia32/stub-cache-ia32.cc', - '../../src/ia32/virtual-frame-ia32.cc', - '../../src/ia32/virtual-frame-ia32.h', - ], - }], - ['v8_target_arch=="x64" or v8_target_arch=="mac" or OS=="mac"', { + }, + { + 'target_name': 'v8_base', + 'type': '<(library)', + 'toolsets': ['host', 'target'], 'include_dirs+': [ - '../../src/x64', + '../../src', ], 'sources': [ - '../../src/jump-target-heavy.h', - '../../src/jump-target-heavy-inl.h', - '../../src/jump-target-heavy.cc', - '../../src/virtual-frame-heavy-inl.h', - '../../src/virtual-frame-heavy.cc', - '../../src/x64/assembler-x64-inl.h', - '../../src/x64/assembler-x64.cc', - '../../src/x64/assembler-x64.h', - '../../src/x64/builtins-x64.cc', - '../../src/x64/code-stubs-x64.cc', - '../../src/x64/code-stubs-x64.h', - '../../src/x64/codegen-x64.cc', - '../../src/x64/codegen-x64.h', - '../../src/x64/cpu-x64.cc', - '../../src/x64/debug-x64.cc', - '../../src/x64/deoptimizer-x64.cc', - '../../src/x64/disasm-x64.cc', - '../../src/x64/frames-x64.cc', - '../../src/x64/frames-x64.h', - '../../src/x64/full-codegen-x64.cc', - '../../src/x64/ic-x64.cc', - '../../src/x64/jump-target-x64.cc', - '../../src/x64/macro-assembler-x64.cc', - '../../src/x64/macro-assembler-x64.h', - '../../src/x64/regexp-macro-assembler-x64.cc', - '../../src/x64/regexp-macro-assembler-x64.h', - '../../src/x64/register-allocator-x64.cc', - '../../src/x64/stub-cache-x64.cc', - '../../src/x64/virtual-frame-x64.cc', - '../../src/x64/virtual-frame-x64.h', + '../../src/accessors.cc', + '../../src/accessors.h', + '../../src/allocation.cc', + '../../src/allocation.h', + '../../src/api.cc', + '../../src/api.h', + '../../src/apiutils.h', + '../../src/arguments.h', + '../../src/assembler.cc', + '../../src/assembler.h', + '../../src/ast.cc', + '../../src/ast-inl.h', + '../../src/ast.h', + '../../src/atomicops_internals_x86_gcc.cc', + '../../src/bignum.cc', + '../../src/bignum.h', + '../../src/bignum-dtoa.cc', + '../../src/bignum-dtoa.h', + '../../src/bootstrapper.cc', + '../../src/bootstrapper.h', + '../../src/builtins.cc', + '../../src/builtins.h', + '../../src/bytecodes-irregexp.h', + '../../src/cached-powers.cc', + '../../src/cached-powers.h', + '../../src/char-predicates-inl.h', + '../../src/char-predicates.h', + '../../src/checks.cc', + '../../src/checks.h', + '../../src/circular-queue-inl.h', + '../../src/circular-queue.cc', + '../../src/circular-queue.h', + '../../src/code-stubs.cc', + '../../src/code-stubs.h', + '../../src/code.h', + '../../src/codegen-inl.h', + '../../src/codegen.cc', + '../../src/codegen.h', + '../../src/compilation-cache.cc', + '../../src/compilation-cache.h', + '../../src/compiler.cc', + '../../src/compiler.h', + '../../src/contexts.cc', + '../../src/contexts.h', + '../../src/conversions-inl.h', + '../../src/conversions.cc', + '../../src/conversions.h', + '../../src/counters.cc', + '../../src/counters.h', + '../../src/cpu.h', + '../../src/cpu-profiler-inl.h', + '../../src/cpu-profiler.cc', + '../../src/cpu-profiler.h', + '../../src/data-flow.cc', + '../../src/data-flow.h', + '../../src/dateparser.cc', + '../../src/dateparser.h', + '../../src/dateparser-inl.h', + '../../src/debug.cc', + '../../src/debug.h', + '../../src/debug-agent.cc', + '../../src/debug-agent.h', + '../../src/deoptimizer.cc', + '../../src/deoptimizer.h', + '../../src/disasm.h', + '../../src/disassembler.cc', + '../../src/disassembler.h', + '../../src/dtoa.cc', + '../../src/dtoa.h', + '../../src/diy-fp.cc', + '../../src/diy-fp.h', + '../../src/double.h', + '../../src/execution.cc', + '../../src/execution.h', + '../../src/factory.cc', + '../../src/factory.h', + '../../src/fast-dtoa.cc', + '../../src/fast-dtoa.h', + '../../src/flag-definitions.h', + '../../src/fixed-dtoa.cc', + '../../src/fixed-dtoa.h', + '../../src/flags.cc', + '../../src/flags.h', + '../../src/frame-element.cc', + '../../src/frame-element.h', + '../../src/frames-inl.h', + '../../src/frames.cc', + '../../src/frames.h', + '../../src/full-codegen.cc', + '../../src/full-codegen.h', + '../../src/func-name-inferrer.cc', + '../../src/func-name-inferrer.h', + '../../src/global-handles.cc', + '../../src/global-handles.h', + '../../src/globals.h', + '../../src/handles-inl.h', + '../../src/handles.cc', + '../../src/handles.h', + '../../src/hashmap.cc', + '../../src/hashmap.h', + '../../src/heap-inl.h', + '../../src/heap.cc', + '../../src/heap.h', + '../../src/heap-profiler.cc', + '../../src/heap-profiler.h', + '../../src/hydrogen.cc', + '../../src/hydrogen.h', + '../../src/hydrogen-instructions.cc', + '../../src/hydrogen-instructions.h', + '../../src/ic-inl.h', + '../../src/ic.cc', + '../../src/ic.h', + '../../src/interpreter-irregexp.cc', + '../../src/interpreter-irregexp.h', + '../../src/jump-target-inl.h', + '../../src/jump-target.cc', + '../../src/jump-target.h', + '../../src/jsregexp.cc', + '../../src/jsregexp.h', + '../../src/list-inl.h', + '../../src/list.h', + '../../src/lithium-allocator.cc', + '../../src/lithium-allocator.h', + '../../src/liveedit.cc', + '../../src/liveedit.h', + '../../src/log-inl.h', + '../../src/log-utils.cc', + '../../src/log-utils.h', + '../../src/log.cc', + '../../src/log.h', + '../../src/macro-assembler.h', + '../../src/mark-compact.cc', + '../../src/mark-compact.h', + '../../src/memory.h', + '../../src/messages.cc', + '../../src/messages.h', + '../../src/natives.h', + '../../src/objects-debug.cc', + '../../src/objects-printer.cc', + '../../src/objects-inl.h', + '../../src/objects-visiting.cc', + '../../src/objects-visiting.h', + '../../src/objects.cc', + '../../src/objects.h', + '../../src/oprofile-agent.h', + '../../src/oprofile-agent.cc', + '../../src/parser.cc', + '../../src/parser.h', + '../../src/platform.h', + '../../src/preparse-data.cc', + '../../src/preparse-data.h', + '../../src/preparser.cc', + '../../src/preparser.h', + '../../src/prettyprinter.cc', + '../../src/prettyprinter.h', + '../../src/property.cc', + '../../src/property.h', + '../../src/profile-generator-inl.h', + '../../src/profile-generator.cc', + '../../src/profile-generator.h', + '../../src/regexp-macro-assembler-irregexp-inl.h', + '../../src/regexp-macro-assembler-irregexp.cc', + '../../src/regexp-macro-assembler-irregexp.h', + '../../src/regexp-macro-assembler-tracer.cc', + '../../src/regexp-macro-assembler-tracer.h', + '../../src/regexp-macro-assembler.cc', + '../../src/regexp-macro-assembler.h', + '../../src/regexp-stack.cc', + '../../src/regexp-stack.h', + '../../src/register-allocator.h', + '../../src/register-allocator-inl.h', + '../../src/register-allocator.cc', + '../../src/rewriter.cc', + '../../src/rewriter.h', + '../../src/runtime.cc', + '../../src/runtime.h', + '../../src/runtime-profiler.cc', + '../../src/runtime-profiler.h', + '../../src/safepoint-table.cc', + '../../src/safepoint-table.h', + '../../src/scanner-base.cc', + '../../src/scanner-base.h', + '../../src/scanner.cc', + '../../src/scanner.h', + '../../src/scopeinfo.cc', + '../../src/scopeinfo.h', + '../../src/scopes.cc', + '../../src/scopes.h', + '../../src/serialize.cc', + '../../src/serialize.h', + '../../src/shell.h', + '../../src/smart-pointer.h', + '../../src/snapshot-common.cc', + '../../src/snapshot.h', + '../../src/spaces-inl.h', + '../../src/spaces.cc', + '../../src/spaces.h', + '../../src/string-search.cc', + '../../src/string-search.h', + '../../src/string-stream.cc', + '../../src/string-stream.h', + '../../src/strtod.cc', + '../../src/strtod.h', + '../../src/stub-cache.cc', + '../../src/stub-cache.h', + '../../src/token.cc', + '../../src/token.h', + '../../src/top.cc', + '../../src/top.h', + '../../src/type-info.cc', + '../../src/type-info.h', + '../../src/unbound-queue-inl.h', + '../../src/unbound-queue.h', + '../../src/unicode-inl.h', + '../../src/unicode.cc', + '../../src/unicode.h', + '../../src/utils.cc', + '../../src/utils.h', + '../../src/v8-counters.cc', + '../../src/v8-counters.h', + '../../src/v8.cc', + '../../src/v8.h', + '../../src/v8checks.h', + '../../src/v8globals.h', + '../../src/v8threads.cc', + '../../src/v8threads.h', + '../../src/v8utils.h', + '../../src/variables.cc', + '../../src/variables.h', + '../../src/version.cc', + '../../src/version.h', + '../../src/virtual-frame-inl.h', + '../../src/virtual-frame.cc', + '../../src/virtual-frame.h', + '../../src/vm-state-inl.h', + '../../src/vm-state.h', + '../../src/zone-inl.h', + '../../src/zone.cc', + '../../src/zone.h', + '../../src/extensions/externalize-string-extension.cc', + '../../src/extensions/externalize-string-extension.h', + '../../src/extensions/gc-extension.cc', + '../../src/extensions/gc-extension.h', ], - }], - ['OS=="linux"', { - 'link_settings': { - 'libraries': [ - # Needed for clock_gettime() used by src/platform-linux.cc. - '-lrt', - ]}, - 'sources': [ - '../../src/platform-linux.cc', - '../../src/platform-posix.cc' + 'conditions': [ + ['v8_target_arch=="arm"', { + 'include_dirs+': [ + '../../src/arm', + ], + 'sources': [ + '../../src/jump-target-light.h', + '../../src/jump-target-light-inl.h', + '../../src/jump-target-light.cc', + '../../src/virtual-frame-light-inl.h', + '../../src/virtual-frame-light.cc', + '../../src/arm/assembler-arm-inl.h', + '../../src/arm/assembler-arm.cc', + '../../src/arm/assembler-arm.h', + '../../src/arm/builtins-arm.cc', + '../../src/arm/code-stubs-arm.cc', + '../../src/arm/code-stubs-arm.h', + '../../src/arm/codegen-arm.cc', + '../../src/arm/codegen-arm.h', + '../../src/arm/constants-arm.h', + '../../src/arm/constants-arm.cc', + '../../src/arm/cpu-arm.cc', + '../../src/arm/debug-arm.cc', + '../../src/arm/deoptimizer-arm.cc', + '../../src/arm/disasm-arm.cc', + '../../src/arm/frames-arm.cc', + '../../src/arm/frames-arm.h', + '../../src/arm/full-codegen-arm.cc', + '../../src/arm/ic-arm.cc', + '../../src/arm/jump-target-arm.cc', + '../../src/arm/lithium-codegen-arm.cc', + '../../src/arm/lithium-codegen-arm.h', + '../../src/arm/lithium-arm.cc', + '../../src/arm/lithium-arm.h', + '../../src/arm/macro-assembler-arm.cc', + '../../src/arm/macro-assembler-arm.h', + '../../src/arm/regexp-macro-assembler-arm.cc', + '../../src/arm/regexp-macro-assembler-arm.h', + '../../src/arm/register-allocator-arm.cc', + '../../src/arm/simulator-arm.cc', + '../../src/arm/stub-cache-arm.cc', + '../../src/arm/virtual-frame-arm-inl.h', + '../../src/arm/virtual-frame-arm.cc', + '../../src/arm/virtual-frame-arm.h', + ], + 'conditions': [ + # The ARM assembler assumes the host is 32 bits, + # so force building 32-bit host tools. + ['host_arch=="x64" and _toolset=="host"', { + 'cflags': ['-m32'], + 'ldflags': ['-m32'], + }] + ] + }], + ['v8_target_arch=="ia32" or v8_target_arch=="mac" or OS=="mac"', { + 'include_dirs+': [ + '../../src/ia32', + ], + 'sources': [ + '../../src/jump-target-heavy.h', + '../../src/jump-target-heavy-inl.h', + '../../src/jump-target-heavy.cc', + '../../src/virtual-frame-heavy-inl.h', + '../../src/virtual-frame-heavy.cc', + '../../src/ia32/assembler-ia32-inl.h', + '../../src/ia32/assembler-ia32.cc', + '../../src/ia32/assembler-ia32.h', + '../../src/ia32/builtins-ia32.cc', + '../../src/ia32/code-stubs-ia32.cc', + '../../src/ia32/code-stubs-ia32.h', + '../../src/ia32/codegen-ia32.cc', + '../../src/ia32/codegen-ia32.h', + '../../src/ia32/cpu-ia32.cc', + '../../src/ia32/debug-ia32.cc', + '../../src/ia32/deoptimizer-ia32.cc', + '../../src/ia32/disasm-ia32.cc', + '../../src/ia32/frames-ia32.cc', + '../../src/ia32/frames-ia32.h', + '../../src/ia32/full-codegen-ia32.cc', + '../../src/ia32/ic-ia32.cc', + '../../src/ia32/jump-target-ia32.cc', + '../../src/ia32/lithium-codegen-ia32.cc', + '../../src/ia32/lithium-codegen-ia32.h', + '../../src/ia32/lithium-ia32.cc', + '../../src/ia32/lithium-ia32.h', + '../../src/ia32/macro-assembler-ia32.cc', + '../../src/ia32/macro-assembler-ia32.h', + '../../src/ia32/regexp-macro-assembler-ia32.cc', + '../../src/ia32/regexp-macro-assembler-ia32.h', + '../../src/ia32/register-allocator-ia32.cc', + '../../src/ia32/stub-cache-ia32.cc', + '../../src/ia32/virtual-frame-ia32.cc', + '../../src/ia32/virtual-frame-ia32.h', + ], + }], + ['v8_target_arch=="x64" or v8_target_arch=="mac" or OS=="mac"', { + 'include_dirs+': [ + '../../src/x64', + ], + 'sources': [ + '../../src/jump-target-heavy.h', + '../../src/jump-target-heavy-inl.h', + '../../src/jump-target-heavy.cc', + '../../src/virtual-frame-heavy-inl.h', + '../../src/virtual-frame-heavy.cc', + '../../src/x64/assembler-x64-inl.h', + '../../src/x64/assembler-x64.cc', + '../../src/x64/assembler-x64.h', + '../../src/x64/builtins-x64.cc', + '../../src/x64/code-stubs-x64.cc', + '../../src/x64/code-stubs-x64.h', + '../../src/x64/codegen-x64.cc', + '../../src/x64/codegen-x64.h', + '../../src/x64/cpu-x64.cc', + '../../src/x64/debug-x64.cc', + '../../src/x64/deoptimizer-x64.cc', + '../../src/x64/disasm-x64.cc', + '../../src/x64/frames-x64.cc', + '../../src/x64/frames-x64.h', + '../../src/x64/full-codegen-x64.cc', + '../../src/x64/ic-x64.cc', + '../../src/x64/jump-target-x64.cc', + '../../src/x64/macro-assembler-x64.cc', + '../../src/x64/macro-assembler-x64.h', + '../../src/x64/regexp-macro-assembler-x64.cc', + '../../src/x64/regexp-macro-assembler-x64.h', + '../../src/x64/register-allocator-x64.cc', + '../../src/x64/stub-cache-x64.cc', + '../../src/x64/virtual-frame-x64.cc', + '../../src/x64/virtual-frame-x64.h', + ], + }], + ['OS=="linux"', { + 'link_settings': { + 'libraries': [ + # Needed for clock_gettime() used by src/platform-linux.cc. + '-lrt', + ]}, + 'sources': [ + '../../src/platform-linux.cc', + '../../src/platform-posix.cc' + ], + } ], - } - ], - ['OS=="freebsd"', { - 'link_settings': { - 'libraries': [ - '-L/usr/local/lib -lexecinfo', - ]}, - 'sources': [ - '../../src/platform-freebsd.cc', - '../../src/platform-posix.cc' + ['OS=="freebsd"', { + 'link_settings': { + 'libraries': [ + '-L/usr/local/lib -lexecinfo', + ]}, + 'sources': [ + '../../src/platform-freebsd.cc', + '../../src/platform-posix.cc' + ], + } ], - } - ], - ['OS=="openbsd"', { - 'link_settings': { - 'libraries': [ - '-L/usr/local/lib -lexecinfo', - ]}, - 'sources': [ - '../../src/platform-openbsd.cc', - '../../src/platform-posix.cc' + ['OS=="openbsd"', { + 'link_settings': { + 'libraries': [ + '-L/usr/local/lib -lexecinfo', + ]}, + 'sources': [ + '../../src/platform-openbsd.cc', + '../../src/platform-posix.cc' + ], + } ], - } - ], - ['OS=="mac"', { - 'sources': [ - '../../src/platform-macos.cc', - '../../src/platform-posix.cc' - ]}, - ], - ['OS=="win"', { - 'sources': [ - '../../src/platform-win32.cc', + ['OS=="mac"', { + 'sources': [ + '../../src/platform-macos.cc', + '../../src/platform-posix.cc' + ]}, + ], + ['OS=="win"', { + 'sources': [ + '../../src/platform-win32.cc', + ], + # 4355, 4800 came from common.vsprops + 'msvs_disabled_warnings': [4355, 4800], + 'link_settings': { + 'libraries': [ '-lwinmm.lib' ], + }, + }], + ['OS=="win" and component=="shared_library"', { + 'defines': [ + 'BUILDING_V8_SHARED' + ], + }], ], - # 4355, 4800 came from common.vsprops - 'msvs_disabled_warnings': [4355, 4800], - 'link_settings': { - 'libraries': [ '-lwinmm.lib' ], + }, + { + 'target_name': 'js2c', + 'type': 'none', + 'toolsets': ['host'], + 'variables': { + 'library_files': [ + '../../src/runtime.js', + '../../src/v8natives.js', + '../../src/array.js', + '../../src/string.js', + '../../src/uri.js', + '../../src/math.js', + '../../src/messages.js', + '../../src/apinatives.js', + '../../src/debug-debugger.js', + '../../src/mirror-debugger.js', + '../../src/liveedit-debugger.js', + '../../src/date.js', + '../../src/json.js', + '../../src/regexp.js', + '../../src/macros.py', + ], }, - }], - ['OS=="win" and component=="shared_library"', { - 'defines': [ - 'BUILDING_V8_SHARED' + 'actions': [ + { + 'action_name': 'js2c', + 'inputs': [ + '../../tools/js2c.py', + '<@(library_files)', + ], + 'outputs': [ + '<(SHARED_INTERMEDIATE_DIR)/libraries.cc', + '<(SHARED_INTERMEDIATE_DIR)/libraries-empty.cc', + ], + 'action': [ + 'python', + '../../tools/js2c.py', + '<@(_outputs)', + 'CORE', + '<@(library_files)' + ], + }, ], - }], - ], - }, - { - 'target_name': 'js2c', - 'type': 'none', - 'toolsets': ['host'], - 'variables': { - 'library_files': [ - '../../src/runtime.js', - '../../src/v8natives.js', - '../../src/array.js', - '../../src/string.js', - '../../src/uri.js', - '../../src/math.js', - '../../src/messages.js', - '../../src/apinatives.js', - '../../src/debug-debugger.js', - '../../src/mirror-debugger.js', - '../../src/liveedit-debugger.js', - '../../src/date.js', - '../../src/json.js', - '../../src/regexp.js', - '../../src/macros.py', - ], - }, - 'actions': [ + }, { - 'action_name': 'js2c', - 'inputs': [ - '../../tools/js2c.py', - '<@(library_files)', + 'target_name': 'mksnapshot', + 'type': 'executable', + 'toolsets': ['host'], + 'dependencies': [ + 'v8_nosnapshot', ], - 'outputs': [ - '<(SHARED_INTERMEDIATE_DIR)/libraries.cc', - '<(SHARED_INTERMEDIATE_DIR)/libraries-empty.cc', + 'include_dirs+': [ + '../../src', ], - 'action': [ - 'python', - '../../tools/js2c.py', - '<@(_outputs)', - 'CORE', - '<@(library_files)' + 'sources': [ + '../../src/mksnapshot.cc', + ], + 'conditions': [ + # The ARM assembler assumes the host is 32 bits, so force building + # 32-bit host tools. + ['v8_target_arch=="arm" and host_arch=="x64" and _toolset=="host"', { + 'cflags': ['-m32'], + 'ldflags': ['-m32'], + }] + ] + }, + { + 'target_name': 'v8_shell', + 'type': 'executable', + 'dependencies': [ + 'v8' + ], + 'sources': [ + '../../samples/shell.cc', + ], + 'conditions': [ + ['OS=="win"', { + # This could be gotten by not setting chromium_code, if that's OK. + 'defines': ['_CRT_SECURE_NO_WARNINGS'], + }], ], }, ], - }, - { - 'target_name': 'mksnapshot', - 'type': 'executable', - 'toolsets': ['host'], - 'dependencies': [ - 'v8_nosnapshot', - ], - 'include_dirs+': [ - '../../src', - ], - 'sources': [ - '../../src/mksnapshot.cc', - ], - 'conditions': [ - # The ARM assembler assumes the host is 32 bits, so force building - # 32-bit host tools. - ['v8_target_arch=="arm" and host_arch=="x64" and _toolset=="host"', { - 'cflags': ['-m32'], - 'ldflags': ['-m32'], - }] - ] - }, - { - 'target_name': 'v8_shell', - 'type': 'executable', - 'dependencies': [ - 'v8' - ], - 'sources': [ - '../../samples/shell.cc', - ], - 'conditions': [ - ['OS=="win"', { - # This could be gotten by not setting chromium_code, if that's OK. - 'defines': ['_CRT_SECURE_NO_WARNINGS'], - }], + }, { # use_system_v8 != 0 + 'targets': [ + { + 'target_name': 'v8', + 'type': 'settings', + 'link_settings': { + 'libraries': [ + '-lv8', + ], + }, + }, + { + 'target_name': 'v8_shell', + 'type': 'none', + 'dependencies': [ + 'v8' + ], + }, ], - }, + }], ], } diff --git a/tools/v8.xcodeproj/project.pbxproj b/tools/v8.xcodeproj/project.pbxproj index 5254c6e6..80a845cb 100644 --- a/tools/v8.xcodeproj/project.pbxproj +++ b/tools/v8.xcodeproj/project.pbxproj @@ -59,7 +59,6 @@ 893E24AD12B14B3D0083370F /* hydrogen.cc in Sources */ = {isa = PBXBuildFile; fileRef = 893E248F12B14B3D0083370F /* hydrogen.cc */; }; 893E24AE12B14B3D0083370F /* lithium-allocator.cc in Sources */ = {isa = PBXBuildFile; fileRef = 893E249312B14B3D0083370F /* lithium-allocator.cc */; }; 893E24AF12B14B3D0083370F /* preparse-data.cc in Sources */ = {isa = PBXBuildFile; fileRef = 893E249512B14B3D0083370F /* preparse-data.cc */; }; - 893E24B012B14B3D0083370F /* preparser-api.cc in Sources */ = {isa = PBXBuildFile; fileRef = 893E249712B14B3D0083370F /* preparser-api.cc */; }; 893E24B112B14B3D0083370F /* preparser.cc in Sources */ = {isa = PBXBuildFile; fileRef = 893E249812B14B3D0083370F /* preparser.cc */; }; 893E24B212B14B3D0083370F /* runtime-profiler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 893E249A12B14B3D0083370F /* runtime-profiler.cc */; }; 893E24B312B14B3D0083370F /* safepoint-table.cc in Sources */ = {isa = PBXBuildFile; fileRef = 893E249C12B14B3D0083370F /* safepoint-table.cc */; }; @@ -74,7 +73,6 @@ 893E24BC12B14B3D0083370F /* hydrogen.cc in Sources */ = {isa = PBXBuildFile; fileRef = 893E248F12B14B3D0083370F /* hydrogen.cc */; }; 893E24BD12B14B3D0083370F /* lithium-allocator.cc in Sources */ = {isa = PBXBuildFile; fileRef = 893E249312B14B3D0083370F /* lithium-allocator.cc */; }; 893E24BE12B14B3D0083370F /* preparse-data.cc in Sources */ = {isa = PBXBuildFile; fileRef = 893E249512B14B3D0083370F /* preparse-data.cc */; }; - 893E24BF12B14B3D0083370F /* preparser-api.cc in Sources */ = {isa = PBXBuildFile; fileRef = 893E249712B14B3D0083370F /* preparser-api.cc */; }; 893E24C012B14B3D0083370F /* preparser.cc in Sources */ = {isa = PBXBuildFile; fileRef = 893E249812B14B3D0083370F /* preparser.cc */; }; 893E24C112B14B3D0083370F /* runtime-profiler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 893E249A12B14B3D0083370F /* runtime-profiler.cc */; }; 893E24C212B14B3D0083370F /* safepoint-table.cc in Sources */ = {isa = PBXBuildFile; fileRef = 893E249C12B14B3D0083370F /* safepoint-table.cc */; }; @@ -94,6 +92,8 @@ 8944AD100F1D4D500028D560 /* regexp-stack.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8944AD0E0F1D4D3A0028D560 /* regexp-stack.cc */; }; 8944AD110F1D4D570028D560 /* regexp-stack.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8944AD0E0F1D4D3A0028D560 /* regexp-stack.cc */; }; 894599A30F5D8729008DA8FB /* debug-agent.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8956B6CD0F5D86570033B5A2 /* debug-agent.cc */; }; + 8946827512C26EB700C914BC /* objects-printer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8946827412C26EB700C914BC /* objects-printer.cc */; }; + 8946827612C26EB700C914BC /* objects-printer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8946827412C26EB700C914BC /* objects-printer.cc */; }; 89495E480E79FC23001F68C3 /* compilation-cache.cc in Sources */ = {isa = PBXBuildFile; fileRef = 89495E460E79FC23001F68C3 /* compilation-cache.cc */; }; 89495E490E79FC23001F68C3 /* compilation-cache.cc in Sources */ = {isa = PBXBuildFile; fileRef = 89495E460E79FC23001F68C3 /* compilation-cache.cc */; }; 8956B6CF0F5D86730033B5A2 /* debug-agent.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8956B6CD0F5D86570033B5A2 /* debug-agent.cc */; }; @@ -412,7 +412,6 @@ 893E249412B14B3D0083370F /* lithium-allocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "lithium-allocator.h"; sourceTree = "<group>"; }; 893E249512B14B3D0083370F /* preparse-data.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "preparse-data.cc"; sourceTree = "<group>"; }; 893E249612B14B3D0083370F /* preparse-data.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "preparse-data.h"; sourceTree = "<group>"; }; - 893E249712B14B3D0083370F /* preparser-api.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "preparser-api.cc"; sourceTree = "<group>"; }; 893E249812B14B3D0083370F /* preparser.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = preparser.cc; sourceTree = "<group>"; }; 893E249912B14B3D0083370F /* preparser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = preparser.h; sourceTree = "<group>"; }; 893E249A12B14B3D0083370F /* runtime-profiler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "runtime-profiler.cc"; sourceTree = "<group>"; }; @@ -447,6 +446,7 @@ 893E24DB12B14B9F0083370F /* gc-extension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "gc-extension.h"; path = "extensions/gc-extension.h"; sourceTree = "<group>"; }; 8944AD0E0F1D4D3A0028D560 /* regexp-stack.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "regexp-stack.cc"; sourceTree = "<group>"; }; 8944AD0F0F1D4D3A0028D560 /* regexp-stack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "regexp-stack.h"; sourceTree = "<group>"; }; + 8946827412C26EB700C914BC /* objects-printer.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "objects-printer.cc"; sourceTree = "<group>"; }; 89471C7F0EB23EE400B6874B /* flag-definitions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "flag-definitions.h"; sourceTree = "<group>"; }; 89495E460E79FC23001F68C3 /* compilation-cache.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "compilation-cache.cc"; sourceTree = "<group>"; }; 89495E470E79FC23001F68C3 /* compilation-cache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "compilation-cache.h"; sourceTree = "<group>"; }; @@ -467,8 +467,6 @@ 897F767A0E71B4CC007ACF34 /* v8_shell */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = v8_shell; sourceTree = BUILT_PRODUCTS_DIR; }; 897FF0D40E719A8500D62E90 /* v8-debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "v8-debug.h"; sourceTree = "<group>"; }; 897FF0D50E719A8500D62E90 /* v8.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = v8.h; sourceTree = "<group>"; }; - 897FF0E00E719B3500D62E90 /* COPYING */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = COPYING; sourceTree = "<group>"; }; - 897FF0E10E719B3500D62E90 /* dtoa.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dtoa.c; sourceTree = "<group>"; }; 897FF0F60E719B8F00D62E90 /* accessors.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = accessors.cc; sourceTree = "<group>"; }; 897FF0F70E719B8F00D62E90 /* accessors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = accessors.h; sourceTree = "<group>"; }; 897FF0F80E719B8F00D62E90 /* allocation.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = allocation.cc; sourceTree = "<group>"; }; @@ -1003,6 +1001,7 @@ 897FF15F0E719B8F00D62E90 /* natives.h */, 897FF1600E719B8F00D62E90 /* objects-debug.cc */, 897FF1610E719B8F00D62E90 /* objects-inl.h */, + 8946827412C26EB700C914BC /* objects-printer.cc */, C2D1E9711212F27B00187A52 /* objects-visiting.cc */, C2D1E9721212F27B00187A52 /* objects-visiting.h */, 897FF1620E719B8F00D62E90 /* objects.cc */, @@ -1020,7 +1019,6 @@ 897FF16A0E719B8F00D62E90 /* platform.h */, 893E249512B14B3D0083370F /* preparse-data.cc */, 893E249612B14B3D0083370F /* preparse-data.h */, - 893E249712B14B3D0083370F /* preparser-api.cc */, 893E249812B14B3D0083370F /* preparser.cc */, 893E249912B14B3D0083370F /* preparser.h */, 897FF16B0E719B8F00D62E90 /* prettyprinter.cc */, @@ -1161,7 +1159,6 @@ 893E24E212B14BD20083370F /* C++ */, 89A9C1630E71C8E300BE6CCA /* generated */, 897FF0D80E719ABA00D62E90 /* js */, - 897FF0DE0E719B3400D62E90 /* third_party */, ); path = src; sourceTree = "<group>"; @@ -1194,23 +1191,6 @@ name = js; sourceTree = "<group>"; }; - 897FF0DE0E719B3400D62E90 /* third_party */ = { - isa = PBXGroup; - children = ( - 897FF0DF0E719B3400D62E90 /* dtoa */, - ); - path = third_party; - sourceTree = "<group>"; - }; - 897FF0DF0E719B3400D62E90 /* dtoa */ = { - isa = PBXGroup; - children = ( - 897FF0E00E719B3500D62E90 /* COPYING */, - 897FF0E10E719B3500D62E90 /* dtoa.c */, - ); - path = dtoa; - sourceTree = "<group>"; - }; 897FF1B30E719BCE00D62E90 /* samples */ = { isa = PBXGroup; children = ( @@ -1583,7 +1563,6 @@ 893E24BC12B14B3D0083370F /* hydrogen.cc in Sources */, 893E24BD12B14B3D0083370F /* lithium-allocator.cc in Sources */, 893E24BE12B14B3D0083370F /* preparse-data.cc in Sources */, - 893E24BF12B14B3D0083370F /* preparser-api.cc in Sources */, 893E24C012B14B3D0083370F /* preparser.cc in Sources */, 893E24C112B14B3D0083370F /* runtime-profiler.cc in Sources */, 893E24C212B14B3D0083370F /* safepoint-table.cc in Sources */, @@ -1595,6 +1574,7 @@ 893E24D712B14B8A0083370F /* lithium-ia32.cc in Sources */, 893E24DC12B14B9F0083370F /* externalize-string-extension.cc in Sources */, 893E24DD12B14B9F0083370F /* gc-extension.cc in Sources */, + 8946827512C26EB700C914BC /* objects-printer.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1738,7 +1718,6 @@ 893E24AD12B14B3D0083370F /* hydrogen.cc in Sources */, 893E24AE12B14B3D0083370F /* lithium-allocator.cc in Sources */, 893E24AF12B14B3D0083370F /* preparse-data.cc in Sources */, - 893E24B012B14B3D0083370F /* preparser-api.cc in Sources */, 893E24B112B14B3D0083370F /* preparser.cc in Sources */, 893E24B212B14B3D0083370F /* runtime-profiler.cc in Sources */, 893E24B312B14B3D0083370F /* safepoint-table.cc in Sources */, @@ -1750,6 +1729,7 @@ 893E24CE12B14B520083370F /* lithium-codegen-arm.cc in Sources */, 893E24DE12B14B9F0083370F /* externalize-string-extension.cc in Sources */, 893E24DF12B14B9F0083370F /* gc-extension.cc in Sources */, + 8946827612C26EB700C914BC /* objects-printer.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1850,7 +1830,7 @@ DEBUG, ENABLE_LOGGING_AND_PROFILING, V8_ENABLE_CHECKS, - OBJECT_PRINT, + OBJECT_PRINT, ENABLE_VMSTATE_TRACKING, ); GCC_SYMBOLS_PRIVATE_EXTERN = YES; @@ -1915,7 +1895,7 @@ V8_TARGET_ARCH_IA32, DEBUG, V8_ENABLE_CHECKS, - OBJECT_PRINT, + OBJECT_PRINT, ENABLE_DEBUGGER_SUPPORT, ); HEADER_SEARCH_PATHS = ../src; @@ -1978,7 +1958,7 @@ V8_TARGET_ARCH_IA32, DEBUG, V8_ENABLE_CHECKS, - OBJECT_PRINT, + OBJECT_PRINT, ENABLE_DEBUGGER_SUPPORT, ); HEADER_SEARCH_PATHS = ../src; diff --git a/tools/visual_studio/v8_base.vcproj b/tools/visual_studio/v8_base.vcproj index e53b3fc3..ceeebf9a 100644 --- a/tools/visual_studio/v8_base.vcproj +++ b/tools/visual_studio/v8_base.vcproj @@ -793,6 +793,10 @@ > </File> <File + RelativePath="..\..\src\objects-printer.cc" + > + </File> + <File RelativePath="..\..\src\objects-visiting.cc" > </File> diff --git a/tools/visual_studio/v8_base_arm.vcproj b/tools/visual_studio/v8_base_arm.vcproj index 1054958a..cd4c52eb 100644 --- a/tools/visual_studio/v8_base_arm.vcproj +++ b/tools/visual_studio/v8_base_arm.vcproj @@ -793,6 +793,10 @@ > </File> <File + RelativePath="..\..\src\objects-printer.cc" + > + </File> + <File RelativePath="..\..\src\objects-visiting.cc" > </File> diff --git a/tools/visual_studio/v8_base_x64.vcproj b/tools/visual_studio/v8_base_x64.vcproj index 28f299ed..2c7bf5ef 100644 --- a/tools/visual_studio/v8_base_x64.vcproj +++ b/tools/visual_studio/v8_base_x64.vcproj @@ -770,6 +770,10 @@ > </File> <File + RelativePath="..\..\src\objects-printer.cc" + > + </File> + <File RelativePath="..\..\src\objects-visiting.cc" > </File> |