blob: 310611cdf75f6fabcb46612815731c3cd3aba3ca [file] [log] [blame]
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001// Copyright 2006-2008 Google Inc. All Rights Reserved.
2// 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 <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
35#include "compiler.h"
36#include "cpu.h"
37#include "dateparser.h"
38#include "debug.h"
39#include "execution.h"
40#include "jsregexp.h"
41#include "platform.h"
42#include "runtime.h"
43#include "scopeinfo.h"
44#include "v8threads.h"
45
46namespace v8 { namespace internal {
47
48
49#define RUNTIME_ASSERT(value) do { \
50 if (!(value)) return IllegalOperation(); \
51} while (false)
52
53// Cast the given object to a value of the specified type and store
54// it in a variable with the given name. If the object is not of the
55// expected type call IllegalOperation and return.
56#define CONVERT_CHECKED(Type, name, obj) \
57 RUNTIME_ASSERT(obj->Is##Type()); \
58 Type* name = Type::cast(obj);
59
60#define CONVERT_ARG_CHECKED(Type, name, index) \
61 RUNTIME_ASSERT(args[index]->Is##Type()); \
62 Handle<Type> name = args.at<Type>(index);
63
kasper.lundbd3ec4e2008-07-09 11:06:54 +000064// Cast the given object to a boolean and store it in a variable with
65// the given name. If the object is not a boolean call IllegalOperation
66// and return.
67#define CONVERT_BOOLEAN_CHECKED(name, obj) \
68 RUNTIME_ASSERT(obj->IsBoolean()); \
69 bool name = (obj)->IsTrue();
70
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000071// Cast the given object to a double and store it in a variable with
72// the given name. If the object is not a number (as opposed to
73// the number not-a-number) call IllegalOperation and return.
74#define CONVERT_DOUBLE_CHECKED(name, obj) \
75 RUNTIME_ASSERT(obj->IsNumber()); \
76 double name = (obj)->Number();
77
78// Call the specified converter on the object *comand store the result in
79// a variable of the specified type with the given name. If the
80// object is not a Number call IllegalOperation and return.
81#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
82 RUNTIME_ASSERT(obj->IsNumber()); \
83 type name = NumberTo##Type(obj);
84
85// Non-reentrant string buffer for efficient general use in this file.
86static StaticResource<StringInputBuffer> string_input_buffer;
87
88
89static Object* IllegalOperation() {
90 return Top::Throw(Heap::illegal_access_symbol());
91}
92
93
94static Object* Runtime_CloneObjectLiteralBoilerplate(Arguments args) {
95 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096 return boilerplate->Copy();
97}
98
99
100static Object* Runtime_CreateObjectLiteralBoilerplate(Arguments args) {
101 HandleScope scope;
102 ASSERT(args.length() == 3);
103 // Copy the arguments.
104 Handle<FixedArray> literals = args.at<FixedArray>(0);
105 int literals_index = Smi::cast(args[1])->value();
106 Handle<FixedArray> constant_properties = args.at<FixedArray>(2);
107
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000108 // Get the object function from the literals array. This is the
109 // object function from the context in which the function was
110 // created. We do not use the object function from the current
111 // global context because this might be the object function from
112 // another context which we should not have access to.
113 const int kObjectFunIndex = JSFunction::kLiteralObjectFunctionIndex;
114 Handle<JSFunction> constructor =
115 Handle<JSFunction>(JSFunction::cast(literals->get(kObjectFunIndex)));
116
117 Handle<JSObject> boilerplate = Factory::NewJSObject(constructor, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000118
119 { // Add the constant propeties to the boilerplate.
120 int length = constant_properties->length();
121 OptimizedObjectForAddingMultipleProperties opt(boilerplate, true);
122 for (int index = 0; index < length; index +=2) {
123 Handle<Object> key(constant_properties->get(index+0));
124 Handle<Object> value(constant_properties->get(index+1));
125 uint32_t element_index = 0;
126 if (key->IsSymbol()) {
127 // If key is a symbol it is not an array element.
128 Handle<String> name(String::cast(*key));
129 ASSERT(!name->AsArrayIndex(&element_index));
130 SetProperty(boilerplate, name, value, NONE);
131 } else if (Array::IndexFromObject(*key, &element_index)) {
132 // Array index (uint32).
133 SetElement(boilerplate, element_index, value);
134 } else {
135 // Non-uint32 number.
136 ASSERT(key->IsNumber());
137 double num = key->Number();
138 char arr[100];
139 Vector<char> buffer(arr, ARRAY_SIZE(arr));
140 const char* str = DoubleToCString(num, buffer);
141 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
142 SetProperty(boilerplate, name, value, NONE);
143 }
144 }
145 }
146
147 // Update the functions literal and return the boilerplate.
148 literals->set(literals_index, *boilerplate);
149
150 return *boilerplate;
151}
152
153
154static Object* Runtime_CreateArrayLiteral(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000155 // Takes a FixedArray of elements containing the literal elements of
156 // the array literal and produces JSArray with those elements.
157 // Additionally takes the literals array of the surrounding function
158 // which contains the Array function to use for creating the array
159 // literal.
160 ASSERT(args.length() == 2);
161 CONVERT_CHECKED(FixedArray, elements, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000162
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000163#ifdef USE_OLD_CALLING_CONVENTIONS
164 ASSERT(args[1]->IsTheHole());
165 // TODO(1332579): Pass in the literals array from the function once
166 // the new calling convention is in place on ARM. Currently, we
167 // retrieve the array constructor from the global context. This is
168 // a security problem since the global object might have been
169 // reinitialized and the array constructor from the global context
170 // might be from a context that we are not allowed to access.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000171 JSFunction* constructor =
172 JSFunction::cast(Top::context()->global_context()->array_function());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000173#else
174 CONVERT_CHECKED(FixedArray, literals, args[1]);
175 const int kArrayFunIndex = JSFunction::kLiteralArrayFunctionIndex;
176 JSFunction* constructor = JSFunction::cast(literals->get(kArrayFunIndex));
177#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000178
179 // Create the JSArray.
180 Object* object = Heap::AllocateJSObject(constructor);
181 if (object->IsFailure()) return object;
182
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000183 // Copy the elements.
184 Object* content = elements->Copy();
185 if (content->IsFailure()) return content;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000186
187 // Set the elements.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000188 JSArray::cast(object)->SetContent(FixedArray::cast(content));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000189 return object;
190}
191
192
193static Object* Runtime_ClassOf(Arguments args) {
194 NoHandleAllocation ha;
195 ASSERT(args.length() == 1);
196 Object* obj = args[0];
197 if (!obj->IsJSObject()) return Heap::null_value();
198 return JSObject::cast(obj)->class_name();
199}
200
201
202static Object* Runtime_IsInPrototypeChain(Arguments args) {
203 NoHandleAllocation ha;
204 ASSERT(args.length() == 2);
205 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
206 Object* O = args[0];
207 Object* V = args[1];
208 while (true) {
209 Object* prototype = V->GetPrototype();
210 if (prototype->IsNull()) return Heap::false_value();
211 if (O == prototype) return Heap::true_value();
212 V = prototype;
213 }
214}
215
216
217static Object* Runtime_IsConstructCall(Arguments args) {
218 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000219 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000220 JavaScriptFrameIterator it;
221 return Heap::ToBoolean(it.frame()->IsConstructor());
222}
223
224
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000225static Object* Runtime_RegExpCompile(Arguments args) {
226 HandleScope scope; // create a new handle scope
227 ASSERT(args.length() == 3);
228 CONVERT_CHECKED(JSValue, raw_re, args[0]);
229 Handle<JSValue> re(raw_re);
230 CONVERT_CHECKED(String, raw_pattern, args[1]);
231 Handle<String> pattern(raw_pattern);
232 CONVERT_CHECKED(String, raw_flags, args[2]);
233 Handle<String> flags(raw_flags);
234 return *RegExpImpl::JsreCompile(re, pattern, flags);
235}
236
237
238static Object* Runtime_CreateApiFunction(Arguments args) {
239 HandleScope scope;
240 ASSERT(args.length() == 1);
241 CONVERT_CHECKED(FunctionTemplateInfo, raw_data, args[0]);
242 Handle<FunctionTemplateInfo> data(raw_data);
243 return *Factory::CreateApiFunction(data);
244}
245
246
247static Object* Runtime_IsTemplate(Arguments args) {
248 ASSERT(args.length() == 1);
249 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000250 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000251 return Heap::ToBoolean(result);
252}
253
254
255static Object* Runtime_GetTemplateField(Arguments args) {
256 ASSERT(args.length() == 2);
257 CONVERT_CHECKED(HeapObject, templ, args[0]);
258 RUNTIME_ASSERT(templ->IsStruct());
259 CONVERT_CHECKED(Smi, field, args[1]);
260 return HeapObject::GetHeapObjectField(templ, field->value());
261}
262
263
264static Object* ThrowRedeclarationError(const char* type, Handle<String> name) {
265 HandleScope scope;
266 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
267 Handle<Object> args[2] = { type_handle, name };
268 Handle<Object> error =
269 Factory::NewTypeError("redeclaration", HandleVector(args, 2));
270 return Top::Throw(*error);
271}
272
273
274static Object* Runtime_DeclareGlobals(Arguments args) {
275 HandleScope scope;
276 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
277
278 CONVERT_ARG_CHECKED(FixedArray, pairs, 0);
279 Handle<Context> context = args.at<Context>(1);
280 bool is_eval = Smi::cast(args[2])->value() == 1;
281
282 // Compute the property attributes. According to ECMA-262, section
283 // 13, page 71, the property must be read-only and
284 // non-deletable. However, neither SpiderMonkey nor KJS creates the
285 // property as read-only, so we don't either.
286 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
287
288 // Only optimize the object if we intend to add more than 5 properties.
289 OptimizedObjectForAddingMultipleProperties ba(global, pairs->length()/2 > 5);
290
291 // Traverse the name/value pairs and set the properties.
292 int length = pairs->length();
293 for (int i = 0; i < length; i += 2) {
294 HandleScope scope;
295 Handle<String> name(String::cast(pairs->get(i)));
296 Handle<Object> value(pairs->get(i + 1));
297
298 // We have to declare a global const property. To capture we only
299 // assign to it when evaluating the assignment for "const x =
300 // <expr>" the initial value is the hole.
301 bool is_const_property = value->IsTheHole();
302
303 if (value->IsUndefined() || is_const_property) {
304 // Lookup the property in the global object, and don't set the
305 // value of the variable if the property is already there.
306 LookupResult lookup;
307 global->Lookup(*name, &lookup);
308 if (lookup.IsProperty()) {
309 // Determine if the property is local by comparing the holder
310 // against the global object. The information will be used to
311 // avoid throwing re-declaration errors when declaring
312 // variables or constants that exist in the prototype chain.
313 bool is_local = (*global == lookup.holder());
314 // Get the property attributes and determine if the property is
315 // read-only.
316 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
317 bool is_read_only = (attributes & READ_ONLY) != 0;
318 if (lookup.type() == INTERCEPTOR) {
319 // If the interceptor says the property is there, we
320 // just return undefined without overwriting the property.
321 // Otherwise, we continue to setting the property.
322 if (attributes != ABSENT) {
323 // Check if the existing property conflicts with regards to const.
324 if (is_local && (is_read_only || is_const_property)) {
325 const char* type = (is_read_only) ? "const" : "var";
326 return ThrowRedeclarationError(type, name);
327 };
328 // The property already exists without conflicting: Go to
329 // the next declaration.
330 continue;
331 }
332 // Fall-through and introduce the absent property by using
333 // SetProperty.
334 } else {
335 if (is_local && (is_read_only || is_const_property)) {
336 const char* type = (is_read_only) ? "const" : "var";
337 return ThrowRedeclarationError(type, name);
338 }
339 // The property already exists without conflicting: Go to
340 // the next declaration.
341 continue;
342 }
343 }
344 } else {
345 // Copy the function and update its context. Use it as value.
346 Handle<JSFunction> boilerplate = Handle<JSFunction>::cast(value);
347 Handle<JSFunction> function =
348 Factory::NewFunctionFromBoilerplate(boilerplate, context);
349 value = function;
350 }
351
352 LookupResult lookup;
353 global->LocalLookup(*name, &lookup);
354
355 PropertyAttributes attributes = is_const_property
356 ? static_cast<PropertyAttributes>(base | READ_ONLY)
357 : base;
358
359 if (lookup.IsProperty()) {
360 // There's a local property that we need to overwrite because
361 // we're either declaring a function or there's an interceptor
362 // that claims the property is absent.
363
364 // Check for conflicting re-declarations. We cannot have
365 // conflicting types in case of intercepted properties because
366 // they are absent.
367 if (lookup.type() != INTERCEPTOR &&
368 (lookup.IsReadOnly() || is_const_property)) {
369 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
370 return ThrowRedeclarationError(type, name);
371 }
372 SetProperty(global, name, value, attributes);
373 } else {
374 // If a property with this name does not already exist on the
375 // global object add the property locally. We take special
376 // precautions to always add it as a local property even in case
377 // of callbacks in the prototype chain (this rules out using
378 // SetProperty). Also, we must use the handle-based version to
379 // avoid GC issues.
380 AddProperty(global, name, value, attributes);
381 }
382 }
383 // Done.
384 return Heap::undefined_value();
385}
386
387
388static Object* Runtime_DeclareContextSlot(Arguments args) {
389 HandleScope scope;
390 ASSERT(args.length() == 5);
391
392 // args[0] is result (TOS)
393 CONVERT_ARG_CHECKED(Context, context, 1);
394 Handle<String> name(String::cast(args[2]));
395 PropertyAttributes mode =
396 static_cast<PropertyAttributes>(Smi::cast(args[3])->value());
397 ASSERT(mode == READ_ONLY || mode == NONE);
398 Handle<Object> initial_value(args[4]);
399
400 // Declarations are always done in the function context.
401 context = Handle<Context>(context->fcontext());
402
403 int index;
404 PropertyAttributes attributes;
405 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
406 Handle<Object> context_obj =
407 context->Lookup(name, flags, &index, &attributes);
408
409 if (attributes != ABSENT) {
410 // The name was declared before; check for conflicting
411 // re-declarations: This is similar to the code in parser.cc in
412 // the AstBuildingParser::Declare function.
413 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
414 // Functions are not read-only.
415 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
416 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
417 return ThrowRedeclarationError(type, name);
418 }
419
420 // Initialize it if necessary.
421 if (*initial_value != NULL) {
422 if (index >= 0) {
423 // The variable or constant context slot should always be in
424 // the function context; not in any outer context nor in the
425 // arguments object.
426 ASSERT(context_obj.is_identical_to(context));
427 if (((attributes & READ_ONLY) == 0) ||
428 context->get(index)->IsTheHole()) {
429 context->set(index, *initial_value);
430 }
431 } else {
432 // Slow case: The property is not in the FixedArray part of the context.
433 Handle<JSObject> context_ext = Handle<JSObject>::cast(context_obj);
434 SetProperty(context_ext, name, initial_value, mode);
435 }
436 }
437 return args[0]; // return TOS
438 }
439
440 // The property is not in the function context. It needs to be "declared"
441 // in the function context's extension context, or in the global context.
442 Handle<JSObject> context_ext;
443 if (context->extension() != NULL) {
444 // The function context's extension context exists - use it.
445 context_ext = Handle<JSObject>(context->extension());
446 } else {
447 // The function context's extension context does not exists - allocate it.
448 context_ext = Factory::NewJSObject(Top::context_extension_function());
449 // And store it in the extension slot.
450 context->set_extension(*context_ext);
451 }
452 ASSERT(*context_ext != NULL);
453
454 // Declare the property by setting it to the initial value if provided,
455 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
456 // constant declarations).
457 ASSERT(!context_ext->HasLocalProperty(*name));
458 Handle<Object> value(Heap::undefined_value());
459 if (*initial_value != NULL) value = initial_value;
460 SetProperty(context_ext, name, value, mode);
461 ASSERT(context_ext->GetLocalPropertyAttribute(*name) == mode);
462 return args[0]; // return TOS
463}
464
465
466static Object* Runtime_InitializeVarGlobal(Arguments args) {
467 NoHandleAllocation nha;
468
469 // Determine if we need to assign to the variable if it already
470 // exists (based on the number of arguments).
471 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
472 bool assign = args.length() == 2;
473
474 CONVERT_ARG_CHECKED(String, name, 0);
475 GlobalObject* global = Top::context()->global();
476
477 // According to ECMA-262, section 12.2, page 62, the property must
478 // not be deletable.
479 PropertyAttributes attributes = DONT_DELETE;
480
481 // Lookup the property locally in the global object. If it isn't
482 // there, we add the property and take special precautions to always
483 // add it as a local property even in case of callbacks in the
484 // prototype chain (this rules out using SetProperty).
485 LookupResult lookup;
486 global->LocalLookup(*name, &lookup);
487 if (!lookup.IsProperty()) {
488 Object* value = (assign) ? args[1] : Heap::undefined_value();
489 return global->AddProperty(*name, value, attributes);
490 }
491
492 // Determine if this is a redeclaration of something read-only.
493 if (lookup.IsReadOnly()) {
494 return ThrowRedeclarationError("const", name);
495 }
496
497 // Determine if this is a redeclaration of an intercepted read-only
498 // property and figure out if the property exists at all.
499 bool found = true;
500 PropertyType type = lookup.type();
501 if (type == INTERCEPTOR) {
502 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
503 if (intercepted == ABSENT) {
504 // The interceptor claims the property isn't there. We need to
505 // make sure to introduce it.
506 found = false;
507 } else if ((intercepted & READ_ONLY) != 0) {
508 // The property is present, but read-only. Since we're trying to
509 // overwrite it with a variable declaration we must throw a
510 // re-declaration error.
511 return ThrowRedeclarationError("const", name);
512 }
513 // Restore global object from context (in case of GC).
514 global = Top::context()->global();
515 }
516
517 if (found && !assign) {
518 // The global property is there and we're not assigning any value
519 // to it. Just return.
520 return Heap::undefined_value();
521 }
522
523 // Assign the value (or undefined) to the property.
524 Object* value = (assign) ? args[1] : Heap::undefined_value();
525 return global->SetProperty(&lookup, *name, value, attributes);
526}
527
528
529static Object* Runtime_InitializeConstGlobal(Arguments args) {
530 // All constants are declared with an initial value. The name
531 // of the constant is the first argument and the initial value
532 // is the second.
533 RUNTIME_ASSERT(args.length() == 2);
534 CONVERT_ARG_CHECKED(String, name, 0);
535 Handle<Object> value = args.at<Object>(1);
536
537 // Get the current global object from top.
538 GlobalObject* global = Top::context()->global();
539
540 // According to ECMA-262, section 12.2, page 62, the property must
541 // not be deletable. Since it's a const, it must be READ_ONLY too.
542 PropertyAttributes attributes =
543 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
544
545 // Lookup the property locally in the global object. If it isn't
546 // there, we add the property and take special precautions to always
547 // add it as a local property even in case of callbacks in the
548 // prototype chain (this rules out using SetProperty).
549 LookupResult lookup;
550 global->LocalLookup(*name, &lookup);
551 if (!lookup.IsProperty()) {
552 return global->AddProperty(*name, *value, attributes);
553 }
554
555 // Determine if this is a redeclaration of something not
556 // read-only. In case the result is hidden behind an interceptor we
557 // need to ask it for the property attributes.
558 if (!lookup.IsReadOnly()) {
559 if (lookup.type() != INTERCEPTOR) {
560 return ThrowRedeclarationError("var", name);
561 }
562
563 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
564
565 // Throw re-declaration error if the intercepted property is present
566 // but not read-only.
567 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
568 return ThrowRedeclarationError("var", name);
569 }
570
571 // Restore global object from context (in case of GC) and continue
572 // with setting the value because the property is either absent or
573 // read-only. We also have to do redo the lookup.
574 global = Top::context()->global();
575
576 // BUG 1213579: Handle the case where we have to set a read-only
577 // property through an interceptor and only do it if it's
578 // uninitialized, e.g. the hole. Nirk...
579 global->SetProperty(*name, *value, attributes);
580 return *value;
581 }
582
583 // Set the value, but only we're assigning the initial value to a
584 // constant. For now, we determine this by checking if the
585 // current value is the hole.
586 PropertyType type = lookup.type();
587 if (type == FIELD) {
588 FixedArray* properties = global->properties();
589 int index = lookup.GetFieldIndex();
590 if (properties->get(index)->IsTheHole()) {
591 properties->set(index, *value);
592 }
593 } else if (type == NORMAL) {
594 Dictionary* dictionary = global->property_dictionary();
595 int entry = lookup.GetDictionaryEntry();
596 if (dictionary->ValueAt(entry)->IsTheHole()) {
597 dictionary->ValueAtPut(entry, *value);
598 }
599 } else {
600 // Ignore re-initialization of constants that have already been
601 // assigned a function value.
602 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
603 }
604
605 // Use the set value as the result of the operation.
606 return *value;
607}
608
609
610static Object* Runtime_InitializeConstContextSlot(Arguments args) {
611 HandleScope scope;
612 ASSERT(args.length() == 3);
613
614 Handle<Object> value(args[0]);
615 ASSERT(!value->IsTheHole());
616 CONVERT_ARG_CHECKED(Context, context, 1);
617 Handle<String> name(String::cast(args[2]));
618
619 // Initializations are always done in the function context.
620 context = Handle<Context>(context->fcontext());
621
622 int index;
623 PropertyAttributes attributes;
624 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
625 Handle<Object> context_obj =
626 context->Lookup(name, flags, &index, &attributes);
627
628 // The property should always be present. It is always declared
629 // before being initialized through DeclareContextSlot.
630 ASSERT(attributes != ABSENT && (attributes & READ_ONLY) != 0);
631
632 // If the slot is in the context, we set it but only if it hasn't
633 // been set before.
634 if (index >= 0) {
635 // The constant context slot should always be in the function
636 // context; not in any outer context nor in the arguments object.
637 ASSERT(context_obj.is_identical_to(context));
638 if (context->get(index)->IsTheHole()) {
639 context->set(index, *value);
640 }
641 return *value;
642 }
643
644 // Otherwise, the slot must be in a JS object extension.
645 Handle<JSObject> context_ext(JSObject::cast(*context_obj));
646
647 // We must initialize the value only if it wasn't initialized
648 // before, e.g. for const declarations in a loop. The property has
649 // the hole value if it wasn't initialized yet. NOTE: We cannot use
650 // GetProperty() to get the current value as it 'unholes' the value.
651 LookupResult lookup;
652 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
653 ASSERT(lookup.IsProperty()); // the property was declared
654 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
655
656 PropertyType type = lookup.type();
657 if (type == FIELD) {
658 FixedArray* properties = context_ext->properties();
659 int index = lookup.GetFieldIndex();
660 if (properties->get(index)->IsTheHole()) {
661 properties->set(index, *value);
662 }
663 } else if (type == NORMAL) {
664 Dictionary* dictionary = context_ext->property_dictionary();
665 int entry = lookup.GetDictionaryEntry();
666 if (dictionary->ValueAt(entry)->IsTheHole()) {
667 dictionary->ValueAtPut(entry, *value);
668 }
669 } else {
670 // We should not reach here. Any real, named property should be
671 // either a field or a dictionary slot.
672 UNREACHABLE();
673 }
674 return *value;
675}
676
677
678static Object* Runtime_RegExpExec(Arguments args) {
679 HandleScope scope;
680 ASSERT(args.length() == 3);
681 CONVERT_CHECKED(JSValue, raw_regexp, args[0]);
682 Handle<JSValue> regexp(raw_regexp);
683 CONVERT_CHECKED(String, raw_subject, args[1]);
684 Handle<String> subject(raw_subject);
685 Handle<Object> index(args[2]);
686 ASSERT(index->IsNumber());
687 return *RegExpImpl::JsreExec(regexp, subject, index);
688}
689
690
691static Object* Runtime_RegExpExecGlobal(Arguments args) {
692 HandleScope scope;
693 ASSERT(args.length() == 2);
694 CONVERT_CHECKED(JSValue, raw_regexp, args[0]);
695 Handle<JSValue> regexp(raw_regexp);
696 CONVERT_CHECKED(String, raw_subject, args[1]);
697 Handle<String> subject(raw_subject);
698 return *RegExpImpl::JsreExecGlobal(regexp, subject);
699}
700
701
702static Object* Runtime_MaterializeRegExpLiteral(Arguments args) {
703 HandleScope scope;
704 ASSERT(args.length() == 4);
705 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
706 int index = Smi::cast(args[1])->value();
707 Handle<String> pattern = args.at<String>(2);
708 Handle<String> flags = args.at<String>(3);
709
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000710 // Get the RegExp function from the literals array. This is the
711 // RegExp function from the context in which the function was
712 // created. We do not use the RegExp function from the current
713 // global context because this might be the RegExp function from
714 // another context which we should not have access to.
715 const int kRegexpFunIndex = JSFunction::kLiteralRegExpFunctionIndex;
716 Handle<JSFunction> constructor =
717 Handle<JSFunction>(JSFunction::cast(literals->get(kRegexpFunIndex)));
718
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000719 // Compute the regular expression literal.
720 bool has_pending_exception;
721 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000722 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
723 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000724 if (has_pending_exception) {
725 ASSERT(Top::has_pending_exception());
726 return Failure::Exception();
727 }
728 literals->set(index, *regexp);
729 return *regexp;
730}
731
732
733static Object* Runtime_FunctionGetName(Arguments args) {
734 NoHandleAllocation ha;
735 ASSERT(args.length() == 1);
736
737 CONVERT_CHECKED(JSFunction, f, args[0]);
738 return f->shared()->name();
739}
740
741
742static Object* Runtime_FunctionGetScript(Arguments args) {
743 HandleScope scope;
744 ASSERT(args.length() == 1);
745
746 CONVERT_CHECKED(JSFunction, fun, args[0]);
747 Handle<Object> script = Handle<Object>(fun->shared()->script());
748 if (!script->IsScript()) return Heap::undefined_value();
749
750 return *GetScriptWrapper(Handle<Script>::cast(script));
751}
752
753
754static Object* Runtime_FunctionGetSourceCode(Arguments args) {
755 NoHandleAllocation ha;
756 ASSERT(args.length() == 1);
757
758 CONVERT_CHECKED(JSFunction, f, args[0]);
759 return f->shared()->GetSourceCode();
760}
761
762
763static Object* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
764 NoHandleAllocation ha;
765 ASSERT(args.length() == 1);
766
767 CONVERT_CHECKED(JSFunction, fun, args[0]);
768 int pos = fun->shared()->start_position();
769 return Smi::FromInt(pos);
770}
771
772
773static Object* Runtime_FunctionSetInstanceClassName(Arguments args) {
774 NoHandleAllocation ha;
775 ASSERT(args.length() == 2);
776
777 CONVERT_CHECKED(JSFunction, fun, args[0]);
778 CONVERT_CHECKED(String, name, args[1]);
779 fun->SetInstanceClassName(name);
780 return Heap::undefined_value();
781}
782
783
784static Object* Runtime_FunctionSetLength(Arguments args) {
785 NoHandleAllocation ha;
786 ASSERT(args.length() == 2);
787
788 CONVERT_CHECKED(JSFunction, fun, args[0]);
789 CONVERT_CHECKED(Smi, length, args[1]);
790 fun->shared()->set_length(length->value());
791 return length;
792}
793
794
795static Object* Runtime_FunctionSetPrototype(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000796 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000797 ASSERT(args.length() == 2);
798
799 CONVERT_CHECKED(JSFunction, fun, args[0]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000800 Object* obj = Accessors::FunctionSetPrototype(fun, args[1], NULL);
801 if (obj->IsFailure()) return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000802 return args[0]; // return TOS
803}
804
805
806static Object* Runtime_SetCode(Arguments args) {
807 HandleScope scope;
808 ASSERT(args.length() == 2);
809
810 CONVERT_CHECKED(JSFunction, raw_target, args[0]);
811 Handle<JSFunction> target(raw_target);
812 Handle<Object> code = args.at<Object>(1);
813
814 Handle<Context> context(target->context());
815
816 if (!code->IsNull()) {
817 RUNTIME_ASSERT(code->IsJSFunction());
818 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
819 SetExpectedNofProperties(target, fun->shared()->expected_nof_properties());
820 if (!fun->is_compiled() && !CompileLazy(fun, KEEP_EXCEPTION)) {
821 return Failure::Exception();
822 }
823 // Set the code, formal parameter count, and the length of the target
824 // function.
825 target->set_code(fun->code());
826 target->shared()->set_length(fun->shared()->length());
827 target->shared()->set_formal_parameter_count(
828 fun->shared()->formal_parameter_count());
kasper.lund7276f142008-07-30 08:49:36 +0000829 // Set the source code of the target function.
830 target->shared()->set_script(fun->shared()->script());
831 target->shared()->set_start_position(fun->shared()->start_position());
832 target->shared()->set_end_position(fun->shared()->end_position());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000833 context = Handle<Context>(fun->context());
834
835 // Make sure we get a fresh copy of the literal vector to avoid
836 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000837 int number_of_literals = fun->NumberOfLiterals();
838 Handle<FixedArray> literals =
839 Factory::NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000840 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000841 // Insert the object, regexp and array functions in the literals
842 // array prefix. These are the functions that will be used when
843 // creating object, regexp and array literals.
844 literals->set(JSFunction::kLiteralObjectFunctionIndex,
845 context->global_context()->object_function());
846 literals->set(JSFunction::kLiteralRegExpFunctionIndex,
847 context->global_context()->regexp_function());
848 literals->set(JSFunction::kLiteralArrayFunctionIndex,
849 context->global_context()->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000850 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000851 target->set_literals(*literals);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000852 }
853
854 target->set_context(*context);
855 return *target;
856}
857
858
859static Object* CharCodeAt(String* subject, Object* index) {
860 uint32_t i = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000861 if (!Array::IndexFromObject(index, &i)) return Heap::nan_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000862 // Flatten the string. If someone wants to get a char at an index
863 // in a cons string, it is likely that more indices will be
864 // accessed.
865 subject->TryFlatten();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000866 if (i >= static_cast<uint32_t>(subject->length())) return Heap::nan_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000867 return Smi::FromInt(subject->Get(i));
868}
869
870
871static Object* Runtime_StringCharCodeAt(Arguments args) {
872 NoHandleAllocation ha;
873 ASSERT(args.length() == 2);
874
875 CONVERT_CHECKED(String, subject, args[0]);
876 Object* index = args[1];
877 return CharCodeAt(subject, index);
878}
879
880
881static Object* Runtime_CharFromCode(Arguments args) {
882 NoHandleAllocation ha;
883 ASSERT(args.length() == 1);
884 uint32_t code;
885 if (Array::IndexFromObject(args[0], &code)) {
886 if (code <= 0xffff) {
887 return Heap::LookupSingleCharacterStringFromCode(code);
888 }
889 }
890 return Heap::empty_string();
891}
892
893
894static inline void ComputeKMPNextTable(String* pattern, int next_table[]) {
895 int i = 0;
896 int j = -1;
897 next_table[0] = -1;
898
899 Access<StringInputBuffer> buffer(&string_input_buffer);
900 buffer->Reset(pattern);
901 int length = pattern->length();
902 uint16_t p = buffer->GetNext();
903 while (i < length - 1) {
904 while (j > -1 && p != pattern->Get(j)) {
905 j = next_table[j];
906 }
907 i++;
908 j++;
909 p = buffer->GetNext();
910 if (p == pattern->Get(j)) {
911 next_table[i] = next_table[j];
912 } else {
913 next_table[i] = j;
914 }
915 }
916}
917
918
919static Object* Runtime_StringIndexOf(Arguments args) {
920 NoHandleAllocation ha;
921 ASSERT(args.length() == 3);
922
923 CONVERT_CHECKED(String, sub, args[0]);
924 CONVERT_CHECKED(String, pat, args[1]);
925 Object* index = args[2];
926
927 int subject_length = sub->length();
928 int pattern_length = pat->length();
929
930 sub->TryFlatten();
931 pat->TryFlatten();
932
933 uint32_t start_index;
934 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
935 if (pattern_length == 0) return Smi::FromInt(start_index);
936
937 // Searching for one specific character is common. For one
938 // character patterns the KMP algorithm is guaranteed to slow down
939 // the search, so we just run through the subject string.
940 if (pattern_length == 1) {
941 uint16_t pattern_char = pat->Get(0);
942 for (int i = start_index; i < subject_length; i++) {
943 if (sub->Get(i) == pattern_char) {
944 return Smi::FromInt(i);
945 }
946 }
947 return Smi::FromInt(-1);
948 }
949
950 // For patterns with a length larger than one character we use the KMP
951 // algorithm.
952 //
953 // Compute the 'next' table.
954 int* next_table = NewArray<int>(pattern_length);
955 ComputeKMPNextTable(pat, next_table);
956 // Search using the 'next' table.
957 int pattern_index = 0;
958 // We would like to use StringInputBuffer here, but it does not have
959 // the ability to start anywhere but the first character of a
960 // string. It would be nice to have efficient forward-seeking
961 // support on StringInputBuffers.
962 int subject_index = start_index;
963 while (subject_index < subject_length) {
964 uint16_t subject_char = sub->Get(subject_index);
965 while (pattern_index > -1 && pat->Get(pattern_index) != subject_char) {
966 pattern_index = next_table[pattern_index];
967 }
968 pattern_index++;
969 subject_index++;
970 if (pattern_index >= pattern_length) {
971 DeleteArray(next_table);
972 return Smi::FromInt(subject_index - pattern_index);
973 }
974 }
975 DeleteArray(next_table);
976 return Smi::FromInt(-1);
977}
978
979
980static Object* Runtime_StringLastIndexOf(Arguments args) {
981 NoHandleAllocation ha;
982 ASSERT(args.length() == 3);
983
984 CONVERT_CHECKED(String, sub, args[0]);
985 CONVERT_CHECKED(String, pat, args[1]);
986 Object* index = args[2];
987
988 sub->TryFlatten();
989 pat->TryFlatten();
990
991 uint32_t start_index;
992 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
993
994 uint32_t pattern_length = pat->length();
995 uint32_t sub_length = sub->length();
996
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000997 if (start_index + pattern_length > sub_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998 start_index = sub_length - pattern_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000999 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001000
1001 for (int i = start_index; i >= 0; i--) {
1002 bool found = true;
1003 for (uint32_t j = 0; j < pattern_length; j++) {
1004 if (sub->Get(i + j) != pat->Get(j)) {
1005 found = false;
1006 break;
1007 }
1008 }
1009 if (found) return Smi::FromInt(i);
1010 }
1011
1012 return Smi::FromInt(-1);
1013}
1014
1015
1016static Object* Runtime_StringLocaleCompare(Arguments args) {
1017 NoHandleAllocation ha;
1018 ASSERT(args.length() == 2);
1019
1020 CONVERT_CHECKED(String, str1, args[0]);
1021 CONVERT_CHECKED(String, str2, args[1]);
1022
1023 if (str1 == str2) return Smi::FromInt(0); // Equal.
1024 int str1_length = str1->length();
1025 int str2_length = str2->length();
1026
1027 // Decide trivial cases without flattening.
1028 if (str1_length == 0) {
1029 if (str2_length == 0) return Smi::FromInt(0); // Equal.
1030 return Smi::FromInt(-str2_length);
1031 } else {
1032 if (str2_length == 0) return Smi::FromInt(str1_length);
1033 }
1034
1035 int end = str1_length < str2_length ? str1_length : str2_length;
1036
1037 // No need to flatten if we are going to find the answer on the first
1038 // character. At this point we know there is at least one character
1039 // in each string, due to the trivial case handling above.
1040 int d = str1->Get(0) - str2->Get(0);
1041 if (d != 0) return Smi::FromInt(d);
1042
1043 str1->TryFlatten();
1044 str2->TryFlatten();
1045
1046 static StringInputBuffer buf1;
1047 static StringInputBuffer buf2;
1048
1049 buf1.Reset(str1);
1050 buf2.Reset(str2);
1051
1052 for (int i = 0; i < end; i++) {
1053 uint16_t char1 = buf1.GetNext();
1054 uint16_t char2 = buf2.GetNext();
1055 if (char1 != char2) return Smi::FromInt(char1 - char2);
1056 }
1057
1058 return Smi::FromInt(str1_length - str2_length);
1059}
1060
1061
1062static Object* Runtime_StringSlice(Arguments args) {
1063 NoHandleAllocation ha;
1064 ASSERT(args.length() == 3);
1065
1066 CONVERT_CHECKED(String, value, args[0]);
1067 CONVERT_DOUBLE_CHECKED(from_number, args[1]);
1068 CONVERT_DOUBLE_CHECKED(to_number, args[2]);
1069
1070 int start = FastD2I(from_number);
1071 int end = FastD2I(to_number);
1072
1073 RUNTIME_ASSERT(end >= start);
1074 RUNTIME_ASSERT(start >= 0);
1075 RUNTIME_ASSERT(end <= value->length());
1076 return value->Slice(start, end);
1077}
1078
1079
1080static Object* Runtime_NumberToRadixString(Arguments args) {
1081 NoHandleAllocation ha;
1082 ASSERT(args.length() == 2);
1083
1084 CONVERT_DOUBLE_CHECKED(value, args[0]);
1085 if (isnan(value)) {
1086 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1087 }
1088 if (isinf(value)) {
1089 if (value < 0) {
1090 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1091 }
1092 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1093 }
1094 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
1095 int radix = FastD2I(radix_number);
1096 RUNTIME_ASSERT(2 <= radix && radix <= 36);
1097 char* str = DoubleToRadixCString(value, radix);
1098 Object* result = Heap::AllocateStringFromAscii(CStrVector(str));
1099 DeleteArray(str);
1100 return result;
1101}
1102
1103
1104static Object* Runtime_NumberToFixed(Arguments args) {
1105 NoHandleAllocation ha;
1106 ASSERT(args.length() == 2);
1107
1108 CONVERT_DOUBLE_CHECKED(value, args[0]);
1109 if (isnan(value)) {
1110 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1111 }
1112 if (isinf(value)) {
1113 if (value < 0) {
1114 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1115 }
1116 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1117 }
1118 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
1119 int f = FastD2I(f_number);
1120 RUNTIME_ASSERT(f >= 0);
1121 char* str = DoubleToFixedCString(value, f);
1122 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
1123 DeleteArray(str);
1124 return res;
1125}
1126
1127
1128static Object* Runtime_NumberToExponential(Arguments args) {
1129 NoHandleAllocation ha;
1130 ASSERT(args.length() == 2);
1131
1132 CONVERT_DOUBLE_CHECKED(value, args[0]);
1133 if (isnan(value)) {
1134 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1135 }
1136 if (isinf(value)) {
1137 if (value < 0) {
1138 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1139 }
1140 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1141 }
1142 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
1143 int f = FastD2I(f_number);
1144 RUNTIME_ASSERT(f >= -1 && f <= 20);
1145 char* str = DoubleToExponentialCString(value, f);
1146 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
1147 DeleteArray(str);
1148 return res;
1149}
1150
1151
1152static Object* Runtime_NumberToPrecision(Arguments args) {
1153 NoHandleAllocation ha;
1154 ASSERT(args.length() == 2);
1155
1156 CONVERT_DOUBLE_CHECKED(value, args[0]);
1157 if (isnan(value)) {
1158 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1159 }
1160 if (isinf(value)) {
1161 if (value < 0) {
1162 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1163 }
1164 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1165 }
1166 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
1167 int f = FastD2I(f_number);
1168 RUNTIME_ASSERT(f >= 1 && f <= 21);
1169 char* str = DoubleToPrecisionCString(value, f);
1170 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
1171 DeleteArray(str);
1172 return res;
1173}
1174
1175
1176// Returns a single character string where first character equals
1177// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001178static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001179 if (index < static_cast<uint32_t>(string->length())) {
1180 string->TryFlatten();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001181 return LookupSingleCharacterStringFromCode(string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001182 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001183 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001184}
1185
1186
1187Object* Runtime::GetElementOrCharAt(Handle<Object> object, uint32_t index) {
1188 // Handle [] indexing on Strings
1189 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001190 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
1191 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001192 }
1193
1194 // Handle [] indexing on String objects
1195 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001196 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
1197 Handle<Object> result =
1198 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
1199 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001200 }
1201
1202 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001203 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001204 return prototype->GetElement(index);
1205 }
1206
1207 return object->GetElement(index);
1208}
1209
1210
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001211Object* Runtime::GetObjectProperty(Handle<Object> object, Handle<Object> key) {
1212 HandleScope scope;
1213
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001214 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001215 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001216 Handle<Object> error =
1217 Factory::NewTypeError("non_object_property_load",
1218 HandleVector(args, 2));
1219 return Top::Throw(*error);
1220 }
1221
1222 // Check if the given key is an array index.
1223 uint32_t index;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001224 if (Array::IndexFromObject(*key, &index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001225 return GetElementOrCharAt(object, index);
1226 }
1227
1228 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001229 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001230 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001231 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001232 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001233 bool has_pending_exception = false;
1234 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001235 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001236 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001237 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001238 }
1239
1240 // Check if the name is trivially convertable to an index and get
1241 // the element if so.
1242 if (name->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001243 return GetElementOrCharAt(object, index);
1244 } else {
1245 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001246 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001247 }
1248}
1249
1250
1251static Object* Runtime_GetProperty(Arguments args) {
1252 NoHandleAllocation ha;
1253 ASSERT(args.length() == 2);
1254
1255 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001256 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001257
1258 return Runtime::GetObjectProperty(object, key);
1259}
1260
1261
1262Object* Runtime::SetObjectProperty(Handle<Object> object,
1263 Handle<Object> key,
1264 Handle<Object> value,
1265 PropertyAttributes attr) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001266 HandleScope scope;
1267
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001268 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001269 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001270 Handle<Object> error =
1271 Factory::NewTypeError("non_object_property_store",
1272 HandleVector(args, 2));
1273 return Top::Throw(*error);
1274 }
1275
1276 // If the object isn't a JavaScript object, we ignore the store.
1277 if (!object->IsJSObject()) return *value;
1278
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001279 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
1280
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001281 // Check if the given key is an array index.
1282 uint32_t index;
1283 if (Array::IndexFromObject(*key, &index)) {
1284 ASSERT(attr == NONE);
1285
1286 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
1287 // of a string using [] notation. We need to support this too in
1288 // JavaScript.
1289 // In the case of a String object we just need to redirect the assignment to
1290 // the underlying string if the index is in range. Since the underlying
1291 // string does nothing with the assignment then we can ignore such
1292 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001293 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001294 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001295 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001296
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001297 Handle<Object> result = SetElement(js_object, index, value);
1298 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001299 return *value;
1300 }
1301
1302 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001303 Handle<Object> result;
1304 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305 ASSERT(attr == NONE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001306 result = SetElement(js_object, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001307 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001308 Handle<String> key_string = Handle<String>::cast(key);
1309 key_string->TryFlatten();
1310 result = SetProperty(js_object, key_string, value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001311 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001312 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001313 return *value;
1314 }
1315
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001316 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001317 bool has_pending_exception = false;
1318 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
1319 if (has_pending_exception) return Failure::Exception();
1320 Handle<String> name = Handle<String>::cast(converted);
1321
1322 if (name->AsArrayIndex(&index)) {
1323 ASSERT(attr == NONE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001324 return js_object->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001325 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001326 return js_object->SetProperty(*name, *value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001327 }
1328}
1329
1330
1331static Object* Runtime_AddProperty(Arguments args) {
1332 NoHandleAllocation ha;
1333 ASSERT(args.length() == 4);
1334
1335 CONVERT_CHECKED(JSObject, object, args[0]);
1336 CONVERT_CHECKED(String, name, args[1]);
1337 RUNTIME_ASSERT(!object->HasLocalProperty(name));
1338 CONVERT_CHECKED(Smi, attr_obj, args[3]);
1339
1340 int attr = attr_obj->value();
1341 RUNTIME_ASSERT((attr & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
1342 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1343
1344 return object->AddProperty(name, args[2], attributes);
1345}
1346
1347
1348static Object* Runtime_SetProperty(Arguments args) {
1349 NoHandleAllocation ha;
1350 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
1351
1352 Handle<Object> object = args.at<Object>(0);
1353 Handle<Object> key = args.at<Object>(1);
1354 Handle<Object> value = args.at<Object>(2);
1355
1356 // Compute attributes.
1357 PropertyAttributes attributes = NONE;
1358 if (args.length() == 4) {
1359 CONVERT_CHECKED(Smi, value_obj, args[3]);
1360 int value = value_obj->value();
1361 // Only attribute bits should be set.
1362 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
1363 attributes = static_cast<PropertyAttributes>(value);
1364 }
1365 return Runtime::SetObjectProperty(object, key, value, attributes);
1366}
1367
1368
1369// Set a local property, even if it is READ_ONLY. If the property does not
1370// exist, it will be added with attributes NONE.
1371static Object* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
1372 NoHandleAllocation ha;
1373 ASSERT(args.length() == 3);
1374
1375 CONVERT_CHECKED(JSObject, object, args[0]);
1376 CONVERT_CHECKED(String, name, args[1]);
1377
1378 return object->IgnoreAttributesAndSetLocalProperty(name, args[2]);
1379}
1380
1381
1382static Object* Runtime_DeleteProperty(Arguments args) {
1383 NoHandleAllocation ha;
1384 ASSERT(args.length() == 2);
1385
1386 CONVERT_CHECKED(JSObject, object, args[0]);
1387 CONVERT_CHECKED(String, key, args[1]);
1388 return object->DeleteProperty(key);
1389}
1390
1391
1392static Object* Runtime_HasLocalProperty(Arguments args) {
1393 NoHandleAllocation ha;
1394 ASSERT(args.length() == 2);
1395 CONVERT_CHECKED(String, key, args[1]);
1396
1397 // Only JS objects can have properties.
1398 if (args[0]->IsJSObject()) {
1399 JSObject* object = JSObject::cast(args[0]);
1400 if (object->HasLocalProperty(key)) return Heap::true_value();
1401 } else if (args[0]->IsString()) {
1402 // Well, there is one exception: Handle [] on strings.
1403 uint32_t index;
1404 if (key->AsArrayIndex(&index)) {
1405 String* string = String::cast(args[0]);
1406 if (index < static_cast<uint32_t>(string->length()))
1407 return Heap::true_value();
1408 }
1409 }
1410 return Heap::false_value();
1411}
1412
1413
1414static Object* Runtime_HasProperty(Arguments args) {
1415 NoHandleAllocation na;
1416 ASSERT(args.length() == 2);
1417
1418 // Only JS objects can have properties.
1419 if (args[0]->IsJSObject()) {
1420 JSObject* object = JSObject::cast(args[0]);
1421 CONVERT_CHECKED(String, key, args[1]);
1422 if (object->HasProperty(key)) return Heap::true_value();
1423 }
1424 return Heap::false_value();
1425}
1426
1427
1428static Object* Runtime_HasElement(Arguments args) {
1429 NoHandleAllocation na;
1430 ASSERT(args.length() == 2);
1431
1432 // Only JS objects can have elements.
1433 if (args[0]->IsJSObject()) {
1434 JSObject* object = JSObject::cast(args[0]);
1435 CONVERT_CHECKED(Smi, index_obj, args[1]);
1436 uint32_t index = index_obj->value();
1437 if (object->HasElement(index)) return Heap::true_value();
1438 }
1439 return Heap::false_value();
1440}
1441
1442
1443static Object* Runtime_IsPropertyEnumerable(Arguments args) {
1444 NoHandleAllocation ha;
1445 ASSERT(args.length() == 2);
1446
1447 CONVERT_CHECKED(JSObject, object, args[0]);
1448 CONVERT_CHECKED(String, key, args[1]);
1449
1450 uint32_t index;
1451 if (key->AsArrayIndex(&index)) {
1452 return Heap::ToBoolean(object->HasElement(index));
1453 }
1454
1455 LookupResult result;
1456 object->LocalLookup(key, &result);
1457 if (!result.IsProperty()) return Heap::false_value();
1458 return Heap::ToBoolean(!result.IsDontEnum());
1459}
1460
1461
1462static Object* Runtime_GetPropertyNames(Arguments args) {
1463 HandleScope scope;
1464 ASSERT(args.length() == 1);
1465
1466 CONVERT_CHECKED(JSObject, raw_object, args[0]);
1467 Handle<JSObject> object(raw_object);
1468 return *GetKeysFor(object);
1469}
1470
1471
1472// Returns either a FixedArray as Runtime_GetPropertyNames,
1473// or, if the given object has an enum cache that contains
1474// all enumerable properties of the object and its prototypes
1475// have none, the map of the object. This is used to speed up
1476// the check for deletions during a for-in.
1477static Object* Runtime_GetPropertyNamesFast(Arguments args) {
1478 ASSERT(args.length() == 1);
1479
1480 CONVERT_CHECKED(JSObject, raw_object, args[0]);
1481
1482 if (raw_object->IsSimpleEnum()) return raw_object->map();
1483
1484 HandleScope scope;
1485 Handle<JSObject> object(raw_object);
1486 Handle<FixedArray> content = GetKeysInFixedArrayFor(object);
1487
1488 // Test again, since cache may have been built by preceding call.
1489 if (object->IsSimpleEnum()) return object->map();
1490
1491 return *content;
1492}
1493
1494
1495static Object* Runtime_GetArgumentsProperty(Arguments args) {
1496 NoHandleAllocation ha;
1497 ASSERT(args.length() == 1);
1498
1499 // Compute the frame holding the arguments.
1500 JavaScriptFrameIterator it;
1501 it.AdvanceToArgumentsFrame();
1502 JavaScriptFrame* frame = it.frame();
1503
1504 // Get the actual number of provided arguments.
1505 const uint32_t n = frame->GetProvidedParametersCount();
1506
1507 // Try to convert the key to an index. If successful and within
1508 // index return the the argument from the frame.
1509 uint32_t index;
1510 if (Array::IndexFromObject(args[0], &index) && index < n) {
1511 return frame->GetParameter(index);
1512 }
1513
1514 // Convert the key to a string.
1515 HandleScope scope;
1516 bool exception = false;
1517 Handle<Object> converted =
1518 Execution::ToString(args.at<Object>(0), &exception);
1519 if (exception) return Failure::Exception();
1520 Handle<String> key = Handle<String>::cast(converted);
1521
1522 // Try to convert the string key into an array index.
1523 if (key->AsArrayIndex(&index)) {
1524 if (index < n) {
1525 return frame->GetParameter(index);
1526 } else {
1527 return Top::initial_object_prototype()->GetElement(index);
1528 }
1529 }
1530
1531 // Handle special arguments properties.
1532 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
1533 if (key->Equals(Heap::callee_symbol())) return frame->function();
1534
1535 // Lookup in the initial Object.prototype object.
1536 return Top::initial_object_prototype()->GetProperty(*key);
1537}
1538
1539
1540static Object* Runtime_ToBool(Arguments args) {
1541 NoHandleAllocation ha;
1542 ASSERT(args.length() == 1);
1543
1544 return args[0]->ToBoolean();
1545}
1546
1547
1548// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
1549// Possible optimizations: put the type string into the oddballs.
1550static Object* Runtime_Typeof(Arguments args) {
1551 NoHandleAllocation ha;
1552
1553 Object* obj = args[0];
1554 if (obj->IsNumber()) return Heap::number_symbol();
1555 HeapObject* heap_obj = HeapObject::cast(obj);
1556
1557 // typeof an undetectable object is 'undefined'
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001558 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001559
1560 InstanceType instance_type = heap_obj->map()->instance_type();
1561 if (instance_type < FIRST_NONSTRING_TYPE) {
1562 return Heap::string_symbol();
1563 }
1564
1565 switch (instance_type) {
1566 case ODDBALL_TYPE:
1567 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
1568 return Heap::boolean_symbol();
1569 }
1570 if (heap_obj->IsNull()) {
1571 return Heap::object_symbol();
1572 }
1573 ASSERT(heap_obj->IsUndefined());
1574 return Heap::undefined_symbol();
1575 case JS_FUNCTION_TYPE:
1576 return Heap::function_symbol();
1577 default:
1578 // For any kind of object not handled above, the spec rule for
1579 // host objects gives that it is okay to return "object"
1580 return Heap::object_symbol();
1581 }
1582}
1583
1584
1585static Object* Runtime_StringToNumber(Arguments args) {
1586 NoHandleAllocation ha;
1587 ASSERT(args.length() == 1);
1588 CONVERT_CHECKED(String, subject, args[0]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001589 subject->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001590 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
1591}
1592
1593
1594static Object* Runtime_StringFromCharCodeArray(Arguments args) {
1595 NoHandleAllocation ha;
1596 ASSERT(args.length() == 1);
1597
1598 CONVERT_CHECKED(JSArray, codes, args[0]);
1599 int length = Smi::cast(codes->length())->value();
1600
1601 // Check if the string can be ASCII.
1602 int i;
1603 for (i = 0; i < length; i++) {
1604 Object* element = codes->GetElement(i);
1605 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
1606 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
1607 break;
1608 }
1609
1610 Object* object = NULL;
1611 if (i == length) { // The string is ASCII.
1612 object = Heap::AllocateRawAsciiString(length);
1613 } else { // The string is not ASCII.
1614 object = Heap::AllocateRawTwoByteString(length);
1615 }
1616
1617 if (object->IsFailure()) return object;
1618 String* result = String::cast(object);
1619 for (int i = 0; i < length; i++) {
1620 Object* element = codes->GetElement(i);
1621 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
1622 result->Set(i, chr & 0xffff);
1623 }
1624 return result;
1625}
1626
1627
1628// kNotEscaped is generated by the following:
1629//
1630// #!/bin/perl
1631// for (my $i = 0; $i < 256; $i++) {
1632// print "\n" if $i % 16 == 0;
1633// my $c = chr($i);
1634// my $escaped = 1;
1635// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
1636// print $escaped ? "0, " : "1, ";
1637// }
1638
1639
1640static bool IsNotEscaped(uint16_t character) {
1641 // Only for 8 bit characters, the rest are always escaped (in a different way)
1642 ASSERT(character < 256);
1643 static const char kNotEscaped[256] = {
1644 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1645 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1646 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
1647 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
1648 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1649 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
1650 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1651 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
1652 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1653 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1654 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1655 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1656 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1657 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1658 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1659 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1660 };
1661 return kNotEscaped[character] != 0;
1662}
1663
1664
1665static Object* Runtime_URIEscape(Arguments args) {
1666 const char hex_chars[] = "0123456789ABCDEF";
1667 NoHandleAllocation ha;
1668 ASSERT(args.length() == 1);
1669 CONVERT_CHECKED(String, source, args[0]);
1670
1671 source->TryFlatten();
1672
1673 int escaped_length = 0;
1674 int length = source->length();
1675 {
1676 Access<StringInputBuffer> buffer(&string_input_buffer);
1677 buffer->Reset(source);
1678 while (buffer->has_more()) {
1679 uint16_t character = buffer->GetNext();
1680 if (character >= 256) {
1681 escaped_length += 6;
1682 } else if (IsNotEscaped(character)) {
1683 escaped_length++;
1684 } else {
1685 escaped_length += 3;
1686 }
1687 // We don't allow strings that are longer than Smi range.
1688 if (!Smi::IsValid(escaped_length)) {
1689 Top::context()->mark_out_of_memory();
1690 return Failure::OutOfMemoryException();
1691 }
1692 }
1693 }
1694 // No length change implies no change. Return original string if no change.
1695 if (escaped_length == length) {
1696 return source;
1697 }
1698 Object* o = Heap::AllocateRawAsciiString(escaped_length);
1699 if (o->IsFailure()) return o;
1700 String* destination = String::cast(o);
1701 int dest_position = 0;
1702
1703 Access<StringInputBuffer> buffer(&string_input_buffer);
1704 buffer->Rewind();
1705 while (buffer->has_more()) {
1706 uint16_t character = buffer->GetNext();
1707 if (character >= 256) {
1708 destination->Set(dest_position, '%');
1709 destination->Set(dest_position+1, 'u');
1710 destination->Set(dest_position+2, hex_chars[character >> 12]);
1711 destination->Set(dest_position+3, hex_chars[(character >> 8) & 0xf]);
1712 destination->Set(dest_position+4, hex_chars[(character >> 4) & 0xf]);
1713 destination->Set(dest_position+5, hex_chars[character & 0xf]);
1714 dest_position += 6;
1715 } else if (IsNotEscaped(character)) {
1716 destination->Set(dest_position, character);
1717 dest_position++;
1718 } else {
1719 destination->Set(dest_position, '%');
1720 destination->Set(dest_position+1, hex_chars[character >> 4]);
1721 destination->Set(dest_position+2, hex_chars[character & 0xf]);
1722 dest_position += 3;
1723 }
1724 }
1725 return destination;
1726}
1727
1728
1729static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
1730 static const signed char kHexValue['g'] = {
1731 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1732 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1733 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1734 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
1735 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1736 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1737 -1, 10, 11, 12, 13, 14, 15 };
1738
1739 if (character1 > 'f') return -1;
1740 int hi = kHexValue[character1];
1741 if (hi == -1) return -1;
1742 if (character2 > 'f') return -1;
1743 int lo = kHexValue[character2];
1744 if (lo == -1) return -1;
1745 return (hi << 4) + lo;
1746}
1747
1748
1749static inline int Unescape(String* source, int i, int length, int* step) {
1750 uint16_t character = source->Get(i);
1751 int32_t hi, lo;
1752 if (character == '%' &&
1753 i <= length - 6 &&
1754 source->Get(i + 1) == 'u' &&
1755 (hi = TwoDigitHex(source->Get(i + 2), source->Get(i + 3))) != -1 &&
1756 (lo = TwoDigitHex(source->Get(i + 4), source->Get(i + 5))) != -1) {
1757 *step = 6;
1758 return (hi << 8) + lo;
1759 } else if (character == '%' &&
1760 i <= length - 3 &&
1761 (lo = TwoDigitHex(source->Get(i + 1), source->Get(i + 2))) != -1) {
1762 *step = 3;
1763 return lo;
1764 } else {
1765 *step = 1;
1766 return character;
1767 }
1768}
1769
1770
1771static Object* Runtime_URIUnescape(Arguments args) {
1772 NoHandleAllocation ha;
1773 ASSERT(args.length() == 1);
1774 CONVERT_CHECKED(String, source, args[0]);
1775
1776 source->TryFlatten();
1777
1778 bool ascii = true;
1779 int length = source->length();
1780
1781 int unescaped_length = 0;
1782 for (int i = 0; i < length; unescaped_length++) {
1783 int step;
1784 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode)
1785 ascii = false;
1786 i += step;
1787 }
1788
1789 // No length change implies no change. Return original string if no change.
1790 if (unescaped_length == length)
1791 return source;
1792
1793 Object* o = ascii ?
1794 Heap::AllocateRawAsciiString(unescaped_length) :
1795 Heap::AllocateRawTwoByteString(unescaped_length);
1796 if (o->IsFailure()) return o;
1797 String* destination = String::cast(o);
1798
1799 int dest_position = 0;
1800 for (int i = 0; i < length; dest_position++) {
1801 int step;
1802 destination->Set(dest_position, Unescape(source, i, length, &step));
1803 i += step;
1804 }
1805 return destination;
1806}
1807
1808
1809static Object* Runtime_StringParseInt(Arguments args) {
1810 NoHandleAllocation ha;
1811
1812 CONVERT_CHECKED(String, s, args[0]);
1813 CONVERT_DOUBLE_CHECKED(n, args[1]);
1814 int radix = FastD2I(n);
1815
1816 s->TryFlatten();
1817
1818 int len = s->length();
1819 int i;
1820
1821 // Skip leading white space.
1822 for (i = 0; i < len && Scanner::kIsWhiteSpace.get(s->Get(i)); i++) ;
1823 if (i == len) return Heap::nan_value();
1824
1825 // Compute the sign (default to +).
1826 int sign = 1;
1827 if (s->Get(i) == '-') {
1828 sign = -1;
1829 i++;
1830 } else if (s->Get(i) == '+') {
1831 i++;
1832 }
1833
1834 // Compute the radix if 0.
1835 if (radix == 0) {
1836 radix = 10;
1837 if (i < len && s->Get(i) == '0') {
1838 radix = 8;
1839 if (i + 1 < len) {
1840 int c = s->Get(i + 1);
1841 if (c == 'x' || c == 'X') {
1842 radix = 16;
1843 i += 2;
1844 }
1845 }
1846 }
1847 } else if (radix == 16) {
1848 // Allow 0x or 0X prefix if radix is 16.
1849 if (i + 1 < len && s->Get(i) == '0') {
1850 int c = s->Get(i + 1);
1851 if (c == 'x' || c == 'X') i += 2;
1852 }
1853 }
1854
1855 RUNTIME_ASSERT(2 <= radix && radix <= 36);
1856 double value;
1857 int end_index = StringToInt(s, i, radix, &value);
1858 if (end_index != i) {
1859 return Heap::NumberFromDouble(sign * value);
1860 }
1861 return Heap::nan_value();
1862}
1863
1864
1865static Object* Runtime_StringParseFloat(Arguments args) {
1866 NoHandleAllocation ha;
1867 CONVERT_CHECKED(String, str, args[0]);
1868
1869 // ECMA-262 section 15.1.2.3, empty string is NaN
1870 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
1871
1872 // Create a number object from the value.
1873 return Heap::NumberFromDouble(value);
1874}
1875
1876
1877static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
1878static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
1879
1880
1881template <class Converter>
1882static Object* ConvertCase(Arguments args,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001883 unibrow::Mapping<Converter, 128>* mapping) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001884 NoHandleAllocation ha;
1885
1886 CONVERT_CHECKED(String, s, args[0]);
1887 int raw_string_length = s->length();
1888 // Assume that the string is not empty; we need this assumption later
1889 if (raw_string_length == 0) return s;
1890 int length = raw_string_length;
1891
1892 s->TryFlatten();
1893
1894 // We try this twice, once with the assumption that the result is
1895 // no longer than the input and, if that assumption breaks, again
1896 // with the exact length. This is implemented using a goto back
1897 // to this label if we discover that the assumption doesn't hold.
1898 // I apologize sincerely for this and will give a vaffel-is to
mads.s.ager31e71382008-08-13 09:32:07 +00001899 // the first person who can implement it in a nicer way.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001900 try_convert:
1901
1902 // Allocate the resulting string.
1903 //
1904 // NOTE: This assumes that the upper/lower case of an ascii
1905 // character is also ascii. This is currently the case, but it
1906 // might break in the future if we implement more context and locale
1907 // dependent upper/lower conversions.
1908 Object* o = s->IsAscii()
1909 ? Heap::AllocateRawAsciiString(length)
1910 : Heap::AllocateRawTwoByteString(length);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001911 if (o->IsFailure()) return o;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001912 String* result = String::cast(o);
1913 bool has_changed_character = false;
1914
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001915 // Convert all characters to upper case, assuming that they will fit
1916 // in the buffer
1917 Access<StringInputBuffer> buffer(&string_input_buffer);
1918 buffer->Reset(s);
1919 unibrow::uchar chars[unibrow::kMaxCaseConvertedSize];
1920 int i = 0;
1921 // We can assume that the string is not empty
1922 uc32 current = buffer->GetNext();
1923 while (i < length) {
1924 uc32 next = buffer->has_more() ? buffer->GetNext() : 0;
1925 int char_length = mapping->get(current, next, chars);
1926 if (char_length == 0) {
1927 // The case conversion of this character is the character itself.
1928 result->Set(i, current);
1929 i++;
1930 } else if (char_length == 1) {
1931 // Common case: converting the letter resulted in one character.
1932 ASSERT(static_cast<uc32>(chars[0]) != current);
1933 result->Set(i, chars[0]);
1934 has_changed_character = true;
1935 i++;
1936 } else if (length == raw_string_length) {
1937 // We've assumed that the result would be as long as the
1938 // input but here is a character that converts to several
1939 // characters. No matter, we calculate the exact length
1940 // of the result and try the whole thing again.
1941 //
1942 // Note that this leaves room for optimization. We could just
1943 // memcpy what we already have to the result string. Also,
1944 // the result string is the last object allocated we could
1945 // "realloc" it and probably, in the vast majority of cases,
1946 // extend the existing string to be able to hold the full
1947 // result.
1948 int current_length = i + char_length + mapping->get(next, 0, chars);
1949 while (buffer->has_more()) {
1950 current = buffer->GetNext();
1951 int char_length = mapping->get(current, 0, chars);
1952 if (char_length == 0) char_length = 1;
1953 current += char_length;
1954 }
1955 length = current_length;
1956 goto try_convert;
1957 } else {
1958 for (int j = 0; j < char_length; j++) {
1959 result->Set(i, chars[j]);
1960 i++;
1961 }
1962 has_changed_character = true;
1963 }
1964 current = next;
1965 }
1966 if (has_changed_character) {
1967 return result;
1968 } else {
1969 // If we didn't actually change anything in doing the conversion
1970 // we simple return the result and let the converted string
1971 // become garbage; there is no reason to keep two identical strings
1972 // alive.
1973 return s;
1974 }
1975}
1976
1977
1978static Object* Runtime_StringToLowerCase(Arguments args) {
1979 return ConvertCase<unibrow::ToLowercase>(args, &to_lower_mapping);
1980}
1981
1982
1983static Object* Runtime_StringToUpperCase(Arguments args) {
1984 return ConvertCase<unibrow::ToUppercase>(args, &to_upper_mapping);
1985}
1986
1987
1988static Object* Runtime_ConsStringFst(Arguments args) {
1989 NoHandleAllocation ha;
1990
1991 CONVERT_CHECKED(ConsString, str, args[0]);
1992 return str->first();
1993}
1994
1995
1996static Object* Runtime_ConsStringSnd(Arguments args) {
1997 NoHandleAllocation ha;
1998
1999 CONVERT_CHECKED(ConsString, str, args[0]);
2000 return str->second();
2001}
2002
2003
2004static Object* Runtime_NumberToString(Arguments args) {
2005 NoHandleAllocation ha;
2006 ASSERT(args.length() == 1);
2007
2008 Object* number = args[0];
2009 RUNTIME_ASSERT(number->IsNumber());
2010
2011 Object* cached = Heap::GetNumberStringCache(number);
2012 if (cached != Heap::undefined_value()) {
2013 return cached;
2014 }
2015
2016 char arr[100];
2017 Vector<char> buffer(arr, ARRAY_SIZE(arr));
2018 const char* str;
2019 if (number->IsSmi()) {
2020 int num = Smi::cast(number)->value();
2021 str = IntToCString(num, buffer);
2022 } else {
2023 double num = HeapNumber::cast(number)->value();
2024 str = DoubleToCString(num, buffer);
2025 }
2026 Object* result = Heap::AllocateStringFromAscii(CStrVector(str));
2027
2028 if (!result->IsFailure()) {
2029 Heap::SetNumberStringCache(number, String::cast(result));
2030 }
2031 return result;
2032}
2033
2034
2035static Object* Runtime_NumberToInteger(Arguments args) {
2036 NoHandleAllocation ha;
2037 ASSERT(args.length() == 1);
2038
2039 Object* obj = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002040 if (obj->IsSmi()) return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002041 CONVERT_DOUBLE_CHECKED(number, obj);
2042 return Heap::NumberFromDouble(DoubleToInteger(number));
2043}
2044
2045
2046static Object* Runtime_NumberToJSUint32(Arguments args) {
2047 NoHandleAllocation ha;
2048 ASSERT(args.length() == 1);
2049
2050 Object* obj = args[0];
2051 if (obj->IsSmi() && Smi::cast(obj)->value() >= 0) return obj;
2052 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, obj);
2053 return Heap::NumberFromUint32(number);
2054}
2055
2056
2057static Object* Runtime_NumberToJSInt32(Arguments args) {
2058 NoHandleAllocation ha;
2059 ASSERT(args.length() == 1);
2060
2061 Object* obj = args[0];
2062 if (obj->IsSmi()) return obj;
2063 CONVERT_DOUBLE_CHECKED(number, obj);
2064 return Heap::NumberFromInt32(DoubleToInt32(number));
2065}
2066
2067
2068static Object* Runtime_NumberAdd(Arguments args) {
2069 NoHandleAllocation ha;
2070 ASSERT(args.length() == 2);
2071
2072 CONVERT_DOUBLE_CHECKED(x, args[0]);
2073 CONVERT_DOUBLE_CHECKED(y, args[1]);
2074 return Heap::AllocateHeapNumber(x + y);
2075}
2076
2077
2078static Object* Runtime_NumberSub(Arguments args) {
2079 NoHandleAllocation ha;
2080 ASSERT(args.length() == 2);
2081
2082 CONVERT_DOUBLE_CHECKED(x, args[0]);
2083 CONVERT_DOUBLE_CHECKED(y, args[1]);
2084 return Heap::AllocateHeapNumber(x - y);
2085}
2086
2087
2088static Object* Runtime_NumberMul(Arguments args) {
2089 NoHandleAllocation ha;
2090 ASSERT(args.length() == 2);
2091
2092 CONVERT_DOUBLE_CHECKED(x, args[0]);
2093 CONVERT_DOUBLE_CHECKED(y, args[1]);
2094 return Heap::AllocateHeapNumber(x * y);
2095}
2096
2097
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002098static Object* Runtime_NumberUnaryMinus(Arguments args) {
2099 NoHandleAllocation ha;
2100 ASSERT(args.length() == 1);
2101
2102 CONVERT_DOUBLE_CHECKED(x, args[0]);
2103 return Heap::AllocateHeapNumber(-x);
2104}
2105
2106
2107static Object* Runtime_NumberDiv(Arguments args) {
2108 NoHandleAllocation ha;
2109 ASSERT(args.length() == 2);
2110
2111 CONVERT_DOUBLE_CHECKED(x, args[0]);
2112 CONVERT_DOUBLE_CHECKED(y, args[1]);
2113 return Heap::NewNumberFromDouble(x / y);
2114}
2115
2116
2117static Object* Runtime_NumberMod(Arguments args) {
2118 NoHandleAllocation ha;
2119 ASSERT(args.length() == 2);
2120
2121 CONVERT_DOUBLE_CHECKED(x, args[0]);
2122 CONVERT_DOUBLE_CHECKED(y, args[1]);
2123
2124#ifdef WIN32
2125 // Workaround MS fmod bugs. ECMA-262 says:
2126 // dividend is finite and divisor is an infinity => result equals dividend
2127 // dividend is a zero and divisor is nonzero finite => result equals dividend
2128 if (!(isfinite(x) && (!isfinite(y) && !isnan(y))) &&
2129 !(x == 0 && (y != 0 && isfinite(y))))
2130#endif
2131 x = fmod(x, y);
2132 // NewNumberFromDouble may return a Smi instead of a Number object
2133 return Heap::NewNumberFromDouble(x);
2134}
2135
2136
2137static Object* Runtime_StringAdd(Arguments args) {
2138 NoHandleAllocation ha;
2139 ASSERT(args.length() == 2);
2140
2141 CONVERT_CHECKED(String, str1, args[0]);
2142 CONVERT_CHECKED(String, str2, args[1]);
2143 int len1 = str1->length();
2144 int len2 = str2->length();
2145 if (len1 == 0) return str2;
2146 if (len2 == 0) return str1;
2147 int length_sum = len1 + len2;
2148 // Make sure that an out of memory exception is thrown if the length
2149 // of the new cons string is too large to fit in a Smi.
2150 if (length_sum > Smi::kMaxValue || length_sum < 0) {
2151 Top::context()->mark_out_of_memory();
2152 return Failure::OutOfMemoryException();
2153 }
2154 return Heap::AllocateConsString(str1, str2);
2155}
2156
2157
2158static Object* Runtime_StringBuilderConcat(Arguments args) {
2159 NoHandleAllocation ha;
2160 ASSERT(args.length() == 2);
2161 CONVERT_CHECKED(JSArray, array, args[0]);
2162 CONVERT_CHECKED(String, special, args[1]);
2163 int special_length = special->length();
2164 Object* smi_array_length = array->length();
2165 if (!smi_array_length->IsSmi()) {
2166 Top::context()->mark_out_of_memory();
2167 return Failure::OutOfMemoryException();
2168 }
2169 int array_length = Smi::cast(smi_array_length)->value();
2170 if (!array->HasFastElements()) {
2171 return Top::Throw(Heap::illegal_argument_symbol());
2172 }
2173 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002174 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002175 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002176 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002177
2178 if (array_length == 0) {
2179 return Heap::empty_string();
2180 } else if (array_length == 1) {
2181 Object* first = fixed_array->get(0);
2182 if (first->IsString()) return first;
2183 }
2184
2185 bool ascii = special->IsAscii();
2186 int position = 0;
2187 for (int i = 0; i < array_length; i++) {
2188 Object* elt = fixed_array->get(i);
2189 if (elt->IsSmi()) {
2190 int len = Smi::cast(elt)->value();
2191 int pos = len >> 11;
2192 len &= 0x7ff;
2193 if (pos + len > special_length) {
2194 return Top::Throw(Heap::illegal_argument_symbol());
2195 }
2196 position += len;
2197 } else if (elt->IsString()) {
2198 String* element = String::cast(elt);
2199 int element_length = element->length();
2200 if (!Smi::IsValid(element_length + position)) {
2201 Top::context()->mark_out_of_memory();
2202 return Failure::OutOfMemoryException();
2203 }
2204 position += element_length;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002205 if (ascii && !element->IsAscii()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002206 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002207 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002208 } else {
2209 return Top::Throw(Heap::illegal_argument_symbol());
2210 }
2211 }
2212
2213 int length = position;
2214 position = 0;
2215 Object* object;
2216 if (ascii) {
2217 object = Heap::AllocateRawAsciiString(length);
2218 } else {
2219 object = Heap::AllocateRawTwoByteString(length);
2220 }
2221 if (object->IsFailure()) return object;
2222
2223 String* answer = String::cast(object);
2224 for (int i = 0; i < array_length; i++) {
2225 Object* element = fixed_array->get(i);
2226 if (element->IsSmi()) {
2227 int len = Smi::cast(element)->value();
2228 int pos = len >> 11;
2229 len &= 0x7ff;
2230 String::Flatten(special, answer, pos, pos + len, position);
2231 position += len;
2232 } else {
2233 String* string = String::cast(element);
2234 int element_length = string->length();
2235 String::Flatten(string, answer, 0, element_length, position);
2236 position += element_length;
2237 }
2238 }
2239 return answer;
2240}
2241
2242
2243static Object* Runtime_NumberOr(Arguments args) {
2244 NoHandleAllocation ha;
2245 ASSERT(args.length() == 2);
2246
2247 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2248 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2249 return Heap::NumberFromInt32(x | y);
2250}
2251
2252
2253static Object* Runtime_NumberAnd(Arguments args) {
2254 NoHandleAllocation ha;
2255 ASSERT(args.length() == 2);
2256
2257 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2258 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2259 return Heap::NumberFromInt32(x & y);
2260}
2261
2262
2263static Object* Runtime_NumberXor(Arguments args) {
2264 NoHandleAllocation ha;
2265 ASSERT(args.length() == 2);
2266
2267 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2268 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2269 return Heap::NumberFromInt32(x ^ y);
2270}
2271
2272
2273static Object* Runtime_NumberNot(Arguments args) {
2274 NoHandleAllocation ha;
2275 ASSERT(args.length() == 1);
2276
2277 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2278 return Heap::NumberFromInt32(~x);
2279}
2280
2281
2282static Object* Runtime_NumberShl(Arguments args) {
2283 NoHandleAllocation ha;
2284 ASSERT(args.length() == 2);
2285
2286 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2287 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2288 return Heap::NumberFromInt32(x << (y & 0x1f));
2289}
2290
2291
2292static Object* Runtime_NumberShr(Arguments args) {
2293 NoHandleAllocation ha;
2294 ASSERT(args.length() == 2);
2295
2296 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
2297 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2298 return Heap::NumberFromUint32(x >> (y & 0x1f));
2299}
2300
2301
2302static Object* Runtime_NumberSar(Arguments args) {
2303 NoHandleAllocation ha;
2304 ASSERT(args.length() == 2);
2305
2306 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2307 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2308 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
2309}
2310
2311
2312static Object* Runtime_ObjectEquals(Arguments args) {
2313 NoHandleAllocation ha;
2314 ASSERT(args.length() == 2);
2315
2316 return Smi::FromInt(args[0] == args[1] ? EQUAL : NOT_EQUAL);
2317}
2318
2319
2320static Object* Runtime_NumberEquals(Arguments args) {
2321 NoHandleAllocation ha;
2322 ASSERT(args.length() == 2);
2323
2324 CONVERT_DOUBLE_CHECKED(x, args[0]);
2325 CONVERT_DOUBLE_CHECKED(y, args[1]);
2326 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
2327 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
2328 if (x == y) return Smi::FromInt(EQUAL);
2329 Object* result;
2330 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
2331 result = Smi::FromInt(EQUAL);
2332 } else {
2333 result = Smi::FromInt(NOT_EQUAL);
2334 }
2335 return result;
2336}
2337
2338
2339static Object* Runtime_StringEquals(Arguments args) {
2340 NoHandleAllocation ha;
2341 ASSERT(args.length() == 2);
2342
2343 CONVERT_CHECKED(String, x, args[0]);
2344 CONVERT_CHECKED(String, y, args[1]);
2345
2346 // This is very similar to String::Equals(String*) but that version
2347 // requires flattened strings as input, whereas we flatten the
2348 // strings only if the fast cases fail. Note that this may fail,
2349 // requiring a GC. String::Equals(String*) returns a bool and has
2350 // no way to signal a failure.
2351 if (y == x) return Smi::FromInt(EQUAL);
2352 if (x->IsSymbol() && y->IsSymbol()) return Smi::FromInt(NOT_EQUAL);
2353 // Compare contents
2354 int len = x->length();
2355 if (len != y->length()) return Smi::FromInt(NOT_EQUAL);
2356 if (len == 0) return Smi::FromInt(EQUAL);
2357 // Fast case: First, middle and last characters.
2358 if (x->Get(0) != y->Get(0)) return Smi::FromInt(NOT_EQUAL);
2359 if (x->Get(len>>1) != y->Get(len>>1)) return Smi::FromInt(NOT_EQUAL);
2360 if (x->Get(len - 1) != y->Get(len - 1)) return Smi::FromInt(NOT_EQUAL);
2361
2362 x->TryFlatten();
2363 y->TryFlatten();
2364
2365 static StringInputBuffer buf1;
2366 static StringInputBuffer buf2;
2367 buf1.Reset(x);
2368 buf2.Reset(y);
2369 while (buf1.has_more()) {
2370 if (buf1.GetNext() != buf2.GetNext())
2371 return Smi::FromInt(NOT_EQUAL);
2372 }
2373 return Smi::FromInt(EQUAL);
2374}
2375
2376
2377static Object* Runtime_NumberCompare(Arguments args) {
2378 NoHandleAllocation ha;
2379 ASSERT(args.length() == 3);
2380
2381 CONVERT_DOUBLE_CHECKED(x, args[0]);
2382 CONVERT_DOUBLE_CHECKED(y, args[1]);
2383 if (isnan(x) || isnan(y)) return args[2];
2384 if (x == y) return Smi::FromInt(EQUAL);
2385 if (isless(x, y)) return Smi::FromInt(LESS);
2386 return Smi::FromInt(GREATER);
2387}
2388
2389
2390static Object* Runtime_StringCompare(Arguments args) {
2391 NoHandleAllocation ha;
2392 ASSERT(args.length() == 2);
2393
2394 CONVERT_CHECKED(String, x, args[0]);
2395 CONVERT_CHECKED(String, y, args[1]);
2396
2397 // A few fast case tests before we flatten.
2398 if (x == y) return Smi::FromInt(EQUAL);
2399 if (y->length() == 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002400 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002401 return Smi::FromInt(GREATER);
2402 } else if (x->length() == 0) {
2403 return Smi::FromInt(LESS);
2404 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002405
2406 int d = x->Get(0) - y->Get(0);
2407 if (d < 0) return Smi::FromInt(LESS);
2408 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002409
2410 x->TryFlatten();
2411 y->TryFlatten();
2412
2413 static StringInputBuffer bufx;
2414 static StringInputBuffer bufy;
2415 bufx.Reset(x);
2416 bufy.Reset(y);
2417 while (bufx.has_more() && bufy.has_more()) {
2418 int d = bufx.GetNext() - bufy.GetNext();
2419 if (d < 0) return Smi::FromInt(LESS);
2420 else if (d > 0) return Smi::FromInt(GREATER);
2421 }
2422
2423 // x is (non-trivial) prefix of y:
2424 if (bufy.has_more()) return Smi::FromInt(LESS);
2425 // y is prefix of x:
2426 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
2427}
2428
2429
2430static Object* Runtime_Math_abs(Arguments args) {
2431 NoHandleAllocation ha;
2432 ASSERT(args.length() == 1);
2433
2434 CONVERT_DOUBLE_CHECKED(x, args[0]);
2435 return Heap::AllocateHeapNumber(fabs(x));
2436}
2437
2438
2439static Object* Runtime_Math_acos(Arguments args) {
2440 NoHandleAllocation ha;
2441 ASSERT(args.length() == 1);
2442
2443 CONVERT_DOUBLE_CHECKED(x, args[0]);
2444 return Heap::AllocateHeapNumber(acos(x));
2445}
2446
2447
2448static Object* Runtime_Math_asin(Arguments args) {
2449 NoHandleAllocation ha;
2450 ASSERT(args.length() == 1);
2451
2452 CONVERT_DOUBLE_CHECKED(x, args[0]);
2453 return Heap::AllocateHeapNumber(asin(x));
2454}
2455
2456
2457static Object* Runtime_Math_atan(Arguments args) {
2458 NoHandleAllocation ha;
2459 ASSERT(args.length() == 1);
2460
2461 CONVERT_DOUBLE_CHECKED(x, args[0]);
2462 return Heap::AllocateHeapNumber(atan(x));
2463}
2464
2465
2466static Object* Runtime_Math_atan2(Arguments args) {
2467 NoHandleAllocation ha;
2468 ASSERT(args.length() == 2);
2469
2470 CONVERT_DOUBLE_CHECKED(x, args[0]);
2471 CONVERT_DOUBLE_CHECKED(y, args[1]);
2472 double result;
2473 if (isinf(x) && isinf(y)) {
2474 // Make sure that the result in case of two infinite arguments
2475 // is a multiple of Pi / 4. The sign of the result is determined
2476 // by the first argument (x) and the sign of the second argument
2477 // determines the multiplier: one or three.
2478 static double kPiDividedBy4 = 0.78539816339744830962;
2479 int multiplier = (x < 0) ? -1 : 1;
2480 if (y < 0) multiplier *= 3;
2481 result = multiplier * kPiDividedBy4;
2482 } else {
2483 result = atan2(x, y);
2484 }
2485 return Heap::AllocateHeapNumber(result);
2486}
2487
2488
2489static Object* Runtime_Math_ceil(Arguments args) {
2490 NoHandleAllocation ha;
2491 ASSERT(args.length() == 1);
2492
2493 CONVERT_DOUBLE_CHECKED(x, args[0]);
2494 return Heap::NumberFromDouble(ceiling(x));
2495}
2496
2497
2498static Object* Runtime_Math_cos(Arguments args) {
2499 NoHandleAllocation ha;
2500 ASSERT(args.length() == 1);
2501
2502 CONVERT_DOUBLE_CHECKED(x, args[0]);
2503 return Heap::AllocateHeapNumber(cos(x));
2504}
2505
2506
2507static Object* Runtime_Math_exp(Arguments args) {
2508 NoHandleAllocation ha;
2509 ASSERT(args.length() == 1);
2510
2511 CONVERT_DOUBLE_CHECKED(x, args[0]);
2512 return Heap::AllocateHeapNumber(exp(x));
2513}
2514
2515
2516static Object* Runtime_Math_floor(Arguments args) {
2517 NoHandleAllocation ha;
2518 ASSERT(args.length() == 1);
2519
2520 CONVERT_DOUBLE_CHECKED(x, args[0]);
2521 return Heap::NumberFromDouble(floor(x));
2522}
2523
2524
2525static Object* Runtime_Math_log(Arguments args) {
2526 NoHandleAllocation ha;
2527 ASSERT(args.length() == 1);
2528
2529 CONVERT_DOUBLE_CHECKED(x, args[0]);
2530 return Heap::AllocateHeapNumber(log(x));
2531}
2532
2533
2534static Object* Runtime_Math_pow(Arguments args) {
2535 NoHandleAllocation ha;
2536 ASSERT(args.length() == 2);
2537
2538 CONVERT_DOUBLE_CHECKED(x, args[0]);
2539 CONVERT_DOUBLE_CHECKED(y, args[1]);
2540 if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
2541 return Heap::nan_value();
2542 } else if (y == 0) {
2543 return Smi::FromInt(1);
2544 } else {
2545 return Heap::AllocateHeapNumber(pow(x, y));
2546 }
2547}
2548
2549// Returns a number value with positive sign, greater than or equal to
2550// 0 but less than 1, chosen randomly.
mads.s.ager31e71382008-08-13 09:32:07 +00002551static Object* Runtime_Math_random(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002552 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00002553 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002554
2555 // To get much better precision, we combine the results of two
2556 // invocations of random(). The result is computed by normalizing a
2557 // double in the range [0, RAND_MAX + 1) obtained by adding the
2558 // high-order bits in the range [0, RAND_MAX] with the low-order
2559 // bits in the range [0, 1).
2560 double lo = static_cast<double>(random()) / (RAND_MAX + 1.0);
2561 double hi = static_cast<double>(random());
2562 double result = (hi + lo) / (RAND_MAX + 1.0);
2563 ASSERT(result >= 0 && result < 1);
2564 return Heap::AllocateHeapNumber(result);
2565}
2566
2567
2568static Object* Runtime_Math_round(Arguments args) {
2569 NoHandleAllocation ha;
2570 ASSERT(args.length() == 1);
2571
2572 CONVERT_DOUBLE_CHECKED(x, args[0]);
2573 if (signbit(x) && x >= -0.5) return Heap::minus_zero_value();
2574 return Heap::NumberFromDouble(floor(x + 0.5));
2575}
2576
2577
2578static Object* Runtime_Math_sin(Arguments args) {
2579 NoHandleAllocation ha;
2580 ASSERT(args.length() == 1);
2581
2582 CONVERT_DOUBLE_CHECKED(x, args[0]);
2583 return Heap::AllocateHeapNumber(sin(x));
2584}
2585
2586
2587static Object* Runtime_Math_sqrt(Arguments args) {
2588 NoHandleAllocation ha;
2589 ASSERT(args.length() == 1);
2590
2591 CONVERT_DOUBLE_CHECKED(x, args[0]);
2592 return Heap::AllocateHeapNumber(sqrt(x));
2593}
2594
2595
2596static Object* Runtime_Math_tan(Arguments args) {
2597 NoHandleAllocation ha;
2598 ASSERT(args.length() == 1);
2599
2600 CONVERT_DOUBLE_CHECKED(x, args[0]);
2601 return Heap::AllocateHeapNumber(tan(x));
2602}
2603
2604
2605static Object* Runtime_NewArguments(Arguments args) {
2606 NoHandleAllocation ha;
2607 ASSERT(args.length() == 1);
2608
2609 // ECMA-262, 3rd., 10.1.8, p.39
2610 CONVERT_CHECKED(JSFunction, callee, args[0]);
2611
2612 // Compute the frame holding the arguments.
2613 JavaScriptFrameIterator it;
2614 it.AdvanceToArgumentsFrame();
2615 JavaScriptFrame* frame = it.frame();
2616
2617 const int length = frame->GetProvidedParametersCount();
2618 Object* result = Heap::AllocateArgumentsObject(callee, length);
2619 if (result->IsFailure()) return result;
2620 FixedArray* array = FixedArray::cast(JSObject::cast(result)->elements());
2621 ASSERT(array->length() == length);
2622 for (int i = 0; i < length; i++) {
2623 array->set(i, frame->GetParameter(i));
2624 }
2625 return result;
2626}
2627
2628
2629static Object* Runtime_NewClosure(Arguments args) {
2630 HandleScope scope;
2631 ASSERT(args.length() == 2);
2632 CONVERT_ARG_CHECKED(JSFunction, boilerplate, 0);
2633 CONVERT_ARG_CHECKED(Context, context, 1);
2634
2635 Handle<JSFunction> result =
2636 Factory::NewFunctionFromBoilerplate(boilerplate, context);
2637 return *result;
2638}
2639
2640
2641static Object* Runtime_NewObject(Arguments args) {
2642 NoHandleAllocation ha;
2643 ASSERT(args.length() == 1);
2644
2645 Object* constructor = args[0];
2646 if (constructor->IsJSFunction()) {
2647 JSFunction* function = JSFunction::cast(constructor);
2648
2649 // Handle steping into constructors.
2650 if (Debug::StepInActive()) {
2651 StackFrameIterator it;
2652 it.Advance();
2653 ASSERT(InternalFrame::cast(it.frame())->is_construct_trampoline());
2654 it.Advance();
2655 if (it.frame()->fp() == Debug::step_in_fp()) {
2656 HandleScope scope;
2657 Debug::FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
2658 }
2659 }
2660
2661 if (function->has_initial_map() &&
2662 function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
2663 // The 'Function' function ignores the receiver object when
2664 // called using 'new' and creates a new JSFunction object that
2665 // is returned. The receiver object is only used for error
2666 // reporting if an error occurs when constructing the new
2667 // JSFunction. AllocateJSObject should not be used to allocate
2668 // JSFunctions since it does not properly initialize the shared
2669 // part of the function. Since the receiver is ignored anyway,
2670 // we use the global object as the receiver instead of a new
2671 // JSFunction object. This way, errors are reported the same
2672 // way whether or not 'Function' is called using 'new'.
2673 return Top::context()->global();
2674 }
2675 return Heap::AllocateJSObject(function);
2676 }
2677
2678 HandleScope scope;
2679 Handle<Object> cons(constructor);
2680 // The constructor is not a function; throw a type error.
2681 Handle<Object> type_error =
2682 Factory::NewTypeError("not_constructor", HandleVector(&cons, 1));
2683 return Top::Throw(*type_error);
2684}
2685
2686
2687#ifdef DEBUG
2688DEFINE_bool(trace_lazy, false, "trace lazy compilation");
2689#endif
2690
2691
2692static Object* Runtime_LazyCompile(Arguments args) {
2693 HandleScope scope;
2694 ASSERT(args.length() == 1);
2695
2696 Handle<JSFunction> function = args.at<JSFunction>(0);
2697#ifdef DEBUG
2698 if (FLAG_trace_lazy) {
2699 PrintF("[lazy: ");
2700 function->shared()->name()->Print();
2701 PrintF("]\n");
2702 }
2703#endif
2704
2705 // Compile the target function.
2706 ASSERT(!function->is_compiled());
2707 if (!CompileLazy(function, KEEP_EXCEPTION)) {
2708 return Failure::Exception();
2709 }
2710
2711 return function->code();
2712}
2713
2714
2715static Object* Runtime_GetCalledFunction(Arguments args) {
2716 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00002717 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002718 StackFrameIterator it;
2719 // Get past the JS-to-C exit frame.
2720 ASSERT(it.frame()->is_exit());
2721 it.Advance();
2722 // Get past the CALL_NON_FUNCTION activation frame.
2723 ASSERT(it.frame()->is_java_script());
2724 it.Advance();
2725 // Argument adaptor frames do not copy the function; we have to skip
2726 // past them to get to the real calling frame.
2727 if (it.frame()->is_arguments_adaptor()) it.Advance();
2728 // Get the function from the top of the expression stack of the
2729 // calling frame.
2730 StandardFrame* frame = StandardFrame::cast(it.frame());
2731 int index = frame->ComputeExpressionsCount() - 1;
2732 Object* result = frame->GetExpression(index);
2733 return result;
2734}
2735
2736
2737static Object* Runtime_GetFunctionDelegate(Arguments args) {
2738 HandleScope scope;
2739 ASSERT(args.length() == 1);
2740 RUNTIME_ASSERT(!args[0]->IsJSFunction());
2741 return *Execution::GetFunctionDelegate(args.at<Object>(0));
2742}
2743
2744
2745static Object* Runtime_NewContext(Arguments args) {
2746 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00002747 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002748
kasper.lund7276f142008-07-30 08:49:36 +00002749 CONVERT_CHECKED(JSFunction, function, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002750 int length = ScopeInfo<>::NumberOfContextSlots(function->code());
2751 Object* result = Heap::AllocateFunctionContext(length, function);
2752 if (result->IsFailure()) return result;
2753
2754 Top::set_context(Context::cast(result));
2755
kasper.lund7276f142008-07-30 08:49:36 +00002756 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002757}
2758
2759
2760static Object* Runtime_PushContext(Arguments args) {
2761 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00002762 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002763
2764 // Convert the object to a proper JavaScript object.
kasper.lund7276f142008-07-30 08:49:36 +00002765 Object* object = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002766 if (!object->IsJSObject()) {
2767 object = object->ToObject();
2768 if (object->IsFailure()) {
2769 if (!Failure::cast(object)->IsInternalError()) return object;
2770 HandleScope scope;
kasper.lund7276f142008-07-30 08:49:36 +00002771 Handle<Object> handle(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002772 Handle<Object> result =
2773 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
2774 return Top::Throw(*result);
2775 }
2776 }
2777
2778 Object* result =
2779 Heap::AllocateWithContext(Top::context(), JSObject::cast(object));
2780 if (result->IsFailure()) return result;
2781
2782 Top::set_context(Context::cast(result));
2783
kasper.lund7276f142008-07-30 08:49:36 +00002784 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002785}
2786
2787
2788static Object* Runtime_LookupContext(Arguments args) {
2789 HandleScope scope;
2790 ASSERT(args.length() == 2);
2791
2792 CONVERT_ARG_CHECKED(Context, context, 0);
2793 CONVERT_ARG_CHECKED(String, name, 1);
2794
2795 int index;
2796 PropertyAttributes attributes;
2797 ContextLookupFlags flags = FOLLOW_CHAINS;
2798 Handle<Object> context_obj =
2799 context->Lookup(name, flags, &index, &attributes);
2800
2801 if (index < 0 && *context_obj != NULL) {
2802 ASSERT(context_obj->IsJSObject());
2803 return *context_obj;
2804 }
2805
2806 // No intermediate context found. Use global object by default.
2807 return Top::context()->global();
2808}
2809
2810
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002811// A mechanism to return pairs of Object*'s. This is somewhat
2812// compiler-dependent as it assumes that a 64-bit value (a long long)
2813// is returned via two registers (edx:eax on ia32). Both the ia32 and
2814// arm platform support this; it is mostly an issue of "coaxing" the
2815// compiler to do the right thing.
2816//
2817// TODO(1236026): This is a non-portable hack that should be removed.
2818typedef uint64_t ObjPair;
2819ObjPair MakePair(Object* x, Object* y) {
2820 return reinterpret_cast<uint32_t>(x) |
2821 (reinterpret_cast<ObjPair>(y) << 32);
2822}
2823
2824
2825static Object* Unhole(Object* x, PropertyAttributes attributes) {
2826 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
2827 USE(attributes);
2828 return x->IsTheHole() ? Heap::undefined_value() : x;
2829}
2830
2831
2832static ObjPair LoadContextSlotHelper(Arguments args, bool throw_error) {
2833 HandleScope scope;
2834 ASSERT(args.length() == 2);
2835
2836 if (!args[0]->IsContext()) return MakePair(IllegalOperation(), NULL);
2837 Handle<Context> context = args.at<Context>(0);
2838 Handle<String> name(String::cast(args[1]));
2839
2840 int index;
2841 PropertyAttributes attributes;
2842 ContextLookupFlags flags = FOLLOW_CHAINS;
2843 Handle<Object> context_obj =
2844 context->Lookup(name, flags, &index, &attributes);
2845
2846 if (index >= 0) {
2847 if (context_obj->IsContext()) {
2848 // The context is an Execution context, and the "property" we were looking
2849 // for is a local variable in that context. According to ECMA-262, 3rd.,
2850 // 10.1.6 and 10.2.3, the receiver is the global object.
2851 return MakePair(
2852 Unhole(Handle<Context>::cast(context_obj)->get(index), attributes),
2853 Top::context()->global());
2854 } else {
2855 return MakePair(
2856 Unhole(Handle<JSObject>::cast(context_obj)->GetElement(index),
2857 attributes),
2858 *context_obj);
2859 }
2860 }
2861
2862 if (*context_obj != NULL) {
2863 ASSERT(Handle<JSObject>::cast(context_obj)->HasProperty(*name));
2864 // Note: As of 5/29/2008, GetProperty does the "unholing" and so this call
2865 // here is redundant. We left it anyway, to be explicit; also it's not clear
2866 // why GetProperty should do the unholing in the first place.
2867 return MakePair(
2868 Unhole(Handle<JSObject>::cast(context_obj)->GetProperty(*name),
2869 attributes),
2870 *context_obj);
2871 }
2872
2873 if (throw_error) {
2874 // The property doesn't exist - throw exception.
2875 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002876 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002877 return MakePair(Top::Throw(*reference_error), NULL);
2878 } else {
2879 // The property doesn't exist - return undefined
2880 return MakePair(Heap::undefined_value(), Heap::undefined_value());
2881 }
2882}
2883
2884
2885static ObjPair Runtime_LoadContextSlot(Arguments args) {
2886 return LoadContextSlotHelper(args, true);
2887}
2888
2889
2890static ObjPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
2891 return LoadContextSlotHelper(args, false);
2892}
2893
2894
2895static Object* Runtime_StoreContextSlot(Arguments args) {
2896 HandleScope scope;
2897 ASSERT(args.length() == 3);
2898
2899 Handle<Object> value(args[0]);
2900 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002901 CONVERT_ARG_CHECKED(String, name, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002902
2903 int index;
2904 PropertyAttributes attributes;
2905 ContextLookupFlags flags = FOLLOW_CHAINS;
2906 Handle<Object> context_obj =
2907 context->Lookup(name, flags, &index, &attributes);
2908
2909 if (index >= 0) {
2910 if (context_obj->IsContext()) {
2911 // Ignore if read_only variable.
2912 if ((attributes & READ_ONLY) == 0) {
2913 Handle<Context>::cast(context_obj)->set(index, *value);
2914 }
2915 } else {
2916 ASSERT((attributes & READ_ONLY) == 0);
2917 Object* result =
2918 Handle<JSObject>::cast(context_obj)->SetElement(index, *value);
2919 USE(result);
2920 ASSERT(!result->IsFailure());
2921 }
2922 return *value;
2923 }
2924
2925 // Slow case: The property is not in a FixedArray context.
2926 // It is either in an JSObject extension context or it was not found.
2927 Handle<JSObject> context_ext;
2928
2929 if (*context_obj != NULL) {
2930 // The property exists in the extension context.
2931 context_ext = Handle<JSObject>::cast(context_obj);
2932 } else {
2933 // The property was not found. It needs to be stored in the global context.
2934 ASSERT(attributes == ABSENT);
2935 attributes = NONE;
2936 context_ext = Handle<JSObject>(Top::context()->global());
2937 }
2938
2939 // Set the property, but ignore if read_only variable.
2940 if ((attributes & READ_ONLY) == 0) {
2941 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
2942 if (set.is_null()) {
2943 // Failure::Exception is converted to a null handle in the
2944 // handle-based methods such as SetProperty. We therefore need
2945 // to convert null handles back to exceptions.
2946 ASSERT(Top::has_pending_exception());
2947 return Failure::Exception();
2948 }
2949 }
2950 return *value;
2951}
2952
2953
2954static Object* Runtime_Throw(Arguments args) {
2955 HandleScope scope;
2956 ASSERT(args.length() == 1);
2957
2958 return Top::Throw(args[0]);
2959}
2960
2961
2962static Object* Runtime_ReThrow(Arguments args) {
2963 HandleScope scope;
2964 ASSERT(args.length() == 1);
2965
2966 return Top::ReThrow(args[0]);
2967}
2968
2969
2970static Object* Runtime_ThrowReferenceError(Arguments args) {
2971 HandleScope scope;
2972 ASSERT(args.length() == 1);
2973
2974 Handle<Object> name(args[0]);
2975 Handle<Object> reference_error =
2976 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
2977 return Top::Throw(*reference_error);
2978}
2979
2980
2981static Object* Runtime_StackOverflow(Arguments args) {
2982 NoHandleAllocation na;
2983 return Top::StackOverflow();
2984}
2985
2986
2987static Object* RuntimePreempt(Arguments args) {
2988 // Clear the preempt request flag.
2989 StackGuard::Continue(PREEMPT);
2990
2991 ContextSwitcher::PreemptionReceived();
2992
2993 {
2994 v8::Unlocker unlocker;
2995 Thread::YieldCPU();
2996 }
2997
2998 return Heap::undefined_value();
2999}
3000
3001
3002static Object* Runtime_DebugBreak(Arguments args) {
kasper.lund44510672008-07-25 07:37:58 +00003003 // Just continue if breaks are disabled or if we fail to load the debugger.
3004 if (Debug::disable_break() || !Debug::Load()) {
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003005 return args[0];
3006 }
3007
kasper.lund7276f142008-07-30 08:49:36 +00003008 // Don't break in system functions. If the current function is
3009 // either in the builtins object of some context or is in the debug
3010 // context just return with the debug break stack guard active.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003011 JavaScriptFrameIterator it;
3012 JavaScriptFrame* frame = it.frame();
3013 Object* fun = frame->function();
3014 if (fun->IsJSFunction()) {
3015 GlobalObject* global = JSFunction::cast(fun)->context()->global();
3016 if (global->IsJSBuiltinsObject() || Debug::IsDebugGlobal(global)) {
3017 return args[0];
3018 }
3019 }
3020
3021 // Clear the debug request flag.
3022 StackGuard::Continue(DEBUGBREAK);
3023
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003024 HandleScope scope;
3025 SaveBreakFrame save;
3026 EnterDebuggerContext enter;
3027
kasper.lund7276f142008-07-30 08:49:36 +00003028 // Notify the debug event listeners.
3029 Debugger::OnDebugBreak(Factory::undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003030
3031 // Return to continue execution.
3032 return args[0];
3033}
3034
3035
3036static Object* Runtime_StackGuard(Arguments args) {
3037 ASSERT(args.length() == 1);
3038
3039 // First check if this is a real stack overflow.
3040 if (StackGuard::IsStackOverflow()) return Runtime_StackOverflow(args);
3041
3042 // If not real stack overflow the stack guard was used to interrupt
3043 // execution for another purpose.
3044 if (StackGuard::IsDebugBreak()) Runtime_DebugBreak(args);
3045 if (StackGuard::IsPreempted()) RuntimePreempt(args);
3046 if (StackGuard::IsInterrupted()) {
3047 // interrupt
3048 StackGuard::Continue(INTERRUPT);
3049 return Top::StackOverflow();
3050 }
3051 return Heap::undefined_value();
3052}
3053
3054
3055// NOTE: These PrintXXX functions are defined for all builds (not just
3056// DEBUG builds) because we may want to be able to trace function
3057// calls in all modes.
3058static void PrintString(String* str) {
3059 // not uncommon to have empty strings
3060 if (str->length() > 0) {
3061 SmartPointer<char> s =
3062 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
3063 PrintF("%s", *s);
3064 }
3065}
3066
3067
3068static void PrintObject(Object* obj) {
3069 if (obj->IsSmi()) {
3070 PrintF("%d", Smi::cast(obj)->value());
3071 } else if (obj->IsString() || obj->IsSymbol()) {
3072 PrintString(String::cast(obj));
3073 } else if (obj->IsNumber()) {
3074 PrintF("%g", obj->Number());
3075 } else if (obj->IsFailure()) {
3076 PrintF("<failure>");
3077 } else if (obj->IsUndefined()) {
3078 PrintF("<undefined>");
3079 } else if (obj->IsNull()) {
3080 PrintF("<null>");
3081 } else if (obj->IsTrue()) {
3082 PrintF("<true>");
3083 } else if (obj->IsFalse()) {
3084 PrintF("<false>");
3085 } else {
3086 PrintF("%p", obj);
3087 }
3088}
3089
3090
3091static int StackSize() {
3092 int n = 0;
3093 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
3094 return n;
3095}
3096
3097
3098static void PrintTransition(Object* result) {
3099 // indentation
3100 { const int nmax = 80;
3101 int n = StackSize();
3102 if (n <= nmax)
3103 PrintF("%4d:%*s", n, n, "");
3104 else
3105 PrintF("%4d:%*s", n, nmax, "...");
3106 }
3107
3108 if (result == NULL) {
3109 // constructor calls
3110 JavaScriptFrameIterator it;
3111 JavaScriptFrame* frame = it.frame();
3112 if (frame->IsConstructor()) PrintF("new ");
3113 // function name
3114 Object* fun = frame->function();
3115 if (fun->IsJSFunction()) {
3116 PrintObject(JSFunction::cast(fun)->shared()->name());
3117 } else {
3118 PrintObject(fun);
3119 }
3120 // function arguments
3121 // (we are intentionally only printing the actually
3122 // supplied parameters, not all parameters required)
3123 PrintF("(this=");
3124 PrintObject(frame->receiver());
3125 const int length = frame->GetProvidedParametersCount();
3126 for (int i = 0; i < length; i++) {
3127 PrintF(", ");
3128 PrintObject(frame->GetParameter(i));
3129 }
3130 PrintF(") {\n");
3131
3132 } else {
3133 // function result
3134 PrintF("} -> ");
3135 PrintObject(result);
3136 PrintF("\n");
3137 }
3138}
3139
3140
3141static Object* Runtime_TraceEnter(Arguments args) {
3142 NoHandleAllocation ha;
3143 PrintTransition(NULL);
3144 return args[0]; // return TOS
3145}
3146
3147
3148static Object* Runtime_TraceExit(Arguments args) {
3149 NoHandleAllocation ha;
3150 PrintTransition(args[0]);
3151 return args[0]; // return TOS
3152}
3153
3154
3155static Object* Runtime_DebugPrint(Arguments args) {
3156 NoHandleAllocation ha;
3157 ASSERT(args.length() == 1);
3158
3159#ifdef DEBUG
3160 if (args[0]->IsString()) {
3161 // If we have a string, assume it's a code "marker"
3162 // and print some interesting cpu debugging info.
3163 JavaScriptFrameIterator it;
3164 JavaScriptFrame* frame = it.frame();
3165 PrintF("fp = %p, sp = %p, pp = %p: ",
3166 frame->fp(), frame->sp(), frame->pp());
3167 } else {
3168 PrintF("DebugPrint: ");
3169 }
3170 args[0]->Print();
3171#else
3172 PrintF("DebugPrint: %p", args[0]);
3173#endif
3174 PrintF("\n");
3175
3176 return args[0]; // return TOS
3177}
3178
3179
3180static Object* Runtime_DebugTrace(Arguments args) {
3181 ASSERT(args.length() == 1);
3182 NoHandleAllocation ha;
3183 Top::PrintStack();
3184 return args[0]; // return TOS
3185}
3186
3187
mads.s.ager31e71382008-08-13 09:32:07 +00003188static Object* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003189 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00003190 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003191
3192 // According to ECMA-262, section 15.9.1, page 117, the precision of
3193 // the number in a Date object representing a particular instant in
3194 // time is milliseconds. Therefore, we floor the result of getting
3195 // the OS time.
3196 double millis = floor(OS::TimeCurrentMillis());
3197 return Heap::NumberFromDouble(millis);
3198}
3199
3200
3201static Object* Runtime_DateParseString(Arguments args) {
3202 HandleScope scope;
3203 ASSERT(args.length() == 1);
3204
3205 CONVERT_CHECKED(String, string_object, args[0]);
3206
3207 Handle<String> str(string_object);
3208 Handle<FixedArray> output = Factory::NewFixedArray(DateParser::OUTPUT_SIZE);
3209 if (DateParser::Parse(*str, *output)) {
3210 return *Factory::NewJSArrayWithElements(output);
3211 } else {
3212 return *Factory::null_value();
3213 }
3214}
3215
3216
3217static Object* Runtime_DateLocalTimezone(Arguments args) {
3218 NoHandleAllocation ha;
3219 ASSERT(args.length() == 1);
3220
3221 CONVERT_DOUBLE_CHECKED(x, args[0]);
3222 char* zone = OS::LocalTimezone(x);
3223 return Heap::AllocateStringFromUtf8(CStrVector(zone));
3224}
3225
3226
3227static Object* Runtime_DateLocalTimeOffset(Arguments args) {
3228 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00003229 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003230
3231 return Heap::NumberFromDouble(OS::LocalTimeOffset());
3232}
3233
3234
3235static Object* Runtime_DateDaylightSavingsOffset(Arguments args) {
3236 NoHandleAllocation ha;
3237 ASSERT(args.length() == 1);
3238
3239 CONVERT_DOUBLE_CHECKED(x, args[0]);
3240 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
3241}
3242
3243
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003244static Object* Runtime_NumberIsFinite(Arguments args) {
3245 NoHandleAllocation ha;
3246 ASSERT(args.length() == 1);
3247
3248 CONVERT_DOUBLE_CHECKED(value, args[0]);
3249 Object* result;
3250 if (isnan(value) || (fpclassify(value) == FP_INFINITE)) {
3251 result = Heap::false_value();
3252 } else {
3253 result = Heap::true_value();
3254 }
3255 return result;
3256}
3257
3258
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003259static Object* EvalContext() {
3260 // The topmost JS frame belongs to the eval function which called
3261 // the CompileString runtime function. We need to unwind one level
3262 // to get to the caller of eval.
3263 StackFrameLocator locator;
3264 JavaScriptFrame* frame = locator.FindJavaScriptFrame(1);
3265
kasper.lund44510672008-07-25 07:37:58 +00003266 // TODO(900055): Right now we check if the caller of eval() supports
3267 // eval to determine if it's an aliased eval or not. This may not be
3268 // entirely correct in the unlikely case where a function uses both
3269 // aliased and direct eval calls.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003270 HandleScope scope;
3271 if (!ScopeInfo<>::SupportsEval(frame->FindCode())) {
kasper.lund44510672008-07-25 07:37:58 +00003272 // Aliased eval: Evaluate in the global context of the eval
3273 // function to support aliased, cross environment evals.
3274 return *Top::global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003275 }
3276
3277 // Fetch the caller context from the frame.
3278 Handle<Context> caller(Context::cast(frame->context()));
3279
3280 // Check for eval() invocations that cross environments. Use the
3281 // context from the stack if evaluating in current environment.
3282 Handle<Context> target = Top::global_context();
3283 if (caller->global_context() == *target) return *caller;
3284
3285 // Compute a function closure that captures the calling context. We
3286 // need a function that has trivial scope info, since it is only
3287 // used to hold the context chain together.
3288 Handle<JSFunction> closure = Factory::NewFunction(Factory::empty_symbol(),
3289 Factory::undefined_value());
3290 closure->set_context(*caller);
3291
3292 // Create a new adaptor context that has the target environment as
3293 // the extension object. This enables the evaluated code to see both
3294 // the current context with locals and everything and to see global
3295 // variables declared in the target global object. Furthermore, any
3296 // properties introduced with 'var' will be added to the target
3297 // global object because it is the extension object.
3298 Handle<Context> adaptor =
3299 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, closure);
3300 adaptor->set_extension(target->global());
3301 return *adaptor;
3302}
3303
3304
3305static Object* Runtime_EvalReceiver(Arguments args) {
3306 StackFrameLocator locator;
3307 return locator.FindJavaScriptFrame(1)->receiver();
3308}
3309
3310
3311static Object* Runtime_CompileString(Arguments args) {
3312 HandleScope scope;
3313 ASSERT(args.length() == 2);
3314 bool contextual = args[1]->IsTrue();
3315 RUNTIME_ASSERT(contextual || args[1]->IsFalse());
3316
3317 // Compute the eval context.
3318 Handle<Context> context;
3319 if (contextual) {
3320 // Get eval context. May not be available if we are calling eval
3321 // through an alias, and the corresponding frame doesn't have a
3322 // proper eval context set up.
3323 Object* eval_context = EvalContext();
3324 if (eval_context->IsFailure()) return eval_context;
3325 context = Handle<Context>(Context::cast(eval_context));
3326 } else {
3327 context = Handle<Context>(Top::context()->global_context());
3328 }
3329
3330 // Compile eval() source.
3331 Handle<String> source(String::cast(args[0]));
3332 Handle<JSFunction> boilerplate =
3333 Compiler::CompileEval(context->IsGlobalContext(), source);
3334 if (boilerplate.is_null()) return Failure::Exception();
3335 Handle<JSFunction> fun =
3336 Factory::NewFunctionFromBoilerplate(boilerplate, context);
3337 return *fun;
3338}
3339
3340
3341static Object* Runtime_CompileScript(Arguments args) {
3342 HandleScope scope;
3343 ASSERT(args.length() == 4);
3344
3345 CONVERT_ARG_CHECKED(String, source, 0);
3346 CONVERT_ARG_CHECKED(String, script, 1);
3347 CONVERT_CHECKED(Smi, line_attrs, args[2]);
3348 int line = line_attrs->value();
3349 CONVERT_CHECKED(Smi, col_attrs, args[3]);
3350 int col = col_attrs->value();
3351 Handle<JSFunction> boilerplate =
3352 Compiler::Compile(source, script, line, col, NULL, NULL);
3353 if (boilerplate.is_null()) return Failure::Exception();
3354 Handle<JSFunction> fun =
3355 Factory::NewFunctionFromBoilerplate(boilerplate,
3356 Handle<Context>(Top::context()));
3357 return *fun;
3358}
3359
3360
3361static Object* Runtime_SetNewFunctionAttributes(Arguments args) {
3362 // This utility adjusts the property attributes for newly created Function
3363 // object ("new Function(...)") by changing the map.
3364 // All it does is changing the prototype property to enumerable
3365 // as specified in ECMA262, 15.3.5.2.
3366 HandleScope scope;
3367 ASSERT(args.length() == 1);
3368 CONVERT_ARG_CHECKED(JSFunction, func, 0);
3369 ASSERT(func->map()->instance_type() ==
3370 Top::function_instance_map()->instance_type());
3371 ASSERT(func->map()->instance_size() ==
3372 Top::function_instance_map()->instance_size());
3373 func->set_map(*Top::function_instance_map());
3374 return *func;
3375}
3376
3377
3378// This will not allocate (flatten the string), but it may run
3379// very slowly for very deeply nested ConsStrings. For debugging use only.
3380static Object* Runtime_GlobalPrint(Arguments args) {
3381 NoHandleAllocation ha;
3382 ASSERT(args.length() == 1);
3383
3384 CONVERT_CHECKED(String, string, args[0]);
3385 StringInputBuffer buffer(string);
3386 while (buffer.has_more()) {
3387 uint16_t character = buffer.GetNext();
3388 PrintF("%c", character);
3389 }
3390 return string;
3391}
3392
3393
3394static Object* Runtime_RemoveArrayHoles(Arguments args) {
3395 ASSERT(args.length() == 1);
3396 // Ignore the case if this is not a JSArray.
3397 if (!args[0]->IsJSArray()) return args[0];
3398 return JSArray::cast(args[0])->RemoveHoles();
3399}
3400
3401
3402// Move contents of argument 0 (an array) to argument 1 (an array)
3403static Object* Runtime_MoveArrayContents(Arguments args) {
3404 ASSERT(args.length() == 2);
3405 CONVERT_CHECKED(JSArray, from, args[0]);
3406 CONVERT_CHECKED(JSArray, to, args[1]);
3407 to->SetContent(FixedArray::cast(from->elements()));
3408 to->set_length(from->length());
3409 from->SetContent(Heap::empty_fixed_array());
3410 from->set_length(0);
3411 return to;
3412}
3413
3414
3415// How many elements does this array have?
3416static Object* Runtime_EstimateNumberOfElements(Arguments args) {
3417 ASSERT(args.length() == 1);
3418 CONVERT_CHECKED(JSArray, array, args[0]);
3419 HeapObject* elements = array->elements();
3420 if (elements->IsDictionary()) {
3421 return Smi::FromInt(Dictionary::cast(elements)->NumberOfElements());
3422 } else {
3423 return array->length();
3424 }
3425}
3426
3427
3428// Returns an array that tells you where in the [0, length) interval an array
3429// might have elements. Can either return keys or intervals. Keys can have
3430// gaps in (undefined). Intervals can also span over some undefined keys.
3431static Object* Runtime_GetArrayKeys(Arguments args) {
3432 ASSERT(args.length() == 2);
3433 HandleScope scope;
3434 CONVERT_CHECKED(JSArray, raw_array, args[0]);
3435 Handle<JSArray> array(raw_array);
3436 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003437 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003438 // Create an array and get all the keys into it, then remove all the
3439 // keys that are not integers in the range 0 to length-1.
3440 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array);
3441 int keys_length = keys->length();
3442 for (int i = 0; i < keys_length; i++) {
3443 Object* key = keys->get(i);
3444 uint32_t index;
3445 if (!Array::IndexFromObject(key, &index) || index >= length) {
3446 // Zap invalid keys.
3447 keys->set_undefined(i);
3448 }
3449 }
3450 return *Factory::NewJSArrayWithElements(keys);
3451 } else {
3452 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
3453 // -1 means start of array.
3454 single_interval->set(0, Smi::FromInt(-1));
3455 Handle<Object> length_object =
3456 Factory::NewNumber(static_cast<double>(length));
3457 single_interval->set(1, *length_object);
3458 return *Factory::NewJSArrayWithElements(single_interval);
3459 }
3460}
3461
3462
3463// DefineAccessor takes an optional final argument which is the
3464// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
3465// to the way accessors are implemented, it is set for both the getter
3466// and setter on the first call to DefineAccessor and ignored on
3467// subsequent calls.
3468static Object* Runtime_DefineAccessor(Arguments args) {
3469 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
3470 // Compute attributes.
3471 PropertyAttributes attributes = NONE;
3472 if (args.length() == 5) {
3473 CONVERT_CHECKED(Smi, attrs, args[4]);
3474 int value = attrs->value();
3475 // Only attribute bits should be set.
3476 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3477 attributes = static_cast<PropertyAttributes>(value);
3478 }
3479
3480 CONVERT_CHECKED(JSObject, obj, args[0]);
3481 CONVERT_CHECKED(String, name, args[1]);
3482 CONVERT_CHECKED(Smi, flag, args[2]);
3483 CONVERT_CHECKED(JSFunction, fun, args[3]);
3484 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
3485}
3486
3487
3488static Object* Runtime_LookupAccessor(Arguments args) {
3489 ASSERT(args.length() == 3);
3490 CONVERT_CHECKED(JSObject, obj, args[0]);
3491 CONVERT_CHECKED(String, name, args[1]);
3492 CONVERT_CHECKED(Smi, flag, args[2]);
3493 return obj->LookupAccessor(name, flag->value() == 0);
3494}
3495
3496
3497// Helper functions for wrapping and unwrapping stack frame ids.
3498static Smi* WrapFrameId(StackFrame::Id id) {
3499 ASSERT(IsAligned(OffsetFrom(id), 4));
3500 return Smi::FromInt(id >> 2);
3501}
3502
3503
3504static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
3505 return static_cast<StackFrame::Id>(wrapped->value() << 2);
3506}
3507
3508
3509// Adds a JavaScript function as a debug event listener.
3510// args[0]: debug event listener function
3511// args[1]: object supplied during callback
3512static Object* Runtime_AddDebugEventListener(Arguments args) {
3513 ASSERT(args.length() == 2);
3514 // Convert the parameters to API objects to call the API function for adding
3515 // a JavaScript function as debug event listener.
3516 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
3517 v8::Handle<v8::Function> fun(ToApi<v8::Function>(raw_fun));
3518 v8::Handle<v8::Value> data(ToApi<v8::Value>(args.at<Object>(0)));
3519 v8::Debug::AddDebugEventListener(fun, data);
3520
3521 return Heap::undefined_value();
3522}
3523
3524
3525// Removes a JavaScript function debug event listener.
3526// args[0]: debug event listener function
3527static Object* Runtime_RemoveDebugEventListener(Arguments args) {
3528 ASSERT(args.length() == 1);
3529 // Convert the parameter to an API object to call the API function for
3530 // removing a JavaScript function debug event listener.
3531 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
3532 v8::Handle<v8::Function> fun(ToApi<v8::Function>(raw_fun));
3533 v8::Debug::RemoveDebugEventListener(fun);
3534
3535 return Heap::undefined_value();
3536}
3537
3538
3539static Object* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00003540 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003541 StackGuard::DebugBreak();
3542 return Heap::undefined_value();
3543}
3544
3545
3546static Object* DebugLookupResultValue(LookupResult* result) {
3547 Object* value;
3548 switch (result->type()) {
3549 case NORMAL: {
3550 Dictionary* dict =
3551 JSObject::cast(result->holder())->property_dictionary();
3552 value = dict->ValueAt(result->GetDictionaryEntry());
3553 if (value->IsTheHole()) {
3554 return Heap::undefined_value();
3555 }
3556 return value;
3557 }
3558 case FIELD:
3559 value =
3560 JSObject::cast(
3561 result->holder())->properties()->get(result->GetFieldIndex());
3562 if (value->IsTheHole()) {
3563 return Heap::undefined_value();
3564 }
3565 return value;
3566 case CONSTANT_FUNCTION:
3567 return result->GetConstantFunction();
3568 case CALLBACKS:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003569 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003570 case MAP_TRANSITION:
3571 case CONSTANT_TRANSITION:
3572 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003573 return Heap::undefined_value();
3574 default:
3575 UNREACHABLE();
3576 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003577 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003578 return Heap::undefined_value();
3579}
3580
3581
3582static Object* Runtime_DebugGetLocalPropertyDetails(Arguments args) {
3583 HandleScope scope;
3584
3585 ASSERT(args.length() == 2);
3586
3587 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3588 CONVERT_ARG_CHECKED(String, name, 1);
3589
3590 // Check if the name is trivially convertible to an index and get the element
3591 // if so.
3592 uint32_t index;
3593 if (name->AsArrayIndex(&index)) {
3594 Handle<FixedArray> details = Factory::NewFixedArray(2);
3595 details->set(0, Runtime::GetElementOrCharAt(obj, index));
3596 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
3597 return *Factory::NewJSArrayWithElements(details);
3598 }
3599
3600 // Perform standard local lookup on the object.
3601 LookupResult result;
3602 obj->LocalLookup(*name, &result);
3603 if (result.IsProperty()) {
3604 Handle<Object> value(DebugLookupResultValue(&result));
3605 Handle<FixedArray> details = Factory::NewFixedArray(2);
3606 details->set(0, *value);
3607 details->set(1, result.GetPropertyDetails().AsSmi());
3608 return *Factory::NewJSArrayWithElements(details);
3609 }
3610 return Heap::undefined_value();
3611}
3612
3613
3614static Object* Runtime_DebugGetProperty(Arguments args) {
3615 HandleScope scope;
3616
3617 ASSERT(args.length() == 2);
3618
3619 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3620 CONVERT_ARG_CHECKED(String, name, 1);
3621
3622 LookupResult result;
3623 obj->Lookup(*name, &result);
3624 if (result.IsProperty()) {
3625 return DebugLookupResultValue(&result);
3626 }
3627 return Heap::undefined_value();
3628}
3629
3630
3631// Return the names of the local named properties.
3632// args[0]: object
3633static Object* Runtime_DebugLocalPropertyNames(Arguments args) {
3634 HandleScope scope;
3635 ASSERT(args.length() == 1);
3636 if (!args[0]->IsJSObject()) {
3637 return Heap::undefined_value();
3638 }
3639 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3640
3641 int n = obj->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
3642 Handle<FixedArray> names = Factory::NewFixedArray(n);
3643 obj->GetLocalPropertyNames(*names);
3644 return *Factory::NewJSArrayWithElements(names);
3645}
3646
3647
3648// Return the names of the local indexed properties.
3649// args[0]: object
3650static Object* Runtime_DebugLocalElementNames(Arguments args) {
3651 HandleScope scope;
3652 ASSERT(args.length() == 1);
3653 if (!args[0]->IsJSObject()) {
3654 return Heap::undefined_value();
3655 }
3656 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3657
3658 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
3659 Handle<FixedArray> names = Factory::NewFixedArray(n);
3660 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
3661 return *Factory::NewJSArrayWithElements(names);
3662}
3663
3664
3665// Return the property type calculated from the property details.
3666// args[0]: smi with property details.
3667static Object* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
3668 ASSERT(args.length() == 1);
3669 CONVERT_CHECKED(Smi, details, args[0]);
3670 PropertyType type = PropertyDetails(details).type();
3671 return Smi::FromInt(static_cast<int>(type));
3672}
3673
3674
3675// Return the property attribute calculated from the property details.
3676// args[0]: smi with property details.
3677static Object* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
3678 ASSERT(args.length() == 1);
3679 CONVERT_CHECKED(Smi, details, args[0]);
3680 PropertyAttributes attributes = PropertyDetails(details).attributes();
3681 return Smi::FromInt(static_cast<int>(attributes));
3682}
3683
3684
3685// Return the property insertion index calculated from the property details.
3686// args[0]: smi with property details.
3687static Object* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
3688 ASSERT(args.length() == 1);
3689 CONVERT_CHECKED(Smi, details, args[0]);
3690 int index = PropertyDetails(details).index();
3691 return Smi::FromInt(index);
3692}
3693
3694
3695// Return information on whether an object has a named or indexed interceptor.
3696// args[0]: object
3697static Object* Runtime_DebugInterceptorInfo(Arguments args) {
3698 HandleScope scope;
3699 ASSERT(args.length() == 1);
3700 if (!args[0]->IsJSObject()) {
3701 return Smi::FromInt(0);
3702 }
3703 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3704
3705 int result = 0;
3706 if (obj->HasNamedInterceptor()) result |= 2;
3707 if (obj->HasIndexedInterceptor()) result |= 1;
3708
3709 return Smi::FromInt(result);
3710}
3711
3712
3713// Return property names from named interceptor.
3714// args[0]: object
3715static Object* Runtime_DebugNamedInterceptorPropertyNames(Arguments args) {
3716 HandleScope scope;
3717 ASSERT(args.length() == 1);
3718 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3719 RUNTIME_ASSERT(obj->HasNamedInterceptor());
3720
3721 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
3722 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
3723 return Heap::undefined_value();
3724}
3725
3726
3727// Return element names from indexed interceptor.
3728// args[0]: object
3729static Object* Runtime_DebugIndexedInterceptorElementNames(Arguments args) {
3730 HandleScope scope;
3731 ASSERT(args.length() == 1);
3732 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3733 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
3734
3735 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
3736 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
3737 return Heap::undefined_value();
3738}
3739
3740
3741// Return property value from named interceptor.
3742// args[0]: object
3743// args[1]: property name
3744static Object* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
3745 HandleScope scope;
3746 ASSERT(args.length() == 2);
3747 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3748 RUNTIME_ASSERT(obj->HasNamedInterceptor());
3749 CONVERT_ARG_CHECKED(String, name, 1);
3750
3751 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003752 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003753}
3754
3755
3756// Return element value from indexed interceptor.
3757// args[0]: object
3758// args[1]: index
3759static Object* Runtime_DebugIndexedInterceptorElementValue(Arguments args) {
3760 HandleScope scope;
3761 ASSERT(args.length() == 2);
3762 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3763 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
3764 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
3765
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003766 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003767}
3768
3769
3770static Object* Runtime_CheckExecutionState(Arguments args) {
3771 ASSERT(args.length() >= 1);
3772 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
3773 // Check that the break id is valid and that there is a valid frame
3774 // where execution is broken.
3775 if (break_id != Top::break_id() ||
3776 Top::break_frame_id() == StackFrame::NO_ID) {
3777 return Top::Throw(Heap::illegal_execution_state_symbol());
3778 }
3779
3780 return Heap::true_value();
3781}
3782
3783
3784static Object* Runtime_GetFrameCount(Arguments args) {
3785 HandleScope scope;
3786 ASSERT(args.length() == 1);
3787
3788 // Check arguments.
3789 Object* result = Runtime_CheckExecutionState(args);
3790 if (result->IsFailure()) return result;
3791
3792 // Count all frames which are relevant to debugging stack trace.
3793 int n = 0;
3794 StackFrame::Id id = Top::break_frame_id();
3795 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
3796 return Smi::FromInt(n);
3797}
3798
3799
3800static const int kFrameDetailsFrameIdIndex = 0;
3801static const int kFrameDetailsReceiverIndex = 1;
3802static const int kFrameDetailsFunctionIndex = 2;
3803static const int kFrameDetailsArgumentCountIndex = 3;
3804static const int kFrameDetailsLocalCountIndex = 4;
3805static const int kFrameDetailsSourcePositionIndex = 5;
3806static const int kFrameDetailsConstructCallIndex = 6;
3807static const int kFrameDetailsDebuggerFrameIndex = 7;
3808static const int kFrameDetailsFirstDynamicIndex = 8;
3809
3810// Return an array with frame details
3811// args[0]: number: break id
3812// args[1]: number: frame index
3813//
3814// The array returned contains the following information:
3815// 0: Frame id
3816// 1: Receiver
3817// 2: Function
3818// 3: Argument count
3819// 4: Local count
3820// 5: Source position
3821// 6: Constructor call
3822// 7: Debugger frame
3823// Arguments name, value
3824// Locals name, value
3825static Object* Runtime_GetFrameDetails(Arguments args) {
3826 HandleScope scope;
3827 ASSERT(args.length() == 2);
3828
3829 // Check arguments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003830 Object* check = Runtime_CheckExecutionState(args);
3831 if (check->IsFailure()) return check;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003832 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
3833
3834 // Find the relevant frame with the requested index.
3835 StackFrame::Id id = Top::break_frame_id();
3836 int count = 0;
3837 JavaScriptFrameIterator it(id);
3838 for (; !it.done(); it.Advance()) {
3839 if (count == index) break;
3840 count++;
3841 }
3842 if (it.done()) return Heap::undefined_value();
3843
3844 // Traverse the saved contexts chain to find the active context for the
3845 // selected frame.
3846 SaveContext* save = Top::save_context();
3847 while (save != NULL && reinterpret_cast<Address>(save) < it.frame()->sp()) {
3848 save = save->prev();
3849 }
3850
3851 // Get the frame id.
3852 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
3853
3854 // Find source position.
3855 int position = it.frame()->FindCode()->SourcePosition(it.frame()->pc());
3856
3857 // Check for constructor frame.
3858 bool constructor = it.frame()->IsConstructor();
3859
3860 // Get code and read scope info from it for local variable information.
3861 Handle<Code> code(it.frame()->FindCode());
3862 ScopeInfo<> info(*code);
3863
3864 // Get the context.
3865 Handle<Context> context(Context::cast(it.frame()->context()));
3866
3867 // Get the locals names and values into a temporary array.
3868 //
3869 // TODO(1240907): Hide compiler-introduced stack variables
3870 // (e.g. .result)? For users of the debugger, they will probably be
3871 // confusing.
3872 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
3873 for (int i = 0; i < info.NumberOfLocals(); i++) {
3874 // Name of the local.
3875 locals->set(i * 2, *info.LocalName(i));
3876
3877 // Fetch the value of the local - either from the stack or from a
3878 // heap-allocated context.
3879 if (i < info.number_of_stack_slots()) {
3880 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
3881 } else {
3882 Handle<String> name = info.LocalName(i);
3883 // Traverse the context chain to the function context as all local
3884 // variables stored in the context will be on the function context.
3885 while (context->previous() != NULL) {
3886 context = Handle<Context>(context->previous());
3887 }
3888 ASSERT(context->is_function_context());
3889 locals->set(i * 2 + 1,
3890 context->get(ScopeInfo<>::ContextSlotIndex(*code, *name,
3891 NULL)));
3892 }
3893 }
3894
3895 // Now advance to the arguments adapter frame (if any). If contains all
3896 // the provided parameters and
3897
3898 // Now advance to the arguments adapter frame (if any). It contains all
3899 // the provided parameters whereas the function frame always have the number
3900 // of arguments matching the functions parameters. The rest of the
3901 // information (except for what is collected above) is the same.
3902 it.AdvanceToArgumentsFrame();
3903
3904 // Find the number of arguments to fill. At least fill the number of
3905 // parameters for the function and fill more if more parameters are provided.
3906 int argument_count = info.number_of_parameters();
3907 if (argument_count < it.frame()->GetProvidedParametersCount()) {
3908 argument_count = it.frame()->GetProvidedParametersCount();
3909 }
3910
3911 // Calculate the size of the result.
3912 int details_size = kFrameDetailsFirstDynamicIndex +
3913 2 * (argument_count + info.NumberOfLocals());
3914 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
3915
3916 // Add the frame id.
3917 details->set(kFrameDetailsFrameIdIndex, *frame_id);
3918
3919 // Add the function (same as in function frame).
3920 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
3921
3922 // Add the arguments count.
3923 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
3924
3925 // Add the locals count
3926 details->set(kFrameDetailsLocalCountIndex,
3927 Smi::FromInt(info.NumberOfLocals()));
3928
3929 // Add the source position.
3930 if (position != kNoPosition) {
3931 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
3932 } else {
3933 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
3934 }
3935
3936 // Add the constructor information.
3937 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
3938
3939 // Add information on whether this frame is invoked in the debugger context.
3940 details->set(kFrameDetailsDebuggerFrameIndex,
3941 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
3942
3943 // Fill the dynamic part.
3944 int details_index = kFrameDetailsFirstDynamicIndex;
3945
3946 // Add arguments name and value.
3947 for (int i = 0; i < argument_count; i++) {
3948 // Name of the argument.
3949 if (i < info.number_of_parameters()) {
3950 details->set(details_index++, *info.parameter_name(i));
3951 } else {
3952 details->set(details_index++, Heap::undefined_value());
3953 }
3954
3955 // Parameter value.
3956 if (i < it.frame()->GetProvidedParametersCount()) {
3957 details->set(details_index++, it.frame()->GetParameter(i));
3958 } else {
3959 details->set(details_index++, Heap::undefined_value());
3960 }
3961 }
3962
3963 // Add locals name and value from the temporary copy from the function frame.
3964 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
3965 details->set(details_index++, locals->get(i));
3966 }
3967
3968 // Add the receiver (same as in function frame).
3969 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
3970 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
3971 Handle<Object> receiver(it.frame()->receiver());
3972 if (!receiver->IsJSObject()) {
3973 // If the receiver is NOT a JSObject we have hit an optimization
3974 // where a value object is not converted into a wrapped JS objects.
3975 // To hide this optimization from the debugger, we wrap the receiver
3976 // by creating correct wrapper object based on the calling frame's
3977 // global context.
3978 it.Advance();
3979 Handle<Context> calling_frames_global_context(
3980 Context::cast(Context::cast(it.frame()->context())->global_context()));
3981 receiver = Factory::ToObject(receiver, calling_frames_global_context);
3982 }
3983 details->set(kFrameDetailsReceiverIndex, *receiver);
3984
3985 ASSERT_EQ(details_size, details_index);
3986 return *Factory::NewJSArrayWithElements(details);
3987}
3988
3989
3990static Object* Runtime_GetCFrames(Arguments args) {
3991 HandleScope scope;
3992 ASSERT(args.length() == 1);
3993 Object* result = Runtime_CheckExecutionState(args);
3994 if (result->IsFailure()) return result;
3995
3996 static const int kMaxCFramesSize = 200;
3997 OS::StackFrame frames[kMaxCFramesSize];
3998 int frames_count = OS::StackWalk(frames, kMaxCFramesSize);
3999 if (frames_count == OS::kStackWalkError) {
4000 return Heap::undefined_value();
4001 }
4002
4003 Handle<String> address_str = Factory::LookupAsciiSymbol("address");
4004 Handle<String> text_str = Factory::LookupAsciiSymbol("text");
4005 Handle<FixedArray> frames_array = Factory::NewFixedArray(frames_count);
4006 for (int i = 0; i < frames_count; i++) {
4007 Handle<JSObject> frame_value = Factory::NewJSObject(Top::object_function());
4008 frame_value->SetProperty(
4009 *address_str,
4010 *Factory::NewNumberFromInt(reinterpret_cast<int>(frames[i].address)),
4011 NONE);
4012
4013 // Get the stack walk text for this frame.
4014 Handle<String> frame_text;
4015 if (strlen(frames[i].text) > 0) {
4016 Vector<const char> str(frames[i].text, strlen(frames[i].text));
4017 frame_text = Factory::NewStringFromAscii(str);
4018 }
4019
4020 if (!frame_text.is_null()) {
4021 frame_value->SetProperty(*text_str, *frame_text, NONE);
4022 }
4023
4024 frames_array->set(i, *frame_value);
4025 }
4026 return *Factory::NewJSArrayWithElements(frames_array);
4027}
4028
4029
4030static Object* Runtime_GetBreakLocations(Arguments args) {
4031 HandleScope scope;
4032 ASSERT(args.length() == 1);
4033
4034 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
4035 Handle<SharedFunctionInfo> shared(raw_fun->shared());
4036 // Find the number of break points
4037 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
4038 if (break_locations->IsUndefined()) return Heap::undefined_value();
4039 // Return array as JS array
4040 return *Factory::NewJSArrayWithElements(
4041 Handle<FixedArray>::cast(break_locations));
4042}
4043
4044
4045// Set a break point in a function
4046// args[0]: function
4047// args[1]: number: break source position (within the function source)
4048// args[2]: number: break point object
4049static Object* Runtime_SetFunctionBreakPoint(Arguments args) {
4050 HandleScope scope;
4051 ASSERT(args.length() == 3);
4052 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
4053 Handle<SharedFunctionInfo> shared(raw_fun->shared());
4054 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
4055 RUNTIME_ASSERT(source_position >= 0);
4056 Handle<Object> break_point_object_arg = args.at<Object>(2);
4057
4058 // Set break point.
4059 Debug::SetBreakPoint(shared, source_position, break_point_object_arg);
4060
4061 return Heap::undefined_value();
4062}
4063
4064
4065static Object* FindSharedFunctionInfoInScript(Handle<Script> script,
4066 int position) {
4067 // Iterate the heap looking for SharedFunctionInfo generated from the
4068 // script. The inner most SharedFunctionInfo containing the source position
4069 // for the requested break point is found.
4070 // NOTE: This might reqire several heap iterations. If the SharedFunctionInfo
4071 // which is found is not compiled it is compiled and the heap is iterated
4072 // again as the compilation might create inner functions from the newly
4073 // compiled function and the actual requested break point might be in one of
4074 // these functions.
4075 bool done = false;
4076 // The current candidate for the source position:
4077 int target_start_position = kNoPosition;
4078 Handle<SharedFunctionInfo> target;
4079 // The current candidate for the last function in script:
4080 Handle<SharedFunctionInfo> last;
4081 while (!done) {
4082 HeapIterator iterator;
4083 while (iterator.has_next()) {
4084 HeapObject* obj = iterator.next();
4085 ASSERT(obj != NULL);
4086 if (obj->IsSharedFunctionInfo()) {
4087 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
4088 if (shared->script() == *script) {
4089 // If the SharedFunctionInfo found has the requested script data and
4090 // contains the source position it is a candidate.
4091 int start_position = shared->function_token_position();
4092 if (start_position == kNoPosition) {
4093 start_position = shared->start_position();
4094 }
4095 if (start_position <= position &&
4096 position <= shared->end_position()) {
4097 // If there is no candidate or this function is within the currrent
4098 // candidate this is the new candidate.
4099 if (target.is_null()) {
4100 target_start_position = start_position;
4101 target = shared;
4102 } else {
4103 if (target_start_position < start_position &&
4104 shared->end_position() < target->end_position()) {
4105 target_start_position = start_position;
4106 target = shared;
4107 }
4108 }
4109 }
4110
4111 // Keep track of the last function in the script.
4112 if (last.is_null() ||
4113 shared->end_position() > last->start_position()) {
4114 last = shared;
4115 }
4116 }
4117 }
4118 }
4119
4120 // Make sure some candidate is selected.
4121 if (target.is_null()) {
4122 if (!last.is_null()) {
4123 // Position after the last function - use last.
4124 target = last;
4125 } else {
4126 // Unable to find function - possibly script without any function.
4127 return Heap::undefined_value();
4128 }
4129 }
4130
4131 // If the candidate found is compiled we are done. NOTE: when lazy
4132 // compilation of inner functions is introduced some additional checking
4133 // needs to be done here to compile inner functions.
4134 done = target->is_compiled();
4135 if (!done) {
4136 // If the candidate is not compiled compile it to reveal any inner
4137 // functions which might contain the requested source position.
4138 CompileLazyShared(target, KEEP_EXCEPTION);
4139 }
4140 }
4141
4142 return *target;
4143}
4144
4145
4146// Change the state of a break point in a script. NOTE: Regarding performance
4147// see the NOTE for GetScriptFromScriptData.
4148// args[0]: script to set break point in
4149// args[1]: number: break source position (within the script source)
4150// args[2]: number: break point object
4151static Object* Runtime_SetScriptBreakPoint(Arguments args) {
4152 HandleScope scope;
4153 ASSERT(args.length() == 3);
4154 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
4155 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
4156 RUNTIME_ASSERT(source_position >= 0);
4157 Handle<Object> break_point_object_arg = args.at<Object>(2);
4158
4159 // Get the script from the script wrapper.
4160 RUNTIME_ASSERT(wrapper->value()->IsScript());
4161 Handle<Script> script(Script::cast(wrapper->value()));
4162
4163 Object* result = FindSharedFunctionInfoInScript(script, source_position);
4164 if (!result->IsUndefined()) {
4165 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
4166 // Find position within function. The script position might be before the
4167 // source position of the first function.
4168 int position;
4169 if (shared->start_position() > source_position) {
4170 position = 0;
4171 } else {
4172 position = source_position - shared->start_position();
4173 }
4174 Debug::SetBreakPoint(shared, position, break_point_object_arg);
4175 }
4176 return Heap::undefined_value();
4177}
4178
4179
4180// Clear a break point
4181// args[0]: number: break point object
4182static Object* Runtime_ClearBreakPoint(Arguments args) {
4183 HandleScope scope;
4184 ASSERT(args.length() == 1);
4185 Handle<Object> break_point_object_arg = args.at<Object>(0);
4186
4187 // Clear break point.
4188 Debug::ClearBreakPoint(break_point_object_arg);
4189
4190 return Heap::undefined_value();
4191}
4192
4193
4194// Change the state of break on exceptions
4195// args[0]: boolean indicating uncaught exceptions
4196// args[1]: boolean indicating on/off
4197static Object* Runtime_ChangeBreakOnException(Arguments args) {
4198 HandleScope scope;
4199 ASSERT(args.length() == 2);
4200 ASSERT(args[0]->IsNumber());
4201 ASSERT(args[1]->IsBoolean());
4202
4203 // Update break point state
4204 ExceptionBreakType type =
4205 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
4206 bool enable = args[1]->ToBoolean()->IsTrue();
4207 Debug::ChangeBreakOnException(type, enable);
4208 return Heap::undefined_value();
4209}
4210
4211
4212// Prepare for stepping
4213// args[0]: break id for checking execution state
4214// args[1]: step action from the enumeration StepAction
4215// args[2]: number of times to perform the step
4216static Object* Runtime_PrepareStep(Arguments args) {
4217 HandleScope scope;
4218 ASSERT(args.length() == 3);
4219 // Check arguments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004220 Object* check = Runtime_CheckExecutionState(args);
4221 if (check->IsFailure()) return check;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004222 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
4223 return Top::Throw(Heap::illegal_argument_symbol());
4224 }
4225
4226 // Get the step action and check validity.
4227 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
4228 if (step_action != StepIn &&
4229 step_action != StepNext &&
4230 step_action != StepOut &&
4231 step_action != StepInMin &&
4232 step_action != StepMin) {
4233 return Top::Throw(Heap::illegal_argument_symbol());
4234 }
4235
4236 // Get the number of steps.
4237 int step_count = NumberToInt32(args[2]);
4238 if (step_count < 1) {
4239 return Top::Throw(Heap::illegal_argument_symbol());
4240 }
4241
4242 // Prepare step.
4243 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
4244 return Heap::undefined_value();
4245}
4246
4247
4248// Clear all stepping set by PrepareStep.
4249static Object* Runtime_ClearStepping(Arguments args) {
4250 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00004251 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004252 Debug::ClearStepping();
4253 return Heap::undefined_value();
4254}
4255
4256
4257// Creates a copy of the with context chain. The copy of the context chain is
4258// is linked to the function context supplied.
4259static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
4260 Handle<Context> function_context) {
4261 // At the bottom of the chain. Return the function context to link to.
4262 if (context_chain->is_function_context()) {
4263 return function_context;
4264 }
4265
4266 // Recursively copy the with contexts.
4267 Handle<Context> previous(context_chain->previous());
4268 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
4269 return Factory::NewWithContext(
4270 CopyWithContextChain(function_context, previous), extension);
4271}
4272
4273
4274// Helper function to find or create the arguments object for
4275// Runtime_DebugEvaluate.
4276static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
4277 Handle<JSFunction> function,
4278 Handle<Code> code,
4279 const ScopeInfo<>* sinfo,
4280 Handle<Context> function_context) {
4281 // Try to find the value of 'arguments' to pass as parameter. If it is not
4282 // found (that is the debugged function does not reference 'arguments' and
4283 // does not support eval) then create an 'arguments' object.
4284 int index;
4285 if (sinfo->number_of_stack_slots() > 0) {
4286 index = ScopeInfo<>::StackSlotIndex(*code, Heap::arguments_symbol());
4287 if (index != -1) {
4288 return Handle<Object>(frame->GetExpression(index));
4289 }
4290 }
4291
4292 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
4293 index = ScopeInfo<>::ContextSlotIndex(*code, Heap::arguments_symbol(),
4294 NULL);
4295 if (index != -1) {
4296 return Handle<Object>(function_context->get(index));
4297 }
4298 }
4299
4300 const int length = frame->GetProvidedParametersCount();
4301 Handle<Object> arguments = Factory::NewArgumentsObject(function, length);
4302 FixedArray* array = FixedArray::cast(JSObject::cast(*arguments)->elements());
4303 ASSERT(array->length() == length);
4304 for (int i = 0; i < length; i++) {
4305 array->set(i, frame->GetParameter(i));
4306 }
4307 return arguments;
4308}
4309
4310
4311// Evaluate a piece of JavaScript in the context of a stack frame for
4312// debugging. This is acomplished by creating a new context which in its
4313// extension part has all the parameters and locals of the function on the
4314// stack frame. A function which calls eval with the code to evaluate is then
4315// compiled in this context and called in this context. As this context
4316// replaces the context of the function on the stack frame a new (empty)
4317// function is created as well to be used as the closure for the context.
4318// This function and the context acts as replacements for the function on the
4319// stack frame presenting the same view of the values of parameters and
4320// local variables as if the piece of JavaScript was evaluated at the point
4321// where the function on the stack frame is currently stopped.
4322static Object* Runtime_DebugEvaluate(Arguments args) {
4323 HandleScope scope;
4324
4325 // Check the execution state and decode arguments frame and source to be
4326 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00004327 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004328 Object* check_result = Runtime_CheckExecutionState(args);
4329 if (check_result->IsFailure()) return check_result;
4330 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
4331 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00004332 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
4333
4334 // Handle the processing of break.
4335 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004336
4337 // Get the frame where the debugging is performed.
4338 StackFrame::Id id = UnwrapFrameId(wrapped_id);
4339 JavaScriptFrameIterator it(id);
4340 JavaScriptFrame* frame = it.frame();
4341 Handle<JSFunction> function(JSFunction::cast(frame->function()));
4342 Handle<Code> code(function->code());
4343 ScopeInfo<> sinfo(*code);
4344
4345 // Traverse the saved contexts chain to find the active context for the
4346 // selected frame.
4347 SaveContext* save = Top::save_context();
4348 while (save != NULL && reinterpret_cast<Address>(save) < frame->sp()) {
4349 save = save->prev();
4350 }
4351 ASSERT(save != NULL);
4352 SaveContext savex;
4353 Top::set_context(*(save->context()));
4354 Top::set_security_context(*(save->security_context()));
4355
4356 // Create the (empty) function replacing the function on the stack frame for
4357 // the purpose of evaluating in the context created below. It is important
4358 // that this function does not describe any parameters and local variables
4359 // in the context. If it does then this will cause problems with the lookup
4360 // in Context::Lookup, where context slots for parameters and local variables
4361 // are looked at before the extension object.
4362 Handle<JSFunction> go_between =
4363 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
4364 go_between->set_context(function->context());
4365#ifdef DEBUG
4366 ScopeInfo<> go_between_sinfo(go_between->shared()->code());
4367 ASSERT(go_between_sinfo.number_of_parameters() == 0);
4368 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
4369#endif
4370
4371 // Allocate and initialize a context extension object with all the
4372 // arguments, stack locals heap locals and extension properties of the
4373 // debugged function.
4374 Handle<JSObject> context_ext = Factory::NewJSObject(Top::object_function());
4375 // First fill all parameters to the context extension.
4376 for (int i = 0; i < sinfo.number_of_parameters(); ++i) {
4377 SetProperty(context_ext,
4378 sinfo.parameter_name(i),
4379 Handle<Object>(frame->GetParameter(i)), NONE);
4380 }
4381 // Second fill all stack locals to the context extension.
4382 for (int i = 0; i < sinfo.number_of_stack_slots(); i++) {
4383 SetProperty(context_ext,
4384 sinfo.stack_slot_name(i),
4385 Handle<Object>(frame->GetExpression(i)), NONE);
4386 }
4387 // Third fill all context locals to the context extension.
4388 Handle<Context> frame_context(Context::cast(frame->context()));
4389 Handle<Context> function_context(frame_context->fcontext());
4390 for (int i = Context::MIN_CONTEXT_SLOTS;
4391 i < sinfo.number_of_context_slots();
4392 ++i) {
4393 int context_index =
4394 ScopeInfo<>::ContextSlotIndex(*code, *sinfo.context_slot_name(i), NULL);
4395 SetProperty(context_ext,
4396 sinfo.context_slot_name(i),
4397 Handle<Object>(function_context->get(context_index)), NONE);
4398 }
4399 // Finally copy any properties from the function context extension. This will
4400 // be variables introduced by eval.
4401 if (function_context->extension() != NULL &&
4402 !function_context->IsGlobalContext()) {
4403 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
4404 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext);
4405 for (int i = 0; i < keys->length(); i++) {
4406 // Names of variables introduced by eval are strings.
4407 ASSERT(keys->get(i)->IsString());
4408 Handle<String> key(String::cast(keys->get(i)));
4409 SetProperty(context_ext, key, GetProperty(ext, key), NONE);
4410 }
4411 }
4412
4413 // Allocate a new context for the debug evaluation and set the extension
4414 // object build.
4415 Handle<Context> context =
4416 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
4417 context->set_extension(*context_ext);
4418 // Copy any with contexts present and chain them in front of this context.
4419 context = CopyWithContextChain(frame_context, context);
4420
4421 // Wrap the evaluation statement in a new function compiled in the newly
4422 // created context. The function has one parameter which has to be called
4423 // 'arguments'. This it to have access to what would have been 'arguments' in
4424 // the function beeing debugged.
4425 // function(arguments,__source__) {return eval(__source__);}
4426 static const char* source_str =
4427 "function(arguments,__source__){return eval(__source__);}";
4428 static const int source_str_length = strlen(source_str);
4429 Handle<String> function_source =
4430 Factory::NewStringFromAscii(Vector<const char>(source_str,
4431 source_str_length));
4432 Handle<JSFunction> boilerplate =
4433 Compiler::CompileEval(context->IsGlobalContext(), function_source);
4434 if (boilerplate.is_null()) return Failure::Exception();
4435 Handle<JSFunction> compiled_function =
4436 Factory::NewFunctionFromBoilerplate(boilerplate, context);
4437
4438 // Invoke the result of the compilation to get the evaluation function.
4439 bool has_pending_exception;
4440 Handle<Object> receiver(frame->receiver());
4441 Handle<Object> evaluation_function =
4442 Execution::Call(compiled_function, receiver, 0, NULL,
4443 &has_pending_exception);
4444
4445 Handle<Object> arguments = GetArgumentsObject(frame, function, code, &sinfo,
4446 function_context);
4447
4448 // Invoke the evaluation function and return the result.
4449 const int argc = 2;
4450 Object** argv[argc] = { arguments.location(),
4451 Handle<Object>::cast(source).location() };
4452 Handle<Object> result =
4453 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
4454 argc, argv, &has_pending_exception);
4455 return *result;
4456}
4457
4458
4459static Object* Runtime_DebugEvaluateGlobal(Arguments args) {
4460 HandleScope scope;
4461
4462 // Check the execution state and decode arguments frame and source to be
4463 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00004464 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004465 Object* check_result = Runtime_CheckExecutionState(args);
4466 if (check_result->IsFailure()) return check_result;
4467 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00004468 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
4469
4470 // Handle the processing of break.
4471 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004472
4473 // Enter the top context from before the debugger was invoked.
4474 SaveContext save;
4475 SaveContext* top = &save;
4476 while (top != NULL && *top->context() == *Debug::debug_context()) {
4477 top = top->prev();
4478 }
4479 if (top != NULL) {
4480 Top::set_context(*top->context());
4481 Top::set_security_context(*top->security_context());
4482 }
4483
4484 // Get the global context now set to the top context from before the
4485 // debugger was invoked.
4486 Handle<Context> context = Top::global_context();
4487
4488 // Compile the source to be evaluated.
4489 Handle<JSFunction> boilerplate(Compiler::CompileEval(true, source));
4490 if (boilerplate.is_null()) return Failure::Exception();
4491 Handle<JSFunction> compiled_function =
4492 Handle<JSFunction>(Factory::NewFunctionFromBoilerplate(boilerplate,
4493 context));
4494
4495 // Invoke the result of the compilation to get the evaluation function.
4496 bool has_pending_exception;
4497 Handle<Object> receiver = Top::global();
4498 Handle<Object> result =
4499 Execution::Call(compiled_function, receiver, 0, NULL,
4500 &has_pending_exception);
4501 return *result;
4502}
4503
4504
4505// Helper function used by Runtime_DebugGetLoadedScripts below.
4506static int DebugGetLoadedScripts(FixedArray* instances, int instances_size) {
4507 NoHandleAllocation ha;
4508 AssertNoAllocation no_alloc;
4509
4510 // Get hold of the current empty script.
4511 Context* context = Top::context()->global_context();
4512 Script* empty = context->empty_script();
4513
4514 // Scan heap for Script objects.
4515 int count = 0;
4516 HeapIterator iterator;
4517 while (iterator.has_next()) {
4518 HeapObject* obj = iterator.next();
4519 ASSERT(obj != NULL);
4520 if (obj->IsScript() && obj != empty) {
4521 if (instances != NULL && count < instances_size) {
4522 instances->set(count, obj);
4523 }
4524 count++;
4525 }
4526 }
4527
4528 return count;
4529}
4530
4531
4532static Object* Runtime_DebugGetLoadedScripts(Arguments args) {
4533 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00004534 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004535
4536 // Perform two GCs to get rid of all unreferenced scripts. The first GC gets
4537 // rid of all the cached script wrappes and the second gets rid of the
4538 // scripts which is no longer referenced.
4539 Heap::CollectGarbage(0, OLD_SPACE);
4540 Heap::CollectGarbage(0, OLD_SPACE);
4541
4542 // Get the number of scripts.
4543 int count;
4544 count = DebugGetLoadedScripts(NULL, 0);
4545
4546 // Allocate an array to hold the result.
4547 Handle<FixedArray> instances = Factory::NewFixedArray(count);
4548
4549 // Fill the script objects.
4550 count = DebugGetLoadedScripts(*instances, count);
4551
4552 // Convert the script objects to proper JS objects.
4553 for (int i = 0; i < count; i++) {
4554 Handle<Script> script(Script::cast(instances->get(i)));
4555 instances->set(i, *GetScriptWrapper(script));
4556 }
4557
4558 // Return result as a JS array.
4559 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
4560 Handle<JSArray>::cast(result)->SetContent(*instances);
4561 return *result;
4562}
4563
4564
4565// Helper function used by Runtime_DebugReferencedBy below.
4566static int DebugReferencedBy(JSObject* target,
4567 Object* instance_filter, int max_references,
4568 FixedArray* instances, int instances_size,
4569 JSFunction* context_extension_function,
4570 JSFunction* arguments_function) {
4571 NoHandleAllocation ha;
4572 AssertNoAllocation no_alloc;
4573
4574 // Iterate the heap.
4575 int count = 0;
4576 JSObject* last = NULL;
4577 HeapIterator iterator;
4578 while (iterator.has_next() &&
4579 (max_references == 0 || count < max_references)) {
4580 // Only look at all JSObjects.
4581 HeapObject* heap_obj = iterator.next();
4582 if (heap_obj->IsJSObject()) {
4583 // Skip context extension objects and argument arrays as these are
4584 // checked in the context of functions using them.
4585 JSObject* obj = JSObject::cast(heap_obj);
4586 if (obj->map()->constructor() == context_extension_function ||
4587 obj->map()->constructor() == arguments_function) {
4588 continue;
4589 }
4590
4591 // Check if the JS object has a reference to the object looked for.
4592 if (obj->ReferencesObject(target)) {
4593 // Check instance filter if supplied. This is normally used to avoid
4594 // references from mirror objects (see Runtime_IsInPrototypeChain).
4595 if (!instance_filter->IsUndefined()) {
4596 Object* V = obj;
4597 while (true) {
4598 Object* prototype = V->GetPrototype();
4599 if (prototype->IsNull()) {
4600 break;
4601 }
4602 if (instance_filter == prototype) {
4603 obj = NULL; // Don't add this object.
4604 break;
4605 }
4606 V = prototype;
4607 }
4608 }
4609
4610 if (obj != NULL) {
4611 // Valid reference found add to instance array if supplied an update
4612 // count.
4613 if (instances != NULL && count < instances_size) {
4614 instances->set(count, obj);
4615 }
4616 last = obj;
4617 count++;
4618 }
4619 }
4620 }
4621 }
4622
4623 // Check for circular reference only. This can happen when the object is only
4624 // referenced from mirrors and has a circular reference in which case the
4625 // object is not really alive and would have been garbage collected if not
4626 // referenced from the mirror.
4627 if (count == 1 && last == target) {
4628 count = 0;
4629 }
4630
4631 // Return the number of referencing objects found.
4632 return count;
4633}
4634
4635
4636// Scan the heap for objects with direct references to an object
4637// args[0]: the object to find references to
4638// args[1]: constructor function for instances to exclude (Mirror)
4639// args[2]: the the maximum number of objects to return
4640static Object* Runtime_DebugReferencedBy(Arguments args) {
4641 ASSERT(args.length() == 3);
4642
4643 // First perform a full GC in order to avoid references from dead objects.
4644 Heap::CollectGarbage(0, OLD_SPACE);
4645
4646 // Check parameters.
4647 CONVERT_CHECKED(JSObject, target, args[0]);
4648 Object* instance_filter = args[1];
4649 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
4650 instance_filter->IsJSObject());
4651 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
4652 RUNTIME_ASSERT(max_references >= 0);
4653
4654 // Get the constructor function for context extension and arguments array.
4655 JSFunction* context_extension_function =
4656 Top::context()->global_context()->context_extension_function();
4657 JSObject* arguments_boilerplate =
4658 Top::context()->global_context()->arguments_boilerplate();
4659 JSFunction* arguments_function =
4660 JSFunction::cast(arguments_boilerplate->map()->constructor());
4661
4662 // Get the number of referencing objects.
4663 int count;
4664 count = DebugReferencedBy(target, instance_filter, max_references,
4665 NULL, 0,
4666 context_extension_function, arguments_function);
4667
4668 // Allocate an array to hold the result.
4669 Object* object = Heap::AllocateFixedArray(count);
4670 if (object->IsFailure()) return object;
4671 FixedArray* instances = FixedArray::cast(object);
4672
4673 // Fill the referencing objects.
4674 count = DebugReferencedBy(target, instance_filter, max_references,
4675 instances, count,
4676 context_extension_function, arguments_function);
4677
4678 // Return result as JS array.
4679 Object* result =
4680 Heap::AllocateJSObject(
4681 Top::context()->global_context()->array_function());
4682 if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances);
4683 return result;
4684}
4685
4686
4687// Helper function used by Runtime_DebugConstructedBy below.
4688static int DebugConstructedBy(JSFunction* constructor, int max_references,
4689 FixedArray* instances, int instances_size) {
4690 AssertNoAllocation no_alloc;
4691
4692 // Iterate the heap.
4693 int count = 0;
4694 HeapIterator iterator;
4695 while (iterator.has_next() &&
4696 (max_references == 0 || count < max_references)) {
4697 // Only look at all JSObjects.
4698 HeapObject* heap_obj = iterator.next();
4699 if (heap_obj->IsJSObject()) {
4700 JSObject* obj = JSObject::cast(heap_obj);
4701 if (obj->map()->constructor() == constructor) {
4702 // Valid reference found add to instance array if supplied an update
4703 // count.
4704 if (instances != NULL && count < instances_size) {
4705 instances->set(count, obj);
4706 }
4707 count++;
4708 }
4709 }
4710 }
4711
4712 // Return the number of referencing objects found.
4713 return count;
4714}
4715
4716
4717// Scan the heap for objects constructed by a specific function.
4718// args[0]: the constructor to find instances of
4719// args[1]: the the maximum number of objects to return
4720static Object* Runtime_DebugConstructedBy(Arguments args) {
4721 ASSERT(args.length() == 2);
4722
4723 // First perform a full GC in order to avoid dead objects.
4724 Heap::CollectGarbage(0, OLD_SPACE);
4725
4726 // Check parameters.
4727 CONVERT_CHECKED(JSFunction, constructor, args[0]);
4728 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
4729 RUNTIME_ASSERT(max_references >= 0);
4730
4731 // Get the number of referencing objects.
4732 int count;
4733 count = DebugConstructedBy(constructor, max_references, NULL, 0);
4734
4735 // Allocate an array to hold the result.
4736 Object* object = Heap::AllocateFixedArray(count);
4737 if (object->IsFailure()) return object;
4738 FixedArray* instances = FixedArray::cast(object);
4739
4740 // Fill the referencing objects.
4741 count = DebugConstructedBy(constructor, max_references, instances, count);
4742
4743 // Return result as JS array.
4744 Object* result =
4745 Heap::AllocateJSObject(
4746 Top::context()->global_context()->array_function());
4747 if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances);
4748 return result;
4749}
4750
4751
4752static Object* Runtime_GetPrototype(Arguments args) {
4753 ASSERT(args.length() == 1);
4754
4755 CONVERT_CHECKED(JSObject, obj, args[0]);
4756
4757 return obj->GetPrototype();
4758}
4759
4760
4761static Object* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00004762 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004763 CPU::DebugBreak();
4764 return Heap::undefined_value();
4765}
4766
4767
4768// Finds the script object from the script data. NOTE: This operation uses
4769// heap traversal to find the function generated for the source position
4770// for the requested break point. For lazily compiled functions several heap
4771// traversals might be required rendering this operation as a rather slow
4772// operation. However for setting break points which is normally done through
4773// some kind of user interaction the performance is not crucial.
4774static Handle<Object> Runtime_GetScriptFromScriptName(
4775 Handle<String> script_name) {
4776 // Scan the heap for Script objects to find the script with the requested
4777 // script data.
4778 Handle<Script> script;
4779 HeapIterator iterator;
4780 while (script.is_null() && iterator.has_next()) {
4781 HeapObject* obj = iterator.next();
4782 // If a script is found check if it has the script data requested.
4783 if (obj->IsScript()) {
4784 if (Script::cast(obj)->name()->IsString()) {
4785 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
4786 script = Handle<Script>(Script::cast(obj));
4787 }
4788 }
4789 }
4790 }
4791
4792 // If no script with the requested script data is found return undefined.
4793 if (script.is_null()) return Factory::undefined_value();
4794
4795 // Return the script found.
4796 return GetScriptWrapper(script);
4797}
4798
4799
4800// Get the script object from script data. NOTE: Regarding performance
4801// see the NOTE for GetScriptFromScriptData.
4802// args[0]: script data for the script to find the source for
4803static Object* Runtime_GetScript(Arguments args) {
4804 HandleScope scope;
4805
4806 ASSERT(args.length() == 1);
4807
4808 CONVERT_CHECKED(String, script_name, args[0]);
4809
4810 // Find the requested script.
4811 Handle<Object> result =
4812 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
4813 return *result;
4814}
4815
4816
4817static Object* Runtime_FunctionGetAssemblerCode(Arguments args) {
4818#ifdef DEBUG
4819 HandleScope scope;
4820 ASSERT(args.length() == 1);
4821 // Get the function and make sure it is compiled.
4822 CONVERT_ARG_CHECKED(JSFunction, func, 0);
4823 if (!func->is_compiled() && !CompileLazy(func, KEEP_EXCEPTION)) {
4824 return Failure::Exception();
4825 }
4826 func->code()->PrintLn();
4827#endif // DEBUG
4828 return Heap::undefined_value();
4829}
4830
4831
4832static Object* Runtime_Abort(Arguments args) {
4833 ASSERT(args.length() == 2);
4834 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
4835 Smi::cast(args[1])->value());
4836 Top::PrintStack();
4837 OS::Abort();
4838 UNREACHABLE();
4839 return NULL;
4840}
4841
4842
kasper.lund44510672008-07-25 07:37:58 +00004843#ifdef DEBUG
4844// ListNatives is ONLY used by the fuzz-natives.js in debug mode
4845// Exclude the code in release mode.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004846static Object* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00004847 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004848 HandleScope scope;
4849 Handle<JSArray> result = Factory::NewJSArray(0);
4850 int index = 0;
4851#define ADD_ENTRY(Name, argc) \
4852 { \
4853 HandleScope inner; \
4854 Handle<String> name = \
4855 Factory::NewStringFromAscii(Vector<const char>(#Name, strlen(#Name))); \
4856 Handle<JSArray> pair = Factory::NewJSArray(0); \
4857 SetElement(pair, 0, name); \
4858 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
4859 SetElement(result, index++, pair); \
4860 }
4861 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
4862#undef ADD_ENTRY
4863 return *result;
4864}
kasper.lund44510672008-07-25 07:37:58 +00004865#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004866
4867
4868static Object* Runtime_IS_VAR(Arguments args) {
4869 UNREACHABLE(); // implemented as macro in the parser
4870 return NULL;
4871}
4872
4873
4874// ----------------------------------------------------------------------------
4875// Implementation of Runtime
4876
4877#define F(name, nargs) \
4878 { #name, "RuntimeStub_" #name, FUNCTION_ADDR(Runtime_##name), nargs, \
4879 static_cast<int>(Runtime::k##name) },
4880
4881static Runtime::Function Runtime_functions[] = {
4882 RUNTIME_FUNCTION_LIST(F)
4883 { NULL, NULL, NULL, 0, -1 }
4884};
4885
4886#undef F
4887
4888
4889Runtime::Function* Runtime::FunctionForId(FunctionId fid) {
4890 ASSERT(0 <= fid && fid < kNofFunctions);
4891 return &Runtime_functions[fid];
4892}
4893
4894
4895Runtime::Function* Runtime::FunctionForName(const char* name) {
4896 for (Function* f = Runtime_functions; f->name != NULL; f++) {
4897 if (strcmp(f->name, name) == 0) {
4898 return f;
4899 }
4900 }
4901 return NULL;
4902}
4903
4904
4905void Runtime::PerformGC(Object* result) {
4906 Failure* failure = Failure::cast(result);
4907 // Try to do a garbage collection; ignore it if it fails. The C
4908 // entry stub will throw an out-of-memory exception in that case.
4909 Heap::CollectGarbage(failure->requested(), failure->allocation_space());
4910}
4911
4912
4913} } // namespace v8::internal