diff options
Diffstat (limited to 'src/3rdparty/v8/src/ia32/full-codegen-ia32.cc')
-rw-r--r-- | src/3rdparty/v8/src/ia32/full-codegen-ia32.cc | 373 |
1 files changed, 187 insertions, 186 deletions
diff --git a/src/3rdparty/v8/src/ia32/full-codegen-ia32.cc b/src/3rdparty/v8/src/ia32/full-codegen-ia32.cc index 66cf497..c58f242 100644 --- a/src/3rdparty/v8/src/ia32/full-codegen-ia32.cc +++ b/src/3rdparty/v8/src/ia32/full-codegen-ia32.cc @@ -123,6 +123,8 @@ void FullCodeGenerator::Generate() { SetFunctionPosition(function()); Comment cmnt(masm_, "[ function compiled by full code generator"); + ProfileEntryHookStub::MaybeCallEntryHook(masm_); + #ifdef DEBUG if (strlen(FLAG_stop_at) > 0 && info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { @@ -136,6 +138,8 @@ void FullCodeGenerator::Generate() { // function calls. if (!info->is_classic_mode() || info->is_native()) { Label ok; + Label start; + __ bind(&start); __ test(ecx, ecx); __ j(zero, &ok, Label::kNear); // +1 for return address. @@ -147,6 +151,8 @@ void FullCodeGenerator::Generate() { __ mov(Operand(esp, receiver_offset), Immediate(isolate()->factory()->undefined_value())); __ bind(&ok); + ASSERT(!FLAG_age_code || + (kSizeOfFullCodegenStrictModePrologue == ok.pos() - start.pos())); } // Open a frame scope to indicate that there is a frame on the stack. The @@ -177,11 +183,14 @@ void FullCodeGenerator::Generate() { int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; if (heap_slots > 0 || (scope()->is_qml_mode() && scope()->is_global_scope())) { - Comment cmnt(masm_, "[ Allocate local context"); + Comment cmnt(masm_, "[ Allocate context"); // Argument to NewContext is the function, which is still in edi. __ push(edi); - if (heap_slots <= FastNewContextStub::kMaximumSlots) { - FastNewContextStub stub((heap_slots < 0)?0:heap_slots); + if (FLAG_harmony_scoping && info->scope()->is_global_scope()) { + __ Push(info->scope()->GetScopeInfo()); + __ CallRuntime(Runtime::kNewGlobalContext, 2); + } else if (heap_slots <= FastNewContextStub::kMaximumSlots) { + FastNewContextStub stub((heap_slots < 0) ? 0 : heap_slots); __ CallStub(&stub); } else { __ CallRuntime(Runtime::kNewFunctionContext, 1); @@ -228,7 +237,7 @@ void FullCodeGenerator::Generate() { __ lea(edx, Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset)); __ push(edx); - __ SafePush(Immediate(Smi::FromInt(num_parameters))); + __ push(Immediate(Smi::FromInt(num_parameters))); // Arguments to ArgumentsAccessStub: // function, receiver address, parameter count. // The stub will rewrite receiver and parameter count if the previous @@ -258,7 +267,7 @@ void FullCodeGenerator::Generate() { scope()->VisitIllegalRedeclaration(this); } else { - PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); + PrepareForBailoutForId(BailoutId::FunctionEntry(), NO_REGISTERS); { Comment cmnt(masm_, "[ Declarations"); // For named function expressions, declare the function name as a // constant. @@ -273,7 +282,7 @@ void FullCodeGenerator::Generate() { } { Comment cmnt(masm_, "[ Stack check"); - PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS); + PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS); Label ok; ExternalReference stack_limit = ExternalReference::address_of_stack_limit(isolate()); @@ -318,20 +327,12 @@ void FullCodeGenerator::EmitProfilingCounterReset() { // Self-optimization is a one-off thing: if it fails, don't try again. reset_value = Smi::kMaxValue; } - if (isolate()->IsDebuggerActive()) { - // Detect debug break requests as soon as possible. - reset_value = 10; - } __ mov(ebx, Immediate(profiling_counter_)); __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), Immediate(Smi::FromInt(reset_value))); } -static const int kMaxBackEdgeWeight = 127; -static const int kBackEdgeDistanceDivisor = 100; - - void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt, Label* back_edge_target) { Comment cmnt(masm_, "[ Stack check"); @@ -343,7 +344,7 @@ void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt, ASSERT(back_edge_target->is_bound()); int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target); weight = Min(kMaxBackEdgeWeight, - Max(1, distance / kBackEdgeDistanceDivisor)); + Max(1, distance / kBackEdgeDistanceUnit)); } EmitProfilingCounterDecrement(weight); __ j(positive, &ok, Label::kNear); @@ -405,7 +406,7 @@ void FullCodeGenerator::EmitReturnSequence() { } else if (FLAG_weighted_back_edges) { int distance = masm_->pc_offset(); weight = Min(kMaxBackEdgeWeight, - Max(1, distance / kBackEdgeDistanceDivisor)); + Max(1, distance / kBackEdgeDistanceUnit)); } EmitProfilingCounterDecrement(weight); Label ok; @@ -761,7 +762,7 @@ void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) { // The variable in the declaration always resides in the current function // context. ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); - if (FLAG_debug_code) { + if (generate_debug_code_) { // Check that we're not inside a with or catch context. __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset)); __ cmp(ebx, isolate()->factory()->with_context_map()); @@ -783,11 +784,11 @@ void FullCodeGenerator::VisitVariableDeclaration( bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET; switch (variable->location()) { case Variable::UNALLOCATED: - globals_->Add(variable->name()); + globals_->Add(variable->name(), zone()); globals_->Add(variable->binding_needs_init() ? isolate()->factory()->the_hole_value() - : isolate()->factory()->undefined_value()); - globals_->Add(isolate()->factory()->ToBoolean(variable->is_qml_global())); + : isolate()->factory()->undefined_value(), zone()); + globals_->Add(isolate()->factory()->ToBoolean(variable->is_qml_global()), zone()); break; case Variable::PARAMETER: @@ -815,10 +816,9 @@ void FullCodeGenerator::VisitVariableDeclaration( __ push(esi); __ push(Immediate(variable->name())); // VariableDeclaration nodes are always introduced in one of four modes. - ASSERT(mode == VAR || mode == LET || - mode == CONST || mode == CONST_HARMONY); - PropertyAttributes attr = (mode == CONST || mode == CONST_HARMONY) - ? READ_ONLY : NONE; + ASSERT(IsDeclaredVariableMode(mode)); + PropertyAttributes attr = + IsImmutableVariableMode(mode) ? READ_ONLY : NONE; __ push(Immediate(Smi::FromInt(attr))); // Push initial value, if any. // Note: For variables we must not push an initial value (such as @@ -842,13 +842,13 @@ void FullCodeGenerator::VisitFunctionDeclaration( Variable* variable = proxy->var(); switch (variable->location()) { case Variable::UNALLOCATED: { - globals_->Add(variable->name()); + globals_->Add(variable->name(), zone()); Handle<SharedFunctionInfo> function = Compiler::BuildFunctionInfo(declaration->fun(), script()); // Check for stack-overflow exception. if (function.is_null()) return SetStackOverflow(); - globals_->Add(function); - globals_->Add(isolate()->factory()->ToBoolean(variable->is_qml_global())); + globals_->Add(function, zone()); + globals_->Add(isolate()->factory()->ToBoolean(variable->is_qml_global()), zone()); break; } @@ -899,9 +899,9 @@ void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) { switch (variable->location()) { case Variable::UNALLOCATED: { Comment cmnt(masm_, "[ ModuleDeclaration"); - globals_->Add(variable->name()); - globals_->Add(instance); - globals_->Add(isolate()->factory()->ToBoolean(variable->is_qml_global())); + globals_->Add(variable->name(), zone()); + globals_->Add(instance, zone()); + globals_->Add(isolate()->factory()->ToBoolean(variable->is_qml_global()), zone()); Visit(declaration->module()); break; } @@ -1098,19 +1098,28 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // We got a map in register eax. Get the enumeration cache from it. + Label no_descriptors; __ bind(&use_cache); + + __ EnumLength(edx, eax); + __ cmp(edx, Immediate(Smi::FromInt(0))); + __ j(equal, &no_descriptors); + __ LoadInstanceDescriptors(eax, ecx); - __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset)); - __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset)); + __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumCacheOffset)); + __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset)); // Set up the four remaining stack slots. __ push(eax); // Map. - __ push(edx); // Enumeration cache. - __ mov(eax, FieldOperand(edx, FixedArray::kLengthOffset)); - __ push(eax); // Enumeration cache length (as smi). + __ push(ecx); // Enumeration cache. + __ push(edx); // Number of valid entries for the map in the enum cache. __ push(Immediate(Smi::FromInt(0))); // Initial index. __ jmp(&loop); + __ bind(&no_descriptors); + __ add(esp, Immediate(kPointerSize)); + __ jmp(&exit); + // We got a fixed array in register eax. Iterate through that. Label non_proxy; __ bind(&fixed_array); @@ -1119,7 +1128,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { isolate()->factory()->NewJSGlobalPropertyCell( Handle<Object>( Smi::FromInt(TypeFeedbackCells::kForInFastCaseMarker))); - RecordTypeFeedbackCell(stmt->PrepareId(), cell); + RecordTypeFeedbackCell(stmt->ForInFeedbackId(), cell); __ LoadHeapObject(ebx, cell); __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), Immediate(Smi::FromInt(TypeFeedbackCells::kForInSlowCaseMarker))); @@ -1275,9 +1284,9 @@ void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var, __ mov(temp, context); } __ bind(&next); - // Terminate at global context. + // Terminate at native context. __ cmp(FieldOperand(temp, HeapObject::kMapOffset), - Immediate(isolate()->factory()->global_context_map())); + Immediate(isolate()->factory()->native_context_map())); __ j(equal, &fast, Label::kNear); // Check that extension is NULL. __ cmp(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0)); @@ -1561,9 +1570,9 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { // Mark all computed expressions that are bound to a key that // is shadowed by a later occurrence of the same key. For the // marked expressions, no store code is emitted. - expr->CalculateEmitStore(); + expr->CalculateEmitStore(zone()); - AccessorTable accessor_table(isolate()->zone()); + AccessorTable accessor_table(zone()); for (int i = 0; i < expr->properties()->length(); i++) { ObjectLiteral::Property* property = expr->properties()->at(i); if (property->IsCompileTimeValue()) continue; @@ -1589,7 +1598,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { Handle<Code> ic = is_classic_mode() ? isolate()->builtins()->StoreIC_Initialize() : isolate()->builtins()->StoreIC_Initialize_Strict(); - CallIC(ic, RelocInfo::CODE_TARGET, key->id()); + CallIC(ic, RelocInfo::CODE_TARGET, key->LiteralFeedbackId()); PrepareForBailoutForId(key->id(), NO_REGISTERS); } else { VisitForEffect(value); @@ -1653,7 +1662,8 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { ASSERT_EQ(2, constant_elements->length()); ElementsKind constant_elements_kind = static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value()); - bool has_constant_fast_elements = constant_elements_kind == FAST_ELEMENTS; + bool has_constant_fast_elements = + IsFastObjectElementsKind(constant_elements_kind); Handle<FixedArrayBase> constant_elements_values( FixedArrayBase::cast(constant_elements->get(1))); @@ -1664,7 +1674,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { Heap* heap = isolate()->heap(); if (has_constant_fast_elements && constant_elements_values->map() == heap->fixed_cow_array_map()) { - // If the elements are already FAST_ELEMENTS, the boilerplate cannot + // If the elements are already FAST_*_ELEMENTS, the boilerplate cannot // change, so it's possible to specialize the stub in advance. __ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(), 1); FastCloneShallowArrayStub stub( @@ -1676,10 +1686,9 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) { __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3); } else { - ASSERT(constant_elements_kind == FAST_ELEMENTS || - constant_elements_kind == FAST_SMI_ONLY_ELEMENTS || + ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind) || FLAG_smi_only_arrays); - // If the elements are already FAST_ELEMENTS, the boilerplate cannot + // If the elements are already FAST_*_ELEMENTS, the boilerplate cannot // change, so it's possible to specialize the stub in advance. FastCloneShallowArrayStub::Mode mode = has_constant_fast_elements ? FastCloneShallowArrayStub::CLONE_ELEMENTS @@ -1707,9 +1716,9 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { } VisitForAccumulatorValue(subexpr); - if (constant_elements_kind == FAST_ELEMENTS) { - // Fast-case array literal with ElementsKind of FAST_ELEMENTS, they cannot - // transition and don't need to call the runtime stub. + if (IsFastObjectElementsKind(constant_elements_kind)) { + // Fast-case array literal with ElementsKind of FAST_*_ELEMENTS, they + // cannot transition and don't need to call the runtime stub. int offset = FixedArray::kHeaderSize + (i * kPointerSize); __ mov(ebx, Operand(esp, 0)); // Copy of array literal. __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset)); @@ -1801,11 +1810,11 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { break; case NAMED_PROPERTY: EmitNamedPropertyLoad(property); - PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG); + PrepareForBailoutForId(property->LoadId(), TOS_REG); break; case KEYED_PROPERTY: EmitKeyedPropertyLoad(property); - PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG); + PrepareForBailoutForId(property->LoadId(), TOS_REG); break; } } @@ -1861,14 +1870,14 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { ASSERT(!key->handle()->IsSmi()); __ mov(ecx, Immediate(key->handle())); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); - CallIC(ic, RelocInfo::CODE_TARGET, prop->id()); + CallIC(ic, RelocInfo::CODE_TARGET, prop->PropertyFeedbackId()); } void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { SetSourcePosition(prop->position()); Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); - CallIC(ic, RelocInfo::CODE_TARGET, prop->id()); + CallIC(ic, RelocInfo::CODE_TARGET, prop->PropertyFeedbackId()); } @@ -1889,7 +1898,8 @@ void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, __ bind(&stub_call); __ mov(eax, ecx); BinaryOpStub stub(op, mode); - CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); + CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, + expr->BinaryOperationFeedbackId()); patch_site.EmitPatchInfo(); __ jmp(&done, Label::kNear); @@ -1974,7 +1984,8 @@ void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, __ pop(edx); BinaryOpStub stub(op, mode); JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code. - CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); + CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, + expr->BinaryOperationFeedbackId()); patch_site.EmitPatchInfo(); context()->Plug(eax); } @@ -2101,7 +2112,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, // in harmony mode. if (var->IsStackAllocated() || var->IsContextSlot()) { MemOperand location = VarOperand(var, ecx); - if (FLAG_debug_code && op == Token::INIT_LET) { + if (generate_debug_code_ && op == Token::INIT_LET) { // Check for an uninitialized let binding. __ mov(edx, location); __ cmp(edx, isolate()->factory()->the_hole_value()); @@ -2136,37 +2147,15 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { ASSERT(prop != NULL); ASSERT(prop->key()->AsLiteral() != NULL); - // If the assignment starts a block of assignments to the same object, - // change to slow case to avoid the quadratic behavior of repeatedly - // adding fast properties. - if (expr->starts_initialization_block()) { - __ push(result_register()); - __ push(Operand(esp, kPointerSize)); // Receiver is now under value. - __ CallRuntime(Runtime::kToSlowProperties, 1); - __ pop(result_register()); - } - // Record source code position before IC call. SetSourcePosition(expr->position()); __ mov(ecx, prop->key()->AsLiteral()->handle()); - if (expr->ends_initialization_block()) { - __ mov(edx, Operand(esp, 0)); - } else { - __ pop(edx); - } + __ pop(edx); Handle<Code> ic = is_classic_mode() ? isolate()->builtins()->StoreIC_Initialize() : isolate()->builtins()->StoreIC_Initialize_Strict(); - CallIC(ic, RelocInfo::CODE_TARGET, expr->id()); + CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId()); - // If the assignment ends an initialization block, revert to fast case. - if (expr->ends_initialization_block()) { - __ push(eax); // Result of assignment, saved even if not needed. - __ push(Operand(esp, kPointerSize)); // Receiver is under value. - __ CallRuntime(Runtime::kToFastProperties, 1); - __ pop(eax); - __ Drop(1); - } PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); context()->Plug(eax); } @@ -2178,38 +2167,14 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { // esp[0] : key // esp[kPointerSize] : receiver - // If the assignment starts a block of assignments to the same object, - // change to slow case to avoid the quadratic behavior of repeatedly - // adding fast properties. - if (expr->starts_initialization_block()) { - __ push(result_register()); - // Receiver is now under the key and value. - __ push(Operand(esp, 2 * kPointerSize)); - __ CallRuntime(Runtime::kToSlowProperties, 1); - __ pop(result_register()); - } - __ pop(ecx); // Key. - if (expr->ends_initialization_block()) { - __ mov(edx, Operand(esp, 0)); // Leave receiver on the stack for later. - } else { - __ pop(edx); - } + __ pop(edx); // Record source code position before IC call. SetSourcePosition(expr->position()); Handle<Code> ic = is_classic_mode() ? isolate()->builtins()->KeyedStoreIC_Initialize() : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); - CallIC(ic, RelocInfo::CODE_TARGET, expr->id()); - - // If the assignment ends an initialization block, revert to fast case. - if (expr->ends_initialization_block()) { - __ pop(edx); - __ push(eax); // Result of assignment, saved even if not needed. - __ push(edx); - __ CallRuntime(Runtime::kToFastProperties, 1); - __ pop(eax); - } + CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId()); PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); context()->Plug(eax); @@ -2224,6 +2189,7 @@ void FullCodeGenerator::VisitProperty(Property* expr) { VisitForAccumulatorValue(expr->obj()); __ mov(edx, result_register()); EmitNamedPropertyLoad(expr); + PrepareForBailoutForId(expr->LoadId(), TOS_REG); context()->Plug(eax); } else { VisitForStackValue(expr->obj()); @@ -2238,7 +2204,7 @@ void FullCodeGenerator::VisitProperty(Property* expr) { void FullCodeGenerator::CallIC(Handle<Code> code, RelocInfo::Mode rmode, - unsigned ast_id) { + TypeFeedbackId ast_id) { ic_total_count_++; __ call(code, rmode, ast_id); } @@ -2262,7 +2228,7 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr, SetSourcePosition(expr->position()); Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode); - CallIC(ic, mode, expr->id()); + CallIC(ic, mode, expr->CallFeedbackId()); RecordJSReturnSite(expr); // Restore context register. __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); @@ -2294,7 +2260,7 @@ void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count); __ mov(ecx, Operand(esp, (arg_count + 1) * kPointerSize)); // Key. - CallIC(ic, RelocInfo::CODE_TARGET, expr->id()); + CallIC(ic, RelocInfo::CODE_TARGET, expr->CallFeedbackId()); RecordJSReturnSite(expr); // Restore context register. __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); @@ -2314,20 +2280,18 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) { // Record source position for debugger. SetSourcePosition(expr->position()); - // Record call targets in unoptimized code, but not in the snapshot. - if (!Serializer::enabled()) { - flags = static_cast<CallFunctionFlags>(flags | RECORD_CALL_TARGET); - Handle<Object> uninitialized = - TypeFeedbackCells::UninitializedSentinel(isolate()); - Handle<JSGlobalPropertyCell> cell = - isolate()->factory()->NewJSGlobalPropertyCell(uninitialized); - RecordTypeFeedbackCell(expr->id(), cell); - __ mov(ebx, cell); - } + // Record call targets in unoptimized code. + flags = static_cast<CallFunctionFlags>(flags | RECORD_CALL_TARGET); + Handle<Object> uninitialized = + TypeFeedbackCells::UninitializedSentinel(isolate()); + Handle<JSGlobalPropertyCell> cell = + isolate()->factory()->NewJSGlobalPropertyCell(uninitialized); + RecordTypeFeedbackCell(expr->CallFeedbackId(), cell); + __ mov(ebx, cell); CallFunctionStub stub(arg_count, flags); __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize)); - __ CallStub(&stub, expr->id()); + __ CallStub(&stub, expr->CallFeedbackId()); RecordJSReturnSite(expr); // Restore context register. @@ -2502,24 +2466,18 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) { SetSourcePosition(expr->position()); // Load function and argument count into edi and eax. - __ SafeSet(eax, Immediate(arg_count)); + __ Set(eax, Immediate(arg_count)); __ mov(edi, Operand(esp, arg_count * kPointerSize)); - // Record call targets in unoptimized code, but not in the snapshot. - CallFunctionFlags flags; - if (!Serializer::enabled()) { - flags = RECORD_CALL_TARGET; - Handle<Object> uninitialized = - TypeFeedbackCells::UninitializedSentinel(isolate()); - Handle<JSGlobalPropertyCell> cell = - isolate()->factory()->NewJSGlobalPropertyCell(uninitialized); - RecordTypeFeedbackCell(expr->id(), cell); - __ mov(ebx, cell); - } else { - flags = NO_CALL_FUNCTION_FLAGS; - } + // Record call targets in unoptimized code. + Handle<Object> uninitialized = + TypeFeedbackCells::UninitializedSentinel(isolate()); + Handle<JSGlobalPropertyCell> cell = + isolate()->factory()->NewJSGlobalPropertyCell(uninitialized); + RecordTypeFeedbackCell(expr->CallNewFeedbackId(), cell); + __ mov(ebx, cell); - CallConstructStub stub(flags); + CallConstructStub stub(RECORD_CALL_TARGET); __ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL); PrepareForBailoutForId(expr->ReturnId(), TOS_REG); context()->Plug(eax); @@ -2660,7 +2618,7 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( context()->PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false, &fall_through); - if (FLAG_debug_code) __ AbortIfSmi(eax); + __ AssertNotSmi(eax); // Check whether this map has already been checked to be safe for default // valueOf. @@ -2676,45 +2634,51 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( __ j(equal, if_false); // Look for valueOf symbol in the descriptor array, and indicate false if - // found. The type is not checked, so if it is a transition it is a false - // negative. + // found. Since we omit an enumeration index check, if it is added via a + // transition that shares its descriptor array, this is a false positive. + Label entry, loop, done; + + // Skip loop if no descriptors are valid. + __ NumberOfOwnDescriptors(ecx, ebx); + __ cmp(ecx, 0); + __ j(equal, &done); + __ LoadInstanceDescriptors(ebx, ebx); - __ mov(ecx, FieldOperand(ebx, FixedArray::kLengthOffset)); - // ebx: descriptor array - // ecx: length of descriptor array + // ebx: descriptor array. + // ecx: valid entries in the descriptor array. // Calculate the end of the descriptor array. STATIC_ASSERT(kSmiTag == 0); STATIC_ASSERT(kSmiTagSize == 1); STATIC_ASSERT(kPointerSize == 4); - __ lea(ecx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize)); + __ imul(ecx, ecx, DescriptorArray::kDescriptorSize); + __ lea(ecx, Operand(ebx, ecx, times_2, DescriptorArray::kFirstOffset)); // Calculate location of the first key name. - __ add(ebx, - Immediate(FixedArray::kHeaderSize + - DescriptorArray::kFirstIndex * kPointerSize)); + __ add(ebx, Immediate(DescriptorArray::kFirstOffset)); // Loop through all the keys in the descriptor array. If one of these is the // symbol valueOf the result is false. - Label entry, loop; __ jmp(&entry); __ bind(&loop); __ mov(edx, FieldOperand(ebx, 0)); __ cmp(edx, FACTORY->value_of_symbol()); __ j(equal, if_false); - __ add(ebx, Immediate(kPointerSize)); + __ add(ebx, Immediate(DescriptorArray::kDescriptorSize * kPointerSize)); __ bind(&entry); __ cmp(ebx, ecx); __ j(not_equal, &loop); + __ bind(&done); + // Reload map as register ebx was used as temporary above. __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); - // If a valueOf property is not found on the object check that it's + // If a valueOf property is not found on the object check that its // prototype is the un-modified String prototype. If not result is false. __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset)); __ JumpIfSmi(ecx, if_false); __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset)); - __ mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); + __ mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); __ mov(edx, - FieldOperand(edx, GlobalObject::kGlobalContextOffset)); + FieldOperand(edx, GlobalObject::kNativeContextOffset)); __ cmp(ecx, ContextOperand(edx, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX)); @@ -2860,7 +2824,7 @@ void FullCodeGenerator::EmitArguments(CallRuntime* expr) { // parameter count in eax. VisitForAccumulatorValue(args->at(0)); __ mov(edx, eax); - __ SafeSet(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters()))); + __ Set(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters()))); ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); __ CallStub(&stub); context()->Plug(eax); @@ -2872,7 +2836,7 @@ void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) { Label exit; // Get the number of formal parameters. - __ SafeSet(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters()))); + __ Set(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters()))); // Check if the calling frame is an arguments adaptor frame. __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); @@ -2885,7 +2849,7 @@ void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) { __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset)); __ bind(&exit); - if (FLAG_debug_code) __ AbortIfNotSmi(eax); + __ AssertSmi(eax); context()->Plug(eax); } @@ -2989,8 +2953,8 @@ void FullCodeGenerator::EmitRandomHeapNumber(CallRuntime* expr) { __ bind(&heapnumber_allocated); __ PrepareCallCFunction(1, ebx); - __ mov(eax, ContextOperand(context_register(), Context::GLOBAL_INDEX)); - __ mov(eax, FieldOperand(eax, GlobalObject::kGlobalContextOffset)); + __ mov(eax, ContextOperand(context_register(), Context::GLOBAL_OBJECT_INDEX)); + __ mov(eax, FieldOperand(eax, GlobalObject::kNativeContextOffset)); __ mov(Operand(esp, 0), eax); __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1); @@ -3077,19 +3041,18 @@ void FullCodeGenerator::EmitDateField(CallRuntime* expr) { VisitForAccumulatorValue(args->at(0)); // Load the object. - Label runtime, done; + Label runtime, done, not_date_object; Register object = eax; Register result = eax; Register scratch = ecx; -#ifdef DEBUG - __ AbortIfSmi(object); + __ JumpIfSmi(object, ¬_date_object); __ CmpObjectType(object, JS_DATE_TYPE, scratch); - __ Assert(equal, "Trying to get date field from non-date."); -#endif + __ j(not_equal, ¬_date_object); if (index->value() == 0) { __ mov(result, FieldOperand(object, JSDate::kValueOffset)); + __ jmp(&done); } else { if (index->value() < JSDate::kFirstUncachedField) { ExternalReference stamp = ExternalReference::date_cache_stamp(isolate()); @@ -3105,8 +3068,12 @@ void FullCodeGenerator::EmitDateField(CallRuntime* expr) { __ mov(Operand(esp, 0), object); __ mov(Operand(esp, 1 * kPointerSize), Immediate(index)); __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2); - __ bind(&done); + __ jmp(&done); } + + __ bind(¬_date_object); + __ CallRuntime(Runtime::kThrowNotDateError, 0); + __ bind(&done); context()->Plug(result); } @@ -3377,10 +3344,11 @@ void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) { } VisitForAccumulatorValue(args->last()); // Function. - // Check for proxy. - Label proxy, done; - __ CmpObjectType(eax, JS_FUNCTION_PROXY_TYPE, ebx); - __ j(equal, &proxy); + Label runtime, done; + // Check for non-function argument (including proxy). + __ JumpIfSmi(eax, &runtime); + __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx); + __ j(not_equal, &runtime); // InvokeFunction requires the function in edi. Move it in there. __ mov(edi, result_register()); @@ -3390,7 +3358,7 @@ void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) { __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); __ jmp(&done); - __ bind(&proxy); + __ bind(&runtime); __ push(eax); __ CallRuntime(Runtime::kCall, args->length()); __ bind(&done); @@ -3420,7 +3388,7 @@ void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) { int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value(); Handle<FixedArray> jsfunction_result_caches( - isolate()->global_context()->jsfunction_result_caches()); + isolate()->native_context()->jsfunction_result_caches()); if (jsfunction_result_caches->length() <= cache_id) { __ Abort("Attempt to use undefined cache."); __ mov(eax, isolate()->factory()->undefined_value()); @@ -3433,9 +3401,9 @@ void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) { Register key = eax; Register cache = ebx; Register tmp = ecx; - __ mov(cache, ContextOperand(esi, Context::GLOBAL_INDEX)); + __ mov(cache, ContextOperand(esi, Context::GLOBAL_OBJECT_INDEX)); __ mov(cache, - FieldOperand(cache, GlobalObject::kGlobalContextOffset)); + FieldOperand(cache, GlobalObject::kNativeContextOffset)); __ mov(cache, ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX)); __ mov(cache, FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id))); @@ -3505,9 +3473,7 @@ void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) { VisitForAccumulatorValue(args->at(0)); - if (FLAG_debug_code) { - __ AbortIfNotString(eax); - } + __ AssertString(eax); Label materialize_true, materialize_false; Label* if_true = NULL; @@ -3530,9 +3496,7 @@ void FullCodeGenerator::EmitGetCachedArrayIndex(CallRuntime* expr) { ASSERT(args->length() == 1); VisitForAccumulatorValue(args->at(0)); - if (FLAG_debug_code) { - __ AbortIfNotString(eax); - } + __ AssertString(eax); __ mov(eax, FieldOperand(eax, String::kHashFieldOffset)); __ IndexFromHash(eax, eax); @@ -3606,7 +3570,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { // Loop condition: while (index < length). // Live loop registers: index, array_length, string, // scratch, string_length, elements. - if (FLAG_debug_code) { + if (generate_debug_code_) { __ cmp(index, array_length); __ Assert(less, "No empty arrays here in EmitFastAsciiArrayJoin"); } @@ -3620,7 +3584,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); __ and_(scratch, Immediate( kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); - __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag); + __ cmp(scratch, kStringTag | kOneByteStringTag | kSeqStringTag); __ j(not_equal, &bailout); __ add(string_length, FieldOperand(string, SeqAsciiString::kLengthOffset)); @@ -3834,7 +3798,7 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { RelocInfo::Mode mode = RelocInfo::CODE_TARGET; Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode); - CallIC(ic, mode, expr->id()); + CallIC(ic, mode, expr->CallRuntimeFeedbackId()); // Restore context register. __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); } else { @@ -3992,7 +3956,8 @@ void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr, // accumulator register eax. VisitForAccumulatorValue(expr->expression()); SetSourcePosition(expr->position()); - CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); + CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, + expr->UnaryOperationFeedbackId()); context()->Plug(eax); } @@ -4050,7 +4015,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { if (assign_type == VARIABLE) { PrepareForBailout(expr->expression(), TOS_REG); } else { - PrepareForBailoutForId(expr->CountId(), TOS_REG); + PrepareForBailoutForId(prop->LoadId(), TOS_REG); } // Call ToNumber only if operand is not a smi. @@ -4113,7 +4078,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { __ mov(edx, eax); __ mov(eax, Immediate(Smi::FromInt(1))); BinaryOpStub stub(expr->binary_op(), NO_OVERWRITE); - CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->CountId()); + CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->CountBinOpFeedbackId()); patch_site.EmitPatchInfo(); __ bind(&done); @@ -4147,7 +4112,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { Handle<Code> ic = is_classic_mode() ? isolate()->builtins()->StoreIC_Initialize() : isolate()->builtins()->StoreIC_Initialize_Strict(); - CallIC(ic, RelocInfo::CODE_TARGET, expr->id()); + CallIC(ic, RelocInfo::CODE_TARGET, expr->CountStoreFeedbackId()); PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); if (expr->is_postfix()) { if (!context()->IsEffect()) { @@ -4164,7 +4129,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { Handle<Code> ic = is_classic_mode() ? isolate()->builtins()->KeyedStoreIC_Initialize() : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); - CallIC(ic, RelocInfo::CODE_TARGET, expr->id()); + CallIC(ic, RelocInfo::CODE_TARGET, expr->CountStoreFeedbackId()); PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); if (expr->is_postfix()) { // Result is on the stack @@ -4372,7 +4337,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { // Record position and call the compare IC. SetSourcePosition(expr->position()); Handle<Code> ic = CompareIC::GetUninitialized(op); - CallIC(ic, RelocInfo::CODE_TARGET, expr->id()); + CallIC(ic, RelocInfo::CODE_TARGET, expr->CompareOperationFeedbackId()); patch_site.EmitPatchInfo(); PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); @@ -4454,7 +4419,7 @@ void FullCodeGenerator::PushFunctionArgumentForContextAllocation() { Scope* declaration_scope = scope()->DeclarationScope(); if (declaration_scope->is_global_scope() || declaration_scope->is_module_scope()) { - // Contexts nested in the global context have a canonical empty function + // Contexts nested in the native context have a canonical empty function // as their closure, not the anonymous closure containing the global // code. Pass a smi sentinel and let the runtime look up the empty // function. @@ -4483,14 +4448,51 @@ void FullCodeGenerator::EnterFinallyBlock() { STATIC_ASSERT(kSmiTag == 0); __ SmiTag(edx); __ push(edx); + // Store result register while executing finally block. __ push(result_register()); + + // Store pending message while executing finally block. + ExternalReference pending_message_obj = + ExternalReference::address_of_pending_message_obj(isolate()); + __ mov(edx, Operand::StaticVariable(pending_message_obj)); + __ push(edx); + + ExternalReference has_pending_message = + ExternalReference::address_of_has_pending_message(isolate()); + __ mov(edx, Operand::StaticVariable(has_pending_message)); + __ SmiTag(edx); + __ push(edx); + + ExternalReference pending_message_script = + ExternalReference::address_of_pending_message_script(isolate()); + __ mov(edx, Operand::StaticVariable(pending_message_script)); + __ push(edx); } void FullCodeGenerator::ExitFinallyBlock() { ASSERT(!result_register().is(edx)); + // Restore pending message from stack. + __ pop(edx); + ExternalReference pending_message_script = + ExternalReference::address_of_pending_message_script(isolate()); + __ mov(Operand::StaticVariable(pending_message_script), edx); + + __ pop(edx); + __ SmiUntag(edx); + ExternalReference has_pending_message = + ExternalReference::address_of_has_pending_message(isolate()); + __ mov(Operand::StaticVariable(has_pending_message), edx); + + __ pop(edx); + ExternalReference pending_message_obj = + ExternalReference::address_of_pending_message_obj(isolate()); + __ mov(Operand::StaticVariable(pending_message_obj), edx); + + // Restore result register from stack. __ pop(result_register()); + // Uncook return address. __ pop(edx); __ SmiUntag(edx); @@ -4526,7 +4528,6 @@ FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit( return previous_; } - #undef __ } } // namespace v8::internal |