11cb0ef41Sopenharmony_ci// Copyright 2015 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#include "src/asmjs/asm-js.h" 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci#include "src/asmjs/asm-names.h" 81cb0ef41Sopenharmony_ci#include "src/asmjs/asm-parser.h" 91cb0ef41Sopenharmony_ci#include "src/ast/ast.h" 101cb0ef41Sopenharmony_ci#include "src/base/optional.h" 111cb0ef41Sopenharmony_ci#include "src/base/platform/elapsed-timer.h" 121cb0ef41Sopenharmony_ci#include "src/base/vector.h" 131cb0ef41Sopenharmony_ci#include "src/codegen/compiler.h" 141cb0ef41Sopenharmony_ci#include "src/codegen/unoptimized-compilation-info.h" 151cb0ef41Sopenharmony_ci#include "src/common/assert-scope.h" 161cb0ef41Sopenharmony_ci#include "src/common/message-template.h" 171cb0ef41Sopenharmony_ci#include "src/execution/execution.h" 181cb0ef41Sopenharmony_ci#include "src/execution/isolate.h" 191cb0ef41Sopenharmony_ci#include "src/handles/handles.h" 201cb0ef41Sopenharmony_ci#include "src/heap/factory.h" 211cb0ef41Sopenharmony_ci#include "src/logging/counters.h" 221cb0ef41Sopenharmony_ci#include "src/objects/heap-number-inl.h" 231cb0ef41Sopenharmony_ci#include "src/objects/objects-inl.h" 241cb0ef41Sopenharmony_ci#include "src/parsing/parse-info.h" 251cb0ef41Sopenharmony_ci#include "src/parsing/scanner-character-streams.h" 261cb0ef41Sopenharmony_ci#include "src/parsing/scanner.h" 271cb0ef41Sopenharmony_ci#include "src/wasm/wasm-engine.h" 281cb0ef41Sopenharmony_ci#include "src/wasm/wasm-js.h" 291cb0ef41Sopenharmony_ci#include "src/wasm/wasm-limits.h" 301cb0ef41Sopenharmony_ci#include "src/wasm/wasm-module-builder.h" 311cb0ef41Sopenharmony_ci#include "src/wasm/wasm-objects-inl.h" 321cb0ef41Sopenharmony_ci#include "src/wasm/wasm-result.h" 331cb0ef41Sopenharmony_ci 341cb0ef41Sopenharmony_cinamespace v8 { 351cb0ef41Sopenharmony_cinamespace internal { 361cb0ef41Sopenharmony_ci 371cb0ef41Sopenharmony_ciconst char* const AsmJs::kSingleFunctionName = "__single_function__"; 381cb0ef41Sopenharmony_ci 391cb0ef41Sopenharmony_cinamespace { 401cb0ef41Sopenharmony_ci 411cb0ef41Sopenharmony_ciHandle<Object> StdlibMathMember(Isolate* isolate, Handle<JSReceiver> stdlib, 421cb0ef41Sopenharmony_ci Handle<Name> name) { 431cb0ef41Sopenharmony_ci Handle<Name> math_name( 441cb0ef41Sopenharmony_ci isolate->factory()->InternalizeString(base::StaticCharVector("Math"))); 451cb0ef41Sopenharmony_ci Handle<Object> math = JSReceiver::GetDataProperty(isolate, stdlib, math_name); 461cb0ef41Sopenharmony_ci if (!math->IsJSReceiver()) return isolate->factory()->undefined_value(); 471cb0ef41Sopenharmony_ci Handle<JSReceiver> math_receiver = Handle<JSReceiver>::cast(math); 481cb0ef41Sopenharmony_ci Handle<Object> value = 491cb0ef41Sopenharmony_ci JSReceiver::GetDataProperty(isolate, math_receiver, name); 501cb0ef41Sopenharmony_ci return value; 511cb0ef41Sopenharmony_ci} 521cb0ef41Sopenharmony_ci 531cb0ef41Sopenharmony_cibool AreStdlibMembersValid(Isolate* isolate, Handle<JSReceiver> stdlib, 541cb0ef41Sopenharmony_ci wasm::AsmJsParser::StdlibSet members, 551cb0ef41Sopenharmony_ci bool* is_typed_array) { 561cb0ef41Sopenharmony_ci if (members.contains(wasm::AsmJsParser::StandardMember::kInfinity)) { 571cb0ef41Sopenharmony_ci members.Remove(wasm::AsmJsParser::StandardMember::kInfinity); 581cb0ef41Sopenharmony_ci Handle<Name> name = isolate->factory()->Infinity_string(); 591cb0ef41Sopenharmony_ci Handle<Object> value = JSReceiver::GetDataProperty(isolate, stdlib, name); 601cb0ef41Sopenharmony_ci if (!value->IsNumber() || !std::isinf(value->Number())) return false; 611cb0ef41Sopenharmony_ci } 621cb0ef41Sopenharmony_ci if (members.contains(wasm::AsmJsParser::StandardMember::kNaN)) { 631cb0ef41Sopenharmony_ci members.Remove(wasm::AsmJsParser::StandardMember::kNaN); 641cb0ef41Sopenharmony_ci Handle<Name> name = isolate->factory()->NaN_string(); 651cb0ef41Sopenharmony_ci Handle<Object> value = JSReceiver::GetDataProperty(isolate, stdlib, name); 661cb0ef41Sopenharmony_ci if (!value->IsNaN()) return false; 671cb0ef41Sopenharmony_ci } 681cb0ef41Sopenharmony_ci#define STDLIB_MATH_FUNC(fname, FName, ignore1, ignore2) \ 691cb0ef41Sopenharmony_ci if (members.contains(wasm::AsmJsParser::StandardMember::kMath##FName)) { \ 701cb0ef41Sopenharmony_ci members.Remove(wasm::AsmJsParser::StandardMember::kMath##FName); \ 711cb0ef41Sopenharmony_ci Handle<Name> name(isolate->factory()->InternalizeString( \ 721cb0ef41Sopenharmony_ci base::StaticCharVector(#fname))); \ 731cb0ef41Sopenharmony_ci Handle<Object> value = StdlibMathMember(isolate, stdlib, name); \ 741cb0ef41Sopenharmony_ci if (!value->IsJSFunction()) return false; \ 751cb0ef41Sopenharmony_ci SharedFunctionInfo shared = Handle<JSFunction>::cast(value)->shared(); \ 761cb0ef41Sopenharmony_ci if (!shared.HasBuiltinId() || \ 771cb0ef41Sopenharmony_ci shared.builtin_id() != Builtin::kMath##FName) { \ 781cb0ef41Sopenharmony_ci return false; \ 791cb0ef41Sopenharmony_ci } \ 801cb0ef41Sopenharmony_ci DCHECK_EQ(shared.GetCode(), \ 811cb0ef41Sopenharmony_ci isolate->builtins()->code(Builtin::kMath##FName)); \ 821cb0ef41Sopenharmony_ci } 831cb0ef41Sopenharmony_ci STDLIB_MATH_FUNCTION_LIST(STDLIB_MATH_FUNC) 841cb0ef41Sopenharmony_ci#undef STDLIB_MATH_FUNC 851cb0ef41Sopenharmony_ci#define STDLIB_MATH_CONST(cname, const_value) \ 861cb0ef41Sopenharmony_ci if (members.contains(wasm::AsmJsParser::StandardMember::kMath##cname)) { \ 871cb0ef41Sopenharmony_ci members.Remove(wasm::AsmJsParser::StandardMember::kMath##cname); \ 881cb0ef41Sopenharmony_ci Handle<Name> name(isolate->factory()->InternalizeString( \ 891cb0ef41Sopenharmony_ci base::StaticCharVector(#cname))); \ 901cb0ef41Sopenharmony_ci Handle<Object> value = StdlibMathMember(isolate, stdlib, name); \ 911cb0ef41Sopenharmony_ci if (!value->IsNumber() || value->Number() != const_value) return false; \ 921cb0ef41Sopenharmony_ci } 931cb0ef41Sopenharmony_ci STDLIB_MATH_VALUE_LIST(STDLIB_MATH_CONST) 941cb0ef41Sopenharmony_ci#undef STDLIB_MATH_CONST 951cb0ef41Sopenharmony_ci#define STDLIB_ARRAY_TYPE(fname, FName) \ 961cb0ef41Sopenharmony_ci if (members.contains(wasm::AsmJsParser::StandardMember::k##FName)) { \ 971cb0ef41Sopenharmony_ci members.Remove(wasm::AsmJsParser::StandardMember::k##FName); \ 981cb0ef41Sopenharmony_ci *is_typed_array = true; \ 991cb0ef41Sopenharmony_ci Handle<Name> name(isolate->factory()->InternalizeString( \ 1001cb0ef41Sopenharmony_ci base::StaticCharVector(#FName))); \ 1011cb0ef41Sopenharmony_ci Handle<Object> value = JSReceiver::GetDataProperty(isolate, stdlib, name); \ 1021cb0ef41Sopenharmony_ci if (!value->IsJSFunction()) return false; \ 1031cb0ef41Sopenharmony_ci Handle<JSFunction> func = Handle<JSFunction>::cast(value); \ 1041cb0ef41Sopenharmony_ci if (!func.is_identical_to(isolate->fname())) return false; \ 1051cb0ef41Sopenharmony_ci } 1061cb0ef41Sopenharmony_ci STDLIB_ARRAY_TYPE(int8_array_fun, Int8Array) 1071cb0ef41Sopenharmony_ci STDLIB_ARRAY_TYPE(uint8_array_fun, Uint8Array) 1081cb0ef41Sopenharmony_ci STDLIB_ARRAY_TYPE(int16_array_fun, Int16Array) 1091cb0ef41Sopenharmony_ci STDLIB_ARRAY_TYPE(uint16_array_fun, Uint16Array) 1101cb0ef41Sopenharmony_ci STDLIB_ARRAY_TYPE(int32_array_fun, Int32Array) 1111cb0ef41Sopenharmony_ci STDLIB_ARRAY_TYPE(uint32_array_fun, Uint32Array) 1121cb0ef41Sopenharmony_ci STDLIB_ARRAY_TYPE(float32_array_fun, Float32Array) 1131cb0ef41Sopenharmony_ci STDLIB_ARRAY_TYPE(float64_array_fun, Float64Array) 1141cb0ef41Sopenharmony_ci#undef STDLIB_ARRAY_TYPE 1151cb0ef41Sopenharmony_ci // All members accounted for. 1161cb0ef41Sopenharmony_ci DCHECK(members.empty()); 1171cb0ef41Sopenharmony_ci return true; 1181cb0ef41Sopenharmony_ci} 1191cb0ef41Sopenharmony_ci 1201cb0ef41Sopenharmony_civoid Report(Handle<Script> script, int position, base::Vector<const char> text, 1211cb0ef41Sopenharmony_ci MessageTemplate message_template, 1221cb0ef41Sopenharmony_ci v8::Isolate::MessageErrorLevel level) { 1231cb0ef41Sopenharmony_ci Isolate* isolate = script->GetIsolate(); 1241cb0ef41Sopenharmony_ci MessageLocation location(script, position, position); 1251cb0ef41Sopenharmony_ci Handle<String> text_object = isolate->factory()->InternalizeUtf8String(text); 1261cb0ef41Sopenharmony_ci Handle<JSMessageObject> message = MessageHandler::MakeMessageObject( 1271cb0ef41Sopenharmony_ci isolate, message_template, &location, text_object, 1281cb0ef41Sopenharmony_ci Handle<FixedArray>::null()); 1291cb0ef41Sopenharmony_ci message->set_error_level(level); 1301cb0ef41Sopenharmony_ci MessageHandler::ReportMessage(isolate, &location, message); 1311cb0ef41Sopenharmony_ci} 1321cb0ef41Sopenharmony_ci 1331cb0ef41Sopenharmony_ci// Hook to report successful execution of {AsmJs::CompileAsmViaWasm} phase. 1341cb0ef41Sopenharmony_civoid ReportCompilationSuccess(Handle<Script> script, int position, 1351cb0ef41Sopenharmony_ci double compile_time, size_t module_size) { 1361cb0ef41Sopenharmony_ci if (FLAG_suppress_asm_messages || !FLAG_trace_asm_time) return; 1371cb0ef41Sopenharmony_ci base::EmbeddedVector<char, 100> text; 1381cb0ef41Sopenharmony_ci int length = SNPrintF(text, "success, compile time %0.3f ms, %zu bytes", 1391cb0ef41Sopenharmony_ci compile_time, module_size); 1401cb0ef41Sopenharmony_ci CHECK_NE(-1, length); 1411cb0ef41Sopenharmony_ci text.Truncate(length); 1421cb0ef41Sopenharmony_ci Report(script, position, text, MessageTemplate::kAsmJsCompiled, 1431cb0ef41Sopenharmony_ci v8::Isolate::kMessageInfo); 1441cb0ef41Sopenharmony_ci} 1451cb0ef41Sopenharmony_ci 1461cb0ef41Sopenharmony_ci// Hook to report failed execution of {AsmJs::CompileAsmViaWasm} phase. 1471cb0ef41Sopenharmony_civoid ReportCompilationFailure(ParseInfo* parse_info, int position, 1481cb0ef41Sopenharmony_ci const char* reason) { 1491cb0ef41Sopenharmony_ci if (FLAG_suppress_asm_messages) return; 1501cb0ef41Sopenharmony_ci parse_info->pending_error_handler()->ReportWarningAt( 1511cb0ef41Sopenharmony_ci position, position, MessageTemplate::kAsmJsInvalid, reason); 1521cb0ef41Sopenharmony_ci} 1531cb0ef41Sopenharmony_ci 1541cb0ef41Sopenharmony_ci// Hook to report successful execution of {AsmJs::InstantiateAsmWasm} phase. 1551cb0ef41Sopenharmony_civoid ReportInstantiationSuccess(Handle<Script> script, int position, 1561cb0ef41Sopenharmony_ci double instantiate_time) { 1571cb0ef41Sopenharmony_ci if (FLAG_suppress_asm_messages || !FLAG_trace_asm_time) return; 1581cb0ef41Sopenharmony_ci base::EmbeddedVector<char, 50> text; 1591cb0ef41Sopenharmony_ci int length = SNPrintF(text, "success, %0.3f ms", instantiate_time); 1601cb0ef41Sopenharmony_ci CHECK_NE(-1, length); 1611cb0ef41Sopenharmony_ci text.Truncate(length); 1621cb0ef41Sopenharmony_ci Report(script, position, text, MessageTemplate::kAsmJsInstantiated, 1631cb0ef41Sopenharmony_ci v8::Isolate::kMessageInfo); 1641cb0ef41Sopenharmony_ci} 1651cb0ef41Sopenharmony_ci 1661cb0ef41Sopenharmony_ci// Hook to report failed execution of {AsmJs::InstantiateAsmWasm} phase. 1671cb0ef41Sopenharmony_civoid ReportInstantiationFailure(Handle<Script> script, int position, 1681cb0ef41Sopenharmony_ci const char* reason) { 1691cb0ef41Sopenharmony_ci if (FLAG_suppress_asm_messages) return; 1701cb0ef41Sopenharmony_ci base::Vector<const char> text = base::CStrVector(reason); 1711cb0ef41Sopenharmony_ci Report(script, position, text, MessageTemplate::kAsmJsLinkingFailed, 1721cb0ef41Sopenharmony_ci v8::Isolate::kMessageWarning); 1731cb0ef41Sopenharmony_ci} 1741cb0ef41Sopenharmony_ci 1751cb0ef41Sopenharmony_ci} // namespace 1761cb0ef41Sopenharmony_ci 1771cb0ef41Sopenharmony_ci// The compilation of asm.js modules is split into two distinct steps: 1781cb0ef41Sopenharmony_ci// [1] ExecuteJobImpl: The asm.js module source is parsed, validated, and 1791cb0ef41Sopenharmony_ci// translated to a valid WebAssembly module. The result are two vectors 1801cb0ef41Sopenharmony_ci// representing the encoded module as well as encoded source position 1811cb0ef41Sopenharmony_ci// information and a StdlibSet bit set. 1821cb0ef41Sopenharmony_ci// [2] FinalizeJobImpl: The module is handed to WebAssembly which decodes it 1831cb0ef41Sopenharmony_ci// into an internal representation and eventually compiles it to machine 1841cb0ef41Sopenharmony_ci// code. 1851cb0ef41Sopenharmony_ciclass AsmJsCompilationJob final : public UnoptimizedCompilationJob { 1861cb0ef41Sopenharmony_ci public: 1871cb0ef41Sopenharmony_ci explicit AsmJsCompilationJob(ParseInfo* parse_info, FunctionLiteral* literal, 1881cb0ef41Sopenharmony_ci AccountingAllocator* allocator) 1891cb0ef41Sopenharmony_ci : UnoptimizedCompilationJob(parse_info->stack_limit(), parse_info, 1901cb0ef41Sopenharmony_ci &compilation_info_), 1911cb0ef41Sopenharmony_ci allocator_(allocator), 1921cb0ef41Sopenharmony_ci zone_(allocator, ZONE_NAME), 1931cb0ef41Sopenharmony_ci compilation_info_(&zone_, parse_info, literal), 1941cb0ef41Sopenharmony_ci module_(nullptr), 1951cb0ef41Sopenharmony_ci asm_offsets_(nullptr), 1961cb0ef41Sopenharmony_ci compile_time_(0), 1971cb0ef41Sopenharmony_ci module_source_size_(0) {} 1981cb0ef41Sopenharmony_ci 1991cb0ef41Sopenharmony_ci AsmJsCompilationJob(const AsmJsCompilationJob&) = delete; 2001cb0ef41Sopenharmony_ci AsmJsCompilationJob& operator=(const AsmJsCompilationJob&) = delete; 2011cb0ef41Sopenharmony_ci 2021cb0ef41Sopenharmony_ci protected: 2031cb0ef41Sopenharmony_ci Status ExecuteJobImpl() final; 2041cb0ef41Sopenharmony_ci Status FinalizeJobImpl(Handle<SharedFunctionInfo> shared_info, 2051cb0ef41Sopenharmony_ci Isolate* isolate) final; 2061cb0ef41Sopenharmony_ci Status FinalizeJobImpl(Handle<SharedFunctionInfo> shared_info, 2071cb0ef41Sopenharmony_ci LocalIsolate* isolate) final { 2081cb0ef41Sopenharmony_ci return CompilationJob::RETRY_ON_MAIN_THREAD; 2091cb0ef41Sopenharmony_ci } 2101cb0ef41Sopenharmony_ci 2111cb0ef41Sopenharmony_ci private: 2121cb0ef41Sopenharmony_ci void RecordHistograms(Isolate* isolate); 2131cb0ef41Sopenharmony_ci 2141cb0ef41Sopenharmony_ci AccountingAllocator* allocator_; 2151cb0ef41Sopenharmony_ci Zone zone_; 2161cb0ef41Sopenharmony_ci UnoptimizedCompilationInfo compilation_info_; 2171cb0ef41Sopenharmony_ci wasm::ZoneBuffer* module_; 2181cb0ef41Sopenharmony_ci wasm::ZoneBuffer* asm_offsets_; 2191cb0ef41Sopenharmony_ci wasm::AsmJsParser::StdlibSet stdlib_uses_; 2201cb0ef41Sopenharmony_ci 2211cb0ef41Sopenharmony_ci double compile_time_; // Time (milliseconds) taken to execute step [2]. 2221cb0ef41Sopenharmony_ci int module_source_size_; // Module source size in bytes. 2231cb0ef41Sopenharmony_ci}; 2241cb0ef41Sopenharmony_ci 2251cb0ef41Sopenharmony_ciUnoptimizedCompilationJob::Status AsmJsCompilationJob::ExecuteJobImpl() { 2261cb0ef41Sopenharmony_ci DisallowHeapAccess no_heap_access; 2271cb0ef41Sopenharmony_ci 2281cb0ef41Sopenharmony_ci // Step 1: Translate asm.js module to WebAssembly module. 2291cb0ef41Sopenharmony_ci Zone* compile_zone = &zone_; 2301cb0ef41Sopenharmony_ci Zone translate_zone(allocator_, ZONE_NAME); 2311cb0ef41Sopenharmony_ci 2321cb0ef41Sopenharmony_ci Utf16CharacterStream* stream = parse_info()->character_stream(); 2331cb0ef41Sopenharmony_ci base::Optional<AllowHandleDereference> allow_deref; 2341cb0ef41Sopenharmony_ci if (stream->can_access_heap()) { 2351cb0ef41Sopenharmony_ci allow_deref.emplace(); 2361cb0ef41Sopenharmony_ci } 2371cb0ef41Sopenharmony_ci stream->Seek(compilation_info()->literal()->start_position()); 2381cb0ef41Sopenharmony_ci wasm::AsmJsParser parser(&translate_zone, stack_limit(), stream); 2391cb0ef41Sopenharmony_ci if (!parser.Run()) { 2401cb0ef41Sopenharmony_ci if (!FLAG_suppress_asm_messages) { 2411cb0ef41Sopenharmony_ci ReportCompilationFailure(parse_info(), parser.failure_location(), 2421cb0ef41Sopenharmony_ci parser.failure_message()); 2431cb0ef41Sopenharmony_ci } 2441cb0ef41Sopenharmony_ci return FAILED; 2451cb0ef41Sopenharmony_ci } 2461cb0ef41Sopenharmony_ci module_ = compile_zone->New<wasm::ZoneBuffer>(compile_zone); 2471cb0ef41Sopenharmony_ci parser.module_builder()->WriteTo(module_); 2481cb0ef41Sopenharmony_ci asm_offsets_ = compile_zone->New<wasm::ZoneBuffer>(compile_zone); 2491cb0ef41Sopenharmony_ci parser.module_builder()->WriteAsmJsOffsetTable(asm_offsets_); 2501cb0ef41Sopenharmony_ci stdlib_uses_ = *parser.stdlib_uses(); 2511cb0ef41Sopenharmony_ci 2521cb0ef41Sopenharmony_ci module_source_size_ = compilation_info()->literal()->end_position() - 2531cb0ef41Sopenharmony_ci compilation_info()->literal()->start_position(); 2541cb0ef41Sopenharmony_ci return SUCCEEDED; 2551cb0ef41Sopenharmony_ci} 2561cb0ef41Sopenharmony_ci 2571cb0ef41Sopenharmony_ciUnoptimizedCompilationJob::Status AsmJsCompilationJob::FinalizeJobImpl( 2581cb0ef41Sopenharmony_ci Handle<SharedFunctionInfo> shared_info, Isolate* isolate) { 2591cb0ef41Sopenharmony_ci // Step 2: Compile and decode the WebAssembly module. 2601cb0ef41Sopenharmony_ci base::ElapsedTimer compile_timer; 2611cb0ef41Sopenharmony_ci compile_timer.Start(); 2621cb0ef41Sopenharmony_ci 2631cb0ef41Sopenharmony_ci Handle<HeapNumber> uses_bitset = 2641cb0ef41Sopenharmony_ci isolate->factory()->NewHeapNumberFromBits(stdlib_uses_.ToIntegral()); 2651cb0ef41Sopenharmony_ci 2661cb0ef41Sopenharmony_ci // The result is a compiled module and serialized standard library uses. 2671cb0ef41Sopenharmony_ci wasm::ErrorThrower thrower(isolate, "AsmJs::Compile"); 2681cb0ef41Sopenharmony_ci Handle<AsmWasmData> result = 2691cb0ef41Sopenharmony_ci wasm::GetWasmEngine() 2701cb0ef41Sopenharmony_ci ->SyncCompileTranslatedAsmJs( 2711cb0ef41Sopenharmony_ci isolate, &thrower, 2721cb0ef41Sopenharmony_ci wasm::ModuleWireBytes(module_->begin(), module_->end()), 2731cb0ef41Sopenharmony_ci base::VectorOf(*asm_offsets_), uses_bitset, 2741cb0ef41Sopenharmony_ci shared_info->language_mode()) 2751cb0ef41Sopenharmony_ci .ToHandleChecked(); 2761cb0ef41Sopenharmony_ci DCHECK(!thrower.error()); 2771cb0ef41Sopenharmony_ci compile_time_ = compile_timer.Elapsed().InMillisecondsF(); 2781cb0ef41Sopenharmony_ci 2791cb0ef41Sopenharmony_ci compilation_info()->SetAsmWasmData(result); 2801cb0ef41Sopenharmony_ci 2811cb0ef41Sopenharmony_ci RecordHistograms(isolate); 2821cb0ef41Sopenharmony_ci ReportCompilationSuccess(handle(Script::cast(shared_info->script()), isolate), 2831cb0ef41Sopenharmony_ci shared_info->StartPosition(), compile_time_, 2841cb0ef41Sopenharmony_ci module_->size()); 2851cb0ef41Sopenharmony_ci return SUCCEEDED; 2861cb0ef41Sopenharmony_ci} 2871cb0ef41Sopenharmony_ci 2881cb0ef41Sopenharmony_civoid AsmJsCompilationJob::RecordHistograms(Isolate* isolate) { 2891cb0ef41Sopenharmony_ci isolate->counters()->asm_module_size_bytes()->AddSample(module_source_size_); 2901cb0ef41Sopenharmony_ci} 2911cb0ef41Sopenharmony_ci 2921cb0ef41Sopenharmony_cistd::unique_ptr<UnoptimizedCompilationJob> AsmJs::NewCompilationJob( 2931cb0ef41Sopenharmony_ci ParseInfo* parse_info, FunctionLiteral* literal, 2941cb0ef41Sopenharmony_ci AccountingAllocator* allocator) { 2951cb0ef41Sopenharmony_ci return std::make_unique<AsmJsCompilationJob>(parse_info, literal, allocator); 2961cb0ef41Sopenharmony_ci} 2971cb0ef41Sopenharmony_ci 2981cb0ef41Sopenharmony_cinamespace { 2991cb0ef41Sopenharmony_ciinline bool IsValidAsmjsMemorySize(size_t size) { 3001cb0ef41Sopenharmony_ci // Enforce asm.js spec minimum size. 3011cb0ef41Sopenharmony_ci if (size < (1u << 12u)) return false; 3021cb0ef41Sopenharmony_ci // Enforce engine-limited and flag-limited maximum allocation size. 3031cb0ef41Sopenharmony_ci if (size > wasm::max_mem_bytes()) return false; 3041cb0ef41Sopenharmony_ci // Enforce power-of-2 sizes for 2^12 - 2^24. 3051cb0ef41Sopenharmony_ci if (size < (1u << 24u)) { 3061cb0ef41Sopenharmony_ci uint32_t size32 = static_cast<uint32_t>(size); 3071cb0ef41Sopenharmony_ci return base::bits::IsPowerOfTwo(size32); 3081cb0ef41Sopenharmony_ci } 3091cb0ef41Sopenharmony_ci // Enforce multiple of 2^24 for sizes >= 2^24 3101cb0ef41Sopenharmony_ci if ((size % (1u << 24u)) != 0) return false; 3111cb0ef41Sopenharmony_ci // All checks passed! 3121cb0ef41Sopenharmony_ci return true; 3131cb0ef41Sopenharmony_ci} 3141cb0ef41Sopenharmony_ci} // namespace 3151cb0ef41Sopenharmony_ci 3161cb0ef41Sopenharmony_ciMaybeHandle<Object> AsmJs::InstantiateAsmWasm(Isolate* isolate, 3171cb0ef41Sopenharmony_ci Handle<SharedFunctionInfo> shared, 3181cb0ef41Sopenharmony_ci Handle<AsmWasmData> wasm_data, 3191cb0ef41Sopenharmony_ci Handle<JSReceiver> stdlib, 3201cb0ef41Sopenharmony_ci Handle<JSReceiver> foreign, 3211cb0ef41Sopenharmony_ci Handle<JSArrayBuffer> memory) { 3221cb0ef41Sopenharmony_ci base::ElapsedTimer instantiate_timer; 3231cb0ef41Sopenharmony_ci instantiate_timer.Start(); 3241cb0ef41Sopenharmony_ci Handle<HeapNumber> uses_bitset(wasm_data->uses_bitset(), isolate); 3251cb0ef41Sopenharmony_ci Handle<Script> script(Script::cast(shared->script()), isolate); 3261cb0ef41Sopenharmony_ci auto* wasm_engine = wasm::GetWasmEngine(); 3271cb0ef41Sopenharmony_ci 3281cb0ef41Sopenharmony_ci // Allocate the WasmModuleObject. 3291cb0ef41Sopenharmony_ci Handle<WasmModuleObject> module = 3301cb0ef41Sopenharmony_ci wasm_engine->FinalizeTranslatedAsmJs(isolate, wasm_data, script); 3311cb0ef41Sopenharmony_ci 3321cb0ef41Sopenharmony_ci // TODO(asmjs): The position currently points to the module definition 3331cb0ef41Sopenharmony_ci // but should instead point to the instantiation site (more intuitive). 3341cb0ef41Sopenharmony_ci int position = shared->StartPosition(); 3351cb0ef41Sopenharmony_ci 3361cb0ef41Sopenharmony_ci // Check that the module is not instantiated as a generator or async function. 3371cb0ef41Sopenharmony_ci if (IsResumableFunction(shared->scope_info().function_kind())) { 3381cb0ef41Sopenharmony_ci ReportInstantiationFailure(script, position, 3391cb0ef41Sopenharmony_ci "Cannot be instantiated as resumable function"); 3401cb0ef41Sopenharmony_ci return MaybeHandle<Object>(); 3411cb0ef41Sopenharmony_ci } 3421cb0ef41Sopenharmony_ci 3431cb0ef41Sopenharmony_ci // Check that all used stdlib members are valid. 3441cb0ef41Sopenharmony_ci bool stdlib_use_of_typed_array_present = false; 3451cb0ef41Sopenharmony_ci wasm::AsmJsParser::StdlibSet stdlib_uses = 3461cb0ef41Sopenharmony_ci wasm::AsmJsParser::StdlibSet::FromIntegral( 3471cb0ef41Sopenharmony_ci uses_bitset->value_as_bits(kRelaxedLoad)); 3481cb0ef41Sopenharmony_ci if (!stdlib_uses.empty()) { // No checking needed if no uses. 3491cb0ef41Sopenharmony_ci if (stdlib.is_null()) { 3501cb0ef41Sopenharmony_ci ReportInstantiationFailure(script, position, "Requires standard library"); 3511cb0ef41Sopenharmony_ci return MaybeHandle<Object>(); 3521cb0ef41Sopenharmony_ci } 3531cb0ef41Sopenharmony_ci if (!AreStdlibMembersValid(isolate, stdlib, stdlib_uses, 3541cb0ef41Sopenharmony_ci &stdlib_use_of_typed_array_present)) { 3551cb0ef41Sopenharmony_ci ReportInstantiationFailure(script, position, "Unexpected stdlib member"); 3561cb0ef41Sopenharmony_ci return MaybeHandle<Object>(); 3571cb0ef41Sopenharmony_ci } 3581cb0ef41Sopenharmony_ci } 3591cb0ef41Sopenharmony_ci 3601cb0ef41Sopenharmony_ci // Check that a valid heap buffer is provided if required. 3611cb0ef41Sopenharmony_ci if (stdlib_use_of_typed_array_present) { 3621cb0ef41Sopenharmony_ci if (memory.is_null()) { 3631cb0ef41Sopenharmony_ci ReportInstantiationFailure(script, position, "Requires heap buffer"); 3641cb0ef41Sopenharmony_ci return MaybeHandle<Object>(); 3651cb0ef41Sopenharmony_ci } 3661cb0ef41Sopenharmony_ci // AsmJs memory must be an ArrayBuffer. 3671cb0ef41Sopenharmony_ci if (memory->is_shared()) { 3681cb0ef41Sopenharmony_ci ReportInstantiationFailure(script, position, 3691cb0ef41Sopenharmony_ci "Invalid heap type: SharedArrayBuffer"); 3701cb0ef41Sopenharmony_ci return MaybeHandle<Object>(); 3711cb0ef41Sopenharmony_ci } 3721cb0ef41Sopenharmony_ci // Mark the buffer as being used as an asm.js memory. This implies two 3731cb0ef41Sopenharmony_ci // things: 1) if the buffer is from a Wasm memory, that memory can no longer 3741cb0ef41Sopenharmony_ci // be grown, since that would detach this buffer, and 2) the buffer cannot 3751cb0ef41Sopenharmony_ci // be postMessage()'d, as that also detaches the buffer. 3761cb0ef41Sopenharmony_ci memory->set_is_asmjs_memory(true); 3771cb0ef41Sopenharmony_ci memory->set_is_detachable(false); 3781cb0ef41Sopenharmony_ci size_t size = memory->byte_length(); 3791cb0ef41Sopenharmony_ci // Check the asm.js heap size against the valid limits. 3801cb0ef41Sopenharmony_ci if (!IsValidAsmjsMemorySize(size)) { 3811cb0ef41Sopenharmony_ci ReportInstantiationFailure(script, position, "Invalid heap size"); 3821cb0ef41Sopenharmony_ci return MaybeHandle<Object>(); 3831cb0ef41Sopenharmony_ci } 3841cb0ef41Sopenharmony_ci } else { 3851cb0ef41Sopenharmony_ci memory = Handle<JSArrayBuffer>::null(); 3861cb0ef41Sopenharmony_ci } 3871cb0ef41Sopenharmony_ci 3881cb0ef41Sopenharmony_ci wasm::ErrorThrower thrower(isolate, "AsmJs::Instantiate"); 3891cb0ef41Sopenharmony_ci MaybeHandle<WasmInstanceObject> maybe_instance = 3901cb0ef41Sopenharmony_ci wasm_engine->SyncInstantiate(isolate, &thrower, module, foreign, memory); 3911cb0ef41Sopenharmony_ci if (maybe_instance.is_null()) { 3921cb0ef41Sopenharmony_ci // An exception caused by the module start function will be set as pending 3931cb0ef41Sopenharmony_ci // and bypass the {ErrorThrower}, this happens in case of a stack overflow. 3941cb0ef41Sopenharmony_ci if (isolate->has_pending_exception()) isolate->clear_pending_exception(); 3951cb0ef41Sopenharmony_ci if (thrower.error()) { 3961cb0ef41Sopenharmony_ci base::ScopedVector<char> error_reason(100); 3971cb0ef41Sopenharmony_ci SNPrintF(error_reason, "Internal wasm failure: %s", thrower.error_msg()); 3981cb0ef41Sopenharmony_ci ReportInstantiationFailure(script, position, error_reason.begin()); 3991cb0ef41Sopenharmony_ci } else { 4001cb0ef41Sopenharmony_ci ReportInstantiationFailure(script, position, "Internal wasm failure"); 4011cb0ef41Sopenharmony_ci } 4021cb0ef41Sopenharmony_ci thrower.Reset(); // Ensure exceptions do not propagate. 4031cb0ef41Sopenharmony_ci return MaybeHandle<Object>(); 4041cb0ef41Sopenharmony_ci } 4051cb0ef41Sopenharmony_ci DCHECK(!thrower.error()); 4061cb0ef41Sopenharmony_ci Handle<WasmInstanceObject> instance = maybe_instance.ToHandleChecked(); 4071cb0ef41Sopenharmony_ci 4081cb0ef41Sopenharmony_ci ReportInstantiationSuccess(script, position, 4091cb0ef41Sopenharmony_ci instantiate_timer.Elapsed().InMillisecondsF()); 4101cb0ef41Sopenharmony_ci 4111cb0ef41Sopenharmony_ci Handle<Name> single_function_name( 4121cb0ef41Sopenharmony_ci isolate->factory()->InternalizeUtf8String(AsmJs::kSingleFunctionName)); 4131cb0ef41Sopenharmony_ci MaybeHandle<Object> single_function = 4141cb0ef41Sopenharmony_ci Object::GetProperty(isolate, instance, single_function_name); 4151cb0ef41Sopenharmony_ci if (!single_function.is_null() && 4161cb0ef41Sopenharmony_ci !single_function.ToHandleChecked()->IsUndefined(isolate)) { 4171cb0ef41Sopenharmony_ci return single_function; 4181cb0ef41Sopenharmony_ci } 4191cb0ef41Sopenharmony_ci 4201cb0ef41Sopenharmony_ci // Here we rely on the fact that the exports object is eagerly created. 4211cb0ef41Sopenharmony_ci // The following check is a weak indicator for that. If this ever changes, 4221cb0ef41Sopenharmony_ci // then we'll have to call the "exports" getter, and be careful about 4231cb0ef41Sopenharmony_ci // handling possible stack overflow exceptions. 4241cb0ef41Sopenharmony_ci DCHECK(instance->exports_object().IsJSObject()); 4251cb0ef41Sopenharmony_ci return handle(instance->exports_object(), isolate); 4261cb0ef41Sopenharmony_ci} 4271cb0ef41Sopenharmony_ci 4281cb0ef41Sopenharmony_ci} // namespace internal 4291cb0ef41Sopenharmony_ci} // namespace v8 430