diff --git a/deps/v8/BUILD.gn b/deps/v8/BUILD.gn index 94c09a167090ff..7524ba8421de1f 100644 --- a/deps/v8/BUILD.gn +++ b/deps/v8/BUILD.gn @@ -258,6 +258,9 @@ config("features") { if (v8_enable_handle_zapping) { defines += [ "ENABLE_HANDLE_ZAPPING" ] } + if (v8_use_snapshot) { + defines += [ "V8_USE_SNAPSHOT" ] + } if (v8_use_external_startup_data) { defines += [ "V8_USE_EXTERNAL_STARTUP_DATA" ] } diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h index 2e67bc333d6b1a..d7b7205ef0a0b1 100644 --- a/deps/v8/include/v8.h +++ b/deps/v8/include/v8.h @@ -6342,8 +6342,9 @@ class V8_EXPORT Isolate { * The optional entry_hook allows the host application to provide the * address of a function that's invoked on entry to every V8-generated * function. Note that entry_hook is invoked at the very start of each - * generated function. Furthermore, if an entry_hook is given, V8 will - * not use a snapshot, including custom snapshots. + * generated function. + * An entry_hook can only be provided in no-snapshot builds; in snapshot + * builds it must be nullptr. */ FunctionEntryHook entry_hook; diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index 156afe349d49fd..031ad5a0237ac4 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -8143,6 +8143,12 @@ Isolate* Isolate::New(const Isolate::CreateParams& params) { isolate->set_snapshot_blob(i::Snapshot::DefaultSnapshotBlob()); } if (params.entry_hook) { +#ifdef V8_USE_SNAPSHOT + // Setting a FunctionEntryHook is only supported in no-snapshot builds. + Utils::ApiCheck( + false, "v8::Isolate::New", + "Setting a FunctionEntryHook is only supported in no-snapshot builds."); +#endif isolate->set_function_entry_hook(params.entry_hook); } auto code_event_handler = params.code_event_handler; diff --git a/deps/v8/src/arm/macro-assembler-arm.cc b/deps/v8/src/arm/macro-assembler-arm.cc index 8d87db283f1a4d..83fb983ed1f5d9 100644 --- a/deps/v8/src/arm/macro-assembler-arm.cc +++ b/deps/v8/src/arm/macro-assembler-arm.cc @@ -2422,20 +2422,6 @@ void MacroAssembler::LoadWeakValue(Register value, Handle cell, JumpIfSmi(value, miss); } - -void MacroAssembler::GetMapConstructor(Register result, Register map, - Register temp, Register temp2) { - Label done, loop; - ldr(result, FieldMemOperand(map, Map::kConstructorOrBackPointerOffset)); - bind(&loop); - JumpIfSmi(result, &done); - CompareObjectType(result, temp, temp2, MAP_TYPE); - b(ne, &done); - ldr(result, FieldMemOperand(result, Map::kConstructorOrBackPointerOffset)); - b(&loop); - bind(&done); -} - void MacroAssembler::CallStub(CodeStub* stub, TypeFeedbackId ast_id, Condition cond) { diff --git a/deps/v8/src/arm/macro-assembler-arm.h b/deps/v8/src/arm/macro-assembler-arm.h index e285bd49fcfee9..04d1d1b92da266 100644 --- a/deps/v8/src/arm/macro-assembler-arm.h +++ b/deps/v8/src/arm/macro-assembler-arm.h @@ -824,11 +824,6 @@ class MacroAssembler: public Assembler { // --------------------------------------------------------------------------- // Support functions. - // Machine code version of Map::GetConstructor(). - // |temp| holds |result|'s map when done, and |temp2| its instance type. - void GetMapConstructor(Register result, Register map, Register temp, - Register temp2); - // Compare object type for heap object. heap_object contains a non-Smi // whose object type should be compared with the given type. This both // sets the flags and leaves the object type in the type_reg register. diff --git a/deps/v8/src/arm64/macro-assembler-arm64.cc b/deps/v8/src/arm64/macro-assembler-arm64.cc index 549db5d048bc9a..2302d3dff02993 100644 --- a/deps/v8/src/arm64/macro-assembler-arm64.cc +++ b/deps/v8/src/arm64/macro-assembler-arm64.cc @@ -3385,19 +3385,6 @@ void MacroAssembler::LoadElementsKindFromMap(Register result, Register map) { } -void MacroAssembler::GetMapConstructor(Register result, Register map, - Register temp, Register temp2) { - Label done, loop; - Ldr(result, FieldMemOperand(map, Map::kConstructorOrBackPointerOffset)); - Bind(&loop); - JumpIfSmi(result, &done); - CompareObjectType(result, temp, temp2, MAP_TYPE); - B(ne, &done); - Ldr(result, FieldMemOperand(result, Map::kConstructorOrBackPointerOffset)); - B(&loop); - Bind(&done); -} - void MacroAssembler::PushRoot(Heap::RootListIndex index) { UseScratchRegisterScope temps(this); Register temp = temps.AcquireX(); diff --git a/deps/v8/src/arm64/macro-assembler-arm64.h b/deps/v8/src/arm64/macro-assembler-arm64.h index 560a824c048ff5..a9f1d8e783f83d 100644 --- a/deps/v8/src/arm64/macro-assembler-arm64.h +++ b/deps/v8/src/arm64/macro-assembler-arm64.h @@ -1363,11 +1363,6 @@ class MacroAssembler : public Assembler { // --------------------------------------------------------------------------- // Support functions. - // Machine code version of Map::GetConstructor(). - // |temp| holds |result|'s map when done, and |temp2| its instance type. - void GetMapConstructor(Register result, Register map, Register temp, - Register temp2); - // Compare object type for heap object. heap_object contains a non-Smi // whose object type should be compared with the given type. This both // sets the flags and leaves the object type in the type_reg register. diff --git a/deps/v8/src/ast/ast-types.cc b/deps/v8/src/ast/ast-types.cc index 3dde86413a24a9..ffbecd27b0f08e 100644 --- a/deps/v8/src/ast/ast-types.cc +++ b/deps/v8/src/ast/ast-types.cc @@ -186,7 +186,6 @@ AstType::bitset AstBitsetType::Lub(i::Map* map) { if (map == heap->boolean_map()) return kBoolean; if (map == heap->the_hole_map()) return kHole; DCHECK(map == heap->uninitialized_map() || - map == heap->no_interceptor_result_sentinel_map() || map == heap->termination_exception_map() || map == heap->arguments_marker_map() || map == heap->optimized_out_map() || diff --git a/deps/v8/src/compiler.cc b/deps/v8/src/compiler.cc index fded1e2b86e014..2c9c888b6f916a 100644 --- a/deps/v8/src/compiler.cc +++ b/deps/v8/src/compiler.cc @@ -759,6 +759,16 @@ bool GetOptimizedCodeLater(CompilationJob* job) { CompilationInfo* info = job->info(); Isolate* isolate = info->isolate(); + if (FLAG_mark_optimizing_shared_functions && + info->closure()->shared()->has_concurrent_optimization_job()) { + if (FLAG_trace_concurrent_recompilation) { + PrintF(" ** Compilation job already running for "); + info->shared_info()->ShortPrint(); + PrintF(".\n"); + } + return false; + } + if (!isolate->optimizing_compile_dispatcher()->IsQueueAvailable()) { if (FLAG_trace_concurrent_recompilation) { PrintF(" ** Compilation queue full, will retry optimizing "); @@ -793,6 +803,7 @@ bool GetOptimizedCodeLater(CompilationJob* job) { if (job->PrepareJob() != CompilationJob::SUCCEEDED) return false; isolate->optimizing_compile_dispatcher()->QueueForOptimization(job); + info->closure()->shared()->set_has_concurrent_optimization_job(true); if (FLAG_trace_concurrent_recompilation) { PrintF(" ** Queued "); @@ -813,9 +824,6 @@ MaybeHandle GetOptimizedCode(Handle function, DCHECK_IMPLIES(ignition_osr, !osr_ast_id.IsNone()); DCHECK_IMPLIES(ignition_osr, FLAG_ignition_osr); - // Shared function no longer needs to be tiered up - shared->set_marked_for_tier_up(false); - Handle cached_code; // TODO(4764): When compiling for OSR from bytecode, BailoutId might derive // from bytecode offset and overlap with actual BailoutId. No lookup! @@ -928,6 +936,13 @@ MaybeHandle GetOptimizedCode(Handle function, return MaybeHandle(); } +MaybeHandle GetOptimizedCodeMaybeLater(Handle function) { + Isolate* isolate = function->GetIsolate(); + return GetOptimizedCode(function, isolate->concurrent_recompilation_enabled() + ? Compiler::CONCURRENT + : Compiler::NOT_CONCURRENT); +} + CompilationJob::Status FinalizeOptimizedCompilationJob(CompilationJob* job) { CompilationInfo* info = job->info(); Isolate* isolate = info->isolate(); @@ -947,6 +962,11 @@ CompilationJob::Status FinalizeOptimizedCompilationJob(CompilationJob* job) { shared->set_profiler_ticks(0); } + shared->set_has_concurrent_optimization_job(false); + + // Shared function no longer needs to be tiered up. + shared->set_marked_for_tier_up(false); + DCHECK(!shared->HasDebugInfo()); // 1) Optimization on the concurrent thread may have failed. @@ -1094,9 +1114,7 @@ MaybeHandle GetLazyCode(Handle function) { } Handle code; - // TODO(leszeks): Look into performing this compilation concurrently. - if (GetOptimizedCode(function, Compiler::NOT_CONCURRENT) - .ToHandle(&code)) { + if (GetOptimizedCodeMaybeLater(function).ToHandle(&code)) { return code; } break; diff --git a/deps/v8/src/compiler/OWNERS b/deps/v8/src/compiler/OWNERS index d1c0f9adb91284..8704f92bc8cdc0 100644 --- a/deps/v8/src/compiler/OWNERS +++ b/deps/v8/src/compiler/OWNERS @@ -7,6 +7,7 @@ mstarzinger@chromium.org mtrofin@chromium.org titzer@chromium.org danno@chromium.org +tebbi@chromium.org per-file wasm-*=ahaas@chromium.org per-file wasm-*=clemensh@chromium.org diff --git a/deps/v8/src/compiler/types.cc b/deps/v8/src/compiler/types.cc index f28a56a43bb081..7536acea0ad16b 100644 --- a/deps/v8/src/compiler/types.cc +++ b/deps/v8/src/compiler/types.cc @@ -181,7 +181,6 @@ Type::bitset BitsetType::Lub(i::Map* map) { if (map == heap->boolean_map()) return kBoolean; if (map == heap->the_hole_map()) return kHole; DCHECK(map == heap->uninitialized_map() || - map == heap->no_interceptor_result_sentinel_map() || map == heap->termination_exception_map() || map == heap->arguments_marker_map() || map == heap->optimized_out_map() || diff --git a/deps/v8/src/compiler/wasm-compiler.cc b/deps/v8/src/compiler/wasm-compiler.cc index e275b532edd7a5..04cad936457f0d 100644 --- a/deps/v8/src/compiler/wasm-compiler.cc +++ b/deps/v8/src/compiler/wasm-compiler.cc @@ -4099,13 +4099,6 @@ SourcePositionTable* WasmCompilationUnit::BuildGraphForWasmFunction( func_index_ < FLAG_trace_wasm_ast_end) { PrintRawWasmCode(isolate_->allocator(), func_body_, module_env_->module); } - // TODO(clemens): Remove the trace_wasm_text_start flag. - // if (func_index_ >= FLAG_trace_wasm_text_start && func_index_ < - // FLAG_trace_wasm_text_end) { - // OFStream os(stdout); - // PrintWasmText(module_env_.module, module_env_->wire_bytes, - // function_->func_index, os, nullptr); - //} if (FLAG_trace_wasm_decode_time) { *decode_ms = decode_timer.Elapsed().InMillisecondsF(); } diff --git a/deps/v8/src/counters.h b/deps/v8/src/counters.h index 6ca923aa03235b..a0a30d5d4c17ba 100644 --- a/deps/v8/src/counters.h +++ b/deps/v8/src/counters.h @@ -786,7 +786,9 @@ class RuntimeCallTimer final { V(LoadIC_LoadFieldFromPrototypeDH) \ V(LoadIC_LoadField) \ V(LoadIC_LoadGlobal) \ - V(LoadIC_LoadInterceptor) \ + V(LoadIC_LoadInterceptorDH) \ + V(LoadIC_LoadNonMaskingInterceptorDH) \ + V(LoadIC_LoadInterceptorFromPrototypeDH) \ V(LoadIC_LoadNonexistentDH) \ V(LoadIC_LoadNonexistent) \ V(LoadIC_LoadNormalDH) \ diff --git a/deps/v8/src/crankshaft/arm/lithium-arm.cc b/deps/v8/src/crankshaft/arm/lithium-arm.cc index 2c0392f0c0efeb..e743e5dfb0f6d9 100644 --- a/deps/v8/src/crankshaft/arm/lithium-arm.cc +++ b/deps/v8/src/crankshaft/arm/lithium-arm.cc @@ -206,16 +206,6 @@ void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) { stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } -void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) { - stream->Add("if class_of_test("); - value()->PrintTo(stream); - stream->Add(", \"%o\") then B%d else B%d", - *hydrogen()->class_name(), - true_block_id(), - false_block_id()); -} - - void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if typeof "); value()->PrintTo(stream); @@ -1718,14 +1708,6 @@ LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch( return new(zone()) LHasInstanceTypeAndBranch(value); } -LInstruction* LChunkBuilder::DoClassOfTestAndBranch( - HClassOfTestAndBranch* instr) { - DCHECK(instr->value()->representation().IsTagged()); - LOperand* value = UseRegister(instr->value()); - return new(zone()) LClassOfTestAndBranch(value, TempRegister()); -} - - LInstruction* LChunkBuilder::DoSeqStringGetChar(HSeqStringGetChar* instr) { LOperand* string = UseRegisterAtStart(instr->string()); LOperand* index = UseRegisterOrConstantAtStart(instr->index()); diff --git a/deps/v8/src/crankshaft/arm/lithium-arm.h b/deps/v8/src/crankshaft/arm/lithium-arm.h index 0d066c97aa1cad..beac34c1216f59 100644 --- a/deps/v8/src/crankshaft/arm/lithium-arm.h +++ b/deps/v8/src/crankshaft/arm/lithium-arm.h @@ -42,7 +42,6 @@ class LCodeGen; V(ClampDToUint8) \ V(ClampIToUint8) \ V(ClampTToUint8) \ - V(ClassOfTestAndBranch) \ V(CompareNumericAndBranch) \ V(CmpObjectEqAndBranch) \ V(CmpHoleAndBranch) \ @@ -1066,24 +1065,6 @@ class LHasInstanceTypeAndBranch final : public LControlInstruction<1, 0> { }; -class LClassOfTestAndBranch final : public LControlInstruction<1, 1> { - public: - LClassOfTestAndBranch(LOperand* value, LOperand* temp) { - inputs_[0] = value; - temps_[0] = temp; - } - - LOperand* value() { return inputs_[0]; } - LOperand* temp() { return temps_[0]; } - - DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch, - "class-of-test-and-branch") - DECLARE_HYDROGEN_ACCESSOR(ClassOfTestAndBranch) - - void PrintDataTo(StringStream* stream) override; -}; - - class LCmpT final : public LTemplateInstruction<1, 3, 0> { public: LCmpT(LOperand* context, LOperand* left, LOperand* right) { diff --git a/deps/v8/src/crankshaft/arm/lithium-codegen-arm.cc b/deps/v8/src/crankshaft/arm/lithium-codegen-arm.cc index 245c5fced472d2..0bdd70574ff480 100644 --- a/deps/v8/src/crankshaft/arm/lithium-codegen-arm.cc +++ b/deps/v8/src/crankshaft/arm/lithium-codegen-arm.cc @@ -2391,69 +2391,6 @@ void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { EmitBranch(instr, BranchCondition(instr->hydrogen())); } -// Branches to a label or falls through with the answer in flags. Trashes -// the temp registers, but not the input. -void LCodeGen::EmitClassOfTest(Label* is_true, - Label* is_false, - Handleclass_name, - Register input, - Register temp, - Register temp2) { - DCHECK(!input.is(temp)); - DCHECK(!input.is(temp2)); - DCHECK(!temp.is(temp2)); - - __ JumpIfSmi(input, is_false); - - __ CompareObjectType(input, temp, temp2, FIRST_FUNCTION_TYPE); - STATIC_ASSERT(LAST_FUNCTION_TYPE == LAST_TYPE); - if (String::Equals(isolate()->factory()->Function_string(), class_name)) { - __ b(hs, is_true); - } else { - __ b(hs, is_false); - } - - // Check if the constructor in the map is a function. - Register instance_type = ip; - __ GetMapConstructor(temp, temp, temp2, instance_type); - - // Objects with a non-function constructor have class 'Object'. - __ cmp(instance_type, Operand(JS_FUNCTION_TYPE)); - if (String::Equals(isolate()->factory()->Object_string(), class_name)) { - __ b(ne, is_true); - } else { - __ b(ne, is_false); - } - - // temp now contains the constructor function. Grab the - // instance class name from there. - __ ldr(temp, FieldMemOperand(temp, JSFunction::kSharedFunctionInfoOffset)); - __ ldr(temp, FieldMemOperand(temp, - SharedFunctionInfo::kInstanceClassNameOffset)); - // The class name we are testing against is internalized since it's a literal. - // The name in the constructor is internalized because of the way the context - // is booted. This routine isn't expected to work for random API-created - // classes and it doesn't have to because you can't access it with natives - // syntax. Since both sides are internalized it is sufficient to use an - // identity comparison. - __ cmp(temp, Operand(class_name)); - // End with the answer in flags. -} - - -void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { - Register input = ToRegister(instr->value()); - Register temp = scratch0(); - Register temp2 = ToRegister(instr->temp()); - Handle class_name = instr->hydrogen()->class_name(); - - EmitClassOfTest(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_), - class_name, input, temp, temp2); - - EmitBranch(instr, eq); -} - - void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { Register reg = ToRegister(instr->value()); Register temp = ToRegister(instr->temp()); diff --git a/deps/v8/src/crankshaft/arm/lithium-codegen-arm.h b/deps/v8/src/crankshaft/arm/lithium-codegen-arm.h index 26b7fb50a81d54..00850484094894 100644 --- a/deps/v8/src/crankshaft/arm/lithium-codegen-arm.h +++ b/deps/v8/src/crankshaft/arm/lithium-codegen-arm.h @@ -142,13 +142,6 @@ class LCodeGen: public LCodeGenBase { LInstruction* GetNextInstruction(); - void EmitClassOfTest(Label* if_true, - Label* if_false, - Handle class_name, - Register input, - Register temporary, - Register temporary2); - bool HasAllocatedStackSlots() const { return chunk()->HasAllocatedStackSlots(); } diff --git a/deps/v8/src/crankshaft/arm64/lithium-arm64.cc b/deps/v8/src/crankshaft/arm64/lithium-arm64.cc index e5227e301f16fd..8db73f14d3edf3 100644 --- a/deps/v8/src/crankshaft/arm64/lithium-arm64.cc +++ b/deps/v8/src/crankshaft/arm64/lithium-arm64.cc @@ -84,16 +84,6 @@ void LCallNewArray::PrintDataTo(StringStream* stream) { } -void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) { - stream->Add("if class_of_test("); - value()->PrintTo(stream); - stream->Add(", \"%o\") then B%d else B%d", - *hydrogen()->class_name(), - true_block_id(), - false_block_id()); -} - - void LCompareNumericAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if "); left()->PrintTo(stream); @@ -1191,16 +1181,6 @@ LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) { } -LInstruction* LChunkBuilder::DoClassOfTestAndBranch( - HClassOfTestAndBranch* instr) { - DCHECK(instr->value()->representation().IsTagged()); - LOperand* value = UseRegisterAtStart(instr->value()); - return new(zone()) LClassOfTestAndBranch(value, - TempRegister(), - TempRegister()); -} - - LInstruction* LChunkBuilder::DoCompareNumericAndBranch( HCompareNumericAndBranch* instr) { Representation r = instr->representation(); diff --git a/deps/v8/src/crankshaft/arm64/lithium-arm64.h b/deps/v8/src/crankshaft/arm64/lithium-arm64.h index a9d85e5a3e0302..5020975cf2e61d 100644 --- a/deps/v8/src/crankshaft/arm64/lithium-arm64.h +++ b/deps/v8/src/crankshaft/arm64/lithium-arm64.h @@ -45,7 +45,6 @@ class LCodeGen; V(ClampDToUint8) \ V(ClampIToUint8) \ V(ClampTToUint8) \ - V(ClassOfTestAndBranch) \ V(CmpHoleAndBranchD) \ V(CmpHoleAndBranchT) \ V(CmpMapAndBranch) \ @@ -973,26 +972,6 @@ class LClampTToUint8 final : public LTemplateInstruction<1, 1, 1> { }; -class LClassOfTestAndBranch final : public LControlInstruction<1, 2> { - public: - LClassOfTestAndBranch(LOperand* value, LOperand* temp1, LOperand* temp2) { - inputs_[0] = value; - temps_[0] = temp1; - temps_[1] = temp2; - } - - LOperand* value() { return inputs_[0]; } - LOperand* temp1() { return temps_[0]; } - LOperand* temp2() { return temps_[1]; } - - DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch, - "class-of-test-and-branch") - DECLARE_HYDROGEN_ACCESSOR(ClassOfTestAndBranch) - - void PrintDataTo(StringStream* stream) override; -}; - - class LCmpHoleAndBranchD final : public LControlInstruction<1, 1> { public: explicit LCmpHoleAndBranchD(LOperand* object, LOperand* temp) { diff --git a/deps/v8/src/crankshaft/arm64/lithium-codegen-arm64.cc b/deps/v8/src/crankshaft/arm64/lithium-codegen-arm64.cc index 81529244209a36..da9ea784517dce 100644 --- a/deps/v8/src/crankshaft/arm64/lithium-codegen-arm64.cc +++ b/deps/v8/src/crankshaft/arm64/lithium-codegen-arm64.cc @@ -2229,56 +2229,6 @@ void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) { } -void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { - Handle class_name = instr->hydrogen()->class_name(); - Label* true_label = instr->TrueLabel(chunk_); - Label* false_label = instr->FalseLabel(chunk_); - Register input = ToRegister(instr->value()); - Register scratch1 = ToRegister(instr->temp1()); - Register scratch2 = ToRegister(instr->temp2()); - - __ JumpIfSmi(input, false_label); - - Register map = scratch2; - __ CompareObjectType(input, map, scratch1, FIRST_FUNCTION_TYPE); - STATIC_ASSERT(LAST_FUNCTION_TYPE == LAST_TYPE); - if (String::Equals(isolate()->factory()->Function_string(), class_name)) { - __ B(hs, true_label); - } else { - __ B(hs, false_label); - } - - // Check if the constructor in the map is a function. - { - UseScratchRegisterScope temps(masm()); - Register instance_type = temps.AcquireX(); - __ GetMapConstructor(scratch1, map, scratch2, instance_type); - __ Cmp(instance_type, JS_FUNCTION_TYPE); - } - // Objects with a non-function constructor have class 'Object'. - if (String::Equals(class_name, isolate()->factory()->Object_string())) { - __ B(ne, true_label); - } else { - __ B(ne, false_label); - } - - // The constructor function is in scratch1. Get its instance class name. - __ Ldr(scratch1, - FieldMemOperand(scratch1, JSFunction::kSharedFunctionInfoOffset)); - __ Ldr(scratch1, - FieldMemOperand(scratch1, - SharedFunctionInfo::kInstanceClassNameOffset)); - - // The class name we are testing against is internalized since it's a literal. - // The name in the constructor is internalized because of the way the context - // is booted. This routine isn't expected to work for random API-created - // classes and it doesn't have to because you can't access it with natives - // syntax. Since both sides are internalized it is sufficient to use an - // identity comparison. - EmitCompareAndBranch(instr, eq, scratch1, Operand(class_name)); -} - - void LCodeGen::DoCmpHoleAndBranchD(LCmpHoleAndBranchD* instr) { DCHECK(instr->hydrogen()->representation().IsDouble()); FPRegister object = ToDoubleRegister(instr->object()); diff --git a/deps/v8/src/crankshaft/hydrogen-instructions.cc b/deps/v8/src/crankshaft/hydrogen-instructions.cc index 8cf49201d054ed..c12f45a4a461f0 100644 --- a/deps/v8/src/crankshaft/hydrogen-instructions.cc +++ b/deps/v8/src/crankshaft/hydrogen-instructions.cc @@ -811,7 +811,6 @@ bool HInstruction::CanDeoptimize() { case HValue::kBlockEntry: case HValue::kCallNewArray: case HValue::kCapturedObject: - case HValue::kClassOfTestAndBranch: case HValue::kCompareGeneric: case HValue::kCompareHoleAndBranch: case HValue::kCompareMap: @@ -1027,13 +1026,6 @@ std::ostream& HCallRuntime::PrintDataTo(std::ostream& os) const { // NOLINT } -std::ostream& HClassOfTestAndBranch::PrintDataTo( - std::ostream& os) const { // NOLINT - return os << "class_of_test(" << NameOf(value()) << ", \"" - << class_name()->ToCString().get() << "\")"; -} - - std::ostream& HWrapReceiver::PrintDataTo(std::ostream& os) const { // NOLINT return os << NameOf(receiver()) << " " << NameOf(function()); } diff --git a/deps/v8/src/crankshaft/hydrogen-instructions.h b/deps/v8/src/crankshaft/hydrogen-instructions.h index 7059425cb04097..8d236293b59d25 100644 --- a/deps/v8/src/crankshaft/hydrogen-instructions.h +++ b/deps/v8/src/crankshaft/hydrogen-instructions.h @@ -73,7 +73,6 @@ class SmallMapList; V(CheckSmi) \ V(CheckValue) \ V(ClampToUint8) \ - V(ClassOfTestAndBranch) \ V(CompareNumericAndBranch) \ V(CompareHoleAndBranch) \ V(CompareGeneric) \ @@ -4011,30 +4010,6 @@ class HHasInstanceTypeAndBranch final : public HUnaryControlInstruction { InstanceType to_; // Inclusive range, not all combinations work. }; -class HClassOfTestAndBranch final : public HUnaryControlInstruction { - public: - DECLARE_INSTRUCTION_FACTORY_P2(HClassOfTestAndBranch, HValue*, - Handle); - - DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch) - - Representation RequiredInputRepresentation(int index) override { - return Representation::Tagged(); - } - - std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT - - Handle class_name() const { return class_name_; } - - private: - HClassOfTestAndBranch(HValue* value, Handle class_name) - : HUnaryControlInstruction(value, NULL, NULL), - class_name_(class_name) { } - - Handle class_name_; -}; - - class HTypeofIsAndBranch final : public HUnaryControlInstruction { public: DECLARE_INSTRUCTION_FACTORY_P2(HTypeofIsAndBranch, HValue*, Handle); diff --git a/deps/v8/src/crankshaft/hydrogen.cc b/deps/v8/src/crankshaft/hydrogen.cc index 96798249f6d731..a806d8f9b6bf8e 100644 --- a/deps/v8/src/crankshaft/hydrogen.cc +++ b/deps/v8/src/crankshaft/hydrogen.cc @@ -11023,20 +11023,6 @@ HValue* HGraphBuilder::BuildBinaryOperation( } -// Check for the form (%_ClassOf(foo) === 'BarClass'). -static bool IsClassOfTest(CompareOperation* expr) { - if (expr->op() != Token::EQ_STRICT) return false; - CallRuntime* call = expr->left()->AsCallRuntime(); - if (call == NULL) return false; - Literal* literal = expr->right()->AsLiteral(); - if (literal == NULL) return false; - if (!literal->value()->IsString()) return false; - if (call->is_jsruntime()) return false; - if (call->function()->function_id != Runtime::kInlineClassOf) return false; - DCHECK_EQ(call->arguments()->length(), 1); - return true; -} - void HOptimizedGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { DCHECK(!HasStackOverflow()); DCHECK(current_block() != NULL); @@ -11225,17 +11211,6 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) { return HandleLiteralCompareNil(expr, sub_expr, kNullValue); } - if (IsClassOfTest(expr)) { - CallRuntime* call = expr->left()->AsCallRuntime(); - DCHECK(call->arguments()->length() == 1); - CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); - HValue* value = Pop(); - Literal* literal = expr->right()->AsLiteral(); - Handle rhs = Handle::cast(literal->value()); - HClassOfTestAndBranch* instr = New(value, rhs); - return ast_context()->ReturnControl(instr, expr->id()); - } - AstType* left_type = bounds_.get(expr->left()).lower; AstType* right_type = bounds_.get(expr->right()).lower; AstType* combined_type = expr->combined_type(); diff --git a/deps/v8/src/crankshaft/ia32/lithium-codegen-ia32.cc b/deps/v8/src/crankshaft/ia32/lithium-codegen-ia32.cc index d5b87492c5b0aa..5674b7305ad0f9 100644 --- a/deps/v8/src/crankshaft/ia32/lithium-codegen-ia32.cc +++ b/deps/v8/src/crankshaft/ia32/lithium-codegen-ia32.cc @@ -2188,67 +2188,6 @@ void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { EmitBranch(instr, BranchCondition(instr->hydrogen())); } -// Branches to a label or falls through with the answer in the z flag. Trashes -// the temp registers, but not the input. -void LCodeGen::EmitClassOfTest(Label* is_true, - Label* is_false, - Handleclass_name, - Register input, - Register temp, - Register temp2) { - DCHECK(!input.is(temp)); - DCHECK(!input.is(temp2)); - DCHECK(!temp.is(temp2)); - __ JumpIfSmi(input, is_false); - - __ CmpObjectType(input, FIRST_FUNCTION_TYPE, temp); - STATIC_ASSERT(LAST_FUNCTION_TYPE == LAST_TYPE); - if (String::Equals(isolate()->factory()->Function_string(), class_name)) { - __ j(above_equal, is_true); - } else { - __ j(above_equal, is_false); - } - - // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range. - // Check if the constructor in the map is a function. - __ GetMapConstructor(temp, temp, temp2); - // Objects with a non-function constructor have class 'Object'. - __ CmpInstanceType(temp2, JS_FUNCTION_TYPE); - if (String::Equals(class_name, isolate()->factory()->Object_string())) { - __ j(not_equal, is_true); - } else { - __ j(not_equal, is_false); - } - - // temp now contains the constructor function. Grab the - // instance class name from there. - __ mov(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset)); - __ mov(temp, FieldOperand(temp, - SharedFunctionInfo::kInstanceClassNameOffset)); - // The class name we are testing against is internalized since it's a literal. - // The name in the constructor is internalized because of the way the context - // is booted. This routine isn't expected to work for random API-created - // classes and it doesn't have to because you can't access it with natives - // syntax. Since both sides are internalized it is sufficient to use an - // identity comparison. - __ cmp(temp, class_name); - // End with the answer in the z flag. -} - - -void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { - Register input = ToRegister(instr->value()); - Register temp = ToRegister(instr->temp()); - Register temp2 = ToRegister(instr->temp2()); - - Handle class_name = instr->hydrogen()->class_name(); - - EmitClassOfTest(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_), - class_name, input, temp, temp2); - - EmitBranch(instr, equal); -} - void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { Register reg = ToRegister(instr->value()); diff --git a/deps/v8/src/crankshaft/ia32/lithium-codegen-ia32.h b/deps/v8/src/crankshaft/ia32/lithium-codegen-ia32.h index 8e16d9c5fcb217..cdc28695dc33c7 100644 --- a/deps/v8/src/crankshaft/ia32/lithium-codegen-ia32.h +++ b/deps/v8/src/crankshaft/ia32/lithium-codegen-ia32.h @@ -119,13 +119,6 @@ class LCodeGen: public LCodeGenBase { XMMRegister double_scratch0() const { return xmm0; } - void EmitClassOfTest(Label* if_true, - Label* if_false, - Handle class_name, - Register input, - Register temporary, - Register temporary2); - bool HasAllocatedStackSlots() const { return chunk()->HasAllocatedStackSlots(); } diff --git a/deps/v8/src/crankshaft/ia32/lithium-ia32.cc b/deps/v8/src/crankshaft/ia32/lithium-ia32.cc index 7272a9112face1..05083ee79f89e3 100644 --- a/deps/v8/src/crankshaft/ia32/lithium-ia32.cc +++ b/deps/v8/src/crankshaft/ia32/lithium-ia32.cc @@ -224,16 +224,6 @@ void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) { stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } -void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) { - stream->Add("if class_of_test("); - value()->PrintTo(stream); - stream->Add(", \"%o\") then B%d else B%d", - *hydrogen()->class_name(), - true_block_id(), - false_block_id()); -} - - void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if typeof "); value()->PrintTo(stream); @@ -1694,15 +1684,6 @@ LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch( TempRegister()); } -LInstruction* LChunkBuilder::DoClassOfTestAndBranch( - HClassOfTestAndBranch* instr) { - DCHECK(instr->value()->representation().IsTagged()); - return new(zone()) LClassOfTestAndBranch(UseRegister(instr->value()), - TempRegister(), - TempRegister()); -} - - LInstruction* LChunkBuilder::DoSeqStringGetChar(HSeqStringGetChar* instr) { LOperand* string = UseRegisterAtStart(instr->string()); LOperand* index = UseRegisterOrConstantAtStart(instr->index()); diff --git a/deps/v8/src/crankshaft/ia32/lithium-ia32.h b/deps/v8/src/crankshaft/ia32/lithium-ia32.h index 13ad4bd1a358bb..322dc1512d98cd 100644 --- a/deps/v8/src/crankshaft/ia32/lithium-ia32.h +++ b/deps/v8/src/crankshaft/ia32/lithium-ia32.h @@ -46,7 +46,6 @@ class LCodeGen; V(ClampDToUint8) \ V(ClampIToUint8) \ V(ClampTToUint8) \ - V(ClassOfTestAndBranch) \ V(CompareNumericAndBranch) \ V(CmpObjectEqAndBranch) \ V(CmpHoleAndBranch) \ @@ -1075,26 +1074,6 @@ class LHasInstanceTypeAndBranch final : public LControlInstruction<1, 1> { void PrintDataTo(StringStream* stream) override; }; -class LClassOfTestAndBranch final : public LControlInstruction<1, 2> { - public: - LClassOfTestAndBranch(LOperand* value, LOperand* temp, LOperand* temp2) { - inputs_[0] = value; - temps_[0] = temp; - temps_[1] = temp2; - } - - LOperand* value() { return inputs_[0]; } - LOperand* temp() { return temps_[0]; } - LOperand* temp2() { return temps_[1]; } - - DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch, - "class-of-test-and-branch") - DECLARE_HYDROGEN_ACCESSOR(ClassOfTestAndBranch) - - void PrintDataTo(StringStream* stream) override; -}; - - class LCmpT final : public LTemplateInstruction<1, 3, 0> { public: LCmpT(LOperand* context, LOperand* left, LOperand* right) { diff --git a/deps/v8/src/crankshaft/mips/lithium-codegen-mips.cc b/deps/v8/src/crankshaft/mips/lithium-codegen-mips.cc index cd6e45af85da8d..2ec4e53f122cae 100644 --- a/deps/v8/src/crankshaft/mips/lithium-codegen-mips.cc +++ b/deps/v8/src/crankshaft/mips/lithium-codegen-mips.cc @@ -2299,68 +2299,6 @@ void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { Operand(TestType(instr->hydrogen()))); } -// Branches to a label or falls through with the answer in flags. Trashes -// the temp registers, but not the input. -void LCodeGen::EmitClassOfTest(Label* is_true, - Label* is_false, - Handleclass_name, - Register input, - Register temp, - Register temp2) { - DCHECK(!input.is(temp)); - DCHECK(!input.is(temp2)); - DCHECK(!temp.is(temp2)); - - __ JumpIfSmi(input, is_false); - __ GetObjectType(input, temp, temp2); - STATIC_ASSERT(LAST_FUNCTION_TYPE == LAST_TYPE); - if (String::Equals(isolate()->factory()->Function_string(), class_name)) { - __ Branch(is_true, hs, temp2, Operand(FIRST_FUNCTION_TYPE)); - } else { - __ Branch(is_false, hs, temp2, Operand(FIRST_FUNCTION_TYPE)); - } - - // Check if the constructor in the map is a function. - Register instance_type = scratch1(); - DCHECK(!instance_type.is(temp)); - __ GetMapConstructor(temp, temp, temp2, instance_type); - - // Objects with a non-function constructor have class 'Object'. - if (String::Equals(class_name, isolate()->factory()->Object_string())) { - __ Branch(is_true, ne, instance_type, Operand(JS_FUNCTION_TYPE)); - } else { - __ Branch(is_false, ne, instance_type, Operand(JS_FUNCTION_TYPE)); - } - - // temp now contains the constructor function. Grab the - // instance class name from there. - __ lw(temp, FieldMemOperand(temp, JSFunction::kSharedFunctionInfoOffset)); - __ lw(temp, FieldMemOperand(temp, - SharedFunctionInfo::kInstanceClassNameOffset)); - // The class name we are testing against is internalized since it's a literal. - // The name in the constructor is internalized because of the way the context - // is booted. This routine isn't expected to work for random API-created - // classes and it doesn't have to because you can't access it with natives - // syntax. Since both sides are internalized it is sufficient to use an - // identity comparison. - - // End with the address of this class_name instance in temp register. - // On MIPS, the caller must do the comparison with Handleclass_name. -} - - -void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { - Register input = ToRegister(instr->value()); - Register temp = scratch0(); - Register temp2 = ToRegister(instr->temp()); - Handle class_name = instr->hydrogen()->class_name(); - - EmitClassOfTest(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_), - class_name, input, temp, temp2); - - EmitBranch(instr, eq, temp, Operand(class_name)); -} - void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { Register reg = ToRegister(instr->value()); diff --git a/deps/v8/src/crankshaft/mips/lithium-codegen-mips.h b/deps/v8/src/crankshaft/mips/lithium-codegen-mips.h index 28ca01cd71d815..7bd7d5b30dbcb1 100644 --- a/deps/v8/src/crankshaft/mips/lithium-codegen-mips.h +++ b/deps/v8/src/crankshaft/mips/lithium-codegen-mips.h @@ -142,13 +142,6 @@ class LCodeGen: public LCodeGenBase { LInstruction* GetNextInstruction(); - void EmitClassOfTest(Label* if_true, - Label* if_false, - Handle class_name, - Register input, - Register temporary, - Register temporary2); - bool HasAllocatedStackSlots() const { return chunk()->HasAllocatedStackSlots(); } diff --git a/deps/v8/src/crankshaft/mips/lithium-mips.cc b/deps/v8/src/crankshaft/mips/lithium-mips.cc index 26d422a710b356..e1403a89e85907 100644 --- a/deps/v8/src/crankshaft/mips/lithium-mips.cc +++ b/deps/v8/src/crankshaft/mips/lithium-mips.cc @@ -212,16 +212,6 @@ void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) { stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } -void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) { - stream->Add("if class_of_test("); - value()->PrintTo(stream); - stream->Add(", \"%o\") then B%d else B%d", - *hydrogen()->class_name(), - true_block_id(), - false_block_id()); -} - - void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if typeof "); value()->PrintTo(stream); @@ -1664,14 +1654,6 @@ LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch( return new(zone()) LHasInstanceTypeAndBranch(value); } -LInstruction* LChunkBuilder::DoClassOfTestAndBranch( - HClassOfTestAndBranch* instr) { - DCHECK(instr->value()->representation().IsTagged()); - return new(zone()) LClassOfTestAndBranch(UseRegister(instr->value()), - TempRegister()); -} - - LInstruction* LChunkBuilder::DoSeqStringGetChar(HSeqStringGetChar* instr) { LOperand* string = UseRegisterAtStart(instr->string()); LOperand* index = UseRegisterOrConstantAtStart(instr->index()); diff --git a/deps/v8/src/crankshaft/mips/lithium-mips.h b/deps/v8/src/crankshaft/mips/lithium-mips.h index 209987b0121129..dd9bcf352aae81 100644 --- a/deps/v8/src/crankshaft/mips/lithium-mips.h +++ b/deps/v8/src/crankshaft/mips/lithium-mips.h @@ -42,7 +42,6 @@ class LCodeGen; V(ClampDToUint8) \ V(ClampIToUint8) \ V(ClampTToUint8) \ - V(ClassOfTestAndBranch) \ V(CompareNumericAndBranch) \ V(CmpObjectEqAndBranch) \ V(CmpHoleAndBranch) \ @@ -1044,24 +1043,6 @@ class LHasInstanceTypeAndBranch final : public LControlInstruction<1, 0> { void PrintDataTo(StringStream* stream) override; }; -class LClassOfTestAndBranch final : public LControlInstruction<1, 1> { - public: - LClassOfTestAndBranch(LOperand* value, LOperand* temp) { - inputs_[0] = value; - temps_[0] = temp; - } - - LOperand* value() { return inputs_[0]; } - LOperand* temp() { return temps_[0]; } - - DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch, - "class-of-test-and-branch") - DECLARE_HYDROGEN_ACCESSOR(ClassOfTestAndBranch) - - void PrintDataTo(StringStream* stream) override; -}; - - class LCmpT final : public LTemplateInstruction<1, 3, 0> { public: LCmpT(LOperand* context, LOperand* left, LOperand* right) { diff --git a/deps/v8/src/crankshaft/mips64/lithium-codegen-mips64.cc b/deps/v8/src/crankshaft/mips64/lithium-codegen-mips64.cc index d32052c5e75765..f244a17828122d 100644 --- a/deps/v8/src/crankshaft/mips64/lithium-codegen-mips64.cc +++ b/deps/v8/src/crankshaft/mips64/lithium-codegen-mips64.cc @@ -2420,71 +2420,6 @@ void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { Operand(TestType(instr->hydrogen()))); } -// Branches to a label or falls through with the answer in flags. Trashes -// the temp registers, but not the input. -void LCodeGen::EmitClassOfTest(Label* is_true, - Label* is_false, - Handleclass_name, - Register input, - Register temp, - Register temp2) { - DCHECK(!input.is(temp)); - DCHECK(!input.is(temp2)); - DCHECK(!temp.is(temp2)); - - __ JumpIfSmi(input, is_false); - - __ GetObjectType(input, temp, temp2); - STATIC_ASSERT(LAST_FUNCTION_TYPE == LAST_TYPE); - if (String::Equals(isolate()->factory()->Function_string(), class_name)) { - __ Branch(is_true, hs, temp2, Operand(FIRST_FUNCTION_TYPE)); - } else { - __ Branch(is_false, hs, temp2, Operand(FIRST_FUNCTION_TYPE)); - } - - // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range. - // Check if the constructor in the map is a function. - Register instance_type = scratch1(); - DCHECK(!instance_type.is(temp)); - __ GetMapConstructor(temp, temp, temp2, instance_type); - - // Objects with a non-function constructor have class 'Object'. - if (String::Equals(class_name, isolate()->factory()->Object_string())) { - __ Branch(is_true, ne, instance_type, Operand(JS_FUNCTION_TYPE)); - } else { - __ Branch(is_false, ne, instance_type, Operand(JS_FUNCTION_TYPE)); - } - - // temp now contains the constructor function. Grab the - // instance class name from there. - __ ld(temp, FieldMemOperand(temp, JSFunction::kSharedFunctionInfoOffset)); - __ ld(temp, FieldMemOperand(temp, - SharedFunctionInfo::kInstanceClassNameOffset)); - // The class name we are testing against is internalized since it's a literal. - // The name in the constructor is internalized because of the way the context - // is booted. This routine isn't expected to work for random API-created - // classes and it doesn't have to because you can't access it with natives - // syntax. Since both sides are internalized it is sufficient to use an - // identity comparison. - - // End with the address of this class_name instance in temp register. - // On MIPS, the caller must do the comparison with Handleclass_name. -} - - -void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { - Register input = ToRegister(instr->value()); - Register temp = scratch0(); - Register temp2 = ToRegister(instr->temp()); - Handle class_name = instr->hydrogen()->class_name(); - - EmitClassOfTest(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_), - class_name, input, temp, temp2); - - EmitBranch(instr, eq, temp, Operand(class_name)); -} - - void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { Register reg = ToRegister(instr->value()); Register temp = ToRegister(instr->temp()); diff --git a/deps/v8/src/crankshaft/mips64/lithium-codegen-mips64.h b/deps/v8/src/crankshaft/mips64/lithium-codegen-mips64.h index ba332ae3605426..b5d18052918022 100644 --- a/deps/v8/src/crankshaft/mips64/lithium-codegen-mips64.h +++ b/deps/v8/src/crankshaft/mips64/lithium-codegen-mips64.h @@ -144,13 +144,6 @@ class LCodeGen: public LCodeGenBase { LInstruction* GetNextInstruction(); - void EmitClassOfTest(Label* if_true, - Label* if_false, - Handle class_name, - Register input, - Register temporary, - Register temporary2); - bool HasAllocatedStackSlots() const { return chunk()->HasAllocatedStackSlots(); } diff --git a/deps/v8/src/crankshaft/mips64/lithium-mips64.cc b/deps/v8/src/crankshaft/mips64/lithium-mips64.cc index fd0ebc82062917..80aca773452063 100644 --- a/deps/v8/src/crankshaft/mips64/lithium-mips64.cc +++ b/deps/v8/src/crankshaft/mips64/lithium-mips64.cc @@ -212,16 +212,6 @@ void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) { stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } -void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) { - stream->Add("if class_of_test("); - value()->PrintTo(stream); - stream->Add(", \"%o\") then B%d else B%d", - *hydrogen()->class_name(), - true_block_id(), - false_block_id()); -} - - void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if typeof "); value()->PrintTo(stream); @@ -1670,14 +1660,6 @@ LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch( return new(zone()) LHasInstanceTypeAndBranch(value); } -LInstruction* LChunkBuilder::DoClassOfTestAndBranch( - HClassOfTestAndBranch* instr) { - DCHECK(instr->value()->representation().IsTagged()); - return new(zone()) LClassOfTestAndBranch(UseRegister(instr->value()), - TempRegister()); -} - - LInstruction* LChunkBuilder::DoSeqStringGetChar(HSeqStringGetChar* instr) { LOperand* string = UseRegisterAtStart(instr->string()); LOperand* index = UseRegisterOrConstantAtStart(instr->index()); diff --git a/deps/v8/src/crankshaft/mips64/lithium-mips64.h b/deps/v8/src/crankshaft/mips64/lithium-mips64.h index f5b402a6368e46..64bae7783d4a10 100644 --- a/deps/v8/src/crankshaft/mips64/lithium-mips64.h +++ b/deps/v8/src/crankshaft/mips64/lithium-mips64.h @@ -44,7 +44,6 @@ class LCodeGen; V(ClampDToUint8) \ V(ClampIToUint8) \ V(ClampTToUint8) \ - V(ClassOfTestAndBranch) \ V(CompareNumericAndBranch) \ V(CmpObjectEqAndBranch) \ V(CmpHoleAndBranch) \ @@ -1062,23 +1061,6 @@ class LHasInstanceTypeAndBranch final : public LControlInstruction<1, 0> { void PrintDataTo(StringStream* stream) override; }; -class LClassOfTestAndBranch final : public LControlInstruction<1, 1> { - public: - LClassOfTestAndBranch(LOperand* value, LOperand* temp) { - inputs_[0] = value; - temps_[0] = temp; - } - - LOperand* value() { return inputs_[0]; } - LOperand* temp() { return temps_[0]; } - - DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch, - "class-of-test-and-branch") - DECLARE_HYDROGEN_ACCESSOR(ClassOfTestAndBranch) - - void PrintDataTo(StringStream* stream) override; -}; - class LCmpT final : public LTemplateInstruction<1, 3, 0> { public: diff --git a/deps/v8/src/crankshaft/ppc/lithium-codegen-ppc.cc b/deps/v8/src/crankshaft/ppc/lithium-codegen-ppc.cc index f930611b143e7c..7a729d3571de6c 100644 --- a/deps/v8/src/crankshaft/ppc/lithium-codegen-ppc.cc +++ b/deps/v8/src/crankshaft/ppc/lithium-codegen-ppc.cc @@ -2489,65 +2489,6 @@ void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { EmitBranch(instr, BranchCondition(instr->hydrogen())); } -// Branches to a label or falls through with the answer in flags. Trashes -// the temp registers, but not the input. -void LCodeGen::EmitClassOfTest(Label* is_true, Label* is_false, - Handle class_name, Register input, - Register temp, Register temp2) { - DCHECK(!input.is(temp)); - DCHECK(!input.is(temp2)); - DCHECK(!temp.is(temp2)); - - __ JumpIfSmi(input, is_false); - - __ CompareObjectType(input, temp, temp2, FIRST_FUNCTION_TYPE); - STATIC_ASSERT(LAST_FUNCTION_TYPE == LAST_TYPE); - if (String::Equals(isolate()->factory()->Function_string(), class_name)) { - __ bge(is_true); - } else { - __ bge(is_false); - } - - // Check if the constructor in the map is a function. - Register instance_type = ip; - __ GetMapConstructor(temp, temp, temp2, instance_type); - - // Objects with a non-function constructor have class 'Object'. - __ cmpi(instance_type, Operand(JS_FUNCTION_TYPE)); - if (String::Equals(isolate()->factory()->Object_string(), class_name)) { - __ bne(is_true); - } else { - __ bne(is_false); - } - - // temp now contains the constructor function. Grab the - // instance class name from there. - __ LoadP(temp, FieldMemOperand(temp, JSFunction::kSharedFunctionInfoOffset)); - __ LoadP(temp, - FieldMemOperand(temp, SharedFunctionInfo::kInstanceClassNameOffset)); - // The class name we are testing against is internalized since it's a literal. - // The name in the constructor is internalized because of the way the context - // is booted. This routine isn't expected to work for random API-created - // classes and it doesn't have to because you can't access it with natives - // syntax. Since both sides are internalized it is sufficient to use an - // identity comparison. - __ Cmpi(temp, Operand(class_name), r0); - // End with the answer in flags. -} - - -void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { - Register input = ToRegister(instr->value()); - Register temp = scratch0(); - Register temp2 = ToRegister(instr->temp()); - Handle class_name = instr->hydrogen()->class_name(); - - EmitClassOfTest(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_), - class_name, input, temp, temp2); - - EmitBranch(instr, eq); -} - void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { Register reg = ToRegister(instr->value()); diff --git a/deps/v8/src/crankshaft/ppc/lithium-codegen-ppc.h b/deps/v8/src/crankshaft/ppc/lithium-codegen-ppc.h index 32b9e1848735dc..72df5b4e9c4999 100644 --- a/deps/v8/src/crankshaft/ppc/lithium-codegen-ppc.h +++ b/deps/v8/src/crankshaft/ppc/lithium-codegen-ppc.h @@ -135,10 +135,6 @@ class LCodeGen : public LCodeGenBase { LInstruction* GetNextInstruction(); - void EmitClassOfTest(Label* if_true, Label* if_false, - Handle class_name, Register input, - Register temporary, Register temporary2); - bool HasAllocatedStackSlots() const { return chunk()->HasAllocatedStackSlots(); } diff --git a/deps/v8/src/crankshaft/ppc/lithium-ppc.cc b/deps/v8/src/crankshaft/ppc/lithium-ppc.cc index 75aec2f86dd4e8..c5169b5639457e 100644 --- a/deps/v8/src/crankshaft/ppc/lithium-ppc.cc +++ b/deps/v8/src/crankshaft/ppc/lithium-ppc.cc @@ -220,14 +220,6 @@ void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) { stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } -void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) { - stream->Add("if class_of_test("); - value()->PrintTo(stream); - stream->Add(", \"%o\") then B%d else B%d", *hydrogen()->class_name(), - true_block_id(), false_block_id()); -} - - void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if typeof "); value()->PrintTo(stream); @@ -1694,14 +1686,6 @@ LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch( return new (zone()) LHasInstanceTypeAndBranch(value); } -LInstruction* LChunkBuilder::DoClassOfTestAndBranch( - HClassOfTestAndBranch* instr) { - DCHECK(instr->value()->representation().IsTagged()); - LOperand* value = UseRegister(instr->value()); - return new (zone()) LClassOfTestAndBranch(value, TempRegister()); -} - - LInstruction* LChunkBuilder::DoSeqStringGetChar(HSeqStringGetChar* instr) { LOperand* string = UseRegisterAtStart(instr->string()); LOperand* index = UseRegisterOrConstantAtStart(instr->index()); diff --git a/deps/v8/src/crankshaft/ppc/lithium-ppc.h b/deps/v8/src/crankshaft/ppc/lithium-ppc.h index 4dda385cfe75fe..c3fac49a06ccab 100644 --- a/deps/v8/src/crankshaft/ppc/lithium-ppc.h +++ b/deps/v8/src/crankshaft/ppc/lithium-ppc.h @@ -42,7 +42,6 @@ class LCodeGen; V(ClampDToUint8) \ V(ClampIToUint8) \ V(ClampTToUint8) \ - V(ClassOfTestAndBranch) \ V(CompareNumericAndBranch) \ V(CmpObjectEqAndBranch) \ V(CmpHoleAndBranch) \ @@ -1053,23 +1052,6 @@ class LHasInstanceTypeAndBranch final : public LControlInstruction<1, 0> { void PrintDataTo(StringStream* stream) override; }; -class LClassOfTestAndBranch final : public LControlInstruction<1, 1> { - public: - LClassOfTestAndBranch(LOperand* value, LOperand* temp) { - inputs_[0] = value; - temps_[0] = temp; - } - - LOperand* value() { return inputs_[0]; } - LOperand* temp() { return temps_[0]; } - - DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch, "class-of-test-and-branch") - DECLARE_HYDROGEN_ACCESSOR(ClassOfTestAndBranch) - - void PrintDataTo(StringStream* stream) override; -}; - - class LCmpT final : public LTemplateInstruction<1, 3, 0> { public: LCmpT(LOperand* context, LOperand* left, LOperand* right) { diff --git a/deps/v8/src/crankshaft/s390/lithium-codegen-s390.cc b/deps/v8/src/crankshaft/s390/lithium-codegen-s390.cc index 02c6b6f7faef1b..3bfa78462b8fd7 100644 --- a/deps/v8/src/crankshaft/s390/lithium-codegen-s390.cc +++ b/deps/v8/src/crankshaft/s390/lithium-codegen-s390.cc @@ -2479,64 +2479,6 @@ void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { EmitBranch(instr, BranchCondition(instr->hydrogen())); } -// Branches to a label or falls through with the answer in flags. Trashes -// the temp registers, but not the input. -void LCodeGen::EmitClassOfTest(Label* is_true, Label* is_false, - Handle class_name, Register input, - Register temp, Register temp2) { - DCHECK(!input.is(temp)); - DCHECK(!input.is(temp2)); - DCHECK(!temp.is(temp2)); - - __ JumpIfSmi(input, is_false); - - __ CompareObjectType(input, temp, temp2, FIRST_FUNCTION_TYPE); - STATIC_ASSERT(LAST_FUNCTION_TYPE == LAST_TYPE); - if (String::Equals(isolate()->factory()->Function_string(), class_name)) { - __ bge(is_true); - } else { - __ bge(is_false); - } - - // Check if the constructor in the map is a function. - Register instance_type = ip; - __ GetMapConstructor(temp, temp, temp2, instance_type); - - // Objects with a non-function constructor have class 'Object'. - __ CmpP(instance_type, Operand(JS_FUNCTION_TYPE)); - if (String::Equals(isolate()->factory()->Object_string(), class_name)) { - __ bne(is_true); - } else { - __ bne(is_false); - } - - // temp now contains the constructor function. Grab the - // instance class name from there. - __ LoadP(temp, FieldMemOperand(temp, JSFunction::kSharedFunctionInfoOffset)); - __ LoadP(temp, - FieldMemOperand(temp, SharedFunctionInfo::kInstanceClassNameOffset)); - // The class name we are testing against is internalized since it's a literal. - // The name in the constructor is internalized because of the way the context - // is booted. This routine isn't expected to work for random API-created - // classes and it doesn't have to because you can't access it with natives - // syntax. Since both sides are internalized it is sufficient to use an - // identity comparison. - __ CmpP(temp, Operand(class_name)); - // End with the answer in flags. -} - -void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { - Register input = ToRegister(instr->value()); - Register temp = scratch0(); - Register temp2 = ToRegister(instr->temp()); - Handle class_name = instr->hydrogen()->class_name(); - - EmitClassOfTest(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_), - class_name, input, temp, temp2); - - EmitBranch(instr, eq); -} - void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { Register reg = ToRegister(instr->value()); Register temp = ToRegister(instr->temp()); diff --git a/deps/v8/src/crankshaft/s390/lithium-codegen-s390.h b/deps/v8/src/crankshaft/s390/lithium-codegen-s390.h index a8d59ff5b1387c..6a0a204d325a7a 100644 --- a/deps/v8/src/crankshaft/s390/lithium-codegen-s390.h +++ b/deps/v8/src/crankshaft/s390/lithium-codegen-s390.h @@ -135,10 +135,6 @@ class LCodeGen : public LCodeGenBase { LInstruction* GetNextInstruction(); - void EmitClassOfTest(Label* if_true, Label* if_false, - Handle class_name, Register input, - Register temporary, Register temporary2); - bool HasAllocatedStackSlots() const { return chunk()->HasAllocatedStackSlots(); } diff --git a/deps/v8/src/crankshaft/s390/lithium-s390.cc b/deps/v8/src/crankshaft/s390/lithium-s390.cc index 79868f5579d462..b768bc43812fe1 100644 --- a/deps/v8/src/crankshaft/s390/lithium-s390.cc +++ b/deps/v8/src/crankshaft/s390/lithium-s390.cc @@ -203,13 +203,6 @@ void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) { stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } -void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) { - stream->Add("if class_of_test("); - value()->PrintTo(stream); - stream->Add(", \"%o\") then B%d else B%d", *hydrogen()->class_name(), - true_block_id(), false_block_id()); -} - void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if typeof "); value()->PrintTo(stream); @@ -1527,13 +1520,6 @@ LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch( return new (zone()) LHasInstanceTypeAndBranch(value); } -LInstruction* LChunkBuilder::DoClassOfTestAndBranch( - HClassOfTestAndBranch* instr) { - DCHECK(instr->value()->representation().IsTagged()); - LOperand* value = UseRegister(instr->value()); - return new (zone()) LClassOfTestAndBranch(value, TempRegister()); -} - LInstruction* LChunkBuilder::DoSeqStringGetChar(HSeqStringGetChar* instr) { LOperand* string = UseRegisterAtStart(instr->string()); LOperand* index = UseRegisterOrConstantAtStart(instr->index()); diff --git a/deps/v8/src/crankshaft/s390/lithium-s390.h b/deps/v8/src/crankshaft/s390/lithium-s390.h index f9710b1092e507..bd3b32d9a071d4 100644 --- a/deps/v8/src/crankshaft/s390/lithium-s390.h +++ b/deps/v8/src/crankshaft/s390/lithium-s390.h @@ -42,7 +42,6 @@ class LCodeGen; V(ClampDToUint8) \ V(ClampIToUint8) \ V(ClampTToUint8) \ - V(ClassOfTestAndBranch) \ V(CompareNumericAndBranch) \ V(CmpObjectEqAndBranch) \ V(CmpHoleAndBranch) \ @@ -976,22 +975,6 @@ class LHasInstanceTypeAndBranch final : public LControlInstruction<1, 0> { void PrintDataTo(StringStream* stream) override; }; -class LClassOfTestAndBranch final : public LControlInstruction<1, 1> { - public: - LClassOfTestAndBranch(LOperand* value, LOperand* temp) { - inputs_[0] = value; - temps_[0] = temp; - } - - LOperand* value() { return inputs_[0]; } - LOperand* temp() { return temps_[0]; } - - DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch, "class-of-test-and-branch") - DECLARE_HYDROGEN_ACCESSOR(ClassOfTestAndBranch) - - void PrintDataTo(StringStream* stream) override; -}; - class LCmpT final : public LTemplateInstruction<1, 3, 0> { public: LCmpT(LOperand* context, LOperand* left, LOperand* right) { diff --git a/deps/v8/src/crankshaft/x64/lithium-codegen-x64.cc b/deps/v8/src/crankshaft/x64/lithium-codegen-x64.cc index 65816a1b6907b1..30a13e88cbba87 100644 --- a/deps/v8/src/crankshaft/x64/lithium-codegen-x64.cc +++ b/deps/v8/src/crankshaft/x64/lithium-codegen-x64.cc @@ -2335,69 +2335,6 @@ void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { EmitBranch(instr, BranchCondition(instr->hydrogen())); } -// Branches to a label or falls through with the answer in the z flag. -// Trashes the temp register. -void LCodeGen::EmitClassOfTest(Label* is_true, - Label* is_false, - Handle class_name, - Register input, - Register temp, - Register temp2) { - DCHECK(!input.is(temp)); - DCHECK(!input.is(temp2)); - DCHECK(!temp.is(temp2)); - - __ JumpIfSmi(input, is_false); - - __ CmpObjectType(input, FIRST_FUNCTION_TYPE, temp); - STATIC_ASSERT(LAST_FUNCTION_TYPE == LAST_TYPE); - if (String::Equals(isolate()->factory()->Function_string(), class_name)) { - __ j(above_equal, is_true); - } else { - __ j(above_equal, is_false); - } - - // Check if the constructor in the map is a function. - __ GetMapConstructor(temp, temp, kScratchRegister); - - // Objects with a non-function constructor have class 'Object'. - __ CmpInstanceType(kScratchRegister, JS_FUNCTION_TYPE); - if (String::Equals(class_name, isolate()->factory()->Object_string())) { - __ j(not_equal, is_true); - } else { - __ j(not_equal, is_false); - } - - // temp now contains the constructor function. Grab the - // instance class name from there. - __ movp(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset)); - __ movp(temp, FieldOperand(temp, - SharedFunctionInfo::kInstanceClassNameOffset)); - // The class name we are testing against is internalized since it's a literal. - // The name in the constructor is internalized because of the way the context - // is booted. This routine isn't expected to work for random API-created - // classes and it doesn't have to because you can't access it with natives - // syntax. Since both sides are internalized it is sufficient to use an - // identity comparison. - DCHECK(class_name->IsInternalizedString()); - __ Cmp(temp, class_name); - // End with the answer in the z flag. -} - - -void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { - Register input = ToRegister(instr->value()); - Register temp = ToRegister(instr->temp()); - Register temp2 = ToRegister(instr->temp2()); - Handle class_name = instr->hydrogen()->class_name(); - - EmitClassOfTest(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_), - class_name, input, temp, temp2); - - EmitBranch(instr, equal); -} - - void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { Register reg = ToRegister(instr->value()); diff --git a/deps/v8/src/crankshaft/x64/lithium-codegen-x64.h b/deps/v8/src/crankshaft/x64/lithium-codegen-x64.h index 22a32a147d4001..b9caccc49df098 100644 --- a/deps/v8/src/crankshaft/x64/lithium-codegen-x64.h +++ b/deps/v8/src/crankshaft/x64/lithium-codegen-x64.h @@ -117,13 +117,6 @@ class LCodeGen: public LCodeGenBase { XMMRegister double_scratch0() const { return kScratchDoubleReg; } - void EmitClassOfTest(Label* if_true, - Label* if_false, - Handle class_name, - Register input, - Register temporary, - Register scratch); - bool HasAllocatedStackSlots() const { return chunk()->HasAllocatedStackSlots(); } diff --git a/deps/v8/src/crankshaft/x64/lithium-x64.cc b/deps/v8/src/crankshaft/x64/lithium-x64.cc index d0671e9d41136d..62a66753468059 100644 --- a/deps/v8/src/crankshaft/x64/lithium-x64.cc +++ b/deps/v8/src/crankshaft/x64/lithium-x64.cc @@ -220,16 +220,6 @@ void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) { } -void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) { - stream->Add("if class_of_test("); - value()->PrintTo(stream); - stream->Add(", \"%o\") then B%d else B%d", - *hydrogen()->class_name(), - true_block_id(), - false_block_id()); -} - - void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if typeof "); value()->PrintTo(stream); @@ -1698,15 +1688,6 @@ LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch( return new(zone()) LHasInstanceTypeAndBranch(value); } -LInstruction* LChunkBuilder::DoClassOfTestAndBranch( - HClassOfTestAndBranch* instr) { - LOperand* value = UseRegister(instr->value()); - return new(zone()) LClassOfTestAndBranch(value, - TempRegister(), - TempRegister()); -} - - LInstruction* LChunkBuilder::DoSeqStringGetChar(HSeqStringGetChar* instr) { LOperand* string = UseRegisterAtStart(instr->string()); LOperand* index = UseRegisterOrConstantAtStart(instr->index()); diff --git a/deps/v8/src/crankshaft/x64/lithium-x64.h b/deps/v8/src/crankshaft/x64/lithium-x64.h index 3c953ffefa0f77..5147b5574a998a 100644 --- a/deps/v8/src/crankshaft/x64/lithium-x64.h +++ b/deps/v8/src/crankshaft/x64/lithium-x64.h @@ -42,7 +42,6 @@ class LCodeGen; V(ClampDToUint8) \ V(ClampIToUint8) \ V(ClampTToUint8) \ - V(ClassOfTestAndBranch) \ V(CompareNumericAndBranch) \ V(CmpObjectEqAndBranch) \ V(CmpHoleAndBranch) \ @@ -1069,26 +1068,6 @@ class LHasInstanceTypeAndBranch final : public LControlInstruction<1, 0> { void PrintDataTo(StringStream* stream) override; }; -class LClassOfTestAndBranch final : public LControlInstruction<1, 2> { - public: - LClassOfTestAndBranch(LOperand* value, LOperand* temp, LOperand* temp2) { - inputs_[0] = value; - temps_[0] = temp; - temps_[1] = temp2; - } - - LOperand* value() { return inputs_[0]; } - LOperand* temp() { return temps_[0]; } - LOperand* temp2() { return temps_[1]; } - - DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch, - "class-of-test-and-branch") - DECLARE_HYDROGEN_ACCESSOR(ClassOfTestAndBranch) - - void PrintDataTo(StringStream* stream) override; -}; - - class LCmpT final : public LTemplateInstruction<1, 3, 0> { public: LCmpT(LOperand* context, LOperand* left, LOperand* right) { diff --git a/deps/v8/src/crankshaft/x87/lithium-codegen-x87.cc b/deps/v8/src/crankshaft/x87/lithium-codegen-x87.cc index f526a19603a0ca..88a9cea68efc8c 100644 --- a/deps/v8/src/crankshaft/x87/lithium-codegen-x87.cc +++ b/deps/v8/src/crankshaft/x87/lithium-codegen-x87.cc @@ -2473,68 +2473,6 @@ void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { EmitBranch(instr, BranchCondition(instr->hydrogen())); } -// Branches to a label or falls through with the answer in the z flag. Trashes -// the temp registers, but not the input. -void LCodeGen::EmitClassOfTest(Label* is_true, - Label* is_false, - Handleclass_name, - Register input, - Register temp, - Register temp2) { - DCHECK(!input.is(temp)); - DCHECK(!input.is(temp2)); - DCHECK(!temp.is(temp2)); - __ JumpIfSmi(input, is_false); - - __ CmpObjectType(input, FIRST_FUNCTION_TYPE, temp); - STATIC_ASSERT(LAST_FUNCTION_TYPE == LAST_TYPE); - if (String::Equals(isolate()->factory()->Function_string(), class_name)) { - __ j(above_equal, is_true); - } else { - __ j(above_equal, is_false); - } - - // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range. - // Check if the constructor in the map is a function. - __ GetMapConstructor(temp, temp, temp2); - // Objects with a non-function constructor have class 'Object'. - __ CmpInstanceType(temp2, JS_FUNCTION_TYPE); - if (String::Equals(class_name, isolate()->factory()->Object_string())) { - __ j(not_equal, is_true); - } else { - __ j(not_equal, is_false); - } - - // temp now contains the constructor function. Grab the - // instance class name from there. - __ mov(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset)); - __ mov(temp, FieldOperand(temp, - SharedFunctionInfo::kInstanceClassNameOffset)); - // The class name we are testing against is internalized since it's a literal. - // The name in the constructor is internalized because of the way the context - // is booted. This routine isn't expected to work for random API-created - // classes and it doesn't have to because you can't access it with natives - // syntax. Since both sides are internalized it is sufficient to use an - // identity comparison. - __ cmp(temp, class_name); - // End with the answer in the z flag. -} - - -void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { - Register input = ToRegister(instr->value()); - Register temp = ToRegister(instr->temp()); - Register temp2 = ToRegister(instr->temp2()); - - Handle class_name = instr->hydrogen()->class_name(); - - EmitClassOfTest(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_), - class_name, input, temp, temp2); - - EmitBranch(instr, equal); -} - - void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { Register reg = ToRegister(instr->value()); __ cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map()); diff --git a/deps/v8/src/crankshaft/x87/lithium-codegen-x87.h b/deps/v8/src/crankshaft/x87/lithium-codegen-x87.h index 850f3309003754..be7faddff2adab 100644 --- a/deps/v8/src/crankshaft/x87/lithium-codegen-x87.h +++ b/deps/v8/src/crankshaft/x87/lithium-codegen-x87.h @@ -152,13 +152,6 @@ class LCodeGen: public LCodeGenBase { private: Scope* scope() const { return scope_; } - void EmitClassOfTest(Label* if_true, - Label* if_false, - Handle class_name, - Register input, - Register temporary, - Register temporary2); - bool HasAllocatedStackSlots() const { return chunk()->HasAllocatedStackSlots(); } diff --git a/deps/v8/src/crankshaft/x87/lithium-x87.cc b/deps/v8/src/crankshaft/x87/lithium-x87.cc index 1844d241179df0..44c7a1bee10569 100644 --- a/deps/v8/src/crankshaft/x87/lithium-x87.cc +++ b/deps/v8/src/crankshaft/x87/lithium-x87.cc @@ -235,16 +235,6 @@ void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) { stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } -void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) { - stream->Add("if class_of_test("); - value()->PrintTo(stream); - stream->Add(", \"%o\") then B%d else B%d", - *hydrogen()->class_name(), - true_block_id(), - false_block_id()); -} - - void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if typeof "); value()->PrintTo(stream); @@ -1697,15 +1687,6 @@ LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch( TempRegister()); } -LInstruction* LChunkBuilder::DoClassOfTestAndBranch( - HClassOfTestAndBranch* instr) { - DCHECK(instr->value()->representation().IsTagged()); - return new(zone()) LClassOfTestAndBranch(UseRegister(instr->value()), - TempRegister(), - TempRegister()); -} - - LInstruction* LChunkBuilder::DoSeqStringGetChar(HSeqStringGetChar* instr) { LOperand* string = UseRegisterAtStart(instr->string()); LOperand* index = UseRegisterOrConstantAtStart(instr->index()); diff --git a/deps/v8/src/crankshaft/x87/lithium-x87.h b/deps/v8/src/crankshaft/x87/lithium-x87.h index 3653a2de2f14b9..9ebf87b5f98246 100644 --- a/deps/v8/src/crankshaft/x87/lithium-x87.h +++ b/deps/v8/src/crankshaft/x87/lithium-x87.h @@ -46,7 +46,6 @@ class LCodeGen; V(ClampDToUint8) \ V(ClampIToUint8) \ V(ClampTToUint8NoSSE2) \ - V(ClassOfTestAndBranch) \ V(ClobberDoubles) \ V(CompareNumericAndBranch) \ V(CmpObjectEqAndBranch) \ @@ -1069,26 +1068,6 @@ class LHasInstanceTypeAndBranch final : public LControlInstruction<1, 1> { void PrintDataTo(StringStream* stream) override; }; -class LClassOfTestAndBranch final : public LControlInstruction<1, 2> { - public: - LClassOfTestAndBranch(LOperand* value, LOperand* temp, LOperand* temp2) { - inputs_[0] = value; - temps_[0] = temp; - temps_[1] = temp2; - } - - LOperand* value() { return inputs_[0]; } - LOperand* temp() { return temps_[0]; } - LOperand* temp2() { return temps_[1]; } - - DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch, - "class-of-test-and-branch") - DECLARE_HYDROGEN_ACCESSOR(ClassOfTestAndBranch) - - void PrintDataTo(StringStream* stream) override; -}; - - class LCmpT final : public LTemplateInstruction<1, 3, 0> { public: LCmpT(LOperand* context, LOperand* left, LOperand* right) { diff --git a/deps/v8/src/flag-definitions.h b/deps/v8/src/flag-definitions.h index 656fefbd2bbd23..02eb6aec3b9ae2 100644 --- a/deps/v8/src/flag-definitions.h +++ b/deps/v8/src/flag-definitions.h @@ -282,6 +282,8 @@ DEFINE_BOOL(allocation_site_pretenuring, true, "pretenure with allocation sites") DEFINE_BOOL(mark_shared_functions_for_tier_up, true, "mark shared functions for tier up") +DEFINE_BOOL(mark_optimizing_shared_functions, true, + "mark shared functions if they are concurrently optimizing") DEFINE_BOOL(page_promotion, true, "promote pages based on utilization") DEFINE_INT(page_promotion_threshold, 70, "min percentage of live bytes on a page to enable fast evacuation") @@ -544,10 +546,6 @@ DEFINE_BOOL(trace_wasm_interpreter, false, "trace interpretation of wasm code") DEFINE_INT(trace_wasm_ast_start, 0, "start function for WASM AST trace (inclusive)") DEFINE_INT(trace_wasm_ast_end, 0, "end function for WASM AST trace (exclusive)") -DEFINE_INT(trace_wasm_text_start, 0, - "start function for WASM text generation (inclusive)") -DEFINE_INT(trace_wasm_text_end, 0, - "end function for WASM text generation (exclusive)") DEFINE_UINT(skip_compiling_wasm_funcs, 0, "start compiling at function N") DEFINE_BOOL(wasm_break_on_decoder_error, false, "debug break when wasm decoder encounters an error") @@ -592,6 +590,8 @@ DEFINE_BOOL(wasm_trap_if, true, DEFINE_BOOL(wasm_code_fuzzer_gen_test, false, "Generate a test case when running the wasm-code fuzzer") DEFINE_BOOL(print_wasm_code, false, "Print WebAssembly code") +DEFINE_BOOL(wasm_interpret_all, false, + "Execute all wasm code in the wasm interpreter") // Profiler flags. DEFINE_INT(frame_count, 1, "number of stack frames inspected by the profiler") diff --git a/deps/v8/src/full-codegen/arm/full-codegen-arm.cc b/deps/v8/src/full-codegen/arm/full-codegen-arm.cc index 1f7b98627221fa..30f94059ddebb4 100644 --- a/deps/v8/src/full-codegen/arm/full-codegen-arm.cc +++ b/deps/v8/src/full-codegen/arm/full-codegen-arm.cc @@ -2045,58 +2045,6 @@ void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) { } -void FullCodeGenerator::EmitClassOf(CallRuntime* expr) { - ZoneList* args = expr->arguments(); - DCHECK(args->length() == 1); - Label done, null, function, non_function_constructor; - - VisitForAccumulatorValue(args->at(0)); - - // If the object is not a JSReceiver, we return null. - __ JumpIfSmi(r0, &null); - STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); - __ CompareObjectType(r0, r0, r1, FIRST_JS_RECEIVER_TYPE); - // Map is now in r0. - __ b(lt, &null); - - // Return 'Function' for JSFunction and JSBoundFunction objects. - __ cmp(r1, Operand(FIRST_FUNCTION_TYPE)); - STATIC_ASSERT(LAST_FUNCTION_TYPE == LAST_TYPE); - __ b(hs, &function); - - // Check if the constructor in the map is a JS function. - Register instance_type = r2; - __ GetMapConstructor(r0, r0, r1, instance_type); - __ cmp(instance_type, Operand(JS_FUNCTION_TYPE)); - __ b(ne, &non_function_constructor); - - // r0 now contains the constructor function. Grab the - // instance class name from there. - __ ldr(r0, FieldMemOperand(r0, JSFunction::kSharedFunctionInfoOffset)); - __ ldr(r0, FieldMemOperand(r0, SharedFunctionInfo::kInstanceClassNameOffset)); - __ b(&done); - - // Functions have class 'Function'. - __ bind(&function); - __ LoadRoot(r0, Heap::kFunction_stringRootIndex); - __ jmp(&done); - - // Objects with a non-function constructor have class 'Object'. - __ bind(&non_function_constructor); - __ LoadRoot(r0, Heap::kObject_stringRootIndex); - __ jmp(&done); - - // Non-JS objects have class null. - __ bind(&null); - __ LoadRoot(r0, Heap::kNullValueRootIndex); - - // All done. - __ bind(&done); - - context()->Plug(r0); -} - - void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 2); diff --git a/deps/v8/src/full-codegen/arm64/full-codegen-arm64.cc b/deps/v8/src/full-codegen/arm64/full-codegen-arm64.cc index f6b9c2f389365a..d1108f37c5aef2 100644 --- a/deps/v8/src/full-codegen/arm64/full-codegen-arm64.cc +++ b/deps/v8/src/full-codegen/arm64/full-codegen-arm64.cc @@ -1994,61 +1994,6 @@ void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) { } -void FullCodeGenerator::EmitClassOf(CallRuntime* expr) { - ASM_LOCATION("FullCodeGenerator::EmitClassOf"); - ZoneList* args = expr->arguments(); - DCHECK(args->length() == 1); - Label done, null, function, non_function_constructor; - - VisitForAccumulatorValue(args->at(0)); - - // If the object is not a JSReceiver, we return null. - __ JumpIfSmi(x0, &null); - STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); - __ CompareObjectType(x0, x10, x11, FIRST_JS_RECEIVER_TYPE); - // x10: object's map. - // x11: object's type. - __ B(lt, &null); - - // Return 'Function' for JSFunction objects. - __ Cmp(x11, FIRST_FUNCTION_TYPE); - STATIC_ASSERT(LAST_FUNCTION_TYPE == LAST_TYPE); - __ B(hs, &function); - - // Check if the constructor in the map is a JS function. - Register instance_type = x14; - __ GetMapConstructor(x12, x10, x13, instance_type); - __ Cmp(instance_type, JS_FUNCTION_TYPE); - __ B(ne, &non_function_constructor); - - // x12 now contains the constructor function. Grab the - // instance class name from there. - __ Ldr(x13, FieldMemOperand(x12, JSFunction::kSharedFunctionInfoOffset)); - __ Ldr(x0, - FieldMemOperand(x13, SharedFunctionInfo::kInstanceClassNameOffset)); - __ B(&done); - - // Functions have class 'Function'. - __ Bind(&function); - __ LoadRoot(x0, Heap::kFunction_stringRootIndex); - __ B(&done); - - // Objects with a non-function constructor have class 'Object'. - __ Bind(&non_function_constructor); - __ LoadRoot(x0, Heap::kObject_stringRootIndex); - __ B(&done); - - // Non-JS objects have class null. - __ Bind(&null); - __ LoadRoot(x0, Heap::kNullValueRootIndex); - - // All done. - __ Bind(&done); - - context()->Plug(x0); -} - - void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 2); diff --git a/deps/v8/src/full-codegen/full-codegen.h b/deps/v8/src/full-codegen/full-codegen.h index 58a9b9a813e745..d03788262a1d2f 100644 --- a/deps/v8/src/full-codegen/full-codegen.h +++ b/deps/v8/src/full-codegen/full-codegen.h @@ -410,7 +410,6 @@ class FullCodeGenerator final : public AstVisitor { F(IsJSReceiver) \ F(GetSuperConstructor) \ F(DebugBreakInOptimizedCode) \ - F(ClassOf) \ F(StringCharCodeAt) \ F(SubString) \ F(ToInteger) \ diff --git a/deps/v8/src/full-codegen/ia32/full-codegen-ia32.cc b/deps/v8/src/full-codegen/ia32/full-codegen-ia32.cc index 87db6f18a42cf0..86e0ccc8dc885c 100644 --- a/deps/v8/src/full-codegen/ia32/full-codegen-ia32.cc +++ b/deps/v8/src/full-codegen/ia32/full-codegen-ia32.cc @@ -1966,56 +1966,6 @@ void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) { } -void FullCodeGenerator::EmitClassOf(CallRuntime* expr) { - ZoneList* args = expr->arguments(); - DCHECK(args->length() == 1); - Label done, null, function, non_function_constructor; - - VisitForAccumulatorValue(args->at(0)); - - // If the object is not a JSReceiver, we return null. - __ JumpIfSmi(eax, &null, Label::kNear); - STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); - __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, eax); - __ j(below, &null, Label::kNear); - - // Return 'Function' for JSFunction and JSBoundFunction objects. - __ CmpInstanceType(eax, FIRST_FUNCTION_TYPE); - STATIC_ASSERT(LAST_FUNCTION_TYPE == LAST_TYPE); - __ j(above_equal, &function, Label::kNear); - - // Check if the constructor in the map is a JS function. - __ GetMapConstructor(eax, eax, ebx); - __ CmpInstanceType(ebx, JS_FUNCTION_TYPE); - __ j(not_equal, &non_function_constructor, Label::kNear); - - // eax now contains the constructor function. Grab the - // instance class name from there. - __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset)); - __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset)); - __ jmp(&done, Label::kNear); - - // Non-JS objects have class null. - __ bind(&null); - __ mov(eax, isolate()->factory()->null_value()); - __ jmp(&done, Label::kNear); - - // Functions have class 'Function'. - __ bind(&function); - __ mov(eax, isolate()->factory()->Function_string()); - __ jmp(&done, Label::kNear); - - // Objects with a non-function constructor have class 'Object'. - __ bind(&non_function_constructor); - __ mov(eax, isolate()->factory()->Object_string()); - - // All done. - __ bind(&done); - - context()->Plug(eax); -} - - void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 2); diff --git a/deps/v8/src/full-codegen/mips/full-codegen-mips.cc b/deps/v8/src/full-codegen/mips/full-codegen-mips.cc index cfc9952d08e956..6bbc34761077f8 100644 --- a/deps/v8/src/full-codegen/mips/full-codegen-mips.cc +++ b/deps/v8/src/full-codegen/mips/full-codegen-mips.cc @@ -2066,56 +2066,6 @@ void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) { } -void FullCodeGenerator::EmitClassOf(CallRuntime* expr) { - ZoneList* args = expr->arguments(); - DCHECK(args->length() == 1); - Label done, null, function, non_function_constructor; - - VisitForAccumulatorValue(args->at(0)); - - // If the object is not a JSReceiver, we return null. - __ JumpIfSmi(v0, &null); - STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); - __ GetObjectType(v0, v0, a1); // Map is now in v0. - __ Branch(&null, lt, a1, Operand(FIRST_JS_RECEIVER_TYPE)); - - // Return 'Function' for JSFunction and JSBoundFunction objects. - STATIC_ASSERT(LAST_FUNCTION_TYPE == LAST_TYPE); - __ Branch(&function, hs, a1, Operand(FIRST_FUNCTION_TYPE)); - - // Check if the constructor in the map is a JS function. - Register instance_type = a2; - __ GetMapConstructor(v0, v0, a1, instance_type); - __ Branch(&non_function_constructor, ne, instance_type, - Operand(JS_FUNCTION_TYPE)); - - // v0 now contains the constructor function. Grab the - // instance class name from there. - __ lw(v0, FieldMemOperand(v0, JSFunction::kSharedFunctionInfoOffset)); - __ lw(v0, FieldMemOperand(v0, SharedFunctionInfo::kInstanceClassNameOffset)); - __ Branch(&done); - - // Functions have class 'Function'. - __ bind(&function); - __ LoadRoot(v0, Heap::kFunction_stringRootIndex); - __ jmp(&done); - - // Objects with a non-function constructor have class 'Object'. - __ bind(&non_function_constructor); - __ LoadRoot(v0, Heap::kObject_stringRootIndex); - __ jmp(&done); - - // Non-JS objects have class null. - __ bind(&null); - __ LoadRoot(v0, Heap::kNullValueRootIndex); - - // All done. - __ bind(&done); - - context()->Plug(v0); -} - - void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 2); diff --git a/deps/v8/src/full-codegen/mips64/full-codegen-mips64.cc b/deps/v8/src/full-codegen/mips64/full-codegen-mips64.cc index 37e2d8037cbb4c..a42589e07d216e 100644 --- a/deps/v8/src/full-codegen/mips64/full-codegen-mips64.cc +++ b/deps/v8/src/full-codegen/mips64/full-codegen-mips64.cc @@ -2067,56 +2067,6 @@ void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) { } -void FullCodeGenerator::EmitClassOf(CallRuntime* expr) { - ZoneList* args = expr->arguments(); - DCHECK(args->length() == 1); - Label done, null, function, non_function_constructor; - - VisitForAccumulatorValue(args->at(0)); - - // If the object is not a JSReceiver, we return null. - __ JumpIfSmi(v0, &null); - STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); - __ GetObjectType(v0, v0, a1); // Map is now in v0. - __ Branch(&null, lt, a1, Operand(FIRST_JS_RECEIVER_TYPE)); - - // Return 'Function' for JSFunction and JSBoundFunction objects. - STATIC_ASSERT(LAST_FUNCTION_TYPE == LAST_TYPE); - __ Branch(&function, hs, a1, Operand(FIRST_FUNCTION_TYPE)); - - // Check if the constructor in the map is a JS function. - Register instance_type = a2; - __ GetMapConstructor(v0, v0, a1, instance_type); - __ Branch(&non_function_constructor, ne, instance_type, - Operand(JS_FUNCTION_TYPE)); - - // v0 now contains the constructor function. Grab the - // instance class name from there. - __ ld(v0, FieldMemOperand(v0, JSFunction::kSharedFunctionInfoOffset)); - __ ld(v0, FieldMemOperand(v0, SharedFunctionInfo::kInstanceClassNameOffset)); - __ Branch(&done); - - // Functions have class 'Function'. - __ bind(&function); - __ LoadRoot(v0, Heap::kFunction_stringRootIndex); - __ jmp(&done); - - // Objects with a non-function constructor have class 'Object'. - __ bind(&non_function_constructor); - __ LoadRoot(v0, Heap::kObject_stringRootIndex); - __ jmp(&done); - - // Non-JS objects have class null. - __ bind(&null); - __ LoadRoot(v0, Heap::kNullValueRootIndex); - - // All done. - __ bind(&done); - - context()->Plug(v0); -} - - void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 2); diff --git a/deps/v8/src/full-codegen/ppc/full-codegen-ppc.cc b/deps/v8/src/full-codegen/ppc/full-codegen-ppc.cc index bd69582cdaeea8..7313bac6fcb8f4 100644 --- a/deps/v8/src/full-codegen/ppc/full-codegen-ppc.cc +++ b/deps/v8/src/full-codegen/ppc/full-codegen-ppc.cc @@ -2054,59 +2054,6 @@ void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) { } -void FullCodeGenerator::EmitClassOf(CallRuntime* expr) { - ZoneList* args = expr->arguments(); - DCHECK(args->length() == 1); - Label done, null, function, non_function_constructor; - - VisitForAccumulatorValue(args->at(0)); - - // If the object is not a JSReceiver, we return null. - __ JumpIfSmi(r3, &null); - STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); - __ CompareObjectType(r3, r3, r4, FIRST_JS_RECEIVER_TYPE); - // Map is now in r3. - __ blt(&null); - - // Return 'Function' for JSFunction and JSBoundFunction objects. - __ cmpli(r4, Operand(FIRST_FUNCTION_TYPE)); - STATIC_ASSERT(LAST_FUNCTION_TYPE == LAST_TYPE); - __ bge(&function); - - // Check if the constructor in the map is a JS function. - Register instance_type = r5; - __ GetMapConstructor(r3, r3, r4, instance_type); - __ cmpi(instance_type, Operand(JS_FUNCTION_TYPE)); - __ bne(&non_function_constructor); - - // r3 now contains the constructor function. Grab the - // instance class name from there. - __ LoadP(r3, FieldMemOperand(r3, JSFunction::kSharedFunctionInfoOffset)); - __ LoadP(r3, - FieldMemOperand(r3, SharedFunctionInfo::kInstanceClassNameOffset)); - __ b(&done); - - // Functions have class 'Function'. - __ bind(&function); - __ LoadRoot(r3, Heap::kFunction_stringRootIndex); - __ b(&done); - - // Objects with a non-function constructor have class 'Object'. - __ bind(&non_function_constructor); - __ LoadRoot(r3, Heap::kObject_stringRootIndex); - __ b(&done); - - // Non-JS objects have class null. - __ bind(&null); - __ LoadRoot(r3, Heap::kNullValueRootIndex); - - // All done. - __ bind(&done); - - context()->Plug(r3); -} - - void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 2); diff --git a/deps/v8/src/full-codegen/s390/full-codegen-s390.cc b/deps/v8/src/full-codegen/s390/full-codegen-s390.cc index 340082affcd6f2..9da10a512d883c 100644 --- a/deps/v8/src/full-codegen/s390/full-codegen-s390.cc +++ b/deps/v8/src/full-codegen/s390/full-codegen-s390.cc @@ -2014,58 +2014,6 @@ void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) { context()->Plug(if_true, if_false); } -void FullCodeGenerator::EmitClassOf(CallRuntime* expr) { - ZoneList* args = expr->arguments(); - DCHECK(args->length() == 1); - Label done, null, function, non_function_constructor; - - VisitForAccumulatorValue(args->at(0)); - - // If the object is not a JSReceiver, we return null. - __ JumpIfSmi(r2, &null); - STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); - __ CompareObjectType(r2, r2, r3, FIRST_JS_RECEIVER_TYPE); - // Map is now in r2. - __ blt(&null); - - // Return 'Function' for JSFunction and JSBoundFunction objects. - __ CmpLogicalP(r3, Operand(FIRST_FUNCTION_TYPE)); - STATIC_ASSERT(LAST_FUNCTION_TYPE == LAST_TYPE); - __ bge(&function); - - // Check if the constructor in the map is a JS function. - Register instance_type = r4; - __ GetMapConstructor(r2, r2, r3, instance_type); - __ CmpP(instance_type, Operand(JS_FUNCTION_TYPE)); - __ bne(&non_function_constructor, Label::kNear); - - // r2 now contains the constructor function. Grab the - // instance class name from there. - __ LoadP(r2, FieldMemOperand(r2, JSFunction::kSharedFunctionInfoOffset)); - __ LoadP(r2, - FieldMemOperand(r2, SharedFunctionInfo::kInstanceClassNameOffset)); - __ b(&done, Label::kNear); - - // Functions have class 'Function'. - __ bind(&function); - __ LoadRoot(r2, Heap::kFunction_stringRootIndex); - __ b(&done, Label::kNear); - - // Objects with a non-function constructor have class 'Object'. - __ bind(&non_function_constructor); - __ LoadRoot(r2, Heap::kObject_stringRootIndex); - __ b(&done, Label::kNear); - - // Non-JS objects have class null. - __ bind(&null); - __ LoadRoot(r2, Heap::kNullValueRootIndex); - - // All done. - __ bind(&done); - - context()->Plug(r2); -} - void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 2); diff --git a/deps/v8/src/full-codegen/x64/full-codegen-x64.cc b/deps/v8/src/full-codegen/x64/full-codegen-x64.cc index d4d78edcf68af7..cb3d994f011a24 100644 --- a/deps/v8/src/full-codegen/x64/full-codegen-x64.cc +++ b/deps/v8/src/full-codegen/x64/full-codegen-x64.cc @@ -1955,56 +1955,6 @@ void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) { } -void FullCodeGenerator::EmitClassOf(CallRuntime* expr) { - ZoneList* args = expr->arguments(); - DCHECK(args->length() == 1); - Label done, null, function, non_function_constructor; - - VisitForAccumulatorValue(args->at(0)); - - // If the object is not a JSReceiver, we return null. - __ JumpIfSmi(rax, &null, Label::kNear); - STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); - __ CmpObjectType(rax, FIRST_JS_RECEIVER_TYPE, rax); - __ j(below, &null, Label::kNear); - - // Return 'Function' for JSFunction and JSBoundFunction objects. - __ CmpInstanceType(rax, FIRST_FUNCTION_TYPE); - STATIC_ASSERT(LAST_FUNCTION_TYPE == LAST_TYPE); - __ j(above_equal, &function, Label::kNear); - - // Check if the constructor in the map is a JS function. - __ GetMapConstructor(rax, rax, rbx); - __ CmpInstanceType(rbx, JS_FUNCTION_TYPE); - __ j(not_equal, &non_function_constructor, Label::kNear); - - // rax now contains the constructor function. Grab the - // instance class name from there. - __ movp(rax, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset)); - __ movp(rax, FieldOperand(rax, SharedFunctionInfo::kInstanceClassNameOffset)); - __ jmp(&done, Label::kNear); - - // Non-JS objects have class null. - __ bind(&null); - __ LoadRoot(rax, Heap::kNullValueRootIndex); - __ jmp(&done, Label::kNear); - - // Functions have class 'Function'. - __ bind(&function); - __ LoadRoot(rax, Heap::kFunction_stringRootIndex); - __ jmp(&done, Label::kNear); - - // Objects with a non-function constructor have class 'Object'. - __ bind(&non_function_constructor); - __ LoadRoot(rax, Heap::kObject_stringRootIndex); - - // All done. - __ bind(&done); - - context()->Plug(rax); -} - - void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 2); diff --git a/deps/v8/src/full-codegen/x87/full-codegen-x87.cc b/deps/v8/src/full-codegen/x87/full-codegen-x87.cc index 25d3f216a81276..850bb2b1d31b92 100644 --- a/deps/v8/src/full-codegen/x87/full-codegen-x87.cc +++ b/deps/v8/src/full-codegen/x87/full-codegen-x87.cc @@ -1956,56 +1956,6 @@ void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) { } -void FullCodeGenerator::EmitClassOf(CallRuntime* expr) { - ZoneList* args = expr->arguments(); - DCHECK(args->length() == 1); - Label done, null, function, non_function_constructor; - - VisitForAccumulatorValue(args->at(0)); - - // If the object is not a JSReceiver, we return null. - __ JumpIfSmi(eax, &null, Label::kNear); - STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); - __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, eax); - __ j(below, &null, Label::kNear); - - // Return 'Function' for JSFunction and JSBoundFunction objects. - __ CmpInstanceType(eax, FIRST_FUNCTION_TYPE); - STATIC_ASSERT(LAST_FUNCTION_TYPE == LAST_TYPE); - __ j(above_equal, &function, Label::kNear); - - // Check if the constructor in the map is a JS function. - __ GetMapConstructor(eax, eax, ebx); - __ CmpInstanceType(ebx, JS_FUNCTION_TYPE); - __ j(not_equal, &non_function_constructor, Label::kNear); - - // eax now contains the constructor function. Grab the - // instance class name from there. - __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset)); - __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset)); - __ jmp(&done, Label::kNear); - - // Non-JS objects have class null. - __ bind(&null); - __ mov(eax, isolate()->factory()->null_value()); - __ jmp(&done, Label::kNear); - - // Functions have class 'Function'. - __ bind(&function); - __ mov(eax, isolate()->factory()->Function_string()); - __ jmp(&done, Label::kNear); - - // Objects with a non-function constructor have class 'Object'. - __ bind(&non_function_constructor); - __ mov(eax, isolate()->factory()->Object_string()); - - // All done. - __ bind(&done); - - context()->Plug(eax); -} - - void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 2); diff --git a/deps/v8/src/handles.h b/deps/v8/src/handles.h index 16356fbd66bad0..780c7914b0833d 100644 --- a/deps/v8/src/handles.h +++ b/deps/v8/src/handles.h @@ -106,12 +106,9 @@ class Handle final : public HandleBase { // Constructor for handling automatic up casting. // Ex. Handle can be passed when Handle is expected. template - V8_INLINE Handle(Handle handle) - : HandleBase(handle) { - T* a = nullptr; - S* b = nullptr; - a = b; // Fake assignment to enforce type checks. - USE(a); + V8_INLINE Handle(Handle handle) : HandleBase(handle) { + // Type check: + static_assert(std::is_base_of::value, "static type violation"); } V8_INLINE T* operator->() const { return operator*(); } @@ -192,10 +189,8 @@ class MaybeHandle final { template V8_INLINE MaybeHandle(Handle handle) : location_(reinterpret_cast(handle.location_)) { - T* a = nullptr; - S* b = nullptr; - a = b; // Fake assignment to enforce type checks. - USE(a); + // Type check: + static_assert(std::is_base_of::value, "static type violation"); } // Constructor for handling automatic up casting. @@ -203,10 +198,8 @@ class MaybeHandle final { template V8_INLINE MaybeHandle(MaybeHandle maybe_handle) : location_(reinterpret_cast(maybe_handle.location_)) { - T* a = nullptr; - S* b = nullptr; - a = b; // Fake assignment to enforce type checks. - USE(a); + // Type check: + static_assert(std::is_base_of::value, "static type violation"); } template diff --git a/deps/v8/src/heap/heap.cc b/deps/v8/src/heap/heap.cc index d07dd8527e74e5..a414ea7582e3a4 100644 --- a/deps/v8/src/heap/heap.cc +++ b/deps/v8/src/heap/heap.cc @@ -2330,7 +2330,6 @@ bool Heap::CreateInitialMaps() { Context::BOOLEAN_FUNCTION_INDEX); ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, uninitialized); ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, arguments_marker); - ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, no_interceptor_result_sentinel); ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, exception); ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, termination_exception); ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, optimized_out); @@ -2670,11 +2669,6 @@ void Heap::CreateInitialObjects() { handle(Smi::FromInt(-4), isolate()), "undefined", Oddball::kArgumentsMarker)); - set_no_interceptor_result_sentinel(*factory->NewOddball( - factory->no_interceptor_result_sentinel_map(), - "no_interceptor_result_sentinel", handle(Smi::FromInt(-2), isolate()), - "undefined", Oddball::kOther)); - set_termination_exception(*factory->NewOddball( factory->termination_exception_map(), "termination_exception", handle(Smi::FromInt(-3), isolate()), "undefined", Oddball::kOther)); diff --git a/deps/v8/src/heap/heap.h b/deps/v8/src/heap/heap.h index 30ae1beade5d40..c61dfd54d49513 100644 --- a/deps/v8/src/heap/heap.h +++ b/deps/v8/src/heap/heap.h @@ -67,7 +67,6 @@ using v8::MemoryPressureLevel; /* This means they are never in new space and never on a page that is */ \ /* being compacted. */ \ /* Oddballs */ \ - V(Oddball, no_interceptor_result_sentinel, NoInterceptorResultSentinel) \ V(Oddball, arguments_marker, ArgumentsMarker) \ V(Oddball, exception, Exception) \ V(Oddball, termination_exception, TerminationException) \ @@ -216,7 +215,6 @@ using v8::MemoryPressureLevel; V(Map, boolean_map, BooleanMap) \ V(Map, uninitialized_map, UninitializedMap) \ V(Map, arguments_marker_map, ArgumentsMarkerMap) \ - V(Map, no_interceptor_result_sentinel_map, NoInterceptorResultSentinelMap) \ V(Map, exception_map, ExceptionMap) \ V(Map, termination_exception_map, TerminationExceptionMap) \ V(Map, optimized_out_map, OptimizedOutMap) \ @@ -278,7 +276,6 @@ using v8::MemoryPressureLevel; V(FixedDoubleArrayMap) \ V(WeakCellMap) \ V(TransitionArrayMap) \ - V(NoInterceptorResultSentinel) \ V(HashTableMap) \ V(OrderedHashTableMap) \ V(EmptyFixedArray) \ diff --git a/deps/v8/src/ia32/macro-assembler-ia32.cc b/deps/v8/src/ia32/macro-assembler-ia32.cc index e8842a83238bda..ebb27007b9d32f 100644 --- a/deps/v8/src/ia32/macro-assembler-ia32.cc +++ b/deps/v8/src/ia32/macro-assembler-ia32.cc @@ -1669,19 +1669,6 @@ void MacroAssembler::NegativeZeroTest(Register result, } -void MacroAssembler::GetMapConstructor(Register result, Register map, - Register temp) { - Label done, loop; - mov(result, FieldOperand(map, Map::kConstructorOrBackPointerOffset)); - bind(&loop); - JumpIfSmi(result, &done, Label::kNear); - CmpObjectType(result, MAP_TYPE, temp); - j(not_equal, &done, Label::kNear); - mov(result, FieldOperand(result, Map::kConstructorOrBackPointerOffset)); - jmp(&loop); - bind(&done); -} - void MacroAssembler::CallStub(CodeStub* stub, TypeFeedbackId ast_id) { DCHECK(AllowThisStubCall(stub)); // Calls are not allowed in some stubs. call(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id); diff --git a/deps/v8/src/ia32/macro-assembler-ia32.h b/deps/v8/src/ia32/macro-assembler-ia32.h index 9eb25e49c90835..984b051b91323e 100644 --- a/deps/v8/src/ia32/macro-assembler-ia32.h +++ b/deps/v8/src/ia32/macro-assembler-ia32.h @@ -641,10 +641,6 @@ class MacroAssembler: public Assembler { void NegativeZeroTest(Register result, Register op1, Register op2, Register scratch, Label* then_label); - // Machine code version of Map::GetConstructor(). - // |temp| holds |result|'s map when done. - void GetMapConstructor(Register result, Register map, Register temp); - // --------------------------------------------------------------------------- // Runtime calls diff --git a/deps/v8/src/ic/accessor-assembler.cc b/deps/v8/src/ic/accessor-assembler.cc index c16b2ecac7482b..eec6acc923e8b9 100644 --- a/deps/v8/src/ic/accessor-assembler.cc +++ b/deps/v8/src/ic/accessor-assembler.cc @@ -183,7 +183,7 @@ void AccessorAssembler::HandleLoadICHandlerCase( Bind(&if_smi_handler); { HandleLoadICSmiHandlerCase(p, var_holder.value(), var_smi_handler.value(), - miss, exit_point, support_elements); + miss, exit_point, false, support_elements); } Bind(&try_proto_handler); @@ -245,7 +245,8 @@ void AccessorAssembler::HandleLoadField(Node* holder, Node* handler_word, void AccessorAssembler::HandleLoadICSmiHandlerCase( const LoadICParameters* p, Node* holder, Node* smi_handler, Label* miss, - ExitPoint* exit_point, ElementSupport support_elements) { + ExitPoint* exit_point, bool throw_reference_error_if_nonexistent, + ElementSupport support_elements) { Variable var_double_value(this, MachineRepresentation::kFloat64); Label rebox_double(this, &var_double_value); @@ -253,9 +254,8 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase( Node* handler_kind = DecodeWord(handler_word); if (support_elements == kSupportElements) { Label property(this); - GotoIfNot( - WordEqual(handler_kind, IntPtrConstant(LoadHandler::kForElements)), - &property); + GotoIfNot(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kElement)), + &property); Comment("element_load"); Node* intptr_index = TryToIntptr(p->name, miss); @@ -296,17 +296,32 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase( Comment("property_load"); } - Label constant(this), field(this), normal(this, Label::kDeferred); - GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kForFields)), - &field); + Label constant(this), field(this), normal(this, Label::kDeferred), + interceptor(this, Label::kDeferred), nonexistent(this); + GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kField)), &field); - Branch(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kForConstants)), - &constant, &normal); + GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kConstant)), + &constant); + + GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kNonExistent)), + &nonexistent); + + Branch(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kNormal)), &normal, + &interceptor); Bind(&field); HandleLoadField(holder, handler_word, &var_double_value, &rebox_double, exit_point); + Bind(&nonexistent); + // This is a handler for a load of a non-existent value. + if (throw_reference_error_if_nonexistent) { + exit_point->ReturnCallRuntime(Runtime::kThrowReferenceError, p->context, + p->name); + } else { + exit_point->Return(UndefinedConstant()); + } + Bind(&constant); { Comment("constant_load"); @@ -354,6 +369,14 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase( } } + Bind(&interceptor); + { + Comment("load_interceptor"); + exit_point->ReturnCallRuntime(Runtime::kLoadPropertyWithInterceptor, + p->context, p->name, p->receiver, holder, + p->slot, p->vector); + } + Bind(&rebox_double); exit_point->Return(AllocateHeapNumberWithValue(var_double_value.value())); } @@ -420,23 +443,27 @@ void AccessorAssembler::HandleLoadICProtoHandlerCase( Bind(&tuple_handler); { - Label load_existent(this); - GotoIf(WordNotEqual(maybe_holder_cell, NullConstant()), &load_existent); - // This is a handler for a load of a non-existent value. - if (throw_reference_error_if_nonexistent) { - exit_point->ReturnCallRuntime(Runtime::kThrowReferenceError, p->context, - p->name); - } else { - exit_point->Return(UndefinedConstant()); + Label load_from_cached_holder(this), done(this); + + GotoIf(WordNotEqual(maybe_holder_cell, NullConstant()), + &load_from_cached_holder); + { + var_holder->Bind(p->receiver); + Goto(&done); } - Bind(&load_existent); - Node* holder = LoadWeakCellValue(maybe_holder_cell); - // The |holder| is guaranteed to be alive at this point since we passed - // both the receiver map check and the validity cell check. - CSA_ASSERT(this, WordNotEqual(holder, IntPtrConstant(0))); + Bind(&load_from_cached_holder); + { + Node* holder = LoadWeakCellValue(maybe_holder_cell); + // The |holder| is guaranteed to be alive at this point since we passed + // both the receiver map check and the validity cell check. + CSA_ASSERT(this, WordNotEqual(holder, IntPtrConstant(0))); + + var_holder->Bind(holder); + Goto(&done); + } - var_holder->Bind(holder); + Bind(&done); var_smi_handler->Bind(smi_handler); Goto(if_smi_handler); } @@ -450,10 +477,11 @@ void AccessorAssembler::HandleLoadICProtoHandlerCase( } } -Node* AccessorAssembler::EmitLoadICProtoArrayCheck( - const LoadICParameters* p, Node* handler, Node* handler_length, - Node* handler_flags, Label* miss, - bool throw_reference_error_if_nonexistent) { +Node* AccessorAssembler::EmitLoadICProtoArrayCheck(const LoadICParameters* p, + Node* handler, + Node* handler_length, + Node* handler_flags, + Label* miss) { Variable start_index(this, MachineType::PointerRepresentation()); start_index.Bind(IntPtrConstant(LoadHandler::kFirstPrototypeIndex)); @@ -494,22 +522,22 @@ Node* AccessorAssembler::EmitLoadICProtoArrayCheck( Node* maybe_holder_cell = LoadFixedArrayElement(handler, LoadHandler::kHolderCellIndex); - Label load_existent(this); - GotoIf(WordNotEqual(maybe_holder_cell, NullConstant()), &load_existent); - // This is a handler for a load of a non-existent value. - if (throw_reference_error_if_nonexistent) { - TailCallRuntime(Runtime::kThrowReferenceError, p->context, p->name); - } else { - Return(UndefinedConstant()); + + Variable var_holder(this, MachineRepresentation::kTagged, p->receiver); + Label done(this); + GotoIf(WordEqual(maybe_holder_cell, NullConstant()), &done); + + { + var_holder.Bind(LoadWeakCellValue(maybe_holder_cell)); + // The |holder| is guaranteed to be alive at this point since we passed + // the receiver map check, the validity cell check and the prototype chain + // check. + CSA_ASSERT(this, WordNotEqual(var_holder.value(), IntPtrConstant(0))); + Goto(&done); } - Bind(&load_existent); - Node* holder = LoadWeakCellValue(maybe_holder_cell); - // The |holder| is guaranteed to be alive at this point since we passed - // the receiver map check, the validity cell check and the prototype chain - // check. - CSA_ASSERT(this, WordNotEqual(holder, IntPtrConstant(0))); - return holder; + Bind(&done); + return var_holder.value(); } void AccessorAssembler::HandleLoadGlobalICHandlerCase( @@ -523,12 +551,14 @@ void AccessorAssembler::HandleLoadGlobalICHandlerCase( Variable var_holder(this, MachineRepresentation::kTagged); Variable var_smi_handler(this, MachineRepresentation::kTagged); Label if_smi_handler(this); + HandleLoadICProtoHandlerCase(&p, handler, &var_holder, &var_smi_handler, &if_smi_handler, miss, exit_point, throw_reference_error_if_nonexistent); Bind(&if_smi_handler); - HandleLoadICSmiHandlerCase(&p, var_holder.value(), var_smi_handler.value(), - miss, exit_point, kOnlyProperties); + HandleLoadICSmiHandlerCase( + &p, var_holder.value(), var_smi_handler.value(), miss, exit_point, + throw_reference_error_if_nonexistent, kOnlyProperties); } void AccessorAssembler::JumpIfDataProperty(Node* details, Label* writable, @@ -1813,11 +1843,11 @@ void AccessorAssembler::LoadICProtoArray( Node* handler_length = LoadAndUntagFixedArrayBaseLength(handler); - Node* holder = - EmitLoadICProtoArrayCheck(p, handler, handler_length, handler_flags, - &miss, throw_reference_error_if_nonexistent); + Node* holder = EmitLoadICProtoArrayCheck(p, handler, handler_length, + handler_flags, &miss); HandleLoadICSmiHandlerCase(p, holder, smi_handler, &miss, &direct_exit, + throw_reference_error_if_nonexistent, kOnlyProperties); Bind(&miss); @@ -1844,33 +1874,47 @@ void AccessorAssembler::LoadGlobalIC_TryPropertyCellCase( exit_point->Return(value); } -void AccessorAssembler::LoadGlobalIC_TryHandlerCase(const LoadICParameters* p, +void AccessorAssembler::LoadGlobalIC_TryHandlerCase(const LoadICParameters* pp, TypeofMode typeof_mode, ExitPoint* exit_point, Label* miss) { Comment("LoadGlobalIC_TryHandlerCase"); - Label call_handler(this); + Label call_handler(this), non_smi(this); Node* handler = - LoadFixedArrayElement(p->vector, p->slot, kPointerSize, SMI_PARAMETERS); - CSA_ASSERT(this, Word32BinaryNot(TaggedIsSmi(handler))); + LoadFixedArrayElement(pp->vector, pp->slot, kPointerSize, SMI_PARAMETERS); GotoIf(WordEqual(handler, LoadRoot(Heap::kuninitialized_symbolRootIndex)), miss); - GotoIf(IsCodeMap(LoadMap(handler)), &call_handler); + + GotoIfNot(TaggedIsSmi(handler), &non_smi); bool throw_reference_error_if_nonexistent = typeof_mode == NOT_INSIDE_TYPEOF; - HandleLoadGlobalICHandlerCase(p, handler, miss, exit_point, + + { + LoadICParameters p = *pp; + DCHECK_NULL(p.receiver); + Node* native_context = LoadNativeContext(p.context); + p.receiver = LoadContextElement(native_context, Context::EXTENSION_INDEX); + HandleLoadICSmiHandlerCase(&p, p.receiver, handler, miss, exit_point, + throw_reference_error_if_nonexistent, + kOnlyProperties); + } + + Bind(&non_smi); + GotoIf(IsCodeMap(LoadMap(handler)), &call_handler); + + HandleLoadGlobalICHandlerCase(pp, handler, miss, exit_point, throw_reference_error_if_nonexistent); Bind(&call_handler); { LoadWithVectorDescriptor descriptor(isolate()); - Node* native_context = LoadNativeContext(p->context); + Node* native_context = LoadNativeContext(pp->context); Node* receiver = LoadContextElement(native_context, Context::EXTENSION_INDEX); - exit_point->ReturnCallStub(descriptor, handler, p->context, receiver, - p->name, p->slot, p->vector); + exit_point->ReturnCallStub(descriptor, handler, pp->context, receiver, + pp->name, pp->slot, pp->vector); } } diff --git a/deps/v8/src/ic/accessor-assembler.h b/deps/v8/src/ic/accessor-assembler.h index dc26b8cf9474b7..267026e6b6e0fc 100644 --- a/deps/v8/src/ic/accessor-assembler.h +++ b/deps/v8/src/ic/accessor-assembler.h @@ -139,6 +139,7 @@ class AccessorAssembler : public CodeStubAssembler { void HandleLoadICSmiHandlerCase(const LoadICParameters* p, Node* holder, Node* smi_handler, Label* miss, ExitPoint* exit_point, + bool throw_reference_error_if_nonexistent, ElementSupport support_elements); void HandleLoadICProtoHandlerCase(const LoadICParameters* p, Node* handler, @@ -154,8 +155,7 @@ class AccessorAssembler : public CodeStubAssembler { Node* EmitLoadICProtoArrayCheck(const LoadICParameters* p, Node* handler, Node* handler_length, Node* handler_flags, - Label* miss, - bool throw_reference_error_if_nonexistent); + Label* miss); // LoadGlobalIC implementation. diff --git a/deps/v8/src/ic/arm/handler-compiler-arm.cc b/deps/v8/src/ic/arm/handler-compiler-arm.cc index e2539979306faf..e8e8f30a6e1aa4 100644 --- a/deps/v8/src/ic/arm/handler-compiler-arm.cc +++ b/deps/v8/src/ic/arm/handler-compiler-arm.cc @@ -200,24 +200,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell( __ b(ne, miss); } -static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, Register receiver, Register holder, Register name, - Handle holder_obj, Runtime::FunctionId id) { - DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == - Runtime::FunctionForId(id)->nargs); - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ push(name); - __ push(receiver); - __ push(holder); - - __ CallRuntime(id); -} - - // Generate call to api function. void PropertyHandlerCompiler::GenerateApiAccessorCall( MacroAssembler* masm, const CallOptimization& optimization, @@ -445,86 +427,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle name, Label* miss) { } } -void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( - LookupIterator* it, Register holder_reg) { - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - // 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. - DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1())); - - // Preserve the receiver register explicitly whenever it is different from the - // holder and it is needed should the interceptor return without any result. - // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD - // case might cause a miss during the prototype check. - bool must_perform_prototype_check = - !holder().is_identical_to(it->GetHolder()); - bool must_preserve_receiver_reg = - !receiver().is(holder_reg) && - (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check); - - // Save necessary data before invoking an interceptor. - // Requires a frame to make GC aware of pushed pointers. - { - FrameAndConstantPoolScope frame_scope(masm(), StackFrame::INTERNAL); - if (must_preserve_receiver_reg) { - __ Push(receiver(), holder_reg, this->name()); - } else { - __ Push(holder_reg, this->name()); - } - InterceptorVectorSlotPush(holder_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, this->name(), holder(), - Runtime::kLoadPropertyWithInterceptorOnly); - - // Check if interceptor provided a value for property. If it's - // the case, return immediately. - Label interceptor_failed; - __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex); - __ cmp(r0, scratch1()); - __ b(eq, &interceptor_failed); - frame_scope.GenerateLeaveFrame(); - __ Ret(); - - __ bind(&interceptor_failed); - InterceptorVectorSlotPop(holder_reg); - __ pop(this->name()); - __ pop(holder_reg); - if (must_preserve_receiver_reg) { - __ pop(receiver()); - } - // Leave the internal frame. - } - - GenerateLoadPostInterceptor(it, holder_reg); -} - - -void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { - // Call the runtime system to load the interceptor. - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ Push(name(), receiver(), holder_reg); - // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details. - if (holder_reg.is(receiver())) { - __ Push(slot(), vector()); - } else { - __ Push(scratch3(), scratch2()); // slot, vector - } - - __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); -} - void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() { STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack); } diff --git a/deps/v8/src/ic/arm64/handler-compiler-arm64.cc b/deps/v8/src/ic/arm64/handler-compiler-arm64.cc index 19d818cb2d999d..f6ac4955cca376 100644 --- a/deps/v8/src/ic/arm64/handler-compiler-arm64.cc +++ b/deps/v8/src/ic/arm64/handler-compiler-arm64.cc @@ -99,22 +99,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell( __ JumpIfNotRoot(scratch, Heap::kTheHoleValueRootIndex, miss); } -static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, Register receiver, Register holder, Register name, - Handle holder_obj, Runtime::FunctionId id) { - DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == - Runtime::FunctionForId(id)->nargs); - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ Push(name, receiver, holder); - - __ CallRuntime(id); -} - - // Generate call to api function. void PropertyHandlerCompiler::GenerateApiAccessorCall( MacroAssembler* masm, const CallOptimization& optimization, @@ -474,87 +458,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle name, Label* miss) { } } -void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( - LookupIterator* it, Register holder_reg) { - DCHECK(!AreAliased(receiver(), this->name(), scratch1(), scratch2(), - scratch3())); - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - // 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. - DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1())); - - // Preserve the receiver register explicitly whenever it is different from the - // holder and it is needed should the interceptor return without any result. - // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD - // case might cause a miss during the prototype check. - bool must_perform_prototype_check = - !holder().is_identical_to(it->GetHolder()); - bool must_preserve_receiver_reg = - !receiver().is(holder_reg) && - (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check); - - // Save necessary data before invoking an interceptor. - // Requires a frame to make GC aware of pushed pointers. - { - FrameScope frame_scope(masm(), StackFrame::INTERNAL); - if (must_preserve_receiver_reg) { - __ Push(receiver(), holder_reg, this->name()); - } else { - __ Push(holder_reg, this->name()); - } - InterceptorVectorSlotPush(holder_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, this->name(), holder(), - Runtime::kLoadPropertyWithInterceptorOnly); - - // Check if interceptor provided a value for property. If it's - // the case, return immediately. - Label interceptor_failed; - __ JumpIfRoot(x0, Heap::kNoInterceptorResultSentinelRootIndex, - &interceptor_failed); - frame_scope.GenerateLeaveFrame(); - __ Ret(); - - __ Bind(&interceptor_failed); - InterceptorVectorSlotPop(holder_reg); - if (must_preserve_receiver_reg) { - __ Pop(this->name(), holder_reg, receiver()); - } else { - __ Pop(this->name(), holder_reg); - } - // Leave the internal frame. - } - - GenerateLoadPostInterceptor(it, holder_reg); -} - - -void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { - // Call the runtime system to load the interceptor. - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ Push(name(), receiver(), holder_reg); - // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details. - if (holder_reg.is(receiver())) { - __ Push(slot(), vector()); - } else { - __ Push(scratch3(), scratch2()); // slot, vector - } - - __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); -} - void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() { STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack); } diff --git a/deps/v8/src/ic/handler-compiler.cc b/deps/v8/src/ic/handler-compiler.cc index 6a9734d5ebbb13..3b7425bfbabf2f 100644 --- a/deps/v8/src/ic/handler-compiler.cc +++ b/deps/v8/src/ic/handler-compiler.cc @@ -95,16 +95,6 @@ Register PropertyHandlerCompiler::Frontend(Handle name) { return reg; } -Handle NamedLoadHandlerCompiler::CompileLoadCallback( - Handle name, Handle callback, Handle slow_stub) { - if (V8_UNLIKELY(FLAG_runtime_stats)) { - GenerateTailCall(masm(), slow_stub); - } - Register reg = Frontend(name); - GenerateLoadCallback(reg, callback); - return GetCode(kind(), name); -} - Handle NamedLoadHandlerCompiler::CompileLoadCallback( Handle name, const CallOptimization& call_optimization, int accessor_index, Handle slow_stub) { @@ -118,191 +108,6 @@ Handle NamedLoadHandlerCompiler::CompileLoadCallback( return GetCode(kind(), name); } - -void NamedLoadHandlerCompiler::InterceptorVectorSlotPush(Register holder_reg) { - if (IC::ShouldPushPopSlotAndVector(kind())) { - if (holder_reg.is(receiver())) { - PushVectorAndSlot(); - } else { - DCHECK(holder_reg.is(scratch1())); - PushVectorAndSlot(scratch2(), scratch3()); - } - } -} - - -void NamedLoadHandlerCompiler::InterceptorVectorSlotPop(Register holder_reg, - PopMode mode) { - if (IC::ShouldPushPopSlotAndVector(kind())) { - if (mode == DISCARD) { - DiscardVectorAndSlot(); - } else { - if (holder_reg.is(receiver())) { - PopVectorAndSlot(); - } else { - DCHECK(holder_reg.is(scratch1())); - PopVectorAndSlot(scratch2(), scratch3()); - } - } - } -} - - -Handle NamedLoadHandlerCompiler::CompileLoadInterceptor( - LookupIterator* it) { - // So far the most popular follow ups for interceptor loads are DATA and - // AccessorInfo, so inline only them. Other cases may be added - // later. - bool inline_followup = false; - switch (it->state()) { - case LookupIterator::TRANSITION: - UNREACHABLE(); - case LookupIterator::ACCESS_CHECK: - case LookupIterator::INTERCEPTOR: - case LookupIterator::JSPROXY: - case LookupIterator::NOT_FOUND: - case LookupIterator::INTEGER_INDEXED_EXOTIC: - break; - case LookupIterator::DATA: { - PropertyDetails details = it->property_details(); - inline_followup = details.kind() == kData && - details.location() == kField && - !it->is_dictionary_holder(); - break; - } - case LookupIterator::ACCESSOR: { - Handle accessors = it->GetAccessors(); - if (accessors->IsAccessorInfo()) { - Handle info = Handle::cast(accessors); - inline_followup = - info->getter() != NULL && - AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map()); - } else if (accessors->IsAccessorPair()) { - Handle property_holder(it->GetHolder()); - Handle getter(Handle::cast(accessors)->getter(), - isolate()); - if (!(getter->IsJSFunction() || getter->IsFunctionTemplateInfo())) { - break; - } - if (!property_holder->HasFastProperties()) break; - CallOptimization call_optimization(getter); - Handle receiver_map = map(); - inline_followup = call_optimization.is_simple_api_call() && - call_optimization.IsCompatibleReceiverMap( - receiver_map, property_holder); - } - } - } - - Label miss; - InterceptorVectorSlotPush(receiver()); - bool lost_holder_register = false; - auto holder_orig = holder(); - // non masking interceptors must check the entire chain, so temporarily reset - // the holder to be that last element for the FrontendHeader call. - if (holder()->GetNamedInterceptor()->non_masking()) { - DCHECK(!inline_followup); - JSObject* last = *holder(); - PrototypeIterator iter(isolate(), last); - while (!iter.IsAtEnd()) { - lost_holder_register = true; - // Casting to JSObject is fine here. The LookupIterator makes sure to - // look behind non-masking interceptors during the original lookup, and - // we wouldn't try to compile a handler if there was a Proxy anywhere. - last = iter.GetCurrent(); - iter.Advance(); - } - auto last_handle = handle(last); - set_holder(last_handle); - } - Register reg = FrontendHeader(receiver(), it->name(), &miss, RETURN_HOLDER); - // Reset the holder so further calculations are correct. - set_holder(holder_orig); - if (lost_holder_register) { - if (*it->GetReceiver() == *holder()) { - reg = receiver(); - } else { - // Reload lost holder register. - auto cell = isolate()->factory()->NewWeakCell(holder()); - __ LoadWeakValue(reg, cell, &miss); - } - } - FrontendFooter(it->name(), &miss); - InterceptorVectorSlotPop(reg); - if (inline_followup) { - // TODO(368): Compile in the whole chain: all the interceptors in - // prototypes and ultimate answer. - GenerateLoadInterceptorWithFollowup(it, reg); - } else { - GenerateLoadInterceptor(reg); - } - return GetCode(kind(), it->name()); -} - -void NamedLoadHandlerCompiler::GenerateLoadCallback( - Register reg, Handle callback) { - DCHECK(receiver().is(ApiGetterDescriptor::ReceiverRegister())); - __ Move(ApiGetterDescriptor::HolderRegister(), reg); - // The callback is alive if this instruction is executed, - // so the weak cell is not cleared and points to data. - Handle cell = isolate()->factory()->NewWeakCell(callback); - __ GetWeakValue(ApiGetterDescriptor::CallbackRegister(), cell); - - CallApiGetterStub stub(isolate()); - __ TailCallStub(&stub); -} - -void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor( - LookupIterator* it, Register interceptor_reg) { - Handle real_named_property_holder(it->GetHolder()); - - Handle holder_map(holder()->map()); - set_map(holder_map); - set_holder(real_named_property_holder); - - Label miss; - InterceptorVectorSlotPush(interceptor_reg); - Register reg = - FrontendHeader(interceptor_reg, it->name(), &miss, RETURN_HOLDER); - FrontendFooter(it->name(), &miss); - // We discard the vector and slot now because we don't miss below this point. - InterceptorVectorSlotPop(reg, DISCARD); - - switch (it->state()) { - case LookupIterator::ACCESS_CHECK: - case LookupIterator::INTERCEPTOR: - case LookupIterator::JSPROXY: - case LookupIterator::NOT_FOUND: - case LookupIterator::INTEGER_INDEXED_EXOTIC: - case LookupIterator::TRANSITION: - UNREACHABLE(); - case LookupIterator::DATA: { - DCHECK_EQ(kData, it->property_details().kind()); - DCHECK_EQ(kField, it->property_details().location()); - __ Move(LoadFieldDescriptor::ReceiverRegister(), reg); - Handle smi_handler = - LoadIC::SimpleFieldLoad(isolate(), it->GetFieldIndex()); - __ Move(LoadFieldDescriptor::SmiHandlerRegister(), smi_handler); - GenerateTailCall(masm(), isolate()->builtins()->LoadField()); - break; - } - case LookupIterator::ACCESSOR: - if (it->GetAccessors()->IsAccessorInfo()) { - Handle info = - Handle::cast(it->GetAccessors()); - DCHECK_NOT_NULL(info->getter()); - GenerateLoadCallback(reg, info); - } else { - Handle function = handle( - AccessorPair::cast(*it->GetAccessors())->getter(), isolate()); - CallOptimization call_optimization(function); - GenerateApiAccessorCall(masm(), call_optimization, holder_map, - receiver(), scratch2(), false, no_reg, reg, - it->GetAccessorIndex()); - } - } -} - Handle NamedLoadHandlerCompiler::CompileLoadViaGetter( Handle name, int accessor_index, int expected_arguments) { Register holder = Frontend(name); diff --git a/deps/v8/src/ic/handler-compiler.h b/deps/v8/src/ic/handler-compiler.h index a37375abfb2d69..1165290e630e0f 100644 --- a/deps/v8/src/ic/handler-compiler.h +++ b/deps/v8/src/ic/handler-compiler.h @@ -129,19 +129,10 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler { virtual ~NamedLoadHandlerCompiler() {} - Handle CompileLoadCallback(Handle name, - Handle callback, - Handle slow_stub); - Handle CompileLoadCallback(Handle name, const CallOptimization& call_optimization, int accessor_index, Handle slow_stub); - // The LookupIterator is used to perform a lookup behind the interceptor. If - // the iterator points to a LookupIterator::PROPERTY, its access will be - // inlined. - Handle CompileLoadInterceptor(LookupIterator* it); - Handle CompileLoadViaGetter(Handle name, int accessor_index, int expected_arguments); @@ -158,15 +149,6 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler { no_reg); } - // These constants describe the structure of the interceptor arguments on the - // stack. The arguments are pushed by the (platform-specific) - // PushInterceptorArguments and read by LoadPropertyWithInterceptorOnly and - // LoadWithInterceptor. - static const int kInterceptorArgsNameIndex = 0; - static const int kInterceptorArgsThisIndex = 1; - static const int kInterceptorArgsHolderIndex = 2; - static const int kInterceptorArgsLength = 3; - protected: virtual Register FrontendHeader(Register object_reg, Handle name, Label* miss, ReturnHolder return_what); @@ -174,18 +156,6 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler { virtual void FrontendFooter(Handle name, Label* miss); private: - void GenerateLoadCallback(Register reg, Handle callback); - - // Helper emits no code if vector-ics are disabled. - void InterceptorVectorSlotPush(Register holder_reg); - enum PopMode { POP, DISCARD }; - void InterceptorVectorSlotPop(Register holder_reg, PopMode mode = POP); - - void GenerateLoadInterceptor(Register holder_reg); - void GenerateLoadInterceptorWithFollowup(LookupIterator* it, - Register holder_reg); - void GenerateLoadPostInterceptor(LookupIterator* it, Register reg); - Register scratch3() { return registers_[4]; } }; diff --git a/deps/v8/src/ic/handler-configuration-inl.h b/deps/v8/src/ic/handler-configuration-inl.h index 406d9473f284d5..0aa46c2618e070 100644 --- a/deps/v8/src/ic/handler-configuration-inl.h +++ b/deps/v8/src/ic/handler-configuration-inl.h @@ -13,68 +13,68 @@ namespace v8 { namespace internal { -Handle LoadHandler::LoadNormal(Isolate* isolate) { - int config = KindBits::encode(kForNormal); +Handle LoadHandler::LoadNormal(Isolate* isolate) { + int config = KindBits::encode(kNormal); return handle(Smi::FromInt(config), isolate); } -Handle LoadHandler::LoadField(Isolate* isolate, - FieldIndex field_index) { - int config = KindBits::encode(kForFields) | +Handle LoadHandler::LoadInterceptor(Isolate* isolate) { + int config = KindBits::encode(kInterceptor); + return handle(Smi::FromInt(config), isolate); +} + +Handle LoadHandler::LoadField(Isolate* isolate, FieldIndex field_index) { + int config = KindBits::encode(kField) | IsInobjectBits::encode(field_index.is_inobject()) | IsDoubleBits::encode(field_index.is_double()) | FieldOffsetBits::encode(field_index.offset()); return handle(Smi::FromInt(config), isolate); } -Handle LoadHandler::LoadConstant(Isolate* isolate, int descriptor) { - int config = KindBits::encode(kForConstants) | - IsAccessorInfoBits::encode(false) | +Handle LoadHandler::LoadConstant(Isolate* isolate, int descriptor) { + int config = KindBits::encode(kConstant) | IsAccessorInfoBits::encode(false) | DescriptorBits::encode(descriptor); return handle(Smi::FromInt(config), isolate); } -Handle LoadHandler::LoadApiGetter(Isolate* isolate, int descriptor) { - int config = KindBits::encode(kForConstants) | - IsAccessorInfoBits::encode(true) | +Handle LoadHandler::LoadApiGetter(Isolate* isolate, int descriptor) { + int config = KindBits::encode(kConstant) | IsAccessorInfoBits::encode(true) | DescriptorBits::encode(descriptor); return handle(Smi::FromInt(config), isolate); } -Handle LoadHandler::EnableAccessCheckOnReceiver( - Isolate* isolate, Handle smi_handler) { - int config = Smi::cast(*smi_handler)->value(); +Handle LoadHandler::EnableAccessCheckOnReceiver(Isolate* isolate, + Handle smi_handler) { + int config = smi_handler->value(); #ifdef DEBUG Kind kind = KindBits::decode(config); - DCHECK_NE(kForElements, kind); + DCHECK_NE(kElement, kind); #endif config = DoAccessCheckOnReceiverBits::update(config, true); return handle(Smi::FromInt(config), isolate); } -Handle LoadHandler::EnableLookupOnReceiver(Isolate* isolate, - Handle smi_handler) { - int config = Smi::cast(*smi_handler)->value(); +Handle LoadHandler::EnableLookupOnReceiver(Isolate* isolate, + Handle smi_handler) { + int config = smi_handler->value(); #ifdef DEBUG Kind kind = KindBits::decode(config); - DCHECK_NE(kForElements, kind); + DCHECK_NE(kElement, kind); #endif config = LookupOnReceiverBits::update(config, true); return handle(Smi::FromInt(config), isolate); } -Handle LoadHandler::LoadNonExistent(Isolate* isolate, - bool do_lookup_on_receiver) { - int config = KindBits::encode(kForNonExistent) | - LookupOnReceiverBits::encode(do_lookup_on_receiver); +Handle LoadHandler::LoadNonExistent(Isolate* isolate) { + int config = KindBits::encode(kNonExistent); return handle(Smi::FromInt(config), isolate); } -Handle LoadHandler::LoadElement(Isolate* isolate, - ElementsKind elements_kind, - bool convert_hole_to_undefined, - bool is_js_array) { - int config = KindBits::encode(kForElements) | +Handle LoadHandler::LoadElement(Isolate* isolate, + ElementsKind elements_kind, + bool convert_hole_to_undefined, + bool is_js_array) { + int config = KindBits::encode(kElement) | ElementsKindBits::encode(elements_kind) | ConvertHoleBits::encode(convert_hole_to_undefined) | IsJsArrayBits::encode(is_js_array); diff --git a/deps/v8/src/ic/handler-configuration.h b/deps/v8/src/ic/handler-configuration.h index 478cb01dcf19f1..c68dc4801ba317 100644 --- a/deps/v8/src/ic/handler-configuration.h +++ b/deps/v8/src/ic/handler-configuration.h @@ -17,24 +17,24 @@ namespace internal { class LoadHandler { public: enum Kind { - kForElements, - kForNormal, - kForFields, - kForConstants, - kForNonExistent + kElement, + kNormal, + kField, + kConstant, + kInterceptor, + kNonExistent }; class KindBits : public BitField {}; // Defines whether access rights check should be done on receiver object. - // Applicable to kForFields, kForConstants and kForNonExistent kinds only when - // loading value from prototype chain. Ignored when loading from holder. + // Applicable to named property kinds only when loading value from prototype + // chain. Ignored when loading from holder. class DoAccessCheckOnReceiverBits : public BitField {}; // Defines whether a lookup should be done on receiver object before - // proceeding to the prototype chain. Applicable to kForFields, kForConstants - // and kForNonExistent kinds only when loading value from prototype chain. - // Ignored when loading from holder. + // proceeding to the prototype chain. Applicable to named property kinds only + // when loading value from prototype chain. Ignored when loading from holder. class LookupOnReceiverBits : public BitField {}; @@ -51,7 +51,7 @@ class LoadHandler { STATIC_ASSERT(DescriptorBits::kNext <= kSmiValueSize); // - // Encoding when KindBits contains kForFields. + // Encoding when KindBits contains kField. // class IsInobjectBits : public BitField { }; @@ -64,7 +64,7 @@ class LoadHandler { STATIC_ASSERT(FieldOffsetBits::kNext <= kSmiValueSize); // - // Encoding when KindBits contains kForElements. + // Encoding when KindBits contains kElement. // class IsJsArrayBits : public BitField {}; class ConvertHoleBits : public BitField {}; @@ -89,38 +89,40 @@ class LoadHandler { static const int kFirstPrototypeIndex = 3; // Creates a Smi-handler for loading a property from a slow object. - static inline Handle LoadNormal(Isolate* isolate); + static inline Handle LoadNormal(Isolate* isolate); + + // Creates a Smi-handler for loading a property from an object with an + // interceptor. + static inline Handle LoadInterceptor(Isolate* isolate); // Creates a Smi-handler for loading a field from fast object. - static inline Handle LoadField(Isolate* isolate, - FieldIndex field_index); + static inline Handle LoadField(Isolate* isolate, FieldIndex field_index); // Creates a Smi-handler for loading a constant from fast object. - static inline Handle LoadConstant(Isolate* isolate, int descriptor); + static inline Handle LoadConstant(Isolate* isolate, int descriptor); // Creates a Smi-handler for loading an Api getter property from fast object. - static inline Handle LoadApiGetter(Isolate* isolate, int descriptor); + static inline Handle LoadApiGetter(Isolate* isolate, int descriptor); // Sets DoAccessCheckOnReceiverBits in given Smi-handler. The receiver // check is a part of a prototype chain check. - static inline Handle EnableAccessCheckOnReceiver( - Isolate* isolate, Handle smi_handler); + static inline Handle EnableAccessCheckOnReceiver( + Isolate* isolate, Handle smi_handler); // Sets LookupOnReceiverBits in given Smi-handler. The receiver // check is a part of a prototype chain check. - static inline Handle EnableLookupOnReceiver( - Isolate* isolate, Handle smi_handler); + static inline Handle EnableLookupOnReceiver(Isolate* isolate, + Handle smi_handler); // Creates a Smi-handler for loading a non-existent property. Works only as // a part of prototype chain check. - static inline Handle LoadNonExistent(Isolate* isolate, - bool do_lookup_on_receiver); + static inline Handle LoadNonExistent(Isolate* isolate); // Creates a Smi-handler for loading an element. - static inline Handle LoadElement(Isolate* isolate, - ElementsKind elements_kind, - bool convert_hole_to_undefined, - bool is_js_array); + static inline Handle LoadElement(Isolate* isolate, + ElementsKind elements_kind, + bool convert_hole_to_undefined, + bool is_js_array); }; // A set of bit fields representing Smi handlers for stores. diff --git a/deps/v8/src/ic/ia32/handler-compiler-ia32.cc b/deps/v8/src/ic/ia32/handler-compiler-ia32.cc index 508490cd34b041..f8264644bad9b2 100644 --- a/deps/v8/src/ic/ia32/handler-compiler-ia32.cc +++ b/deps/v8/src/ic/ia32/handler-compiler-ia32.cc @@ -287,23 +287,6 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter( } } -static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, Register receiver, Register holder, Register name, - Handle holder_obj, Runtime::FunctionId id) { - DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == - Runtime::FunctionForId(id)->nargs); - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ push(name); - __ push(receiver); - __ push(holder); - - __ CallRuntime(id); -} - #undef __ #define __ ACCESS_MASM(masm()) @@ -445,102 +428,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle name, Label* miss) { } } -void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( - LookupIterator* it, Register holder_reg) { - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - // 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. - DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1())); - - // Preserve the receiver register explicitly whenever it is different from the - // holder and it is needed should the interceptor return without any result. - // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD - // case might cause a miss during the prototype check. - bool must_perform_prototype_check = - !holder().is_identical_to(it->GetHolder()); - bool must_preserve_receiver_reg = - !receiver().is(holder_reg) && - (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check); - - // Save necessary data before invoking an interceptor. - // Requires a frame to make GC aware of pushed pointers. - { - FrameScope frame_scope(masm(), StackFrame::INTERNAL); - - if (must_preserve_receiver_reg) { - __ push(receiver()); - } - __ push(holder_reg); - __ push(this->name()); - InterceptorVectorSlotPush(holder_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, this->name(), holder(), - Runtime::kLoadPropertyWithInterceptorOnly); - - // Check if interceptor provided a value for property. If it's - // the case, return immediately. - Label interceptor_failed; - __ cmp(eax, factory()->no_interceptor_result_sentinel()); - __ j(equal, &interceptor_failed); - frame_scope.GenerateLeaveFrame(); - __ ret(0); - - // Clobber registers when generating debug-code to provoke errors. - __ bind(&interceptor_failed); - if (FLAG_debug_code) { - __ mov(receiver(), Immediate(bit_cast(kZapValue))); - __ mov(holder_reg, Immediate(bit_cast(kZapValue))); - __ mov(this->name(), Immediate(bit_cast(kZapValue))); - } - - InterceptorVectorSlotPop(holder_reg); - __ pop(this->name()); - __ pop(holder_reg); - if (must_preserve_receiver_reg) { - __ pop(receiver()); - } - - // Leave the internal frame. - } - - GenerateLoadPostInterceptor(it, holder_reg); -} - - -void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - // Call the runtime system to load the interceptor. - - // Stack: - // return address - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ push(receiver()); - __ push(holder_reg); - // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details. - if (holder_reg.is(receiver())) { - __ push(slot()); - __ push(vector()); - } else { - __ push(scratch3()); // slot - __ push(scratch2()); // vector - } - __ push(Operand(esp, 4 * kPointerSize)); // return address - __ mov(Operand(esp, 5 * kPointerSize), name()); - - __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); -} - void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() { // Zap register aliases of the arguments passed on the stack to ensure they // are properly loaded by the handler (debug-only). diff --git a/deps/v8/src/ic/ic.cc b/deps/v8/src/ic/ic.cc index 901a5afb044586..e4001c6d10de4a 100644 --- a/deps/v8/src/ic/ic.cc +++ b/deps/v8/src/ic/ic.cc @@ -869,7 +869,7 @@ void IC::PatchCache(Handle name, Handle handler) { } } -Handle LoadIC::SimpleFieldLoad(Isolate* isolate, FieldIndex index) { +Handle LoadIC::SimpleFieldLoad(Isolate* isolate, FieldIndex index) { TRACE_HANDLER_STATS(isolate, LoadIC_LoadFieldDH); return LoadHandler::LoadField(isolate, index); } @@ -967,12 +967,13 @@ int GetPrototypeCheckCount(Isolate* isolate, Handle receiver_map, Handle LoadIC::LoadFromPrototype(Handle receiver_map, Handle holder, Handle name, - Handle smi_handler) { + Handle smi_handler) { int checks_count = GetPrototypeCheckCount(isolate(), receiver_map, holder, name); DCHECK_LE(0, checks_count); - if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) { + if (receiver_map->IsPrimitiveMap() || + receiver_map->is_access_check_needed()) { DCHECK(!receiver_map->is_dictionary_map()); DCHECK_LE(1, checks_count); // For native context. smi_handler = @@ -1003,43 +1004,45 @@ Handle LoadIC::LoadFromPrototype(Handle receiver_map, return handler_array; } -Handle LoadIC::LoadNonExistent(Handle receiver_map, - Handle name) { - Handle holder; // null handle - int checks_count = - GetPrototypeCheckCount(isolate(), receiver_map, holder, name); +Handle LoadIC::LoadFullChain(Handle receiver_map, + Handle holder, Handle name, + Handle smi_handler) { + Handle end; // null handle + int checks_count = GetPrototypeCheckCount(isolate(), receiver_map, end, name); DCHECK_LE(0, checks_count); - bool do_negative_lookup_on_receiver = - receiver_map->is_dictionary_map() && !receiver_map->IsJSGlobalObjectMap(); - Handle smi_handler = - LoadHandler::LoadNonExistent(isolate(), do_negative_lookup_on_receiver); - - if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) { + if (receiver_map->IsPrimitiveMap() || + receiver_map->is_access_check_needed()) { DCHECK(!receiver_map->is_dictionary_map()); DCHECK_LE(1, checks_count); // For native context. smi_handler = LoadHandler::EnableAccessCheckOnReceiver(isolate(), smi_handler); + } else if (receiver_map->is_dictionary_map() && + !receiver_map->IsJSGlobalObjectMap()) { + smi_handler = LoadHandler::EnableLookupOnReceiver(isolate(), smi_handler); } Handle validity_cell = Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); if (validity_cell.is_null()) { DCHECK_EQ(0, checks_count); - validity_cell = handle(Smi::FromInt(0), isolate()); + // Lookup on receiver isn't supported in case of a simple smi handler. + if (!LoadHandler::LookupOnReceiverBits::decode(smi_handler->value())) { + return smi_handler; + } + validity_cell = handle(Smi::kZero, isolate()); } Factory* factory = isolate()->factory(); if (checks_count == 0) { - return factory->NewTuple3(factory->null_value(), smi_handler, - validity_cell); + return factory->NewTuple3(holder, smi_handler, validity_cell); } Handle handler_array(factory->NewFixedArray( LoadHandler::kFirstPrototypeIndex + checks_count, TENURED)); handler_array->set(LoadHandler::kSmiHandlerIndex, *smi_handler); handler_array->set(LoadHandler::kValidityCellIndex, *validity_cell); - handler_array->set(LoadHandler::kHolderCellIndex, *factory->null_value()); - InitPrototypeChecks(isolate(), receiver_map, holder, name, handler_array, + handler_array->set(LoadHandler::kHolderCellIndex, *holder); + InitPrototypeChecks(isolate(), receiver_map, end, name, handler_array, LoadHandler::kFirstPrototypeIndex); return handler_array; } @@ -1099,7 +1102,9 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) { code = slow_stub(); } else if (!lookup->IsFound()) { TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH); - code = LoadNonExistent(receiver_map(), lookup->name()); + Handle smi_handler = LoadHandler::LoadNonExistent(isolate()); + code = LoadFullChain(receiver_map(), isolate()->factory()->null_value(), + lookup->name(), smi_handler); } else { if (IsLoadGlobalIC() && lookup->state() == LookupIterator::DATA && lookup->GetReceiver().is_identical_to(lookup->GetHolder())) { @@ -1304,8 +1309,26 @@ Handle LoadIC::GetMapIndependentHandler(LookupIterator* lookup) { Handle holder = lookup->GetHolder(); bool receiver_is_holder = receiver.is_identical_to(holder); switch (lookup->state()) { - case LookupIterator::INTERCEPTOR: - break; // Custom-compiled handler. + case LookupIterator::INTERCEPTOR: { + Handle smi_handler = LoadHandler::LoadInterceptor(isolate()); + + if (holder->GetNamedInterceptor()->non_masking()) { + Handle holder_ref = isolate()->factory()->null_value(); + if (!receiver_is_holder) { + holder_ref = Map::GetOrCreatePrototypeWeakCell(holder, isolate()); + } + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonMaskingInterceptorDH); + return LoadFullChain(map, holder_ref, lookup->name(), smi_handler); + } + + if (receiver_is_holder) { + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptorDH); + return smi_handler; + } + + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptorFromPrototypeDH); + return LoadFromPrototype(map, holder, lookup->name(), smi_handler); + } case LookupIterator::ACCESSOR: { // Use simple field loads for some well-known callback properties. @@ -1345,17 +1368,14 @@ Handle LoadIC::GetMapIndependentHandler(LookupIterator* lookup) { TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); return slow_stub(); } - Handle smi_handler = + Handle smi_handler = LoadHandler::LoadApiGetter(isolate(), lookup->GetAccessorIndex()); if (receiver_is_holder) { TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterDH); return smi_handler; } - if (!IsLoadGlobalIC()) { - TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterFromPrototypeDH); - return LoadFromPrototype(map, holder, lookup->name(), smi_handler); - } - break; // Custom-compiled handler. + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterFromPrototypeDH); + return LoadFromPrototype(map, holder, lookup->name(), smi_handler); } } TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); @@ -1364,7 +1384,7 @@ Handle LoadIC::GetMapIndependentHandler(LookupIterator* lookup) { case LookupIterator::DATA: { DCHECK_EQ(kData, lookup->property_details().kind()); - Handle smi_handler; + Handle smi_handler; if (lookup->is_dictionary_holder()) { if (holder->IsJSGlobalObject()) { break; // Custom-compiled handler. @@ -1427,17 +1447,9 @@ Handle LoadIC::CompileHandler(LookupIterator* lookup, Handle map = receiver_map(); switch (lookup->state()) { - case LookupIterator::INTERCEPTOR: { - DCHECK(!holder->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptor); - NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder); - // Perform a lookup behind the interceptor. Copy the LookupIterator since - // the original iterator will be used to fetch the value. - LookupIterator it = *lookup; - it.Next(); - LookupForRead(&it); - return compiler.CompileLoadInterceptor(&it); - } + case LookupIterator::INTERCEPTOR: + UNREACHABLE(); + break; case LookupIterator::ACCESSOR: { #ifdef DEBUG @@ -1448,45 +1460,30 @@ Handle LoadIC::CompileHandler(LookupIterator* lookup, DCHECK(IsCompatibleReceiver(lookup, map)); Handle accessors = lookup->GetAccessors(); - if (accessors->IsAccessorPair()) { - if (lookup->TryLookupCachedProperty()) { - DCHECK_EQ(LookupIterator::DATA, lookup->state()); - return ComputeHandler(lookup); - } - DCHECK(holder->HasFastProperties()); - DCHECK(!GetHostFunction()->shared()->HasDebugInfo()); - Handle getter(Handle::cast(accessors)->getter(), - isolate()); - CallOptimization call_optimization(getter); - NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder); - if (call_optimization.is_simple_api_call()) { - TRACE_HANDLER_STATS(isolate(), LoadIC_LoadCallback); - int index = lookup->GetAccessorIndex(); - Handle code = compiler.CompileLoadCallback( - lookup->name(), call_optimization, index, slow_stub()); - return code; - } - TRACE_HANDLER_STATS(isolate(), LoadIC_LoadViaGetter); - int expected_arguments = Handle::cast(getter) - ->shared() - ->internal_formal_parameter_count(); - return compiler.CompileLoadViaGetter( - lookup->name(), lookup->GetAccessorIndex(), expected_arguments); - } else { - DCHECK(accessors->IsAccessorInfo()); - Handle info = Handle::cast(accessors); - DCHECK(v8::ToCData
(info->getter()) != nullptr); - DCHECK(AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map)); - DCHECK(holder->HasFastProperties()); - DCHECK(!receiver_is_holder); - DCHECK(!info->is_sloppy() || receiver->IsJSReceiver()); + DCHECK(accessors->IsAccessorPair()); + if (lookup->TryLookupCachedProperty()) { + DCHECK_EQ(LookupIterator::DATA, lookup->state()); + return ComputeHandler(lookup); + } + DCHECK(holder->HasFastProperties()); + DCHECK(!GetHostFunction()->shared()->HasDebugInfo()); + Handle getter(Handle::cast(accessors)->getter(), + isolate()); + CallOptimization call_optimization(getter); + NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder); + if (call_optimization.is_simple_api_call()) { TRACE_HANDLER_STATS(isolate(), LoadIC_LoadCallback); - NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder); - Handle code = - compiler.CompileLoadCallback(lookup->name(), info, slow_stub()); + int index = lookup->GetAccessorIndex(); + Handle code = compiler.CompileLoadCallback( + lookup->name(), call_optimization, index, slow_stub()); return code; } - UNREACHABLE(); + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadViaGetter); + int expected_arguments = Handle::cast(getter) + ->shared() + ->internal_formal_parameter_count(); + return compiler.CompileLoadViaGetter( + lookup->name(), lookup->GetAccessorIndex(), expected_arguments); } case LookupIterator::DATA: { @@ -3055,57 +3052,16 @@ RUNTIME_FUNCTION(Runtime_StoreCallbackProperty) { } -/** - * Attempts to load a property with an interceptor (which must be present), - * but doesn't search the prototype chain. - * - * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't - * provide any value for the given name. - */ -RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptorOnly) { - DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength); - Handle name = - args.at(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex); - Handle receiver = - args.at(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex); - Handle holder = - args.at(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex); - HandleScope scope(isolate); - - if (!receiver->IsJSReceiver()) { - ASSIGN_RETURN_FAILURE_ON_EXCEPTION( - isolate, receiver, Object::ConvertReceiver(isolate, receiver)); - } - - InterceptorInfo* interceptor = holder->GetNamedInterceptor(); - PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver, - *holder, Object::DONT_THROW); - - v8::GenericNamedPropertyGetterCallback getter = - v8::ToCData( - interceptor->getter()); - Handle result = arguments.Call(getter, name); - - RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); - - if (!result.is_null()) return *result; - return isolate->heap()->no_interceptor_result_sentinel(); -} - - /** * Loads a property with an interceptor performing post interceptor * lookup if interceptor failed. */ RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) { HandleScope scope(isolate); - DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength + 2); - Handle name = - args.at(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex); - Handle receiver = - args.at(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex); - Handle holder = - args.at(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex); + DCHECK_EQ(5, args.length()); + Handle name = args.at(0); + Handle receiver = args.at(1); + Handle holder = args.at(2); if (!receiver->IsJSReceiver()) { ASSIGN_RETURN_FAILURE_ON_EXCEPTION( diff --git a/deps/v8/src/ic/ic.h b/deps/v8/src/ic/ic.h index 9a643438a903bf..e73518e7e3986b 100644 --- a/deps/v8/src/ic/ic.h +++ b/deps/v8/src/ic/ic.h @@ -311,17 +311,20 @@ class LoadIC : public IC { private: // Creates a data handler that represents a load of a field by given index. - static Handle SimpleFieldLoad(Isolate* isolate, FieldIndex index); + static Handle SimpleFieldLoad(Isolate* isolate, FieldIndex index); // Creates a data handler that represents a prototype chain check followed // by given Smi-handler that encoded a load from the holder. // Can be used only if GetPrototypeCheckCount() returns non negative value. Handle LoadFromPrototype(Handle receiver_map, Handle holder, Handle name, - Handle smi_handler); + Handle smi_handler); // Creates a data handler that represents a load of a non-existent property. - Handle LoadNonExistent(Handle receiver_map, Handle name); + // {holder} is the object from which the property is loaded. If no holder is + // needed (e.g., for "nonexistent"), null_value() may be passed in. + Handle LoadFullChain(Handle receiver_map, Handle holder, + Handle name, Handle smi_handler); friend class IC; friend class NamedLoadHandlerCompiler; diff --git a/deps/v8/src/ic/mips/handler-compiler-mips.cc b/deps/v8/src/ic/mips/handler-compiler-mips.cc index 88d4817eb8b5a6..de31775ccc5c1f 100644 --- a/deps/v8/src/ic/mips/handler-compiler-mips.cc +++ b/deps/v8/src/ic/mips/handler-compiler-mips.cc @@ -190,22 +190,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell( __ Branch(miss, ne, scratch, Operand(at)); } -static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, Register receiver, Register holder, Register name, - Handle holder_obj, Runtime::FunctionId id) { - DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == - Runtime::FunctionForId(id)->nargs); - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ Push(name, receiver, holder); - - __ CallRuntime(id); -} - - // Generate call to api function. void PropertyHandlerCompiler::GenerateApiAccessorCall( MacroAssembler* masm, const CallOptimization& optimization, @@ -428,85 +412,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle name, Label* miss) { } } -void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( - LookupIterator* it, Register holder_reg) { - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - // 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. - DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1())); - - // Preserve the receiver register explicitly whenever it is different from the - // holder and it is needed should the interceptor return without any result. - // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD - // case might cause a miss during the prototype check. - bool must_perform_prototype_check = - !holder().is_identical_to(it->GetHolder()); - bool must_preserve_receiver_reg = - !receiver().is(holder_reg) && - (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check); - - // Save necessary data before invoking an interceptor. - // Requires a frame to make GC aware of pushed pointers. - { - FrameScope frame_scope(masm(), StackFrame::INTERNAL); - if (must_preserve_receiver_reg) { - __ Push(receiver(), holder_reg, this->name()); - } else { - __ Push(holder_reg, this->name()); - } - InterceptorVectorSlotPush(holder_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, this->name(), holder(), - Runtime::kLoadPropertyWithInterceptorOnly); - - // Check if interceptor provided a value for property. If it's - // the case, return immediately. - Label interceptor_failed; - __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex); - __ Branch(&interceptor_failed, eq, v0, Operand(scratch1())); - frame_scope.GenerateLeaveFrame(); - __ Ret(); - - __ bind(&interceptor_failed); - InterceptorVectorSlotPop(holder_reg); - if (must_preserve_receiver_reg) { - __ Pop(receiver(), holder_reg, this->name()); - } else { - __ Pop(holder_reg, this->name()); - } - // Leave the internal frame. - } - - GenerateLoadPostInterceptor(it, holder_reg); -} - - -void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { - // Call the runtime system to load the interceptor. - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ Push(name(), receiver(), holder_reg); - // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details. - if (holder_reg.is(receiver())) { - __ Push(slot(), vector()); - } else { - __ Push(scratch3(), scratch2()); // slot, vector - } - - __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); -} - void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() { STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack); } diff --git a/deps/v8/src/ic/mips64/handler-compiler-mips64.cc b/deps/v8/src/ic/mips64/handler-compiler-mips64.cc index feb8f2a27d9546..27aaaa20080904 100644 --- a/deps/v8/src/ic/mips64/handler-compiler-mips64.cc +++ b/deps/v8/src/ic/mips64/handler-compiler-mips64.cc @@ -190,22 +190,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell( __ Branch(miss, ne, scratch, Operand(at)); } -static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, Register receiver, Register holder, Register name, - Handle holder_obj, Runtime::FunctionId id) { - DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == - Runtime::FunctionForId(id)->nargs); - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ Push(name, receiver, holder); - - __ CallRuntime(id); -} - - // Generate call to api function. void PropertyHandlerCompiler::GenerateApiAccessorCall( MacroAssembler* masm, const CallOptimization& optimization, @@ -428,85 +412,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle name, Label* miss) { } } -void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( - LookupIterator* it, Register holder_reg) { - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - // 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. - DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1())); - - // Preserve the receiver register explicitly whenever it is different from the - // holder and it is needed should the interceptor return without any result. - // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD - // case might cause a miss during the prototype check. - bool must_perform_prototype_check = - !holder().is_identical_to(it->GetHolder()); - bool must_preserve_receiver_reg = - !receiver().is(holder_reg) && - (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check); - - // Save necessary data before invoking an interceptor. - // Requires a frame to make GC aware of pushed pointers. - { - FrameScope frame_scope(masm(), StackFrame::INTERNAL); - if (must_preserve_receiver_reg) { - __ Push(receiver(), holder_reg, this->name()); - } else { - __ Push(holder_reg, this->name()); - } - InterceptorVectorSlotPush(holder_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, this->name(), holder(), - Runtime::kLoadPropertyWithInterceptorOnly); - - // Check if interceptor provided a value for property. If it's - // the case, return immediately. - Label interceptor_failed; - __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex); - __ Branch(&interceptor_failed, eq, v0, Operand(scratch1())); - frame_scope.GenerateLeaveFrame(); - __ Ret(); - - __ bind(&interceptor_failed); - InterceptorVectorSlotPop(holder_reg); - if (must_preserve_receiver_reg) { - __ Pop(receiver(), holder_reg, this->name()); - } else { - __ Pop(holder_reg, this->name()); - } - // Leave the internal frame. - } - - GenerateLoadPostInterceptor(it, holder_reg); -} - - -void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { - // Call the runtime system to load the interceptor. - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ Push(name(), receiver(), holder_reg); - // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details. - if (holder_reg.is(receiver())) { - __ Push(slot(), vector()); - } else { - __ Push(scratch3(), scratch2()); // slot, vector - } - - __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); -} - void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() { STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack); } diff --git a/deps/v8/src/ic/ppc/handler-compiler-ppc.cc b/deps/v8/src/ic/ppc/handler-compiler-ppc.cc index fc447d03346051..fff5e096c53007 100644 --- a/deps/v8/src/ic/ppc/handler-compiler-ppc.cc +++ b/deps/v8/src/ic/ppc/handler-compiler-ppc.cc @@ -195,22 +195,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell( } -static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, Register receiver, Register holder, Register name, - Handle holder_obj, Runtime::FunctionId id) { - DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == - Runtime::FunctionForId(id)->nargs); - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ Push(name, receiver, holder); - - __ CallRuntime(id); -} - - // Generate call to api function. void PropertyHandlerCompiler::GenerateApiAccessorCall( MacroAssembler* masm, const CallOptimization& optimization, @@ -443,86 +427,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle name, Label* miss) { } } -void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( - LookupIterator* it, Register holder_reg) { - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - // 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. - DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1())); - - // Preserve the receiver register explicitly whenever it is different from the - // holder and it is needed should the interceptor return without any result. - // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD - // case might cause a miss during the prototype check. - bool must_perform_prototype_check = - !holder().is_identical_to(it->GetHolder()); - bool must_preserve_receiver_reg = - !receiver().is(holder_reg) && - (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check); - - // Save necessary data before invoking an interceptor. - // Requires a frame to make GC aware of pushed pointers. - { - FrameAndConstantPoolScope frame_scope(masm(), StackFrame::INTERNAL); - if (must_preserve_receiver_reg) { - __ Push(receiver(), holder_reg, this->name()); - } else { - __ Push(holder_reg, this->name()); - } - InterceptorVectorSlotPush(holder_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, this->name(), holder(), - Runtime::kLoadPropertyWithInterceptorOnly); - - // Check if interceptor provided a value for property. If it's - // the case, return immediately. - Label interceptor_failed; - __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex); - __ cmp(r3, scratch1()); - __ beq(&interceptor_failed); - frame_scope.GenerateLeaveFrame(); - __ Ret(); - - __ bind(&interceptor_failed); - InterceptorVectorSlotPop(holder_reg); - __ pop(this->name()); - __ pop(holder_reg); - if (must_preserve_receiver_reg) { - __ pop(receiver()); - } - // Leave the internal frame. - } - - GenerateLoadPostInterceptor(it, holder_reg); -} - - -void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { - // Call the runtime system to load the interceptor. - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ Push(name(), receiver(), holder_reg); - // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details. - if (holder_reg.is(receiver())) { - __ Push(slot(), vector()); - } else { - __ Push(scratch3(), scratch2()); // slot, vector - } - - __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); -} - void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() { STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack); } diff --git a/deps/v8/src/ic/s390/handler-compiler-s390.cc b/deps/v8/src/ic/s390/handler-compiler-s390.cc index 02f53339caa2db..4ae1f3503cd9e7 100644 --- a/deps/v8/src/ic/s390/handler-compiler-s390.cc +++ b/deps/v8/src/ic/s390/handler-compiler-s390.cc @@ -186,21 +186,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell( __ bne(miss); } -static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, Register receiver, Register holder, Register name, - Handle holder_obj, Runtime::FunctionId id) { - DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == - Runtime::FunctionForId(id)->nargs); - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ Push(name, receiver, holder); - - __ CallRuntime(id); -} - // Generate call to api function. void PropertyHandlerCompiler::GenerateApiAccessorCall( MacroAssembler* masm, const CallOptimization& optimization, @@ -425,84 +410,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle name, Label* miss) { } } -void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( - LookupIterator* it, Register holder_reg) { - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - // 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. - DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1())); - - // Preserve the receiver register explicitly whenever it is different from the - // holder and it is needed should the interceptor return without any result. - // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD - // case might cause a miss during the prototype check. - bool must_perform_prototype_check = - !holder().is_identical_to(it->GetHolder()); - bool must_preserve_receiver_reg = - !receiver().is(holder_reg) && - (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check); - - // Save necessary data before invoking an interceptor. - // Requires a frame to make GC aware of pushed pointers. - { - FrameScope frame_scope(masm(), StackFrame::INTERNAL); - if (must_preserve_receiver_reg) { - __ Push(receiver(), holder_reg, this->name()); - } else { - __ Push(holder_reg, this->name()); - } - InterceptorVectorSlotPush(holder_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, this->name(), holder(), - Runtime::kLoadPropertyWithInterceptorOnly); - - // Check if interceptor provided a value for property. If it's - // the case, return immediately. - Label interceptor_failed; - __ CompareRoot(r2, Heap::kNoInterceptorResultSentinelRootIndex); - __ beq(&interceptor_failed, Label::kNear); - frame_scope.GenerateLeaveFrame(); - __ Ret(); - - __ bind(&interceptor_failed); - InterceptorVectorSlotPop(holder_reg); - __ Pop(this->name()); - __ Pop(holder_reg); - if (must_preserve_receiver_reg) { - __ Pop(receiver()); - } - // Leave the internal frame. - } - - GenerateLoadPostInterceptor(it, holder_reg); -} - -void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { - // Call the runtime system to load the interceptor. - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ Push(name(), receiver(), holder_reg); - // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details. - if (holder_reg.is(receiver())) { - __ Push(slot(), vector()); - } else { - __ Push(scratch3(), scratch2()); // slot, vector - } - - __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); -} - void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() { STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack); } diff --git a/deps/v8/src/ic/x64/handler-compiler-x64.cc b/deps/v8/src/ic/x64/handler-compiler-x64.cc index 88bacad47bb637..cf141db8f1c3ce 100644 --- a/deps/v8/src/ic/x64/handler-compiler-x64.cc +++ b/deps/v8/src/ic/x64/handler-compiler-x64.cc @@ -83,24 +83,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( __ DecrementCounter(counters->negative_lookups_miss(), 1); } -static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, Register receiver, Register holder, Register name, - Handle holder_obj, Runtime::FunctionId id) { - DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == - Runtime::FunctionForId(id)->nargs); - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ Push(name); - __ Push(receiver); - __ Push(holder); - - __ CallRuntime(id); -} - - // Generate call to api function. void PropertyHandlerCompiler::GenerateApiAccessorCall( MacroAssembler* masm, const CallOptimization& optimization, @@ -437,96 +419,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle name, Label* miss) { } } -void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( - LookupIterator* it, Register holder_reg) { - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - // 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. - DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1())); - - // Preserve the receiver register explicitly whenever it is different from the - // holder and it is needed should the interceptor return without any result. - // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD - // case might cause a miss during the prototype check. - bool must_perform_prototype_check = - !holder().is_identical_to(it->GetHolder()); - bool must_preserve_receiver_reg = - !receiver().is(holder_reg) && - (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check); - - // Save necessary data before invoking an interceptor. - // Requires a frame to make GC aware of pushed pointers. - { - FrameScope frame_scope(masm(), StackFrame::INTERNAL); - - if (must_preserve_receiver_reg) { - __ Push(receiver()); - } - __ Push(holder_reg); - __ Push(this->name()); - InterceptorVectorSlotPush(holder_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, this->name(), holder(), - Runtime::kLoadPropertyWithInterceptorOnly); - - // 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); - frame_scope.GenerateLeaveFrame(); - __ ret(0); - - __ bind(&interceptor_failed); - InterceptorVectorSlotPop(holder_reg); - __ Pop(this->name()); - __ Pop(holder_reg); - if (must_preserve_receiver_reg) { - __ Pop(receiver()); - } - - // Leave the internal frame. - } - - GenerateLoadPostInterceptor(it, holder_reg); -} - - -void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { - // Call the runtime system to load the interceptor. - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - // Stack: - // return address - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ Push(receiver()); - __ Push(holder_reg); - // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details. - if (holder_reg.is(receiver())) { - __ Push(slot()); - __ Push(vector()); - } else { - __ Push(scratch3()); // slot - __ Push(scratch2()); // vector - } - __ Push(Operand(rsp, 4 * kPointerSize)); // return address - __ movp(Operand(rsp, 5 * kPointerSize), name()); - - __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); -} - void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() { STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack); } diff --git a/deps/v8/src/ic/x87/handler-compiler-x87.cc b/deps/v8/src/ic/x87/handler-compiler-x87.cc index 6e5fe9f670b053..5851b018e35bcb 100644 --- a/deps/v8/src/ic/x87/handler-compiler-x87.cc +++ b/deps/v8/src/ic/x87/handler-compiler-x87.cc @@ -287,23 +287,6 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter( } } -static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, Register receiver, Register holder, Register name, - Handle holder_obj, Runtime::FunctionId id) { - DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength == - Runtime::FunctionForId(id)->nargs); - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ push(name); - __ push(receiver); - __ push(holder); - - __ CallRuntime(id); -} - #undef __ #define __ ACCESS_MASM(masm()) @@ -445,102 +428,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle name, Label* miss) { } } -void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( - LookupIterator* it, Register holder_reg) { - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - - // 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. - DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1())); - - // Preserve the receiver register explicitly whenever it is different from the - // holder and it is needed should the interceptor return without any result. - // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD - // case might cause a miss during the prototype check. - bool must_perform_prototype_check = - !holder().is_identical_to(it->GetHolder()); - bool must_preserve_receiver_reg = - !receiver().is(holder_reg) && - (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check); - - // Save necessary data before invoking an interceptor. - // Requires a frame to make GC aware of pushed pointers. - { - FrameScope frame_scope(masm(), StackFrame::INTERNAL); - - if (must_preserve_receiver_reg) { - __ push(receiver()); - } - __ push(holder_reg); - __ push(this->name()); - InterceptorVectorSlotPush(holder_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, this->name(), holder(), - Runtime::kLoadPropertyWithInterceptorOnly); - - // Check if interceptor provided a value for property. If it's - // the case, return immediately. - Label interceptor_failed; - __ cmp(eax, factory()->no_interceptor_result_sentinel()); - __ j(equal, &interceptor_failed); - frame_scope.GenerateLeaveFrame(); - __ ret(0); - - // Clobber registers when generating debug-code to provoke errors. - __ bind(&interceptor_failed); - if (FLAG_debug_code) { - __ mov(receiver(), Immediate(bit_cast(kZapValue))); - __ mov(holder_reg, Immediate(bit_cast(kZapValue))); - __ mov(this->name(), Immediate(bit_cast(kZapValue))); - } - - InterceptorVectorSlotPop(holder_reg); - __ pop(this->name()); - __ pop(holder_reg); - if (must_preserve_receiver_reg) { - __ pop(receiver()); - } - - // Leave the internal frame. - } - - GenerateLoadPostInterceptor(it, holder_reg); -} - - -void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) { - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate())); - // Call the runtime system to load the interceptor. - - // Stack: - // return address - - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3); - __ push(receiver()); - __ push(holder_reg); - // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details. - if (holder_reg.is(receiver())) { - __ push(slot()); - __ push(vector()); - } else { - __ push(scratch3()); // slot - __ push(scratch2()); // vector - } - __ push(Operand(esp, 4 * kPointerSize)); // return address - __ mov(Operand(esp, 5 * kPointerSize), name()); - - __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor); -} - void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() { // Zap register aliases of the arguments passed on the stack to ensure they // are properly loaded by the handler (debug-only). diff --git a/deps/v8/src/isolate.cc b/deps/v8/src/isolate.cc index 52c313b5b582b2..50692c167954c4 100644 --- a/deps/v8/src/isolate.cc +++ b/deps/v8/src/isolate.cc @@ -537,9 +537,26 @@ Handle Isolate::CaptureSimpleStackTrace(Handle error_object, abstract_code, offset, flags); } break; - case StackFrame::WASM_INTERPRETER_ENTRY: - // TODO(clemensh): Add frames. - break; + case StackFrame::WASM_INTERPRETER_ENTRY: { + WasmInterpreterEntryFrame* interpreter_frame = + WasmInterpreterEntryFrame::cast(frame); + Handle instance(interpreter_frame->wasm_instance(), + this); + // Get the interpreted stack ( pairs). + std::vector> interpreted_stack = + instance->debug_info()->GetInterpretedStack( + interpreter_frame->fp()); + + // interpreted_stack is bottom-up, i.e. caller before callee. We need it + // the other way around. + for (auto it = interpreted_stack.rbegin(), + end = interpreted_stack.rend(); + it != end; ++it) { + elements = FrameArray::AppendWasmFrame( + elements, instance, it->first, Handle::null(), + it->second, FrameArray::kIsWasmInterpretedFrame); + } + } break; default: break; diff --git a/deps/v8/src/keys.cc b/deps/v8/src/keys.cc index af3d393f07e635..da26263fc49c2e 100644 --- a/deps/v8/src/keys.cc +++ b/deps/v8/src/keys.cc @@ -712,6 +712,17 @@ Handle KeyAccumulator::GetOwnEnumPropertyKeys( } } +namespace { + +struct NameComparator { + bool operator()(uint32_t hash1, uint32_t hash2, const Handle& key1, + const Handle& key2) const { + return Name::Equals(key1, key2); + } +}; + +} // namespace + // ES6 9.5.12 // Returns |true| on success, |nothing| in case of exception. Maybe KeyAccumulator::CollectOwnJSProxyKeys(Handle receiver, @@ -800,33 +811,36 @@ Maybe KeyAccumulator::CollectOwnJSProxyKeys(Handle receiver, } // 16. Let uncheckedResultKeys be a new List which is a copy of trapResult. Zone set_zone(isolate_->allocator(), ZONE_NAME); + ZoneAllocationPolicy alloc(&set_zone); const int kPresent = 1; const int kGone = 0; - IdentityMap unchecked_result_keys( - isolate_->heap(), ZoneAllocationPolicy(&set_zone)); + base::TemplateHashMapImpl, int, NameComparator, + ZoneAllocationPolicy> + unchecked_result_keys(ZoneHashMap::kDefaultHashMapCapacity, + NameComparator(), alloc); int unchecked_result_keys_size = 0; for (int i = 0; i < trap_result->length(); ++i) { - DCHECK(trap_result->get(i)->IsUniqueName()); - Object* key = trap_result->get(i); - int* entry = unchecked_result_keys.Get(key); - if (*entry != kPresent) { - *entry = kPresent; + Handle key(Name::cast(trap_result->get(i)), isolate_); + auto entry = unchecked_result_keys.LookupOrInsert(key, key->Hash(), alloc); + if (entry->value != kPresent) { + entry->value = kPresent; unchecked_result_keys_size++; } } // 17. Repeat, for each key that is an element of targetNonconfigurableKeys: for (int i = 0; i < nonconfigurable_keys_length; ++i) { - Object* key = target_nonconfigurable_keys->get(i); + Object* raw_key = target_nonconfigurable_keys->get(i); + Handle key(Name::cast(raw_key), isolate_); // 17a. If key is not an element of uncheckedResultKeys, throw a // TypeError exception. - int* found = unchecked_result_keys.Find(key); - if (found == nullptr || *found == kGone) { + auto found = unchecked_result_keys.Lookup(key, key->Hash()); + if (found == nullptr || found->value == kGone) { isolate_->Throw(*isolate_->factory()->NewTypeError( - MessageTemplate::kProxyOwnKeysMissing, handle(key, isolate_))); + MessageTemplate::kProxyOwnKeysMissing, key)); return Nothing(); } // 17b. Remove key from uncheckedResultKeys. - *found = kGone; + found->value = kGone; unchecked_result_keys_size--; } // 18. If extensibleTarget is true, return trapResult. @@ -835,18 +849,19 @@ Maybe KeyAccumulator::CollectOwnJSProxyKeys(Handle receiver, } // 19. Repeat, for each key that is an element of targetConfigurableKeys: for (int i = 0; i < target_configurable_keys->length(); ++i) { - Object* key = target_configurable_keys->get(i); - if (key->IsSmi()) continue; // Zapped entry, was nonconfigurable. + Object* raw_key = target_configurable_keys->get(i); + if (raw_key->IsSmi()) continue; // Zapped entry, was nonconfigurable. + Handle key(Name::cast(raw_key), isolate_); // 19a. If key is not an element of uncheckedResultKeys, throw a // TypeError exception. - int* found = unchecked_result_keys.Find(key); - if (found == nullptr || *found == kGone) { + auto found = unchecked_result_keys.Lookup(key, key->Hash()); + if (found == nullptr || found->value == kGone) { isolate_->Throw(*isolate_->factory()->NewTypeError( - MessageTemplate::kProxyOwnKeysMissing, handle(key, isolate_))); + MessageTemplate::kProxyOwnKeysMissing, key)); return Nothing(); } // 19b. Remove key from uncheckedResultKeys. - *found = kGone; + found->value = kGone; unchecked_result_keys_size--; } // 20. If uncheckedResultKeys is not empty, throw a TypeError exception. diff --git a/deps/v8/src/messages.cc b/deps/v8/src/messages.cc index b5150ef400eedb..2019b40d228009 100644 --- a/deps/v8/src/messages.cc +++ b/deps/v8/src/messages.cc @@ -639,12 +639,19 @@ WasmStackFrame::WasmStackFrame() {} void WasmStackFrame::FromFrameArray(Isolate* isolate, Handle array, int frame_ix) { - // This function is called for both wasm and asm.js->wasm frames. - DCHECK(array->IsWasmFrame(frame_ix) || array->IsAsmJsWasmFrame(frame_ix)); + // This function is called for compiled and interpreted wasm frames, and for + // asm.js->wasm frames. + DCHECK(array->IsWasmFrame(frame_ix) || + array->IsWasmInterpretedFrame(frame_ix) || + array->IsAsmJsWasmFrame(frame_ix)); isolate_ = isolate; wasm_instance_ = handle(array->WasmInstance(frame_ix), isolate); wasm_func_index_ = array->WasmFunctionIndex(frame_ix)->value(); - code_ = handle(array->Code(frame_ix), isolate); + if (array->IsWasmInterpretedFrame(frame_ix)) { + code_ = Handle::null(); + } else { + code_ = handle(array->Code(frame_ix), isolate); + } offset_ = array->Offset(frame_ix)->value(); } @@ -692,6 +699,7 @@ MaybeHandle WasmStackFrame::ToString() { } int WasmStackFrame::GetPosition() const { + if (IsInterpreted()) return offset_; // TODO(wasm): Clean this up (bug 5007). return (offset_ < 0) ? (-1 - offset_) : code_->SourcePosition(offset_); } @@ -802,13 +810,17 @@ void FrameArrayIterator::Next() { next_frame_ix_++; } StackFrameBase* FrameArrayIterator::Frame() { DCHECK(HasNext()); const int flags = array_->Flags(next_frame_ix_)->value(); - switch (flags & (FrameArray::kIsWasmFrame | FrameArray::kIsAsmJsWasmFrame)) { + int flag_mask = FrameArray::kIsWasmFrame | + FrameArray::kIsWasmInterpretedFrame | + FrameArray::kIsAsmJsWasmFrame; + switch (flags & flag_mask) { case 0: // JavaScript Frame. js_frame_.FromFrameArray(isolate_, array_, next_frame_ix_); return &js_frame_; case FrameArray::kIsWasmFrame: - // Wasm Frame; + case FrameArray::kIsWasmInterpretedFrame: + // Wasm Frame: wasm_frame_.FromFrameArray(isolate_, array_, next_frame_ix_); return &wasm_frame_; case FrameArray::kIsAsmJsWasmFrame: diff --git a/deps/v8/src/messages.h b/deps/v8/src/messages.h index bb595c2f8a5071..4bdfcce0c1171e 100644 --- a/deps/v8/src/messages.h +++ b/deps/v8/src/messages.h @@ -149,6 +149,7 @@ class WasmStackFrame : public StackFrameBase { bool IsToplevel() override { return false; } bool IsConstructor() override { return false; } bool IsStrict() const override { return false; } + bool IsInterpreted() const { return code_.is_null(); } MaybeHandle ToString() override; @@ -161,7 +162,7 @@ class WasmStackFrame : public StackFrameBase { // TODO(wasm): Use proper typing. Handle wasm_instance_; uint32_t wasm_func_index_; - Handle code_; + Handle code_; // null handle for interpreted frames. int offset_; private: diff --git a/deps/v8/src/mips/macro-assembler-mips.cc b/deps/v8/src/mips/macro-assembler-mips.cc index a28c04a8e21f9d..3226d9373f6010 100644 --- a/deps/v8/src/mips/macro-assembler-mips.cc +++ b/deps/v8/src/mips/macro-assembler-mips.cc @@ -4722,20 +4722,6 @@ void MacroAssembler::IsObjectNameType(Register object, // --------------------------------------------------------------------------- // Support functions. - -void MacroAssembler::GetMapConstructor(Register result, Register map, - Register temp, Register temp2) { - Label done, loop; - lw(result, FieldMemOperand(map, Map::kConstructorOrBackPointerOffset)); - bind(&loop); - JumpIfSmi(result, &done); - GetObjectType(result, temp, temp2); - Branch(&done, ne, temp2, Operand(MAP_TYPE)); - lw(result, FieldMemOperand(result, Map::kConstructorOrBackPointerOffset)); - Branch(&loop); - bind(&done); -} - void MacroAssembler::GetObjectType(Register object, Register map, Register type_reg) { diff --git a/deps/v8/src/mips/macro-assembler-mips.h b/deps/v8/src/mips/macro-assembler-mips.h index e202e3bc91ecb3..dee6a0a3d73575 100644 --- a/deps/v8/src/mips/macro-assembler-mips.h +++ b/deps/v8/src/mips/macro-assembler-mips.h @@ -1101,11 +1101,6 @@ class MacroAssembler: public Assembler { // ------------------------------------------------------------------------- // Support functions. - // Machine code version of Map::GetConstructor(). - // |temp| holds |result|'s map when done, and |temp2| its instance type. - void GetMapConstructor(Register result, Register map, Register temp, - Register temp2); - void GetObjectType(Register function, Register map, Register type_reg); diff --git a/deps/v8/src/mips64/macro-assembler-mips64.cc b/deps/v8/src/mips64/macro-assembler-mips64.cc index 849327e60b7069..829293f1a0d76a 100644 --- a/deps/v8/src/mips64/macro-assembler-mips64.cc +++ b/deps/v8/src/mips64/macro-assembler-mips64.cc @@ -4914,19 +4914,6 @@ void MacroAssembler::IsObjectNameType(Register object, // Support functions. -void MacroAssembler::GetMapConstructor(Register result, Register map, - Register temp, Register temp2) { - Label done, loop; - ld(result, FieldMemOperand(map, Map::kConstructorOrBackPointerOffset)); - bind(&loop); - JumpIfSmi(result, &done); - GetObjectType(result, temp, temp2); - Branch(&done, ne, temp2, Operand(MAP_TYPE)); - ld(result, FieldMemOperand(result, Map::kConstructorOrBackPointerOffset)); - Branch(&loop); - bind(&done); -} - void MacroAssembler::GetObjectType(Register object, Register map, Register type_reg) { diff --git a/deps/v8/src/mips64/macro-assembler-mips64.h b/deps/v8/src/mips64/macro-assembler-mips64.h index bfb1d520b4dccb..0bb0ad099badea 100644 --- a/deps/v8/src/mips64/macro-assembler-mips64.h +++ b/deps/v8/src/mips64/macro-assembler-mips64.h @@ -1155,11 +1155,6 @@ class MacroAssembler: public Assembler { // ------------------------------------------------------------------------- // Support functions. - // Machine code version of Map::GetConstructor(). - // |temp| holds |result|'s map when done, and |temp2| its instance type. - void GetMapConstructor(Register result, Register map, Register temp, - Register temp2); - void GetObjectType(Register function, Register map, Register type_reg); diff --git a/deps/v8/src/objects-debug.cc b/deps/v8/src/objects-debug.cc index 97ba4f4cc83018..64c90b7d1a1204 100644 --- a/deps/v8/src/objects-debug.cc +++ b/deps/v8/src/objects-debug.cc @@ -694,8 +694,6 @@ void Oddball::OddballVerify() { this == heap->false_value()); } else if (map() == heap->uninitialized_map()) { CHECK(this == heap->uninitialized_value()); - } else if (map() == heap->no_interceptor_result_sentinel_map()) { - CHECK(this == heap->no_interceptor_result_sentinel()); } else if (map() == heap->arguments_marker_map()) { CHECK(this == heap->arguments_marker()); } else if (map() == heap->termination_exception_map()) { diff --git a/deps/v8/src/objects-inl.h b/deps/v8/src/objects-inl.h index c142e9a36ef25a..b2b72ac1c4aa14 100644 --- a/deps/v8/src/objects-inl.h +++ b/deps/v8/src/objects-inl.h @@ -2690,6 +2690,11 @@ bool FrameArray::IsWasmFrame(int frame_ix) const { return (flags & kIsWasmFrame) != 0; } +bool FrameArray::IsWasmInterpretedFrame(int frame_ix) const { + const int flags = Flags(frame_ix)->value(); + return (flags & kIsWasmInterpretedFrame) != 0; +} + bool FrameArray::IsAsmJsWasmFrame(int frame_ix) const { const int flags = Flags(frame_ix)->value(); return (flags & kIsAsmJsWasmFrame) != 0; @@ -5966,6 +5971,8 @@ BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_declaration, kIsDeclaration) BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, marked_for_tier_up, kMarkedForTierUp) +BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, + has_concurrent_optimization_job, kHasConcurrentOptimizationJob) BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, needs_home_object, kNeedsHomeObject) diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc index 7688422a2c7d05..56b666fb8126f7 100644 --- a/deps/v8/src/objects.cc +++ b/deps/v8/src/objects.cc @@ -10010,8 +10010,7 @@ Handle EnsureSpaceInFixedArray(Handle array, int new_capacity = length; new_capacity = new_capacity + Max(new_capacity / 2, 2); int grow_by = new_capacity - capacity; - array = Handle::cast( - isolate->factory()->CopyFixedArrayAndGrow(array, grow_by)); + array = isolate->factory()->CopyFixedArrayAndGrow(array, grow_by); } return array; } @@ -10064,7 +10063,8 @@ Handle FrameArray::AppendWasmFrame(Handle in, Handle array = EnsureSpace(in, new_length); array->SetWasmInstance(frame_count, *wasm_instance); array->SetWasmFunctionIndex(frame_count, Smi::FromInt(wasm_function_index)); - array->SetCode(frame_count, *code); + // code will be a null handle for interpreted wasm frames. + if (!code.is_null()) array->SetCode(frame_count, *code); array->SetOffset(frame_count, Smi::FromInt(offset)); array->SetFlags(frame_count, Smi::FromInt(flags)); array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1)); diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index e8415fc4fcf44c..fadc5011a81e87 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -2984,17 +2984,21 @@ class FrameArray : public FixedArray { #undef DECLARE_FRAME_ARRAY_ACCESSORS inline bool IsWasmFrame(int frame_ix) const; + inline bool IsWasmInterpretedFrame(int frame_ix) const; inline bool IsAsmJsWasmFrame(int frame_ix) const; inline int FrameCount() const; void ShrinkToFit(); // Flags. - static const int kIsWasmFrame = 1 << 0; - static const int kIsAsmJsWasmFrame = 1 << 1; - static const int kIsStrict = 1 << 2; - static const int kForceConstructor = 1 << 3; - static const int kAsmJsAtNumberConversion = 1 << 4; + enum Flag { + kIsWasmFrame = 1 << 0, + kIsWasmInterpretedFrame = 1 << 1, + kIsAsmJsWasmFrame = 1 << 2, + kIsStrict = 1 << 3, + kForceConstructor = 1 << 4, + kAsmJsAtNumberConversion = 1 << 5 + }; static Handle AppendJSFrame(Handle in, Handle receiver, @@ -7255,6 +7259,9 @@ class SharedFunctionInfo: public HeapObject { // Whether this function was marked to be tiered up. DECL_BOOLEAN_ACCESSORS(marked_for_tier_up) + // Whether this function has a concurrent compilation job running. + DECL_BOOLEAN_ACCESSORS(has_concurrent_optimization_job) + // Indicates that asm->wasm conversion failed and should not be re-attempted. DECL_BOOLEAN_ACCESSORS(is_asm_wasm_broken) @@ -7537,9 +7544,9 @@ class SharedFunctionInfo: public HeapObject { kDontFlush, kIsDeclaration, kIsAsmWasmBroken, + kHasConcurrentOptimizationJob, kUnused1, // Unused fields. - kUnused2, // byte 2 kFunctionKind, diff --git a/deps/v8/src/ppc/macro-assembler-ppc.cc b/deps/v8/src/ppc/macro-assembler-ppc.cc index f2aa2e06f4e491..be32cdeb4bcf0a 100644 --- a/deps/v8/src/ppc/macro-assembler-ppc.cc +++ b/deps/v8/src/ppc/macro-assembler-ppc.cc @@ -2125,19 +2125,6 @@ void MacroAssembler::LoadWeakValue(Register value, Handle cell, } -void MacroAssembler::GetMapConstructor(Register result, Register map, - Register temp, Register temp2) { - Label done, loop; - LoadP(result, FieldMemOperand(map, Map::kConstructorOrBackPointerOffset)); - bind(&loop); - JumpIfSmi(result, &done); - CompareObjectType(result, temp, temp2, MAP_TYPE); - bne(&done); - LoadP(result, FieldMemOperand(result, Map::kConstructorOrBackPointerOffset)); - b(&loop); - bind(&done); -} - void MacroAssembler::CallStub(CodeStub* stub, TypeFeedbackId ast_id, Condition cond) { DCHECK(AllowThisStubCall(stub)); // Stub calls are not allowed in some stubs. diff --git a/deps/v8/src/ppc/macro-assembler-ppc.h b/deps/v8/src/ppc/macro-assembler-ppc.h index a1d2932f43f158..d911509918d8ac 100644 --- a/deps/v8/src/ppc/macro-assembler-ppc.h +++ b/deps/v8/src/ppc/macro-assembler-ppc.h @@ -744,11 +744,6 @@ class MacroAssembler : public Assembler { // --------------------------------------------------------------------------- // Support functions. - // Machine code version of Map::GetConstructor(). - // |temp| holds |result|'s map when done, and |temp2| its instance type. - void GetMapConstructor(Register result, Register map, Register temp, - Register temp2); - // Compare object type for heap object. heap_object contains a non-Smi // whose object type should be compared with the given type. This both // sets the flags and leaves the object type in the type_reg register. diff --git a/deps/v8/src/runtime/runtime.h b/deps/v8/src/runtime/runtime.h index d7c3a02fc7faed..355522afb770e8 100644 --- a/deps/v8/src/runtime/runtime.h +++ b/deps/v8/src/runtime/runtime.h @@ -658,7 +658,6 @@ namespace internal { F(LoadGlobalIC_Slow, 3, 1) \ F(LoadIC_Miss, 4, 1) \ F(LoadPropertyWithInterceptor, 5, 1) \ - F(LoadPropertyWithInterceptorOnly, 3, 1) \ F(StoreCallbackProperty, 6, 1) \ F(StoreIC_Miss, 5, 1) \ F(StorePropertyWithInterceptor, 5, 1) \ diff --git a/deps/v8/src/s390/macro-assembler-s390.cc b/deps/v8/src/s390/macro-assembler-s390.cc index 220184f1310bbe..877fcfade57869 100644 --- a/deps/v8/src/s390/macro-assembler-s390.cc +++ b/deps/v8/src/s390/macro-assembler-s390.cc @@ -1944,19 +1944,6 @@ void MacroAssembler::LoadWeakValue(Register value, Handle cell, JumpIfSmi(value, miss); } -void MacroAssembler::GetMapConstructor(Register result, Register map, - Register temp, Register temp2) { - Label done, loop; - LoadP(result, FieldMemOperand(map, Map::kConstructorOrBackPointerOffset)); - bind(&loop); - JumpIfSmi(result, &done); - CompareObjectType(result, temp, temp2, MAP_TYPE); - bne(&done); - LoadP(result, FieldMemOperand(result, Map::kConstructorOrBackPointerOffset)); - b(&loop); - bind(&done); -} - void MacroAssembler::CallStub(CodeStub* stub, TypeFeedbackId ast_id, Condition cond) { DCHECK(AllowThisStubCall(stub)); // Stub calls are not allowed in some stubs. diff --git a/deps/v8/src/s390/macro-assembler-s390.h b/deps/v8/src/s390/macro-assembler-s390.h index 60be4c68945bba..4adcd4f964afeb 100644 --- a/deps/v8/src/s390/macro-assembler-s390.h +++ b/deps/v8/src/s390/macro-assembler-s390.h @@ -1076,11 +1076,6 @@ class MacroAssembler : public Assembler { // --------------------------------------------------------------------------- // Support functions. - // Machine code version of Map::GetConstructor(). - // |temp| holds |result|'s map when done, and |temp2| its instance type. - void GetMapConstructor(Register result, Register map, Register temp, - Register temp2); - // Compare object type for heap object. heap_object contains a non-Smi // whose object type should be compared with the given type. This both // sets the flags and leaves the object type in the type_reg register. diff --git a/deps/v8/src/trap-handler/DEPS b/deps/v8/src/trap-handler/DEPS new file mode 100644 index 00000000000000..681cbd8825f809 --- /dev/null +++ b/deps/v8/src/trap-handler/DEPS @@ -0,0 +1,17 @@ +# In order to make it easier to audit the signal handler code, we use very +# restrictive include rules to limit the amount of code that the signal handler +# can depend on. + +include_rules = [ + "-src", + "-include", + "+src/trap-handler", +] + +specific_include_rules = { + "trap-handler.h": [ + "+src/base/build_config.h", + "+src/globals.h", + "+src/flags.h", + ] +} diff --git a/deps/v8/src/trap-handler/OWNERS b/deps/v8/src/trap-handler/OWNERS new file mode 100644 index 00000000000000..e44dd971554432 --- /dev/null +++ b/deps/v8/src/trap-handler/OWNERS @@ -0,0 +1,10 @@ +set noparent + +jochen@chromium.org +bradnelson@chromium.org + +# Changes to this directory should also be reviewed by: +# +# eholk@chromium.org +# mseaborn@chromium.org +# mark@chromium.org diff --git a/deps/v8/src/trap-handler/handler-inside.cc b/deps/v8/src/trap-handler/handler-inside.cc new file mode 100644 index 00000000000000..a51bd9427f0c95 --- /dev/null +++ b/deps/v8/src/trap-handler/handler-inside.cc @@ -0,0 +1,170 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// PLEASE READ BEFORE CHANGING THIS FILE! +// +// This file implements the out of bounds signal handler for +// WebAssembly. Signal handlers are notoriously difficult to get +// right, and getting it wrong can lead to security +// vulnerabilities. In order to minimize this risk, here are some +// rules to follow. +// +// 1. Do not introduce any new external dependencies. This file needs +// to be self contained so it is easy to audit everything that a +// signal handler might do. +// +// 2. Any changes must be reviewed by someone from the crash reporting +// or security team. See OWNERS for suggested reviewers. +// +// For more information, see https://goo.gl/yMeyUY. +// +// This file contains most of the code that actually runs in a signal handler +// context. Some additional code is used both inside and outside the signal +// handler. This code can be found in handler-shared.cc. + +#include +#include +#include + +#include "src/trap-handler/trap-handler-internal.h" +#include "src/trap-handler/trap-handler.h" + +namespace v8 { +namespace internal { +namespace trap_handler { + +namespace { + +bool IsKernelGeneratedSignal(siginfo_t* info) { + return info->si_code > 0 && info->si_code != SI_USER && + info->si_code != SI_QUEUE && info->si_code != SI_TIMER && + info->si_code != SI_ASYNCIO && info->si_code != SI_MESGQ; +} + +#if V8_TRAP_HANDLER_SUPPORTED +class SigUnmaskStack { + public: + explicit SigUnmaskStack(sigset_t sigs) { + // TODO(eholk): consider using linux-syscall-support for calling this + // syscall. + pthread_sigmask(SIG_UNBLOCK, &sigs, &old_mask_); + } + + ~SigUnmaskStack() { pthread_sigmask(SIG_SETMASK, &old_mask_, nullptr); } + + private: + sigset_t old_mask_; + + // We'd normally use DISALLOW_COPY_AND_ASSIGN, but we're avoiding a dependency + // on base/macros.h + SigUnmaskStack(const SigUnmaskStack&) = delete; + void operator=(const SigUnmaskStack&) = delete; +}; +#endif +} // namespace + +#if V8_TRAP_HANDLER_SUPPORTED && V8_OS_LINUX +bool TryHandleSignal(int signum, siginfo_t* info, ucontext_t* context) { + // Bail out early in case we got called for the wrong kind of signal. + if (signum != SIGSEGV) { + return false; + } + + // Make sure the signal was generated by the kernel and not some other source. + if (!IsKernelGeneratedSignal(info)) { + return false; + } + + // Ensure the faulting thread was actually running Wasm code. + if (!IsThreadInWasm()) { + return false; + } + + // Clear g_thread_in_wasm_code, primarily to protect against nested faults. + g_thread_in_wasm_code = false; + + // Begin signal mask scope. We need to be sure to restore the signal mask + // before we restore the g_thread_in_wasm_code flag. + { + // Unmask the signal so that if this signal handler crashes, the crash will + // be handled by the crash reporter. Otherwise, the process might be killed + // with the crash going unreported. + sigset_t sigs; + // Fortunately, sigemptyset and sigaddset are async-signal-safe according to + // the POSIX standard. + sigemptyset(&sigs); + sigaddset(&sigs, SIGSEGV); + SigUnmaskStack unmask(sigs); + + uintptr_t fault_addr = context->uc_mcontext.gregs[REG_RIP]; + + // TODO(eholk): broad code range check + + // Taking locks in a signal handler is risky because a fault in the signal + // handler could lead to a deadlock when attempting to acquire the lock + // again. We guard against this case with g_thread_in_wasm_code. The lock + // may only be taken when not executing Wasm code (an assert in + // MetadataLock's constructor ensures this). This signal handler will bail + // out before trying to take the lock if g_thread_in_wasm_code is not set. + MetadataLock lock_holder; + + for (size_t i = 0; i < gNumCodeObjects; ++i) { + const CodeProtectionInfo* data = gCodeObjects[i].code_info; + if (data == nullptr) { + continue; + } + const uintptr_t base = reinterpret_cast(data->base); + + if (fault_addr >= base && fault_addr < base + data->size) { + // Hurray, we found the code object. Check for protected addresses. + const ptrdiff_t offset = fault_addr - base; + + for (unsigned i = 0; i < data->num_protected_instructions; ++i) { + if (data->instructions[i].instr_offset == offset) { + // Hurray again, we found the actual instruction. Tell the caller to + // return to the landing pad. + context->uc_mcontext.gregs[REG_RIP] = + data->instructions[i].landing_offset + base; + return true; + } + } + } + } + } // end signal mask scope + + // If we get here, it's not a recoverable wasm fault, so we go to the next + // handler. + g_thread_in_wasm_code = true; + return false; +} +#endif // V8_TRAP_HANDLER_SUPPORTED && V8_OS_LINUX + +#if V8_TRAP_HANDLER_SUPPORTED +void HandleSignal(int signum, siginfo_t* info, void* context) { + ucontext_t* uc = reinterpret_cast(context); + + if (!TryHandleSignal(signum, info, uc)) { + // Since V8 didn't handle this signal, we want to re-raise the same signal. + // For kernel-generated SEGV signals, we do this by restoring the default + // SEGV handler and then returning. The fault will happen again and the + // usual SEGV handling will happen. + // + // We handle user-generated signals by calling raise() instead. This is for + // completeness. We should never actually see one of these, but just in + // case, we do the right thing. + struct sigaction action; + action.sa_handler = SIG_DFL; + sigemptyset(&action.sa_mask); + action.sa_flags = 0; + sigaction(signum, &action, nullptr); + if (!IsKernelGeneratedSignal(info)) { + raise(signum); + } + } + // TryHandleSignal modifies context to change where we return to. +} +#endif +} // namespace trap_handler +} // namespace internal +} // namespace v8 diff --git a/deps/v8/src/trap-handler/handler-outside.cc b/deps/v8/src/trap-handler/handler-outside.cc new file mode 100644 index 00000000000000..ea1500e67e67ec --- /dev/null +++ b/deps/v8/src/trap-handler/handler-outside.cc @@ -0,0 +1,191 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// PLEASE READ BEFORE CHANGING THIS FILE! +// +// This file implements the support code for the out of bounds signal handler. +// Nothing in here actually runs in the signal handler, but the code here +// manipulates data structures used by the signal handler so we still need to be +// careful. In order to minimize this risk, here are some rules to follow. +// +// 1. Avoid introducing new external dependencies. The files in src/trap-handler +// should be as self-contained as possible to make it easy to audit the code. +// +// 2. Any changes must be reviewed by someone from the crash reporting +// or security team. Se OWNERS for suggested reviewers. +// +// For more information, see https://goo.gl/yMeyUY. +// +// For the code that runs in the signal handler itself, see handler-inside.cc. + +#include +#include +#include +#include +#include + +#include +#include + +#include "src/trap-handler/trap-handler-internal.h" +#include "src/trap-handler/trap-handler.h" + +namespace { +size_t gNextCodeObject = 0; +} + +namespace v8 { +namespace internal { +namespace trap_handler { + +const size_t kInitialCodeObjectSize = 1024; +const size_t kCodeObjectGrowthFactor = 2; + +constexpr size_t HandlerDataSize(size_t num_protected_instructions) { + return offsetof(CodeProtectionInfo, instructions) + + num_protected_instructions * sizeof(ProtectedInstructionData); +} + +CodeProtectionInfo* CreateHandlerData( + void* base, size_t size, size_t num_protected_instructions, + ProtectedInstructionData* protected_instructions) { + const size_t alloc_size = HandlerDataSize(num_protected_instructions); + CodeProtectionInfo* data = + reinterpret_cast(malloc(alloc_size)); + + if (data == nullptr) { + return nullptr; + } + + data->base = base; + data->size = size; + data->num_protected_instructions = num_protected_instructions; + + memcpy(data->instructions, protected_instructions, + num_protected_instructions * sizeof(ProtectedInstructionData)); + + return data; +} + +void UpdateHandlerDataCodePointer(int index, void* base) { + MetadataLock lock; + if (static_cast(index) >= gNumCodeObjects) { + abort(); + } + CodeProtectionInfo* data = gCodeObjects[index].code_info; + data->base = base; +} + +int RegisterHandlerData(void* base, size_t size, + size_t num_protected_instructions, + ProtectedInstructionData* protected_instructions) { + // TODO(eholk): in debug builds, make sure this data isn't already registered. + + CodeProtectionInfo* data = CreateHandlerData( + base, size, num_protected_instructions, protected_instructions); + + if (data == nullptr) { + abort(); + } + + MetadataLock lock; + + size_t i = gNextCodeObject; + + // Explicitly convert std::numeric_limits::max() to unsigned to avoid + // compiler warnings about signed/unsigned comparisons. We aren't worried + // about sign extension because we know std::numeric_limits::max() is + // positive. + const size_t int_max = std::numeric_limits::max(); + + // We didn't find an opening in the available space, so grow. + if (i == gNumCodeObjects) { + size_t new_size = gNumCodeObjects > 0 + ? gNumCodeObjects * kCodeObjectGrowthFactor + : kInitialCodeObjectSize; + + // Because we must return an int, there is no point in allocating space for + // more objects than can fit in an int. + if (new_size > int_max) { + new_size = int_max; + } + if (new_size == gNumCodeObjects) { + return -1; + } + + // Now that we know our new size is valid, we can go ahead and realloc the + // array. + gCodeObjects = static_cast( + realloc(gCodeObjects, sizeof(*gCodeObjects) * new_size)); + + if (gCodeObjects == nullptr) { + abort(); + } + + memset(gCodeObjects + gNumCodeObjects, 0, + sizeof(*gCodeObjects) * (new_size - gNumCodeObjects)); + gNumCodeObjects = new_size; + } + + DCHECK(gCodeObjects[i].code_info == nullptr); + + // Find out where the next entry should go. + if (gCodeObjects[i].next_free == 0) { + // if this is a fresh entry, use the next one. + gNextCodeObject = i + 1; + DCHECK(gNextCodeObject == gNumCodeObjects || + (gCodeObjects[gNextCodeObject].code_info == nullptr && + gCodeObjects[gNextCodeObject].next_free == 0)); + } else { + gNextCodeObject = gCodeObjects[i].next_free - 1; + } + + if (i <= int_max) { + gCodeObjects[i].code_info = data; + return static_cast(i); + } else { + return -1; + } +} + +void ReleaseHandlerData(int index) { + // Remove the data from the global list if it's there. + CodeProtectionInfo* data = nullptr; + { + MetadataLock lock; + + data = gCodeObjects[index].code_info; + gCodeObjects[index].code_info = nullptr; + + // +1 because we reserve {next_entry == 0} to indicate a fresh list entry. + gCodeObjects[index].next_free = gNextCodeObject + 1; + gNextCodeObject = index; + } + // TODO(eholk): on debug builds, ensure there are no more copies in + // the list. + free(data); +} + +bool RegisterDefaultSignalHandler() { +#if V8_TRAP_HANDLER_SUPPORTED + struct sigaction action; + action.sa_sigaction = HandleSignal; + action.sa_flags = SA_SIGINFO; + sigemptyset(&action.sa_mask); + // {sigaction} installs a new custom segfault handler. On success, it returns + // 0. If we get a nonzero value, we report an error to the caller by returning + // false. + if (sigaction(SIGSEGV, &action, nullptr) != 0) { + return false; + } + + return true; +#else + return false; +#endif +} + +} // namespace trap_handler +} // namespace internal +} // namespace v8 diff --git a/deps/v8/src/trap-handler/handler-shared.cc b/deps/v8/src/trap-handler/handler-shared.cc new file mode 100644 index 00000000000000..7b399f5eeac1be --- /dev/null +++ b/deps/v8/src/trap-handler/handler-shared.cc @@ -0,0 +1,52 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// PLEASE READ BEFORE CHANGING THIS FILE! +// +// This file contains code that is used both inside and outside the out of +// bounds signal handler. Because this code runs in a signal handler context, +// use extra care when modifying this file. Here are some rules to follow. +// +// 1. Do not introduce any new external dependencies. This file needs +// to be self contained so it is easy to audit everything that a +// signal handler might do. +// +// 2. Any changes must be reviewed by someone from the crash reporting +// or security team. See OWNERS for suggested reviewers. +// +// For more information, see https://goo.gl/yMeyUY. + +#include "src/trap-handler/trap-handler-internal.h" + +namespace v8 { +namespace internal { +namespace trap_handler { + +THREAD_LOCAL bool g_thread_in_wasm_code = false; + +size_t gNumCodeObjects = 0; +CodeProtectionInfoListEntry* gCodeObjects = nullptr; + +std::atomic_flag MetadataLock::spinlock_ = ATOMIC_FLAG_INIT; + +MetadataLock::MetadataLock() { + if (g_thread_in_wasm_code) { + abort(); + } + + while (spinlock_.test_and_set(std::memory_order::memory_order_acquire)) { + } +} + +MetadataLock::~MetadataLock() { + if (g_thread_in_wasm_code) { + abort(); + } + + spinlock_.clear(std::memory_order::memory_order_release); +} + +} // namespace trap_handler +} // namespace internal +} // namespace v8 diff --git a/deps/v8/src/trap-handler/trap-handler-internal.h b/deps/v8/src/trap-handler/trap-handler-internal.h new file mode 100644 index 00000000000000..b4efd7ff9e3195 --- /dev/null +++ b/deps/v8/src/trap-handler/trap-handler-internal.h @@ -0,0 +1,67 @@ +// Copyright 2016 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef TRAP_HANDLER_INTERNAL_H_ +#define TRAP_HANDLER_INTERNAL_H_ + +// This file should not be included (even transitively) by files outside of +// src/trap-handler. + +#include "src/trap-handler/trap-handler.h" + +#include + +namespace v8 { +namespace internal { +namespace trap_handler { + +// This describes a chunk of code that the signal handler will be able to handle +// faults in. {base} points to the beginning of the chunk, and {size} is the +// number of bytes in the code chunk. The remainder of the struct is a list of +// protected memory access instructions and an offset to a landing pad to handle +// faults on that instruction. +struct CodeProtectionInfo { + void* base; + size_t size; + size_t num_protected_instructions; + ProtectedInstructionData instructions[1]; +}; + +class MetadataLock { + static std::atomic_flag spinlock_; + + public: + MetadataLock(); + ~MetadataLock(); + + // We'd normally use DISALLOW_COPY_AND_ASSIGN, but we're avoiding a dependency + // on base/macros.h + MetadataLock(const MetadataLock&) = delete; + void operator=(const MetadataLock&) = delete; +}; + +#if V8_TRAP_HANDLER_SUPPORTED +void HandleSignal(int signum, siginfo_t* info, void* context); +#endif + +// To enable constant time registration of handler data, we keep a free list of +// entries in the gCodeObjects table. Each entry contains a {next_free} field, +// which can be used to figure out where the next entry should be inserted. +// In order to avoid having to initialize all the links to start with, we use +// 0 to indicate that this is a fresh, never-used list entry and that therefore +// the next entry is known to be free. If {next_entry} is greater than zero, +// then {next_entry - 1} is the index that we should insert into next. +struct CodeProtectionInfoListEntry { + CodeProtectionInfo* code_info; + size_t next_free; +}; + +extern size_t gNumCodeObjects; +extern CodeProtectionInfoListEntry* gCodeObjects; + +} // namespace trap_handler +} // namespace internal +} // namespace v8 + +#endif // TRAP_HANDLER_INTERNAL_H_ diff --git a/deps/v8/src/wasm/wasm-interpreter.cc b/deps/v8/src/wasm/wasm-interpreter.cc index f32b5e617b360f..bdf8bbb1ec0d6d 100644 --- a/deps/v8/src/wasm/wasm-interpreter.cc +++ b/deps/v8/src/wasm/wasm-interpreter.cc @@ -936,16 +936,16 @@ class ThreadImpl { InterpreterCode* code = codemap()->FindCode(function); CHECK_NOT_NULL(code); ++num_interpreted_calls_; - frames_.push_back({code, 0, 0, stack_.size()}); + frames_.push_back({code, 0, stack_.size()}); for (size_t i = 0; i < function->sig->parameter_count(); ++i) { stack_.push_back(args[i]); } - frames_.back().ret_pc = InitLocals(code); + frames_.back().pc = InitLocals(code); blocks_.push_back( {0, stack_.size(), frames_.size(), static_cast(code->function->sig->return_count())}); TRACE(" => PushFrame(#%u @%zu)\n", code->function->func_index, - frames_.back().ret_pc); + frames_.back().pc); } WasmInterpreter::State Run() { @@ -954,7 +954,7 @@ class ThreadImpl { if (state_ == WasmInterpreter::STOPPED || state_ == WasmInterpreter::PAUSED) { state_ = WasmInterpreter::RUNNING; - Execute(frames_.back().code, frames_.back().ret_pc, kRunSteps); + Execute(frames_.back().code, frames_.back().pc, kRunSteps); } } while (state_ == WasmInterpreter::STOPPED); return state_; @@ -965,7 +965,7 @@ class ThreadImpl { if (state_ == WasmInterpreter::STOPPED || state_ == WasmInterpreter::PAUSED) { state_ = WasmInterpreter::RUNNING; - Execute(frames_.back().code, frames_.back().ret_pc, 1); + Execute(frames_.back().code, frames_.back().pc, 1); } return state_; } @@ -991,10 +991,10 @@ class ThreadImpl { DCHECK_LE(0, index); DCHECK_GT(frames_.size(), index); Frame* frame = &frames_[index]; - DCHECK_GE(kMaxInt, frame->ret_pc); + DCHECK_GE(kMaxInt, frame->pc); DCHECK_GE(kMaxInt, frame->sp); DCHECK_GE(kMaxInt, frame->llimit()); - return frame_cons(frame->code->function, static_cast(frame->ret_pc), + return frame_cons(frame->code->function, static_cast(frame->pc), static_cast(frame->sp), static_cast(frame->llimit())); } @@ -1020,8 +1020,7 @@ class ThreadImpl { // Entries on the stack of functions being evaluated. struct Frame { InterpreterCode* code; - pc_t call_pc; - pc_t ret_pc; + pc_t pc; sp_t sp; // Limit of parameters. @@ -1060,22 +1059,21 @@ class ThreadImpl { } // Push a frame with arguments already on the stack. - void PushFrame(InterpreterCode* code, pc_t call_pc, pc_t ret_pc) { + void PushFrame(InterpreterCode* code, pc_t pc) { CHECK_NOT_NULL(code); DCHECK(!frames_.empty()); ++num_interpreted_calls_; - frames_.back().call_pc = call_pc; - frames_.back().ret_pc = ret_pc; + frames_.back().pc = pc; size_t arity = code->function->sig->parameter_count(); DCHECK_GE(stack_.size(), arity); // The parameters will overlap the arguments already on the stack. - frames_.push_back({code, 0, 0, stack_.size() - arity}); + frames_.push_back({code, 0, stack_.size() - arity}); blocks_.push_back( {0, stack_.size(), frames_.size(), static_cast(code->function->sig->return_count())}); - frames_.back().ret_pc = InitLocals(code); + frames_.back().pc = InitLocals(code); TRACE(" => push func#%u @%zu\n", code->function->func_index, - frames_.back().ret_pc); + frames_.back().pc); } pc_t InitLocals(InterpreterCode* code) { @@ -1105,7 +1103,7 @@ class ThreadImpl { void CommitPc(pc_t pc) { if (!frames_.empty()) { - frames_.back().ret_pc = pc; + frames_.back().pc = pc; } } @@ -1130,7 +1128,24 @@ class ThreadImpl { return LookupTarget(code, pc); } - bool DoReturn(InterpreterCode** code, pc_t* pc, pc_t* limit, size_t arity) { + pc_t ReturnPc(Decoder* decoder, InterpreterCode* code, pc_t pc) { + switch (code->orig_start[pc]) { + case kExprCallFunction: { + CallFunctionOperand operand(decoder, code->at(pc)); + return pc + 1 + operand.length; + } + case kExprCallIndirect: { + CallIndirectOperand operand(decoder, code->at(pc)); + return pc + 1 + operand.length; + } + default: + UNREACHABLE(); + return 0; + } + } + + bool DoReturn(Decoder* decoder, InterpreterCode** code, pc_t* pc, pc_t* limit, + size_t arity) { DCHECK_GT(frames_.size(), 0); // Pop all blocks for this frame. while (!blocks_.empty() && blocks_.back().fp == frames_.size()) { @@ -1149,7 +1164,8 @@ class ThreadImpl { // Return to caller frame. Frame* top = &frames_.back(); *code = top->code; - *pc = top->ret_pc; + decoder->Reset((*code)->start, (*code)->end); + *pc = ReturnPc(decoder, *code, top->pc); *limit = top->code->end - top->code->start; TRACE(" => pop func#%u @%zu\n", (*code)->function->func_index, *pc); DoStackTransfer(dest, arity); @@ -1157,10 +1173,12 @@ class ThreadImpl { } } - void DoCall(InterpreterCode* target, pc_t* pc, pc_t ret_pc, pc_t* limit) { - PushFrame(target, *pc, ret_pc); - *pc = frames_.back().ret_pc; + void DoCall(Decoder* decoder, InterpreterCode* target, pc_t* pc, + pc_t* limit) { + PushFrame(target, *pc); + *pc = frames_.back().pc; *limit = target->end - target->start; + decoder->Reset(target->start, target->end); } // Copies {arity} values on the top of the stack down the stack to {dest}, @@ -1334,14 +1352,12 @@ class ThreadImpl { } case kExprReturn: { size_t arity = code->function->sig->return_count(); - if (!DoReturn(&code, &pc, &limit, arity)) return; - decoder.Reset(code->start, code->end); + if (!DoReturn(&decoder, &code, &pc, &limit, arity)) return; PAUSE_IF_BREAK_FLAG(AfterReturn); continue; } case kExprUnreachable: { - DoTrap(kTrapUnreachable, pc); - return CommitPc(pc); + return DoTrap(kTrapUnreachable, pc); } case kExprEnd: { blocks_.pop_back(); @@ -1398,10 +1414,8 @@ class ThreadImpl { } case kExprCallFunction: { CallFunctionOperand operand(&decoder, code->at(pc)); - InterpreterCode* target = codemap()->GetCode(operand.index); - DoCall(target, &pc, pc + 1 + operand.length, &limit); - code = target; - decoder.Reset(code->start, code->end); + code = codemap()->GetCode(operand.index); + DoCall(&decoder, code, &pc, &limit); PAUSE_IF_BREAK_FLAG(AfterCall); continue; } @@ -1426,9 +1440,8 @@ class ThreadImpl { } } - DoCall(target, &pc, pc + 1 + operand.length, &limit); + DoCall(&decoder, target, &pc, &limit); code = target; - decoder.Reset(code->start, code->end); PAUSE_IF_BREAK_FLAG(AfterCall); continue; } @@ -1656,9 +1669,9 @@ class ThreadImpl { if (pc == limit) { // Fell off end of code; do an implicit return. TRACE("@%-3zu: ImplicitReturn\n", pc); - if (!DoReturn(&code, &pc, &limit, code->function->sig->return_count())) + if (!DoReturn(&decoder, &code, &pc, &limit, + code->function->sig->return_count())) return; - decoder.Reset(code->start, code->end); PAUSE_IF_BREAK_FLAG(AfterReturn); } } diff --git a/deps/v8/src/wasm/wasm-module.cc b/deps/v8/src/wasm/wasm-module.cc index 04f600e3219cf8..f522f86b352dcf 100644 --- a/deps/v8/src/wasm/wasm-module.cc +++ b/deps/v8/src/wasm/wasm-module.cc @@ -1314,11 +1314,22 @@ class InstantiationHelper { } //-------------------------------------------------------------------------- - // Set all breakpoints that were set on the shared module. + // Debugging support. //-------------------------------------------------------------------------- + // Set all breakpoints that were set on the shared module. WasmSharedModuleData::SetBreakpointsOnNewInstance( compiled_module_->shared(), instance); + if (FLAG_wasm_interpret_all) { + Handle debug_info = + WasmInstanceObject::GetOrCreateDebugInfo(instance); + for (int func_index = num_imported_functions, + num_wasm_functions = static_cast(module_->functions.size()); + func_index < num_wasm_functions; ++func_index) { + WasmDebugInfo::RedirectToInterpreter(debug_info, func_index); + } + } + //-------------------------------------------------------------------------- // Run the start function if one was specified. //-------------------------------------------------------------------------- diff --git a/deps/v8/src/x64/macro-assembler-x64.cc b/deps/v8/src/x64/macro-assembler-x64.cc index b75b38eb9a8530..d84b20fb7d8e7e 100644 --- a/deps/v8/src/x64/macro-assembler-x64.cc +++ b/deps/v8/src/x64/macro-assembler-x64.cc @@ -4028,19 +4028,6 @@ Condition MacroAssembler::IsObjectNameType(Register heap_object, } -void MacroAssembler::GetMapConstructor(Register result, Register map, - Register temp) { - Label done, loop; - movp(result, FieldOperand(map, Map::kConstructorOrBackPointerOffset)); - bind(&loop); - JumpIfSmi(result, &done, Label::kNear); - CmpObjectType(result, MAP_TYPE, temp); - j(not_equal, &done, Label::kNear); - movp(result, FieldOperand(result, Map::kConstructorOrBackPointerOffset)); - jmp(&loop); - bind(&done); -} - void MacroAssembler::SetCounter(StatsCounter* counter, int value) { if (FLAG_native_code_counters && counter->Enabled()) { Operand counter_operand = ExternalOperand(ExternalReference(counter)); diff --git a/deps/v8/src/x64/macro-assembler-x64.h b/deps/v8/src/x64/macro-assembler-x64.h index 5f877097defaed..59f8ff6ca6580b 100644 --- a/deps/v8/src/x64/macro-assembler-x64.h +++ b/deps/v8/src/x64/macro-assembler-x64.h @@ -1347,10 +1347,6 @@ class MacroAssembler: public Assembler { void NegativeZeroTest(Register result, Register op1, Register op2, Register scratch, Label* then_label); - // Machine code version of Map::GetConstructor(). - // |temp| holds |result|'s map when done. - void GetMapConstructor(Register result, Register map, Register temp); - // Find the function context up the context chain. void LoadContext(Register dst, int context_chain_length); diff --git a/deps/v8/src/x87/macro-assembler-x87.cc b/deps/v8/src/x87/macro-assembler-x87.cc index 62588d9265ef3b..37ca3856efc54a 100644 --- a/deps/v8/src/x87/macro-assembler-x87.cc +++ b/deps/v8/src/x87/macro-assembler-x87.cc @@ -1609,20 +1609,6 @@ void MacroAssembler::NegativeZeroTest(Register result, bind(&ok); } - -void MacroAssembler::GetMapConstructor(Register result, Register map, - Register temp) { - Label done, loop; - mov(result, FieldOperand(map, Map::kConstructorOrBackPointerOffset)); - bind(&loop); - JumpIfSmi(result, &done, Label::kNear); - CmpObjectType(result, MAP_TYPE, temp); - j(not_equal, &done, Label::kNear); - mov(result, FieldOperand(result, Map::kConstructorOrBackPointerOffset)); - jmp(&loop); - bind(&done); -} - void MacroAssembler::CallStub(CodeStub* stub, TypeFeedbackId ast_id) { DCHECK(AllowThisStubCall(stub)); // Calls are not allowed in some stubs. call(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id); diff --git a/deps/v8/src/x87/macro-assembler-x87.h b/deps/v8/src/x87/macro-assembler-x87.h index 5f0d6bf8eff895..8fe19de6422a86 100644 --- a/deps/v8/src/x87/macro-assembler-x87.h +++ b/deps/v8/src/x87/macro-assembler-x87.h @@ -633,10 +633,6 @@ class MacroAssembler: public Assembler { void NegativeZeroTest(Register result, Register op1, Register op2, Register scratch, Label* then_label); - // Machine code version of Map::GetConstructor(). - // |temp| holds |result|'s map when done. - void GetMapConstructor(Register result, Register map, Register temp); - // --------------------------------------------------------------------------- // Runtime calls diff --git a/deps/v8/test/cctest/cctest.status b/deps/v8/test/cctest/cctest.status index c75b53d6f573d5..49150a15bcc2cd 100644 --- a/deps/v8/test/cctest/cctest.status +++ b/deps/v8/test/cctest/cctest.status @@ -185,6 +185,10 @@ 'test-api/FastReturnValues*': [PASS, SLOW], 'test-decls/CrossScriptReferences_Simple2': [PASS, SLOW], }], # 'no_snap == True' +['no_snap == False', { + # FunctionEntryHooks require bootstrapping from scratch. + 'test-api/SetFunctionEntryHook': [SKIP], +}], # 'no_snap == False' ############################################################################## # TODO(machenbach): Fix application of '*'. Nosnap windows needs a separate diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index 5bc94bc155e781..cc3d15ea448401 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -14253,7 +14253,7 @@ void SetFunctionEntryHookTest::RunTest() { CHECK_EQ(2, CountInvocations(NULL, "bar")); CHECK_EQ(200, CountInvocations("bar", "foo")); CHECK_EQ(200, CountInvocations(NULL, "foo")); - } else if (i::FLAG_crankshaft || i::FLAG_turbo) { + } else if (i::FLAG_crankshaft) { // For ignition we don't see the actual functions being called, instead // we see the InterpreterEntryTrampoline at least 102 times // (100 unoptimized calls to foo, and 2 calls to bar). diff --git a/deps/v8/test/debugger/regress/regress-6085.js b/deps/v8/test/debugger/regress/regress-6085.js new file mode 100644 index 00000000000000..ef251516459e1f --- /dev/null +++ b/deps/v8/test/debugger/regress/regress-6085.js @@ -0,0 +1,49 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +function* serialize() { + debugger; + switch (0) { + case 0: + let x = 1; + return x; // Check scopes + } +} + +let exception = null; +let step_count = 0; +let scopes_checked = false; + +function listener(event, exec_state, event_data, data) { + if (event != Debug.DebugEvent.Break) return; + try { + if (exec_state.frame().sourceLineText().includes("Check scopes")) { + let expected = [ debug.ScopeType.Block, + debug.ScopeType.Local, + debug.ScopeType.Script, + debug.ScopeType.Global ]; + for (let i = 0; i < exec_state.frame().scopeCount(); i++) { + assertEquals(expected[i], exec_state.frame().scope(i).scopeType()); + } + scopes_checked = true; + } + if (step_count++ < 3) exec_state.prepareStep(Debug.StepAction.StepNext); + } catch (e) { + exception = e; + print(e, e.stack); + } +} + + + +let Debug = debug.Debug; +Debug.setListener(listener); + +let gen = serialize(); +gen.next(); + +Debug.setListener(null); +assertNull(exception); +assertEquals(4, step_count); +assertTrue(scopes_checked); diff --git a/deps/v8/test/inspector/debugger/async-for-await-of-promise-stack-expected.txt b/deps/v8/test/inspector/debugger/async-for-await-of-promise-stack-expected.txt new file mode 100644 index 00000000000000..fb1403917a5143 --- /dev/null +++ b/deps/v8/test/inspector/debugger/async-for-await-of-promise-stack-expected.txt @@ -0,0 +1,57 @@ +Checks that async chains for for-await-of are correct. + +Running test: testBasic +Debugger (test.js:10:2) +Basic (test.js:48:4) +-- async function (test.js:46:20)-- +Basic (test.js:46:20) +(anonymous) (testBasic.js:0:0) + + +Running test: testUncaughtReject +Debugger (test.js:10:2) +-- async function (test.js:52:29)-- +UncaughtReject (test.js:52:29) +(anonymous) (testUncaughtReject.js:0:0) + + +Running test: testUncaughtThrow +Debugger (test.js:10:2) +-- async function (test.js:61:28)-- +UncaughtThrow (test.js:61:28) +(anonymous) (testUncaughtThrow.js:0:0) + + +Running test: testCaughtReject +Debugger (test.js:10:2) +CaughtReject (test.js:76:4) +-- async function (test.js:70:27)-- +CaughtReject (test.js:70:27) +(anonymous) (testCaughtReject.js:0:0) + + +Running test: testCaughtThrow +Debugger (test.js:10:2) +CaughtThrow (test.js:86:4) +-- async function (test.js:80:26)-- +CaughtThrow (test.js:80:26) +(anonymous) (testCaughtThrow.js:0:0) + + +Running test: testUncaughtRejectOnBreak + +Running test: testUncaughtThrowOnBreak +Debugger (test.js:10:2) +-- async function (test.js:99:35)-- +UncaughtThrowOnBreak (test.js:99:35) +(anonymous) (testUncaughtThrowOnBreak.js:0:0) + + +Running test: testCaughtRejectOnBreak + +Running test: testCaughtThrowOnBreak +Debugger (test.js:10:2) +CaughtThrowOnBreak (test.js:124:4) +-- async function (test.js:118:33)-- +CaughtThrowOnBreak (test.js:118:33) +(anonymous) (testCaughtThrowOnBreak.js:0:0) \ No newline at end of file diff --git a/deps/v8/test/inspector/debugger/async-for-await-of-promise-stack.js b/deps/v8/test/inspector/debugger/async-for-await-of-promise-stack.js new file mode 100644 index 00000000000000..4e6c0bf15ecdde --- /dev/null +++ b/deps/v8/test/inspector/debugger/async-for-await-of-promise-stack.js @@ -0,0 +1,164 @@ +// Copyright 2016 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --harmony-async-iteration + +InspectorTest.log('Checks that async chains for for-await-of are correct.'); + +InspectorTest.addScript(` + +function Debugger(value) { + debugger; +} + +function Reject(reason) { + var reject; + var promise = new Promise(function(resolvefn, rejectfn) { + reject = rejectfn; + }); + setTimeout(reject.bind(undefined, reason), 0); + return promise; +} + +function Throw(reason) { + return { + get then() { throw reason; } + }; +} + +function ThrowOnReturn(items) { + var it = items[Symbol.iterator](); + return { + [Symbol.iterator]() { return this; }, + next(v) { return it.next(v); }, + return(v) { throw new Error("boop"); } + }; +} + +function RejectOnReturn(items) { + var it = items[Symbol.iterator](); + return { + [Symbol.iterator]() { return this; }, + next(v) { return it.next(v); }, + return(v) { return Reject(new Error("boop")); } + }; +} + +async function Basic() { + for await (let x of ["a"]) { + Debugger(); + } +} + +async function UncaughtReject() { + async function loop() { + for await (let x of [Reject(new Error("boop"))]) { + Debugger(); + } + } + return loop().catch(Debugger); +} + +async function UncaughtThrow() { + async function loop() { + for await (let x of [Throw(new Error("boop"))]) { + Debugger(); + } + } + return loop().catch(Debugger); +} + +async function CaughtReject() { + try { + for await (let x of [Reject(new Error("boop"))]) { + Debugger(x); + } + } catch (e) { + Debugger(e); + } +} + +async function CaughtThrow() { + try { + for await (let x of [Throw(new Error("boop"))]) { + Debugger(x); + } + } catch (e) { + Debugger(e); + } +} + +async function UncaughtRejectOnBreak() { + async function loop() { + for await (let x of RejectOnReturn(["0", "1"])) { + break; + } + } + return loop().catch(Debugger); +} + +async function UncaughtThrowOnBreak() { + async function loop() { + for await (let x of ThrowOnReturn(["0", "1"])) { + break; + } + } + return loop().catch(Debugger); +} + +async function CaughtRejectOnBreak() { + try { + for await (let x of RejectOnReturn(["0", "1"])) { + break; + } + } catch (e) { + Debugger(e); + } +} + +async function CaughtThrowOnBreak() { + try { + for await (let x of ThrowOnReturn(["0", "1"])) { + break; + } + } catch (e) { + Debugger(e); + } +} +//# sourceURL=test.js`, 7, 129); + +InspectorTest.setupScriptMap(); +Protocol.Debugger.onPaused(message => { + InspectorTest.logCallFrames(message.params.callFrames); + InspectorTest.logAsyncStackTrace(message.params.asyncStackTrace); + InspectorTest.log(''); + Protocol.Debugger.resume(); +}); + +Protocol.Debugger.enable(); +Protocol.Debugger.setAsyncCallStackDepth({ maxDepth: 128 }); +var testList = [ + 'Basic', + 'UncaughtReject', + 'UncaughtThrow', + 'CaughtReject', + 'CaughtThrow', + 'UncaughtRejectOnBreak', + 'UncaughtThrowOnBreak', + 'CaughtRejectOnBreak', + 'CaughtThrowOnBreak', +] +InspectorTest.runTestSuite(testList.map(name => { + return eval(` + (function test${capitalize(name)}(next) { + Protocol.Runtime.evaluate({ expression: \`${name}() +//# sourceURL=test${capitalize(name)}.js\`, awaitPromise: true}) + .then(next); + }) + `); +})); + +function capitalize(string) { + return string.charAt(0).toUpperCase() + string.slice(1); +} diff --git a/deps/v8/test/inspector/debugger/stepping-and-break-program-api-expected.txt b/deps/v8/test/inspector/debugger/stepping-and-break-program-api-expected.txt new file mode 100644 index 00000000000000..cd7c214b75faba --- /dev/null +++ b/deps/v8/test/inspector/debugger/stepping-and-break-program-api-expected.txt @@ -0,0 +1,19 @@ +Checks that stepping is cleared after breakProgram. +paused at: +function callBreakProgram() { + #debugger; + breakProgram('reason', ''); + +paused at: + debugger; + #breakProgram('reason', ''); +} + +paused at: + debugger; + #breakProgram('reason', ''); +} + +paused at: +#debugger; + diff --git a/deps/v8/test/inspector/debugger/stepping-and-break-program-api.js b/deps/v8/test/inspector/debugger/stepping-and-break-program-api.js new file mode 100644 index 00000000000000..4900843fc533fd --- /dev/null +++ b/deps/v8/test/inspector/debugger/stepping-and-break-program-api.js @@ -0,0 +1,34 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +InspectorTest.log('Checks that stepping is cleared after breakProgram.'); + +InspectorTest.addScript(` +function callBreakProgram() { + debugger; + breakProgram('reason', ''); +}`); + +InspectorTest.setupScriptMap(); +(async function test() { + Protocol.Debugger.enable(); + Protocol.Runtime.evaluate({expression: 'callBreakProgram();'}); + // Should break at this debugger statement, not at end of callBreakProgram. + Protocol.Runtime.evaluate({expression: 'setTimeout(\'debugger;\', 0);'}); + await waitPauseAndDumpLocation(); + Protocol.Debugger.stepOver(); + await waitPauseAndDumpLocation(); + Protocol.Debugger.stepOver(); + await waitPauseAndDumpLocation(); + Protocol.Debugger.resume(); + await waitPauseAndDumpLocation(); + InspectorTest.completeTest(); +})(); + +async function waitPauseAndDumpLocation() { + var message = await Protocol.Debugger.oncePaused(); + InspectorTest.log('paused at:'); + InspectorTest.logSourceLocation(message.params.callFrames[0].location); + return message; +} diff --git a/deps/v8/test/inspector/debugger/wasm-imports-expected.txt b/deps/v8/test/inspector/debugger/wasm-imports-expected.txt index 2c3f1ae7ad0b4b..0a53bdc521512d 100644 --- a/deps/v8/test/inspector/debugger/wasm-imports-expected.txt +++ b/deps/v8/test/inspector/debugger/wasm-imports-expected.txt @@ -17,6 +17,7 @@ end Getting current stack trace via "new Error().stack". Error at v8://test/getStack:1:1 + at func ([0]+1) at main ([1]+1) at v8://test/runWasm:1:22 exports.main returned. diff --git a/deps/v8/test/intl/intl.status b/deps/v8/test/intl/intl.status index bc544b52374eaa..e38ab3ed784e1b 100644 --- a/deps/v8/test/intl/intl.status +++ b/deps/v8/test/intl/intl.status @@ -31,12 +31,6 @@ 'overrides/caching': [PASS, FAIL], }], # ALWAYS -['arch == arm64 and mode == debug and simulator_run == True and variant == ignition', { - # Ignition on ARM64 simulator in debug mode. - 'date-format/timezone': [PASS, ['no_snap', SKIP]], - 'number-format/check-digit-ranges': [PASS, ['no_snap', SKIP]], -}], # 'arch == arm64 and mode == debug and simulator_run == True and variant == ignition' - ['variant == asm_wasm', { '*': [SKIP], }], # variant == asm_wasm diff --git a/deps/v8/test/mjsunit/es6/array-iterator-turbo.js b/deps/v8/test/mjsunit/es6/array-iterator-turbo.js index 39c46575a6e927..def018eea2c94e 100644 --- a/deps/v8/test/mjsunit/es6/array-iterator-turbo.js +++ b/deps/v8/test/mjsunit/es6/array-iterator-turbo.js @@ -3,6 +3,7 @@ // found in the LICENSE file. // Flags: --turbo --turbo-escape --allow-natives-syntax --no-always-opt +// Flags: --crankshaft --turbo-filter=* "use strict"; diff --git a/deps/v8/test/mjsunit/es6/typedarray-construct-offset-not-smi.js b/deps/v8/test/mjsunit/es6/typedarray-construct-offset-not-smi.js new file mode 100644 index 00000000000000..27beb762dc8d1b --- /dev/null +++ b/deps/v8/test/mjsunit/es6/typedarray-construct-offset-not-smi.js @@ -0,0 +1,58 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +(function TestBufferByteLengthNonSmi() { + var non_smi_byte_length = %_MaxSmi() + 1; + + try { + var buffer = new ArrayBuffer(non_smi_byte_length); + } catch (e) { + // The ArrayBuffer allocation can fail on 32-bit archs, so no need to try to + // construct the typed array. + return; + } + var arr = new Uint16Array(buffer); + + assertEquals(non_smi_byte_length, arr.byteLength); + assertEquals(non_smi_byte_length / 2, arr.length); + + arr = new Uint32Array(buffer); + assertEquals(non_smi_byte_length, arr.byteLength); + assertEquals(non_smi_byte_length / 4, arr.length); +})(); + +(function TestByteOffsetNonSmi() { + var non_smi_byte_length = %_MaxSmi() + 11; + try { + var buffer = new ArrayBuffer(non_smi_byte_length); + } catch (e) { + // The ArrayBuffer allocation can fail on 32-bit archs, so no need to try to + // construct the typed array. + return; + } + print(buffer.byteLength); + var whole = new Uint16Array(buffer); + whole[non_smi_byte_length / 2 - 1] = 1; + whole[non_smi_byte_length / 2 - 2] = 2; + whole[non_smi_byte_length / 2 - 3] = 3; + whole[non_smi_byte_length / 2 - 4] = 4; + whole[non_smi_byte_length / 2 - 5] = 5; + + assertEquals(non_smi_byte_length / 2, whole.length); + assertEquals(1, whole[non_smi_byte_length / 2 - 1]); + + var arr = new Uint16Array(buffer, non_smi_byte_length - 10, 5); + + assertEquals(non_smi_byte_length, arr.buffer.byteLength); + assertEquals(10, arr.byteLength); + assertEquals(5, arr.length); + + assertEquals(5, arr[0]); + assertEquals(4, arr[1]); + assertEquals(3, arr[2]); + assertEquals(2, arr[3]); + assertEquals(1, arr[4]); +})(); diff --git a/deps/v8/test/mjsunit/mjsunit.status b/deps/v8/test/mjsunit/mjsunit.status index fb694374eabe6e..86681c13604107 100644 --- a/deps/v8/test/mjsunit/mjsunit.status +++ b/deps/v8/test/mjsunit/mjsunit.status @@ -595,7 +595,7 @@ }], # 'arch == ppc64' ############################################################################## -['variant == nocrankshaft', { +['variant == fullcode', { 'es6/array-iterator-turbo': [SKIP], }], # variant == nocranshaft @@ -606,8 +606,24 @@ 'array-natives-elements': [SKIP], 'ignition/regress-599001-verifyheap': [SKIP], 'unicode-test': [SKIP], + + # Slow tests. + 'regress/regress-2185-2': [SKIP], }], # variant == stress +############################################################################## +['variant == noturbofan_stress', { + # Slow tests. + 'ignition/regress-599001-verifyheap': [SKIP], + 'regress/regress-2185-2': [SKIP], +}], # variant == noturbofan_stress + +############################################################################## +['variant == nooptimization', { + # Slow tests. + 'regress/regress-2185-2': [SKIP], +}], # variant == nooptimization + ############################################################################## ['variant == turbofan_opt', { 'es6/array-iterator-turbo': [SKIP], diff --git a/deps/v8/test/mjsunit/modules-turbo1.js b/deps/v8/test/mjsunit/modules-turbo1.js index d0cf5f9bc2cbff..ce688e1dad4707 100644 --- a/deps/v8/test/mjsunit/modules-turbo1.js +++ b/deps/v8/test/mjsunit/modules-turbo1.js @@ -3,7 +3,7 @@ // found in the LICENSE file. // MODULE -// Flags: --allow-natives-syntax --turbo --crankshaft +// Flags: --allow-natives-syntax --turbo --crankshaft --turbo-filter=* export let x = 0; function foo() { x++ }; diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-700678.js b/deps/v8/test/mjsunit/regress/regress-crbug-700678.js new file mode 100644 index 00000000000000..1a9623ac4eaa78 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-700678.js @@ -0,0 +1,20 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +(function testNonConfigurableProperty() { + function ownKeys(x) { return ["23", "length"]; } + var target = []; + var proxy = new Proxy(target, {ownKeys:ownKeys}); + Object.defineProperty(target, "23", {value:true}); + assertEquals(["23", "length"], Object.getOwnPropertyNames(proxy)); +})(); + +(function testPreventedExtension() { + function ownKeys(x) { return ["42", "length"]; } + var target = []; + var proxy = new Proxy(target, {ownKeys:ownKeys}); + target[42] = true; + Object.preventExtensions(target); + assertEquals(["42", "length"], Object.getOwnPropertyNames(proxy)); +})(); diff --git a/deps/v8/test/mjsunit/shared-function-tier-up-turbo.js b/deps/v8/test/mjsunit/shared-function-tier-up-turbo.js index c29ee1adc6653a..6f146a865f6e79 100644 --- a/deps/v8/test/mjsunit/shared-function-tier-up-turbo.js +++ b/deps/v8/test/mjsunit/shared-function-tier-up-turbo.js @@ -4,6 +4,7 @@ // // Flags: --mark-shared-functions-for-tier-up --allow-natives-syntax // Flags: --ignition-staging --turbo --crankshaft --no-always-opt +// Flags: --turbo-filter=* // If we are always or never optimizing it is useless. assertFalse(isAlwaysOptimize()); diff --git a/deps/v8/tools/get_byteorder.py b/deps/v8/tools/get_byteorder.py new file mode 100755 index 00000000000000..598948b42ab0dc --- /dev/null +++ b/deps/v8/tools/get_byteorder.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python +# +# Copyright 2017 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Get Byteorder of host architecture""" + + +import sys + +def main(): + print sys.byteorder + return 0 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/deps/v8/tools/release/script_test.py b/deps/v8/tools/release/script_test.py index cbb2134f6d92f9..b9a17e97fa3baf 100755 --- a/deps/v8/tools/release/script_test.py +++ b/deps/v8/tools/release/script_test.py @@ -43,7 +43,6 @@ def Main(argv): alltests = map(unittest.TestLoader().loadTestsFromTestCase, [ test_scripts.ToplevelTest, test_scripts.ScriptTest, - test_scripts.SystemTest, ]) unittest.TextTestRunner(verbosity=2).run(unittest.TestSuite(alltests)) cov.stop() diff --git a/deps/v8/tools/release/test_scripts.py b/deps/v8/tools/release/test_scripts.py index 1695f97fa51281..32b1add991a36e 100644 --- a/deps/v8/tools/release/test_scripts.py +++ b/deps/v8/tools/release/test_scripts.py @@ -1920,31 +1920,3 @@ def ResetVersion(major, minor, build, patch=0): },], } self.assertEquals(expected_json, json.loads(FileToText(json_output))) - - - - -class SystemTest(unittest.TestCase): - def testReload(self): - options = ScriptsBase( - TEST_CONFIG, DEFAULT_SIDE_EFFECT_HANDLER, {}).MakeOptions([]) - step = MakeStep(step_class=PrepareChangeLog, number=0, state={}, config={}, - options=options, - side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER) - body = step.Reload( -"""------------------------------------------------------------------------ -r17997 | machenbach@chromium.org | 2013-11-22 11:04:04 +0100 (...) | 6 lines - -Prepare push to trunk. Now working on version 3.23.11. - -R=danno@chromium.org - -Review URL: https://codereview.chromium.org/83173002 - -------------------------------------------------------------------------""") - self.assertEquals( -"""Prepare push to trunk. Now working on version 3.23.11. - -R=danno@chromium.org - -Committed: https://code.google.com/p/v8/source/detail?r=17997""", body) diff --git a/deps/v8/tools/release/test_update_node.py b/deps/v8/tools/release/test_update_node.py new file mode 100755 index 00000000000000..5105a242e25d2c --- /dev/null +++ b/deps/v8/tools/release/test_update_node.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python +# Copyright 2017 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os +import shutil +import subprocess +import sys +import tempfile +import unittest + +import update_node + +# Base paths. +BASE_DIR = os.path.dirname(os.path.abspath(__file__)) +TEST_DATA = os.path.join(BASE_DIR, 'testdata') + +# Expectations. +EXPECTED_GITIGNORE = """ +/testing/gtest/* +!/testing/gtest/include +/testing/gtest/include/* +!/testing/gtest/include/gtest +/testing/gtest/include/gtest/* +!/testing/gtest/include/gtest/gtest_prod.h +!/third_party/jinja2 +!/third_party/markupsafe +/unrelated +""" + +EXPECTED_GIT_DIFF = """ + rename deps/v8/baz/{delete_me => v8_new} (100%) + rename deps/v8/{delete_me => new/v8_new} (100%) + create mode 100644 deps/v8/third_party/jinja2/jinja2 + create mode 100644 deps/v8/third_party/markupsafe/markupsafe + create mode 100644 deps/v8/v8_new +""" + +ADDED_FILES = [ + 'v8_new', + 'new/v8_new', + 'baz/v8_new', + 'testing/gtest/gtest_new', + 'testing/gtest/new/gtest_new', + 'testing/gtest/baz/gtest_new', + 'third_party/jinja2/jinja2', + 'third_party/markupsafe/markupsafe' +] + +REMOVED_FILES = [ + 'delete_me', + 'baz/delete_me', + 'testing/gtest/delete_me', + 'testing/gtest/baz/delete_me', +] + +def gitify(path): + files = os.listdir(path) + subprocess.check_call(['git', 'init'], cwd=path) + subprocess.check_call(['git', 'add'] + files, cwd=path) + subprocess.check_call(['git', 'commit', '-m', 'Initial'], cwd=path) + + +class TestUpdateNode(unittest.TestCase): + def setUp(self): + self.workdir = tempfile.mkdtemp(prefix='tmp_test_node_') + + def tearDown(self): + shutil.rmtree(self.workdir) + + def testUpdate(self): + v8_cwd = os.path.join(self.workdir, 'v8') + node_cwd = os.path.join(self.workdir, 'node') + + # Set up V8 test fixture. + shutil.copytree(src=os.path.join(TEST_DATA, 'v8'), dst=v8_cwd) + gitify(v8_cwd) + for repository in update_node.SUB_REPOSITORIES: + gitify(os.path.join(v8_cwd, *repository)) + + # Set up node test fixture. + shutil.copytree(src=os.path.join(TEST_DATA, 'node'), dst=node_cwd) + gitify(os.path.join(node_cwd)) + + # Run update script. + update_node.Main([v8_cwd, node_cwd, "--commit"]) + + # Check expectations. + with open(os.path.join(node_cwd, 'deps', 'v8', '.gitignore')) as f: + actual_gitignore = f.read() + self.assertEquals(EXPECTED_GITIGNORE.strip(), actual_gitignore.strip()) + for f in ADDED_FILES: + added_file = os.path.join(node_cwd, 'deps', 'v8', *f.split('/')) + self.assertTrue(os.path.exists(added_file)) + for f in REMOVED_FILES: + removed_file = os.path.join(node_cwd, 'deps', 'v8', *f.split('/')) + self.assertFalse(os.path.exists(removed_file)) + gitlog = subprocess.check_output(['git', 'diff', 'master', '--summary'], + cwd=node_cwd) + self.assertEquals(EXPECTED_GIT_DIFF.strip(), gitlog.strip()) + +if __name__ == "__main__": + unittest.main() diff --git a/deps/v8/tools/release/testdata/v8/.gitignore b/deps/v8/tools/release/testdata/v8/.gitignore new file mode 100644 index 00000000000000..855286229f8dea --- /dev/null +++ b/deps/v8/tools/release/testdata/v8/.gitignore @@ -0,0 +1,4 @@ +/unrelated +/testing/gtest +/third_party/jinja2 +/third_party/markupsafe \ No newline at end of file diff --git a/deps/v8/tools/release/testdata/v8/baz/v8_foo b/deps/v8/tools/release/testdata/v8/baz/v8_foo new file mode 100644 index 00000000000000..eb1ae458f8ee6e --- /dev/null +++ b/deps/v8/tools/release/testdata/v8/baz/v8_foo @@ -0,0 +1 @@ +... diff --git a/deps/v8/tools/release/testdata/v8/baz/v8_new b/deps/v8/tools/release/testdata/v8/baz/v8_new new file mode 100644 index 00000000000000..eb1ae458f8ee6e --- /dev/null +++ b/deps/v8/tools/release/testdata/v8/baz/v8_new @@ -0,0 +1 @@ +... diff --git a/deps/v8/tools/release/testdata/v8/new/v8_new b/deps/v8/tools/release/testdata/v8/new/v8_new new file mode 100644 index 00000000000000..eb1ae458f8ee6e --- /dev/null +++ b/deps/v8/tools/release/testdata/v8/new/v8_new @@ -0,0 +1 @@ +... diff --git a/deps/v8/tools/release/testdata/v8/v8_foo b/deps/v8/tools/release/testdata/v8/v8_foo new file mode 100644 index 00000000000000..eb1ae458f8ee6e --- /dev/null +++ b/deps/v8/tools/release/testdata/v8/v8_foo @@ -0,0 +1 @@ +... diff --git a/deps/v8/tools/release/testdata/v8/v8_new b/deps/v8/tools/release/testdata/v8/v8_new new file mode 100644 index 00000000000000..eb1ae458f8ee6e --- /dev/null +++ b/deps/v8/tools/release/testdata/v8/v8_new @@ -0,0 +1 @@ +... diff --git a/deps/v8/tools/release/update_node.py b/deps/v8/tools/release/update_node.py new file mode 100755 index 00000000000000..f715547587d2b7 --- /dev/null +++ b/deps/v8/tools/release/update_node.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python +# Copyright 2017 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import argparse +import os +import shutil +import subprocess +import sys + +TARGET_SUBDIR = os.path.join("deps", "v8") + +SUB_REPOSITORIES = [ ["testing", "gtest"], + ["third_party", "jinja2"], + ["third_party", "markupsafe"] ] + +DELETE_FROM_GITIGNORE = [ "/base", + "/testing/gtest", + "/third_party/jinja2", + "/third_party/markupsafe" ] + +# Node.js requires only a single header file from gtest to build V8. +# Both jinja2 and markupsafe are required to generate part of the inspector. +ADD_TO_GITIGNORE = [ "/testing/gtest/*", + "!/testing/gtest/include", + "/testing/gtest/include/*", + "!/testing/gtest/include/gtest", + "/testing/gtest/include/gtest/*", + "!/testing/gtest/include/gtest/gtest_prod.h", + "!/third_party/jinja2", + "!/third_party/markupsafe" ] + +def RunGclient(path): + assert os.path.isdir(path) + print ">> Running gclient sync" + subprocess.check_call(["gclient", "sync", "--nohooks"], cwd=path) + +def UninitGit(path): + target = os.path.join(path, ".git") + if os.path.isdir(target): + print ">> Cleaning up %s" % path + shutil.rmtree(target) + +def UpdateTarget(repository, options): + source = os.path.join(options.v8_path, *repository) + target = os.path.join(options.node_path, TARGET_SUBDIR, *repository) + print ">> Updating target directory %s" % target + print ">> from active branch at %s" % source + if not os.path.exists(target): + os.makedirs(target) + # Remove possible remnants of previous incomplete runs. + UninitGit(target) + + git_commands = [ + ["git", "init"], # initialize target repo + ["git", "remote", "add", "origin", source], # point to the source repo + ["git", "fetch", "origin", "HEAD"], # sync to the current branch + ["git", "reset", "--hard", "FETCH_HEAD"], # reset to the current branch + ["git", "clean", "-fd"], # delete removed files + ] + try: + for command in git_commands: + subprocess.check_call(command, cwd=target) + except: + raise + finally: + UninitGit(target) + +def UpdateGitIgnore(options): + file_name = os.path.join(options.node_path, TARGET_SUBDIR, ".gitignore") + assert os.path.isfile(file_name) + print ">> Updating .gitignore with lines" + with open(file_name) as gitignore: + content = gitignore.readlines() + content = [x.strip() for x in content] + for x in DELETE_FROM_GITIGNORE: + if x in content: + print "- %s" % x + content.remove(x) + for x in ADD_TO_GITIGNORE: + if x not in content: + print "+ %s" % x + content.append(x) + content.sort(key=lambda x: x[1:] if x.startswith("!") else x) + with open(file_name, "w") as gitignore: + for x in content: + gitignore.write("%s\n" % x) + +def CreateCommit(options): + print ">> Creating commit." + # Find git hash from source. + githash = subprocess.check_output(["git", "rev-parse", "--short", "HEAD"], + cwd=options.v8_path).strip() + # Create commit at target. + git_commands = [ + ["git", "checkout", "-b", "update_v8_to_%s" % githash], # new branch + ["git", "add", "."], # add files + ["git", "commit", "-m", "Update V8 to %s" % githash] # new commit + ] + for command in git_commands: + subprocess.check_call(command, cwd=options.node_path) + +def ParseOptions(args): + parser = argparse.ArgumentParser(description="Update V8 in Node.js") + parser.add_argument("v8_path", help="Path to V8 checkout") + parser.add_argument("node_path", help="Path to Node.js checkout") + parser.add_argument("--gclient", action="store_true", help="Run gclient sync") + parser.add_argument("--commit", action="store_true", help="Create commit") + options = parser.parse_args(args) + assert os.path.isdir(options.v8_path) + options.v8_path = os.path.abspath(options.v8_path) + assert os.path.isdir(options.node_path) + options.node_path = os.path.abspath(options.node_path) + return options + +def Main(args): + options = ParseOptions(args) + if options.gclient: + RunGclient(options.v8_path) + # Update main V8 repository. + UpdateTarget([""], options) + # Patch .gitignore before updating sub-repositories. + UpdateGitIgnore(options) + for repo in SUB_REPOSITORIES: + UpdateTarget(repo, options) + if options.commit: + CreateCommit(options) + +if __name__ == "__main__": + Main(sys.argv[1:]) diff --git a/deps/v8/tools/run-tests.py b/deps/v8/tools/run-tests.py index 9c54dbd596bc9b..7a17027a2d6ac1 100755 --- a/deps/v8/tools/run-tests.py +++ b/deps/v8/tools/run-tests.py @@ -110,7 +110,7 @@ MORE_VARIANTS = [ "stress", "noturbofan_stress", - "ignition", + "nooptimization", "asm_wasm", "wasm_traps", ] @@ -123,7 +123,7 @@ # Additional variants, run on all bots. "more": MORE_VARIANTS, # Additional variants, run on a subset of bots. - "extra": ["nocrankshaft"], + "extra": ["fullcode"], } DEBUG_FLAGS = ["--nohard-abort", "--nodead-code-elimination", diff --git a/deps/v8/tools/testrunner/local/variants.py b/deps/v8/tools/testrunner/local/variants.py index 269d5972fd7b7a..b7a8387573bd25 100644 --- a/deps/v8/tools/testrunner/local/variants.py +++ b/deps/v8/tools/testrunner/local/variants.py @@ -10,8 +10,8 @@ "turbofan_opt": [["--turbo", "--always-opt"]], "noturbofan": [["--no-turbo"]], "noturbofan_stress": [["--no-turbo", "--stress-opt", "--always-opt"]], - "nocrankshaft": [["--nocrankshaft"]], - "ignition": [["--ignition"]], + "fullcode": [["--nocrankshaft", "--no-turbo"]], + "nooptimization": [["--nocrankshaft", "--turbo-filter=~"]], "ignition_turbofan": [["--ignition-staging", "--turbo"]], "asm_wasm": [["--validate-asm"]], "wasm_traps": [["--wasm_guard_pages", "--wasm_trap_handler", "--invoke-weak-callbacks"]], @@ -24,8 +24,8 @@ "turbofan": [["--turbo"]], "noturbofan": [["--no-turbo"]], "noturbofan_stress": [["--no-turbo", "--stress-opt"]], - "nocrankshaft": [["--nocrankshaft"]], - "ignition": [["--ignition"]], + "fullcode": [["--nocrankshaft", "--no-turbo"]], + "nooptimization": [["--nocrankshaft", "--turbo-filter=~"]], "ignition_turbofan": [["--ignition-staging", "--turbo"]], "asm_wasm": [["--validate-asm"]], "wasm_traps": [["--wasm_guard_pages", "--wasm_trap_handler", "--invoke-weak-callbacks"]], @@ -33,5 +33,5 @@ ALL_VARIANTS = set(["default", "stress", "turbofan", "turbofan_opt", "noturbofan", "noturbofan_stress", - "nocrankshaft", "ignition", + "fullcode", "nooptimization", "ignition_turbofan", "asm_wasm", "wasm_traps"])