blob: 5535d171bec7d5328f3b3245e43eb0b0f6d557df [file] [log] [blame]
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001// Copyright 2011 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "bootstrapper.h"
31#include "code-stubs.h"
ager@chromium.orgea91cc52011-05-23 06:06:11 +000032#include "stub-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000033#include "factory.h"
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000034#include "gdb-jit.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000035#include "macro-assembler.h"
36
kasperl@chromium.org71affb52009-05-26 05:44:31 +000037namespace v8 {
38namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000039
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000040bool CodeStub::FindCodeInCache(Code** code_out) {
lrn@chromium.org7516f052011-03-30 08:52:27 +000041 Heap* heap = Isolate::Current()->heap();
42 int index = heap->code_stubs()->FindEntry(GetKey());
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000043 if (index != NumberDictionary::kNotFound) {
lrn@chromium.org7516f052011-03-30 08:52:27 +000044 *code_out = Code::cast(heap->code_stubs()->ValueAt(index));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000045 return true;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000046 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000047 return false;
48}
ager@chromium.orgc4c92722009-11-18 14:12:51 +000049
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000050
51void CodeStub::GenerateCode(MacroAssembler* masm) {
52 // Update the static counter each time a new code stub is generated.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000053 masm->isolate()->counters()->code_stubs()->Increment();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000054
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000055 // Nested stubs are not allowed for leafs.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000056 AllowStubCallsScope allow_scope(masm, AllowsStubCalls());
57
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000058 // Generate the code for the stub.
59 masm->set_generating_stub(true);
60 Generate(masm);
61}
62
63
whesse@chromium.org030d38e2011-07-13 13:23:34 +000064SmartPointer<const char> CodeStub::GetName() {
65 char buffer[100];
66 NoAllocationStringAllocator allocator(buffer,
67 static_cast<unsigned>(sizeof(buffer)));
68 StringStream stream(&allocator);
69 PrintName(&stream);
70 return stream.ToCString();
71}
72
73
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000074void CodeStub::RecordCodeGeneration(Code* code, MacroAssembler* masm) {
75 code->set_major_key(MajorKey());
76
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000077 Isolate* isolate = masm->isolate();
whesse@chromium.org030d38e2011-07-13 13:23:34 +000078 SmartPointer<const char> name = GetName();
79 PROFILE(isolate, CodeCreateEvent(Logger::STUB_TAG, code, *name));
80 GDBJIT(AddCode(GDBJITInterface::STUB, *name, code));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000081 Counters* counters = isolate->counters();
82 counters->total_stubs_code_size()->Increment(code->instruction_size());
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000083
84#ifdef ENABLE_DISASSEMBLER
85 if (FLAG_print_code_stubs) {
whesse@chromium.org030d38e2011-07-13 13:23:34 +000086 code->Disassemble(*name);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000087 PrintF("\n");
88 }
89#endif
90}
91
92
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000093int CodeStub::GetCodeKind() {
94 return Code::STUB;
95}
96
97
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000098Handle<Code> CodeStub::GetCode() {
lrn@chromium.org7516f052011-03-30 08:52:27 +000099 Isolate* isolate = Isolate::Current();
100 Factory* factory = isolate->factory();
101 Heap* heap = isolate->heap();
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000102 Code* code;
103 if (!FindCodeInCache(&code)) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000104 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000105
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000106 // Generate the new code.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000107 MacroAssembler masm(isolate, NULL, 256);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000108 GenerateCode(&masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000109
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000110 // Create the code object.
111 CodeDesc desc;
112 masm.GetCode(&desc);
113
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000114 // Copy the generated code into a heap object.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000115 Code::Flags flags = Code::ComputeFlags(
116 static_cast<Code::Kind>(GetCodeKind()),
117 InLoop(),
118 GetICState());
lrn@chromium.org7516f052011-03-30 08:52:27 +0000119 Handle<Code> new_object = factory->NewCode(
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000120 desc, flags, masm.CodeObject(), NeedsImmovableCode());
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000121 RecordCodeGeneration(*new_object, &masm);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000122 FinishCode(*new_object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000123
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000124 // Update the dictionary and the root in Heap.
125 Handle<NumberDictionary> dict =
lrn@chromium.org7516f052011-03-30 08:52:27 +0000126 factory->DictionaryAtNumberPut(
127 Handle<NumberDictionary>(heap->code_stubs()),
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000128 GetKey(),
129 new_object);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000130 heap->public_set_code_stubs(*dict);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000131
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000132 code = *new_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000133 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000134
lrn@chromium.org7516f052011-03-30 08:52:27 +0000135 ASSERT(!NeedsImmovableCode() || heap->lo_space()->Contains(code));
136 return Handle<Code>(code, isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000137}
138
139
lrn@chromium.org303ada72010-10-27 09:33:13 +0000140MaybeObject* CodeStub::TryGetCode() {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000141 Code* code;
142 if (!FindCodeInCache(&code)) {
143 // Generate the new code.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000144 MacroAssembler masm(Isolate::Current(), NULL, 256);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000145 GenerateCode(&masm);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000146 Heap* heap = masm.isolate()->heap();
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000147
148 // Create the code object.
149 CodeDesc desc;
150 masm.GetCode(&desc);
151
152 // Try to copy the generated code into a heap object.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000153 Code::Flags flags = Code::ComputeFlags(
154 static_cast<Code::Kind>(GetCodeKind()),
155 InLoop(),
156 GetICState());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000157 Object* new_object;
158 { MaybeObject* maybe_new_object =
lrn@chromium.org7516f052011-03-30 08:52:27 +0000159 heap->CreateCode(desc, flags, masm.CodeObject());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000160 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
161 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000162 code = Code::cast(new_object);
163 RecordCodeGeneration(code, &masm);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000164 FinishCode(code);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000165
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000166 // Try to update the code cache but do not fail if unable.
167 MaybeObject* maybe_new_object =
lrn@chromium.org7516f052011-03-30 08:52:27 +0000168 heap->code_stubs()->AtNumberPut(GetKey(), code);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000169 if (maybe_new_object->ToObject(&new_object)) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000170 heap->public_set_code_stubs(NumberDictionary::cast(new_object));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000171 }
172 }
173
174 return code;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000175}
176
177
ager@chromium.org5c838252010-02-19 08:53:10 +0000178const char* CodeStub::MajorName(CodeStub::Major major_key,
179 bool allow_unknown_keys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000180 switch (major_key) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000181#define DEF_CASE(name) case name: return #name "Stub";
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000182 CODE_STUB_LIST(DEF_CASE)
ager@chromium.org3811b432009-10-28 14:53:37 +0000183#undef DEF_CASE
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000184 default:
ager@chromium.org5c838252010-02-19 08:53:10 +0000185 if (!allow_unknown_keys) {
186 UNREACHABLE();
187 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000188 return NULL;
189 }
190}
191
192
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000193int ICCompareStub::MinorKey() {
194 return OpField::encode(op_ - Token::EQ) | StateField::encode(state_);
195}
196
197
198void ICCompareStub::Generate(MacroAssembler* masm) {
199 switch (state_) {
200 case CompareIC::UNINITIALIZED:
201 GenerateMiss(masm);
202 break;
203 case CompareIC::SMIS:
204 GenerateSmis(masm);
205 break;
206 case CompareIC::HEAP_NUMBERS:
207 GenerateHeapNumbers(masm);
208 break;
lrn@chromium.org1c092762011-05-09 09:42:16 +0000209 case CompareIC::STRINGS:
210 GenerateStrings(masm);
211 break;
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000212 case CompareIC::SYMBOLS:
213 GenerateSymbols(masm);
214 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000215 case CompareIC::OBJECTS:
216 GenerateObjects(masm);
217 break;
218 default:
219 UNREACHABLE();
220 }
221}
222
223
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000224void InstanceofStub::PrintName(StringStream* stream) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000225 const char* args = "";
226 if (HasArgsInRegisters()) {
227 args = "_REGS";
228 }
229
230 const char* inline_check = "";
231 if (HasCallSiteInlineCheck()) {
232 inline_check = "_INLINE";
233 }
234
235 const char* return_true_false_object = "";
236 if (ReturnTrueFalseObject()) {
237 return_true_false_object = "_TRUEFALSE";
238 }
239
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000240 stream->Add("InstanceofStub%s%s%s",
241 args,
242 inline_check,
243 return_true_false_object);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000244}
245
246
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000247void KeyedLoadElementStub::Generate(MacroAssembler* masm) {
248 switch (elements_kind_) {
249 case JSObject::FAST_ELEMENTS:
250 KeyedLoadStubCompiler::GenerateLoadFastElement(masm);
251 break;
252 case JSObject::FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000253 KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(masm);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000254 break;
255 case JSObject::EXTERNAL_BYTE_ELEMENTS:
256 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
257 case JSObject::EXTERNAL_SHORT_ELEMENTS:
258 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
259 case JSObject::EXTERNAL_INT_ELEMENTS:
260 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
261 case JSObject::EXTERNAL_FLOAT_ELEMENTS:
262 case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
263 case JSObject::EXTERNAL_PIXEL_ELEMENTS:
264 KeyedLoadStubCompiler::GenerateLoadExternalArray(masm, elements_kind_);
265 break;
266 case JSObject::DICTIONARY_ELEMENTS:
267 KeyedLoadStubCompiler::GenerateLoadDictionaryElement(masm);
268 break;
269 case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
270 UNREACHABLE();
271 break;
272 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000273}
274
275
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000276void KeyedStoreElementStub::Generate(MacroAssembler* masm) {
277 switch (elements_kind_) {
278 case JSObject::FAST_ELEMENTS:
279 KeyedStoreStubCompiler::GenerateStoreFastElement(masm, is_js_array_);
280 break;
281 case JSObject::FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000282 KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(masm,
283 is_js_array_);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000284 break;
285 case JSObject::EXTERNAL_BYTE_ELEMENTS:
286 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
287 case JSObject::EXTERNAL_SHORT_ELEMENTS:
288 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
289 case JSObject::EXTERNAL_INT_ELEMENTS:
290 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
291 case JSObject::EXTERNAL_FLOAT_ELEMENTS:
292 case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
293 case JSObject::EXTERNAL_PIXEL_ELEMENTS:
294 KeyedStoreStubCompiler::GenerateStoreExternalArray(masm, elements_kind_);
295 break;
296 case JSObject::DICTIONARY_ELEMENTS:
297 KeyedStoreStubCompiler::GenerateStoreDictionaryElement(masm);
298 break;
299 case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
300 UNREACHABLE();
301 break;
302 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000303}
304
305
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000306void ArgumentsAccessStub::PrintName(StringStream* stream) {
307 const char* type_name = NULL; // Make g++ happy.
308 switch (type_) {
309 case READ_ELEMENT: type_name = "ReadElement"; break;
310 case NEW_NON_STRICT_FAST: type_name = "NewNonStrictFast"; break;
311 case NEW_NON_STRICT_SLOW: type_name = "NewNonStrictSlow"; break;
312 case NEW_STRICT: type_name = "NewStrict"; break;
313 }
314 stream->Add("ArgumentsAccessStub_%s", type_name);
315}
316
317
318void CallFunctionStub::PrintName(StringStream* stream) {
319 const char* in_loop_name = NULL; // Make g++ happy.
320 switch (in_loop_) {
321 case NOT_IN_LOOP: in_loop_name = ""; break;
322 case IN_LOOP: in_loop_name = "_InLoop"; break;
323 }
324 const char* flags_name = NULL; // Make g++ happy.
325 switch (flags_) {
326 case NO_CALL_FUNCTION_FLAGS: flags_name = ""; break;
327 case RECEIVER_MIGHT_BE_IMPLICIT: flags_name = "_Implicit"; break;
328 }
329 stream->Add("CallFunctionStub_Args%d%s%s", argc_, in_loop_name, flags_name);
330}
331
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000332
333void ToBooleanStub::PrintName(StringStream* stream) {
334 stream->Add("ToBooleanStub_");
335 types_.Print(stream);
336}
337
338
vegorov@chromium.org7943d462011-08-01 11:41:52 +0000339void ToBooleanStub::Types::Print(StringStream* stream) const {
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000340 if (IsEmpty()) stream->Add("None");
341 if (Contains(UNDEFINED)) stream->Add("Undefined");
342 if (Contains(BOOLEAN)) stream->Add("Bool");
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000343 if (Contains(NULL_TYPE)) stream->Add("Null");
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000344 if (Contains(SMI)) stream->Add("Smi");
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000345 if (Contains(SPEC_OBJECT)) stream->Add("SpecObject");
346 if (Contains(STRING)) stream->Add("String");
347 if (Contains(HEAP_NUMBER)) stream->Add("HeapNumber");
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000348}
349
350
vegorov@chromium.org7943d462011-08-01 11:41:52 +0000351void ToBooleanStub::Types::TraceTransition(Types to) const {
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000352 if (!FLAG_trace_ic) return;
353 char buffer[100];
354 NoAllocationStringAllocator allocator(buffer,
355 static_cast<unsigned>(sizeof(buffer)));
356 StringStream stream(&allocator);
357 stream.Add("[ToBooleanIC (");
358 Print(&stream);
359 stream.Add("->");
360 to.Print(&stream);
361 stream.Add(")]\n");
362 stream.OutputToStdOut();
363}
364
365
366bool ToBooleanStub::Types::Record(Handle<Object> object) {
367 if (object->IsUndefined()) {
368 Add(UNDEFINED);
369 return false;
370 } else if (object->IsBoolean()) {
371 Add(BOOLEAN);
372 return object->IsTrue();
373 } else if (object->IsNull()) {
374 Add(NULL_TYPE);
375 return false;
376 } else if (object->IsSmi()) {
377 Add(SMI);
378 return Smi::cast(*object)->value() != 0;
379 } else if (object->IsSpecObject()) {
380 Add(SPEC_OBJECT);
381 return !object->IsUndetectableObject();
382 } else if (object->IsString()) {
383 Add(STRING);
384 return !object->IsUndetectableObject() &&
385 String::cast(*object)->length() != 0;
386 } else if (object->IsHeapNumber()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000387 ASSERT(!object->IsUndetectableObject());
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000388 Add(HEAP_NUMBER);
389 double value = HeapNumber::cast(*object)->value();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000390 return value != 0 && !isnan(value);
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000391 } else {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000392 // We should never see an internal object at runtime here!
393 UNREACHABLE();
394 return true;
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000395 }
396}
397
398
vegorov@chromium.org7943d462011-08-01 11:41:52 +0000399bool ToBooleanStub::Types::NeedsMap() const {
400 return Contains(ToBooleanStub::SPEC_OBJECT)
401 || Contains(ToBooleanStub::STRING)
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000402 || Contains(ToBooleanStub::HEAP_NUMBER);
403}
404
405
406bool ToBooleanStub::Types::CanBeUndetectable() const {
407 return Contains(ToBooleanStub::SPEC_OBJECT)
408 || Contains(ToBooleanStub::STRING);
vegorov@chromium.org7943d462011-08-01 11:41:52 +0000409}
410
411
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000412} } // namespace v8::internal